From 59033075c4164ff370eb28f41e89aea551bbe144 Mon Sep 17 00:00:00 2001 From: MfromAzeroth <62727238+MfromAzeroth@users.noreply.github.com> Date: Sun, 12 Sep 2021 02:42:32 +0200 Subject: [PATCH 1/6] Added 'uhpr' to available values in CUnitData.java --- .../handlers/w3x/simulation/data/CUnitData.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/data/CUnitData.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/data/CUnitData.java index abfb4e450..6351a4bb5 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/data/CUnitData.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/data/CUnitData.java @@ -33,7 +33,6 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.hero.CPrimaryAttribute; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityQueue; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityRally; -import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityReviveHero; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CDefenseType; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType; @@ -52,6 +51,7 @@ 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 HIT_POINT_REGENERATION = War3ID.fromString("uhpr"); 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"); @@ -144,7 +144,6 @@ public class CUnitData { private static final War3ID STRUCTURES_BUILT = War3ID.fromString("ubui"); private static final War3ID UNITS_TRAINED = War3ID.fromString("utra"); private static final War3ID RESEARCHES_AVAILABLE = War3ID.fromString("ures"); - private static final War3ID REVIVES_HEROES = War3ID.fromString("urev"); private static final War3ID UNIT_RACE = War3ID.fromString("urac"); private static final War3ID REQUIRES = War3ID.fromString("ureq"); @@ -245,10 +244,7 @@ public CUnit create(final CSimulation simulation, final int playerIndex, final W if (!unitsTrained.isEmpty() || !researchesAvailable.isEmpty()) { unit.add(simulation, new CAbilityQueue(handleIdAllocator.createId(), unitsTrained, researchesAvailable)); } - if (unitTypeInstance.isRevivesHeroes()) { - unit.add(simulation, new CAbilityReviveHero(handleIdAllocator.createId())); - } - if (!unitsTrained.isEmpty() || unitTypeInstance.isRevivesHeroes()) { + if (!unitsTrained.isEmpty()) { unit.add(simulation, new CAbilityRally(handleIdAllocator.createId())); } if (unitTypeInstance.isHero()) { @@ -274,6 +270,7 @@ private CUnitType getUnitTypeInstance(final War3ID typeId, final BufferedImage b if (unitTypeInstance == null) { final String legacyName = getLegacyName(unitType); final int life = unitType.getFieldAsInteger(HIT_POINT_MAXIMUM, 0); + final float lifeRegeneration = unitType.getFieldAsFloat(HIT_POINT_REGENERATION,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); @@ -455,8 +452,6 @@ private CUnitType getUnitTypeInstance(final War3ID typeId, final BufferedImage b final int foodUsed = unitType.getFieldAsInteger(FOOD_USED, 0); final int foodMade = unitType.getFieldAsInteger(FOOD_MADE, 0); - final boolean revivesHeroes = unitType.getFieldAsBoolean(REVIVES_HEROES, 0); - final String unitsTrainedString = unitType.getFieldAsString(UNITS_TRAINED, 0); final String[] unitsTrainedStringItems = unitsTrainedString.trim().split(","); final List unitsTrained = new ArrayList<>(); @@ -538,14 +533,14 @@ else if (requirementsLevelsStringItems.length > 0) { final List heroProperNames = Arrays.asList(properNames.split(",")); - unitTypeInstance = new CUnitType(unitName, legacyName, typeId, life, manaInitial, manaMaximum, speed, + unitTypeInstance = new CUnitType(unitName, legacyName, typeId, life, lifeRegeneration, manaInitial, manaMaximum, speed, defense, abilityList, isBldg, movementType, moveHeight, collisionSize, classifications, attacks, armorType, raise, decay, defenseType, impactZ, buildingPathingPixelMap, deathTime, targetedAs, acquisitionRange, minimumAttackRange, structuresBuilt, unitsTrained, researchesAvailable, unitRace, goldCost, lumberCost, foodUsed, foodMade, buildTime, preventedPathingTypes, requiredPathingTypes, propWindow, turnRate, requirements, unitLevel, hero, strength, strPlus, agility, agiPlus, intelligence, intPlus, primaryAttribute, heroAbilityList, heroProperNames, properNamesCount, - canFlee, priority, revivesHeroes); + canFlee, priority); this.unitIdToUnitType.put(typeId, unitTypeInstance); this.jassLegacyNameToUnitId.put(legacyName, typeId); } From 4b0848a295b857290b9e59ab98dfc45c9cd2614b Mon Sep 17 00:00:00 2001 From: MfromAzeroth <62727238+MfromAzeroth@users.noreply.github.com> Date: Sun, 12 Sep 2021 02:44:12 +0200 Subject: [PATCH 2/6] Added hit point regeneration data to constructor in CUnitType.java --- .../handlers/w3x/simulation/CUnitType.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnitType.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnitType.java index cea6b5f2a..a2c3cf751 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnitType.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnitType.java @@ -23,6 +23,7 @@ public class CUnitType { private final String legacyName; private final War3ID typeId; private final int maxLife; + private final float lifeRegeneration; private final int manaInitial; private final int manaMaximum; private final int speed; @@ -75,9 +76,8 @@ public class CUnitType { private final int properNamesCount; private final boolean canFlee; private final int priority; - private final boolean revivesHeroes; - public CUnitType(final String name, final String legacyName, final War3ID typeId, final int maxLife, + public CUnitType(final String name, final String legacyName, final War3ID typeId, final int maxLife, final float lifeRegeneration, final int manaInitial, final int manaMaximum, final int speed, final int defense, final String abilityList, final boolean isBldg, final MovementType movementType, final float defaultFlyingHeight, final float collisionSize, final EnumSet classifications, @@ -93,11 +93,12 @@ public CUnitType(final String name, final String legacyName, final War3ID typeId final float strengthPerLevel, final int agility, final float agilityPerLevel, final int intelligence, final float intelligencePerLevel, final CPrimaryAttribute primaryAttribute, final List heroAbilityList, final List heroProperNames, final int properNamesCount, - final boolean canFlee, final int priority, final boolean revivesHeroes) { + final boolean canFlee, final int priority) { this.name = name; this.legacyName = legacyName; this.typeId = typeId; this.maxLife = maxLife; + this.lifeRegeneration = lifeRegeneration; this.manaInitial = manaInitial; this.manaMaximum = manaMaximum; this.speed = speed; @@ -147,7 +148,6 @@ public CUnitType(final String name, final String legacyName, final War3ID typeId this.properNamesCount = properNamesCount; this.canFlee = canFlee; this.priority = priority; - this.revivesHeroes = revivesHeroes; } public String getName() { @@ -166,6 +166,10 @@ public int getMaxLife() { return this.maxLife; } + public float getLifeRegeneration() { + return this.lifeRegeneration; + } + public int getManaInitial() { return this.manaInitial; } @@ -361,8 +365,4 @@ public boolean isCanFlee() { public int getPriority() { return this.priority; } - - public boolean isRevivesHeroes() { - return this.revivesHeroes; - } } From 61c3ac4da15b0441998e5401d92ed2d4de6c4e1e Mon Sep 17 00:00:00 2001 From: MfromAzeroth <62727238+MfromAzeroth@users.noreply.github.com> Date: Sun, 12 Sep 2021 02:45:37 +0200 Subject: [PATCH 3/6] Added regenerateHitPoints function in CUnit.java and added call to it in update() --- .../handlers/w3x/simulation/CUnit.java | 237 ++++-------------- 1 file changed, 42 insertions(+), 195 deletions(-) diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java index a3f003dfb..3fe355872 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java @@ -30,7 +30,6 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorAttack; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorAttackListener; -import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorAttackMove; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorFollow; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorHoldPosition; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorMove; @@ -93,13 +92,13 @@ public class CUnit extends CWidget { // questionable -- it already was -- but I meant for those to inform us // which fields shouldn't be persisted if we do game state save later private transient CUnitStateNotifier stateNotifier = new CUnitStateNotifier(); - private transient List stateListenersUpdates = new ArrayList<>(); + private transient List stateListenersNeedingAdd = new ArrayList<>(); + private transient List stateListenersNeedingRemove = new ArrayList<>(); private final float acquisitionRange; private transient static AutoAttackTargetFinderEnum autoAttackTargetFinderEnum = new AutoAttackTargetFinderEnum(); private transient CBehaviorMove moveBehavior; private transient CBehaviorAttack attackBehavior; - private transient CBehaviorAttackMove attackMoveBehavior; private transient CBehaviorFollow followBehavior; private transient CBehaviorPatrol patrolBehavior; private transient CBehaviorStop stopBehavior; @@ -189,12 +188,6 @@ public void add(final CSimulation simulation, final CAbility ability) { ability.onAdd(simulation, this); } - public void remove(final CSimulation simulation, final CAbility ability) { - this.abilities.remove(ability); - simulation.onAbilityRemovedFromUnit(this, ability); - ability.onRemove(simulation, this); - } - public War3ID getTypeId() { return this.typeId; } @@ -253,16 +246,14 @@ public int getSpeed() { * this unit from the game. */ public boolean update(final CSimulation game) { - for (final StateListenerUpdate update : this.stateListenersUpdates) { - switch (update.getUpdateType()) { - case ADD: - this.stateNotifier.subscribe(update.listener); - break; - case REMOVE: - this.stateNotifier.unsubscribe(update.listener); - break; - } + for (final CUnitStateListener listener : this.stateListenersNeedingAdd) { + this.stateNotifier.subscribe(listener); } + this.stateListenersNeedingAdd.clear(); + for (final CUnitStateListener listener : this.stateListenersNeedingRemove) { + this.stateNotifier.unsubscribe(listener); + } + this.stateListenersNeedingRemove.clear(); if (isDead()) { if (this.collisionRectangle != null) { // Moved this here because doing it on "kill" was able to happen in some cases @@ -279,15 +270,10 @@ public boolean update(final CSimulation game) { this.boneCorpse = true; // start final phase immediately for "cant raise" case } - if (!this.unitType.isHero()) { - if (!this.unitType.isDecay()) { - // if we dont raise AND dont decay, then now that death anim is over - // we just delete the unit - return true; - } - } - else { - game.heroDeathEvent(this); + if (!this.unitType.isDecay()) { + // if we dont raise AND dont decay, then now that death anim is over + // we just delete the unit + return true; } this.deathTurnTick = gameTurnTick; } @@ -301,18 +287,13 @@ else if (!this.boneCorpse) { } else if (game.getGameTurnTick() > (this.deathTurnTick + (int) (getEndingDecayTime(game) / WarsmashConstants.SIMULATION_STEP_TIME))) { - if (this.unitType.isHero()) { - if (!getHeroData().isAwaitingRevive()) { - setHidden(true); - getHeroData().setAwaitingRevive(true); - game.heroDissipateEvent(this); - } - return false; - } return true; } } else if (!this.paused) { + + regenerateHitPoints(); + if ((this.rallyPoint != this) && (this.rallyPoint instanceof CUnit) && ((CUnit) this.rallyPoint).isDead()) { setRallyPoint(this); } @@ -362,15 +343,6 @@ else if (!this.paused) { this.queuedUnitFoodPaid = true; } } - else if (this.buildQueueTypes[0] == QueueItemType.HERO_REVIVE) { - final CPlayer player = game.getPlayer(this.playerIndex); - final CUnitType trainedUnitType = game.getUnit(queuedRawcode.getValue()).getUnitType(); - final int newFoodUsed = player.getFoodUsed() + trainedUnitType.getFoodUsed(); - if (newFoodUsed <= player.getFoodCap()) { - player.setFoodUsed(newFoodUsed); - this.queuedUnitFoodPaid = true; - } - } else { this.queuedUnitFoodPaid = true; System.err.println( @@ -403,48 +375,6 @@ else if (this.buildQueueTypes[0] == QueueItemType.HERO_REVIVE) { this.stateNotifier.queueChanged(); } } - else if (this.buildQueueTypes[0] == QueueItemType.HERO_REVIVE) { - final CUnit revivingHero = game.getUnit(queuedRawcode.getValue()); - final CUnitType trainedUnitType = revivingHero.getUnitType(); - final CGameplayConstants gameplayConstants = game.getGameplayConstants(); - if (this.constructionProgress >= gameplayConstants.getHeroReviveTime( - trainedUnitType.getBuildTime(), revivingHero.getHeroData().getHeroLevel())) { - this.constructionProgress = 0; - revivingHero.getHeroData().setReviving(false); - revivingHero.getHeroData().setAwaitingRevive(false); - revivingHero.corpse = false; - revivingHero.boneCorpse = false; - revivingHero.deathTurnTick = 0; - revivingHero.setX(getX()); - revivingHero.setY(getY()); - game.getWorldCollision().addUnit(revivingHero); - revivingHero.setPoint(getX(), getY(), game.getWorldCollision(), game.getRegionManager()); - revivingHero.setHidden(false); - revivingHero.setLife(game, - revivingHero.getMaximumLife() * gameplayConstants.getHeroReviveLifeFactor()); - revivingHero.setMana((revivingHero.getMaximumMana() - * gameplayConstants.getHeroReviveManaFactor()) - + (gameplayConstants.getHeroReviveManaStart() * trainedUnitType.getManaInitial())); - // dont add food cost to player 2x - revivingHero.setFoodUsed(trainedUnitType.getFoodUsed()); - final CPlayer player = game.getPlayer(this.playerIndex); - player.setUnitFoodMade(revivingHero, trainedUnitType.getFoodMade()); - player.addTechtreeUnlocked(queuedRawcode); - // nudge the trained unit out around us - revivingHero.nudgeAround(game, this); - game.heroReviveEvent(this, revivingHero); - if (this.rallyPoint != null) { - final int rallyOrderId = OrderIds.smart; - this.rallyPoint.visit( - UseAbilityOnTargetByIdVisitor.INSTANCE.reset(game, revivingHero, rallyOrderId)); - } - for (int i = 0; i < (this.buildQueue.length - 1); i++) { - setBuildQueueItem(game, i, this.buildQueue[i + 1], this.buildQueueTypes[i + 1]); - } - setBuildQueueItem(game, this.buildQueue.length - 1, null, null); - this.stateNotifier.queueChanged(); - } - } else if (this.buildQueueTypes[0] == QueueItemType.RESEARCH) { final CUnitType trainedUnitType = game.getUnitData().getUnitType(queuedRawcode); if (this.constructionProgress >= trainedUnitType.getBuildTime()) { @@ -516,9 +446,6 @@ public float getEndingDecayTime(final CSimulation game) { if (this.isBuilding()) { return game.getGameplayConstants().getStructureDecayTime(); } - if (this.unitType.isHero()) { - return game.getGameplayConstants().getDissipateTime(); - } return game.getGameplayConstants().getBoneDecayTime(); } @@ -1098,11 +1025,11 @@ private int getRGBFromPixelData(final BufferedImage buildingPathingPixelMap, fin } public void addStateListener(final CUnitStateListener listener) { - this.stateListenersUpdates.add(new StateListenerUpdate(listener, StateListenerUpdateType.ADD)); + this.stateListenersNeedingAdd.add(listener); } public void removeStateListener(final CUnitStateListener listener) { - this.stateListenersUpdates.add(new StateListenerUpdate(listener, StateListenerUpdateType.REMOVE)); + this.stateListenersNeedingRemove.add(listener); } public boolean isCorpse() { @@ -1147,10 +1074,6 @@ public float getAcquisitionRange() { return this.acquisitionRange; } - public void heal(final CSimulation game, final int lifeToRegain) { - setLife(game, Math.min(getLife() + lifeToRegain, getMaximumLife())); - } - private static final class AutoAttackTargetFinderEnum implements CUnitEnumFunction { private CSimulation game; private CUnit source; @@ -1169,7 +1092,7 @@ private AutoAttackTargetFinderEnum reset(final CSimulation game, final CUnit sou @Override public boolean call(final CUnit unit) { if (!this.game.getPlayer(this.source.getPlayerIndex()).hasAlliance(unit.getPlayerIndex(), - CAllianceType.PASSIVE) && !unit.isDead() && !unit.isInvulnerable()) { + CAllianceType.PASSIVE)) { for (final CUnitAttack attack : this.source.getAttacks()) { if (this.source.canReach(unit, this.source.acquisitionRange) && unit.canBeTargetedBy(this.game, this.source, attack.getTargetsAllowed()) @@ -1205,14 +1128,6 @@ public void setAttackBehavior(final CBehaviorAttack attackBehavior) { this.attackBehavior = attackBehavior; } - public void setAttackMoveBehavior(final CBehaviorAttackMove attackMoveBehavior) { - this.attackMoveBehavior = attackMoveBehavior; - } - - public CBehaviorAttackMove getAttackMoveBehavior() { - return this.attackMoveBehavior; - } - public CBehaviorStop getStopBehavior() { return this.stopBehavior; } @@ -1348,16 +1263,9 @@ public float getBuildQueueTimeRemaining(final CSimulation simulation) { switch (this.buildQueueTypes[0]) { case RESEARCH: return 999; // TODO - case UNIT: { + case UNIT: final CUnitType trainedUnitType = simulation.getUnitData().getUnitType(this.buildQueue[0]); return trainedUnitType.getBuildTime(); - } - case HERO_REVIVE: { - final CUnit hero = simulation.getUnit(this.buildQueue[0].getValue()); - final CUnitType trainedUnitType = hero.getUnitType(); - return simulation.getGameplayConstants().getHeroReviveTime(trainedUnitType.getBuildTime(), - hero.getHeroData().getHeroLevel()); - } default: return 0; } @@ -1373,43 +1281,22 @@ public void cancelBuildQueueItem(final CSimulation game, final int cancelIndex) switch (cancelledType) { case RESEARCH: break; - case UNIT: { + case UNIT: final CPlayer player = game.getPlayer(this.playerIndex); final CUnitType unitType = game.getUnitData().getUnitType(this.buildQueue[cancelIndex]); player.setFoodUsed(player.getFoodUsed() - unitType.getFoodUsed()); break; } - case HERO_REVIVE: { - final CPlayer player = game.getPlayer(this.playerIndex); - final CUnitType unitType = game.getUnit(this.buildQueue[cancelIndex].getValue()).getUnitType(); - player.setFoodUsed(player.getFoodUsed() - unitType.getFoodUsed()); - break; - } - } } switch (cancelledType) { case RESEARCH: break; - case UNIT: { + case UNIT: final CPlayer player = game.getPlayer(this.playerIndex); final CUnitType unitType = game.getUnitData().getUnitType(this.buildQueue[cancelIndex]); player.refundFor(unitType); break; } - case HERO_REVIVE: { - final CPlayer player = game.getPlayer(this.playerIndex); - final CUnit hero = game.getUnit(this.buildQueue[cancelIndex].getValue()); - final CUnitType unitType = hero.getUnitType(); - final CAbilityHero heroData = hero.getHeroData(); - heroData.setReviving(false); - final CGameplayConstants gameplayConstants = game.getGameplayConstants(); - player.refund( - gameplayConstants.getHeroReviveGoldCost(unitType.getGoldCost(), heroData.getHeroLevel()), - gameplayConstants.getHeroReviveLumberCost(unitType.getLumberCost(), - heroData.getHeroLevel())); - break; - } - } for (int i = cancelIndex; i < (this.buildQueueTypes.length - 1); i++) { setBuildQueueItem(game, i, this.buildQueue[i + 1], this.buildQueueTypes[i + 1]); } @@ -1425,33 +1312,17 @@ public void setBuildQueueItem(final CSimulation game, final int index, final War this.buildQueueTypes[index] = queueItemType; if (index == 0) { this.queuedUnitFoodPaid = true; - if (rawcode != null) { - if (queueItemType == QueueItemType.UNIT) { - final CPlayer player = game.getPlayer(this.playerIndex); - final CUnitType unitType = game.getUnitData().getUnitType(this.buildQueue[index]); - if (unitType.getFoodUsed() != 0) { - final int newFoodUsed = player.getFoodUsed() + unitType.getFoodUsed(); - if (newFoodUsed <= player.getFoodCap()) { - player.setFoodUsed(newFoodUsed); - } - else { - this.queuedUnitFoodPaid = false; - game.getCommandErrorListener(this.playerIndex).showNoFoodError(); - } + if ((rawcode != null) && (queueItemType == QueueItemType.UNIT)) { + final CPlayer player = game.getPlayer(this.playerIndex); + final CUnitType unitType = game.getUnitData().getUnitType(this.buildQueue[index]); + if (unitType.getFoodUsed() != 0) { + final int newFoodUsed = player.getFoodUsed() + unitType.getFoodUsed(); + if (newFoodUsed <= player.getFoodCap()) { + player.setFoodUsed(newFoodUsed); } - } - else if (queueItemType == QueueItemType.HERO_REVIVE) { - final CPlayer player = game.getPlayer(this.playerIndex); - final CUnitType unitType = game.getUnit(this.buildQueue[index].getValue()).getUnitType(); - if (unitType.getFoodUsed() != 0) { - final int newFoodUsed = player.getFoodUsed() + unitType.getFoodUsed(); - if (newFoodUsed <= player.getFoodCap()) { - player.setFoodUsed(newFoodUsed); - } - else { - this.queuedUnitFoodPaid = false; - game.getCommandErrorListener(this.playerIndex).showNoFoodError(); - } + else { + this.queuedUnitFoodPaid = false; + game.getCommandErrorListener(this.playerIndex).showNoFoodError(); } } } @@ -1466,26 +1337,13 @@ public void queueTrainingUnit(final CSimulation game, final War3ID rawcode) { } } - public void queueRevivingHero(final CSimulation game, final CUnit hero) { - if (queue(game, new War3ID(hero.getHandleId()), QueueItemType.HERO_REVIVE)) { - hero.getHeroData().setReviving(true); - final CPlayer player = game.getPlayer(this.playerIndex); - final int heroReviveGoldCost = game.getGameplayConstants() - .getHeroReviveGoldCost(hero.getUnitType().getGoldCost(), hero.getHeroData().getHeroLevel()); - final int heroReviveLumberCost = game.getGameplayConstants() - .getHeroReviveLumberCost(hero.getUnitType().getGoldCost(), hero.getHeroData().getHeroLevel()); - player.charge(heroReviveGoldCost, heroReviveLumberCost); - } - } - public void queueResearch(final CSimulation game, final War3ID rawcode) { queue(game, rawcode, QueueItemType.RESEARCH); } public static enum QueueItemType { UNIT, - RESEARCH, - HERO_REVIVE; + RESEARCH; } public void setRallyPoint(final AbilityTarget target) { @@ -1722,26 +1580,15 @@ public void onRemove(final CSimulation simulation) { simulation.getWorldCollision().removeUnit(this); } - private static enum StateListenerUpdateType { - ADD, - REMOVE; - } - - private static final class StateListenerUpdate { - private final CUnitStateListener listener; - private final StateListenerUpdateType updateType; - - public StateListenerUpdate(final CUnitStateListener listener, final StateListenerUpdateType updateType) { - this.listener = listener; - this.updateType = updateType; - } - - public CUnitStateListener getListener() { - return this.listener; - } - - public StateListenerUpdateType getUpdateType() { - return this.updateType; + /** + * @Author MfromAzeroth + * This method increases a unit's health according to its hit point regeneration + * (If something with this is off it's probably my fault) + */ + private void regenerateHitPoints(){ + if(this.life Date: Sun, 16 Jan 2022 04:05:19 +0100 Subject: [PATCH 4/6] Merged with Retera's newest public version and added Wisp consumption on Night Elf build --- .../handlers/w3x/simulation/CUnit.java | 376 +++++++++++++----- .../handlers/w3x/simulation/CUnitType.java | 50 +-- .../build/CAbilityNightElfBuild.java | 5 +- .../behaviors/build/CBehaviorHumanBuild.java | 4 + .../build/CBehaviorNightElfBuild.java | 66 +++ .../behaviors/build/CBehaviorOrcBuild.java | 8 +- .../behaviors/build/ConstructionFlag.java | 5 + .../w3x/simulation/data/CUnitData.java | 175 ++++---- 8 files changed, 478 insertions(+), 211 deletions(-) create mode 100644 core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorHumanBuild.java create mode 100644 core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorNightElfBuild.java create mode 100644 core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/ConstructionFlag.java diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java index 3fe355872..825725dab 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java @@ -30,11 +30,14 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorAttack; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorAttackListener; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorAttackMove; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorFollow; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorHoldPosition; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorMove; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorPatrol; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehaviorStop; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.build.CBehaviorNightElfBuild; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.build.ConstructionFlag; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.attacks.CUnitAttack; @@ -85,6 +88,8 @@ public class CUnit extends CWidget { private int deathTurnTick; private boolean corpse; private boolean boneCorpse; + //addedByMFromAz - my fault if it's bad + private boolean consumed; private transient CUnitAnimationListener unitAnimationListener; @@ -92,19 +97,21 @@ public class CUnit extends CWidget { // questionable -- it already was -- but I meant for those to inform us // which fields shouldn't be persisted if we do game state save later private transient CUnitStateNotifier stateNotifier = new CUnitStateNotifier(); - private transient List stateListenersNeedingAdd = new ArrayList<>(); - private transient List stateListenersNeedingRemove = new ArrayList<>(); + private transient List stateListenersUpdates = new ArrayList<>(); private final float acquisitionRange; private transient static AutoAttackTargetFinderEnum autoAttackTargetFinderEnum = new AutoAttackTargetFinderEnum(); private transient CBehaviorMove moveBehavior; private transient CBehaviorAttack attackBehavior; + private transient CBehaviorAttackMove attackMoveBehavior; private transient CBehaviorFollow followBehavior; private transient CBehaviorPatrol patrolBehavior; private transient CBehaviorStop stopBehavior; private transient CBehaviorHoldPosition holdPositionBehavior; private boolean constructing = false; private float constructionProgress; + //added by MfromAz - if it's bad that's on me + private ConstructionFlag constuctionProcessType; private boolean hidden = false; private boolean paused = false; private boolean acceptingOrders = true; @@ -125,8 +132,8 @@ public class CUnit extends CWidget { private transient Set priorContainingRegions = new LinkedHashSet<>(); public CUnit(final int handleId, final int playerIndex, final float x, final float y, final float life, - final War3ID typeId, final float facing, final float mana, final int maximumLife, final int maximumMana, - final int speed, final CUnitType unitType, final RemovablePathingMapInstance pathingInstance) { + final War3ID typeId, final float facing, final float mana, final int maximumLife, final int maximumMana, + final int speed, final CUnitType unitType, final RemovablePathingMapInstance pathingInstance) { super(handleId, x, y, life); this.playerIndex = playerIndex; this.typeId = typeId; @@ -143,6 +150,8 @@ public CUnit(final int handleId, final int playerIndex, final float x, final flo this.stopBehavior = new CBehaviorStop(this); this.defaultBehavior = this.stopBehavior; this.currentBehavior = this.defaultBehavior; + + this.consumed = false; } private void computeDerivedFields() { @@ -188,6 +197,12 @@ public void add(final CSimulation simulation, final CAbility ability) { ability.onAdd(simulation, this); } + public void remove(final CSimulation simulation, final CAbility ability) { + this.abilities.remove(ability); + simulation.onAbilityRemovedFromUnit(this, ability); + ability.onRemove(simulation, this); + } + public War3ID getTypeId() { return this.typeId; } @@ -241,19 +256,36 @@ public int getSpeed() { return this.speed; } + public boolean isConsumed(){ + return consumed; + } + + public void setConsumed(boolean consumed){ + this.consumed = consumed; + } + + public ConstructionFlag getConstuctionProcessType(){return constuctionProcessType;} + + public void setConstuctionProcessType(ConstructionFlag flag) {this.constuctionProcessType = flag;} + /** * Updates one tick of simulation logic and return true if it's time to remove * this unit from the game. */ public boolean update(final CSimulation game) { - for (final CUnitStateListener listener : this.stateListenersNeedingAdd) { - this.stateNotifier.subscribe(listener); + for (final StateListenerUpdate update : this.stateListenersUpdates) { + switch (update.getUpdateType()) { + case ADD: + this.stateNotifier.subscribe(update.listener); + break; + case REMOVE: + this.stateNotifier.unsubscribe(update.listener); + break; + } } - this.stateListenersNeedingAdd.clear(); - for (final CUnitStateListener listener : this.stateListenersNeedingRemove) { - this.stateNotifier.unsubscribe(listener); + if(isConsumed()){ + return true; } - this.stateListenersNeedingRemove.clear(); if (isDead()) { if (this.collisionRectangle != null) { // Moved this here because doing it on "kill" was able to happen in some cases @@ -270,10 +302,15 @@ public boolean update(final CSimulation game) { this.boneCorpse = true; // start final phase immediately for "cant raise" case } - if (!this.unitType.isDecay()) { - // if we dont raise AND dont decay, then now that death anim is over - // we just delete the unit - return true; + if (!this.unitType.isHero()) { + if (!this.unitType.isDecay()) { + // if we dont raise AND dont decay, then now that death anim is over + // we just delete the unit + return true; + } + } + else { + game.heroDeathEvent(this); } this.deathTurnTick = gameTurnTick; } @@ -287,26 +324,41 @@ else if (!this.boneCorpse) { } else if (game.getGameTurnTick() > (this.deathTurnTick + (int) (getEndingDecayTime(game) / WarsmashConstants.SIMULATION_STEP_TIME))) { + if (this.unitType.isHero()) { + if (!getHeroData().isAwaitingRevive()) { + setHidden(true); + getHeroData().setAwaitingRevive(true); + game.heroDissipateEvent(this); + } + return false; + } return true; } } else if (!this.paused) { - - regenerateHitPoints(); - if ((this.rallyPoint != this) && (this.rallyPoint instanceof CUnit) && ((CUnit) this.rallyPoint).isDead()) { setRallyPoint(this); } if (this.constructing) { this.constructionProgress += WarsmashConstants.SIMULATION_STEP_TIME; final int buildTime = this.unitType.getBuildTime(); + //ignore this for human build (MFROMAZ) final float healthGain = (WarsmashConstants.SIMULATION_STEP_TIME / buildTime) * (this.maximumLife * (1.0f - WarsmashConstants.BUILDING_CONSTRUCT_START_LIFE)); setLife(game, Math.min(this.life + healthGain, this.maximumLife)); if (this.constructionProgress >= buildTime) { this.constructing = false; this.constructionProgress = 0; - popoutWorker(game); + CUnit worker = getWorkerInside(); + + //removing wisp here (MFROMAZ) + if(this.constuctionProcessType!=null&&this.constuctionProcessType==ConstructionFlag.CONSUME_WORKER){ + worker.setConsumed(true); + }else{ + popoutWorker(game); + } + + //create Blight here (MFROMAZ) final Iterator abilityIterator = this.abilities.iterator(); while (abilityIterator.hasNext()) { final CAbility ability = abilityIterator.next(); @@ -343,6 +395,15 @@ else if (!this.paused) { this.queuedUnitFoodPaid = true; } } + else if (this.buildQueueTypes[0] == QueueItemType.HERO_REVIVE) { + final CPlayer player = game.getPlayer(this.playerIndex); + final CUnitType trainedUnitType = game.getUnit(queuedRawcode.getValue()).getUnitType(); + final int newFoodUsed = player.getFoodUsed() + trainedUnitType.getFoodUsed(); + if (newFoodUsed <= player.getFoodCap()) { + player.setFoodUsed(newFoodUsed); + this.queuedUnitFoodPaid = true; + } + } else { this.queuedUnitFoodPaid = true; System.err.println( @@ -375,6 +436,48 @@ else if (!this.paused) { this.stateNotifier.queueChanged(); } } + else if (this.buildQueueTypes[0] == QueueItemType.HERO_REVIVE) { + final CUnit revivingHero = game.getUnit(queuedRawcode.getValue()); + final CUnitType trainedUnitType = revivingHero.getUnitType(); + final CGameplayConstants gameplayConstants = game.getGameplayConstants(); + if (this.constructionProgress >= gameplayConstants.getHeroReviveTime( + trainedUnitType.getBuildTime(), revivingHero.getHeroData().getHeroLevel())) { + this.constructionProgress = 0; + revivingHero.getHeroData().setReviving(false); + revivingHero.getHeroData().setAwaitingRevive(false); + revivingHero.corpse = false; + revivingHero.boneCorpse = false; + revivingHero.deathTurnTick = 0; + revivingHero.setX(getX()); + revivingHero.setY(getY()); + game.getWorldCollision().addUnit(revivingHero); + revivingHero.setPoint(getX(), getY(), game.getWorldCollision(), game.getRegionManager()); + revivingHero.setHidden(false); + revivingHero.setLife(game, + revivingHero.getMaximumLife() * gameplayConstants.getHeroReviveLifeFactor()); + revivingHero.setMana((revivingHero.getMaximumMana() + * gameplayConstants.getHeroReviveManaFactor()) + + (gameplayConstants.getHeroReviveManaStart() * trainedUnitType.getManaInitial())); + // dont add food cost to player 2x + revivingHero.setFoodUsed(trainedUnitType.getFoodUsed()); + final CPlayer player = game.getPlayer(this.playerIndex); + player.setUnitFoodMade(revivingHero, trainedUnitType.getFoodMade()); + player.addTechtreeUnlocked(queuedRawcode); + // nudge the trained unit out around us + revivingHero.nudgeAround(game, this); + game.heroReviveEvent(this, revivingHero); + if (this.rallyPoint != null) { + final int rallyOrderId = OrderIds.smart; + this.rallyPoint.visit( + UseAbilityOnTargetByIdVisitor.INSTANCE.reset(game, revivingHero, rallyOrderId)); + } + for (int i = 0; i < (this.buildQueue.length - 1); i++) { + setBuildQueueItem(game, i, this.buildQueue[i + 1], this.buildQueueTypes[i + 1]); + } + setBuildQueueItem(game, this.buildQueue.length - 1, null, null); + this.stateNotifier.queueChanged(); + } + } else if (this.buildQueueTypes[0] == QueueItemType.RESEARCH) { final CUnitType trainedUnitType = game.getUnitData().getUnitType(queuedRawcode); if (this.constructionProgress >= trainedUnitType.getBuildTime()) { @@ -446,6 +549,9 @@ public float getEndingDecayTime(final CSimulation game) { if (this.isBuilding()) { return game.getGameplayConstants().getStructureDecayTime(); } + if (this.unitType.isHero()) { + return game.getGameplayConstants().getDissipateTime(); + } return game.getGameplayConstants().getBoneDecayTime(); } @@ -700,7 +806,7 @@ else if (this.collisionRectangle != null) { } public void setPoint(final float newX, final float newY, final CWorldCollision collision, - final CRegionManager regionManager) { + final CRegionManager regionManager) { final float prevX = getX(); final float prevY = getY(); setX(newX); @@ -790,7 +896,7 @@ public double distance(final float x, final float y) { @Override public void damage(final CSimulation simulation, final CUnit source, final CAttackType attackType, - final String weaponType, final float damage) { + final String weaponType, final float damage) { final boolean wasDead = isDead(); if (!this.invulnerable) { final float damageRatioFromArmorClass = simulation.getGameplayConstants().getDamageRatioAgainst(attackType, @@ -887,16 +993,16 @@ private void kill(final CSimulation simulation, final CUnit source) { final int heroExpRange = gameplayConstants.getHeroExpRange(); simulation.getWorldCollision().enumUnitsInRect(new Rectangle(this.getX() - heroExpRange, this.getY() - heroExpRange, heroExpRange * 2, heroExpRange * 2), new CUnitEnumFunction() { - @Override - public boolean call(final CUnit unit) { - if ((unit.distance(killedUnit) <= heroExpRange) - && sourcePlayer.hasAlliance(unit.getPlayerIndex(), CAllianceType.SHARED_XP) - && (unit.getHeroData() != null)) { - xpReceivingHeroes.add(unit); - } - return false; - } - }); + @Override + public boolean call(final CUnit unit) { + if ((unit.distance(killedUnit) <= heroExpRange) + && sourcePlayer.hasAlliance(unit.getPlayerIndex(), CAllianceType.SHARED_XP) + && (unit.getHeroData() != null)) { + xpReceivingHeroes.add(unit); + } + return false; + } + }); if (xpReceivingHeroes.isEmpty()) { if (gameplayConstants.isGlobalExperience()) { for (int i = 0; i < WarsmashConstants.MAX_PLAYERS; i++) { @@ -950,7 +1056,7 @@ public boolean canReach(final float x, final float y, final float range) { } public boolean canReachToPathing(final float range, final float rotationForPathing, - final BufferedImage buildingPathingPixelMap, final float targetX, final float targetY) { + final BufferedImage buildingPathingPixelMap, final float targetX, final float targetY) { final int rotation = ((int) rotationForPathing + 450) % 360; final float relativeOffsetX = getX() - targetX; final float relativeOffsetY = getY() - targetY; @@ -998,38 +1104,38 @@ public boolean canReachToPathing(final float range, final float rotationForPathi } private int getRGBFromPixelData(final BufferedImage buildingPathingPixelMap, final int checkX, final int checkY, - final int rotation) { + final int rotation) { // Below: y is downwards (:() int x; int y; switch (rotation) { - case 90: - x = checkY; - y = buildingPathingPixelMap.getWidth() - 1 - checkX; - break; - case 180: - x = buildingPathingPixelMap.getWidth() - 1 - checkX; - y = buildingPathingPixelMap.getHeight() - 1 - checkY; - break; - case 270: - x = buildingPathingPixelMap.getHeight() - 1 - checkY; - y = checkX; - break; - default: - case 0: - x = checkX; - y = checkY; + case 90: + x = checkY; + y = buildingPathingPixelMap.getWidth() - 1 - checkX; + break; + case 180: + x = buildingPathingPixelMap.getWidth() - 1 - checkX; + y = buildingPathingPixelMap.getHeight() - 1 - checkY; + break; + case 270: + x = buildingPathingPixelMap.getHeight() - 1 - checkY; + y = checkX; + break; + default: + case 0: + x = checkX; + y = checkY; } return buildingPathingPixelMap.getRGB(x, buildingPathingPixelMap.getHeight() - 1 - y); } public void addStateListener(final CUnitStateListener listener) { - this.stateListenersNeedingAdd.add(listener); + this.stateListenersUpdates.add(new StateListenerUpdate(listener, StateListenerUpdateType.ADD)); } public void removeStateListener(final CUnitStateListener listener) { - this.stateListenersNeedingRemove.add(listener); + this.stateListenersUpdates.add(new StateListenerUpdate(listener, StateListenerUpdateType.REMOVE)); } public boolean isCorpse() { @@ -1042,7 +1148,7 @@ public boolean isBoneCorpse() { @Override public boolean canBeTargetedBy(final CSimulation simulation, final CUnit source, - final EnumSet targetsAllowed) { + final EnumSet targetsAllowed) { if (targetsAllowed.containsAll(this.unitType.getTargetedAs()) || (!targetsAllowed.contains(CTargetType.GROUND) && (!targetsAllowed.contains(CTargetType.STRUCTURE) && !targetsAllowed.contains(CTargetType.AIR)))) { final int sourcePlayerIndex = source.getPlayerIndex(); @@ -1074,6 +1180,10 @@ public float getAcquisitionRange() { return this.acquisitionRange; } + public void heal(final CSimulation game, final int lifeToRegain) { + setLife(game, Math.min(getLife() + lifeToRegain, getMaximumLife())); + } + private static final class AutoAttackTargetFinderEnum implements CUnitEnumFunction { private CSimulation game; private CUnit source; @@ -1081,7 +1191,7 @@ private static final class AutoAttackTargetFinderEnum implements CUnitEnumFuncti private boolean foundAnyTarget; private AutoAttackTargetFinderEnum reset(final CSimulation game, final CUnit source, - final boolean disableMove) { + final boolean disableMove) { this.game = game; this.source = source; this.disableMove = disableMove; @@ -1092,7 +1202,7 @@ private AutoAttackTargetFinderEnum reset(final CSimulation game, final CUnit sou @Override public boolean call(final CUnit unit) { if (!this.game.getPlayer(this.source.getPlayerIndex()).hasAlliance(unit.getPlayerIndex(), - CAllianceType.PASSIVE)) { + CAllianceType.PASSIVE) && !unit.isDead() && !unit.isInvulnerable()) { for (final CUnitAttack attack : this.source.getAttacks()) { if (this.source.canReach(unit, this.source.acquisitionRange) && unit.canBeTargetedBy(this.game, this.source, attack.getTargetsAllowed()) @@ -1128,6 +1238,14 @@ public void setAttackBehavior(final CBehaviorAttack attackBehavior) { this.attackBehavior = attackBehavior; } + public void setAttackMoveBehavior(final CBehaviorAttackMove attackMoveBehavior) { + this.attackMoveBehavior = attackMoveBehavior; + } + + public CBehaviorAttackMove getAttackMoveBehavior() { + return this.attackMoveBehavior; + } + public CBehaviorStop getStopBehavior() { return this.stopBehavior; } @@ -1261,13 +1379,20 @@ public float getBuildQueueTimeRemaining(final CSimulation simulation) { return 0; } switch (this.buildQueueTypes[0]) { - case RESEARCH: - return 999; // TODO - case UNIT: - final CUnitType trainedUnitType = simulation.getUnitData().getUnitType(this.buildQueue[0]); - return trainedUnitType.getBuildTime(); - default: - return 0; + case RESEARCH: + return 999; // TODO + case UNIT: { + final CUnitType trainedUnitType = simulation.getUnitData().getUnitType(this.buildQueue[0]); + return trainedUnitType.getBuildTime(); + } + case HERO_REVIVE: { + final CUnit hero = simulation.getUnit(this.buildQueue[0].getValue()); + final CUnitType trainedUnitType = hero.getUnitType(); + return simulation.getGameplayConstants().getHeroReviveTime(trainedUnitType.getBuildTime(), + hero.getHeroData().getHeroLevel()); + } + default: + return 0; } } @@ -1279,23 +1404,44 @@ public void cancelBuildQueueItem(final CSimulation game, final int cancelIndex) if (cancelIndex == 0) { this.constructionProgress = 0.0f; switch (cancelledType) { + case RESEARCH: + break; + case UNIT: { + final CPlayer player = game.getPlayer(this.playerIndex); + final CUnitType unitType = game.getUnitData().getUnitType(this.buildQueue[cancelIndex]); + player.setFoodUsed(player.getFoodUsed() - unitType.getFoodUsed()); + break; + } + case HERO_REVIVE: { + final CPlayer player = game.getPlayer(this.playerIndex); + final CUnitType unitType = game.getUnit(this.buildQueue[cancelIndex].getValue()).getUnitType(); + player.setFoodUsed(player.getFoodUsed() - unitType.getFoodUsed()); + break; + } + } + } + switch (cancelledType) { case RESEARCH: break; - case UNIT: + case UNIT: { final CPlayer player = game.getPlayer(this.playerIndex); final CUnitType unitType = game.getUnitData().getUnitType(this.buildQueue[cancelIndex]); - player.setFoodUsed(player.getFoodUsed() - unitType.getFoodUsed()); + player.refundFor(unitType); + break; + } + case HERO_REVIVE: { + final CPlayer player = game.getPlayer(this.playerIndex); + final CUnit hero = game.getUnit(this.buildQueue[cancelIndex].getValue()); + final CUnitType unitType = hero.getUnitType(); + final CAbilityHero heroData = hero.getHeroData(); + heroData.setReviving(false); + final CGameplayConstants gameplayConstants = game.getGameplayConstants(); + player.refund( + gameplayConstants.getHeroReviveGoldCost(unitType.getGoldCost(), heroData.getHeroLevel()), + gameplayConstants.getHeroReviveLumberCost(unitType.getLumberCost(), + heroData.getHeroLevel())); break; } - } - switch (cancelledType) { - case RESEARCH: - break; - case UNIT: - final CPlayer player = game.getPlayer(this.playerIndex); - final CUnitType unitType = game.getUnitData().getUnitType(this.buildQueue[cancelIndex]); - player.refundFor(unitType); - break; } for (int i = cancelIndex; i < (this.buildQueueTypes.length - 1); i++) { setBuildQueueItem(game, i, this.buildQueue[i + 1], this.buildQueueTypes[i + 1]); @@ -1307,22 +1453,38 @@ public void cancelBuildQueueItem(final CSimulation game, final int cancelIndex) } public void setBuildQueueItem(final CSimulation game, final int index, final War3ID rawcode, - final QueueItemType queueItemType) { + final QueueItemType queueItemType) { this.buildQueue[index] = rawcode; this.buildQueueTypes[index] = queueItemType; if (index == 0) { this.queuedUnitFoodPaid = true; - if ((rawcode != null) && (queueItemType == QueueItemType.UNIT)) { - final CPlayer player = game.getPlayer(this.playerIndex); - final CUnitType unitType = game.getUnitData().getUnitType(this.buildQueue[index]); - if (unitType.getFoodUsed() != 0) { - final int newFoodUsed = player.getFoodUsed() + unitType.getFoodUsed(); - if (newFoodUsed <= player.getFoodCap()) { - player.setFoodUsed(newFoodUsed); + if (rawcode != null) { + if (queueItemType == QueueItemType.UNIT) { + final CPlayer player = game.getPlayer(this.playerIndex); + final CUnitType unitType = game.getUnitData().getUnitType(this.buildQueue[index]); + if (unitType.getFoodUsed() != 0) { + final int newFoodUsed = player.getFoodUsed() + unitType.getFoodUsed(); + if (newFoodUsed <= player.getFoodCap()) { + player.setFoodUsed(newFoodUsed); + } + else { + this.queuedUnitFoodPaid = false; + game.getCommandErrorListener(this.playerIndex).showNoFoodError(); + } } - else { - this.queuedUnitFoodPaid = false; - game.getCommandErrorListener(this.playerIndex).showNoFoodError(); + } + else if (queueItemType == QueueItemType.HERO_REVIVE) { + final CPlayer player = game.getPlayer(this.playerIndex); + final CUnitType unitType = game.getUnit(this.buildQueue[index].getValue()).getUnitType(); + if (unitType.getFoodUsed() != 0) { + final int newFoodUsed = player.getFoodUsed() + unitType.getFoodUsed(); + if (newFoodUsed <= player.getFoodCap()) { + player.setFoodUsed(newFoodUsed); + } + else { + this.queuedUnitFoodPaid = false; + game.getCommandErrorListener(this.playerIndex).showNoFoodError(); + } } } } @@ -1337,13 +1499,26 @@ public void queueTrainingUnit(final CSimulation game, final War3ID rawcode) { } } + public void queueRevivingHero(final CSimulation game, final CUnit hero) { + if (queue(game, new War3ID(hero.getHandleId()), QueueItemType.HERO_REVIVE)) { + hero.getHeroData().setReviving(true); + final CPlayer player = game.getPlayer(this.playerIndex); + final int heroReviveGoldCost = game.getGameplayConstants() + .getHeroReviveGoldCost(hero.getUnitType().getGoldCost(), hero.getHeroData().getHeroLevel()); + final int heroReviveLumberCost = game.getGameplayConstants() + .getHeroReviveLumberCost(hero.getUnitType().getGoldCost(), hero.getHeroData().getHeroLevel()); + player.charge(heroReviveGoldCost, heroReviveLumberCost); + } + } + public void queueResearch(final CSimulation game, final War3ID rawcode) { queue(game, rawcode, QueueItemType.RESEARCH); } public static enum QueueItemType { UNIT, - RESEARCH; + RESEARCH, + HERO_REVIVE; } public void setRallyPoint(final AbilityTarget target) { @@ -1377,7 +1552,7 @@ private static final class UseAbilityOnTargetByIdVisitor implements AbilityTarge private int rallyOrderId; private UseAbilityOnTargetByIdVisitor reset(final CSimulation game, final CUnit trainedUnit, - final int rallyOrderId) { + final int rallyOrderId) { this.game = game; this.trainedUnit = trainedUnit; this.rallyOrderId = rallyOrderId; @@ -1412,7 +1587,7 @@ public Void accept(final CUnit targetUnit) { } private Void acceptWidget(final CSimulation game, final CUnit trainedUnit, final int rallyOrderId, - final CWidget target) { + final CWidget target) { CAbility abilityToUse = null; for (final CAbility ability : trainedUnit.getAbilities()) { ability.checkCanUse(game, trainedUnit, rallyOrderId, BooleanAbilityActivationReceiver.INSTANCE); @@ -1580,15 +1755,26 @@ public void onRemove(final CSimulation simulation) { simulation.getWorldCollision().removeUnit(this); } - /** - * @Author MfromAzeroth - * This method increases a unit's health according to its hit point regeneration - * (If something with this is off it's probably my fault) - */ - private void regenerateHitPoints(){ - if(this.life classifications, - final List attacks, final String armorType, final boolean raise, final boolean decay, - final CDefenseType defenseType, final float impactZ, final BufferedImage buildingPathingPixelMap, - final float deathTime, final EnumSet targetedAs, final float defaultAcquisitionRange, - final float minimumAttackRange, final List structuresBuilt, final List unitsTrained, - final List researchesAvailable, final CUnitRace unitRace, final int goldCost, final int lumberCost, - final int foodUsed, final int foodMade, final int buildTime, - final EnumSet preventedPathingTypes, - final EnumSet requiredPathingTypes, final float propWindow, final float turnRate, - final List requirements, final int level, final boolean hero, final int strength, - final float strengthPerLevel, final int agility, final float agilityPerLevel, final int intelligence, - final float intelligencePerLevel, final CPrimaryAttribute primaryAttribute, - final List heroAbilityList, final List heroProperNames, final int properNamesCount, - final boolean canFlee, final int priority) { + private final boolean revivesHeroes; + + public CUnitType(final String name, final String legacyName, final War3ID typeId, final int maxLife, + final int manaInitial, final int manaMaximum, final int speed, final int defense, final String abilityList, + final boolean isBldg, final MovementType movementType, final float defaultFlyingHeight, + final float collisionSize, final EnumSet classifications, + final List attacks, final String armorType, final boolean raise, final boolean decay, + final CDefenseType defenseType, final float impactZ, final BufferedImage buildingPathingPixelMap, + final float deathTime, final EnumSet targetedAs, final float defaultAcquisitionRange, + final float minimumAttackRange, final List structuresBuilt, final List unitsTrained, + final List researchesAvailable, final CUnitRace unitRace, final int goldCost, final int lumberCost, + final int foodUsed, final int foodMade, final int buildTime, + final EnumSet preventedPathingTypes, + final EnumSet requiredPathingTypes, final float propWindow, final float turnRate, + final List requirements, final int level, final boolean hero, final int strength, + final float strengthPerLevel, final int agility, final float agilityPerLevel, final int intelligence, + final float intelligencePerLevel, final CPrimaryAttribute primaryAttribute, + final List heroAbilityList, final List heroProperNames, final int properNamesCount, + final boolean canFlee, final int priority, final boolean revivesHeroes) { this.name = name; this.legacyName = legacyName; this.typeId = typeId; this.maxLife = maxLife; - this.lifeRegeneration = lifeRegeneration; this.manaInitial = manaInitial; this.manaMaximum = manaMaximum; this.speed = speed; @@ -148,6 +147,7 @@ public CUnitType(final String name, final String legacyName, final War3ID typeId this.properNamesCount = properNamesCount; this.canFlee = canFlee; this.priority = priority; + this.revivesHeroes = revivesHeroes; } public String getName() { @@ -166,10 +166,6 @@ public int getMaxLife() { return this.maxLife; } - public float getLifeRegeneration() { - return this.lifeRegeneration; - } - public int getManaInitial() { return this.manaInitial; } @@ -365,4 +361,8 @@ public boolean isCanFlee() { public int getPriority() { return this.priority; } -} + + public boolean isRevivesHeroes() { + return this.revivesHeroes; + } +} \ No newline at end of file diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityNightElfBuild.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityNightElfBuild.java index 9fd0a2ada..19193b101 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityNightElfBuild.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityNightElfBuild.java @@ -11,12 +11,13 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityVisitor; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityPointTarget; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.build.CBehaviorNightElfBuild; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.build.CBehaviorOrcBuild; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer; public class CAbilityNightElfBuild extends AbstractCAbilityBuild { - private CBehaviorOrcBuild buildBehavior; + private CBehaviorNightElfBuild buildBehavior; public CAbilityNightElfBuild(final int handleId, final List structuresBuilt) { super(handleId, structuresBuilt); @@ -29,7 +30,7 @@ public T visit(final CAbilityVisitor visitor) { @Override public void onAdd(final CSimulation game, final CUnit unit) { - this.buildBehavior = new CBehaviorOrcBuild(unit); + this.buildBehavior = new CBehaviorNightElfBuild(unit); } @Override diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorHumanBuild.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorHumanBuild.java new file mode 100644 index 000000000..626faed5e --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorHumanBuild.java @@ -0,0 +1,4 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.build; + +public class CBehaviorHumanBuild { +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorNightElfBuild.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorNightElfBuild.java new file mode 100644 index 000000000..8040e4989 --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorNightElfBuild.java @@ -0,0 +1,66 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.build; + +import com.etheller.warsmash.util.WarsmashConstants; +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.CUnitType; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityBuildInProgress; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.pathing.CBuildingPathingType; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer; + +import java.awt.image.BufferedImage; +import java.util.EnumSet; + +public class CBehaviorNightElfBuild extends CBehaviorOrcBuild{ + public CBehaviorNightElfBuild(CUnit unit) { + super(unit); + } + + @Override + protected CBehavior update(final CSimulation simulation, final boolean withinFacingWindow) { + if (!this.unitCreated) { + this.unitCreated = true; + final CUnitType unitTypeToCreate = simulation.getUnitData().getUnitType(this.orderId); + final BufferedImage buildingPathingPixelMap = unitTypeToCreate.getBuildingPathingPixelMap(); + boolean buildLocationObstructed = false; + if (buildingPathingPixelMap != null) { + final EnumSet preventedPathingTypes = unitTypeToCreate.getPreventedPathingTypes(); + final EnumSet requiredPathingTypes = unitTypeToCreate.getRequiredPathingTypes(); + + if (!simulation.getPathingGrid().checkPathingTexture(this.target.getX(), this.target.getY(), + (int) simulation.getGameplayConstants().getBuildingAngle(), buildingPathingPixelMap, + preventedPathingTypes, requiredPathingTypes, simulation.getWorldCollision(), this.unit)) { + buildLocationObstructed = true; + } + } + final int playerIndex = this.unit.getPlayerIndex(); + if (!buildLocationObstructed) { + final CUnit constructedStructure = simulation.createUnit(this.orderId, playerIndex, this.target.getX(), + this.target.getY(), simulation.getGameplayConstants().getBuildingAngle()); + constructedStructure.setConstructing(true); + constructedStructure.setWorkerInside(this.unit); + constructedStructure.setLife(simulation, + constructedStructure.getMaximumLife() * WarsmashConstants.BUILDING_CONSTRUCT_START_LIFE); + constructedStructure.setFoodUsed(unitTypeToCreate.getFoodUsed()); + constructedStructure.add(simulation, + new CAbilityBuildInProgress(simulation.getHandleIdAllocator().createId())); + for (final CAbility ability : constructedStructure.getAbilities()) { + ability.visit(AbilityDisableWhileUnderConstructionVisitor.INSTANCE); + } + this.unit.setHidden(true); + this.unit.setPaused(true); + this.unit.setInvulnerable(true); + constructedStructure.setConstuctionProcessType(ConstructionFlag.CONSUME_WORKER); + simulation.unitConstructedEvent(this.unit, constructedStructure); + } + else { + final CPlayer player = simulation.getPlayer(playerIndex); + refund(player, unitTypeToCreate); + simulation.getCommandErrorListener(playerIndex).showCantPlaceError(); + } + } + return this.unit.pollNextOrderBehavior(simulation); + } +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorOrcBuild.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorOrcBuild.java index 9f7cd1b9f..335652b41 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorOrcBuild.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorOrcBuild.java @@ -17,9 +17,9 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer; public class CBehaviorOrcBuild extends CAbstractRangedBehavior { - private int highlightOrderId; - private War3ID orderId; - private boolean unitCreated = false; + protected int highlightOrderId; + protected War3ID orderId; + protected boolean unitCreated = false; public CBehaviorOrcBuild(final CUnit unit) { super(unit); @@ -118,7 +118,7 @@ public void end(final CSimulation game, final boolean interrupted) { } } - private void refund(final CPlayer player, final CUnitType unitTypeToCreate) { + protected void refund(final CPlayer player, final CUnitType unitTypeToCreate) { player.setFoodUsed(player.getFoodUsed() - unitTypeToCreate.getFoodUsed()); player.refundFor(unitTypeToCreate); } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/ConstructionFlag.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/ConstructionFlag.java new file mode 100644 index 000000000..065dfab5a --- /dev/null +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/ConstructionFlag.java @@ -0,0 +1,5 @@ +package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.build; + +public enum ConstructionFlag { + NONE, CONSUME_WORKER, REQURIE_REPAIR; +} diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/data/CUnitData.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/data/CUnitData.java index 6351a4bb5..8754146ee 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/data/CUnitData.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/data/CUnitData.java @@ -33,6 +33,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.hero.CPrimaryAttribute; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityQueue; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityRally; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.queue.CAbilityReviveHero; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CAttackType; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CDefenseType; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.combat.CTargetType; @@ -51,7 +52,6 @@ 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 HIT_POINT_REGENERATION = War3ID.fromString("uhpr"); 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"); @@ -144,6 +144,7 @@ public class CUnitData { private static final War3ID STRUCTURES_BUILT = War3ID.fromString("ubui"); private static final War3ID UNITS_TRAINED = War3ID.fromString("utra"); private static final War3ID RESEARCHES_AVAILABLE = War3ID.fromString("ures"); + private static final War3ID REVIVES_HEROES = War3ID.fromString("urev"); private static final War3ID UNIT_RACE = War3ID.fromString("urac"); private static final War3ID REQUIRES = War3ID.fromString("ureq"); @@ -179,7 +180,7 @@ public class CUnitData { private final SimulationRenderController simulationRenderController; public CUnitData(final CGameplayConstants gameplayConstants, final MutableObjectData unitData, - final CAbilityData abilityData, final SimulationRenderController simulationRenderController) { + final CAbilityData abilityData, final SimulationRenderController simulationRenderController) { this.gameplayConstants = gameplayConstants; this.unitData = unitData; this.abilityData = abilityData; @@ -187,8 +188,8 @@ public CUnitData(final CGameplayConstants gameplayConstants, final MutableObject } 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 HandleIdAllocator handleIdAllocator, final RemovablePathingMapInstance pathingInstance) { + final float y, final float facing, final BufferedImage buildingPathingPixelMap, + final HandleIdAllocator handleIdAllocator, final RemovablePathingMapInstance pathingInstance) { final MutableGameObject unitType = this.unitData.get(typeId); final int handleId = handleIdAllocator.createId(); @@ -216,27 +217,27 @@ public CUnit create(final CSimulation simulation, final int playerIndex, final W final List structuresBuilt = unitTypeInstance.getStructuresBuilt(); if (!structuresBuilt.isEmpty()) { switch (unitTypeInstance.getRace()) { - case ORC: - unit.add(simulation, new CAbilityOrcBuild(handleIdAllocator.createId(), structuresBuilt)); - break; - case HUMAN: - unit.add(simulation, new CAbilityHumanBuild(handleIdAllocator.createId(), structuresBuilt)); - break; - case UNDEAD: - unit.add(simulation, new CAbilityUndeadBuild(handleIdAllocator.createId(), structuresBuilt)); - break; - case NIGHTELF: - unit.add(simulation, new CAbilityNightElfBuild(handleIdAllocator.createId(), structuresBuilt)); - break; - case NAGA: - unit.add(simulation, new CAbilityNagaBuild(handleIdAllocator.createId(), structuresBuilt)); - break; - case CREEPS: - case CRITTERS: - case DEMON: - case OTHER: - unit.add(simulation, new CAbilityOrcBuild(handleIdAllocator.createId(), structuresBuilt)); - break; + case ORC: + unit.add(simulation, new CAbilityOrcBuild(handleIdAllocator.createId(), structuresBuilt)); + break; + case HUMAN: + unit.add(simulation, new CAbilityHumanBuild(handleIdAllocator.createId(), structuresBuilt)); + break; + case UNDEAD: + unit.add(simulation, new CAbilityUndeadBuild(handleIdAllocator.createId(), structuresBuilt)); + break; + case NIGHTELF: + unit.add(simulation, new CAbilityNightElfBuild(handleIdAllocator.createId(), structuresBuilt)); + break; + case NAGA: + unit.add(simulation, new CAbilityNagaBuild(handleIdAllocator.createId(), structuresBuilt)); + break; + case CREEPS: + case CRITTERS: + case DEMON: + case OTHER: + unit.add(simulation, new CAbilityOrcBuild(handleIdAllocator.createId(), structuresBuilt)); + break; } } final List unitsTrained = unitTypeInstance.getUnitsTrained(); @@ -244,7 +245,10 @@ public CUnit create(final CSimulation simulation, final int playerIndex, final W if (!unitsTrained.isEmpty() || !researchesAvailable.isEmpty()) { unit.add(simulation, new CAbilityQueue(handleIdAllocator.createId(), unitsTrained, researchesAvailable)); } - if (!unitsTrained.isEmpty()) { + if (unitTypeInstance.isRevivesHeroes()) { + unit.add(simulation, new CAbilityReviveHero(handleIdAllocator.createId())); + } + if (!unitsTrained.isEmpty() || unitTypeInstance.isRevivesHeroes()) { unit.add(simulation, new CAbilityRally(handleIdAllocator.createId())); } if (unitTypeInstance.isHero()) { @@ -265,12 +269,11 @@ public CUnit create(final CSimulation simulation, final int playerIndex, final W } private CUnitType getUnitTypeInstance(final War3ID typeId, final BufferedImage buildingPathingPixelMap, - final MutableGameObject unitType) { + final MutableGameObject unitType) { CUnitType unitTypeInstance = this.unitIdToUnitType.get(typeId); if (unitTypeInstance == null) { final String legacyName = getLegacyName(unitType); final int life = unitType.getFieldAsInteger(HIT_POINT_MAXIMUM, 0); - final float lifeRegeneration = unitType.getFieldAsFloat(HIT_POINT_REGENERATION,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); @@ -420,10 +423,10 @@ private CUnitType getUnitTypeInstance(final War3ID typeId, final BufferedImage b final CUnitAttack otherAttack = attacks.get(0); if ((otherAttack.getAttackType() == attackType) && (targetsAllowed.size() == 1) && (targetsAllowed.contains(CTargetType.TREE) - || (targetsAllowed.contains(CTargetType.STRUCTURE) - && (otherAttack.getDamageBase() == damageBase) - && (otherAttack.getDamageSidesPerDie() == damageSidesPerDie) - && (otherAttack.getDamageDice() == damageDice)))) { + || (targetsAllowed.contains(CTargetType.STRUCTURE) + && (otherAttack.getDamageBase() == damageBase) + && (otherAttack.getDamageSidesPerDie() == damageSidesPerDie) + && (otherAttack.getDamageDice() == damageDice)))) { showUI = false; } } @@ -452,6 +455,8 @@ private CUnitType getUnitTypeInstance(final War3ID typeId, final BufferedImage b final int foodUsed = unitType.getFieldAsInteger(FOOD_USED, 0); final int foodMade = unitType.getFieldAsInteger(FOOD_MADE, 0); + final boolean revivesHeroes = unitType.getFieldAsBoolean(REVIVES_HEROES, 0); + final String unitsTrainedString = unitType.getFieldAsString(UNITS_TRAINED, 0); final String[] unitsTrainedStringItems = unitsTrainedString.trim().split(","); final List unitsTrained = new ArrayList<>(); @@ -533,14 +538,14 @@ else if (requirementsLevelsStringItems.length > 0) { final List heroProperNames = Arrays.asList(properNames.split(",")); - unitTypeInstance = new CUnitType(unitName, legacyName, typeId, life, lifeRegeneration, manaInitial, manaMaximum, speed, + unitTypeInstance = new CUnitType(unitName, legacyName, typeId, life, manaInitial, manaMaximum, speed, defense, abilityList, isBldg, movementType, moveHeight, collisionSize, classifications, attacks, armorType, raise, decay, defenseType, impactZ, buildingPathingPixelMap, deathTime, targetedAs, acquisitionRange, minimumAttackRange, structuresBuilt, unitsTrained, researchesAvailable, unitRace, goldCost, lumberCost, foodUsed, foodMade, buildTime, preventedPathingTypes, requiredPathingTypes, propWindow, turnRate, requirements, unitLevel, hero, strength, strPlus, agility, agiPlus, intelligence, intPlus, primaryAttribute, heroAbilityList, heroProperNames, properNamesCount, - canFlee, priority); + canFlee, priority, revivesHeroes); this.unitIdToUnitType.put(typeId, unitTypeInstance); this.jassLegacyNameToUnitId.put(legacyName, typeId); } @@ -577,56 +582,56 @@ private static int[] populateHeroStatTable(final int maxHeroLevel, final float s } private CUnitAttack createAttack(final float animationBackswingPoint, final float animationDamagePoint, - final int areaOfEffectFullDamage, final int areaOfEffectMediumDamage, final int areaOfEffectSmallDamage, - final EnumSet 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 targetsAllowed, - final String weaponSound, final CWeaponType weaponType) { + final int areaOfEffectFullDamage, final int areaOfEffectMediumDamage, final int areaOfEffectSmallDamage, + final EnumSet 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 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; + 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; } @@ -655,7 +660,7 @@ public int getA1MinDamage(final War3ID unitTypeId) { 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)); + * this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK1_DMG_SIDES_PER_DIE, 0)); } public int getA2MinDamage(final War3ID unitTypeId) { @@ -666,7 +671,7 @@ public int getA2MinDamage(final War3ID unitTypeId) { 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)); + * this.unitData.get(unitTypeId).getFieldAsInteger(ATTACK2_DMG_SIDES_PER_DIE, 0)); } public int getDefense(final War3ID unitTypeId) { @@ -748,4 +753,4 @@ public CUnitType getUnitTypeByJassLegacyName(final String jassLegacyName) { } return getUnitType(typeId); } -} +} \ No newline at end of file From 4ee537de4923741a85ba0eade05dd2356dd21f94 Mon Sep 17 00:00:00 2001 From: MfromAzeroth Date: Mon, 24 Jan 2022 22:16:45 +0100 Subject: [PATCH 5/6] Implemented Human Build, Power Building and Repair Costs --- .../handlers/w3x/simulation/CUnit.java | 21 ++- .../abilities/build/CAbilityHumanBuild.java | 36 +++- .../abilities/build/CAbilityHumanRepair.java | 23 +++ .../CAbilityTypeDefinitionHumanRepair.java | 6 +- .../types/impl/CAbilityTypeHumanRepair.java | 3 +- .../CAbilityTypeHumanRepairLevelData.java | 11 +- .../behaviors/build/CBehaviorHumanBuild.java | 162 +++++++++++++++++- .../behaviors/build/CBehaviorHumanRepair.java | 69 +++++++- .../build/CBehaviorNightElfBuild.java | 5 +- .../w3x/simulation/players/CPlayer.java | 15 ++ resources.mpq | Bin 0 -> 2240 bytes warsmash.ini | 14 ++ 12 files changed, 339 insertions(+), 26 deletions(-) create mode 100644 resources.mpq create mode 100644 warsmash.ini diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java index 825725dab..886073777 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java @@ -112,6 +112,7 @@ public class CUnit extends CWidget { private float constructionProgress; //added by MfromAz - if it's bad that's on me private ConstructionFlag constuctionProcessType; + private boolean constructionPowerBuild = false; private boolean hidden = false; private boolean paused = false; private boolean acceptingOrders = true; @@ -268,6 +269,10 @@ public void setConsumed(boolean consumed){ public void setConstuctionProcessType(ConstructionFlag flag) {this.constuctionProcessType = flag;} + public void setConstructionPowerBuild(boolean constructionPowerBuild){this.constructionPowerBuild= constructionPowerBuild;} + + public boolean isConstructionPowerBuilding(){return constructionPowerBuild;} + /** * Updates one tick of simulation logic and return true if it's time to remove * this unit from the game. @@ -340,12 +345,19 @@ else if (!this.paused) { setRallyPoint(this); } if (this.constructing) { - this.constructionProgress += WarsmashConstants.SIMULATION_STEP_TIME; + + final int buildTime = this.unitType.getBuildTime(); //ignore this for human build (MFROMAZ) - final float healthGain = (WarsmashConstants.SIMULATION_STEP_TIME / buildTime) - * (this.maximumLife * (1.0f - WarsmashConstants.BUILDING_CONSTRUCT_START_LIFE)); - setLife(game, Math.min(this.life + healthGain, this.maximumLife)); + if(this.constuctionProcessType==null||this.constuctionProcessType!=ConstructionFlag.REQURIE_REPAIR) { + this.constructionProgress += WarsmashConstants.SIMULATION_STEP_TIME; + final float healthGain = (WarsmashConstants.SIMULATION_STEP_TIME / buildTime) + * (this.maximumLife * (1.0f - WarsmashConstants.BUILDING_CONSTRUCT_START_LIFE)); + setLife(game, Math.min(this.life + healthGain, this.maximumLife)); + }else{ + this.constructionPowerBuild = false; + //resetting here every frame so that workers can set it to true on the next one again + } if (this.constructionProgress >= buildTime) { this.constructing = false; this.constructionProgress = 0; @@ -359,6 +371,7 @@ else if (!this.paused) { } //create Blight here (MFROMAZ) + final Iterator abilityIterator = this.abilities.iterator(); while (abilityIterator.hasNext()) { final CAbility ability = abilityIterator.next(); diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityHumanBuild.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityHumanBuild.java index b6f420ff9..a7dce6549 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityHumanBuild.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityHumanBuild.java @@ -1,21 +1,26 @@ package com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build; +import java.awt.image.BufferedImage; import java.util.List; import com.etheller.warsmash.util.War3ID; 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.CUnitType; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CWidget; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbilityVisitor; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityPointTarget; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.build.CBehaviorHumanBuild; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.build.CBehaviorNightElfBuild; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer; public class CAbilityHumanBuild extends AbstractCAbilityBuild { + private CBehaviorHumanBuild buildBehavior; public CAbilityHumanBuild(final int handleId, final List structuresBuilt) { super(handleId, structuresBuilt); - // TODO Auto-generated constructor stub } @Override @@ -25,8 +30,7 @@ public int getBaseOrderId() { @Override public void onAdd(final CSimulation game, final CUnit unit) { - // TODO Auto-generated method stub - + this.buildBehavior = new CBehaviorHumanBuild(unit); } @Override @@ -37,21 +41,37 @@ public void onRemove(final CSimulation game, final CUnit unit) { @Override public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final CWidget target) { - // TODO Auto-generated method stub - return null; + return caster.pollNextOrderBehavior(game); } @Override public CBehavior begin(final CSimulation game, final CUnit caster, final int orderId, final AbilityPointTarget point) { // caster.getMoveBehavior().reset(point.x, point.y, ) - return null; + final War3ID orderIdAsRawtype = new War3ID(orderId); + final CUnitType unitType = game.getUnitData().getUnitType(orderIdAsRawtype); + final BufferedImage buildingPathingPixelMap = unitType.getBuildingPathingPixelMap(); + if (buildingPathingPixelMap != null) { + point.x = (float) Math.floor(point.x / 64f) * 64f; + point.y = (float) Math.floor(point.y / 64f) * 64f; + if (((buildingPathingPixelMap.getWidth() / 2) % 2) == 1) { + point.x += 32f; + } + if (((buildingPathingPixelMap.getHeight() / 2) % 2) == 1) { + point.y += 32f; + } + } + final CPlayer player = game.getPlayer(caster.getPlayerIndex()); + player.chargeFor(unitType); + if (unitType.getFoodUsed() != 0) { + player.setFoodUsed(player.getFoodUsed() + unitType.getFoodUsed()); + } + return this.buildBehavior.reset(point, orderId, getBaseOrderId()); } @Override public CBehavior beginNoTarget(final CSimulation game, final CUnit caster, final int orderId) { - // TODO Auto-generated method stub - return null; + return caster.pollNextOrderBehavior(game); } @Override diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityHumanRepair.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityHumanRepair.java index 3b1ec1400..f2f3a9df5 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityHumanRepair.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityHumanRepair.java @@ -21,8 +21,12 @@ public class CAbilityHumanRepair extends AbstractGenericSingleIconActiveAbility private final float repairCostRatio; private final float repairTimeRatio; private final float castRange; + private final float powerBuildCostRatio; + private final float powerBuildTimeRatio; private CBehaviorHumanRepair behaviorRepair; + /* + //old version left in for compatibility public CAbilityHumanRepair(int handleId, War3ID alias, EnumSet targetsAllowed, float navalRangeBonus, float repairCostRatio, float repairTimeRatio, float castRange) { @@ -32,6 +36,21 @@ public CAbilityHumanRepair(int handleId, War3ID alias, EnumSet targ this.repairCostRatio = repairCostRatio; this.repairTimeRatio = repairTimeRatio; this.castRange = castRange; + this.powerBuildCostRatio = 0; + this.powerBuildTimeRatio = 0; + }*/ + + public CAbilityHumanRepair(int handleId, War3ID alias, EnumSet targetsAllowed, + float navalRangeBonus, float repairCostRatio, float repairTimeRatio, + float castRange, float powerBuildCostRatio, float powerBuildTimeRatio) { + super(handleId, alias); + this.targetsAllowed = targetsAllowed; + this.navalRangeBonus = navalRangeBonus; + this.repairCostRatio = repairCostRatio; + this.repairTimeRatio = repairTimeRatio; + this.castRange = castRange; + this.powerBuildCostRatio = powerBuildCostRatio; + this.powerBuildTimeRatio = powerBuildTimeRatio; } @Override @@ -132,4 +151,8 @@ public float getRepairTimeRatio() { public float getCastRange() { return castRange; } + + public float getPowerBuildCostRatio() { return powerBuildCostRatio; } + + public float getPowerBuildTimeRatio() { return powerBuildTimeRatio; } } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/types/definitions/impl/CAbilityTypeDefinitionHumanRepair.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/types/definitions/impl/CAbilityTypeDefinitionHumanRepair.java index 758d6ad0d..0660d25f1 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/types/definitions/impl/CAbilityTypeDefinitionHumanRepair.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/types/definitions/impl/CAbilityTypeDefinitionHumanRepair.java @@ -15,6 +15,8 @@ public class CAbilityTypeDefinitionHumanRepair extends AbstractCAbilityTypeDefin implements CAbilityTypeDefinition { protected static final War3ID COST_RATIO = War3ID.fromString("Rep1"); protected static final War3ID TIME_RATIO = War3ID.fromString("Rep2"); + protected static final War3ID POWER_COST_RATIO = War3ID.fromString("Rep3"); + protected static final War3ID POWER_TIME_RATIO = War3ID.fromString("Rep4"); protected static final War3ID NAVAL_RANGE_BONUS = War3ID.fromString("Rep5"); @Override @@ -23,9 +25,11 @@ protected CAbilityTypeHumanRepairLevelData createLevelData(final MutableGameObje final EnumSet targetsAllowedAtLevel = CTargetType.parseTargetTypeSet(targetsAllowedAtLevelString); final float costRatio = abilityEditorData.getFieldAsFloat(COST_RATIO, level); final float timeRatio = abilityEditorData.getFieldAsFloat(TIME_RATIO, level); + final float powerBuildCostRatio = abilityEditorData.getFieldAsFloat(POWER_COST_RATIO,level); + final float powerBuildTimeRatio = abilityEditorData.getFieldAsFloat(POWER_TIME_RATIO,level); final float navalRangeBonus = abilityEditorData.getFieldAsFloat(NAVAL_RANGE_BONUS, level); final float castRange = abilityEditorData.getFieldAsFloat(CAST_RANGE, level); - return new CAbilityTypeHumanRepairLevelData(targetsAllowedAtLevel, navalRangeBonus, costRatio, timeRatio, castRange); + return new CAbilityTypeHumanRepairLevelData(targetsAllowedAtLevel, navalRangeBonus, costRatio, timeRatio, castRange, powerBuildCostRatio, powerBuildTimeRatio); } @Override diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/types/impl/CAbilityTypeHumanRepair.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/types/impl/CAbilityTypeHumanRepair.java index e1c769221..3b6767f12 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/types/impl/CAbilityTypeHumanRepair.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/types/impl/CAbilityTypeHumanRepair.java @@ -17,9 +17,10 @@ public CAbilityTypeHumanRepair(final War3ID alias, final War3ID code, @Override public CAbility createAbility(final int handleId) { final CAbilityTypeHumanRepairLevelData levelData = getLevelData(0); + //System.out.println("Time: "+levelData.getPowerbuildTimeRatio() + " Cost: " + levelData.getPowerbuildCostRatio() ); return new CAbilityHumanRepair(handleId, getAlias(), levelData.getTargetsAllowed(), levelData.getNavalRangeBonus(), levelData.getRepairCostRatio(), levelData.getRepairTimeRatio(), - levelData.getCastRange()); + levelData.getCastRange(), levelData.getPowerbuildCostRatio(), levelData.getPowerbuildTimeRatio()); } } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/types/impl/CAbilityTypeHumanRepairLevelData.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/types/impl/CAbilityTypeHumanRepairLevelData.java index 834bf8798..6535c00f5 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/types/impl/CAbilityTypeHumanRepairLevelData.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/types/impl/CAbilityTypeHumanRepairLevelData.java @@ -10,13 +10,18 @@ public class CAbilityTypeHumanRepairLevelData extends CAbilityTypeLevelData { private final float navalRangeBonus; private final float repairCostRatio; private final float repairTimeRatio; + private final float powerbuildCostRatio; + private final float powerbuildTimeRatio; private final float castRange; - public CAbilityTypeHumanRepairLevelData(EnumSet targetsAllowed, float navalRangeBonus, float repairCostRatio, float repairTimeRatio, float castRange) { + public CAbilityTypeHumanRepairLevelData(EnumSet targetsAllowed, float navalRangeBonus, float repairCostRatio, + float repairTimeRatio, float castRange, float powerBuildCostRatio, float powerBuildTimeRatio) { super(targetsAllowed); this.navalRangeBonus = navalRangeBonus; this.repairCostRatio = repairCostRatio; this.repairTimeRatio = repairTimeRatio; + this.powerbuildCostRatio = powerBuildCostRatio; + this.powerbuildTimeRatio = powerBuildTimeRatio; this.castRange = castRange; } @@ -35,4 +40,8 @@ public float getRepairCostRatio() { public float getRepairTimeRatio() { return repairTimeRatio; } + + public float getPowerbuildCostRatio(){ return powerbuildCostRatio; }; + + public float getPowerbuildTimeRatio() { return powerbuildTimeRatio; } } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorHumanBuild.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorHumanBuild.java index 626faed5e..d3c8b0aac 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorHumanBuild.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorHumanBuild.java @@ -1,4 +1,164 @@ package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.build; -public class CBehaviorHumanBuild { +import com.etheller.warsmash.util.War3ID; +import com.etheller.warsmash.util.WarsmashConstants; +import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens; +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.CUnitType; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityBuildInProgress; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityHumanRepair; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.targeting.AbilityPointTarget; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CAbstractRangedBehavior; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.pathing.CBuildingPathingType; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer; + +import java.awt.image.BufferedImage; +import java.util.EnumSet; + +public class CBehaviorHumanBuild extends CAbstractRangedBehavior { + private static int delayAnimationTicks = (int) (2.267f / WarsmashConstants.SIMULATION_STEP_TIME); + private int highlightOrderId; + private War3ID orderId; + private boolean unitCreated = false; + private boolean done = false; + private CUnit constructedStructure = null; + + public CBehaviorHumanBuild(CUnit unit) { + super(unit); + } + + public CBehavior reset(final AbilityPointTarget target, final int orderId, final int highlightOrderId) { + this.highlightOrderId = highlightOrderId; + this.orderId = new War3ID(orderId); + this.unitCreated = false; + this.done = false; + return innerReset(target); + } + + @Override + public boolean isWithinRange(final CSimulation simulation) { + if (this.done != false) { + return true; + } + final CUnitType unitType = simulation.getUnitData().getUnitType(this.orderId); + final BufferedImage buildingPathingPixelMap = unitType.getBuildingPathingPixelMap(); + if (buildingPathingPixelMap == null) { + return this.unit.canReach(this.target.getX(), this.target.getY(), unitType.getCollisionSize()); + } + return this.unit.canReachToPathing(0, simulation.getGameplayConstants().getBuildingAngle(), + buildingPathingPixelMap, this.target.getX(), this.target.getY()); + } + + @Override + public int getHighlightOrderId() { + return this.highlightOrderId; + } + + @Override + protected CBehavior update(final CSimulation simulation, final boolean withinFacingWindow) { + if (this.done) { + if(this.constructedStructure==null){ + return this.unit.pollNextOrderBehavior(simulation); + }else{ + CBehaviorHumanRepair repair = new CBehaviorHumanRepair(this.unit,this.unit.getFirstAbilityOfType(CAbilityHumanRepair.class)); + repair.reset(this.constructedStructure); + return repair; + } + } + else if (!this.unitCreated) { + this.unitCreated = true; + final CUnitType unitTypeToCreate = simulation.getUnitData().getUnitType(this.orderId); + final BufferedImage buildingPathingPixelMap = unitTypeToCreate.getBuildingPathingPixelMap(); + boolean buildLocationObstructed = false; + if (buildingPathingPixelMap != null) { + final EnumSet preventedPathingTypes = unitTypeToCreate.getPreventedPathingTypes(); + final EnumSet requiredPathingTypes = unitTypeToCreate.getRequiredPathingTypes(); + + if (!simulation.getPathingGrid().checkPathingTexture(this.target.getX(), this.target.getY(), + (int) simulation.getGameplayConstants().getBuildingAngle(), buildingPathingPixelMap, + preventedPathingTypes, requiredPathingTypes, simulation.getWorldCollision(), this.unit)) { + buildLocationObstructed = true; + } + } + final int playerIndex = this.unit.getPlayerIndex(); + if (!buildLocationObstructed) { + constructedStructure = simulation.createUnit(this.orderId, playerIndex, this.target.getX(), + this.target.getY(), simulation.getGameplayConstants().getBuildingAngle()); + constructedStructure.setConstructing(true); + constructedStructure.setLife(simulation, + constructedStructure.getMaximumLife() * WarsmashConstants.BUILDING_CONSTRUCT_START_LIFE); + constructedStructure.setFoodUsed(unitTypeToCreate.getFoodUsed()); + constructedStructure.add(simulation, + new CAbilityBuildInProgress(simulation.getHandleIdAllocator().createId())); + for (final CAbility ability : constructedStructure.getAbilities()) { + ability.visit(AbilityDisableWhileUnderConstructionVisitor.INSTANCE); + } + final float deltaX = this.unit.getX() - this.target.getX(); + final float deltaY = this.unit.getY() - this.target.getY(); + final float delta = (float) Math.sqrt((deltaX * deltaX) + (deltaY * deltaY)); + this.unit.setPoint(this.target.getX() + ((deltaX / delta) * unitTypeToCreate.getCollisionSize()), + this.target.getY() + ((deltaY / delta) * unitTypeToCreate.getCollisionSize()), + simulation.getWorldCollision(), simulation.getRegionManager()); + constructedStructure.setConstuctionProcessType(ConstructionFlag.REQURIE_REPAIR); + simulation.unitRepositioned(this.unit); + simulation.unitConstructedEvent(this.unit, constructedStructure); + this.done = true; + } + else { + final CPlayer player = simulation.getPlayer(playerIndex); + refund(player, unitTypeToCreate); + simulation.getCommandErrorListener(playerIndex).showCantPlaceError(); + return this.unit.pollNextOrderBehavior(simulation); + } + } + this.unit.getUnitAnimationListener().playAnimation(false, AnimationTokens.PrimaryTag.STAND, SequenceUtils.WORK, 1.0f, true); + return this; + } + + @Override + protected boolean checkTargetStillValid(final CSimulation simulation) { + return true; + } + + @Override + protected CBehavior updateOnInvalidTarget(final CSimulation simulation) { + return this.unit.pollNextOrderBehavior(simulation); + } + + @Override + protected void resetBeforeMoving(final CSimulation simulation) { + + } + + @Override + public void begin(final CSimulation game) { + + } + + @Override + public void end(final CSimulation game, final boolean interrupted) { + if (!this.unitCreated && interrupted) { + final CPlayer player = game.getPlayer(this.unit.getPlayerIndex()); + final CUnitType unitTypeToCreate = game.getUnitData().getUnitType(this.orderId); + refund(player, unitTypeToCreate); + } + } + + private void refund(final CPlayer player, final CUnitType unitTypeToCreate) { + player.setFoodUsed(player.getFoodUsed() - unitTypeToCreate.getFoodUsed()); + player.refundFor(unitTypeToCreate); + } + + @Override + public void endMove(final CSimulation game, final boolean interrupted) { + if (!this.unitCreated && interrupted) { + final CPlayer player = game.getPlayer(this.unit.getPlayerIndex()); + final CUnitType unitTypeToCreate = game.getUnitData().getUnitType(this.orderId); + refund(player, unitTypeToCreate); + } + } } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorHumanRepair.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorHumanRepair.java index 330555451..6573867e9 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorHumanRepair.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorHumanRepair.java @@ -1,5 +1,6 @@ package com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.build; +import com.etheller.warsmash.util.WarsmashConstants; import com.etheller.warsmash.viewer5.handlers.w3x.AnimationTokens; import com.etheller.warsmash.viewer5.handlers.w3x.SequenceUtils; import com.etheller.warsmash.viewer5.handlers.w3x.environment.PathingGrid; @@ -12,6 +13,7 @@ import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.CBehavior; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.behaviors.harvest.CBehaviorHarvest; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.orders.OrderIds; +import com.etheller.warsmash.viewer5.handlers.w3x.simulation.players.CPlayer; public class CBehaviorHumanRepair extends CAbstractRangedBehavior { private final CAbilityHumanRepair ability; @@ -42,17 +44,66 @@ public boolean isWithinRange(CSimulation simulation) { @Override protected CBehavior update(CSimulation simulation, boolean withinFacingWindow) { - unit.getUnitAnimationListener().playAnimation(false, AnimationTokens.PrimaryTag.STAND, - SequenceUtils.WORK, 1.0f, true); if(this.target instanceof CWidget) { CWidget targetWidget = (CWidget) this.target; - float newLifeValue = targetWidget.getLife() + 1; - boolean done = newLifeValue > targetWidget.getMaxLife(); - if(done) { - newLifeValue = targetWidget.getMaxLife(); - } - targetWidget.setLife(simulation, newLifeValue); - if(done) { + //progress construction here (MFROMAZ) + if(targetWidget.getClass()==CUnit.class) { + CUnit targetUnit = ((CUnit) targetWidget); + final CPlayer player = simulation.getPlayer(unit.getPlayerIndex()); + float newLifeValue = targetWidget.getLife() + + ((WarsmashConstants.SIMULATION_STEP_TIME / (targetUnit.getUnitType().getBuildTime()*this.ability.getRepairTimeRatio())) + * (targetUnit.getMaxLife())); + float costs_gold = ((WarsmashConstants.SIMULATION_STEP_TIME / (targetUnit.getUnitType().getBuildTime()*this.ability.getRepairTimeRatio())) + * (targetUnit.getUnitType().getGoldCost()*this.ability.getRepairCostRatio())); + float costs_lumber = ((WarsmashConstants.SIMULATION_STEP_TIME / (targetUnit.getUnitType().getBuildTime()*this.ability.getRepairTimeRatio())) + * (targetUnit.getUnitType().getLumberCost()*this.ability.getRepairCostRatio())); + + unit.getUnitAnimationListener().playAnimation(false, AnimationTokens.PrimaryTag.STAND, + SequenceUtils.WORK, 1.0f, true); + + float healthGain = (WarsmashConstants.SIMULATION_STEP_TIME / targetUnit.getUnitType().getBuildTime()) + * (targetUnit.getMaxLife() * (1.0f - WarsmashConstants.BUILDING_CONSTRUCT_START_LIFE)) * (ability.getRepairTimeRatio()); + + if (targetUnit.getConstuctionProcessType() != null + && targetUnit.getConstuctionProcessType().equals(ConstructionFlag.REQURIE_REPAIR) + && targetUnit.isConstructing() + && targetUnit.getConstructionProgress() < targetUnit.getUnitType().getBuildTime() /*targetUnit.getClassifications().contains(CUnitClassification.BUILDING) &&*/) { + float constructionProgressGain = WarsmashConstants.SIMULATION_STEP_TIME; + healthGain = (WarsmashConstants.SIMULATION_STEP_TIME / targetUnit.getUnitType().getBuildTime()) + * (targetUnit.getMaxLife() * (1.0f - WarsmashConstants.BUILDING_CONSTRUCT_START_LIFE)); + if(targetUnit.isConstructionPowerBuilding()){ + costs_gold = ((WarsmashConstants.SIMULATION_STEP_TIME / (targetUnit.getUnitType().getBuildTime()*this.ability.getPowerBuildTimeRatio())) + * (targetUnit.getUnitType().getGoldCost()*this.ability.getPowerBuildCostRatio())); + costs_lumber = ((WarsmashConstants.SIMULATION_STEP_TIME / (targetUnit.getUnitType().getBuildTime()*this.ability.getPowerBuildTimeRatio())) + * (targetUnit.getUnitType().getLumberCost()*this.ability.getPowerBuildCostRatio())); + constructionProgressGain = WarsmashConstants.SIMULATION_STEP_TIME * this.ability.getPowerBuildTimeRatio(); + healthGain = (WarsmashConstants.SIMULATION_STEP_TIME* ability.getPowerBuildTimeRatio() / targetUnit.getUnitType().getBuildTime()) + * (targetUnit.getMaxLife() * (1.0f - WarsmashConstants.BUILDING_CONSTRUCT_START_LIFE)); + }else{ + costs_gold = 0.0f; + costs_lumber = 0.0f; + targetUnit.setConstructionPowerBuild(true); + } + if(costs_gold > player.getGold() || costs_lumber > player.getLumber()) { + return unit.pollNextOrderBehavior(simulation); + } + targetUnit.setConstructionProgress(targetUnit.getConstructionProgress() +constructionProgressGain); + } + + newLifeValue = Math.min(targetUnit.getLife() + healthGain, targetUnit.getMaximumLife()); + if(costs_gold > player.getGold() || costs_lumber > player.getLumber()){ + return unit.pollNextOrderBehavior(simulation); + } + boolean done = (newLifeValue >= targetWidget.getMaxLife()); + if (done) { + newLifeValue = targetWidget.getMaxLife(); + } + player.charge(costs_gold,costs_lumber); + targetWidget.setLife(simulation, newLifeValue); + if (done && (targetUnit.getConstructionProgress()>= targetUnit.getUnitType().getBuildTime())||!targetUnit.isConstructing()) { + return unit.pollNextOrderBehavior(simulation); + } + }else{ return unit.pollNextOrderBehavior(simulation); } } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorNightElfBuild.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorNightElfBuild.java index 8040e4989..7b3820980 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorNightElfBuild.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorNightElfBuild.java @@ -3,6 +3,7 @@ import com.etheller.warsmash.util.WarsmashConstants; 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.CUnitClassification; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.CUnitType; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.CAbility; import com.etheller.warsmash.viewer5.handlers.w3x.simulation.abilities.build.CAbilityBuildInProgress; @@ -52,7 +53,9 @@ protected CBehavior update(final CSimulation simulation, final boolean withinFac this.unit.setHidden(true); this.unit.setPaused(true); this.unit.setInvulnerable(true); - constructedStructure.setConstuctionProcessType(ConstructionFlag.CONSUME_WORKER); + if(constructedStructure.getUnitType().getClassifications().contains(CUnitClassification.ANCIENT)) { + constructedStructure.setConstuctionProcessType(ConstructionFlag.CONSUME_WORKER); + } simulation.unitConstructedEvent(this.unit, constructedStructure); } else { diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/players/CPlayer.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/players/CPlayer.java index 0bf8ea423..ca12e9fbf 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/players/CPlayer.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/players/CPlayer.java @@ -29,6 +29,8 @@ public class CPlayer extends CBasePlayer { private final List heroes = new ArrayList<>(); private final EnumMap> eventTypeToEvents = new EnumMap<>( JassGameEventsWar3.class); + private float accumulatedLumberCost = 0.0f; + private float accumulatedGoldCost = 0.0f; // if you use triggers for this then the transient tag here becomes really // questionable -- it already was -- but I meant for those to inform us @@ -143,6 +145,19 @@ public boolean charge(final int gold, final int lumber) { return false; } + public boolean charge(final float gold, final float lumber){ + this.accumulatedLumberCost += lumber; + this.accumulatedGoldCost += gold; + int newGoldCost = (int)accumulatedGoldCost; + int newLumberCost = (int)accumulatedLumberCost; + if(this.charge(newGoldCost,newLumberCost)) { + this.accumulatedLumberCost -= newLumberCost; + this.accumulatedGoldCost -= newGoldCost; + return true; + } + return false; + } + public void refundFor(final CUnitType unitType) { this.lumber += unitType.getLumberCost(); this.gold += unitType.getGoldCost(); diff --git a/resources.mpq b/resources.mpq new file mode 100644 index 0000000000000000000000000000000000000000..8435df7441bb619f316f9a162cd4053403ca8f8a GIT binary patch literal 2240 zcmZWqX*?4Q7#}0%2ty=iuEsRvj!?ojG^e7`*Z=lSydpX2{~9#eA*A#nfz@S63=0Dyo2768Ef$UhE`-2d?A5i$y9 zvTr5%$s;JHShy(;L^Xv{S+|lvWQyt5wE%eaCIv}0F@us}gGeNNevz%`shSF`K}x)% zyyTox15=A!e_Q=0ZGvVdb;qM3$b_BT-wz@~BhLW<;6U}@W45`!EMdu}cVhIo#|Qx?H!_lA;)_zs>i1zRu-FNF|A~E`ah# zb=WIaNBZm7LMM1c(ht#tJYh__E_b&Q6n5g2en2nvMTp^A^=(E*K51T>bOBgyXx@r> zjRA}?^zGW|UDV);eG5C-41!<`4jNpltyByI=-Vb8SbMb;%Cn*Phom>(yXxMpu1y-) z{Bq7qY@VxqA3`jw|6P&oUn9YVYZ{?dQv5|^8}j$8LzFE$x>$j>2LL>Wo6>QIaeq6U zU-Um7Bg&lZB(lVZ90*l#8 zM2%CK&cp1M`~`O46nyUWr!xy;;JF{P`LCy*7B3XwuNUCcg}zpl#7KDqV%r>=08o+h zo5xj<8IQJU{BROw?>nZ*7hY<4*kvIq&*mjN5;!PINJ-y{6zSSTNHyIN3?=stOnxN zSzbeC;}c3UNMq)iAK-vQ<8|JcBvmvcj^b321oxl}=(q&wTi+hGb{|OKd4mRPMU-(b zdp1qHIGGogACNWp^Uvoe+S0SaNF_3?rv!hV`$_k1aISr8fe%W^s(zx_Rl9p1BLsw5 zYAb?C7Yv;wAQHIU7>rWSzDk@(^SfE3;d6~-w|E7A4xX!JO5Q2bVuOom`x+nP71ZV< zaitY?U8%RF`sia_h0IwUdS|I9=r+-NG16@Bz-=^CI8%|NbeZb!{h_zs^j(6qbt35$ zhMwdn^*o(>AI@_cQr=*}@u}z8%l9oW&j4ryfg0ugLchcpR|Xs+RYj}cPE}sGfo((8 zS=MG=FPfq0GrV*eZy7%6t?xT!6XPIf4dNKa(pIXf$E~gok-y;jG5b+fBGF#uX;q6f zN5|-?0P{*XVM(_tex$ZKQsQn-Uc{Y**fGJ~4%BEk`U|$MS@hOUy!AUN#7$#Z{-yhZ zdr`Fer#A}-;H}^oHc_KJLYwxZy$Rax_fd2wRYx+Z3)MAs*bZL5!MPkEydH9q@am#4 zWZdYjb$??#GjfL`U)Y+c*SDvU+pEmAy$|J8%iqlhK0K>+K-b)I$B+aey~F5JS#cxf zO{-8FxFUI&nrl=j*);0zP(XF$Gd!`Q6yPobb(D{VU`B1iKymc z*U8ow0XJ%p4e}eW4-4wFg1%qT?Mn^IZ2uN9+<2vBTx9d4{gBVZWJT}VR&w(_w-z-{ zyFNoQk>`v=;=}Xz)htStYuX1_?*#2AW57PK+i{{>}Va-;iD$!;x$b07I zps%T3ACM<z6Y^e5Y2^rk?T|g(aqj>21O?{(`O2^S)(G=1y1?=G!c%=rhaDr z!|RwhZL*p0L-{0HKLoa+X()AtKsIIBWS_m(O}IYe(H=H!hOM=Y2l(u~@&Ke|MAzh` zb%$n+Pgi_a{gejGJ#VwITDCH45QX=+yP|~whR>T&g7Ll0GAYpIk6Pr04h?n309zG= zm=QzNs7S{A=f`EVz-b{gJzD75g0PReZDBW8!>wE++Wd_gpHim0B4BLL%Lv)+u!Ic6 zuC7&q+lF}SZkcdVAI~eQUl1b!p;LXleDA-v^nX7olD>&pPY-@^`6Drku`t-9B3OFo z>VHq?YKRxa>+|pf_odR^vKLY|AxlJe8Cgc`j72^k&zoi&X|I0^eG{%1ZUMJ&y$Lel z2cS4FBaXT1{&FE*oSmInTphFiOqYqY9Xi@bsG+f zx25e6FvTh#V(@hRXOvKw-;RrQHEV(w`}>2;)J+Kpg4D?1F~kjq{hEu>l`hqC zeb6Qi3ZplB3Wvtiu`!i{aF4Slc3Zzo91jQd2#?p}zXhF3F|z0BsPZ({=^bKy|MaEm zc4F9t6(hTn`lx}ywN0XG^7>Gwj%#y;oU&EY4yj%Y;4GjST7+}&wfv_@rw|B%ic9{g zl#=V3vX?Y@1~d5Lko>ip;dxoHpL%qcn0S-+T1xCMb|;wuUsHO-#_H(klXOhD<-cVs BH0}TZ literal 0 HcmV?d00001 diff --git a/warsmash.ini b/warsmash.ini new file mode 100644 index 000000000..a94197463 --- /dev/null +++ b/warsmash.ini @@ -0,0 +1,14 @@ +[DataSources] +Count=6 +Type00=MPQ +Path00="..\..\war3.mpq" +Type01=MPQ +Path01="..\..\War3x.mpq" +Type02=MPQ +Path02="..\..\War3xlocal.mpq" +Type03=MPQ +Path03="..\..\War3Patch.mpq" +Type04=MPQ +Path04="resources.mpq" +Type05=Folder +Path05="." \ No newline at end of file From 2a58c546cddb7dba03232a62b9fd1f57edc15a82 Mon Sep 17 00:00:00 2001 From: MfromAzeroth Date: Wed, 9 Feb 2022 23:00:57 +0100 Subject: [PATCH 6/6] Bug fixes and details for night elf build adding food cost changes wisp death upon destruction during construction wisp return upon canceling construction --- .../handlers/w3x/simulation/CUnit.java | 26 ++++++++++++++++--- .../build/CAbilityBuildInProgress.java | 1 + .../build/CAbilityNightElfBuild.java | 5 ++++ .../behaviors/build/CBehaviorHumanRepair.java | 18 ++++++++----- .../build/CBehaviorNightElfBuild.java | 20 ++++++++++++++ 5 files changed, 61 insertions(+), 9 deletions(-) diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java index 886073777..5dd147278 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/CUnit.java @@ -124,6 +124,7 @@ public class CUnit extends CWidget { private final QueueItemType[] buildQueueTypes = new QueueItemType[WarsmashConstants.BUILD_QUEUE_SIZE]; private boolean queuedUnitFoodPaid = false; private AbilityTarget rallyPoint; + private boolean constructionCanceled = false; private int foodMade; private int foodUsed; @@ -273,6 +274,11 @@ public void setConsumed(boolean consumed){ public boolean isConstructionPowerBuilding(){return constructionPowerBuild;} + public void setConstructionCanceled(boolean constructionCanceled){this.constructionCanceled= constructionCanceled;} + + public boolean isConstructionCanceled(){return constructionCanceled;} + + /** * Updates one tick of simulation logic and return true if it's time to remove * this unit from the game. @@ -289,6 +295,9 @@ public boolean update(final CSimulation game) { } } if(isConsumed()){ + //Food is subtracted when building process starts + int resetFoodWithUsageAddedBack = game.getPlayer(this.getPlayerIndex()).getFoodUsed()+this.getFoodUsed(); + game.getPlayer(this.getPlayerIndex()).setFoodUsed(resetFoodWithUsageAddedBack); return true; } if (isDead()) { @@ -345,8 +354,6 @@ else if (!this.paused) { setRallyPoint(this); } if (this.constructing) { - - final int buildTime = this.unitType.getBuildTime(); //ignore this for human build (MFROMAZ) if(this.constuctionProcessType==null||this.constuctionProcessType!=ConstructionFlag.REQURIE_REPAIR) { @@ -977,7 +984,20 @@ private void kill(final CSimulation simulation, final CUnit source) { this.pathingInstance.remove(); this.pathingInstance = null; } - popoutWorker(simulation); + if(!(this.getConstuctionProcessType()!=null&&this.getConstuctionProcessType()==ConstructionFlag.CONSUME_WORKER)){ + popoutWorker(simulation); + }else{ + if(workerInside!=null) { + if (this.isConstructionCanceled()) { + int resetFoodWithUsageAddedBack = simulation.getPlayer(this.getPlayerIndex()).getFoodUsed() + workerInside.getFoodUsed(); + popoutWorker(simulation); + simulation.getPlayer(this.getPlayerIndex()).setFoodUsed(resetFoodWithUsageAddedBack); + } else { + workerInside.setConsumed(true); + } + } + } + final CPlayer player = simulation.getPlayer(this.playerIndex); if (this.foodMade != 0) { player.setUnitFoodMade(this, 0); diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityBuildInProgress.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityBuildInProgress.java index 7c9c08590..cdb5ebc45 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityBuildInProgress.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityBuildInProgress.java @@ -37,6 +37,7 @@ public void onTick(final CSimulation game, final CUnit unit) { public boolean checkBeforeQueue(final CSimulation game, final CUnit caster, final int orderId, AbilityTarget target) { final CPlayer player = game.getPlayer(caster.getPlayerIndex()); player.refundFor(caster.getUnitType()); + caster.setConstructionCanceled(true); caster.setLife(game, 0); return false; } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityNightElfBuild.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityNightElfBuild.java index 19193b101..ce49a0566 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityNightElfBuild.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/abilities/build/CAbilityNightElfBuild.java @@ -75,4 +75,9 @@ public CBehavior beginNoTarget(final CSimulation game, final CUnit caster, final public int getBaseOrderId() { return OrderIds.nightelfbuild; } + + @Override + public void onCancelFromQueue(CSimulation game, CUnit unit, int orderId) { + super.onCancelFromQueue(game, unit, orderId); + } } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorHumanRepair.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorHumanRepair.java index 6573867e9..a4cef475a 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorHumanRepair.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorHumanRepair.java @@ -61,8 +61,8 @@ protected CBehavior update(CSimulation simulation, boolean withinFacingWindow) { unit.getUnitAnimationListener().playAnimation(false, AnimationTokens.PrimaryTag.STAND, SequenceUtils.WORK, 1.0f, true); - float healthGain = (WarsmashConstants.SIMULATION_STEP_TIME / targetUnit.getUnitType().getBuildTime()) - * (targetUnit.getMaxLife() * (1.0f - WarsmashConstants.BUILDING_CONSTRUCT_START_LIFE)) * (ability.getRepairTimeRatio()); + float healthGain = (WarsmashConstants.SIMULATION_STEP_TIME / targetUnit.getUnitType().getBuildTime())* (ability.getRepairTimeRatio() + * (targetUnit.getMaxLife() * (1.0f - WarsmashConstants.BUILDING_CONSTRUCT_START_LIFE)) ); if (targetUnit.getConstuctionProcessType() != null && targetUnit.getConstuctionProcessType().equals(ConstructionFlag.REQURIE_REPAIR) @@ -85,6 +85,7 @@ protected CBehavior update(CSimulation simulation, boolean withinFacingWindow) { targetUnit.setConstructionPowerBuild(true); } if(costs_gold > player.getGold() || costs_lumber > player.getLumber()) { + return unit.pollNextOrderBehavior(simulation); } targetUnit.setConstructionProgress(targetUnit.getConstructionProgress() +constructionProgressGain); @@ -92,18 +93,23 @@ protected CBehavior update(CSimulation simulation, boolean withinFacingWindow) { newLifeValue = Math.min(targetUnit.getLife() + healthGain, targetUnit.getMaximumLife()); if(costs_gold > player.getGold() || costs_lumber > player.getLumber()){ + return unit.pollNextOrderBehavior(simulation); } - boolean done = (newLifeValue >= targetWidget.getMaxLife()); + boolean done = (newLifeValue >= ((CUnit) targetWidget).getUnitType().getMaxLife()); if (done) { newLifeValue = targetWidget.getMaxLife(); } - player.charge(costs_gold,costs_lumber); - targetWidget.setLife(simulation, newLifeValue); - if (done && (targetUnit.getConstructionProgress()>= targetUnit.getUnitType().getBuildTime())||!targetUnit.isConstructing()) { + if(player.charge(costs_gold,costs_lumber)) { + targetWidget.setLife(simulation, newLifeValue); + }else{ + return unit.pollNextOrderBehavior(simulation); + } + if (done && ((targetUnit.getConstructionProgress()>= targetUnit.getUnitType().getBuildTime())||!targetUnit.isConstructing())) { return unit.pollNextOrderBehavior(simulation); } }else{ + return unit.pollNextOrderBehavior(simulation); } } diff --git a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorNightElfBuild.java b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorNightElfBuild.java index 7b3820980..3b09b51ef 100644 --- a/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorNightElfBuild.java +++ b/core/src/com/etheller/warsmash/viewer5/handlers/w3x/simulation/behaviors/build/CBehaviorNightElfBuild.java @@ -15,6 +15,8 @@ import java.util.EnumSet; public class CBehaviorNightElfBuild extends CBehaviorOrcBuild{ + private CUnit constructedStructure; + public CBehaviorNightElfBuild(CUnit unit) { super(unit); } @@ -55,7 +57,9 @@ protected CBehavior update(final CSimulation simulation, final boolean withinFac this.unit.setInvulnerable(true); if(constructedStructure.getUnitType().getClassifications().contains(CUnitClassification.ANCIENT)) { constructedStructure.setConstuctionProcessType(ConstructionFlag.CONSUME_WORKER); + simulation.getPlayer(playerIndex).setFoodUsed(simulation.getPlayer(playerIndex).getFoodUsed()-this.unit.getFoodUsed()); } + this.constructedStructure = constructedStructure; simulation.unitConstructedEvent(this.unit, constructedStructure); } else { @@ -66,4 +70,20 @@ protected CBehavior update(final CSimulation simulation, final boolean withinFac } return this.unit.pollNextOrderBehavior(simulation); } + + /*@Override + public void end(CSimulation game, boolean interrupted) { + if(this.constructedStructure!=null) { + this.constructedStructure.setConstructionCanceled(true); + } + super.end(game, interrupted); + } + + @Override + public void endMove(CSimulation game, boolean interrupted){ + if(this.constructedStructure!=null) { + this.constructedStructure.setConstructionCanceled(true); + } + super.end(game, interrupted); + }*/ }