Highlight proper movement icons, improve sequence filter

This commit is contained in:
Retera 2020-10-31 15:08:00 -04:00
parent fa94450d54
commit 238015f21d
17 changed files with 1998 additions and 1910 deletions

View File

@ -0,0 +1,41 @@
package com.etheller.warsmash.viewer5.handlers.w3x;
import java.util.Comparator;
import java.util.EnumSet;
public class SecondaryTagSequenceComparator implements Comparator<IndexedSequence> {
private final StandSequenceComparator standSequenceComparator;
private EnumSet<AnimationTokens.SecondaryTag> ignoredTags;
public SecondaryTagSequenceComparator(StandSequenceComparator standSequenceComparator) {
this.standSequenceComparator = standSequenceComparator;
}
public SecondaryTagSequenceComparator reset(EnumSet<AnimationTokens.SecondaryTag> ignoredTags) {
this.ignoredTags = ignoredTags;
return this;
}
@Override
public int compare(final IndexedSequence a, final IndexedSequence b) {
EnumSet<AnimationTokens.SecondaryTag> secondaryTagsA = a.sequence.getSecondaryTags();
EnumSet<AnimationTokens.SecondaryTag> secondaryTagsB = b.sequence.getSecondaryTags();
int secondaryTagsAOrdinal = getTagsOrdinal(secondaryTagsA, ignoredTags);
int secondaryTagsBOrdinal = getTagsOrdinal(secondaryTagsB, ignoredTags);
if (secondaryTagsAOrdinal != secondaryTagsBOrdinal) {
return secondaryTagsBOrdinal - secondaryTagsAOrdinal;
}
return standSequenceComparator.compare(a, b);
}
public static int getTagsOrdinal(EnumSet<AnimationTokens.SecondaryTag> secondaryTagsA, EnumSet<AnimationTokens.SecondaryTag> ignoredTags) {
int secondaryTagsBOrdinal = Integer.MAX_VALUE;
for (AnimationTokens.SecondaryTag secondaryTag : secondaryTagsA) {
if (secondaryTag.ordinal() < secondaryTagsBOrdinal && !ignoredTags.contains(secondaryTag)) {
secondaryTagsBOrdinal = secondaryTag.ordinal();
}
}
return secondaryTagsBOrdinal;
}
}

View File

@ -1,6 +1,7 @@
package com.etheller.warsmash.viewer5.handlers.w3x;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.List;
@ -11,229 +12,244 @@ import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.SecondaryTag;
public class SequenceUtils {
public static final EnumSet<SecondaryTag> EMPTY = EnumSet.noneOf(SecondaryTag.class);
public static final EnumSet<SecondaryTag> READY = EnumSet.of(SecondaryTag.READY);
public static final EnumSet<SecondaryTag> FLESH = EnumSet.of(SecondaryTag.FLESH);
public static final EnumSet<SecondaryTag> BONE = EnumSet.of(SecondaryTag.BONE);
public static final EnumSet<SecondaryTag> EMPTY = EnumSet.noneOf(SecondaryTag.class);
public static final EnumSet<SecondaryTag> READY = EnumSet.of(SecondaryTag.READY);
public static final EnumSet<SecondaryTag> FLESH = EnumSet.of(SecondaryTag.FLESH);
public static final EnumSet<SecondaryTag> BONE = EnumSet.of(SecondaryTag.BONE);
private static final StandSequenceComparator STAND_SEQUENCE_COMPARATOR = new StandSequenceComparator();
private static final StandSequenceComparator STAND_SEQUENCE_COMPARATOR = new StandSequenceComparator();
private static final SecondaryTagSequenceComparator SECONDARY_TAG_SEQUENCE_COMPARATOR = new SecondaryTagSequenceComparator(STAND_SEQUENCE_COMPARATOR);
public static List<IndexedSequence> filterSequences(final String type, final List<Sequence> sequences) {
final List<IndexedSequence> filtered = new ArrayList<>();
public static List<IndexedSequence> filterSequences(final String type, final List<Sequence> sequences) {
final List<IndexedSequence> filtered = new ArrayList<>();
for (int i = 0, l = sequences.size(); i < l; i++) {
final Sequence sequence = sequences.get(i);
final String name = sequence.getName().split("-")[0].trim().toLowerCase();
for (int i = 0, l = sequences.size(); i < l; i++) {
final Sequence sequence = sequences.get(i);
final String name = sequence.getName().split("-")[0].trim().toLowerCase();
if (name.equals(type)) {
filtered.add(new IndexedSequence(sequence, i));
}
}
if (name.equals(type)) {
filtered.add(new IndexedSequence(sequence, i));
}
}
return filtered;
}
return filtered;
}
private static List<IndexedSequence> filterSequences(final PrimaryTag type, final EnumSet<SecondaryTag> tags,
final List<Sequence> sequences) {
final List<IndexedSequence> filtered = new ArrayList<>();
private static List<IndexedSequence> filterSequences(final PrimaryTag type, final EnumSet<SecondaryTag> tags,
final List<Sequence> sequences) {
final List<IndexedSequence> filtered = new ArrayList<>();
for (int i = 0, l = sequences.size(); i < l; i++) {
final Sequence sequence = sequences.get(i);
if (sequence.getPrimaryTags().contains(type) && sequence.getSecondaryTags().containsAll(tags)
&& tags.containsAll(sequence.getSecondaryTags())) {
for (final AnimationTokens.SecondaryTag secondaryTag : sequence.getSecondaryTags()) {
if (tags.contains(secondaryTag)) {
filtered.add(new IndexedSequence(sequence, i));
}
}
}
}
if (filtered.isEmpty()) {
for (int i = 0, l = sequences.size(); i < l; i++) {
final Sequence sequence = sequences.get(i);
if (sequence.getPrimaryTags().contains(type) && sequence.getSecondaryTags().containsAll(tags)
&& tags.containsAll(sequence.getSecondaryTags())) {
filtered.add(new IndexedSequence(sequence, i));
}
}
}
for (int i = 0, l = sequences.size(); i < l; i++) {
final Sequence sequence = sequences.get(i);
if (sequence.getPrimaryTags().contains(type) && (sequence.getSecondaryTags().containsAll(tags)
&& tags.containsAll(sequence.getSecondaryTags()))) {
filtered.add(new IndexedSequence(sequence, i));
}
}
return filtered;
}
return filtered;
}
public static IndexedSequence selectSequence(final String type, final List<Sequence> sequences) {
final List<IndexedSequence> filtered = filterSequences(type, sequences);
public static IndexedSequence selectSequence(final String type, final List<Sequence> sequences) {
final List<IndexedSequence> filtered = filterSequences(type, sequences);
filtered.sort(STAND_SEQUENCE_COMPARATOR);
filtered.sort(STAND_SEQUENCE_COMPARATOR);
int i = 0;
final double randomRoll = Math.random() * 100;
for (final int l = filtered.size(); i < l; i++) {
final Sequence sequence = filtered.get(i).sequence;
final float rarity = sequence.getRarity();
int i = 0;
final double randomRoll = Math.random() * 100;
for (final int l = filtered.size(); i < l; i++) {
final Sequence sequence = filtered.get(i).sequence;
final float rarity = sequence.getRarity();
if (rarity == 0) {
break;
}
if (rarity == 0) {
break;
}
if (randomRoll < (10 - rarity)) {
return filtered.get(i);
}
}
if (randomRoll < (10 - rarity)) {
return filtered.get(i);
}
}
final int sequencesLeft = filtered.size() - i;
final int random = (int) (i + Math.floor(Math.random() * sequencesLeft));
if (sequencesLeft <= 0) {
return null; // new IndexedSequence(null, 0);
}
final IndexedSequence sequence = filtered.get(random);
final int sequencesLeft = filtered.size() - i;
final int random = (int) (i + Math.floor(Math.random() * sequencesLeft));
if (sequencesLeft <= 0) {
return null; // new IndexedSequence(null, 0);
}
final IndexedSequence sequence = filtered.get(random);
return sequence;
}
return sequence;
}
public static IndexedSequence selectSequence(final AnimationTokens.PrimaryTag type,
final EnumSet<AnimationTokens.SecondaryTag> tags, final List<Sequence> sequences,
final boolean allowRarityVariations) {
final List<IndexedSequence> filtered = filterSequences(type, tags, sequences);
public static IndexedSequence selectSequence(final AnimationTokens.PrimaryTag type,
final EnumSet<AnimationTokens.SecondaryTag> tags, final List<Sequence> sequences,
final boolean allowRarityVariations) {
List<IndexedSequence> filtered = filterSequences(type, tags, sequences);
Comparator<IndexedSequence> sequenceComparator = STAND_SEQUENCE_COMPARATOR;
filtered.sort(STAND_SEQUENCE_COMPARATOR);
if (filtered.isEmpty() && !tags.isEmpty()) {
filtered = filterSequences(type, EMPTY, sequences);
}
if (filtered.isEmpty()) {
// find tags
EnumSet<SecondaryTag> fallbackTags = null;
for (int i = 0, l = sequences.size(); i < l; i++) {
final Sequence sequence = sequences.get(i);
if (sequence.getPrimaryTags().contains(type)) {
if (fallbackTags == null || sequence.getSecondaryTags().size() < fallbackTags.size()
|| (sequence.getSecondaryTags().size() == fallbackTags.size() && SecondaryTagSequenceComparator.getTagsOrdinal(sequence.getSecondaryTags(), tags)
> SecondaryTagSequenceComparator.getTagsOrdinal(fallbackTags, tags))
) {
fallbackTags = sequence.getSecondaryTags();
}
}
}
if (fallbackTags != null) {
filtered = filterSequences(type, fallbackTags, sequences);
}
}
int i = 0;
final double randomRoll = Math.random() * 100;
for (final int l = filtered.size(); i < l; i++) {
final Sequence sequence = filtered.get(i).sequence;
final float rarity = sequence.getRarity();
filtered.sort(sequenceComparator);
if (rarity == 0) {
break;
}
int i = 0;
final double randomRoll = Math.random() * 100;
for (final int l = filtered.size(); i < l; i++) {
final Sequence sequence = filtered.get(i).sequence;
final float rarity = sequence.getRarity();
if ((randomRoll < (10 - rarity)) && allowRarityVariations) {
return filtered.get(i);
}
}
if (rarity == 0) {
break;
}
final int sequencesLeft = filtered.size() - i;
final int random = (int) (i + Math.floor(Math.random() * sequencesLeft));
if (sequencesLeft <= 0) {
return null; // new IndexedSequence(null, 0);
}
final IndexedSequence sequence = filtered.get(random);
if ((randomRoll < (10 - rarity)) && allowRarityVariations) {
return filtered.get(i);
}
}
return sequence;
}
final int sequencesLeft = filtered.size() - i;
final int random = (int) (i + Math.floor(Math.random() * sequencesLeft));
if (sequencesLeft <= 0) {
return null; // new IndexedSequence(null, 0);
}
final IndexedSequence sequence = filtered.get(random);
public static void randomStandSequence(final MdxComplexInstance target) {
final MdxModel model = (MdxModel) target.model;
final List<Sequence> sequences = model.getSequences();
final IndexedSequence sequence = selectSequence("stand", sequences);
return sequence;
}
if (sequence != null) {
target.setSequence(sequence.index);
}
else {
target.setSequence(0);
}
}
public static void randomStandSequence(final MdxComplexInstance target) {
final MdxModel model = (MdxModel) target.model;
final List<Sequence> sequences = model.getSequences();
final IndexedSequence sequence = selectSequence("stand", sequences);
public static void randomDeathSequence(final MdxComplexInstance target) {
final MdxModel model = (MdxModel) target.model;
final List<Sequence> sequences = model.getSequences();
final IndexedSequence sequence = selectSequence("death", sequences);
if (sequence != null) {
target.setSequence(sequence.index);
} else {
target.setSequence(0);
}
}
if (sequence != null) {
target.setSequence(sequence.index);
}
else {
target.setSequence(0);
}
}
public static void randomDeathSequence(final MdxComplexInstance target) {
final MdxModel model = (MdxModel) target.model;
final List<Sequence> sequences = model.getSequences();
final IndexedSequence sequence = selectSequence("death", sequences);
public static void randomWalkSequence(final MdxComplexInstance target) {
final MdxModel model = (MdxModel) target.model;
final List<Sequence> sequences = model.getSequences();
final IndexedSequence sequence = selectSequence("walk", sequences);
if (sequence != null) {
target.setSequence(sequence.index);
} else {
target.setSequence(0);
}
}
if (sequence != null) {
target.setSequence(sequence.index);
}
else {
randomStandSequence(target);
}
}
public static void randomWalkSequence(final MdxComplexInstance target) {
final MdxModel model = (MdxModel) target.model;
final List<Sequence> sequences = model.getSequences();
final IndexedSequence sequence = selectSequence("walk", sequences);
public static void randomBirthSequence(final MdxComplexInstance target) {
final MdxModel model = (MdxModel) target.model;
final List<Sequence> sequences = model.getSequences();
final IndexedSequence sequence = selectSequence("birth", sequences);
if (sequence != null) {
target.setSequence(sequence.index);
} else {
randomStandSequence(target);
}
}
if (sequence != null) {
target.setSequence(sequence.index);
}
else {
randomStandSequence(target);
}
}
public static void randomBirthSequence(final MdxComplexInstance target) {
final MdxModel model = (MdxModel) target.model;
final List<Sequence> sequences = model.getSequences();
final IndexedSequence sequence = selectSequence("birth", sequences);
public static void randomPortraitSequence(final MdxComplexInstance target) {
final MdxModel model = (MdxModel) target.model;
final List<Sequence> sequences = model.getSequences();
final IndexedSequence sequence = selectSequence("portrait", sequences);
if (sequence != null) {
target.setSequence(sequence.index);
} else {
randomStandSequence(target);
}
}
if (sequence != null) {
target.setSequence(sequence.index);
}
else {
randomStandSequence(target);
}
}
public static void randomPortraitSequence(final MdxComplexInstance target) {
final MdxModel model = (MdxModel) target.model;
final List<Sequence> sequences = model.getSequences();
final IndexedSequence sequence = selectSequence("portrait", sequences);
public static void randomPortraitTalkSequence(final MdxComplexInstance target) {
final MdxModel model = (MdxModel) target.model;
final List<Sequence> sequences = model.getSequences();
final IndexedSequence sequence = selectSequence("portrait talk", sequences);
if (sequence != null) {
target.setSequence(sequence.index);
} else {
randomStandSequence(target);
}
}
if (sequence != null) {
target.setSequence(sequence.index);
}
else {
randomPortraitSequence(target);
}
}
public static void randomPortraitTalkSequence(final MdxComplexInstance target) {
final MdxModel model = (MdxModel) target.model;
final List<Sequence> sequences = model.getSequences();
final IndexedSequence sequence = selectSequence("portrait talk", sequences);
public static void randomSequence(final MdxComplexInstance target, final String sequenceName) {
final MdxModel model = (MdxModel) target.model;
final List<Sequence> sequences = model.getSequences();
final IndexedSequence sequence = selectSequence(sequenceName, sequences);
if (sequence != null) {
target.setSequence(sequence.index);
} else {
randomPortraitSequence(target);
}
}
if (sequence != null) {
target.setSequence(sequence.index);
}
else {
randomStandSequence(target);
}
}
public static void randomSequence(final MdxComplexInstance target, final String sequenceName) {
final MdxModel model = (MdxModel) target.model;
final List<Sequence> sequences = model.getSequences();
final IndexedSequence sequence = selectSequence(sequenceName, sequences);
public static Sequence randomSequence(final MdxComplexInstance target, final PrimaryTag animationName,
final EnumSet<SecondaryTag> secondaryAnimationTags, final boolean allowRarityVariations) {
final MdxModel model = (MdxModel) target.model;
final List<Sequence> sequences = model.getSequences();
final IndexedSequence sequence = selectSequence(animationName, secondaryAnimationTags, sequences,
allowRarityVariations);
if (sequence != null) {
target.setSequence(sequence.index);
} else {
randomStandSequence(target);
}
}
if (sequence != null) {
target.setSequence(sequence.index);
return sequence.sequence;
}
else {
if (!secondaryAnimationTags.isEmpty()) {
return randomSequence(target, animationName, EMPTY, allowRarityVariations);
}
return null;
}
}
public static Sequence randomSequence(final MdxComplexInstance target, final PrimaryTag animationName,
final boolean allowRarityVariations) {
final MdxModel model = (MdxModel) target.model;
final List<Sequence> sequences = model.getSequences();
final IndexedSequence sequence = selectSequence(animationName, null, sequences,
allowRarityVariations);
public static Sequence randomSequence(final MdxComplexInstance target, final PrimaryTag animationName) {
return randomSequence(target, animationName, EMPTY, false);
}
if (sequence != null) {
target.setSequence(sequence.index);
return sequence.sequence;
} else {
return null;
}
}
public static Sequence randomSequence(final MdxComplexInstance target, final PrimaryTag animationName,
final EnumSet<SecondaryTag> secondaryAnimationTags, final boolean allowRarityVariations) {
final MdxModel model = (MdxModel) target.model;
final List<Sequence> sequences = model.getSequences();
final IndexedSequence sequence = selectSequence(animationName, secondaryAnimationTags, sequences,
allowRarityVariations);
if (sequence != null) {
target.setSequence(sequence.index);
return sequence.sequence;
} else {
return null;
}
}
public static Sequence randomSequence(final MdxComplexInstance target, final PrimaryTag animationName) {
return randomSequence(target, animationName, EMPTY, false);
}
}

View File

@ -61,7 +61,7 @@ public class TerrainShaders {
" vec3 terrain_normal = normalize(vNormal);//vec3(hL - hR, hD - hU, 2.0)+vNormal);\r\n" + //
"\r\n" + //
" Normal = terrain_normal;\r\n" + //
Shaders.lightSystem("Normal", "myposition.xyz", "lightTexture", "lightTextureHeight", "lightCount",
Shaders.lightSystem("terrain_normal", "myposition.xyz", "lightTexture", "lightTextureHeight", "lightCount",
true)
+ "\r\n" + //
" shadeColor = clamp(lightFactor, 0.0, 1.0);\r\n" + //

View File

@ -194,9 +194,6 @@ public class RenderUnit {
}
else {
currentWalkableUnder = map.getHighestWalkableUnder(x, y);
if (currentWalkableUnder != null) {
System.out.println("WALKABLE UNDER");
}
War3MapViewer.gdxRayHeap.set(x, y, 4096, 0, 0, -8192);
if ((currentWalkableUnder != null)
&& currentWalkableUnder.intersectRayWithCollision(War3MapViewer.gdxRayHeap,

View File

@ -13,75 +13,73 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityV
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
public class CommandCardPopulatingAbilityVisitor implements CAbilityVisitor<Void> {
public static final CommandCardPopulatingAbilityVisitor INSTANCE = new CommandCardPopulatingAbilityVisitor();
public static final CommandCardPopulatingAbilityVisitor INSTANCE = new CommandCardPopulatingAbilityVisitor();
private CSimulation game;
private CUnit unit;
private CSimulation game;
private CUnit unit;
private CommandButtonListener commandButtonListener;
private AbilityDataUI abilityDataUI;
private boolean hasStop;
private CommandButtonListener commandButtonListener;
private AbilityDataUI abilityDataUI;
private boolean hasStop;
public CommandCardPopulatingAbilityVisitor reset(final CSimulation game, final CUnit unit,
final CommandButtonListener commandButtonListener, final AbilityDataUI abilityDataUI) {
this.game = game;
this.unit = unit;
this.commandButtonListener = commandButtonListener;
this.abilityDataUI = abilityDataUI;
this.hasStop = false;
return this;
}
public CommandCardPopulatingAbilityVisitor reset(final CSimulation game, final CUnit unit,
final CommandButtonListener commandButtonListener, final AbilityDataUI abilityDataUI) {
this.game = game;
this.unit = unit;
this.commandButtonListener = commandButtonListener;
this.abilityDataUI = abilityDataUI;
this.hasStop = false;
return this;
}
@Override
public Void accept(final CAbilityAttack ability) {
addCommandButton(ability, this.abilityDataUI.getAttackUI(), ability.getHandleId(), OrderIds.attack, 0, false);
if (!this.hasStop) {
this.hasStop = true;
addCommandButton(null, this.abilityDataUI.getStopUI(), 0, OrderIds.stop, 0, false);
}
return null;
}
@Override
public Void accept(final CAbilityAttack ability) {
addCommandButton(ability, this.abilityDataUI.getAttackUI(), ability.getHandleId(), OrderIds.attack, 0, false);
if (!this.hasStop) {
this.hasStop = true;
addCommandButton(null, this.abilityDataUI.getStopUI(), 0, OrderIds.stop, 0, false);
}
return null;
}
@Override
public Void accept(final CAbilityMove ability) {
addCommandButton(ability, this.abilityDataUI.getMoveUI(), ability.getHandleId(), OrderIds.move, 0, false);
addCommandButton(ability, this.abilityDataUI.getHoldPosUI(), ability.getHandleId(), OrderIds.holdposition, 0,
false);
addCommandButton(ability, this.abilityDataUI.getPatrolUI(), ability.getHandleId(), OrderIds.patrol, 0, false);
if (!this.hasStop) {
this.hasStop = true;
addCommandButton(null, this.abilityDataUI.getStopUI(), 0, OrderIds.stop, 0, false);
}
return null;
}
@Override
public Void accept(final CAbilityMove ability) {
addCommandButton(ability, this.abilityDataUI.getMoveUI(), ability.getHandleId(), OrderIds.move, 0, false);
addCommandButton(ability, this.abilityDataUI.getHoldPosUI(), ability.getHandleId(), OrderIds.holdposition, 0,
false);
addCommandButton(ability, this.abilityDataUI.getPatrolUI(), ability.getHandleId(), OrderIds.patrol, 0, false);
if (!this.hasStop) {
this.hasStop = true;
addCommandButton(null, this.abilityDataUI.getStopUI(), 0, OrderIds.stop, 0, false);
}
return null;
}
@Override
public Void accept(final CAbilityGeneric ability) {
addCommandButton(ability, this.abilityDataUI.getUI(ability.getRawcode()).getOnIconUI(), ability.getHandleId(),
OrderIds.channel, 0, false);
return null;
}
@Override
public Void accept(final CAbilityGeneric ability) {
addCommandButton(ability, this.abilityDataUI.getUI(ability.getRawcode()).getOnIconUI(), ability.getHandleId(),
OrderIds.channel, 0, false);
return null;
}
@Override
public Void accept(final CAbilityColdArrows ability) {
final boolean autoCastActive = ability.isAutoCastActive();
int autoCastId;
if (autoCastActive) {
autoCastId = OrderIds.coldarrows;
}
else {
autoCastId = OrderIds.uncoldarrows;
}
addCommandButton(ability, this.abilityDataUI.getUI(ability.getRawcode()).getOnIconUI(), ability.getHandleId(),
OrderIds.coldarrowstarg, autoCastId, autoCastActive);
return null;
}
@Override
public Void accept(final CAbilityColdArrows ability) {
final boolean autoCastActive = ability.isAutoCastActive();
int autoCastId;
if (autoCastActive) {
autoCastId = OrderIds.coldarrows;
} else {
autoCastId = OrderIds.uncoldarrows;
}
addCommandButton(ability, this.abilityDataUI.getUI(ability.getRawcode()).getOnIconUI(), ability.getHandleId(),
OrderIds.coldarrowstarg, autoCastId, autoCastActive);
return null;
}
private void addCommandButton(final CAbility ability, final IconUI iconUI, final int handleId, final int orderId,
final int autoCastOrderId, final boolean autoCastActive) {
final boolean active = ((handleId == this.unit.getCurrentAbilityHandleId())
&& (orderId == this.unit.getCurrentOrderId()));
this.commandButtonListener.commandButton(iconUI.getButtonPositionX(), iconUI.getButtonPositionY(),
iconUI.getIcon(), handleId, orderId, autoCastOrderId, active, autoCastActive);
}
private void addCommandButton(final CAbility ability, final IconUI iconUI, final int handleId, final int orderId,
final int autoCastOrderId, final boolean autoCastActive) {
final boolean active = (this.unit.getCurrentBehavior() != null && orderId == this.unit.getCurrentBehavior().getHighlightOrderId());
this.commandButtonListener.commandButton(iconUI.getButtonPositionX(), iconUI.getButtonPositionY(),
iconUI.getIcon(), handleId, orderId, autoCastOrderId, active, autoCastActive);
}
}

View File

@ -6,6 +6,7 @@ import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.CyclicBarrier;
import com.badlogic.gdx.math.Rectangle;
import com.etheller.warsmash.util.War3ID;
@ -200,7 +201,11 @@ public class CUnit extends CWidget {
}
}
else if (this.currentBehavior != null) {
CBehavior lastBehavior = this.currentBehavior;
this.currentBehavior = this.currentBehavior.update(game);
if(this.currentBehavior.getHighlightOrderId() != lastBehavior.getHighlightOrderId()) {
this.stateNotifier.ordersChanged(getCurrentAbilityHandleId(), getCurrentOrderId());
}
}
else {
// check to auto acquire targets
@ -243,15 +248,15 @@ public class CUnit extends CWidget {
else {
this.currentBehavior = beginOrder(game, order);
this.orderQueue.clear();
final boolean omitNotify = (this.currentOrder == null) && (order == null);
if (!omitNotify) {
this.stateNotifier.ordersChanged(getCurrentAbilityHandleId(), getCurrentOrderId());
}
}
}
private CBehavior beginOrder(final CSimulation game, final COrder order) {
final boolean omitNotify = (this.currentOrder == null) && (order == null);
this.currentOrder = order;
if (!omitNotify) {
this.stateNotifier.ordersChanged(getCurrentAbilityHandleId(), getCurrentOrderId());
}
CBehavior nextBehavior;
if (order != null) {
nextBehavior = order.begin(game, this);
@ -426,7 +431,7 @@ public class CUnit extends CWidget {
CAllianceType.PASSIVE)) {
for (final CUnitAttack attack : this.unitType.getAttacks()) {
if (source.canBeTargetedBy(simulation, this, attack.getTargetsAllowed())) {
this.currentBehavior = getAttackBehavior().reset(attack, source);
this.currentBehavior = getAttackBehavior().reset(OrderIds.attack, attack, source);
break;
}
}
@ -590,7 +595,7 @@ public class CUnit extends CWidget {
if (this.source.canReach(unit, this.source.acquisitionRange)
&& unit.canBeTargetedBy(this.game, this.source, attack.getTargetsAllowed())
&& (this.source.distance(unit) >= this.source.getUnitType().getMinimumAttackRange())) {
this.source.currentBehavior = this.source.getAttackBehavior().reset(attack, unit);
this.source.currentBehavior = this.source.getAttackBehavior().reset(OrderIds.attack, attack, unit);
return true;
}
}

View File

@ -109,12 +109,12 @@ public class CAbilityAttack implements CAbility {
CBehavior behavior = null;
for (final CUnitAttack attack : caster.getUnitType().getAttacks()) {
if (target.canBeTargetedBy(game, caster, attack.getTargetsAllowed())) {
behavior = caster.getAttackBehavior().reset(attack, target);
behavior = caster.getAttackBehavior().reset(OrderIds.attack, attack, target);
break;
}
}
if (behavior == null) {
behavior = caster.getMoveBehavior().reset(target.getX(), target.getY());
behavior = caster.getMoveBehavior().reset(OrderIds.attack, target.getX(), target.getY());
}
return behavior;
}

View File

@ -94,7 +94,7 @@ public class CAbilityColdArrows implements CAbility {
CBehavior behavior = null;
for (final CUnitAttack attack : caster.getUnitType().getAttacks()) {
if (target.canBeTargetedBy(game, caster, attack.getTargetsAllowed())) {
behavior = caster.getAttackBehavior().reset(attack, target);
behavior = caster.getAttackBehavior().reset(OrderIds.coldarrowstarg, attack, target);
break;
}
}

View File

@ -87,7 +87,7 @@ public class CAbilityMove implements CAbility {
@Override
public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final CWidget target) {
return caster.getFollowBehavior().reset((CUnit) target);
return caster.getFollowBehavior().reset(OrderIds.move, (CUnit) target);
}
@Override
@ -96,7 +96,7 @@ public class CAbilityMove implements CAbility {
return caster.getPatrolBehavior().reset(point);
}
else {
return caster.getMoveBehavior().reset(point.x, point.y);
return caster.getMoveBehavior().reset(OrderIds.move, point.x, point.y);
}
}

View File

@ -10,4 +10,6 @@ public interface CBehavior {
* @return
*/
CBehavior update(CSimulation game);
int getHighlightOrderId();
}

View File

@ -10,6 +10,8 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUni
public class CBehaviorAttack extends CAbstractRangedBehavior {
private int highlightOrderId;
public CBehaviorAttack(final CUnit unit) {
super(unit);
}
@ -19,7 +21,8 @@ public class CBehaviorAttack extends CAbstractRangedBehavior {
private int backSwingTime;
private int thisOrderCooldownEndTime;
public CBehaviorAttack reset(final CUnitAttack unitAttack, final CWidget target) {
public CBehaviorAttack reset(int highlightOrderId, final CUnitAttack unitAttack, final CWidget target) {
this.highlightOrderId = highlightOrderId;
super.innerReset(target);
this.unitAttack = unitAttack;
this.damagePointLaunchTime = 0;
@ -28,6 +31,11 @@ public class CBehaviorAttack extends CAbstractRangedBehavior {
return this;
}
@Override
public int getHighlightOrderId() {
return highlightOrderId;
}
@Override
public boolean isWithinRange(final CSimulation simulation) {
float range = this.unitAttack.getRange();

View File

@ -7,14 +7,22 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
public class CBehaviorFollow extends CAbstractRangedBehavior {
private int higlightOrderId;
public CBehaviorFollow(final CUnit unit) {
super(unit);
}
public CBehavior reset(final CUnit target) {
public CBehavior reset(int higlightOrderId, final CUnit target) {
this.higlightOrderId = higlightOrderId;
return innerReset(target);
}
@Override
public int getHighlightOrderId() {
return higlightOrderId;
}
@Override
public boolean isWithinRange(final CSimulation simulation) {
return this.unit.canReach(this.target, this.unit.getAcquisitionRange());

View File

@ -18,6 +18,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.pathing.CPathfindin
public class CBehaviorMove implements CBehavior {
private static final Rectangle tempRect = new Rectangle();
private final CUnit unit;
private int highlightOrderId;
public CBehaviorMove(final CUnit unit) {
this.unit = unit;
@ -31,25 +32,34 @@ public class CBehaviorMove implements CBehavior {
private CUnit followUnit;
private CRangedBehavior rangedBehavior;
public CBehaviorMove reset(final float targetX, final float targetY) {
return reset(targetX, targetY, null);
public CBehaviorMove reset(int highlightOrderId, final float targetX, final float targetY) {
internalResetMove(highlightOrderId, targetX, targetY);
this.rangedBehavior = null;
return this;
}
public CBehaviorMove reset(final float targetX, final float targetY, final CRangedBehavior rangedBehavior) {
private void internalResetMove(int highlightOrderId, final float targetX, final float targetY) {
this.highlightOrderId = highlightOrderId;
this.wasWithinPropWindow = false;
this.gridMapping = CPathfindingProcessor.isCollisionSizeBetterSuitedForCorners(
this.unit.getUnitType().getCollisionSize()) ? CPathfindingProcessor.GridMapping.CORNERS
: CPathfindingProcessor.GridMapping.CELLS;
: CPathfindingProcessor.GridMapping.CELLS;
this.target = new Point2D.Float(targetX, targetY);
this.path = null;
this.searchCycles = 0;
this.followUnit = null;
}
public CBehaviorMove reset(final float targetX, final float targetY, final CRangedBehavior rangedBehavior) {
internalResetMove(rangedBehavior.getHighlightOrderId(), targetX, targetY);
this.rangedBehavior = rangedBehavior;
return this;
}
public CBehaviorMove reset(final CUnit followUnit) {
return reset(followUnit, null);
public CBehaviorMove reset(int highlightOrderId, final CUnit followUnit) {
internalResetMove(highlightOrderId, followUnit);
this.rangedBehavior = null;
return this;
}
public CBehaviorMove reset(final CUnit followUnit, final CRangedBehavior rangedBehavior) {
@ -65,6 +75,23 @@ public class CBehaviorMove implements CBehavior {
return this;
}
private void internalResetMove(int highlightOrderId, CUnit followUnit) {
this.highlightOrderId = highlightOrderId;
this.wasWithinPropWindow = false;
this.gridMapping = CPathfindingProcessor.isCollisionSizeBetterSuitedForCorners(
this.unit.getUnitType().getCollisionSize()) ? CPathfindingProcessor.GridMapping.CORNERS
: CPathfindingProcessor.GridMapping.CELLS;
this.target = new Float(followUnit.getX(), followUnit.getY());
this.path = null;
this.searchCycles = 0;
this.followUnit = followUnit;
}
@Override
public int getHighlightOrderId() {
return highlightOrderId;
}
@Override
public CBehavior update(final CSimulation simulation) {
if ((this.rangedBehavior != null) && this.rangedBehavior.isWithinRange(simulation)) {

View File

@ -3,6 +3,7 @@ package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors;
import com.badlogic.gdx.math.Vector2;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
public class CBehaviorPatrol implements CRangedBehavior {
@ -20,6 +21,11 @@ public class CBehaviorPatrol implements CRangedBehavior {
return this;
}
@Override
public int getHighlightOrderId() {
return OrderIds.patrol;
}
@Override
public boolean isWithinRange(final CSimulation simulation) {
return this.unit.distance(this.target.x, this.target.y) <= simulation.getGameplayConstants()

View File

@ -4,6 +4,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens.PrimaryTag;
import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CSimulation;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnit;
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds;
public class CBehaviorStop implements CBehavior {
@ -13,8 +14,14 @@ public class CBehaviorStop implements CBehavior {
this.unit = unit;
}
@Override
public int getHighlightOrderId() {
return OrderIds.stop;
}
@Override
public CBehavior update(final CSimulation game) {
this.unit.autoAcquireAttackTargets(game);
this.unit.getUnitAnimationListener().playAnimation(false, PrimaryTag.STAND, SequenceUtils.EMPTY, 1.0f, true);
return this.unit.pollNextOrderBehavior(game);
}

View File

@ -32,410 +32,410 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUni
import com.etheller.warsmash.viewer5.handlers.w3x.simulation.util.SimulationRenderController;
public class CUnitData {
private static final War3ID MANA_INITIAL_AMOUNT = War3ID.fromString("umpi");
private static final War3ID MANA_MAXIMUM = War3ID.fromString("umpm");
private static final War3ID HIT_POINT_MAXIMUM = War3ID.fromString("uhpm");
private static final War3ID MOVEMENT_SPEED_BASE = War3ID.fromString("umvs");
private static final War3ID PROPULSION_WINDOW = War3ID.fromString("uprw");
private static final War3ID TURN_RATE = War3ID.fromString("umvr");
private static final War3ID IS_BLDG = War3ID.fromString("ubdg");
private static final War3ID NAME = War3ID.fromString("unam");
private static final War3ID PROJECTILE_LAUNCH_X = War3ID.fromString("ulpx");
private static final War3ID PROJECTILE_LAUNCH_Y = War3ID.fromString("ulpy");
private static final War3ID PROJECTILE_LAUNCH_Z = War3ID.fromString("ulpz");
private static final War3ID ATTACKS_ENABLED = War3ID.fromString("uaen");
private static final War3ID ATTACK1_BACKSWING_POINT = War3ID.fromString("ubs1");
private static final War3ID ATTACK1_DAMAGE_POINT = War3ID.fromString("udp1");
private static final War3ID ATTACK1_AREA_OF_EFFECT_FULL_DMG = War3ID.fromString("ua1f");
private static final War3ID ATTACK1_AREA_OF_EFFECT_HALF_DMG = War3ID.fromString("ua1h");
private static final War3ID ATTACK1_AREA_OF_EFFECT_QUARTER_DMG = War3ID.fromString("ua1q");
private static final War3ID ATTACK1_AREA_OF_EFFECT_TARGETS = War3ID.fromString("ua1p");
private static final War3ID ATTACK1_ATTACK_TYPE = War3ID.fromString("ua1t");
private static final War3ID ATTACK1_COOLDOWN = War3ID.fromString("ua1c");
private static final War3ID ATTACK1_DMG_BASE = War3ID.fromString("ua1b");
private static final War3ID ATTACK1_DAMAGE_FACTOR_HALF = War3ID.fromString("uhd1");
private static final War3ID ATTACK1_DAMAGE_FACTOR_QUARTER = War3ID.fromString("uqd1");
private static final War3ID ATTACK1_DAMAGE_LOSS_FACTOR = War3ID.fromString("udl1");
private static final War3ID ATTACK1_DMG_DICE = War3ID.fromString("ua1d");
private static final War3ID ATTACK1_DMG_SIDES_PER_DIE = War3ID.fromString("ua1s");
private static final War3ID ATTACK1_DMG_SPILL_DIST = War3ID.fromString("usd1");
private static final War3ID ATTACK1_DMG_SPILL_RADIUS = War3ID.fromString("usr1");
private static final War3ID ATTACK1_DMG_UPGRADE_AMT = War3ID.fromString("udu1");
private static final War3ID ATTACK1_TARGET_COUNT = War3ID.fromString("utc1");
private static final War3ID ATTACK1_PROJECTILE_ARC = War3ID.fromString("uma1");
private static final War3ID ATTACK1_MISSILE_ART = War3ID.fromString("ua1m");
private static final War3ID ATTACK1_PROJECTILE_HOMING_ENABLED = War3ID.fromString("umh1");
private static final War3ID ATTACK1_PROJECTILE_SPEED = War3ID.fromString("ua1z");
private static final War3ID ATTACK1_RANGE = War3ID.fromString("ua1r");
private static final War3ID ATTACK1_RANGE_MOTION_BUFFER = War3ID.fromString("urb1");
private static final War3ID ATTACK1_SHOW_UI = War3ID.fromString("uwu1");
private static final War3ID ATTACK1_TARGETS_ALLOWED = War3ID.fromString("ua1g");
private static final War3ID ATTACK1_WEAPON_SOUND = War3ID.fromString("ucs1");
private static final War3ID ATTACK1_WEAPON_TYPE = War3ID.fromString("ua1w");
private static final War3ID MANA_INITIAL_AMOUNT = War3ID.fromString("umpi");
private static final War3ID MANA_MAXIMUM = War3ID.fromString("umpm");
private static final War3ID HIT_POINT_MAXIMUM = War3ID.fromString("uhpm");
private static final War3ID MOVEMENT_SPEED_BASE = War3ID.fromString("umvs");
private static final War3ID PROPULSION_WINDOW = War3ID.fromString("uprw");
private static final War3ID TURN_RATE = War3ID.fromString("umvr");
private static final War3ID IS_BLDG = War3ID.fromString("ubdg");
private static final War3ID NAME = War3ID.fromString("unam");
private static final War3ID PROJECTILE_LAUNCH_X = War3ID.fromString("ulpx");
private static final War3ID PROJECTILE_LAUNCH_Y = War3ID.fromString("ulpy");
private static final War3ID PROJECTILE_LAUNCH_Z = War3ID.fromString("ulpz");
private static final War3ID ATTACKS_ENABLED = War3ID.fromString("uaen");
private static final War3ID ATTACK1_BACKSWING_POINT = War3ID.fromString("ubs1");
private static final War3ID ATTACK1_DAMAGE_POINT = War3ID.fromString("udp1");
private static final War3ID ATTACK1_AREA_OF_EFFECT_FULL_DMG = War3ID.fromString("ua1f");
private static final War3ID ATTACK1_AREA_OF_EFFECT_HALF_DMG = War3ID.fromString("ua1h");
private static final War3ID ATTACK1_AREA_OF_EFFECT_QUARTER_DMG = War3ID.fromString("ua1q");
private static final War3ID ATTACK1_AREA_OF_EFFECT_TARGETS = War3ID.fromString("ua1p");
private static final War3ID ATTACK1_ATTACK_TYPE = War3ID.fromString("ua1t");
private static final War3ID ATTACK1_COOLDOWN = War3ID.fromString("ua1c");
private static final War3ID ATTACK1_DMG_BASE = War3ID.fromString("ua1b");
private static final War3ID ATTACK1_DAMAGE_FACTOR_HALF = War3ID.fromString("uhd1");
private static final War3ID ATTACK1_DAMAGE_FACTOR_QUARTER = War3ID.fromString("uqd1");
private static final War3ID ATTACK1_DAMAGE_LOSS_FACTOR = War3ID.fromString("udl1");
private static final War3ID ATTACK1_DMG_DICE = War3ID.fromString("ua1d");
private static final War3ID ATTACK1_DMG_SIDES_PER_DIE = War3ID.fromString("ua1s");
private static final War3ID ATTACK1_DMG_SPILL_DIST = War3ID.fromString("usd1");
private static final War3ID ATTACK1_DMG_SPILL_RADIUS = War3ID.fromString("usr1");
private static final War3ID ATTACK1_DMG_UPGRADE_AMT = War3ID.fromString("udu1");
private static final War3ID ATTACK1_TARGET_COUNT = War3ID.fromString("utc1");
private static final War3ID ATTACK1_PROJECTILE_ARC = War3ID.fromString("uma1");
private static final War3ID ATTACK1_MISSILE_ART = War3ID.fromString("ua1m");
private static final War3ID ATTACK1_PROJECTILE_HOMING_ENABLED = War3ID.fromString("umh1");
private static final War3ID ATTACK1_PROJECTILE_SPEED = War3ID.fromString("ua1z");
private static final War3ID ATTACK1_RANGE = War3ID.fromString("ua1r");
private static final War3ID ATTACK1_RANGE_MOTION_BUFFER = War3ID.fromString("urb1");
private static final War3ID ATTACK1_SHOW_UI = War3ID.fromString("uwu1");
private static final War3ID ATTACK1_TARGETS_ALLOWED = War3ID.fromString("ua1g");
private static final War3ID ATTACK1_WEAPON_SOUND = War3ID.fromString("ucs1");
private static final War3ID ATTACK1_WEAPON_TYPE = War3ID.fromString("ua1w");
private static final War3ID ATTACK2_BACKSWING_POINT = War3ID.fromString("ubs2");
private static final War3ID ATTACK2_DAMAGE_POINT = War3ID.fromString("udp2");
private static final War3ID ATTACK2_AREA_OF_EFFECT_FULL_DMG = War3ID.fromString("ua2f");
private static final War3ID ATTACK2_AREA_OF_EFFECT_HALF_DMG = War3ID.fromString("ua2h");
private static final War3ID ATTACK2_AREA_OF_EFFECT_QUARTER_DMG = War3ID.fromString("ua2q");
private static final War3ID ATTACK2_AREA_OF_EFFECT_TARGETS = War3ID.fromString("ua2p");
private static final War3ID ATTACK2_ATTACK_TYPE = War3ID.fromString("ua2t");
private static final War3ID ATTACK2_COOLDOWN = War3ID.fromString("ua2c");
private static final War3ID ATTACK2_DMG_BASE = War3ID.fromString("ua2b");
private static final War3ID ATTACK2_DAMAGE_FACTOR_HALF = War3ID.fromString("uhd2");
private static final War3ID ATTACK2_DAMAGE_FACTOR_QUARTER = War3ID.fromString("uqd2");
private static final War3ID ATTACK2_DAMAGE_LOSS_FACTOR = War3ID.fromString("udl2");
private static final War3ID ATTACK2_DMG_DICE = War3ID.fromString("ua2d");
private static final War3ID ATTACK2_DMG_SIDES_PER_DIE = War3ID.fromString("ua2s");
private static final War3ID ATTACK2_DMG_SPILL_DIST = War3ID.fromString("usd2");
private static final War3ID ATTACK2_DMG_SPILL_RADIUS = War3ID.fromString("usr2");
private static final War3ID ATTACK2_DMG_UPGRADE_AMT = War3ID.fromString("udu2");
private static final War3ID ATTACK2_TARGET_COUNT = War3ID.fromString("utc2");
private static final War3ID ATTACK2_PROJECTILE_ARC = War3ID.fromString("uma2");
private static final War3ID ATTACK2_MISSILE_ART = War3ID.fromString("ua2m");
private static final War3ID ATTACK2_PROJECTILE_HOMING_ENABLED = War3ID.fromString("umh2");
private static final War3ID ATTACK2_PROJECTILE_SPEED = War3ID.fromString("ua2z");
private static final War3ID ATTACK2_RANGE = War3ID.fromString("ua2r");
private static final War3ID ATTACK2_RANGE_MOTION_BUFFER = War3ID.fromString("urb2");
private static final War3ID ATTACK2_SHOW_UI = War3ID.fromString("uwu2");
private static final War3ID ATTACK2_TARGETS_ALLOWED = War3ID.fromString("ua2g");
private static final War3ID ATTACK2_WEAPON_SOUND = War3ID.fromString("ucs2");
private static final War3ID ATTACK2_WEAPON_TYPE = War3ID.fromString("ua2w");
private static final War3ID ATTACK2_BACKSWING_POINT = War3ID.fromString("ubs2");
private static final War3ID ATTACK2_DAMAGE_POINT = War3ID.fromString("udp2");
private static final War3ID ATTACK2_AREA_OF_EFFECT_FULL_DMG = War3ID.fromString("ua2f");
private static final War3ID ATTACK2_AREA_OF_EFFECT_HALF_DMG = War3ID.fromString("ua2h");
private static final War3ID ATTACK2_AREA_OF_EFFECT_QUARTER_DMG = War3ID.fromString("ua2q");
private static final War3ID ATTACK2_AREA_OF_EFFECT_TARGETS = War3ID.fromString("ua2p");
private static final War3ID ATTACK2_ATTACK_TYPE = War3ID.fromString("ua2t");
private static final War3ID ATTACK2_COOLDOWN = War3ID.fromString("ua2c");
private static final War3ID ATTACK2_DMG_BASE = War3ID.fromString("ua2b");
private static final War3ID ATTACK2_DAMAGE_FACTOR_HALF = War3ID.fromString("uhd2");
private static final War3ID ATTACK2_DAMAGE_FACTOR_QUARTER = War3ID.fromString("uqd2");
private static final War3ID ATTACK2_DAMAGE_LOSS_FACTOR = War3ID.fromString("udl2");
private static final War3ID ATTACK2_DMG_DICE = War3ID.fromString("ua2d");
private static final War3ID ATTACK2_DMG_SIDES_PER_DIE = War3ID.fromString("ua2s");
private static final War3ID ATTACK2_DMG_SPILL_DIST = War3ID.fromString("usd2");
private static final War3ID ATTACK2_DMG_SPILL_RADIUS = War3ID.fromString("usr2");
private static final War3ID ATTACK2_DMG_UPGRADE_AMT = War3ID.fromString("udu2");
private static final War3ID ATTACK2_TARGET_COUNT = War3ID.fromString("utc2");
private static final War3ID ATTACK2_PROJECTILE_ARC = War3ID.fromString("uma2");
private static final War3ID ATTACK2_MISSILE_ART = War3ID.fromString("ua2m");
private static final War3ID ATTACK2_PROJECTILE_HOMING_ENABLED = War3ID.fromString("umh2");
private static final War3ID ATTACK2_PROJECTILE_SPEED = War3ID.fromString("ua2z");
private static final War3ID ATTACK2_RANGE = War3ID.fromString("ua2r");
private static final War3ID ATTACK2_RANGE_MOTION_BUFFER = War3ID.fromString("urb2");
private static final War3ID ATTACK2_SHOW_UI = War3ID.fromString("uwu2");
private static final War3ID ATTACK2_TARGETS_ALLOWED = War3ID.fromString("ua2g");
private static final War3ID ATTACK2_WEAPON_SOUND = War3ID.fromString("ucs2");
private static final War3ID ATTACK2_WEAPON_TYPE = War3ID.fromString("ua2w");
private static final War3ID ACQUISITION_RANGE = War3ID.fromString("uacq");
private static final War3ID MINIMUM_ATTACK_RANGE = War3ID.fromString("uamn");
private static final War3ID ACQUISITION_RANGE = War3ID.fromString("uacq");
private static final War3ID MINIMUM_ATTACK_RANGE = War3ID.fromString("uamn");
private static final War3ID PROJECTILE_IMPACT_Z = War3ID.fromString("uimz");
private static final War3ID PROJECTILE_IMPACT_Z = War3ID.fromString("uimz");
private static final War3ID DEATH_TYPE = War3ID.fromString("udea");
private static final War3ID ARMOR_TYPE = War3ID.fromString("uarm");
private static final War3ID DEATH_TYPE = War3ID.fromString("udea");
private static final War3ID ARMOR_TYPE = War3ID.fromString("uarm");
private static final War3ID DEFENSE = War3ID.fromString("udef");
private static final War3ID DEFENSE_TYPE = War3ID.fromString("udty");
private static final War3ID MOVE_HEIGHT = War3ID.fromString("umvh");
private static final War3ID MOVE_TYPE = War3ID.fromString("umvt");
private static final War3ID COLLISION_SIZE = War3ID.fromString("ucol");
private static final War3ID CLASSIFICATION = War3ID.fromString("utyp");
private static final War3ID DEATH_TIME = War3ID.fromString("udtm");
private static final War3ID TARGETED_AS = War3ID.fromString("utar");
private static final War3ID DEFENSE = War3ID.fromString("udef");
private static final War3ID DEFENSE_TYPE = War3ID.fromString("udty");
private static final War3ID MOVE_HEIGHT = War3ID.fromString("umvh");
private static final War3ID MOVE_TYPE = War3ID.fromString("umvt");
private static final War3ID COLLISION_SIZE = War3ID.fromString("ucol");
private static final War3ID CLASSIFICATION = War3ID.fromString("utyp");
private static final War3ID DEATH_TIME = War3ID.fromString("udtm");
private static final War3ID TARGETED_AS = War3ID.fromString("utar");
private static final War3ID ABILITIES_NORMAL = War3ID.fromString("uabi");
private final MutableObjectData unitData;
private final Map<War3ID, CUnitType> unitIdToUnitType = new HashMap<>();
private final CAbilityData abilityData;
private static final War3ID ABILITIES_NORMAL = War3ID.fromString("uabi");
private final MutableObjectData unitData;
private final Map<War3ID, CUnitType> unitIdToUnitType = new HashMap<>();
private final CAbilityData abilityData;
public CUnitData(final MutableObjectData unitData, final CAbilityData abilityData) {
this.unitData = unitData;
this.abilityData = abilityData;
}
public CUnitData(final MutableObjectData unitData, final CAbilityData abilityData) {
this.unitData = unitData;
this.abilityData = abilityData;
}
public CUnit create(final CSimulation simulation, final int playerIndex, final War3ID typeId, final float x,
final float y, final float facing, final BufferedImage buildingPathingPixelMap,
final SimulationRenderController simulationRenderController, final HandleIdAllocator handleIdAllocator) {
final MutableGameObject unitType = this.unitData.get(typeId);
final int handleId = handleIdAllocator.createId();
final int life = unitType.getFieldAsInteger(HIT_POINT_MAXIMUM, 0);
final int manaInitial = unitType.getFieldAsInteger(MANA_INITIAL_AMOUNT, 0);
final int manaMaximum = unitType.getFieldAsInteger(MANA_MAXIMUM, 0);
final int speed = unitType.getFieldAsInteger(MOVEMENT_SPEED_BASE, 0);
final int defense = unitType.getFieldAsInteger(DEFENSE, 0);
final String abilityList = unitType.getFieldAsString(ABILITIES_NORMAL, 0);
public CUnit create(final CSimulation simulation, final int playerIndex, final War3ID typeId, final float x,
final float y, final float facing, final BufferedImage buildingPathingPixelMap,
final SimulationRenderController simulationRenderController, final HandleIdAllocator handleIdAllocator) {
final MutableGameObject unitType = this.unitData.get(typeId);
final int handleId = handleIdAllocator.createId();
final int life = unitType.getFieldAsInteger(HIT_POINT_MAXIMUM, 0);
final int manaInitial = unitType.getFieldAsInteger(MANA_INITIAL_AMOUNT, 0);
final int manaMaximum = unitType.getFieldAsInteger(MANA_MAXIMUM, 0);
final int speed = unitType.getFieldAsInteger(MOVEMENT_SPEED_BASE, 0);
final int defense = unitType.getFieldAsInteger(DEFENSE, 0);
final String abilityList = unitType.getFieldAsString(ABILITIES_NORMAL, 0);
final CUnitType unitTypeInstance = getUnitTypeInstance(typeId, buildingPathingPixelMap, unitType);
final CUnitType unitTypeInstance = getUnitTypeInstance(typeId, buildingPathingPixelMap, unitType);
final CUnit unit = new CUnit(handleId, playerIndex, x, y, life, typeId, facing, manaInitial, life, manaMaximum,
speed, defense, unitTypeInstance);
if (speed > 0) {
unit.add(simulation, new CAbilityMove(handleIdAllocator.createId()));
}
if (!unitTypeInstance.getAttacks().isEmpty()) {
unit.add(simulation, new CAbilityAttack(handleIdAllocator.createId()));
}
for (final String ability : abilityList.split(",")) {
unit.add(simulation, this.abilityData.createAbility(ability, handleIdAllocator.createId()));
}
return unit;
}
final CUnit unit = new CUnit(handleId, playerIndex, x, y, life, typeId, facing, manaInitial, life, manaMaximum,
speed, defense, unitTypeInstance);
if (speed > 0) {
unit.add(simulation, new CAbilityMove(handleIdAllocator.createId()));
}
if (!unitTypeInstance.getAttacks().isEmpty()) {
unit.add(simulation, new CAbilityAttack(handleIdAllocator.createId()));
}
for (final String ability : abilityList.split(",")) {
if (ability.length() > 0 && !"_".equals(ability)) {
unit.add(simulation, this.abilityData.createAbility(ability, handleIdAllocator.createId()));
}
}
return unit;
}
private CUnitType getUnitTypeInstance(final War3ID typeId, final BufferedImage buildingPathingPixelMap,
final MutableGameObject unitType) {
CUnitType unitTypeInstance = this.unitIdToUnitType.get(typeId);
if (unitTypeInstance == null) {
final float moveHeight = unitType.getFieldAsFloat(MOVE_HEIGHT, 0);
final String movetp = unitType.getFieldAsString(MOVE_TYPE, 0);
final float collisionSize = unitType.getFieldAsFloat(COLLISION_SIZE, 0);
final boolean isBldg = unitType.getFieldAsBoolean(IS_BLDG, 0);
final PathingGrid.MovementType movementType = PathingGrid.getMovementType(movetp);
final String unitName = unitType.getFieldAsString(NAME, 0);
final float acquisitionRange = unitType.getFieldAsFloat(ACQUISITION_RANGE, 0);
final float minimumAttackRange = unitType.getFieldAsFloat(MINIMUM_ATTACK_RANGE, 0);
final EnumSet<CTargetType> targetedAs = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(TARGETED_AS, 0));
final String classificationString = unitType.getFieldAsString(CLASSIFICATION, 0);
final EnumSet<CUnitClassification> classifications = EnumSet.noneOf(CUnitClassification.class);
if (classificationString != null) {
final String[] classificationValues = classificationString.split(",");
for (final String unitEditorKey : classificationValues) {
final CUnitClassification unitClassification = CUnitClassification
.parseUnitClassification(unitEditorKey);
if (unitClassification != null) {
classifications.add(unitClassification);
}
}
}
final List<CUnitAttack> attacks = new ArrayList<>();
final int attacksEnabled = unitType.getFieldAsInteger(ATTACKS_ENABLED, 0);
if ((attacksEnabled & 0x1) != 0) {
try {
// attack one
final float animationBackswingPoint = unitType.getFieldAsFloat(ATTACK1_BACKSWING_POINT, 0);
final float animationDamagePoint = unitType.getFieldAsFloat(ATTACK1_DAMAGE_POINT, 0);
final int areaOfEffectFullDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_FULL_DMG, 0);
final int areaOfEffectMediumDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_HALF_DMG, 0);
final int areaOfEffectSmallDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_QUARTER_DMG,
0);
final EnumSet<CTargetType> areaOfEffectTargets = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK1_AREA_OF_EFFECT_TARGETS, 0));
final CAttackType attackType = CAttackType
.parseAttackType(unitType.getFieldAsString(ATTACK1_ATTACK_TYPE, 0));
final float cooldownTime = unitType.getFieldAsFloat(ATTACK1_COOLDOWN, 0);
final int damageBase = unitType.getFieldAsInteger(ATTACK1_DMG_BASE, 0);
final float damageFactorMedium = unitType.getFieldAsFloat(ATTACK1_DAMAGE_FACTOR_HALF, 0);
final float damageFactorSmall = unitType.getFieldAsFloat(ATTACK1_DAMAGE_FACTOR_QUARTER, 0);
final float damageLossFactor = unitType.getFieldAsFloat(ATTACK1_DAMAGE_LOSS_FACTOR, 0);
final int damageDice = unitType.getFieldAsInteger(ATTACK1_DMG_DICE, 0);
final int damageSidesPerDie = unitType.getFieldAsInteger(ATTACK1_DMG_SIDES_PER_DIE, 0);
final float damageSpillDistance = unitType.getFieldAsFloat(ATTACK1_DMG_SPILL_DIST, 0);
final float damageSpillRadius = unitType.getFieldAsFloat(ATTACK1_DMG_SPILL_RADIUS, 0);
final int damageUpgradeAmount = unitType.getFieldAsInteger(ATTACK1_DMG_UPGRADE_AMT, 0);
final int maximumNumberOfTargets = unitType.getFieldAsInteger(ATTACK1_TARGET_COUNT, 0);
final float projectileArc = unitType.getFieldAsFloat(ATTACK1_PROJECTILE_ARC, 0);
final String projectileArt = unitType.getFieldAsString(ATTACK1_MISSILE_ART, 0);
final boolean projectileHomingEnabled = unitType
.getFieldAsBoolean(ATTACK1_PROJECTILE_HOMING_ENABLED, 0);
final int projectileSpeed = unitType.getFieldAsInteger(ATTACK1_PROJECTILE_SPEED, 0);
final int range = unitType.getFieldAsInteger(ATTACK1_RANGE, 0);
final float rangeMotionBuffer = unitType.getFieldAsFloat(ATTACK1_RANGE_MOTION_BUFFER, 0);
final boolean showUI = unitType.getFieldAsBoolean(ATTACK1_SHOW_UI, 0);
final EnumSet<CTargetType> targetsAllowed = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK1_TARGETS_ALLOWED, 0));
final String weaponSound = unitType.getFieldAsString(ATTACK1_WEAPON_SOUND, 0);
final CWeaponType weaponType = CWeaponType
.parseWeaponType(unitType.getFieldAsString(ATTACK1_WEAPON_TYPE, 0));
attacks.add(createAttack(animationBackswingPoint, animationDamagePoint, areaOfEffectFullDamage,
areaOfEffectMediumDamage, areaOfEffectSmallDamage, areaOfEffectTargets, attackType,
cooldownTime, damageBase, damageFactorMedium, damageFactorSmall, damageLossFactor,
damageDice, damageSidesPerDie, damageSpillDistance, damageSpillRadius, damageUpgradeAmount,
maximumNumberOfTargets, projectileArc, projectileArt, projectileHomingEnabled,
projectileSpeed, range, rangeMotionBuffer, showUI, targetsAllowed, weaponSound,
weaponType));
}
catch (final Exception exc) {
System.err.println("Attack 1 failed to parse with: " + exc.getClass() + ":" + exc.getMessage());
}
}
if ((attacksEnabled & 0x2) != 0) {
try {
// attack two
final float animationBackswingPoint = unitType.getFieldAsFloat(ATTACK2_BACKSWING_POINT, 0);
final float animationDamagePoint = unitType.getFieldAsFloat(ATTACK2_DAMAGE_POINT, 0);
final int areaOfEffectFullDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_FULL_DMG, 0);
final int areaOfEffectMediumDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_HALF_DMG, 0);
final int areaOfEffectSmallDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_QUARTER_DMG,
0);
final EnumSet<CTargetType> areaOfEffectTargets = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK2_AREA_OF_EFFECT_TARGETS, 0));
final CAttackType attackType = CAttackType
.parseAttackType(unitType.getFieldAsString(ATTACK2_ATTACK_TYPE, 0));
final float cooldownTime = unitType.getFieldAsFloat(ATTACK2_COOLDOWN, 0);
final int damageBase = unitType.getFieldAsInteger(ATTACK2_DMG_BASE, 0);
final float damageFactorMedium = unitType.getFieldAsFloat(ATTACK2_DAMAGE_FACTOR_HALF, 0);
final float damageFactorSmall = unitType.getFieldAsFloat(ATTACK2_DAMAGE_FACTOR_QUARTER, 0);
final float damageLossFactor = unitType.getFieldAsFloat(ATTACK2_DAMAGE_LOSS_FACTOR, 0);
final int damageDice = unitType.getFieldAsInteger(ATTACK2_DMG_DICE, 0);
final int damageSidesPerDie = unitType.getFieldAsInteger(ATTACK2_DMG_SIDES_PER_DIE, 0);
final float damageSpillDistance = unitType.getFieldAsFloat(ATTACK2_DMG_SPILL_DIST, 0);
final float damageSpillRadius = unitType.getFieldAsFloat(ATTACK2_DMG_SPILL_RADIUS, 0);
final int damageUpgradeAmount = unitType.getFieldAsInteger(ATTACK2_DMG_UPGRADE_AMT, 0);
final int maximumNumberOfTargets = unitType.getFieldAsInteger(ATTACK2_TARGET_COUNT, 0);
final float projectileArc = unitType.getFieldAsFloat(ATTACK2_PROJECTILE_ARC, 0);
final String projectileArt = unitType.getFieldAsString(ATTACK2_MISSILE_ART, 0);
final boolean projectileHomingEnabled = unitType
.getFieldAsBoolean(ATTACK2_PROJECTILE_HOMING_ENABLED, 0);
final int projectileSpeed = unitType.getFieldAsInteger(ATTACK2_PROJECTILE_SPEED, 0);
final int range = unitType.getFieldAsInteger(ATTACK2_RANGE, 0);
final float rangeMotionBuffer = unitType.getFieldAsFloat(ATTACK2_RANGE_MOTION_BUFFER, 0);
final boolean showUI = unitType.getFieldAsBoolean(ATTACK2_SHOW_UI, 0);
final EnumSet<CTargetType> targetsAllowed = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK2_TARGETS_ALLOWED, 0));
final String weaponSound = unitType.getFieldAsString(ATTACK2_WEAPON_SOUND, 0);
final CWeaponType weaponType = CWeaponType
.parseWeaponType(unitType.getFieldAsString(ATTACK2_WEAPON_TYPE, 0));
attacks.add(createAttack(animationBackswingPoint, animationDamagePoint, areaOfEffectFullDamage,
areaOfEffectMediumDamage, areaOfEffectSmallDamage, areaOfEffectTargets, attackType,
cooldownTime, damageBase, damageFactorMedium, damageFactorSmall, damageLossFactor,
damageDice, damageSidesPerDie, damageSpillDistance, damageSpillRadius, damageUpgradeAmount,
maximumNumberOfTargets, projectileArc, projectileArt, projectileHomingEnabled,
projectileSpeed, range, rangeMotionBuffer, showUI, targetsAllowed, weaponSound,
weaponType));
}
catch (final Exception exc) {
System.err.println("Attack 2 failed to parse with: " + exc.getClass() + ":" + exc.getMessage());
}
}
final int deathType = unitType.getFieldAsInteger(DEATH_TYPE, 0);
final boolean raise = (deathType & 0x1) != 0;
final boolean decay = (deathType & 0x2) != 0;
final String armorType = unitType.getFieldAsString(ARMOR_TYPE, 0);
final float impactZ = unitType.getFieldAsFloat(PROJECTILE_IMPACT_Z, 0);
final CDefenseType defenseType = CDefenseType.parseDefenseType(unitType.getFieldAsString(DEFENSE_TYPE, 0));
final float deathTime = unitType.getFieldAsFloat(DEATH_TIME, 0);
unitTypeInstance = new CUnitType(unitName, isBldg, movementType, moveHeight, collisionSize, classifications,
attacks, armorType, raise, decay, defenseType, impactZ, buildingPathingPixelMap, deathTime,
targetedAs, acquisitionRange, minimumAttackRange);
this.unitIdToUnitType.put(typeId, unitTypeInstance);
}
return unitTypeInstance;
}
private CUnitType getUnitTypeInstance(final War3ID typeId, final BufferedImage buildingPathingPixelMap,
final MutableGameObject unitType) {
CUnitType unitTypeInstance = this.unitIdToUnitType.get(typeId);
if (unitTypeInstance == null) {
final float moveHeight = unitType.getFieldAsFloat(MOVE_HEIGHT, 0);
final String movetp = unitType.getFieldAsString(MOVE_TYPE, 0);
final float collisionSize = unitType.getFieldAsFloat(COLLISION_SIZE, 0);
final boolean isBldg = unitType.getFieldAsBoolean(IS_BLDG, 0);
final PathingGrid.MovementType movementType = PathingGrid.getMovementType(movetp);
final String unitName = unitType.getFieldAsString(NAME, 0);
final float acquisitionRange = unitType.getFieldAsFloat(ACQUISITION_RANGE, 0);
final float minimumAttackRange = unitType.getFieldAsFloat(MINIMUM_ATTACK_RANGE, 0);
final EnumSet<CTargetType> targetedAs = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(TARGETED_AS, 0));
final String classificationString = unitType.getFieldAsString(CLASSIFICATION, 0);
final EnumSet<CUnitClassification> classifications = EnumSet.noneOf(CUnitClassification.class);
if (classificationString != null) {
final String[] classificationValues = classificationString.split(",");
for (final String unitEditorKey : classificationValues) {
final CUnitClassification unitClassification = CUnitClassification
.parseUnitClassification(unitEditorKey);
if (unitClassification != null) {
classifications.add(unitClassification);
}
}
}
final List<CUnitAttack> attacks = new ArrayList<>();
final int attacksEnabled = unitType.getFieldAsInteger(ATTACKS_ENABLED, 0);
if ((attacksEnabled & 0x1) != 0) {
try {
// attack one
final float animationBackswingPoint = unitType.getFieldAsFloat(ATTACK1_BACKSWING_POINT, 0);
final float animationDamagePoint = unitType.getFieldAsFloat(ATTACK1_DAMAGE_POINT, 0);
final int areaOfEffectFullDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_FULL_DMG, 0);
final int areaOfEffectMediumDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_HALF_DMG, 0);
final int areaOfEffectSmallDamage = unitType.getFieldAsInteger(ATTACK1_AREA_OF_EFFECT_QUARTER_DMG,
0);
final EnumSet<CTargetType> areaOfEffectTargets = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK1_AREA_OF_EFFECT_TARGETS, 0));
final CAttackType attackType = CAttackType
.parseAttackType(unitType.getFieldAsString(ATTACK1_ATTACK_TYPE, 0));
final float cooldownTime = unitType.getFieldAsFloat(ATTACK1_COOLDOWN, 0);
final int damageBase = unitType.getFieldAsInteger(ATTACK1_DMG_BASE, 0);
final float damageFactorMedium = unitType.getFieldAsFloat(ATTACK1_DAMAGE_FACTOR_HALF, 0);
final float damageFactorSmall = unitType.getFieldAsFloat(ATTACK1_DAMAGE_FACTOR_QUARTER, 0);
final float damageLossFactor = unitType.getFieldAsFloat(ATTACK1_DAMAGE_LOSS_FACTOR, 0);
final int damageDice = unitType.getFieldAsInteger(ATTACK1_DMG_DICE, 0);
final int damageSidesPerDie = unitType.getFieldAsInteger(ATTACK1_DMG_SIDES_PER_DIE, 0);
final float damageSpillDistance = unitType.getFieldAsFloat(ATTACK1_DMG_SPILL_DIST, 0);
final float damageSpillRadius = unitType.getFieldAsFloat(ATTACK1_DMG_SPILL_RADIUS, 0);
final int damageUpgradeAmount = unitType.getFieldAsInteger(ATTACK1_DMG_UPGRADE_AMT, 0);
final int maximumNumberOfTargets = unitType.getFieldAsInteger(ATTACK1_TARGET_COUNT, 0);
final float projectileArc = unitType.getFieldAsFloat(ATTACK1_PROJECTILE_ARC, 0);
final String projectileArt = unitType.getFieldAsString(ATTACK1_MISSILE_ART, 0);
final boolean projectileHomingEnabled = unitType
.getFieldAsBoolean(ATTACK1_PROJECTILE_HOMING_ENABLED, 0);
final int projectileSpeed = unitType.getFieldAsInteger(ATTACK1_PROJECTILE_SPEED, 0);
final int range = unitType.getFieldAsInteger(ATTACK1_RANGE, 0);
final float rangeMotionBuffer = unitType.getFieldAsFloat(ATTACK1_RANGE_MOTION_BUFFER, 0);
final boolean showUI = unitType.getFieldAsBoolean(ATTACK1_SHOW_UI, 0);
final EnumSet<CTargetType> targetsAllowed = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK1_TARGETS_ALLOWED, 0));
final String weaponSound = unitType.getFieldAsString(ATTACK1_WEAPON_SOUND, 0);
final CWeaponType weaponType = CWeaponType
.parseWeaponType(unitType.getFieldAsString(ATTACK1_WEAPON_TYPE, 0));
attacks.add(createAttack(animationBackswingPoint, animationDamagePoint, areaOfEffectFullDamage,
areaOfEffectMediumDamage, areaOfEffectSmallDamage, areaOfEffectTargets, attackType,
cooldownTime, damageBase, damageFactorMedium, damageFactorSmall, damageLossFactor,
damageDice, damageSidesPerDie, damageSpillDistance, damageSpillRadius, damageUpgradeAmount,
maximumNumberOfTargets, projectileArc, projectileArt, projectileHomingEnabled,
projectileSpeed, range, rangeMotionBuffer, showUI, targetsAllowed, weaponSound,
weaponType));
} catch (final Exception exc) {
System.err.println("Attack 1 failed to parse with: " + exc.getClass() + ":" + exc.getMessage());
}
}
if ((attacksEnabled & 0x2) != 0) {
try {
// attack two
final float animationBackswingPoint = unitType.getFieldAsFloat(ATTACK2_BACKSWING_POINT, 0);
final float animationDamagePoint = unitType.getFieldAsFloat(ATTACK2_DAMAGE_POINT, 0);
final int areaOfEffectFullDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_FULL_DMG, 0);
final int areaOfEffectMediumDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_HALF_DMG, 0);
final int areaOfEffectSmallDamage = unitType.getFieldAsInteger(ATTACK2_AREA_OF_EFFECT_QUARTER_DMG,
0);
final EnumSet<CTargetType> areaOfEffectTargets = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK2_AREA_OF_EFFECT_TARGETS, 0));
final CAttackType attackType = CAttackType
.parseAttackType(unitType.getFieldAsString(ATTACK2_ATTACK_TYPE, 0));
final float cooldownTime = unitType.getFieldAsFloat(ATTACK2_COOLDOWN, 0);
final int damageBase = unitType.getFieldAsInteger(ATTACK2_DMG_BASE, 0);
final float damageFactorMedium = unitType.getFieldAsFloat(ATTACK2_DAMAGE_FACTOR_HALF, 0);
final float damageFactorSmall = unitType.getFieldAsFloat(ATTACK2_DAMAGE_FACTOR_QUARTER, 0);
final float damageLossFactor = unitType.getFieldAsFloat(ATTACK2_DAMAGE_LOSS_FACTOR, 0);
final int damageDice = unitType.getFieldAsInteger(ATTACK2_DMG_DICE, 0);
final int damageSidesPerDie = unitType.getFieldAsInteger(ATTACK2_DMG_SIDES_PER_DIE, 0);
final float damageSpillDistance = unitType.getFieldAsFloat(ATTACK2_DMG_SPILL_DIST, 0);
final float damageSpillRadius = unitType.getFieldAsFloat(ATTACK2_DMG_SPILL_RADIUS, 0);
final int damageUpgradeAmount = unitType.getFieldAsInteger(ATTACK2_DMG_UPGRADE_AMT, 0);
final int maximumNumberOfTargets = unitType.getFieldAsInteger(ATTACK2_TARGET_COUNT, 0);
final float projectileArc = unitType.getFieldAsFloat(ATTACK2_PROJECTILE_ARC, 0);
final String projectileArt = unitType.getFieldAsString(ATTACK2_MISSILE_ART, 0);
final boolean projectileHomingEnabled = unitType
.getFieldAsBoolean(ATTACK2_PROJECTILE_HOMING_ENABLED, 0);
final int projectileSpeed = unitType.getFieldAsInteger(ATTACK2_PROJECTILE_SPEED, 0);
final int range = unitType.getFieldAsInteger(ATTACK2_RANGE, 0);
final float rangeMotionBuffer = unitType.getFieldAsFloat(ATTACK2_RANGE_MOTION_BUFFER, 0);
final boolean showUI = unitType.getFieldAsBoolean(ATTACK2_SHOW_UI, 0);
final EnumSet<CTargetType> targetsAllowed = CTargetType
.parseTargetTypeSet(unitType.getFieldAsString(ATTACK2_TARGETS_ALLOWED, 0));
final String weaponSound = unitType.getFieldAsString(ATTACK2_WEAPON_SOUND, 0);
final CWeaponType weaponType = CWeaponType
.parseWeaponType(unitType.getFieldAsString(ATTACK2_WEAPON_TYPE, 0));
attacks.add(createAttack(animationBackswingPoint, animationDamagePoint, areaOfEffectFullDamage,
areaOfEffectMediumDamage, areaOfEffectSmallDamage, areaOfEffectTargets, attackType,
cooldownTime, damageBase, damageFactorMedium, damageFactorSmall, damageLossFactor,
damageDice, damageSidesPerDie, damageSpillDistance, damageSpillRadius, damageUpgradeAmount,
maximumNumberOfTargets, projectileArc, projectileArt, projectileHomingEnabled,
projectileSpeed, range, rangeMotionBuffer, showUI, targetsAllowed, weaponSound,
weaponType));
} catch (final Exception exc) {
System.err.println("Attack 2 failed to parse with: " + exc.getClass() + ":" + exc.getMessage());
}
}
final int deathType = unitType.getFieldAsInteger(DEATH_TYPE, 0);
final boolean raise = (deathType & 0x1) != 0;
final boolean decay = (deathType & 0x2) != 0;
final String armorType = unitType.getFieldAsString(ARMOR_TYPE, 0);
final float impactZ = unitType.getFieldAsFloat(PROJECTILE_IMPACT_Z, 0);
final CDefenseType defenseType = CDefenseType.parseDefenseType(unitType.getFieldAsString(DEFENSE_TYPE, 0));
final float deathTime = unitType.getFieldAsFloat(DEATH_TIME, 0);
unitTypeInstance = new CUnitType(unitName, isBldg, movementType, moveHeight, collisionSize, classifications,
attacks, armorType, raise, decay, defenseType, impactZ, buildingPathingPixelMap, deathTime,
targetedAs, acquisitionRange, minimumAttackRange);
this.unitIdToUnitType.put(typeId, unitTypeInstance);
}
return unitTypeInstance;
}
private CUnitAttack createAttack(final float animationBackswingPoint, final float animationDamagePoint,
final int areaOfEffectFullDamage, final int areaOfEffectMediumDamage, final int areaOfEffectSmallDamage,
final EnumSet<CTargetType> areaOfEffectTargets, final CAttackType attackType, final float cooldownTime,
final int damageBase, final float damageFactorMedium, final float damageFactorSmall,
final float damageLossFactor, final int damageDice, final int damageSidesPerDie,
final float damageSpillDistance, final float damageSpillRadius, final int damageUpgradeAmount,
final int maximumNumberOfTargets, final float projectileArc, final String projectileArt,
final boolean projectileHomingEnabled, final int projectileSpeed, final int range,
final float rangeMotionBuffer, final boolean showUI, final EnumSet<CTargetType> targetsAllowed,
final String weaponSound, final CWeaponType weaponType) {
final CUnitAttack attack;
switch (weaponType) {
case MISSILE:
attack = new CUnitAttackMissile(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt, projectileHomingEnabled,
projectileSpeed);
break;
case MBOUNCE:
attack = new CUnitAttackMissileBounce(animationBackswingPoint, animationDamagePoint, attackType,
cooldownTime, damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range,
rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt,
projectileHomingEnabled, projectileSpeed, damageLossFactor, maximumNumberOfTargets,
areaOfEffectFullDamage, areaOfEffectTargets);
break;
case MSPLASH:
case ARTILLERY:
attack = new CUnitAttackMissileSplash(animationBackswingPoint, animationDamagePoint, attackType,
cooldownTime, damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range,
rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt,
projectileHomingEnabled, projectileSpeed, areaOfEffectFullDamage, areaOfEffectMediumDamage,
areaOfEffectSmallDamage, areaOfEffectTargets, damageFactorMedium, damageFactorSmall);
break;
case MLINE:
case ALINE:
attack = new CUnitAttackMissileLine(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt, projectileHomingEnabled,
projectileSpeed, damageSpillDistance, damageSpillRadius);
break;
case INSTANT:
attack = new CUnitAttackInstant(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType, projectileArt);
break;
default:
case NORMAL:
attack = new CUnitAttackNormal(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType);
break;
}
return attack;
}
private CUnitAttack createAttack(final float animationBackswingPoint, final float animationDamagePoint,
final int areaOfEffectFullDamage, final int areaOfEffectMediumDamage, final int areaOfEffectSmallDamage,
final EnumSet<CTargetType> areaOfEffectTargets, final CAttackType attackType, final float cooldownTime,
final int damageBase, final float damageFactorMedium, final float damageFactorSmall,
final float damageLossFactor, final int damageDice, final int damageSidesPerDie,
final float damageSpillDistance, final float damageSpillRadius, final int damageUpgradeAmount,
final int maximumNumberOfTargets, final float projectileArc, final String projectileArt,
final boolean projectileHomingEnabled, final int projectileSpeed, final int range,
final float rangeMotionBuffer, final boolean showUI, final EnumSet<CTargetType> targetsAllowed,
final String weaponSound, final CWeaponType weaponType) {
final CUnitAttack attack;
switch (weaponType) {
case MISSILE:
attack = new CUnitAttackMissile(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt, projectileHomingEnabled,
projectileSpeed);
break;
case MBOUNCE:
attack = new CUnitAttackMissileBounce(animationBackswingPoint, animationDamagePoint, attackType,
cooldownTime, damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range,
rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt,
projectileHomingEnabled, projectileSpeed, damageLossFactor, maximumNumberOfTargets,
areaOfEffectFullDamage, areaOfEffectTargets);
break;
case MSPLASH:
case ARTILLERY:
attack = new CUnitAttackMissileSplash(animationBackswingPoint, animationDamagePoint, attackType,
cooldownTime, damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range,
rangeMotionBuffer, showUI, targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt,
projectileHomingEnabled, projectileSpeed, areaOfEffectFullDamage, areaOfEffectMediumDamage,
areaOfEffectSmallDamage, areaOfEffectTargets, damageFactorMedium, damageFactorSmall);
break;
case MLINE:
case ALINE:
attack = new CUnitAttackMissileLine(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType, projectileArc, projectileArt, projectileHomingEnabled,
projectileSpeed, damageSpillDistance, damageSpillRadius);
break;
case INSTANT:
attack = new CUnitAttackInstant(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType, projectileArt);
break;
default:
case NORMAL:
attack = new CUnitAttackNormal(animationBackswingPoint, animationDamagePoint, attackType, cooldownTime,
damageBase, damageDice, damageSidesPerDie, damageUpgradeAmount, range, rangeMotionBuffer, showUI,
targetsAllowed, weaponSound, weaponType);
break;
}
return attack;
}
public float getPropulsionWindow(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(PROPULSION_WINDOW, 0);
}
public float getPropulsionWindow(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(PROPULSION_WINDOW, 0);
}
public float getTurnRate(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(TURN_RATE, 0);
}
public float getTurnRate(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(TURN_RATE, 0);
}
public boolean isBuilding(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsBoolean(IS_BLDG, 0);
}
public boolean isBuilding(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsBoolean(IS_BLDG, 0);
}
public String getName(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getName();
}
public String getName(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getName();
}
public int getA1MinDamage(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_BASE, 0)
+ this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_DICE, 0);
}
public int getA1MinDamage(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_BASE, 0)
+ this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_DICE, 0);
}
public int getA1MaxDamage(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_BASE, 0)
+ (this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_DICE, 0)
* this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_SIDES_PER_DIE, 0));
}
public int getA1MaxDamage(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_BASE, 0)
+ (this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_DICE, 0)
* this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_SIDES_PER_DIE, 0));
}
public int getA2MinDamage(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_BASE, 0)
+ this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_DICE, 0);
}
public int getA2MinDamage(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_BASE, 0)
+ this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_DICE, 0);
}
public int getA2MaxDamage(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_BASE, 0)
+ (this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_DICE, 0)
* this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_SIDES_PER_DIE, 0));
}
public int getA2MaxDamage(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_BASE, 0)
+ (this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_DICE, 0)
* this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_SIDES_PER_DIE, 0));
}
public int getDefense(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(DEFENSE, 0);
}
public int getDefense(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(DEFENSE, 0);
}
public int getA1ProjectileSpeed(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_PROJECTILE_SPEED, 0);
}
public int getA1ProjectileSpeed(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_PROJECTILE_SPEED, 0);
}
public float getA1ProjectileArc(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK1_PROJECTILE_ARC, 0);
}
public float getA1ProjectileArc(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK1_PROJECTILE_ARC, 0);
}
public int getA2ProjectileSpeed(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_PROJECTILE_SPEED, 0);
}
public int getA2ProjectileSpeed(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_PROJECTILE_SPEED, 0);
}
public float getA2ProjectileArc(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK2_PROJECTILE_ARC, 0);
}
public float getA2ProjectileArc(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK2_PROJECTILE_ARC, 0);
}
public String getA1MissileArt(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsString(ATTACK1_MISSILE_ART, 0);
}
public String getA1MissileArt(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsString(ATTACK1_MISSILE_ART, 0);
}
public String getA2MissileArt(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsString(ATTACK2_MISSILE_ART, 0);
}
public String getA2MissileArt(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsString(ATTACK2_MISSILE_ART, 0);
}
public float getA1Cooldown(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK1_COOLDOWN, 0);
}
public float getA1Cooldown(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK1_COOLDOWN, 0);
}
public float getA2Cooldown(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK2_COOLDOWN, 0);
}
public float getA2Cooldown(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(ATTACK2_COOLDOWN, 0);
}
public float getProjectileLaunchX(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(PROJECTILE_LAUNCH_X, 0);
}
public float getProjectileLaunchX(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(PROJECTILE_LAUNCH_X, 0);
}
public float getProjectileLaunchY(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(PROJECTILE_LAUNCH_Y, 0);
}
public float getProjectileLaunchY(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(PROJECTILE_LAUNCH_Y, 0);
}
public float getProjectileLaunchZ(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(PROJECTILE_LAUNCH_Z, 0);
}
public float getProjectileLaunchZ(final War3ID unitTypeId) {
return this.unitData.get(unitTypeId).getFieldAsFloat(PROJECTILE_LAUNCH_Z, 0);
}
}