From 549e85c273bb61f0fba6a9b4616d3fa0821acc20 Mon Sep 17 00:00:00 2001 From: Simon Date: Sat, 3 Dec 2022 16:39:51 +0100 Subject: [PATCH 1/5] Add interfaces to facilitate other types of game than TW --- megamek/src/megamek/client/Client.java | 7 +- .../src/megamek/client/bot/MoveOption.java | 2 +- .../megamek/client/bot/PhysicalOption.java | 26 +- .../client/bot/princess/FireControl.java | 14 +- .../client/bot/princess/FiringPlan.java | 4 +- .../bot/princess/MultiTargetFireControl.java | 2 +- .../NewtonianAerospacePathRanker.java | 2 +- .../client/bot/princess/PathRanker.java | 2 +- .../client/bot/princess/PhysicalInfo.java | 4 +- .../megamek/client/bot/princess/Princess.java | 10 +- .../client/bot/princess/WeaponFireInfo.java | 10 +- .../megamek/client/commands/FireCommand.java | 4 +- .../client/ui/swing/FiringDisplay.java | 14 +- .../src/megamek/client/ui/swing/MapMenu.java | 2 +- .../client/ui/swing/MovementDisplay.java | 6 +- .../ui/swing/OffBoardTargetOverlay.java | 2 +- .../client/ui/swing/PhysicalDisplay.java | 50 ++-- .../ui/swing/PointblankShotDisplay.java | 4 +- .../ui/swing/TargetingPhaseDisplay.java | 8 +- .../client/ui/swing/lobby/LobbyActions.java | 2 +- .../ui/swing/lobby/LobbyMekCellFormatter.java | 2 +- .../client/ui/swing/lobby/LobbyMekPopup.java | 2 +- .../ui/swing/lobby/MekTreeForceModel.java | 19 +- megamek/src/megamek/common/AbstractGame.java | 67 +++++ megamek/src/megamek/common/Aero.java | 5 + megamek/src/megamek/common/BTObject.java | 236 ++++++++++++++++++ megamek/src/megamek/common/BattleArmor.java | 5 + .../src/megamek/common/BuildingTarget.java | 7 +- megamek/src/megamek/common/Compute.java | 18 +- megamek/src/megamek/common/Entity.java | 74 ++---- .../src/megamek/common/FixedWingSupport.java | 5 + .../src/megamek/common/ForceAssignable.java | 99 ++++++++ megamek/src/megamek/common/Game.java | 70 ++---- megamek/src/megamek/common/HexTarget.java | 7 +- megamek/src/megamek/common/IGame.java | 51 +++- megamek/src/megamek/common/INarcPod.java | 7 +- megamek/src/megamek/common/InGameObject.java | 56 +++++ megamek/src/megamek/common/Jumpship.java | 5 + megamek/src/megamek/common/Mech.java | 10 + .../src/megamek/common/MinefieldTarget.java | 23 +- megamek/src/megamek/common/MoveStep.java | 6 +- megamek/src/megamek/common/Protomech.java | 5 + megamek/src/megamek/common/SmallCraft.java | 5 + megamek/src/megamek/common/Tank.java | 6 +- megamek/src/megamek/common/Targetable.java | 16 +- .../actions/AirmechRamAttackAction.java | 4 +- .../actions/BAVibroClawAttackAction.java | 2 +- .../actions/BreakGrappleAttackAction.java | 2 +- .../common/actions/BrushOffAttackAction.java | 2 +- .../common/actions/ChargeAttackAction.java | 4 +- .../common/actions/DfaAttackAction.java | 2 +- .../common/actions/GrappleAttackAction.java | 2 +- .../common/actions/PhysicalAttackAction.java | 2 +- .../ProtomechPhysicalAttackAction.java | 2 +- .../common/actions/PushAttackAction.java | 4 +- .../common/actions/RamAttackAction.java | 2 +- .../actions/TeleMissileAttackAction.java | 2 +- .../common/actions/ThrashAttackAction.java | 2 +- .../common/actions/WeaponAttackAction.java | 30 +-- .../common/alphaStrike/ASCardDisplayable.java | 47 ++-- .../common/alphaStrike/ASUnitType.java | 8 +- .../alphaStrike/AlphaStrikeElement.java | 39 ++- megamek/src/megamek/common/force/Force.java | 10 +- megamek/src/megamek/common/force/Forces.java | 143 +++++------ .../common/weapons/ACWeaponHandler.java | 3 +- ...tilleryBayWeaponIndirectHomingHandler.java | 10 +- .../ArtilleryWeaponIndirectHomingHandler.java | 10 +- .../common/weapons/BombAttackHandler.java | 2 +- .../megamek/common/weapons/CLIATMHandler.java | 2 +- .../CapitalMissileBearingsOnlyHandler.java | 6 +- .../common/weapons/ChemicalLaserHandler.java | 2 +- .../common/weapons/EnergyWeaponHandler.java | 3 +- .../common/weapons/LRMFragHandler.java | 2 +- .../common/weapons/LRMSwarmHandler.java | 8 +- .../common/weapons/MissileWeaponHandler.java | 2 +- .../megamek/common/weapons/PPCHandler.java | 3 +- .../weapons/PulseLaserWeaponHandler.java | 3 +- .../common/weapons/SRMFragHandler.java | 2 +- .../weapons/StopSwarmAttackHandler.java | 3 +- .../megamek/common/weapons/WeaponHandler.java | 4 +- .../infantry/InfantryWeaponHandler.java | 2 +- megamek/src/megamek/server/GameManager.java | 16 +- .../src/megamek/server/ServerLobbyHelper.java | 5 +- .../client/bot/princess/FireControlTest.java | 4 +- 84 files changed, 916 insertions(+), 466 deletions(-) create mode 100644 megamek/src/megamek/common/AbstractGame.java create mode 100644 megamek/src/megamek/common/BTObject.java create mode 100644 megamek/src/megamek/common/ForceAssignable.java create mode 100644 megamek/src/megamek/common/InGameObject.java diff --git a/megamek/src/megamek/client/Client.java b/megamek/src/megamek/client/Client.java index 3fd63552328..efb1945444d 100644 --- a/megamek/src/megamek/client/Client.java +++ b/megamek/src/megamek/client/Client.java @@ -1013,7 +1013,12 @@ protected void receiveForcesDelete(Packet c) { Set delForces = new HashSet<>(); Set delEntities = new HashSet<>(); forceIds.stream().map(forces::getForce).forEach(delForces::add); - delForces.stream().map(forces::getFullEntities).forEach(delEntities::addAll); + for (Force delForce : delForces) { + forces.getFullEntities(delForce).stream() + .filter(e -> e instanceof Entity) + .map(e -> (Entity) e) + .forEach(delEntities::add); + } forces.deleteForces(delForces); diff --git a/megamek/src/megamek/client/bot/MoveOption.java b/megamek/src/megamek/client/bot/MoveOption.java index 0fbad859883..513be321e8d 100644 --- a/megamek/src/megamek/client/bot/MoveOption.java +++ b/megamek/src/megamek/client/bot/MoveOption.java @@ -557,7 +557,7 @@ int getPhysicalTargetId() { if (target == null) { return -1; } - return target.getTargetId(); + return target.getId(); } @Override diff --git a/megamek/src/megamek/client/bot/PhysicalOption.java b/megamek/src/megamek/client/bot/PhysicalOption.java index e013deac29c..f27ce3ff581 100644 --- a/megamek/src/megamek/client/bot/PhysicalOption.java +++ b/megamek/src/megamek/client/bot/PhysicalOption.java @@ -82,57 +82,57 @@ public PhysicalOption(Entity attacker, Targetable target, double dmg, public AbstractAttackAction toAction() { switch (type) { case PUNCH_LEFT: - return new PunchAttackAction(attacker.getId(), target.getTargetType(), target.getTargetId(), + return new PunchAttackAction(attacker.getId(), target.getTargetType(), target.getId(), PunchAttackAction.LEFT); case PUNCH_RIGHT: - return new PunchAttackAction(attacker.getId(), target.getTargetType(), target.getTargetId(), + return new PunchAttackAction(attacker.getId(), target.getTargetType(), target.getId(), PunchAttackAction.RIGHT); case PUNCH_BOTH: - return new PunchAttackAction(attacker.getId(), target.getTargetType(), target.getTargetId(), + return new PunchAttackAction(attacker.getId(), target.getTargetType(), target.getId(), PunchAttackAction.BOTH); case KICK_LEFT: - return new KickAttackAction(attacker.getId(), target.getTargetType(), target.getTargetId(), + return new KickAttackAction(attacker.getId(), target.getTargetType(), target.getId(), KickAttackAction.LEFT); case KICK_RIGHT: - return new KickAttackAction(attacker.getId(), target.getTargetType(), target.getTargetId(), + return new KickAttackAction(attacker.getId(), target.getTargetType(), target.getId(), KickAttackAction.RIGHT); case USE_CLUB: if (club != null) { return new ClubAttackAction(attacker.getId(), target.getTargetType(), target - .getTargetId(), club, ToHitData.HIT_NORMAL, false); + .getId(), club, ToHitData.HIT_NORMAL, false); } return null; case PUSH_ATTACK: - return new PushAttackAction(attacker.getId(), target.getTargetId(), + return new PushAttackAction(attacker.getId(), target.getId(), target.getPosition()); case TRIP_ATTACK: return null; // Trip attack not implemented yet case BRUSH_LEFT: if (target == null) { return new BrushOffAttackAction(attacker.getId(), i_target - .getTargetType(), i_target.getTargetId(), + .getTargetType(), i_target.getId(), BrushOffAttackAction.LEFT); } return new BrushOffAttackAction(attacker.getId(), target - .getTargetType(), target.getTargetId(), + .getTargetType(), target.getId(), BrushOffAttackAction.LEFT); case BRUSH_RIGHT: if (target == null) { return new BrushOffAttackAction(attacker.getId(), i_target - .getTargetType(), i_target.getTargetId(), + .getTargetType(), i_target.getId(), BrushOffAttackAction.RIGHT); } return new BrushOffAttackAction(attacker.getId(), target - .getTargetType(), target.getTargetId(), + .getTargetType(), target.getId(), BrushOffAttackAction.RIGHT); case BRUSH_BOTH: if (target == null) { return new BrushOffAttackAction(attacker.getId(), i_target - .getTargetType(), i_target.getTargetId(), + .getTargetType(), i_target.getId(), BrushOffAttackAction.BOTH); } return new BrushOffAttackAction(attacker.getId(), target - .getTargetType(), target.getTargetId(), + .getTargetType(), target.getId(), BrushOffAttackAction.BOTH); /* * case THRASH_INF : return new diff --git a/megamek/src/megamek/client/bot/princess/FireControl.java b/megamek/src/megamek/client/bot/princess/FireControl.java index 7824da9f409..032d92de9f2 100644 --- a/megamek/src/megamek/client/bot/princess/FireControl.java +++ b/megamek/src/megamek/client/bot/princess/FireControl.java @@ -701,7 +701,7 @@ ToHitData guessToHitModifierForWeapon(final Entity shooter, if (targetState.isAirborneAero() && !shooterState.isAero()) { // If the aero is attacking me, there is no range. - if (target.getTargetId() == shooter.getId()) { + if (target.getId() == shooter.getId()) { distance = 0; } else { // Take into account altitude. @@ -1286,7 +1286,7 @@ protected boolean isSubCommander(final Entity entity) { } else if ((damageFraction < 0.5) || (target.getTargetType() == Targetable.TYPE_BUILDING) || (target.getTargetType() == Targetable.TYPE_HEX_CLEAR) - || (owner.getGame().getEntity(target.getTargetId()) instanceof Infantry)) { + || (owner.getGame().getEntity(target.getId()) instanceof Infantry)) { return 0; } @@ -2200,7 +2200,7 @@ public SpotAction getSpotAction(FiringPlan plan, Entity spotter, FireControlStat // otherwise, we still can't spot if (!closestTargets.isEmpty()) { Targetable target = closestTargets.get(Compute.randomInt(closestTargets.size())); - return new SpotAction(spotter.getId(), target.getTargetId()); + return new SpotAction(spotter.getId(), target.getId()); } return null; @@ -2289,16 +2289,16 @@ FiringPlan getBestFiringPlan(final Entity shooter, // Loop through each enemy and find the best plan for attacking them. for (final Targetable enemy : enemies) { - if (owner.getBehaviorSettings().getIgnoredUnitTargets().contains(enemy.getTargetId())) { + if (owner.getBehaviorSettings().getIgnoredUnitTargets().contains(enemy.getId())) { LogManager.getLogger().info(enemy.getDisplayName() + " is being explicitly ignored"); continue; } - final boolean priorityTarget = owner.getPriorityUnitTargets().contains(enemy.getTargetId()); + final boolean priorityTarget = owner.getPriorityUnitTargets().contains(enemy.getId()); // Skip retreating enemies so long as they haven't fired on me while retreating. final int playerId = (enemy instanceof Entity) ? ((Entity) enemy).getOwnerId() : -1; - if (!priorityTarget && honorUtil.isEnemyBroken(enemy.getTargetId(), playerId, + if (!priorityTarget && honorUtil.isEnemyBroken(enemy.getId(), playerId, owner.getForcedWithdrawal())) { LogManager.getLogger().info(enemy.getDisplayName() + " is broken - ignoring"); continue; @@ -3182,7 +3182,7 @@ public SearchlightAttackAction getSearchLightAction(Entity shooter, FiringPlan p } if (bestTarget != null) { - SearchlightAttackAction slaa = new SearchlightAttackAction(shooter.getId(), bestTarget.getTargetType(), bestTarget.getTargetId()); + SearchlightAttackAction slaa = new SearchlightAttackAction(shooter.getId(), bestTarget.getTargetType(), bestTarget.getId()); return slaa; } diff --git a/megamek/src/megamek/client/bot/princess/FiringPlan.java b/megamek/src/megamek/client/bot/princess/FiringPlan.java index 9edefc7d9d5..65b1a24bd06 100644 --- a/megamek/src/megamek/client/bot/princess/FiringPlan.java +++ b/megamek/src/megamek/client/bot/princess/FiringPlan.java @@ -161,9 +161,9 @@ String getDebugDescription(boolean detailed) { Set targets = new HashSet<>(); // loop through all the targets for this firing plan, only show each target once. for (WeaponFireInfo weaponFireInfo : this) { - if (!targets.contains(weaponFireInfo.getTarget().getTargetId())) { + if (!targets.contains(weaponFireInfo.getTarget().getId())) { description.append(weaponFireInfo.getTarget().getDisplayName()).append(", "); - targets.add(weaponFireInfo.getTarget().getTargetId()); + targets.add(weaponFireInfo.getTarget().getId()); } } diff --git a/megamek/src/megamek/client/bot/princess/MultiTargetFireControl.java b/megamek/src/megamek/client/bot/princess/MultiTargetFireControl.java index 021a6800697..6184b291555 100644 --- a/megamek/src/megamek/client/bot/princess/MultiTargetFireControl.java +++ b/megamek/src/megamek/client/bot/princess/MultiTargetFireControl.java @@ -115,7 +115,7 @@ WeaponFireInfo getBestShot(Mounted weapon) { for (Targetable target : getTargetableEnemyEntities(weapon.getEntity(), owner.getGame(), owner.getFireControlState())) { final int ownerID = (target instanceof Entity) ? ((Entity) target).getOwnerId() : -1; - if (owner.getHonorUtil().isEnemyBroken(target.getTargetId(), ownerID, owner.getBehaviorSettings().isForcedWithdrawal())) { + if (owner.getHonorUtil().isEnemyBroken(target.getId(), ownerID, owner.getBehaviorSettings().isForcedWithdrawal())) { LogManager.getLogger().info(target.getDisplayName() + " is broken - ignoring"); continue; } diff --git a/megamek/src/megamek/client/bot/princess/NewtonianAerospacePathRanker.java b/megamek/src/megamek/client/bot/princess/NewtonianAerospacePathRanker.java index 1f79074e0cb..f66d58b2347 100644 --- a/megamek/src/megamek/client/bot/princess/NewtonianAerospacePathRanker.java +++ b/megamek/src/megamek/client/bot/princess/NewtonianAerospacePathRanker.java @@ -39,7 +39,7 @@ public Entity findClosestEnemy(Entity me, Coords position, Game game) { List enemies = getOwner().getEnemyEntities(); for (Entity e : enemies) { // Also, skip withdrawing enemy bot units, to avoid humping disabled tanks and ejected mechwarriors - if (getOwner().getHonorUtil().isEnemyBroken(e.getTargetId(), e.getOwnerId(), getOwner().getForcedWithdrawal())) { + if (getOwner().getHonorUtil().isEnemyBroken(e.getId(), e.getOwnerId(), getOwner().getForcedWithdrawal())) { continue; } diff --git a/megamek/src/megamek/client/bot/princess/PathRanker.java b/megamek/src/megamek/client/bot/princess/PathRanker.java index 269c6d9afa2..ac4ef09c935 100644 --- a/megamek/src/megamek/client/bot/princess/PathRanker.java +++ b/megamek/src/megamek/client/bot/princess/PathRanker.java @@ -246,7 +246,7 @@ public Targetable findClosestEnemy(Entity me, Coords position, Game game, // Also, skip withdrawing enemy bot units, to avoid humping disabled tanks and ejected // MechWarriors if (e.isAirborneAeroOnGroundMap() || - getOwner().getHonorUtil().isEnemyBroken(e.getTargetId(), e.getOwnerId(), + getOwner().getHonorUtil().isEnemyBroken(e.getId(), e.getOwnerId(), getOwner().getForcedWithdrawal())) { continue; } diff --git a/megamek/src/megamek/client/bot/princess/PhysicalInfo.java b/megamek/src/megamek/client/bot/princess/PhysicalInfo.java index c0ec4a1b462..96212e49299 100644 --- a/megamek/src/megamek/client/bot/princess/PhysicalInfo.java +++ b/megamek/src/megamek/client/bot/princess/PhysicalInfo.java @@ -92,10 +92,10 @@ public double getExpectedDamage() { protected PhysicalAttackAction buildAction(PhysicalAttackType attackType, int shooterId, Targetable target) { if (attackType.isPunch()) { int armId = PhysicalAttackType.RIGHT_PUNCH == attackType ? PunchAttackAction.RIGHT : PunchAttackAction.LEFT; - return new PunchAttackAction(shooterId, target.getTargetType(), target.getTargetId(), armId, false, false, false); + return new PunchAttackAction(shooterId, target.getTargetType(), target.getId(), armId, false, false, false); } else if (attackType.isKick()) { int legId = PhysicalAttackType.RIGHT_KICK == attackType ? KickAttackAction.RIGHT : KickAttackAction.LEFT; - return new KickAttackAction(shooterId, target.getTargetType(), target.getTargetId(), legId); + return new KickAttackAction(shooterId, target.getTargetType(), target.getId(), legId); } else { // todo handle other physical attack types. return null; diff --git a/megamek/src/megamek/client/bot/princess/Princess.java b/megamek/src/megamek/client/bot/princess/Princess.java index c05a2d969b0..fab7bff93bf 100644 --- a/megamek/src/megamek/client/bot/princess/Princess.java +++ b/megamek/src/megamek/client/bot/princess/Princess.java @@ -315,7 +315,7 @@ public UnitBehavior getUnitBehaviorTracker() { } double getDamageAlreadyAssigned(final Targetable target) { - final Integer targetId = target.getTargetId(); + final Integer targetId = target.getId(); if (damageMap.containsKey(targetId)) { return damageMap.get(targetId); } @@ -607,7 +607,7 @@ protected void calculateFiringTurn() { // damageMap for the target enemy. // while we're looping through all the shots anyway, send any firing mode changes for (WeaponFireInfo shot : plan) { - Integer targetId = shot.getTarget().getTargetId(); + Integer targetId = shot.getTarget().getId(); double existingTargetDamage = damageMap.getOrDefault(targetId, 0.0); double newDamage = existingTargetDamage + shot.getExpectedDamage(); damageMap.put(targetId, newDamage); @@ -1327,7 +1327,7 @@ protected void initFiring() { final List potentialTargets = FireControl.getAllTargetableEnemyEntities(getLocalPlayer(), getGame(), getFireControlState()); for (final Targetable target : potentialTargets) { - damageMap.put(target.getTargetId(), 0d); + damageMap.put(target.getId(), 0d); } getFireControlState().clearTransientData(); @@ -1457,7 +1457,7 @@ private void checkForDishonoredEnemies() { continue; } - if (getHonorUtil().isEnemyBroken(entity.getTargetId(), entity.getOwnerId(), + if (getHonorUtil().isEnemyBroken(entity.getId(), entity.getOwnerId(), getForcedWithdrawal()) || !entity.isMilitary()) { // If he'd just continued running, I would have let him // go, but the bastard shot at me! @@ -1569,7 +1569,7 @@ protected void initMovement() { final List potentialTargets = FireControl.getAllTargetableEnemyEntities( getLocalPlayer(), getGame(), fireControlState); for (final Targetable target : potentialTargets) { - damageMap.put(target.getTargetId(), 0d); + damageMap.put(target.getId(), 0d); } } catch (Exception ignored) { diff --git a/megamek/src/megamek/client/bot/princess/WeaponFireInfo.java b/megamek/src/megamek/client/bot/princess/WeaponFireInfo.java index 2749b09ddb7..93e57bc29de 100644 --- a/megamek/src/megamek/client/bot/princess/WeaponFireInfo.java +++ b/megamek/src/megamek/client/bot/princess/WeaponFireInfo.java @@ -334,10 +334,10 @@ WeaponAttackAction buildWeaponAttackAction() { if (!(getWeapon().getType().hasFlag(WeaponType.F_ARTILLERY) || (getWeapon().getType() instanceof CapitalMissileWeapon && Compute.isGroundToGround(shooter, target)))) { - return new WeaponAttackAction(getShooter().getId(), getTarget().getTargetType(), getTarget().getTargetId(), + return new WeaponAttackAction(getShooter().getId(), getTarget().getTargetType(), getTarget().getId(), getShooter().getEquipmentNum(getWeapon())); } else { - return new ArtilleryAttackAction(getShooter().getId(), getTarget().getTargetType(), getTarget().getTargetId(), + return new ArtilleryAttackAction(getShooter().getId(), getTarget().getTargetType(), getTarget().getId(), getShooter().getEquipmentNum(getWeapon()), getGame()); } } @@ -345,7 +345,7 @@ WeaponAttackAction buildWeaponAttackAction() { private WeaponAttackAction buildBombAttackAction(final int[] bombPayload) { final WeaponAttackAction diveBomb = new WeaponAttackAction(getShooter().getId(), getTarget().getTargetType(), - getTarget().getTargetId(), + getTarget().getId(), getShooter().getEquipmentNum(getWeapon())); diveBomb.setBombPayload(bombPayload); @@ -645,11 +645,11 @@ WeaponAttackAction getWeaponAttackAction() { if (!(getWeapon().getType().hasFlag(WeaponType.F_ARTILLERY) || (getWeapon().getType() instanceof CapitalMissileWeapon && Compute.isGroundToGround(shooter, target)))) { - setAction(new WeaponAttackAction(getShooter().getId(), getTarget().getTargetId(), + setAction(new WeaponAttackAction(getShooter().getId(), getTarget().getId(), getShooter().getEquipmentNum(getWeapon()))); } else { setAction(new ArtilleryAttackAction(getShooter().getId(), getTarget().getTargetType(), - getTarget().getTargetId(), getShooter().getEquipmentNum(getWeapon()), + getTarget().getId(), getShooter().getEquipmentNum(getWeapon()), getGame())); } if (getAction() == null) { diff --git a/megamek/src/megamek/client/commands/FireCommand.java b/megamek/src/megamek/client/commands/FireCommand.java index 03c6128370a..1d9a03e9991 100644 --- a/megamek/src/megamek/client/commands/FireCommand.java +++ b/megamek/src/megamek/client/commands/FireCommand.java @@ -207,7 +207,7 @@ private void fire(int weaponNum, Targetable target) { } WeaponAttackAction waa = new WeaponAttackAction(cen, target - .getTargetType(), target.getTargetId(), weaponNum); + .getTargetType(), target.getId(), weaponNum); if (mounted.getLinked() != null && ((WeaponType) mounted.getType()).getAmmoType() != AmmoType.T_NA) { Mounted ammoMount = mounted.getLinked(); @@ -250,7 +250,7 @@ private void doSearchlight(Targetable target) { // create and queue a searchlight action SearchlightAttackAction saa = new SearchlightAttackAction(cen, target.getTargetType(), - target.getTargetId()); + target.getId()); attacks.addElement(saa); // and add it into the game, temporarily diff --git a/megamek/src/megamek/client/ui/swing/FiringDisplay.java b/megamek/src/megamek/client/ui/swing/FiringDisplay.java index 1391ff41dd9..dae43310e68 100644 --- a/megamek/src/megamek/client/ui/swing/FiringDisplay.java +++ b/megamek/src/megamek/client/ui/swing/FiringDisplay.java @@ -1327,9 +1327,9 @@ private void doActivateSpecialAbility() { switch (skillNames.get(input)) { case OptionsConstants.GUNNERY_BLOOD_STALKER: // figure out when to clear Blood Stalker (when unit destroyed or flees or fly off no return) - ActivateBloodStalkerAction bloodStalkerAction = new ActivateBloodStalkerAction(ce().getId(), target.getTargetId()); + ActivateBloodStalkerAction bloodStalkerAction = new ActivateBloodStalkerAction(ce().getId(), target.getId()); attacks.add(0, bloodStalkerAction); - ce().setBloodStalkerTarget(target.getTargetId()); + ce().setBloodStalkerTarget(target.getId()); break; } @@ -1362,7 +1362,7 @@ protected void doSearchlight() { // create and queue a searchlight action SearchlightAttackAction saa = new SearchlightAttackAction(cen, - target.getTargetType(), target.getTargetId()); + target.getTargetType(), target.getId()); attacks.addElement(saa); // and add it into the game, temporarily @@ -1553,10 +1553,10 @@ void fire() { || (mounted.getType() instanceof CapitalMissileWeapon && Compute.isGroundToGround(ce(), t)))) { waa = new WeaponAttackAction(cen, t.getTargetType(), - t.getTargetId(), weaponNum); + t.getId(), weaponNum); } else { waa = new ArtilleryAttackAction(cen, t.getTargetType(), - t.getTargetId(), weaponNum, game); + t.getId(), weaponNum, game); } // check for a bomb payload dialog @@ -1712,7 +1712,7 @@ protected void doSpot() { if (!clientgui.doYesNoDialog(title, body)) { return; } - attacks.addElement(new SpotAction(cen, target.getTargetId())); + attacks.addElement(new SpotAction(cen, target.getId())); } @@ -1813,7 +1813,7 @@ public void target(Targetable t) { if ((visibleTargets != null) && (target != null)) { // Set last target ID, so next/prev target behaves correctly for (int i = 0; i < visibleTargets.length; i++) { - if (visibleTargets[i].getId() == target.getTargetId()) { + if (visibleTargets[i].getId() == target.getId()) { lastTargetID = i; break; } diff --git a/megamek/src/megamek/client/ui/swing/MapMenu.java b/megamek/src/megamek/client/ui/swing/MapMenu.java index 208881cdcb0..104c4ad2b9e 100644 --- a/megamek/src/megamek/client/ui/swing/MapMenu.java +++ b/megamek/src/megamek/client/ui/swing/MapMenu.java @@ -701,7 +701,7 @@ private JMenuItem createAlphaStrikeJMenuItem() { int weaponNum = weapToId.get(weapon); // Used to determine if attack is valid WeaponAttackAction waa = new WeaponAttackAction(myEntity.getId(), - target.getTargetType(), target.getTargetId(), weaponNum); + target.getTargetType(), target.getId(), weaponNum); // Only fire weapons that have a chance to hit int toHitVal = waa.toHit(game).getValue(); if (toHitVal <= 12) { diff --git a/megamek/src/megamek/client/ui/swing/MovementDisplay.java b/megamek/src/megamek/client/ui/swing/MovementDisplay.java index 1e9da0b9d31..0a3af94c790 100644 --- a/megamek/src/megamek/client/ui/swing/MovementDisplay.java +++ b/megamek/src/megamek/client/ui/swing/MovementDisplay.java @@ -1727,7 +1727,7 @@ public synchronized void hexMoused(BoardViewEvent b) { cmd.addStep(MoveStepType.RAM); ToHitData toHit = new RamAttackAction(cen, - target.getTargetType(), target.getTargetId(), + target.getTargetType(), target.getId(), target.getPosition()).toHit(clientgui.getClient().getGame(), cmd); if (toHit.getValue() != TargetRoll.IMPOSSIBLE) { // Determine how much damage the charger will take. @@ -1778,11 +1778,11 @@ public synchronized void hexMoused(BoardViewEvent b) { ToHitData toHit = null; if (ce.isAirborneVTOLorWIGE()) { toHit = new AirmechRamAttackAction(cen, - target.getTargetType(), target.getTargetId(), + target.getTargetType(), target.getId(), target.getPosition()).toHit(clientgui.getClient().getGame(), cmd); } else { toHit = new ChargeAttackAction(cen, - target.getTargetType(), target.getTargetId(), + target.getTargetType(), target.getId(), target.getPosition()).toHit(clientgui.getClient().getGame(), cmd); } diff --git a/megamek/src/megamek/client/ui/swing/OffBoardTargetOverlay.java b/megamek/src/megamek/client/ui/swing/OffBoardTargetOverlay.java index 47c0bfbcb56..981d16dd1ac 100644 --- a/megamek/src/megamek/client/ui/swing/OffBoardTargetOverlay.java +++ b/megamek/src/megamek/client/ui/swing/OffBoardTargetOverlay.java @@ -304,7 +304,7 @@ private void handleButtonClick(OffBoardDirection direction) { // display dropdown containing all observed offboard enemy entities in given direction // upon selection, generate an ArtilleryAttackAction vs selected entity as per TargetingPhaseDisplay, like so: WeaponAttackAction waa = new ArtilleryAttackAction(targetingPhaseDisplay.ce().getId(), choice.getTargetType(), - choice.getTargetId(), + choice.getId(), targetingPhaseDisplay.ce().getEquipmentNum(clientgui.getBoardView().getSelectedArtilleryWeapon()), clientgui.getClient().getGame()); diff --git a/megamek/src/megamek/client/ui/swing/PhysicalDisplay.java b/megamek/src/megamek/client/ui/swing/PhysicalDisplay.java index 5673b542260..55f7d8c644e 100644 --- a/megamek/src/megamek/client/ui/swing/PhysicalDisplay.java +++ b/megamek/src/megamek/client/ui/swing/PhysicalDisplay.java @@ -465,37 +465,37 @@ void punch() { if ((leftArm.getValue() != TargetRoll.IMPOSSIBLE) && (rightArm.getValue() != TargetRoll.IMPOSSIBLE)) { attacks.addElement(new PunchAttackAction(cen, target - .getTargetType(), target.getTargetId(), + .getTargetType(), target.getId(), PunchAttackAction.BOTH, leftBladeExtend, rightBladeExtend, zweihandering)); if (isMeleeMaster && !zweihandering) { // hit 'em again! attacks.addElement(new PunchAttackAction(cen, target - .getTargetType(), target.getTargetId(), + .getTargetType(), target.getId(), PunchAttackAction.BOTH, leftBladeExtend, rightBladeExtend, zweihandering)); } } else if (leftArm.getValue() < rightArm.getValue()) { attacks.addElement(new PunchAttackAction(cen, target - .getTargetType(), target.getTargetId(), + .getTargetType(), target.getId(), PunchAttackAction.LEFT, leftBladeExtend, rightBladeExtend, zweihandering)); if (isMeleeMaster && !zweihandering) { // hit 'em again! attacks.addElement(new PunchAttackAction(cen, target - .getTargetType(), target.getTargetId(), + .getTargetType(), target.getId(), PunchAttackAction.LEFT, leftBladeExtend, rightBladeExtend, zweihandering)); } } else { attacks.addElement(new PunchAttackAction(cen, target - .getTargetType(), target.getTargetId(), + .getTargetType(), target.getId(), PunchAttackAction.RIGHT, leftBladeExtend, rightBladeExtend, zweihandering)); if (isMeleeMaster && !zweihandering) { // hit 'em again! attacks.addElement(new PunchAttackAction(cen, target - .getTargetType(), target.getTargetId(), + .getTargetType(), target.getId(), PunchAttackAction.RIGHT, leftBladeExtend, rightBladeExtend, zweihandering)); } @@ -516,7 +516,7 @@ private void doSearchlight() { // create and queue a searchlight action SearchlightAttackAction saa = new SearchlightAttackAction(cen, target.getTargetType(), - target.getTargetId()); + target.getId()); attacks.addElement(saa); // and add it into the game, temporarily @@ -597,11 +597,11 @@ void kick() { } attacks.addElement(new KickAttackAction(cen, - target.getTargetType(), target.getTargetId(), attackSide)); + target.getTargetType(), target.getId(), attackSide)); if (isMeleeMaster) { // hit 'em again! attacks.addElement(new KickAttackAction(cen, target - .getTargetType(), target.getTargetId(), attackSide)); + .getTargetType(), target.getId(), attackSide)); } ready(); } @@ -625,7 +625,7 @@ void push() { } attacks.addElement(new PushAttackAction(cen, - target.getTargetType(), target.getTargetId(), target + target.getTargetType(), target.getId(), target .getPosition())); ready(); } @@ -649,7 +649,7 @@ void trip() { } attacks.addElement(new TripAttackAction(cen, - target.getTargetType(), target.getTargetId())); + target.getTargetType(), target.getId())); ready(); } } @@ -686,7 +686,7 @@ private void grapple(boolean counter) { doSearchlight(); } - attacks.addElement(new GrappleAttackAction(cen, target.getTargetType(), target.getTargetId())); + attacks.addElement(new GrappleAttackAction(cen, target.getTargetType(), target.getId())); ready(); } } @@ -706,7 +706,7 @@ private void breakGrapple() { doSearchlight(); } - attacks.addElement(new BreakGrappleAttackAction(cen, target.getTargetType(), target.getTargetId())); + attacks.addElement(new BreakGrappleAttackAction(cen, target.getTargetType(), target.getId())); ready(); } } @@ -716,7 +716,7 @@ private void breakGrapple() { */ public void vibroclawatt() { BAVibroClawAttackAction act = new BAVibroClawAttackAction(cen, target.getTargetType(), - target.getTargetId()); + target.getId()); ToHitData toHit = act.toHit(clientgui.getClient().getGame()); String title = Messages.getString("PhysicalDisplay.BAVibroClawDialog.title", @@ -783,7 +783,7 @@ void jumpjetatt() { } attacks.addElement(new JumpJetAttackAction(cen, target - .getTargetType(), target.getTargetId(), leg)); + .getTargetType(), target.getId(), leg)); ready(); } } @@ -897,12 +897,12 @@ void club(Mounted club) { } attacks.addElement(new ClubAttackAction(cen, - target.getTargetType(), target.getTargetId(), club, ash + target.getTargetType(), target.getId(), club, ash .getAimTable(), zweihandering)); if (isMeleeMaster && !zweihandering) { // hit 'em again! attacks.addElement(new ClubAttackAction(cen, target - .getTargetType(), target.getTargetId(), club, ash + .getTargetType(), target.getId(), club, ash .getAimTable(), zweihandering)); } ready(); @@ -929,7 +929,7 @@ private void proto() { } attacks.addElement(new ProtomechPhysicalAttackAction(cen, target - .getTargetType(), target.getTargetId())); + .getTargetType(), target.getId())); ready(); } } @@ -943,7 +943,7 @@ private void explosives() { if (clientgui.doYesNoDialog(title, message)) { disableButtons(); attacks.addElement(new LayExplosivesAttackAction(cen, target.getTargetType(), - target.getTargetId())); + target.getId())); ready(); } } @@ -1035,17 +1035,17 @@ private void brush() { switch (index) { case 0: attacks.addElement(new BrushOffAttackAction(cen, target - .getTargetType(), target.getTargetId(), + .getTargetType(), target.getId(), BrushOffAttackAction.LEFT)); break; case 1: attacks.addElement(new BrushOffAttackAction(cen, target - .getTargetType(), target.getTargetId(), + .getTargetType(), target.getId(), BrushOffAttackAction.RIGHT)); break; case 2: attacks.addElement(new BrushOffAttackAction(cen, target - .getTargetType(), target.getTargetId(), + .getTargetType(), target.getId(), BrushOffAttackAction.BOTH)); break; } @@ -1061,7 +1061,7 @@ private void brush() { if (input != null) { disableButtons(); attacks.addElement(new BrushOffAttackAction(cen, target - .getTargetType(), target.getTargetId(), + .getTargetType(), target.getId(), BrushOffAttackAction.LEFT)); ready(); @@ -1076,7 +1076,7 @@ private void brush() { if (input != null) { disableButtons(); attacks.addElement(new BrushOffAttackAction(cen, target - .getTargetType(), target.getTargetId(), + .getTargetType(), target.getId(), BrushOffAttackAction.RIGHT)); ready(); @@ -1090,7 +1090,7 @@ private void brush() { * Thrash at the target, unless the player cancels the action. */ void thrash() { - ThrashAttackAction act = new ThrashAttackAction(cen, target.getTargetType(), target.getTargetId()); + ThrashAttackAction act = new ThrashAttackAction(cen, target.getTargetType(), target.getId()); ToHitData toHit = act.toHit(clientgui.getClient().getGame()); String title = Messages.getString("PhysicalDisplay.TrashDialog.title", target.getDisplayName()); diff --git a/megamek/src/megamek/client/ui/swing/PointblankShotDisplay.java b/megamek/src/megamek/client/ui/swing/PointblankShotDisplay.java index 3bc67fd80d9..833454b4e7a 100644 --- a/megamek/src/megamek/client/ui/swing/PointblankShotDisplay.java +++ b/megamek/src/megamek/client/ui/swing/PointblankShotDisplay.java @@ -686,10 +686,10 @@ && ce().isUsingSearchlight()) { || (mounted.getType() instanceof CapitalMissileWeapon && Compute.isGroundToGround(ce(), target)))) { waa = new WeaponAttackAction(cen, target.getTargetType(), - target.getTargetId(), weaponNum); + target.getId(), weaponNum); } else { waa = new ArtilleryAttackAction(cen, target.getTargetType(), - target.getTargetId(), weaponNum, game); + target.getId(), weaponNum, game); } if ((mounted.getLinked() != null) diff --git a/megamek/src/megamek/client/ui/swing/TargetingPhaseDisplay.java b/megamek/src/megamek/client/ui/swing/TargetingPhaseDisplay.java index 08a3e138ac2..5735e6b592f 100644 --- a/megamek/src/megamek/client/ui/swing/TargetingPhaseDisplay.java +++ b/megamek/src/megamek/client/ui/swing/TargetingPhaseDisplay.java @@ -729,7 +729,7 @@ private void doSearchlight() { } // create and queue a searchlight action - SearchlightAttackAction saa = new SearchlightAttackAction(cen, target.getTargetType(), target.getTargetId()); + SearchlightAttackAction saa = new SearchlightAttackAction(cen, target.getTargetType(), target.getId()); attacks.addElement(saa); // and add it into the game, temporarily @@ -761,7 +761,7 @@ private void fire() { } WeaponAttackAction waa = new WeaponAttackAction(cen, target.getTargetType(), - target.getTargetId(), weaponNum); + target.getId(), weaponNum); Game game = clientgui.getClient().getGame(); int distance = Compute.effectiveDistance(game, waa.getEntity(game), waa.getTarget(game)); if ((mounted.getType().hasFlag(WeaponType.F_ARTILLERY)) @@ -770,7 +770,7 @@ private void fire() { || (mounted.getType() instanceof CapitalMissileWeapon && Compute.isGroundToGround(ce(), target))) { waa = new ArtilleryAttackAction(cen, target.getTargetType(), - target.getTargetId(), weaponNum, clientgui.getClient().getGame()); + target.getId(), weaponNum, clientgui.getClient().getGame()); // Get the launch velocity for bearings-only telemissiles if (mounted.getType() instanceof TeleOperatedMissileBayWeapon) { TeleMissileSettingDialog tsd = new TeleMissileSettingDialog(clientgui.frame, clientgui.getClient().getGame()); @@ -969,7 +969,7 @@ public void updateTarget() { String flightTimeText = ""; if (isArtilleryAttack) { ArtilleryAttackAction aaa = new ArtilleryAttackAction(ce().getId(), target.getTargetType(), - target.getTargetId(), weaponId, clientgui.getClient().getGame()); + target.getId(), weaponId, clientgui.getClient().getGame()); flightTimeText = String.format("(%d turns)", aaa.getTurnsTilHit()); } diff --git a/megamek/src/megamek/client/ui/swing/lobby/LobbyActions.java b/megamek/src/megamek/client/ui/swing/lobby/LobbyActions.java index a7e953e061f..b342236df0a 100644 --- a/megamek/src/megamek/client/ui/swing/lobby/LobbyActions.java +++ b/megamek/src/megamek/client/ui/swing/lobby/LobbyActions.java @@ -656,7 +656,7 @@ void delete(Collection foDelete, Collection enDelete, boolean con Set finalFoDelete = new HashSet<>(foDelete); // Remove redundant entities = entities in the given forces Set inForces = new HashSet<>(); - foDelete.stream().map(forces::getFullEntities).forEach(inForces::addAll); + foDelete.stream().map(forces::getFullEntities).map(ForceAssignable::filterToEntityList).forEach(inForces::addAll); enDelete.removeIf(inForces::contains); Set finalEnDelete = new HashSet<>(enDelete); diff --git a/megamek/src/megamek/client/ui/swing/lobby/LobbyMekCellFormatter.java b/megamek/src/megamek/client/ui/swing/lobby/LobbyMekCellFormatter.java index aeb24748e1a..cf49a609ce0 100644 --- a/megamek/src/megamek/client/ui/swing/lobby/LobbyMekCellFormatter.java +++ b/megamek/src/megamek/client/ui/swing/lobby/LobbyMekCellFormatter.java @@ -722,7 +722,7 @@ private static String formatForce(Force force, ChatLounge lobby, float size) { } // BV - List fullEntities = lobby.game().getForces().getFullEntities(force); + List fullEntities = ForceAssignable.filterToEntityList(lobby.game().getForces().getFullEntities(force)); result.append(guiScaledFontHTML(color, size)); result.append(DOT_SPACER); int totalBv = fullEntities.stream().filter(e -> !e.isPartOfFighterSquadron()).mapToInt(Entity::calculateBattleValue).sum(); diff --git a/megamek/src/megamek/client/ui/swing/lobby/LobbyMekPopup.java b/megamek/src/megamek/client/ui/swing/lobby/LobbyMekPopup.java index 0a5162f996d..6d800539efd 100644 --- a/megamek/src/megamek/client/ui/swing/lobby/LobbyMekPopup.java +++ b/megamek/src/megamek/client/ui/swing/lobby/LobbyMekPopup.java @@ -113,7 +113,7 @@ static ScalingPopup getPopup(List entities, List forces, ActionLi // A set of all selected entities and all entities in selected forces and their subforces Set joinedEntities = new HashSet<>(entities); for (Force force: forces) { - joinedEntities.addAll(game.getForces().getFullEntities(force)); + joinedEntities.addAll(ForceAssignable.filterToEntityList(game.getForces().getFullEntities(force))); } // Find certain unit features among all units the player can access diff --git a/megamek/src/megamek/client/ui/swing/lobby/MekTreeForceModel.java b/megamek/src/megamek/client/ui/swing/lobby/MekTreeForceModel.java index f183e014843..1a10e5a18de 100644 --- a/megamek/src/megamek/client/ui/swing/lobby/MekTreeForceModel.java +++ b/megamek/src/megamek/client/ui/swing/lobby/MekTreeForceModel.java @@ -18,16 +18,20 @@ */ package megamek.client.ui.swing.lobby; -import java.util.ArrayList; -import javax.swing.tree.*; - import megamek.client.ui.swing.lobby.sorters.MekTreeTopLevelSorter; import megamek.common.Entity; +import megamek.common.ForceAssignable; import megamek.common.Game; import megamek.common.Player; -import megamek.common.force.*; +import megamek.common.force.Force; +import megamek.common.force.Forces; import megamek.common.options.OptionsConstants; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.DefaultTreeModel; +import java.util.ArrayList; +import java.util.List; + public class MekTreeForceModel extends DefaultTreeModel { private static final long serialVersionUID = -6458173460367645667L; @@ -66,7 +70,7 @@ public Object getChild(Object parent, int index) { Forces forces = lobby.game().getForces(); Force pnt = (Force) parent; if (index < pnt.entityCount()) { - return forces.getEntity(pnt.getEntityId(index)); + return lobby.game().getEntity(pnt.getEntityId(index)); } else if (index < pnt.getChildCount()) { return forces.getForce(pnt.getSubForceId(index - pnt.entityCount())); } @@ -104,7 +108,7 @@ private void createTopLevel() { if (realBD) { toplevel.removeIf(f -> localPlayer.isEnemyOf(forces.getOwner(f))); } - ArrayList forceless = new ArrayList<>(forces.forcelessEntities()); + List forceless = ForceAssignable.filterToEntityList(forces.forcelessEntities()); if (realBD) { forceless.removeIf(e -> localPlayer.isEnemyOf(e.getOwner())); } @@ -120,8 +124,7 @@ public boolean isLeaf(Object node) { @Override public int getIndexOfChild(Object parent, Object child) { - if (parent == null || child == null || child == root - || !(parent instanceof Force) + if (child == root || !(parent instanceof Force) || !((child instanceof Force) || (child instanceof Entity))) { return -1; } diff --git a/megamek/src/megamek/common/AbstractGame.java b/megamek/src/megamek/common/AbstractGame.java new file mode 100644 index 00000000000..ed1e8db3272 --- /dev/null +++ b/megamek/src/megamek/common/AbstractGame.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2022 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MegaMek is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MegaMek. If not, see . + */ +package megamek.common; + +import megamek.common.force.Forces; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Vector; +import java.util.concurrent.ConcurrentHashMap; + +public abstract class AbstractGame implements IGame { + + /** The players present in the game mapped to their id as key. */ + protected final ConcurrentHashMap players = new ConcurrentHashMap<>(); + + // Not yet used, should replace Entity-List + protected final ConcurrentHashMap inGameObjects = new ConcurrentHashMap<>(); + + /** + * The forces present in the game. The top level force holds all forces and force-less entities + * and should therefore not be shown. + */ + private final Forces forces = new Forces(this); + + @Override + public Player getPlayer(int id) { + return players.get(id); + } + + @Override + public Vector getPlayersVector() { + return new Vector<>(players.values()); + } + + @Override + public int getNoOfPlayers() { + return players.size(); + } + + @Override + public List getInGameObjects(Collection idList) { + return new ArrayList<>(inGameObjects.values()); + } + + @Override + public Forces getForces() { + return forces; + } +} diff --git a/megamek/src/megamek/common/Aero.java b/megamek/src/megamek/common/Aero.java index 82d063f1aa5..82ab9124474 100644 --- a/megamek/src/megamek/common/Aero.java +++ b/megamek/src/megamek/common/Aero.java @@ -3025,6 +3025,11 @@ public boolean isBomber() { return isFighter(); } + @Override + public boolean isFighter() { + return true; + } + @Override public int availableBombLocation(int cost) { return LOC_NOSE; diff --git a/megamek/src/megamek/common/BTObject.java b/megamek/src/megamek/common/BTObject.java new file mode 100644 index 00000000000..199be0731ed --- /dev/null +++ b/megamek/src/megamek/common/BTObject.java @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2022 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MegaMek is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MegaMek. If not, see . + */ +package megamek.common; + +/** + * This interface represents any physical object that can find itself on the battlefield, including units of any sort + * (Entity, AlphaStrikeElement, BF Unit, SBF Formation), but also objective markers, carryable objects, noncombatants, + * buildings. This does not include players or forces. This interface is for all objects even if they are not part + * of a game (e.g. a unit loaded in the unit selector). + */ +public interface BTObject { + + /** + * Returns true when this object is a Mek (Industrial Mek or BattleMek) or of type BM/IM for Alpha Strike. + * Returns false for any type of unit group even if it is of the right type. + * + * @return True when this is a Mek or BM/IM + */ + default boolean isMek() { + return false; + } + + /** + * Returns true when this object is an aerospace unit (fighter, aerospace support vehicle or large craft) + * or of type AS/CF/SC/DS/DA/WS/JS/SS for Alpha Strike. An aerospace unit is not {@link #isGround()}. + * Returns false for any type of unit group even if it is of the right type. + * + * @return True when this is an aerospace unit (including aerospace support vehicles) + */ + default boolean isAerospace() { + return isFighter() || isLargeAerospace(); + } + + /** + * Returns true when this object is a ProtoMek or of type PM for Alpha Strike. + * Returns false for any type of unit group even if it is of the right type. + * + * @return True when this is a ProtoMek + */ + default boolean isProtoMek() { + return false; + } + + /** + * Returns true when this object is a BattleMek or of type BM for Alpha Strike. + * Returns false for any type of unit group even if it is of the right type. + * + * @return True when this is a BattleMek (not an Industrial Mek) + */ + default boolean isBattleMek() { + return isMek() && !isIndustrialMek(); + } + + /** + * Returns true when this object is an Industrial Mek or of type IM for Alpha Strike. + * Returns false for any type of unit group even if it is of the right type. + * + * @return True when this is an Industrial Mek (not a BattleMek) + */ + default boolean isIndustrialMek() { + return false; + } + + /** + * Returns true when this object is a ground unit (all types of Mek, Infantry and Vehicle except aerospace + * support vehicles such as Fixed-Wing Support). A unit is a ground unit if it is not {@link #isAerospace()}. + * Returns false for any type of unit group even if it is of the right type. + * + * @return True when this is a ground unit + */ + default boolean isGround() { + return !isAerospace() && isSingleUnit(); + } + + /** + * Returns true when this object is a fighter (aerospace or conventional) including + * Fixed-Wing Support or of type CF/AF/SV(MV a) for Alpha Strike. + * Returns false for any type of unit group even if it is of the right type. + * + * @return True when this is a fighter including fixed-wing support + */ + default boolean isFighter() { + return false; + } + + /** + * Returns true when this object is a large aerospace unit (SmallCraft, DropShip, JumpShip, WarShip, Space + * Station). + * Returns false for any type of unit group even if it is of the right type. + * + * @return True when this is a large aerospace unit + */ + default boolean isLargeAerospace() { + return false; + } + + /** + * Returns true when this object is a BattleArmor unit or of type BA for Alpha Strike. + * Returns false for any type of unit group even if it is of the right type. + * + * @return True when this is a BattleArmor unit + */ + default boolean isBattleArmor() { + return false; + } + + /** + * Returns true when this object is a Conventional Infantry unit or of type CI for Alpha Strike. + * Returns false for any type of unit group even if it is of the right type. + * + * @return True when this is a Conventional Infantry unit + */ + default boolean isConventionalInfantry() { + return false; + } + + /** + * Returns true when this object is a Support Vehicle using aerospace movement such as a Fixed-Wing support. + * Returns false for any type of unit group even if it is of the right type. + * + * @return True when this is an aerospace Support Vehicle + */ + default boolean isAerospaceSV() { + return false; + } + + /** + * Returns true when this object is a Support Vehicle of any kind (including ground and aerospace). + * Returns false for any type of unit group even if it is of the right type. + * + * @return True when this is a Support Vehicle + */ + default boolean isSupportVehicle() { + return false; + } + + /** + * Returns true when this object is any Infantry unit or of type CI/BA for Alpha Strike. + * Returns false for any type of unit group even if it is of the right type. + * + * @return True when this is an Infantry unit (BattleArmor and Conventional) + */ + default boolean isInfantry() { + return isConventionalInfantry() || isBattleArmor(); + } + + /** + * Returns true when this object is a Combat Vehicle or ground Support Vehicle (including VTOL) or of + * type CV, ground SV for Alpha Strike. + * Returns false for any type of unit group even if it is of the right type. + * + * @return True when this is a ground vehicle (including support vehicle and VTOL) + */ + default boolean isVehicle() { + return isGround() && (isCombatVehicle() || isSupportVehicle()); + } + + /** + * Returns true when this object is a ground Combat Vehicle, including VTOL but not including Support Vehicles, + * or of type CV for Alpha Strike. + * Returns false for any type of unit group even if it is of the right type. + * + * @return True when this is a ground Combat Vehicle (not including Support Vehicle) + */ + default boolean isCombatVehicle() { + return false; + } + + /** + * For future reference. + * Returns true when this object is a battlefield object (such as a crate) that can be picked up and carried by + * some types of units. + * + * @return True when this is a carryable battlefield object. + */ + default boolean isCarryableObject() { + return false; + } + + /** + * For future reference. + * Returns true when this object is an objective marker, marking a certain hex or building or other object as + * valuable to conquer, hold or destroy. + * + * @return True when this is an objective marker. + */ + default boolean isObjectiveMarker() { + return false; + } + + /** + * Returns true when this object uses or can use aerospace movement. This includes all aerospace units as + * well as LAMs (in fighter mode when in a TW game). + * + * @return True when this may use aerospace movement (aerospace and LAM units) + */ + default boolean isAero() { + return false; + } + + /** + * Returns true when this is a group of units or elements such as a TW Squadron, BF Unit or SBF Formation + * even if it happens to contain only a single element at the time. + * + * @return True when this is a group type unit + */ + default boolean isUnitGroup() { + return false; + } + + /** + * Returns true when this is a single unit such as a TW Entity or AlphaStrikeElement, false when it is a + * group unit type, see {@link #isUnitGroup()} + * + * @return True when this is a single unit or element. + */ + default boolean isSingleUnit() { + return !isUnitGroup(); + } +} \ No newline at end of file diff --git a/megamek/src/megamek/common/BattleArmor.java b/megamek/src/megamek/common/BattleArmor.java index c90226fce70..41ae9ea6305 100644 --- a/megamek/src/megamek/common/BattleArmor.java +++ b/megamek/src/megamek/common/BattleArmor.java @@ -2206,4 +2206,9 @@ public int getSpriteDrawPriority() { protected boolean isFieldWeapon(Mounted equipment) { return false; } + + @Override + public boolean isBattleArmor() { + return true; + } } diff --git a/megamek/src/megamek/common/BuildingTarget.java b/megamek/src/megamek/common/BuildingTarget.java index b3606c9fe67..885566da231 100644 --- a/megamek/src/megamek/common/BuildingTarget.java +++ b/megamek/src/megamek/common/BuildingTarget.java @@ -152,10 +152,15 @@ public int getTargetType() { } @Override - public int getTargetId() { + public int getId() { return id; } + @Override + public int getOwnerId() { + return Player.PLAYER_NONE; + } + @Override public Coords getPosition() { return position; diff --git a/megamek/src/megamek/common/Compute.java b/megamek/src/megamek/common/Compute.java index 1e6e408ad0a..f305776781e 100644 --- a/megamek/src/megamek/common/Compute.java +++ b/megamek/src/megamek/common/Compute.java @@ -935,7 +935,7 @@ public static Entity findSpotter(Game game, Entity attacker, for (Entity other : game.getEntitiesVector()) { if (((other.isSpotting() && (other.getSpotTargetId() == target - .getTargetId())) || (taggedBy == other.getId())) + .getId())) || (taggedBy == other.getId())) && !attacker.isEnemyOf(other)) { // what are this guy's mods to the attack? LosEffects los = LosEffects.calculateLOS(game, other, target, true); @@ -989,7 +989,7 @@ public static boolean isTargetTagged(Targetable target, Game game) { targetTagged = te.getTaggedBy() != -1; } else { // Non entities will require us to look harder for (TagInfo ti : game.getTagInfo()) { - if (target.getTargetId() == ti.target.getTargetId()) { + if (target.getId() == ti.target.getId()) { return true; } } @@ -1018,7 +1018,7 @@ public static boolean isTargetTagged(Entity attacker, Targetable target, Game ga targetTagged = te.getTaggedBy() == attacker.getId(); } else { // Non entities will require us to look harder for (TagInfo ti : game.getTagInfo()) { - if ((target.getTargetId() == ti.target.getTargetId()) && + if ((target.getId() == ti.target.getId()) && (ti.attackerId == attacker.getId())) { return true; } @@ -1319,7 +1319,7 @@ public static ToHitData getRangeMods(Game game, Entity ae, int weaponId, && !((ae instanceof Dropship) && ((Dropship) ae).isSpheroid() && !ae.isAirborne() && !ae.isSpaceborne()) && !((ae instanceof Mech) && (((Mech) ae).getGrappled() == target - .getTargetId()))) { + .getId()))) { return new ToHitData(TargetRoll.AUTOMATIC_FAIL, "Only infantry weapons shoot at zero range"); } @@ -2266,7 +2266,7 @@ public static ToHitData getSecondaryTargetMod(Game game, Entity attacker, WeaponAttackAction prevAttack = (WeaponAttackAction) o; if (prevAttack.getEntityId() == attacker.getId()) { // Don't add id of current target, as it gets counted elsewhere - if (prevAttack.getTargetId() != target.getTargetId()) { + if (prevAttack.getTargetId() != target.getId()) { targIds.add(prevAttack.getTargetId()); } // first front arc target is our primary. @@ -2325,7 +2325,7 @@ public static ToHitData getSecondaryTargetMod(Game game, Entity attacker, return null; // no modifier } - if ((primaryTarget == Entity.NONE) || (primaryTarget == target.getTargetId())) { + if ((primaryTarget == Entity.NONE) || (primaryTarget == target.getId())) { // current target is primary target return null; // no modifier } @@ -2848,7 +2848,7 @@ public static ToHitData getStrafingTerrainModifier(Game game, */ public static int getTargetTotalHP(Game game, Targetable target) { int targetType = target.getTargetType(); - int targetId = target.getTargetId(); + int targetId = target.getId(); Coords position = target.getPosition(); // First, handle buildings versus entities, since they are handled differently. @@ -3772,7 +3772,7 @@ public static boolean isInArc(Game game, int attackerId, int weaponId, Targetable t) { Entity ae = game.getEntity(attackerId); if ((ae instanceof Mech) - && (((Mech) ae).getGrappled() == t.getTargetId())) { + && (((Mech) ae).getGrappled() == t.getId())) { return true; } int facing = ae.isSecondaryArcWeapon(weaponId) ? ae @@ -5530,7 +5530,7 @@ private static ToHitData getAntiMechMods(ToHitData data, Infantry attacker, } // swarm/leg attacks take target movement mods into account - data.append(getTargetMovementModifier(attacker.getGame(), defender.getTargetId())); + data.append(getTargetMovementModifier(attacker.getGame(), defender.getId())); return data; } diff --git a/megamek/src/megamek/common/Entity.java b/megamek/src/megamek/common/Entity.java index 715e34c3db9..af419af26bc 100644 --- a/megamek/src/megamek/common/Entity.java +++ b/megamek/src/megamek/common/Entity.java @@ -49,7 +49,7 @@ * Entity is a master class for basically anything on the board except terrain. */ public abstract class Entity extends TurnOrdered implements Transporter, Targetable, RoundUpdated, - PhaseUpdated, ITechnology { + PhaseUpdated, ITechnology, ForceAssignable { private static final long serialVersionUID = 1430806396279853295L; public static final int DOES_NOT_TRACK_HEAT = 999; @@ -780,21 +780,7 @@ public abstract class Entity extends TurnOrdered implements Transporter, Targeta */ private Set offBoardShotObservers; - /** - * A String representation of the force hierarchy this entity belongs to. - * The String contains all forces from top to bottom separated by backslash - * with no backslash at beginning or end. Each force is followed by a unique id - * separated by the vertical bar. E.g. - * Regiment|1\Battalion B|11\Alpha Company|18\Battle Lance II|112 - *

If this is not empty, the server will attempt to resconstruct the force - * hierarchy when it receives this entity and will empty the string. - * This should be used for loading/saving MULs or transfer from other sources that - * don't have access to the current MM game's forces, such as MekHQ or the Force - * Generators. At all other times, forceId should be used instead. - */ - private String force = ""; - - /** The force this entity belongs to. */ + private String forceString = ""; private int forceId = Force.NO_FORCE; /** @@ -907,11 +893,7 @@ public void restore() { setGameOptions(); } - /** - * Returns the ID number of this Entity. - * - * @return ID Number. - */ + @Override public int getId() { return id; } @@ -1471,6 +1453,7 @@ public void setOwner(Player player) { generateDisplayName(); } + @Override public int getOwnerId() { return ownerId; } @@ -1601,11 +1584,6 @@ public int getTargetType() { return Targetable.TYPE_ENTITY; } - @Override - public int getTargetId() { - return getId(); - } - @Override public int getHeight() { return height(); @@ -11511,23 +11489,6 @@ public boolean isReckless() { return reckless; } - /** - * Helper function to test whether an entity should be treated as an Aero unit (includes - * LAMs in fighter mode) - */ - @Override - public boolean isAero() { - return false; - } - - /** - * Helper function to determine whether an entity is an aero unit but not Small Craft/ - * DropShip/JumpShip/WarShip. - */ - public boolean isFighter() { - return isAero(); - } - public boolean isCapitalFighter() { return isCapitalFighter(false); } @@ -14652,13 +14613,6 @@ public void setMpUsedLastRound(int mpUsedLastRound) { this.mpUsedLastRound = mpUsedLastRound; } - /** - * @return the flag that determines if the Entity is a support vehicle - */ - public boolean isSupportVehicle() { - return false; - } - /** * @return Whether the unit uses primitive or retrotech construction rules */ @@ -15395,27 +15349,27 @@ public void addOffBoardObserver(int teamID) { public boolean isOffBoardObserved(int teamID) { return offBoardShotObservers.contains(teamID); } - + + @Override public String getForceString() { - return force; + return forceString; } - + + @Override public void setForceString(String f) { - force = f; + forceString = f; } - + + @Override public int getForceId() { return forceId; } - + + @Override public void setForceId(int newId) { forceId = newId; } - public boolean partOfForce() { - return forceId != Force.NO_FORCE; - } - public void setBloodStalkerTarget(int value) { bloodStalkerTarget = value; } diff --git a/megamek/src/megamek/common/FixedWingSupport.java b/megamek/src/megamek/common/FixedWingSupport.java index 535ed8e86be..6ee0ee327a6 100644 --- a/megamek/src/megamek/common/FixedWingSupport.java +++ b/megamek/src/megamek/common/FixedWingSupport.java @@ -299,4 +299,9 @@ public double getBVTypeModifier() { public long getEntityType() { return Entity.ETYPE_AERO | Entity.ETYPE_CONV_FIGHTER | Entity.ETYPE_FIXED_WING_SUPPORT; } + + @Override + public boolean isAerospaceSV() { + return true; + } } diff --git a/megamek/src/megamek/common/ForceAssignable.java b/megamek/src/megamek/common/ForceAssignable.java new file mode 100644 index 00000000000..5031293017c --- /dev/null +++ b/megamek/src/megamek/common/ForceAssignable.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2022 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MegaMek is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MegaMek. If not, see . + */ +package megamek.common; + +import megamek.common.alphaStrike.AlphaStrikeElement; +import megamek.common.force.Force; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * This interface represents all GameObjects that can be assigned to a force in MM. These are at the least + * Entity and AlphaStrikeElement but might at some point include BFUnits, SBFFormations or ACS Combat Teams. + * + * The purpose of this interface is to disentangle Force and Entity and facilitate other types of games than TW. + */ +public interface ForceAssignable extends InGameObject { + + /** + * Returns a String representation of the force hierarchy this entity belongs to. + * The String contains all forces from top to bottom separated by backslash + * with no backslash at beginning or end. Each force is followed by a unique id + * separated by the vertical bar. E.g. + *

Regiment|1\Battalion B|11\Alpha Company|18\Battle Lance II|112 + * + *

If this is not empty, the server will attempt to reconstruct the force + * hierarchy when it receives this entity and will empty the string. + * This should be used for loading/saving MULs or transfer from other sources that + * don't have access to the current MM game's forces, such as MekHQ or the Force + * Generators. At all other times, forceId should be used instead and this should return + * an empty string. + * + * @return The string representation of this ForceAssignable's force + */ + String getForceString(); + + /** + * Sets the force string, see {@link #getForceString()}. + * + * @param newForceString The new force string + */ + void setForceString(String newForceString); + + /** @return The unique id of the force this ForceAssignable belongs to. */ + int getForceId(); + + /** + * Sets the unique id of the force this ForceAssignable belongs to. + * + * @param newId the id of the new force to assign this ForceAssignable to. + */ + void setForceId(int newId); + + /** @return True when this ForceAssignable is part of any force. This tests only the assigned force id. */ + default boolean partOfForce() { + return getForceId() != Force.NO_FORCE; + } + + /** + * Filters the given list of ForceAssignables, keeping only those that are an Entity and returns + * a new list of those Entities. + * + * @param forceAssignableList The list of ForceAssignables to filter + * @return A filtered list of all Entities in the given list + */ + static List filterToEntityList(List forceAssignableList) { + return forceAssignableList.stream().filter(a -> a instanceof Entity).map(a -> (Entity) a).collect(Collectors.toList()); + } + + /** + * Filters the given list of ForceAssignables, keeping only those that are an AlphaStrikeElement and returns + * a new list of those AlphaStrikeElements. + * + * @param forceAssignableList The list of ForceAssignables to filter + * @return A filtered list of all AlphaStrikeElements in the given list + */ + static List filterToAlphaStrikeElementList(List forceAssignableList) { + return forceAssignableList.stream() + .filter(a -> a instanceof AlphaStrikeElement) + .map(a -> (AlphaStrikeElement) a) + .collect(Collectors.toList()); + } +} diff --git a/megamek/src/megamek/common/Game.java b/megamek/src/megamek/common/Game.java index 5c7e94012f0..a24fa8114ef 100644 --- a/megamek/src/megamek/common/Game.java +++ b/megamek/src/megamek/common/Game.java @@ -37,14 +37,13 @@ import java.io.Serializable; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.stream.Stream; /** * The game class is the root of all data about the game in progress. Both the * Client and the Server should have one of these objects, and it is their job to * keep it synched. */ -public class Game implements IGame, Serializable { +public class Game extends AbstractGame implements Serializable { private static final long serialVersionUID = 8376320092671792532L; /** @@ -71,11 +70,8 @@ public class Game implements IGame, Serializable { */ private Vector vOutOfGame = new Vector<>(); - private Vector players = new Vector<>(); private Vector teams = new Vector<>(); - private Hashtable playerIds = new Hashtable<>(); - private final Map> entityPosLookup = new HashMap<>(); /** @@ -450,25 +446,12 @@ public Enumeration getPlayers() { return players.elements(); } - /** - * @return the {@link #players} vector - */ - @Override - public Vector getPlayersVector() { - return players; - } - /** * @return a clone of the {@link #players} vector sorted by id */ public Vector getPlayersVectorSorted() { - Vector clone = (Vector) players.clone(); - Collections.sort(clone, new Comparator() { - @Override - public int compare(Player result1, Player result2) { - return ((Integer)result1.getId()).compareTo(result2.getId()); - } - }); + Vector clone = new Vector<>(getPlayersVector()); + clone.sort(Comparator.comparingInt(Player::getId)); return clone; } @@ -479,58 +462,36 @@ public int getNoOfPlayers() { return players.size(); } - /** - * Returns the individual player assigned the id parameter. - */ - @Override - public @Nullable Player getPlayer(final int id) { - return (Player.PLAYER_NONE == id) ? null : playerIds.get(id); - } - @Override public void addPlayer(int id, Player player) { player.setGame(this); - players.addElement(player); - playerIds.put(id, player); + players.put(id, player); setupTeams(); updatePlayer(player); } public void setPlayer(int id, Player player) { - final Player oldPlayer = getPlayer(id); player.setGame(this); - players.setElementAt(player, players.indexOf(oldPlayer)); - playerIds.put(id, player); + players.put(id, player); setupTeams(); updatePlayer(player); } - protected void updatePlayer(Player player) { - processGameEvent(new GamePlayerChangeEvent(this, player)); - } - @Override public void removePlayer(int id) { Player playerToRemove = getPlayer(id); - players.removeElement(playerToRemove); - playerIds.remove(id); + players.remove(id); setupTeams(); - processGameEvent(new GamePlayerChangeEvent(this, playerToRemove)); + updatePlayer(playerToRemove); + } + + private void updatePlayer(Player player) { + processGameEvent(new GamePlayerChangeEvent(this, player)); } - /** - * Returns the number of entities owned by the player, regardless of their - * status, as long as they are in the game. - */ @Override - public int getEntitiesOwnedBy(Player player) { - int count = 0; - for (Entity entity : entities) { - if ((entity != null) && player.equals(entity.getOwner())) { - count++; - } - } - return count; + public List getInGameObjects(Collection idList) { + return new ArrayList<>(entities); } /** @@ -3463,8 +3424,9 @@ public synchronized Forces getForces() { return forces; } - public Stream getEntitiesStream() { - return getEntitiesVector().stream(); + @Override + public List getInGameObjects() { + return new ArrayList<>(entities); } /** diff --git a/megamek/src/megamek/common/HexTarget.java b/megamek/src/megamek/common/HexTarget.java index 0e7341ec8df..68dbfc9ae5d 100644 --- a/megamek/src/megamek/common/HexTarget.java +++ b/megamek/src/megamek/common/HexTarget.java @@ -45,10 +45,15 @@ public int getTargetType() { } @Override - public int getTargetId() { + public int getId() { return HexTarget.coordsToId(m_coords); } + @Override + public int getOwnerId() { + return Player.PLAYER_NONE; + } + @Override public Coords getPosition() { return m_coords; diff --git a/megamek/src/megamek/common/IGame.java b/megamek/src/megamek/common/IGame.java index 944d4c12dc9..e75312bd456 100644 --- a/megamek/src/megamek/common/IGame.java +++ b/megamek/src/megamek/common/IGame.java @@ -1,14 +1,30 @@ -/** +/* + * Copyright (c) 2022 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MegaMek is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * + * You should have received a copy of the GNU General Public License + * along with MegaMek. If not, see . */ package megamek.common; import megamek.common.annotations.Nullable; import megamek.common.enums.GamePhase; +import megamek.common.force.Forces; import megamek.common.options.GameOptions; -import java.util.Enumeration; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; /** * Common interface for games with different rule sets, such as Total Warfare, BattleForce, or Alpha Strike. @@ -23,23 +39,24 @@ public interface IGame { * @param id a player id * @return the individual player assigned the id parameter. */ - Player getPlayer(int id); + @Nullable Player getPlayer(int id); /** * @return an enumeration of {@link Player players} in the game */ + @Deprecated Enumeration getPlayers(); /** * @return The current players as a list. */ - List getPlayersVector(); + Vector getPlayersVector(); /** * Adds the player to the game with the id * - * @param id - * @param player + * @param id The game-unique id of this player + * @param player The Player object */ void addPlayer(int id, Player player); @@ -69,7 +86,9 @@ public interface IGame { * @return the number of entities owned by the player, regardless of their * status, as long as they are in the game. */ - int getEntitiesOwnedBy(Player player); + default int getEntitiesOwnedBy(Player player) { + return (int) getInGameObjects().stream().filter(o -> o.getOwnerId() == player.getId()).count(); + } @Nullable GameTurn getTurn(); @@ -80,4 +99,20 @@ public interface IGame { * @return Whether there is an active claim for victory. */ boolean isForceVictory(); + + /** @return The Forces present in this game. Can be empty, but not null. */ + Forces getForces(); + + /** @return The InGameObject associated with the given id, if there is one. */ + default Optional getInGameObject(int id) { + return getInGameObjects().stream().filter(o -> o.getId() == id).findAny(); + } + + /** @return A list of all InGameObjects of this game. This list is copied and may be safely modified. */ + List getInGameObjects(); + + /** @return A list of all InGameObjects of this game with the given ids. This list may be safely modified. */ + default List getInGameObjects(Collection idList) { + return getInGameObjects().stream().filter(o -> idList.contains(o.getId())).collect(Collectors.toList()); + } } diff --git a/megamek/src/megamek/common/INarcPod.java b/megamek/src/megamek/common/INarcPod.java index e32110f3953..dd284b374ac 100644 --- a/megamek/src/megamek/common/INarcPod.java +++ b/megamek/src/megamek/common/INarcPod.java @@ -130,12 +130,17 @@ public int getTargetType() { } @Override - public int getTargetId() { + public int getId() { // All INarcPods of the same type from the // same team are interchangable targets. return ((team << 4) + type); } + @Override + public int getOwnerId() { + return Player.PLAYER_NONE; + } + @Override public Coords getPosition() { // Hopefully, this will **never** get called. diff --git a/megamek/src/megamek/common/InGameObject.java b/megamek/src/megamek/common/InGameObject.java new file mode 100644 index 00000000000..2a09b633284 --- /dev/null +++ b/megamek/src/megamek/common/InGameObject.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2022 - The MegaMek Team. All Rights Reserved. + * + * This file is part of MegaMek. + * + * MegaMek is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * MegaMek is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with MegaMek. If not, see . + */ +package megamek.common; + +/** + * This interface represents all objects that any type of BT Game (TW, Alpha Strike, BattleForce, SBF, ISAW) + * should possibly keep in its list of playable "entities" or game units, such as Entity and AlphaStrikeElement + * and at some point maybe BFUnits, SBFFormations or ACS Combat Teams, but also Objective Markers, carryable + * objects or buildings. Each such InGameObject must have a game-unique id and can, but does not have to have + * an owning player. + * + * The purpose of this interface is to disentangle Game, Client etc. from Entity and facilitate other + * types of games than TW. + */ +public interface InGameObject extends BTObject { + + /** + * Returns this InGameObject's id. The id must be unique to this InGameObject within the current game. + * equals() must return true for two InGameObject objects with the same id. + * + * @return The game-unique id of this InGameObject (Entity, AlphaStrikeElement etc.) + */ + int getId(); + + /** + * Returns the unique id of this InGameObject's owning player. This id may be Player.NONE. + * + * @return The player id of the owner of this InGameObject. + */ + int getOwnerId(); + + /** + * Returns true when the owner id of this InGameObject is not Player.NONE. + * + * @return True when this InGameObject has an owning player + */ + default boolean hasOwner() { + return getOwnerId() != Player.PLAYER_NONE; + } +} diff --git a/megamek/src/megamek/common/Jumpship.java b/megamek/src/megamek/common/Jumpship.java index d58f209110b..5e34252a579 100644 --- a/megamek/src/megamek/common/Jumpship.java +++ b/megamek/src/megamek/common/Jumpship.java @@ -1468,4 +1468,9 @@ public long getEntityType() { protected int calculateWalk() { return walkMP; } + + @Override + public boolean isLargeAerospace() { + return true; + } } diff --git a/megamek/src/megamek/common/Mech.java b/megamek/src/megamek/common/Mech.java index c1d69622e60..987f891c52d 100644 --- a/megamek/src/megamek/common/Mech.java +++ b/megamek/src/megamek/common/Mech.java @@ -6534,4 +6534,14 @@ public void setCoolingFlawActive(boolean flawActive) { public int getSpriteDrawPriority() { return 6; } + + @Override + public boolean isMek() { + return true; + } + + @Override + public boolean isIndustrialMek() { + return isIndustrial(); + } } diff --git a/megamek/src/megamek/common/MinefieldTarget.java b/megamek/src/megamek/common/MinefieldTarget.java index e78e287ed5e..7d6d0c5576d 100644 --- a/megamek/src/megamek/common/MinefieldTarget.java +++ b/megamek/src/megamek/common/MinefieldTarget.java @@ -19,7 +19,7 @@ public class MinefieldTarget implements Targetable { private static final long serialVersionUID = 420672189241204590L; - private Coords m_coords; + private final Coords m_coords; public MinefieldTarget(Coords c) { m_coords = c; @@ -31,10 +31,15 @@ public int getTargetType() { } @Override - public int getTargetId() { + public int getId() { return MinefieldTarget.coordsToId(m_coords); } + @Override + public int getOwnerId() { + return Player.PLAYER_NONE; + } + @Override public Coords getPosition() { return m_coords; @@ -76,8 +81,6 @@ public String getDisplayName() { * partitioning the binary representation, but this is more human readable * and still allows for a 99999x99999 hex map. */ - - // encode 2 numbers into 1 public static int coordsToId(Coords c) { return c.getY() * 100000 + c.getX(); } @@ -98,28 +101,16 @@ public int sideTable(Coords src, boolean usePrior) { return sideTable(src); } - /* - * (non-Javadoc) - * @see megamek.common.Targetable#isOffBoard() - */ @Override public boolean isOffBoard() { return false; } - /* - * (non-Javadoc) - * @see megamek.common.Targetable#isAirborne() - */ @Override public boolean isAirborne() { return false; } - /* - * (non-Javadoc) - * @see megamek.common.Targetable#isAirborneVTOLorWIGE() - */ @Override public boolean isAirborneVTOLorWIGE() { return false; diff --git a/megamek/src/megamek/common/MoveStep.java b/megamek/src/megamek/common/MoveStep.java index aacf5ef2b99..bf0b8ab6342 100644 --- a/megamek/src/megamek/common/MoveStep.java +++ b/megamek/src/megamek/common/MoveStep.java @@ -205,7 +205,7 @@ public MoveStep(MovePath path, MoveStepType type) { public MoveStep(MovePath path, MoveStepType type, Targetable target, Coords pos) { this(path, type); - targetId = target.getTargetId(); + targetId = target.getId(); targetType = target.getTargetType(); targetPos = pos; if ((type == MoveStepType.UNLOAD) || (type == MoveStepType.LAUNCH) @@ -227,7 +227,7 @@ public MoveStep(MovePath path, MoveStepType type, Targetable target, */ public MoveStep(MovePath path, MoveStepType type, Targetable target) { this(path, type); - targetId = target.getTargetId(); + targetId = target.getId(); targetType = target.getTargetType(); if ((type == MoveStepType.UNLOAD) || (type == MoveStepType.LAUNCH) || (type == MoveStepType.DROP) || (type == MoveStepType.UNDOCK) @@ -418,7 +418,7 @@ public void setTarget(Targetable target) { targetId = Entity.NONE; targetType = Targetable.TYPE_ENTITY; } else { - targetId = target.getTargetId(); + targetId = target.getId(); targetType = target.getTargetType(); } } diff --git a/megamek/src/megamek/common/Protomech.java b/megamek/src/megamek/common/Protomech.java index f8846dfeda7..29dadf81e51 100644 --- a/megamek/src/megamek/common/Protomech.java +++ b/megamek/src/megamek/common/Protomech.java @@ -1525,4 +1525,9 @@ public boolean canBrace() { public int getBraceMPCost() { return 0; } + + @Override + public boolean isProtoMek() { + return true; + } } diff --git a/megamek/src/megamek/common/SmallCraft.java b/megamek/src/megamek/common/SmallCraft.java index eea96ea8c93..f022ec4bdb5 100644 --- a/megamek/src/megamek/common/SmallCraft.java +++ b/megamek/src/megamek/common/SmallCraft.java @@ -899,4 +899,9 @@ public boolean isFighter() { protected int calculateWalk() { return walkMP; } + + @Override + public boolean isLargeAerospace() { + return true; + } } \ No newline at end of file diff --git a/megamek/src/megamek/common/Tank.java b/megamek/src/megamek/common/Tank.java index a7c6b75d800..174851a5bad 100644 --- a/megamek/src/megamek/common/Tank.java +++ b/megamek/src/megamek/common/Tank.java @@ -3035,5 +3035,9 @@ public boolean isTractor() { } return false; } - + + @Override + public boolean isCombatVehicle() { + return !isSupportVehicle(); + } } diff --git a/megamek/src/megamek/common/Targetable.java b/megamek/src/megamek/common/Targetable.java index d98169f9f39..25cd522e2db 100644 --- a/megamek/src/megamek/common/Targetable.java +++ b/megamek/src/megamek/common/Targetable.java @@ -18,7 +18,7 @@ import megamek.common.annotations.Nullable; -public interface Targetable extends Serializable { +public interface Targetable extends InGameObject, Serializable { int TYPE_ENTITY = 0; int TYPE_HEX_CLEAR = 1; int TYPE_HEX_IGNITE = 2; @@ -41,8 +41,6 @@ public interface Targetable extends Serializable { int getTargetType(); - int getTargetId(); - /** @return the coordinates of the hex containing the target */ Coords getPosition(); @@ -89,18 +87,6 @@ public interface Targetable extends Serializable { /** @return if this is off the board */ boolean isOffBoard(); - /** @return True if this is a conventional infantry unit (not BattleArmor) and can safely be cast to Infantry. */ - default boolean isConventionalInfantry() { - return false; - } - - /** - * @return if this is an Entity capable of aerospace movement - */ - default boolean isAero() { - return false; - } - /** * @return if this is an Entity capable of carrying and using bombs */ diff --git a/megamek/src/megamek/common/actions/AirmechRamAttackAction.java b/megamek/src/megamek/common/actions/AirmechRamAttackAction.java index a6dcc73312f..69b81643ad2 100644 --- a/megamek/src/megamek/common/actions/AirmechRamAttackAction.java +++ b/megamek/src/megamek/common/actions/AirmechRamAttackAction.java @@ -29,7 +29,7 @@ public class AirmechRamAttackAction extends DisplacementAttackAction { private static final long serialVersionUID = 5110608317218688433L; public AirmechRamAttackAction(Entity attacker, Targetable target) { - this(attacker.getId(), target.getTargetType(), target.getTargetId(), target.getPosition()); + this(attacker.getId(), target.getTargetType(), target.getId(), target.getPosition()); } public AirmechRamAttackAction(int entityId, int targetType, int targetId, Coords targetPos) { @@ -74,7 +74,7 @@ public ToHitData toHit(Game game, Targetable target, Coords src, Entity te = null; if (target.getTargetType() == Targetable.TYPE_ENTITY) { te = (Entity) target; - targetId = target.getTargetId(); + targetId = target.getId(); } else { return new ToHitData(TargetRoll.IMPOSSIBLE, "Invalid Target"); } diff --git a/megamek/src/megamek/common/actions/BAVibroClawAttackAction.java b/megamek/src/megamek/common/actions/BAVibroClawAttackAction.java index 40588144a14..c5bea04be1d 100644 --- a/megamek/src/megamek/common/actions/BAVibroClawAttackAction.java +++ b/megamek/src/megamek/common/actions/BAVibroClawAttackAction.java @@ -54,7 +54,7 @@ public static ToHitData toHit(Game game, int attackerId, Targetable target) { if (target.getTargetType() == Targetable.TYPE_ENTITY) { te = (Entity) target; - targetId = target.getTargetId(); + targetId = target.getId(); } if (!game.getOptions().booleanOption(OptionsConstants.BASE_FRIENDLY_FIRE)) { diff --git a/megamek/src/megamek/common/actions/BreakGrappleAttackAction.java b/megamek/src/megamek/common/actions/BreakGrappleAttackAction.java index 507bc5d05fc..da9b738af7c 100644 --- a/megamek/src/megamek/common/actions/BreakGrappleAttackAction.java +++ b/megamek/src/megamek/common/actions/BreakGrappleAttackAction.java @@ -83,7 +83,7 @@ public static ToHitData toHit(Game game, int attackerId, Targetable target) { return new ToHitData(TargetRoll.IMPOSSIBLE, "Only mechs and protomechs can be grappled"); } - if (ae.getGrappled() != target.getTargetId()) { + if (ae.getGrappled() != target.getId()) { return new ToHitData(TargetRoll.IMPOSSIBLE, "Not grappled"); } diff --git a/megamek/src/megamek/common/actions/BrushOffAttackAction.java b/megamek/src/megamek/common/actions/BrushOffAttackAction.java index defaea64ecf..5adc1ddfb9e 100644 --- a/megamek/src/megamek/common/actions/BrushOffAttackAction.java +++ b/megamek/src/megamek/common/actions/BrushOffAttackAction.java @@ -103,7 +103,7 @@ public static ToHitData toHit(Game game, int attackerId, } if (target.getTargetType() == Targetable.TYPE_ENTITY) { te = (Entity) target; - targetId = target.getTargetId(); + targetId = target.getId(); } final int armLoc = (arm == BrushOffAttackAction.RIGHT) ? Mech.LOC_RARM : Mech.LOC_LARM; diff --git a/megamek/src/megamek/common/actions/ChargeAttackAction.java b/megamek/src/megamek/common/actions/ChargeAttackAction.java index a3e0d42de6d..3969dfb01c3 100644 --- a/megamek/src/megamek/common/actions/ChargeAttackAction.java +++ b/megamek/src/megamek/common/actions/ChargeAttackAction.java @@ -31,7 +31,7 @@ public class ChargeAttackAction extends DisplacementAttackAction { private static final long serialVersionUID = -3549351664290057785L; public ChargeAttackAction(Entity attacker, Targetable target) { - this(attacker.getId(), target.getTargetType(), target.getTargetId(), + this(attacker.getId(), target.getTargetType(), target.getId(), target.getPosition()); } @@ -78,7 +78,7 @@ public ToHitData toHit(Game game, Targetable target, Coords src, Entity te; if (target.getTargetType() == Targetable.TYPE_ENTITY) { te = (Entity) target; - targetId = target.getTargetId(); + targetId = target.getId(); } else { return new ToHitData(TargetRoll.IMPOSSIBLE, "Invalid Target"); } diff --git a/megamek/src/megamek/common/actions/DfaAttackAction.java b/megamek/src/megamek/common/actions/DfaAttackAction.java index 24a3a79e85c..ada0626467d 100644 --- a/megamek/src/megamek/common/actions/DfaAttackAction.java +++ b/megamek/src/megamek/common/actions/DfaAttackAction.java @@ -193,7 +193,7 @@ public static ToHitData toHit(Game game, int attackerId, Entity te = null; if (target.getTargetType() == Targetable.TYPE_ENTITY) { te = (Entity) target; - targetId = target.getTargetId(); + targetId = target.getId(); } else { return new ToHitData(TargetRoll.IMPOSSIBLE, "Invalid Target"); } diff --git a/megamek/src/megamek/common/actions/GrappleAttackAction.java b/megamek/src/megamek/common/actions/GrappleAttackAction.java index fe85543cc86..6a60fcfafb0 100644 --- a/megamek/src/megamek/common/actions/GrappleAttackAction.java +++ b/megamek/src/megamek/common/actions/GrappleAttackAction.java @@ -304,7 +304,7 @@ public static ToHitData checkIllegal(Game game, Entity ae, Targetable target, in int atGr = ae.getGrappled(); int deGr = te.getGrappled(); if ((atGr != Entity.NONE || deGr != Entity.NONE) - && atGr != target.getTargetId() && te.isGrappleAttacker()) { + && atGr != target.getId() && te.isGrappleAttacker()) { return new ToHitData(TargetRoll.IMPOSSIBLE, "Already grappled"); } diff --git a/megamek/src/megamek/common/actions/PhysicalAttackAction.java b/megamek/src/megamek/common/actions/PhysicalAttackAction.java index bbf08a472ff..65d12deedd6 100644 --- a/megamek/src/megamek/common/actions/PhysicalAttackAction.java +++ b/megamek/src/megamek/common/actions/PhysicalAttackAction.java @@ -127,7 +127,7 @@ public PhysicalAttackAction(int entityId, int targetType, int targetId) { protected static void setCommonModifiers(ToHitData toHit, Game game, Entity ae, Targetable target) { boolean inSameBuilding = Compute.isInSameBuilding(game, ae, target); int attackerId = ae.getId(); - int targetId = target.getTargetId(); + int targetId = target.getId(); // Battle Armor targets are hard for Meks and Tanks to hit. if (target instanceof BattleArmor) { toHit.addModifier(1, "battle armor target"); diff --git a/megamek/src/megamek/common/actions/ProtomechPhysicalAttackAction.java b/megamek/src/megamek/common/actions/ProtomechPhysicalAttackAction.java index e045d187476..1cf3fcb7b61 100644 --- a/megamek/src/megamek/common/actions/ProtomechPhysicalAttackAction.java +++ b/megamek/src/megamek/common/actions/ProtomechPhysicalAttackAction.java @@ -85,7 +85,7 @@ public static ToHitData toHit(Game game, int attackerId, Targetable target) { if (target.getTargetType() == Targetable.TYPE_ENTITY) { te = (Entity) target; - targetId = target.getTargetId(); + targetId = target.getId(); } if (!game.getOptions().booleanOption(OptionsConstants.BASE_FRIENDLY_FIRE)) { diff --git a/megamek/src/megamek/common/actions/PushAttackAction.java b/megamek/src/megamek/common/actions/PushAttackAction.java index 9e14371930c..46ea98d5794 100644 --- a/megamek/src/megamek/common/actions/PushAttackAction.java +++ b/megamek/src/megamek/common/actions/PushAttackAction.java @@ -86,7 +86,7 @@ public static ToHitData toHit(Game game, int attackerId, Targetable target) { Entity te = null; if (target.getTargetType() == Targetable.TYPE_ENTITY) { te = (Entity) target; - targetId = target.getTargetId(); + targetId = target.getId(); } if (ae == null) { @@ -194,7 +194,7 @@ public static ToHitData toHit(Game game, int attackerId, Targetable target) { // can't do anything but counter-push if the target of another attack if (ae.isTargetOfDisplacementAttack() - && (ae.findTargetedDisplacement().getEntityId() != target.getTargetId())) { + && (ae.findTargetedDisplacement().getEntityId() != target.getId())) { return new ToHitData(TargetRoll.IMPOSSIBLE, "Attacker is the target of another push/charge/DFA"); } diff --git a/megamek/src/megamek/common/actions/RamAttackAction.java b/megamek/src/megamek/common/actions/RamAttackAction.java index e543dbb33b3..52e0e579077 100644 --- a/megamek/src/megamek/common/actions/RamAttackAction.java +++ b/megamek/src/megamek/common/actions/RamAttackAction.java @@ -32,7 +32,7 @@ public class RamAttackAction extends AbstractAttackAction { private static final long serialVersionUID = -3549351664290057785L; public RamAttackAction(Entity attacker, Targetable target) { - this(attacker.getId(), target.getTargetType(), target.getTargetId(), target.getPosition()); + this(attacker.getId(), target.getTargetType(), target.getId(), target.getPosition()); } public RamAttackAction(int entityId, int targetType, int targetId, Coords targetPos) { diff --git a/megamek/src/megamek/common/actions/TeleMissileAttackAction.java b/megamek/src/megamek/common/actions/TeleMissileAttackAction.java index f49678494a4..741c696d2dd 100644 --- a/megamek/src/megamek/common/actions/TeleMissileAttackAction.java +++ b/megamek/src/megamek/common/actions/TeleMissileAttackAction.java @@ -42,7 +42,7 @@ public class TeleMissileAttackAction extends AbstractAttackAction { private boolean advancedPD = false; // true if advanced StratOps game rule is on public TeleMissileAttackAction(Entity attacker, Targetable target) { - super(attacker.getId(), target.getTargetType(), target.getTargetId()); + super(attacker.getId(), target.getTargetType(), target.getId()); } public static int getDamageFor(Entity entity) { diff --git a/megamek/src/megamek/common/actions/ThrashAttackAction.java b/megamek/src/megamek/common/actions/ThrashAttackAction.java index b977aea2cbe..b4a6dfb721e 100644 --- a/megamek/src/megamek/common/actions/ThrashAttackAction.java +++ b/megamek/src/megamek/common/actions/ThrashAttackAction.java @@ -31,7 +31,7 @@ public ThrashAttackAction(int entityId, int targetType, int targetId) { } public ThrashAttackAction(int entityId, Targetable target) { - super(entityId, target.getTargetType(), target.getTargetId()); + super(entityId, target.getTargetType(), target.getId()); } /** diff --git a/megamek/src/megamek/common/actions/WeaponAttackAction.java b/megamek/src/megamek/common/actions/WeaponAttackAction.java index ad55cc1befc..b3d4d2ee6ae 100644 --- a/megamek/src/megamek/common/actions/WeaponAttackAction.java +++ b/megamek/src/megamek/common/actions/WeaponAttackAction.java @@ -507,7 +507,7 @@ private static ToHitData toHit(Game game, int attackerId, Targetable target, int || (atype.getAmmoType() == AmmoType.T_MEK_MORTAR)) && (munition == AmmoType.M_SEMIGUIDED)) { for (TagInfo ti : game.getTagInfo()) { - if (target.getTargetId() == ti.target.getTargetId()) { + if (target.getId() == ti.target.getId()) { spotter = game.getEntity(ti.attackerId); } } @@ -547,9 +547,9 @@ private static ToHitData toHit(Game game, int attackerId, Targetable target, int // Swarm should draw LoS between targets, not attacker, since // we don't want LoS to be blocked if (swarmPrimaryTarget.getTargetType() == Targetable.TYPE_ENTITY) { - los = LosEffects.calculateLos(game, swarmPrimaryTarget.getTargetId(), swarmSecondaryTarget); + los = LosEffects.calculateLos(game, swarmPrimaryTarget.getId(), swarmSecondaryTarget); } else { - los = LosEffects.calculateLos(game, swarmSecondaryTarget.getTargetId(), swarmPrimaryTarget); + los = LosEffects.calculateLos(game, swarmSecondaryTarget.getId(), swarmPrimaryTarget); } } @@ -571,9 +571,9 @@ private static ToHitData toHit(Game game, int attackerId, Targetable target, int // Swarm should draw LoS between targets, not attacker, since // we don't want LoS to be blocked if (swarmPrimaryTarget.getTargetType() == Targetable.TYPE_ENTITY) { - los = LosEffects.calculateLos(game, swarmPrimaryTarget.getTargetId(), swarmSecondaryTarget); + los = LosEffects.calculateLos(game, swarmPrimaryTarget.getId(), swarmSecondaryTarget); } else { - los = LosEffects.calculateLos(game, swarmSecondaryTarget.getTargetId(), swarmPrimaryTarget); + los = LosEffects.calculateLos(game, swarmSecondaryTarget.getId(), swarmPrimaryTarget); } } else { // For everything else, set up a plain old LOS @@ -1009,7 +1009,7 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta if (ae.getGrappled() != Entity.NONE) { int grapple = ae.getGrappled(); // It can only target the unit it is grappling with - if (grapple != target.getTargetId()) { + if (grapple != target.getId()) { return Messages.getString("WeaponAttackAction.MustTargetGrappled"); } if (weapon != null) { @@ -1683,7 +1683,7 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta } WeaponAttackAction prevAttk = (WeaponAttackAction) ea; - if ((prevAttk.getEntityId() == ae.getId()) && (prevAttk.getTargetId() != target.getTargetId()) + if ((prevAttk.getEntityId() == ae.getId()) && (prevAttk.getTargetId() != target.getId()) && !wtype.hasFlag(WeaponType.F_ALT_BOMB)) { return Messages.getString("WeaponAttackAction.CantSplitFire"); } @@ -1866,7 +1866,7 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta if (prevAttack.getEntityId() == attackerId) { Mounted prevWeapon = ae.getEquipment(prevAttack.getWeaponId()); if (prevWeapon.getType().getName().equals("Compact Narc")) { - if (prevAttack.getTargetId() != target.getTargetId()) { + if (prevAttack.getTargetId() != target.getId()) { return Messages.getString("WeaponAttackAction.OneTargetForCNarc"); } } @@ -1893,7 +1893,7 @@ private static String toHitIsImpossible(Game game, Entity ae, int attackerId, Ta } WeaponAttackAction prevAttack = (WeaponAttackAction) o; // Is this an attack from this entity to a different target? - if (prevAttack.getEntityId() == ae.getId() && prevAttack.getTargetId() != target.getTargetId()) { + if (prevAttack.getEntityId() == ae.getId() && prevAttack.getTargetId() != target.getId()) { Mounted prevWeapon = ae.getEquipment(prevAttack.getWeaponId()); WeaponType prevWtype = (WeaponType) prevWeapon.getType(); if (prevWeapon.getType().hasFlag(WeaponType.F_TASER) @@ -4178,7 +4178,7 @@ else if ((te instanceof Tank || (te instanceof QuadVee && te.getConversionMode() // target movement - ignore for pointblank shots from hidden units if ((te != null) && !isPointBlankShot) { - ToHitData thTemp = Compute.getTargetMovementModifier(game, target.getTargetId()); + ToHitData thTemp = Compute.getTargetMovementModifier(game, target.getId()); toHit.append(thTemp); toSubtract += thTemp.getValue(); @@ -4331,7 +4331,7 @@ else if ((atype != null) // blood stalker SPA if (ae.getBloodStalkerTarget() > Entity.NONE) { - if (ae.getBloodStalkerTarget() == target.getTargetId()) { + if (ae.getBloodStalkerTarget() == target.getId()) { toHit.addModifier(-1, Messages.getString("WeaponAttackAction.BloodStalkerTarget")); } else { toHit.addModifier(+2, Messages.getString("WeaponAttackAction.BloodStalkerNonTarget")); @@ -4807,7 +4807,7 @@ private static ToHitData handleSwarmSecondaryAttacks(Game game, Entity ae, Targe toHit.addModifier(-toSubtract, Messages.getString("WeaponAttackAction.OriginalTargetMods")); toHit.append(Compute.getImmobileMod(swarmSecondaryTarget, aimingAt, aimingMode)); toHit.append(Compute.getTargetTerrainModifier(game, - game.getTarget(swarmSecondaryTarget.getTargetType(), swarmSecondaryTarget.getTargetId()), eistatus, + game.getTarget(swarmSecondaryTarget.getTargetType(), swarmSecondaryTarget.getId()), eistatus, inSameBuilding, underWater)); toHit.setCover(LosEffects.COVER_NONE); @@ -4832,9 +4832,9 @@ private static ToHitData handleSwarmSecondaryAttacks(Game game, Entity ae, Targe // attacker and the secondary target, but we have received rules // clarifications on the old forums indicating that this is correct if (swarmPrimaryTarget.getTargetType() != Targetable.TYPE_ENTITY) { - swarmlos = LosEffects.calculateLos(game, swarmSecondaryTarget.getTargetId(), target); + swarmlos = LosEffects.calculateLos(game, swarmSecondaryTarget.getId(), target); } else { - swarmlos = LosEffects.calculateLos(game, swarmPrimaryTarget.getTargetId(), swarmSecondaryTarget); + swarmlos = LosEffects.calculateLos(game, swarmPrimaryTarget.getId(), swarmSecondaryTarget); } // reset cover @@ -4849,7 +4849,7 @@ private static ToHitData handleSwarmSecondaryAttacks(Game game, Entity ae, Targe } // target in water? if (swarmSecondaryTarget.getTargetType() == Targetable.TYPE_ENTITY) { - Entity oldEnt = game.getEntity(swarmSecondaryTarget.getTargetId()); + Entity oldEnt = game.getEntity(swarmSecondaryTarget.getId()); toHit.append(Compute.getTargetMovementModifier(game, oldEnt.getId())); // target in partial water - depth 1 for most units int partialWaterLevel = 1; diff --git a/megamek/src/megamek/common/alphaStrike/ASCardDisplayable.java b/megamek/src/megamek/common/alphaStrike/ASCardDisplayable.java index 16b7d5ad16c..fba6a4ee2ec 100644 --- a/megamek/src/megamek/common/alphaStrike/ASCardDisplayable.java +++ b/megamek/src/megamek/common/alphaStrike/ASCardDisplayable.java @@ -18,6 +18,7 @@ */ package megamek.common.alphaStrike; +import megamek.common.BTObject; import megamek.common.UnitRole; import java.util.Arrays; @@ -37,7 +38,7 @@ * These return an undamaged state by default and thus require overriding in AlphaStrikeElement * (e.g. {@link #getCurrentArmor()}. */ -public interface ASCardDisplayable { +public interface ASCardDisplayable extends BTObject { // TODO : Must also be able to return more "current" values for MV, Dmg, crits etc. @@ -147,84 +148,70 @@ default boolean hasMovementMode(String mode) { /** @return True if this AS element is a fighter (AF, CF). */ default boolean isFighter() { - return getASUnitType().isFighter(); + return getASUnitType().isAnyOf(AF, CF) || isAerospaceSV(); } /** @return True if this AS element is a BattleMek or Industrial Mek (BM, IM). */ + @Override default boolean isMek() { return getASUnitType().isMek(); } /** @return True if this AS element is a BattleMek (BM). */ + @Override default boolean isBattleMek() { return getASUnitType().isBattleMek(); } /** @return True if this AS element is a ProtoMek (PM). */ + @Override default boolean isProtoMek() { return getASUnitType().isProtoMek(); } /** @return True if this AS element is a large Aerospace unit, i.e. SC, DS, DA, SS, JS, WS. */ + @Override default boolean isLargeAerospace() { return getASUnitType().isLargeAerospace(); } /** @return True if this AS element is a BattleArmor unit, i.e. BA. */ + @Override default boolean isBattleArmor() { return getASUnitType().isBattleArmor(); } /** @return True if this AS element is a Conventional Infantry unit, i.e. CI. */ + @Override default boolean isConventionalInfantry() { return getASUnitType().isConventionalInfantry(); } + @Override + default boolean isAero() { + return isAerospace() || hasMovementMode("a"); + } + /** * Returns true if this AS element is an aerospace SV, i.e. an SV with a movement mode of * "a", "k", "i", and "p". * * @return True if this AS element is an aerospace SV. */ + @Override default boolean isAerospaceSV() { return isSupportVehicle() && (hasMovementMode("a") || hasMovementMode("k") || hasMovementMode("i") || hasMovementMode("p")); } /** @return True if this AS element is a support vehicle of any kind (SV). */ + @Override default boolean isSupportVehicle() { return getASUnitType().isSupportVehicle(); } - /** @return True if this AS element is Infantry (BA or CI). */ - default boolean isInfantry() { - return getASUnitType().isInfantry(); - } - - /** - * @return True if this AS element is a ground unit. An AS element is a ground unit when it is not - * an aerospace unit. See {@link #isAerospace()} - */ - default boolean isGround() { - return !isAerospace(); - } - - /** - * Returns true if this AS element is an aerospace unit, i.e. a fighter, a capital aerospace - * element or an aerospace SV. See {@link #isAerospaceSV()}. - * - * @return True if this AS element is an aerospace unit (including aero SV units). - */ - default boolean isAerospace() { - return isFighter() || isLargeAerospace() || isAerospaceSV(); - } - - /** @return True if this AS element is a combat vehicle or ground support vehicle (CV, ground SV incl. VTOL). */ - default boolean isVehicle() { - return isGround() && (isCombatVehicle() || isSupportVehicle()); - } - /** @return True if this AS element is a combat vehicle (CV, not support vehicle). */ + @Override default boolean isCombatVehicle() { return getASUnitType().isCombatVehicle(); } diff --git a/megamek/src/megamek/common/alphaStrike/ASUnitType.java b/megamek/src/megamek/common/alphaStrike/ASUnitType.java index d524e3366f4..355904744f1 100644 --- a/megamek/src/megamek/common/alphaStrike/ASUnitType.java +++ b/megamek/src/megamek/common/alphaStrike/ASUnitType.java @@ -108,10 +108,4 @@ public boolean isCombatVehicle() { public boolean isSupportVehicle() { return this == SV; } - - /** @return True if this ASUnitType is Fighter (AF, CF). */ - public boolean isFighter() { - return isAnyOf(AF, CF); - } - -} +} \ No newline at end of file diff --git a/megamek/src/megamek/common/alphaStrike/AlphaStrikeElement.java b/megamek/src/megamek/common/alphaStrike/AlphaStrikeElement.java index e49f17b2835..caa8495479b 100644 --- a/megamek/src/megamek/common/alphaStrike/AlphaStrikeElement.java +++ b/megamek/src/megamek/common/alphaStrike/AlphaStrikeElement.java @@ -20,7 +20,9 @@ import megamek.client.ui.swing.calculationReport.CalculationReport; import megamek.client.ui.swing.calculationReport.DummyCalculationReport; +import megamek.common.ForceAssignable; import megamek.common.UnitRole; +import megamek.common.force.Force; import megamek.common.options.Quirks; import java.io.Serializable; @@ -36,7 +38,7 @@ * @author Neoancient * @author Simon (Juliez) */ -public class AlphaStrikeElement implements Serializable, ASCardDisplayable, +public final class AlphaStrikeElement implements Serializable, ASCardDisplayable, ForceAssignable, ASSpecialAbilityCollector { static final int RANGEBANDS_SML = 3; @@ -63,6 +65,11 @@ public class AlphaStrikeElement implements Serializable, ASCardDisplayable, private int pointValue; private transient CalculationReport conversionReport = new DummyCalculationReport(); + private String forceString = ""; + private int forceId = Force.NO_FORCE; + private int id; + private int ownerId; + private ASUnitType asUnitType; private int size; private int tmm; @@ -484,4 +491,34 @@ public String getPrimaryMovementMode() { public Set getMovementModes() { return movement.keySet(); } + + @Override + public int getId() { + return id; + } + + @Override + public String getForceString() { + return forceString; + } + + @Override + public void setForceString(String newForceString) { + forceString = newForceString; + } + + @Override + public int getForceId() { + return forceId; + } + + @Override + public void setForceId(int newId) { + forceId = newId; + } + + @Override + public int getOwnerId() { + return ownerId; + } } \ No newline at end of file diff --git a/megamek/src/megamek/common/force/Force.java b/megamek/src/megamek/common/force/Force.java index ae8587ad962..09fc0a00818 100644 --- a/megamek/src/megamek/common/force/Force.java +++ b/megamek/src/megamek/common/force/Force.java @@ -18,7 +18,7 @@ */ package megamek.common.force; -import megamek.common.Entity; +import megamek.common.ForceAssignable; import megamek.common.Game; import megamek.common.Player; import megamek.common.annotations.Nullable; @@ -195,7 +195,7 @@ public int getSubForceId(int index) { * Returns true if the provided entity is among the force's direct members. * Does NOT check if the entity is part of any subforce. */ - public boolean containsEntity(Entity entity) { + public boolean containsEntity(ForceAssignable entity) { return containsEntity(entity.getId()); } @@ -211,7 +211,7 @@ public boolean containsEntity(int id) { * Returns the index of the provided entity in the list of direct members of this force. * Returns -1 if the entity is no direct member of this force. */ - public int entityIndex(Entity entity) { + public int entityIndex(ForceAssignable entity) { return entities.indexOf(entity.getId()); } @@ -242,11 +242,11 @@ public List getSubForces() { return Collections.unmodifiableList(subForces); } - void addEntity(Entity entity) { + void addEntity(ForceAssignable entity) { entities.add(entity.getId()); } - void removeEntity(Entity entity) { + void removeEntity(ForceAssignable entity) { entities.remove((Integer) entity.getId()); } diff --git a/megamek/src/megamek/common/force/Forces.java b/megamek/src/megamek/common/force/Forces.java index 16206a7295e..b0b524effef 100644 --- a/megamek/src/megamek/common/force/Forces.java +++ b/megamek/src/megamek/common/force/Forces.java @@ -18,9 +18,8 @@ */ package megamek.common.force; -import megamek.common.Entity; -import megamek.common.Game; -import megamek.common.Player; + +import megamek.common.*; import megamek.common.annotations.Nullable; import megamek.common.icons.Camouflage; import org.apache.logging.log4j.LogManager; @@ -28,6 +27,7 @@ import java.io.Serializable; import java.util.*; import java.util.Map.Entry; +import java.util.stream.Collectors; import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toSet; @@ -38,16 +38,16 @@ * Like in Campaign.java in MHQ this is mainly a map of id to Force along with many utility functions. * Force management and changes are directed through this object. * - * @author Simon + * @author Simon (Juliez) */ public final class Forces implements Serializable { private static final long serialVersionUID = -1382468145554363945L; - private HashMap forces = new HashMap<>(); - private transient Game game; + private final HashMap forces = new HashMap<>(); + private transient IGame game; - public Forces(Game g) { + public Forces(IGame g) { game = g; } @@ -86,8 +86,11 @@ public synchronized int addSubForce(final Force force, final Force parent) { } /** Returns a list of all the game's entities that are not part of any force. */ - public List forcelessEntities() { - return game.getEntitiesStream().filter(e -> !e.partOfForce()).collect(toList()); + public List forcelessEntities() { + return game.getInGameObjects().stream() + .filter(o -> o instanceof ForceAssignable).map(o -> (ForceAssignable) o) + .filter(e -> !e.partOfForce()) + .collect(toList()); } /** Returns the number of top-level forces present, i.e. forces with no parent force. */ @@ -104,7 +107,7 @@ public List getTopLevelForces() { * Returns true if the provided force is part of the present forces either * as a top-level or a subforce. */ - public boolean contains(Force force) { + public boolean contains(@Nullable Force force) { return (force != null) && forces.containsValue(force); } @@ -123,21 +126,13 @@ public Force getForce(int id) { return forces.get(id); } - /** - * Returns the entity with the provided id. (This is a convenience method - * for objects that access force info but don't have a reference to game or client.) - */ - public Entity getEntity(int id) { - return game.getEntity(id); - } - - /** + /** * Adds the provided Entity to the provided force. Does nothing if the force doesn't exist * or if the entity is already in the targeted force. Removes the entity from any former force. * Returns a list of all changed forces, i.e. the former force, if any, and the new force. * The list will be empty if no actual change occurred. */ - public ArrayList addEntity(Entity entity, int forceId) { + public ArrayList addEntity(ForceAssignable entity, int forceId) { ArrayList result = new ArrayList<>(); if (!forces.containsKey(forceId)) { LogManager.getLogger().error("Tried to add entity to non-existing force"); @@ -160,12 +155,12 @@ public ArrayList addEntity(Entity entity, int forceId) { /** * Removes the provided entities from their current forces, if any. Does nothing if an entity - * is already force-less (forceId == Force.NO_FORCE). Ã…Returns a list of all changed forces. + * is already force-less (forceId == Force.NO_FORCE). Returns a list of all changed forces. * The list will be empty if no actual change occurred. */ - public synchronized LinkedHashSet removeEntityFromForces(Collection entities) { + public synchronized LinkedHashSet removeEntityFromForces(Collection entities) { LinkedHashSet result = new LinkedHashSet<>(); - for (Entity entity: entities) { + for (ForceAssignable entity: entities) { result.addAll(removeEntityFromForces(entity)); } return result; @@ -178,7 +173,7 @@ public synchronized LinkedHashSet removeEntityFromForces(Collection removeEntityFromForces(Entity entity) { + public synchronized ArrayList removeEntityFromForces(ForceAssignable entity) { ArrayList result = new ArrayList<>(); int formerForce = getForceId(entity); if (formerForce == NO_FORCE) { @@ -204,13 +199,14 @@ public synchronized ArrayList removeEntityFromForces(Entity entity) { public synchronized ArrayList removeEntityFromForces(int entityId) { ArrayList result = new ArrayList<>(); int formerForce = getForceId(entityId); - if (formerForce == NO_FORCE) { + if ((formerForce == NO_FORCE) || game.getInGameObject(entityId).isEmpty() + || !(game.getInGameObject(entityId).get() instanceof ForceAssignable)) { return result; } - if (game.getEntity(entityId) != null) { - game.getEntity(entityId).setForceId(NO_FORCE); - } - + + ForceAssignable unit = (ForceAssignable) game.getInGameObject(entityId).get(); + unit.setForceId(NO_FORCE); + if (contains(formerForce)) { result.add(getForce(formerForce)); getForce(formerForce).removeEntity(entityId); @@ -267,7 +263,7 @@ public Player getOwner(int forceId) { * E.g., If it is part of a lance in a company, the lance will be returned. * If it is part of no force, returns null. */ - public @Nullable Force getForce(final Entity entity) { + public @Nullable Force getForce(final ForceAssignable entity) { return forces.get(getForceId(entity.getId())); } @@ -276,7 +272,7 @@ public Player getOwner(int forceId) { * E.g., If it is part of a lance in a company, the lance id will be returned. * If it is part of no force, returns Force.NO_FORCE. */ - public int getForceId(Entity entity) { + public int getForceId(ForceAssignable entity) { return getForceId(entity.getId()); } @@ -301,14 +297,14 @@ public int getForceId(int id) { * contain only the name and id and have no parent and no owner and * the passed entity is not added to them! */ - public static List parseForceString(Entity entity) { + public static List parseForceString(ForceAssignable entity) { final List forces = new ArrayList<>(); final String a = entity.getForceString(); final String[] b = a.split("\\|\\|"); for (final String forceText : b) { final String[] force = forceText.split("\\|"); if ((force.length != 2) && (force.length != 4)) { - LogManager.getLogger().error("Cannot parse " + forceText + " into a force! Ending parsing forces for " + entity.getShortName()); + LogManager.getLogger().error("Cannot parse " + forceText + " into a force! Ending parsing forces for " + entity); break; } @@ -318,7 +314,7 @@ public static List parseForceString(Entity entity) { final Force f = new Force(force[0], Integer.parseInt(force[1]), camouflage); forces.add(f); } catch (Exception e) { - LogManager.getLogger().error("Cannot parse " + forceText + " into a force! Ending parsing forces for " + entity.getShortName(), e); + LogManager.getLogger().error("Cannot parse " + forceText + " into a force! Ending parsing forces for " + entity, e); break; } } @@ -359,7 +355,7 @@ private boolean isAvailable(Force force, Player player) { return (owner != null) && !owner.isEnemyOf(player); } - public String forceStringFor(final Entity entity) { + public String forceStringFor(final ForceAssignable entity) { final StringBuilder result = new StringBuilder(); for (final Force ancestor : forceChain(entity)) { result.append(ancestor.getName()).append("|").append(ancestor.getId()); @@ -376,7 +372,7 @@ public String forceStringFor(final Entity entity) { * The list starts with the top-level force containing the entity and ends with * the force that the entity is an immediate member of. */ - public ArrayList forceChain(Entity entity) { + public ArrayList forceChain(ForceAssignable entity) { if (getForce(entity) != null) { return forceChain(getForce(entity)); } else { @@ -448,7 +444,7 @@ public boolean isValid() { * the validity check will test these instead of the current game's. * @see #isValid() */ - public boolean isValid(Collection updatedEntities) { + public boolean isValid(Collection updatedEntities) { Set entIds = new TreeSet<>(); Set subIds = new TreeSet<>(); for (Entry entry: forces.entrySet()) { @@ -458,11 +454,14 @@ public boolean isValid(Collection updatedEntities) { } // Create a copy of the game's entity list and overwrite with the given entities - LinkedHashMap allEntities = new LinkedHashMap<>(); - for (Entity entity: game.getEntitiesVector()) { + LinkedHashMap allEntities = new LinkedHashMap<>(); + List forceRelevantGameObjects = game.getInGameObjects().stream() + .filter(o -> o instanceof ForceAssignable).map(o -> (ForceAssignable) o) + .collect(Collectors.toList()); + for (ForceAssignable entity: forceRelevantGameObjects) { allEntities.put(entity.getId(), entity); } - for (Entity entity: updatedEntities) { + for (ForceAssignable entity: updatedEntities) { allEntities.put(entity.getId(), entity); } @@ -520,34 +519,39 @@ public boolean isValid(Collection updatedEntities) { public void correct() { Set entIds = new TreeSet<>(); Set subIds = new TreeSet<>(); + + // Create a copy of the game's entity list + HashMap allEntities = new HashMap<>(); + List forceRelevantGameObjects = game.getInGameObjects().stream() + .filter(o -> o instanceof ForceAssignable).map(o -> (ForceAssignable) o) + .collect(Collectors.toList()); + for (ForceAssignable entity: forceRelevantGameObjects) { + allEntities.put(entity.getId(), entity); + } + for (Entry entry: forces.entrySet()) { // master list id must be equal to force id entry.getValue().setId(entry.getKey()); - // Create a copy of the game's entity list - HashMap allEntities = new HashMap<>(); - for (Entity entity: game.getEntitiesVector()) { - allEntities.put(entity.getId(), entity); - } - var entityIds = new ArrayList<>(entry.getValue().getEntities()); for (int entityId: entityIds) { // Remove non-existent/dead entities if (!allEntities.containsKey(entityId)) { entry.getValue().removeEntity(entityId); + continue; } // Remove dual entity entries if (!entIds.add(entityId)) { entry.getValue().removeEntity(entityId); } else { - // Entity forceID must match force entry - game.getEntity(entityId).setForceId(entry.getKey()); + // Entity forceID must match force entry; + allEntities.get(entityId).setForceId(entry.getKey()); } // Remove entities from enemy forces Player enOwner = game.getPlayer(allEntities.get(entityId).getOwnerId()); Player foOwner = game.getPlayer(getOwnerId(entry.getValue())); if (enOwner != null && enOwner.isEnemyOf(foOwner)) { - removeEntityFromForces(game.getEntity(entityId)); + removeEntityFromForces(allEntities.get(entityId)); } } @@ -733,19 +737,13 @@ public String toString() { /** * Returns a list of all entities of the given force and all its subforces to any depth. */ - public List getFullEntities(final @Nullable Force force) { - if (force == null) { - return new ArrayList<>(); - } - - final List result = new ArrayList<>(); + public List getFullEntities(final @Nullable Force force) { + final List result = new ArrayList<>(); if (contains(force)) { - for (int entityId : force.getEntities()) { - final Entity entity = game.getEntity(entityId); - if (entity != null) { - result.add(entity); - } - } + game.getInGameObjects(force.getEntities()).stream() + .filter(o -> o instanceof ForceAssignable).map(o -> (ForceAssignable) o) + .forEach(result::add); + for (int subForceId : force.getSubForces()) { result.addAll(getFullEntities(forces.get(subForceId))); } @@ -753,25 +751,11 @@ public List getFullEntities(final @Nullable Force force) { return result; } - /** - * Returns a list of the direct subordinate entities of the given force. - * Entities in subforces of this force are ignored. - */ - public ArrayList getDirectEntities(Force force) { - ArrayList result = new ArrayList<>(); - if (contains(force)) { - for (int entityId: force.getEntities()) { - result.add(game.getEntity(entityId)); - } - } - return result; - } - - /** + /** * Moves up the given entity in the list of entities of its force if possible. * Returns true when an actual change occurred. */ - public ArrayList moveUp(Entity entity) { + public ArrayList moveUp(ForceAssignable entity) { ArrayList result = new ArrayList<>(); Force force = getForce(entity); if (force != null) { @@ -786,7 +770,7 @@ public ArrayList moveUp(Entity entity) { * Moves down the given entity in the list of entities of its force if possible. * Returns true when an actual change occurred. */ - public ArrayList moveDown(Entity entity) { + public ArrayList moveDown(ForceAssignable entity) { ArrayList result = new ArrayList<>(); Force force = getForce(entity); if (force != null) { @@ -826,5 +810,4 @@ public ArrayList moveDown(Force subForce) { } return result; } - -} +} \ No newline at end of file diff --git a/megamek/src/megamek/common/weapons/ACWeaponHandler.java b/megamek/src/megamek/common/weapons/ACWeaponHandler.java index efac52288ef..3c06d019560 100644 --- a/megamek/src/megamek/common/weapons/ACWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/ACWeaponHandler.java @@ -17,7 +17,6 @@ import megamek.common.actions.WeaponAttackAction; import megamek.common.options.OptionsConstants; import megamek.server.GameManager; -import megamek.server.Server; /** * @author Jason Tighe @@ -48,7 +47,7 @@ protected int calcDamagePerHit() { if ((ae instanceof BattleArmor) && (weapon.getLocation() == BattleArmor.LOC_SQUAD) && !(weapon.isSquadSupportWeapon()) - && (ae.getSwarmTargetId() == target.getTargetId())) { + && (ae.getSwarmTargetId() == target.getId())) { toReturn *= ((BattleArmor) ae).getShootingStrength(); } // we default to direct fire weapons for anti-infantry damage diff --git a/megamek/src/megamek/common/weapons/ArtilleryBayWeaponIndirectHomingHandler.java b/megamek/src/megamek/common/weapons/ArtilleryBayWeaponIndirectHomingHandler.java index 966dcfb597d..fb9826c2b81 100644 --- a/megamek/src/megamek/common/weapons/ArtilleryBayWeaponIndirectHomingHandler.java +++ b/megamek/src/megamek/common/weapons/ArtilleryBayWeaponIndirectHomingHandler.java @@ -389,7 +389,7 @@ public void convertHomingShotToEntityTarget() { Objects.requireNonNull(newTarget); if (v.isEmpty()) { - aaa.setTargetId(newTarget.getTargetId()); + aaa.setTargetId(newTarget.getId()); aaa.setTargetType(newTarget.getTargetType()); target = newTarget; toHit = new ToHitData(TargetRoll.IMPOSSIBLE, "tag missed the target"); @@ -406,7 +406,7 @@ public void convertHomingShotToEntityTarget() { } if (allowed.isEmpty()) { - aaa.setTargetId(newTarget.getTargetId()); + aaa.setTargetId(newTarget.getId()); aaa.setTargetType(newTarget.getTargetType()); target = newTarget; toHit = new ToHitData(TargetRoll.IMPOSSIBLE, @@ -415,20 +415,20 @@ public void convertHomingShotToEntityTarget() { //Just use target 0... newTarget = allowed.get(0).target; target = newTarget; - aaa.setTargetId(target.getTargetId()); + aaa.setTargetId(target.getId()); aaa.setTargetType(target.getTargetType()); } else { //The player gets to select the target List targetIds = new ArrayList<>(); List targetTypes = new ArrayList<>(); for (TagInfo target : allowed) { - targetIds.add(target.target.getTargetId()); + targetIds.add(target.target.getId()); targetTypes.add(target.target.getTargetType()); } int choice = gameManager.processTAGTargetCFR(ae.getOwnerId(), targetIds, targetTypes); newTarget = allowed.get(choice).target; target = newTarget; - aaa.setTargetId(target.getTargetId()); + aaa.setTargetId(target.getId()); aaa.setTargetType(target.getTargetType()); } } diff --git a/megamek/src/megamek/common/weapons/ArtilleryWeaponIndirectHomingHandler.java b/megamek/src/megamek/common/weapons/ArtilleryWeaponIndirectHomingHandler.java index 5c6b7b4a40b..23985cd96c8 100644 --- a/megamek/src/megamek/common/weapons/ArtilleryWeaponIndirectHomingHandler.java +++ b/megamek/src/megamek/common/weapons/ArtilleryWeaponIndirectHomingHandler.java @@ -357,7 +357,7 @@ public void convertHomingShotToEntityTarget() { Objects.requireNonNull(newTarget); if (v.isEmpty()) { - aaa.setTargetId(newTarget.getTargetId()); + aaa.setTargetId(newTarget.getId()); aaa.setTargetType(newTarget.getTargetType()); target = newTarget; toHit = new ToHitData(TargetRoll.IMPOSSIBLE, "tag missed the target"); @@ -375,7 +375,7 @@ public void convertHomingShotToEntityTarget() { } if (allowed.isEmpty()) { - aaa.setTargetId(newTarget.getTargetId()); + aaa.setTargetId(newTarget.getId()); aaa.setTargetType(newTarget.getTargetType()); target = newTarget; toHit = new ToHitData(TargetRoll.IMPOSSIBLE, @@ -384,20 +384,20 @@ public void convertHomingShotToEntityTarget() { //Just use target 0... newTarget = allowed.get(0).target; target = newTarget; - aaa.setTargetId(target.getTargetId()); + aaa.setTargetId(target.getId()); aaa.setTargetType(target.getTargetType()); } else { //The player gets to select the target List targetIds = new ArrayList<>(); List targetTypes = new ArrayList<>(); for (TagInfo target : allowed) { - targetIds.add(target.target.getTargetId()); + targetIds.add(target.target.getId()); targetTypes.add(target.target.getTargetType()); } int choice = gameManager.processTAGTargetCFR(ae.getOwnerId(), targetIds, targetTypes); newTarget = allowed.get(choice).target; target = newTarget; - aaa.setTargetId(target.getTargetId()); + aaa.setTargetId(target.getId()); aaa.setTargetType(target.getTargetType()); } } diff --git a/megamek/src/megamek/common/weapons/BombAttackHandler.java b/megamek/src/megamek/common/weapons/BombAttackHandler.java index 942c6502703..a28e44be45e 100644 --- a/megamek/src/megamek/common/weapons/BombAttackHandler.java +++ b/megamek/src/megamek/common/weapons/BombAttackHandler.java @@ -93,7 +93,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { boolean laserGuided = false; if (type == BombType.B_LG) { for (TagInfo ti : game.getTagInfo()) { - if (target.getTargetId() == ti.target.getTargetId()) { + if (target.getId() == ti.target.getId()) { typeModifiedToHit.addModifier(-2, "laser-guided bomb against tagged target"); laserGuided = true; diff --git a/megamek/src/megamek/common/weapons/CLIATMHandler.java b/megamek/src/megamek/common/weapons/CLIATMHandler.java index deb0f08e9be..2d01953673d 100644 --- a/megamek/src/megamek/common/weapons/CLIATMHandler.java +++ b/megamek/src/megamek/common/weapons/CLIATMHandler.java @@ -629,7 +629,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { vPhaseReport.addElement(r); weapon.setUsedThisRound(false); WeaponAttackAction newWaa = new WeaponAttackAction( - ae.getId(), entity.getTargetId(), waa.getWeaponId()); + ae.getId(), entity.getId(), waa.getWeaponId()); newWaa.setNemesisConfused(true); Mounted m = ae.getEquipment(waa.getWeaponId()); Weapon w = (Weapon) m.getType(); diff --git a/megamek/src/megamek/common/weapons/CapitalMissileBearingsOnlyHandler.java b/megamek/src/megamek/common/weapons/CapitalMissileBearingsOnlyHandler.java index 3b7a3011562..30e76dc2a5f 100644 --- a/megamek/src/megamek/common/weapons/CapitalMissileBearingsOnlyHandler.java +++ b/megamek/src/megamek/common/weapons/CapitalMissileBearingsOnlyHandler.java @@ -398,7 +398,7 @@ public void convertHexTargetToEntityTarget(Vector vPhaseReport) { targetCoords = tc; // Set the original missile target data. AMS and to-hit table calculations need this. aaa.setOldTargetCoords(tc); - aaa.setOriginalTargetId(target.getTargetId()); + aaa.setOriginalTargetId(target.getId()); aaa.setOriginalTargetType(target.getTargetType()); int missileFacing = ae.getPosition().direction(tc); Targetable newTarget = null; @@ -492,7 +492,7 @@ public void convertHexTargetToEntityTarget(Vector vPhaseReport) { int choice = gameManager.processTeleguidedMissileCFR(ae.getOwnerId(), targetIds, toHitValues); newTarget = targets.get(choice); target = newTarget; - aaa.setTargetId(target.getTargetId()); + aaa.setTargetId(target.getId()); aaa.setTargetType(target.getTargetType()); // Run this again, otherwise toHit is left set to the value for the last target in the list... setToHit(target); @@ -573,7 +573,7 @@ public void convertHexTargetToEntityTarget(Vector vPhaseReport) { } // Now, assign our chosen target to the missile target = newTarget; - aaa.setTargetId(target.getTargetId()); + aaa.setTargetId(target.getId()); aaa.setTargetType(target.getTargetType()); setToHit(target); gameManager.assignAMS(); diff --git a/megamek/src/megamek/common/weapons/ChemicalLaserHandler.java b/megamek/src/megamek/common/weapons/ChemicalLaserHandler.java index 84b3f9c7763..24af055bd65 100644 --- a/megamek/src/megamek/common/weapons/ChemicalLaserHandler.java +++ b/megamek/src/megamek/common/weapons/ChemicalLaserHandler.java @@ -58,7 +58,7 @@ protected int calcDamagePerHit() { if ((ae instanceof BattleArmor) && (weapon.getLocation() == BattleArmor.LOC_SQUAD) && !(weapon.isSquadSupportWeapon()) - && (ae.getSwarmTargetId() == target.getTargetId())) { + && (ae.getSwarmTargetId() == target.getId())) { toReturn *= ((BattleArmor) ae).getShootingStrength(); } // Check for Altered Damage from Energy Weapons (TacOp, pg.83) diff --git a/megamek/src/megamek/common/weapons/EnergyWeaponHandler.java b/megamek/src/megamek/common/weapons/EnergyWeaponHandler.java index ca18821e6b6..0cbc6d58be4 100644 --- a/megamek/src/megamek/common/weapons/EnergyWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/EnergyWeaponHandler.java @@ -30,7 +30,6 @@ import megamek.common.actions.WeaponAttackAction; import megamek.common.options.OptionsConstants; import megamek.server.GameManager; -import megamek.server.Server; public class EnergyWeaponHandler extends WeaponHandler { private static final long serialVersionUID = 2452514543790235562L; @@ -62,7 +61,7 @@ protected int calcDamagePerHit() { if ((ae instanceof BattleArmor) && (weapon.getLocation() == BattleArmor.LOC_SQUAD) && !(weapon.isSquadSupportWeapon()) - && (ae.getSwarmTargetId() == target.getTargetId())) { + && (ae.getSwarmTargetId() == target.getId())) { toReturn *= ((BattleArmor) ae).getShootingStrength(); } // Check for Altered Damage from Energy Weapons (TacOp, pg.83) diff --git a/megamek/src/megamek/common/weapons/LRMFragHandler.java b/megamek/src/megamek/common/weapons/LRMFragHandler.java index 4c5c741fa44..ea9caab3339 100644 --- a/megamek/src/megamek/common/weapons/LRMFragHandler.java +++ b/megamek/src/megamek/common/weapons/LRMFragHandler.java @@ -50,7 +50,7 @@ protected int calcDamagePerHit() { if ((ae instanceof BattleArmor) && (weapon.getLocation() == BattleArmor.LOC_SQUAD) && !(weapon.isSquadSupportWeapon()) - && (ae.getSwarmTargetId() == target.getTargetId())) { + && (ae.getSwarmTargetId() == target.getId())) { toReturn *= ((BattleArmor) ae).getShootingStrength(); } // against infantry, we have 1 hit diff --git a/megamek/src/megamek/common/weapons/LRMSwarmHandler.java b/megamek/src/megamek/common/weapons/LRMSwarmHandler.java index ea1c199dd1e..7763e34f976 100644 --- a/megamek/src/megamek/common/weapons/LRMSwarmHandler.java +++ b/megamek/src/megamek/common/weapons/LRMSwarmHandler.java @@ -272,10 +272,10 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { vPhaseReport.addElement(r); weapon.setUsedThisRound(false); WeaponAttackAction newWaa = new WeaponAttackAction(ae.getId(), - swarmTarget.getTargetId(), waa.getWeaponId()); + swarmTarget.getId(), waa.getWeaponId()); newWaa.setSwarmingMissiles(true); newWaa.setSwarmMissiles(swarmMissilesNowLeft); - newWaa.setOldTargetId(target.getTargetId()); + newWaa.setOldTargetId(target.getId()); newWaa.setOldTargetType(target.getTargetType()); newWaa.setOriginalTargetId(waa.getOriginalTargetId()); newWaa.setOriginalTargetType(waa.getOriginalTargetType()); @@ -376,10 +376,10 @@ protected boolean handleSpecialMiss(Entity entityTarget, vPhaseReport.addElement(r); weapon.setUsedThisRound(false); WeaponAttackAction newWaa = new WeaponAttackAction(ae.getId(), - swarmTarget.getTargetId(), waa.getWeaponId()); + swarmTarget.getId(), waa.getWeaponId()); newWaa.setSwarmingMissiles(true); newWaa.setSwarmMissiles(swarmMissilesNowLeft); - newWaa.setOldTargetId(target.getTargetId()); + newWaa.setOldTargetId(target.getId()); newWaa.setOldTargetType(target.getTargetType()); newWaa.setOriginalTargetId(waa.getOriginalTargetId()); newWaa.setOriginalTargetType(waa.getOriginalTargetType()); diff --git a/megamek/src/megamek/common/weapons/MissileWeaponHandler.java b/megamek/src/megamek/common/weapons/MissileWeaponHandler.java index 8e0492c4c5c..6351f7c1922 100644 --- a/megamek/src/megamek/common/weapons/MissileWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/MissileWeaponHandler.java @@ -666,7 +666,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { vPhaseReport.addElement(r); weapon.setUsedThisRound(false); WeaponAttackAction newWaa = new WeaponAttackAction(ae.getId(), - entity.getTargetId(), waa.getWeaponId()); + entity.getId(), waa.getWeaponId()); newWaa.setNemesisConfused(true); Mounted m = ae.getEquipment(waa.getWeaponId()); Weapon w = (Weapon) m.getType(); diff --git a/megamek/src/megamek/common/weapons/PPCHandler.java b/megamek/src/megamek/common/weapons/PPCHandler.java index 474aade7777..a3795293a6f 100644 --- a/megamek/src/megamek/common/weapons/PPCHandler.java +++ b/megamek/src/megamek/common/weapons/PPCHandler.java @@ -35,7 +35,6 @@ import megamek.common.actions.WeaponAttackAction; import megamek.common.options.OptionsConstants; import megamek.server.GameManager; -import megamek.server.Server; /** * @author Sebastian Brocks @@ -83,7 +82,7 @@ protected int calcDamagePerHit() { if ((ae instanceof BattleArmor) && (weapon.getLocation() == BattleArmor.LOC_SQUAD) && !(weapon.isSquadSupportWeapon()) - && (ae.getSwarmTargetId() == target.getTargetId())) { + && (ae.getSwarmTargetId() == target.getId())) { toReturn *= ((BattleArmor) ae).getShootingStrength(); } diff --git a/megamek/src/megamek/common/weapons/PulseLaserWeaponHandler.java b/megamek/src/megamek/common/weapons/PulseLaserWeaponHandler.java index a132c5d4ca4..940070dc0d1 100644 --- a/megamek/src/megamek/common/weapons/PulseLaserWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/PulseLaserWeaponHandler.java @@ -28,7 +28,6 @@ import megamek.common.actions.WeaponAttackAction; import megamek.common.options.OptionsConstants; import megamek.server.GameManager; -import megamek.server.Server; public class PulseLaserWeaponHandler extends EnergyWeaponHandler { private static final long serialVersionUID = -5701939682138221449L; @@ -50,7 +49,7 @@ protected int calcDamagePerHit() { if ((ae instanceof BattleArmor) && (weapon.getLocation() == BattleArmor.LOC_SQUAD) && !(weapon.isSquadSupportWeapon()) - && (ae.getSwarmTargetId() == target.getTargetId())) { + && (ae.getSwarmTargetId() == target.getId())) { toReturn *= ((BattleArmor) ae).getShootingStrength(); } // Check for Altered Damage from Energy Weapons (TacOp, pg.83) diff --git a/megamek/src/megamek/common/weapons/SRMFragHandler.java b/megamek/src/megamek/common/weapons/SRMFragHandler.java index d9b9ac948eb..d796d8785d3 100644 --- a/megamek/src/megamek/common/weapons/SRMFragHandler.java +++ b/megamek/src/megamek/common/weapons/SRMFragHandler.java @@ -49,7 +49,7 @@ protected int calcDamagePerHit() { if ((ae instanceof BattleArmor) && (weapon.getLocation() == BattleArmor.LOC_SQUAD) && !(weapon.isSquadSupportWeapon()) - && (ae.getSwarmTargetId() == target.getTargetId())) { + && (ae.getSwarmTargetId() == target.getId())) { toReturn *= ((BattleArmor) ae).getShootingStrength(); } // against infantry, we have 1 hit diff --git a/megamek/src/megamek/common/weapons/StopSwarmAttackHandler.java b/megamek/src/megamek/common/weapons/StopSwarmAttackHandler.java index 382d5797bfd..a5584de98b1 100644 --- a/megamek/src/megamek/common/weapons/StopSwarmAttackHandler.java +++ b/megamek/src/megamek/common/weapons/StopSwarmAttackHandler.java @@ -23,7 +23,6 @@ import megamek.common.actions.WeaponAttackAction; import megamek.common.enums.GamePhase; import megamek.server.GameManager; -import megamek.server.Server; /** * @author Andrew Hunter @@ -63,7 +62,7 @@ public boolean handle(GamePhase phase, Vector vPhaseReport) { r.subject = subjectId; vPhaseReport.addElement(r); // Only apply the "stop swarm 'attack'" to the swarmed Mek. - if (ae.getSwarmTargetId() != target.getTargetId()) { + if (ae.getSwarmTargetId() != target.getId()) { Entity other = game.getEntity(ae.getSwarmTargetId()); other.setSwarmAttackerId(Entity.NONE); } else { diff --git a/megamek/src/megamek/common/weapons/WeaponHandler.java b/megamek/src/megamek/common/weapons/WeaponHandler.java index 772cc34fd50..7e8e983bafd 100644 --- a/megamek/src/megamek/common/weapons/WeaponHandler.java +++ b/megamek/src/megamek/common/weapons/WeaponHandler.java @@ -481,7 +481,7 @@ protected int calcHits(Vector vPhaseReport) { if ((ae instanceof BattleArmor) && (weapon.getLocation() == BattleArmor.LOC_SQUAD) && !(weapon.isSquadSupportWeapon()) - && !(ae.getSwarmTargetId() == target.getTargetId())) { + && !(ae.getSwarmTargetId() == target.getId())) { bSalvo = true; int toReturn = allShotsHit() ? ((BattleArmor) ae) .getShootingStrength() : Compute @@ -1096,7 +1096,7 @@ public boolean handle(GamePhase phase, Vector returnedReports) { game.addTagInfo(info); ae.setSpotting(true); - ae.setSpotTargetId(target.getTargetId()); + ae.setSpotTargetId(target.getId()); r = new Report(3390); r.subject = subjectId; diff --git a/megamek/src/megamek/common/weapons/infantry/InfantryWeaponHandler.java b/megamek/src/megamek/common/weapons/infantry/InfantryWeaponHandler.java index 58360963e3a..00b9a4562a2 100644 --- a/megamek/src/megamek/common/weapons/infantry/InfantryWeaponHandler.java +++ b/megamek/src/megamek/common/weapons/infantry/InfantryWeaponHandler.java @@ -80,7 +80,7 @@ protected int calcHits(Vector vPhaseReport) { int troopersHit = 0; //when swarming all troopers hit - if (ae.getSwarmTargetId() == target.getTargetId()) { + if (ae.getSwarmTargetId() == target.getId()) { troopersHit = ((Infantry) ae).getShootingStrength(); } else if (!(ae instanceof Infantry)) { troopersHit = 1; diff --git a/megamek/src/megamek/server/GameManager.java b/megamek/src/megamek/server/GameManager.java index d4aa8a4fc07..ce0b6df1464 100644 --- a/megamek/src/megamek/server/GameManager.java +++ b/megamek/src/megamek/server/GameManager.java @@ -4533,7 +4533,7 @@ else if (null != crashDropShip) { addReport(r); ChargeAttackAction caa = new ChargeAttackAction(entity.getId(), crashDropShip.getTargetType(), - crashDropShip.getTargetId(), + crashDropShip.getId(), crashDropShip.getPosition()); ToHitData toHit = caa.toHit(game, true); resolveChargeDamage(entity, crashDropShip, toHit, direction); @@ -4656,7 +4656,7 @@ else if ( (curAltitude > (nextAltitude + entity.getMaxElevationChange()) || (target instanceof Aero)) { ChargeAttackAction caa = new ChargeAttackAction( entity.getId(), target.getTargetType(), - target.getTargetId(), target.getPosition()); + target.getId(), target.getPosition()); ToHitData toHit = caa.toHit(game, true); // roll @@ -6749,7 +6749,7 @@ private void processMovement(Entity entity, MovePath md, Map delEntities = new HashSet<>(); - delForces.stream().map(forces::getFullEntities).forEach(delEntities::addAll); + delForces.stream().map(forces::getFullEntities).map(ForceAssignable::filterToEntityList).forEach(delEntities::addAll); // Unload units and disconnect any C3 networks Set updateCandidates = new HashSet<>(); @@ -31978,7 +31978,7 @@ private void resolvePhysicalAttack(PhysicalResult pr, int cen) { if ((target != null) && (target instanceof Entity)) { Entity targetEntity = (Entity) target; targetEntity.setStruck(true); - targetEntity.addAttackedByThisTurn(target.getTargetId()); + targetEntity.addAttackedByThisTurn(target.getId()); creditKill(targetEntity, game.getEntity(cen)); } } diff --git a/megamek/src/megamek/server/ServerLobbyHelper.java b/megamek/src/megamek/server/ServerLobbyHelper.java index 96919a4e5a9..fb354f2f47d 100644 --- a/megamek/src/megamek/server/ServerLobbyHelper.java +++ b/megamek/src/megamek/server/ServerLobbyHelper.java @@ -20,6 +20,7 @@ import megamek.client.ui.swing.lobby.LobbyActions; import megamek.common.Entity; +import megamek.common.ForceAssignable; import megamek.common.Game; import megamek.common.Player; import megamek.common.force.Force; @@ -280,7 +281,7 @@ static void receiveForceAssignFull(Packet c, int connId, Game game, GameManager serverForces.removeIf(allSubForces::contains); for (Force force: serverForces) { - Collection entities = forces.getFullEntities(force); + Collection entities = ForceAssignable.filterToEntityList(forces.getFullEntities(force)); forces.assignFullForces(force, newOwner); for (Entity entity: entities) { entity.setOwner(newOwner); @@ -469,7 +470,7 @@ static Packet createForceUpdatePacket(Collection changedForces, Collectio * A force is editable to the sender of a command if any forces in its force chain * (this includes the force itself) is owned by the sender. This allows editing * forces of other players if they are a subforce of one's own force. - * @see LobbyActions#isEditable(Force) + * See also LobbyActions.isEditable(Force) */ static boolean isEditable(Force force, Game game, Player sender) { List chain = game.getForces().forceChain(force); diff --git a/megamek/unittests/megamek/client/bot/princess/FireControlTest.java b/megamek/unittests/megamek/client/bot/princess/FireControlTest.java index c2083ddc029..a7422e0b83a 100644 --- a/megamek/unittests/megamek/client/bot/princess/FireControlTest.java +++ b/megamek/unittests/megamek/client/bot/princess/FireControlTest.java @@ -1668,7 +1668,7 @@ public void testGuessToHitModifierForWeapon() { // Test fighter's at altitude final ConvFighter mockFighter = mock(ConvFighter.class); when(mockFighter.getAltitude()).thenReturn(3); - when(mockFighter.getTargetId()).thenReturn(2); + when(mockFighter.getId()).thenReturn(2); final EntityState mockFighterState = mock(EntityState.class); when(mockFighterState.isAirborneAero()).thenReturn(true); when(mockFighterState.isBuilding()).thenReturn(false); @@ -1678,7 +1678,7 @@ public void testGuessToHitModifierForWeapon() { expected.addModifier(FireControl.TH_LONG_RANGE); assertToHitDataEquals(expected, testFireControl.guessToHitModifierForWeapon(mockShooter, mockShooterState, mockFighter, mockFighterState, mockWeapon, mockGame)); - when(mockFighter.getTargetId()).thenReturn(1); // Target aero is also firing on shooter. + when(mockFighter.getId()).thenReturn(1); // Target aero is also firing on shooter. expected = new ToHitData(mockShooter.getCrew().getGunnery(), FireControl.TH_GUNNERY); expected.addModifier(FireControl.TH_SHORT_RANGE); assertToHitDataEquals(expected, testFireControl.guessToHitModifierForWeapon(mockShooter, From 3615e1d16027c12ca8e804d2f11080cf25147ffe Mon Sep 17 00:00:00 2001 From: Simon Date: Sat, 7 Jan 2023 12:36:01 +0100 Subject: [PATCH 2/5] Add AbstractGame, extend IGame --- megamek/src/megamek/client/Client.java | 7 - .../client/ui/swing/PlayerListDialog.java | 14 +- megamek/src/megamek/common/AbstractGame.java | 57 ++++- .../src/megamek/common/ForceAssignable.java | 7 +- megamek/src/megamek/common/Game.java | 236 +++++++----------- megamek/src/megamek/common/IGame.java | 37 +-- .../common/alphaStrike/ASCardDisplayable.java | 2 +- megamek/src/megamek/common/force/Force.java | 38 +-- 8 files changed, 188 insertions(+), 210 deletions(-) diff --git a/megamek/src/megamek/client/Client.java b/megamek/src/megamek/client/Client.java index efb1945444d..167dac93ab5 100644 --- a/megamek/src/megamek/client/Client.java +++ b/megamek/src/megamek/client/Client.java @@ -320,13 +320,6 @@ protected boolean keepGameLog() { return PreferenceManager.getClientPreferences().keepGameLog(); } - /** - * Return an enumeration of the players in the game - */ - public Enumeration getPlayers() { - return game.getPlayers(); - } - public Entity getEntity(int id) { return game.getEntity(id); } diff --git a/megamek/src/megamek/client/ui/swing/PlayerListDialog.java b/megamek/src/megamek/client/ui/swing/PlayerListDialog.java index 3d1c42567ff..44779ccd3be 100644 --- a/megamek/src/megamek/client/ui/swing/PlayerListDialog.java +++ b/megamek/src/megamek/client/ui/swing/PlayerListDialog.java @@ -16,11 +16,14 @@ import megamek.client.Client; import megamek.client.ui.Messages; +import megamek.common.IGame; import megamek.common.Player; import megamek.common.Team; import javax.swing.*; import java.awt.*; +import java.util.Comparator; +import java.util.List; public class PlayerListDialog extends JDialog { @@ -55,6 +58,13 @@ public static void refreshPlayerList(JList playerList, refreshPlayerList(playerList, client, false); } + /** @return The game's players list sorted by id. */ + private static List sortedPlayerList(IGame game) { + List playerList = game.getPlayersList(); + playerList.sort(Comparator.comparingInt(Player::getId)); + return playerList; + } + /** * Refreshes the player list component with information from the game * object. @@ -63,7 +73,7 @@ public static void refreshPlayerList(JList playerList, Client client, boolean displayTeam) { ((DefaultListModel) playerList.getModel()).removeAllElements(); - for (Player player : client.getGame().getPlayersVectorSorted()) { + for (Player player : sortedPlayerList(client.getGame())) { StringBuffer playerDisplay = new StringBuffer(String.format("%-12s", player.getName())); // Append team information @@ -124,7 +134,7 @@ public void refreshPlayerList() { public Player getSelected() { if (!playerList.isSelectionEmpty()) { - return client.getGame().getPlayersVectorSorted().elementAt(playerList.getSelectedIndex()); + return sortedPlayerList(client.getGame()).get(playerList.getSelectedIndex()); } return null; diff --git a/megamek/src/megamek/common/AbstractGame.java b/megamek/src/megamek/common/AbstractGame.java index ed1e8db3272..c201af2b8f1 100644 --- a/megamek/src/megamek/common/AbstractGame.java +++ b/megamek/src/megamek/common/AbstractGame.java @@ -20,25 +20,30 @@ import megamek.common.force.Forces; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Vector; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; +/** + * This is a base class to derive all types of Game (TW, AS, BF, SBF...) from. Any such game will have players, units + * (InGameObjects) and Forces (even if empty); the base class manages these. + */ public abstract class AbstractGame implements IGame { /** The players present in the game mapped to their id as key. */ protected final ConcurrentHashMap players = new ConcurrentHashMap<>(); - // Not yet used, should replace Entity-List - protected final ConcurrentHashMap inGameObjects = new ConcurrentHashMap<>(); + /** The InGameObjects (units such as Entity and others) present in the game mapped to their id as key. */ + protected final ConcurrentHashMap inGameObjects = new ConcurrentHashMap<>(); + + /** The teams present in the game. */ + protected final CopyOnWriteArrayList teams = new CopyOnWriteArrayList<>(); /** * The forces present in the game. The top level force holds all forces and force-less entities * and should therefore not be shown. */ - private final Forces forces = new Forces(this); + protected Forces forces = new Forces(this); @Override public Player getPlayer(int id) { @@ -46,22 +51,50 @@ public Player getPlayer(int id) { } @Override + @Deprecated public Vector getPlayersVector() { return new Vector<>(players.values()); } @Override - public int getNoOfPlayers() { - return players.size(); + public List getTeamsList() { + return new ArrayList<>(teams); } @Override - public List getInGameObjects(Collection idList) { - return new ArrayList<>(inGameObjects.values()); + @Deprecated + public Enumeration getTeams() { + return Collections.enumeration(teams); + } + + @Override + public int getNoOfTeams() { + return teams.size(); + } + + @Override + @Deprecated + public Enumeration getPlayers() { + return players.elements(); + } + + @Override + public List getPlayersList() { + return new ArrayList<>(players.values()); + } + + @Override + public int getNoOfPlayers() { + return players.size(); } @Override public Forces getForces() { return forces; } -} + + @Override + public List getInGameObjects() { + return new ArrayList<>(inGameObjects.values()); + } +} \ No newline at end of file diff --git a/megamek/src/megamek/common/ForceAssignable.java b/megamek/src/megamek/common/ForceAssignable.java index 5031293017c..1bdd6a7d628 100644 --- a/megamek/src/megamek/common/ForceAssignable.java +++ b/megamek/src/megamek/common/ForceAssignable.java @@ -37,7 +37,7 @@ public interface ForceAssignable extends InGameObject { * The String contains all forces from top to bottom separated by backslash * with no backslash at beginning or end. Each force is followed by a unique id * separated by the vertical bar. E.g. - *

Regiment|1\Battalion B|11\Alpha Company|18\Battle Lance II|112 + *

Regiment|1||Battalion B|11||Alpha Company|18||Battle Lance II|112 * *

If this is not empty, the server will attempt to reconstruct the force * hierarchy when it receives this entity and will empty the string. @@ -80,7 +80,10 @@ default boolean partOfForce() { * @return A filtered list of all Entities in the given list */ static List filterToEntityList(List forceAssignableList) { - return forceAssignableList.stream().filter(a -> a instanceof Entity).map(a -> (Entity) a).collect(Collectors.toList()); + return forceAssignableList.stream() + .filter(a -> a instanceof Entity) + .map(a -> (Entity) a) + .collect(Collectors.toList()); } /** diff --git a/megamek/src/megamek/common/Game.java b/megamek/src/megamek/common/Game.java index a24fa8114ef..ac87a311a40 100644 --- a/megamek/src/megamek/common/Game.java +++ b/megamek/src/megamek/common/Game.java @@ -38,6 +38,8 @@ import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; +import static java.util.stream.Collectors.toList; + /** * The game class is the root of all data about the game in progress. Both the * Client and the Server should have one of these objects, and it is their job to @@ -62,15 +64,12 @@ public class Game extends AbstractGame implements Serializable { private MapSettings mapSettings = MapSettings.getInstance(); - private final List entities = new CopyOnWriteArrayList<>(); - private Hashtable entityIds = new Hashtable<>(); - /** * Track entities removed from the game (probably by death) */ private Vector vOutOfGame = new Vector<>(); - private Vector teams = new Vector<>(); +// private Vector teams = new Vector<>(); private final Map> entityPosLookup = new HashMap<>(); @@ -147,12 +146,6 @@ public class Game extends AbstractGame implements Serializable { // smoke clouds private List smokeCloudList = new CopyOnWriteArrayList<>(); - /** - * The forces present in the game. The top level force holds all forces and force-less entities - * and should therefore not be shown. - */ - private Forces forces = new Forces(this); - private transient Vector gameListeners = new Vector<>(); /** @@ -298,12 +291,7 @@ public void clearMinefields() { protected void clearMinefieldsHelper() { minefields.clear(); vibrabombs.removeAllElements(); - - Enumeration iter = getPlayers(); - while (iter.hasMoreElements()) { - Player player = iter.nextElement(); - player.removeMinefields(); - } + getPlayersList().forEach(Player::removeMinefields); } public Vector getVibrabombs() { @@ -342,21 +330,6 @@ public void setOptions(final @Nullable GameOptions options) { } } - /** - * Return an enumeration of teams in the game - */ - @Override - public Enumeration getTeams() { - return teams.elements(); - } - - /** - * Return the current number of teams in the game. - */ - public int getNoOfTeams() { - return teams.size(); - } - /** * @return an immutable clone of the vector of teams. Each element is one of the teams in the * game. @@ -436,30 +409,8 @@ public void setupTeams() { } } } - teams = initTeams; - } - - /** - * Return an enumeration of player in the game - */ - public Enumeration getPlayers() { - return players.elements(); - } - - /** - * @return a clone of the {@link #players} vector sorted by id - */ - public Vector getPlayersVectorSorted() { - Vector clone = new Vector<>(getPlayersVector()); - clone.sort(Comparator.comparingInt(Player::getId)); - return clone; - } - - /** - * Return the current number of active players in the game. - */ - public int getNoOfPlayers() { - return players.size(); + teams.clear(); + teams.addAll(initTeams); } @Override @@ -489,18 +440,13 @@ private void updatePlayer(Player player) { processGameEvent(new GamePlayerChangeEvent(this, player)); } - @Override - public List getInGameObjects(Collection idList) { - return new ArrayList<>(entities); - } - /** * Returns the number of entities owned by the player, regardless of their * status. */ public int getAllEntitiesOwnedBy(Player player) { int count = 0; - for (Entity entity : entities) { + for (Entity entity : inGameTWEntities()) { if (entity.getOwner().equals(player)) { count++; } @@ -518,7 +464,7 @@ public int getAllEntitiesOwnedBy(Player player) { */ public int getLiveEntitiesOwnedBy(Player player) { int count = 0; - for (Entity entity : entities) { + for (Entity entity : inGameTWEntities()) { if (entity.getOwner().equals(player) && !entity.isDestroyed() && !entity.isCarcass()) { count++; @@ -533,7 +479,7 @@ public int getLiveEntitiesOwnedBy(Player player) { */ public int getLiveDeployedEntitiesOwnedBy(Player player) { int count = 0; - for (Entity entity : entities) { + for (Entity entity : inGameTWEntities()) { if (entity.getOwner().equals(player) && !entity.isDestroyed() && !entity.isCarcass() && !entity.isOffBoard() && !entity.isCaptured()) { @@ -549,7 +495,7 @@ public int getLiveDeployedEntitiesOwnedBy(Player player) { */ public int getLiveCommandersOwnedBy(Player player) { int count = 0; - for (Entity entity : entities) { + for (Entity entity : inGameTWEntities()) { if (entity.getOwner().equals(player) && !entity.isDestroyed() && !entity.isCarcass() && entity.isCommander() && !entity.isOffBoard() @@ -564,7 +510,7 @@ public int getLiveCommandersOwnedBy(Player player) { * @return true if the player has a valid unit with the Tactical Genius pilot special ability. */ public boolean hasTacticalGenius(Player player) { - for (Entity entity : entities) { + for (Entity entity : inGameTWEntities()) { if (entity.hasAbility(OptionsConstants.MISC_TACTICAL_GENIUS) && entity.getOwner().equals(player) && !entity.isDestroyed() && entity.isDeployed() && !entity.isCarcass() && !entity.getCrew().isUnconscious()) { @@ -583,7 +529,7 @@ public List getValidTargets(Entity entity) { boolean friendlyFire = getOptions().booleanOption(OptionsConstants.BASE_FRIENDLY_FIRE); - for (Entity otherEntity : entities) { + for (Entity otherEntity : inGameTWEntities()) { // Even if friendly fire is acceptable, do not shoot yourself // Enemy units not on the board can not be shot. if ((otherEntity.getPosition() != null) @@ -787,7 +733,7 @@ public boolean isDeploymentComplete() { public void setupRoundDeployment() { deploymentTable = new Hashtable<>(); - for (Entity ent : entities) { + for (Entity ent : inGameTWEntities()) { if (ent.isDeployed()) { continue; } @@ -849,8 +795,9 @@ public List getUndeployedEntities() { /** * @return an enumeration of all the entities in the game. */ + @Deprecated public Iterator getEntities() { - return entities.iterator(); + return inGameTWEntities().iterator(); } /** @@ -859,12 +806,12 @@ public Iterator getEntities() { * to the end of the list if necessary, returning null if there are no entities. */ public @Nullable Entity getPreviousEntityFromList(final @Nullable Entity current) { - if ((current != null) && entities.contains(current)) { - int prev = entities.indexOf(current) - 1; + if ((current != null) && inGameTWEntities().contains(current)) { + int prev = inGameTWEntities().indexOf(current) - 1; if (prev < 0) { - prev = entities.size() - 1; // wrap around to end + prev = inGameTWEntities().size() - 1; // wrap around to end } - return entities.get(prev); + return inGameTWEntities().get(prev); } return null; } @@ -875,12 +822,12 @@ public Iterator getEntities() { * the beginning of the list if necessary, returning null if there are no entities. */ public @Nullable Entity getNextEntityFromList(final @Nullable Entity current) { - if ((current != null) && entities.contains(current)) { - int next = entities.indexOf(current) + 1; - if (next >= entities.size()) { + if ((current != null) && inGameTWEntities().contains(current)) { + int next = inGameTWEntities().indexOf(current) + 1; + if (next >= inGameTWEntities().size()) { next = 0; // wrap-around to beginning } - return entities.get(next); + return inGameTWEntities().get(next); } return null; } @@ -889,14 +836,14 @@ public Iterator getEntities() { * @return the actual vector for the entities */ public List getEntitiesVector() { - return Collections.unmodifiableList(entities); + return Collections.unmodifiableList(inGameTWEntities()); } public synchronized void setEntitiesVector(List entities) { // checkPositionCacheConsistency(); - this.entities.clear(); - this.entities.addAll(entities); - reindexEntities(); +// this.entities.clear(); +// this.entities.addAll(entities); + reindexEntities(entities); resetEntityPositionLookup(); processGameEvent(new GameEntityNewEvent(this, entities)); } @@ -973,7 +920,7 @@ public Vector getC3NetworkMembers(Entity entity) { // Walk through the entities in the game, and add all // members of the C3 network to the output Vector. - for (Entity unit : entities) { + for (Entity unit : inGameTWEntities()) { if (entity.equals(unit) || entity.onSameC3NetworkAs(unit)) { members.addElement(unit); } @@ -1013,7 +960,7 @@ public Vector getC3SubNetworkMembers(Entity entity) { if (entity.hasC3()) { // Walk through the entities in the game, and add all // sub-members of the C3 network to the output Vector. - for (Entity unit : entities) { + for (Entity unit : inGameTWEntities()) { if (entity.equals(unit) || unit.C3MasterIs(entity)) { members.addElement(unit); } @@ -1038,7 +985,7 @@ public Hashtable> getPositionMap() { Vector atPos; // Walk through the entities in this game. - for (Entity entity : entities) { + for (Entity entity : inGameTWEntities()) { // Get the vector for this entity's position. final Coords coords = entity.getPosition(); if (coords != null) { @@ -1133,7 +1080,7 @@ public Enumeration getDevastatedEntities() { public Enumeration getCarcassEntities() { Vector carcasses = new Vector<>(); - for (Entity entity : entities) { + for (Entity entity : inGameTWEntities()) { if (entity.isCarcass()) { carcasses.addElement(entity); } @@ -1146,7 +1093,7 @@ public Enumeration getCarcassEntities() { * Return the current number of entities in the game. */ public int getNoOfEntities() { - return entities.size(); + return inGameTWEntities().size(); } /** @@ -1191,11 +1138,10 @@ public int getNoOfEntities() { } } - /** - * Returns the entity with the given id number, if any. - */ + /** @return The entity with the given id number, if any. */ public @Nullable Entity getEntity(final int id) { - return entityIds.get(id); + InGameObject possibleEntity = inGameObjects.get(id); + return (possibleEntity instanceof Entity) ? (Entity) possibleEntity : null; } /** @@ -1281,16 +1227,13 @@ public synchronized void addEntity(Entity entity, boolean genEvent) { // We don't want to be resetting a UUID that exists already! entity.setC3UUID(); } - // Add this Entity, ensuring that it's id is unique + // Add this Entity, ensuring that its id is unique int id = entity.getId(); - if (!entityIds.containsKey(id)) { - entityIds.put(id, entity); - } else { + if (inGameObjects.containsKey(id)) { id = getNextEntityId(); entity.setId(id); - entityIds.put(id, entity); } - entities.add(entity); + inGameObjects.put(id, entity); updateEntityPositionLookup(entity, null); if (id > lastEntityId) { @@ -1323,8 +1266,7 @@ public synchronized void setEntity(int id, Entity entity, Vector m addEntity(entity); } else { entity.setGame(this); - entities.set(entities.indexOf(oldEntity), entity); - entityIds.put(id, entity); + inGameObjects.put(id, entity); // Get the collection of positions HashSet oldPositions = oldEntity.getOccupiedCoords(); // Update position lookup table @@ -1351,7 +1293,8 @@ public int getNextEntityId() { * @return true if an entity with the specified id number exists in this game. */ public boolean hasEntity(int entityId) { - return entityIds.containsKey(entityId); + Optional possibleEntity = getInGameObject(entityId); + return possibleEntity.isPresent() && possibleEntity.get() instanceof Entity; } /** @@ -1359,16 +1302,12 @@ public boolean hasEntity(int entityId) { * (probably due to double-blind) ignore it. */ public synchronized void removeEntity(int id, int condition) { - // always attempt to remove the entity with this ID from the entities collection - // as it may have gotten stuck there. - entities.removeIf(ent -> (ent.getId() == id)); - Entity toRemove = getEntity(id); if (toRemove == null) { return; } - entityIds.remove(id); + inGameObjects.remove(id); removeEntityPositionLookup(toRemove); toRemove.setRemovalCondition(condition); @@ -1413,8 +1352,7 @@ public synchronized void reset() { roundCount = 0; - entities.clear(); - entityIds.clear(); + inGameObjects.clear(); entityPosLookup.clear(); vOutOfGame.removeAllElements(); @@ -1455,14 +1393,14 @@ private void removeArtyAutoHitHexes() { * Regenerates the entities by id hashtable by going thru all entities in * the Vector */ - private void reindexEntities() { - entityIds.clear(); + private void reindexEntities(List entities) { + inGameObjects.clear(); lastEntityId = 0; // Add these entities to the game. for (Entity entity : entities) { final int id = entity.getId(); - entityIds.put(id, entity); + inGameObjects.put(id, entity); if (id > lastEntityId) { lastEntityId = id; @@ -1471,7 +1409,7 @@ private void reindexEntities() { // We need to ensure that each entity has the proper Game reference // however, the entityIds Hashmap must be fully formed before this // is called, since setGame also calls setGame for loaded Entities - for (Entity entity : entities) { + for (Entity entity : inGameTWEntities()) { entity.setGame(this); } } @@ -1483,7 +1421,7 @@ private void reindexEntities() { * @param c the coordinates to search at */ public Entity getFirstEntity(Coords c) { - for (Entity entity : entities) { + for (Entity entity : inGameTWEntities()) { if (c.equals(entity.getPosition()) && entity.isTargetable()) { return entity; } @@ -1499,7 +1437,7 @@ public Entity getFirstEntity(Coords c) { * @param currentEntity the entity that is firing */ public Entity getFirstEnemyEntity(Coords c, Entity currentEntity) { - for (Entity entity : entities) { + for (Entity entity : inGameTWEntities()) { if (c.equals(entity.getPosition()) && entity.isTargetable() && entity.isEnemyOf(currentEntity)) { return entity; @@ -1543,7 +1481,7 @@ public List getEntitiesVector(Coords c) { public synchronized List getEntitiesVector(Coords c, boolean ignore) { // checkPositionCacheConsistency(); // Make sure the look-up is initialized - if (entityPosLookup.isEmpty() && !entities.isEmpty()) { + if (entityPosLookup.isEmpty() && !inGameTWEntities().isEmpty()) { resetEntityPositionLookup(); } Set posEntities = entityPosLookup.get(c); @@ -1580,7 +1518,7 @@ public synchronized List getEntitiesVector(Coords c, boolean ignore) { */ public synchronized List getAllOffboardEnemyEntities(Player player) { List vector = new ArrayList<>(); - for (Entity e : entities) { + for (Entity e : inGameTWEntities()) { if (e.getOwner().isEnemyOf(player) && e.isOffBoard() && !e.isDestroyed() && e.isDeployed()) { vector.add(e); } @@ -1765,7 +1703,7 @@ public int getFirstEntityNum(final @Nullable GameTurn turn) { return -1; } - for (Entity entity : entities) { + for (Entity entity : inGameTWEntities()) { if (turn.isValidEntity(entity, this)) { return entity.getId(); } @@ -1779,11 +1717,11 @@ public int getFirstEntityNum(final @Nullable GameTurn turn) { * @return the next selectable entity that can act this turn, or null if none can. */ public @Nullable Entity getNextEntity(int start) { - if (entities.isEmpty()) { + if (inGameTWEntities().isEmpty()) { return null; } - start = start % entities.size(); - int entityId = entities.get(start).getId(); + start = start % inGameTWEntities().size(); + int entityId = inGameTWEntities().get(start).getId(); return getEntity(getNextEntityNum(getTurn(), entityId)); } @@ -1793,24 +1731,26 @@ public int getFirstEntityNum(final @Nullable GameTurn turn) { * @return the entity id of the next entity that can move during the specified turn */ public int getNextEntityNum(final @Nullable GameTurn turn, int start) { + List sortedEntities = inGameTWEntities(); + sortedEntities.sort(Comparator.comparingInt(Entity::getId)); // If we don't have a turn, return ENTITY_NONE if (turn == null) { return Entity.NONE; } boolean hasLooped = false; - int i = (entities.indexOf(entityIds.get(start)) + 1) % entities.size(); + int i = (sortedEntities.indexOf(getEntity(start)) + 1) % sortedEntities.size(); if (i == -1) { //This means we were given an invalid entity ID, punt return Entity.NONE; } int startingIndex = i; while (!((hasLooped == true) && (i == startingIndex))) { - final Entity entity = entities.get(i); + final Entity entity = sortedEntities.get(i); if (turn.isValidEntity(entity, this)) { return entity.getId(); } i++; - if (i == entities.size()) { + if (i == sortedEntities.size()) { i = 0; hasLooped = true; } @@ -1825,25 +1765,27 @@ public int getNextEntityNum(final @Nullable GameTurn turn, int start) { * @return the entity id of the previous entity that can move during the specified turn */ public int getPrevEntityNum(GameTurn turn, int start) { + List sortedEntities = inGameTWEntities(); + sortedEntities.sort(Comparator.comparingInt(Entity::getId)); boolean hasLooped = false; - int i = (entities.indexOf(entityIds.get(start)) - 1) % entities.size(); + int i = (sortedEntities.indexOf(getEntity(start)) - 1) % sortedEntities.size(); if (i == -2) { //This means we were given an invalid entity ID, punt return -1; } if (i == -1) { //This means we were given an invalid entity ID, punt - i = entities.size() - 1; + i = sortedEntities.size() - 1; } int startingIndex = i; while (!((hasLooped == true) && (i == startingIndex))) { - final Entity entity = entities.get(i); + final Entity entity = sortedEntities.get(i); if (turn.isValidEntity(entity, this)) { return entity.getId(); } i--; if (i < 0) { - i = entities.size() - 1; + i = sortedEntities.size() - 1; hasLooped = true; } } @@ -1860,7 +1802,7 @@ public int getFirstDeployableEntityNum(final @Nullable GameTurn turn) { if (turn == null) { return -1; } - for (Entity entity : entities) { + for (Entity entity : inGameTWEntities()) { if (turn.isValidEntity(entity, this) && entity.shouldDeploy(getRoundCount())) { return entity.getId(); } @@ -1873,8 +1815,8 @@ public int getFirstDeployableEntityNum(final @Nullable GameTurn turn) { */ public int getNextDeployableEntityNum(GameTurn turn, int start) { if (start >= 0) { - for (int i = start; i < entities.size(); i++) { - final Entity entity = entities.get(i); + for (int i = start; i < inGameTWEntities().size(); i++) { + final Entity entity = inGameTWEntities().get(i); if (turn.isValidEntity(entity, this) && entity.shouldDeploy(getRoundCount())) { return entity.getId(); } @@ -1892,7 +1834,7 @@ public int getNextDeployableEntityNum(GameTurn turn, int start) { */ public ArrayList getPlayerEntities(Player player, boolean hide) { ArrayList output = new ArrayList<>(); - for (Entity entity : entities) { + for (Entity entity : inGameTWEntities()) { if (entity.isPartOfFighterSquadron() && hide) { continue; } @@ -1912,7 +1854,7 @@ public ArrayList getPlayerEntities(Player player, boolean hide) { */ public ArrayList getPlayerEntityIds(Player player, boolean hide) { ArrayList output = new ArrayList<>(); - for (Entity entity : entities) { + for (Entity entity : inGameTWEntities()) { if (entity.isPartOfFighterSquadron() && hide) { continue; } @@ -1961,7 +1903,7 @@ public int getInfantryLeft(int playerId) { Player player = getPlayer(playerId); int remaining = 0; - for (Entity entity : entities) { + for (Entity entity : inGameTWEntities()) { if (player.equals(entity.getOwner()) && entity.isSelectableThisTurn() && (entity instanceof Infantry)) { remaining++; @@ -1979,7 +1921,7 @@ public int getProtoMeksLeft(int playerId) { Player player = getPlayer(playerId); int remaining = 0; - for (Entity entity : entities) { + for (Entity entity : inGameTWEntities()) { if (player.equals(entity.getOwner()) && entity.isSelectableThisTurn() && (entity instanceof Protomech)) { remaining++; @@ -1997,7 +1939,7 @@ public int getVehiclesLeft(int playerId) { Player player = getPlayer(playerId); int remaining = 0; - for (Entity entity : entities) { + for (Entity entity : inGameTWEntities()) { if (player.equals(entity.getOwner()) && entity.isSelectableThisTurn() && (entity instanceof Tank)) { remaining++; @@ -2015,7 +1957,7 @@ public int getMechsLeft(int playerId) { Player player = getPlayer(playerId); int remaining = 0; - for (Entity entity : entities) { + for (Entity entity : inGameTWEntities()) { if (player.equals(entity.getOwner()) && entity.isSelectableThisTurn() && (entity instanceof Mech)) { remaining++; @@ -2268,8 +2210,8 @@ public void addInitiativeRerollRequest(Team t) { public void rollInitAndResolveTies() { if (getOptions().booleanOption(OptionsConstants.RPG_INDIVIDUAL_INITIATIVE)) { Vector vRerolls = new Vector<>(); - for (int i = 0; i < entities.size(); i++) { - Entity e = entities.get(i); + for (int i = 0; i < inGameTWEntities().size(); i++) { + Entity e = inGameTWEntities().get(i); if (initiativeRerollRequests.contains(getTeamForPlayer(e.getOwner()))) { vRerolls.add(e); } @@ -3335,7 +3277,7 @@ private void removeEntityPositionLookup(Entity e) { private void resetEntityPositionLookup() { entityPosLookup.clear(); - for (Entity e : entities) { + for (Entity e : inGameTWEntities()) { updateEntityPositionLookup(e, null); } } @@ -3362,7 +3304,7 @@ private void checkPositionCacheConsistency() { List entitiesInVector = new ArrayList<>(); int entitiesInCacheCount = countEntitiesInCache(entitiesInCache); int entityVectorSize = 0; - for (Entity e : entities) { + for (Entity e : inGameTWEntities()) { if (e.getPosition() != null) { entityVectorSize++; entitiesInVector.add(e.getId()); @@ -3373,7 +3315,7 @@ private void checkPositionCacheConsistency() { if ((entitiesInCacheCount != entityVectorSize) && !getPhase().isDeployment() && !getPhase().isExchange() && !getPhase().isLounge() && !getPhase().isInitiativeReport() && !getPhase().isInitiative()) { - LogManager.getLogger().warn("Entities vector has " + entities.size() + LogManager.getLogger().warn("Entities vector has " + inGameTWEntities().size() + " but pos lookup cache has " + entitiesInCache.size() + "entities!"); List missingIds = new ArrayList<>(); for (Integer id : entitiesInVector) { @@ -3383,7 +3325,7 @@ private void checkPositionCacheConsistency() { } LogManager.getLogger().info("Missing ids: " + missingIds); } - for (Entity e : entities) { + for (Entity e : inGameTWEntities()) { HashSet positions = e.getOccupiedCoords(); for (Coords c : positions) { HashSet ents = entityPosLookup.get(c); @@ -3420,15 +3362,6 @@ public String getUUIDString() { } - public synchronized Forces getForces() { - return forces; - } - - @Override - public List getInGameObjects() { - return new ArrayList<>(entities); - } - /** * Overwrites the current forces object with the provided object. * Called from server messages when loading a game. @@ -3467,4 +3400,9 @@ public void setMapSettings(MapSettings mapSettings) { // clean up linux/macOS/Windows paths this.mapSettings.adjustPathSeparator(); } -} + + /** @return The TW Units (Entity) currently in the game. */ + public List inGameTWEntities() { + return inGameObjects.values().stream().filter(o -> o instanceof Entity).map(o -> (Entity) o).collect(toList()); + } +} \ No newline at end of file diff --git a/megamek/src/megamek/common/IGame.java b/megamek/src/megamek/common/IGame.java index e75312bd456..a3267173ba9 100644 --- a/megamek/src/megamek/common/IGame.java +++ b/megamek/src/megamek/common/IGame.java @@ -41,19 +41,19 @@ public interface IGame { */ @Nullable Player getPlayer(int id); - /** - * @return an enumeration of {@link Player players} in the game - */ + /** @return An enumeration of {@link Player players} in the game. */ @Deprecated Enumeration getPlayers(); - /** - * @return The current players as a list. - */ + /** @return The current players as a list. */ + @Deprecated Vector getPlayersVector(); + /** @return The current players as a list. Implementations should make sure that this list can be safely modified. */ + List getPlayersList(); + /** - * Adds the player to the game with the id + * Adds the given Player to the game with the given game-unique id. * * @param id The game-unique id of this player * @param player The Player object @@ -67,23 +67,24 @@ public interface IGame { */ void removePlayer(int id); - /** - * @return the current number of active players in the game. - */ + /** @return The current number of active players in the game. This includes observers but not ghosts. */ int getNoOfPlayers(); - /** - * @return an enumeration of the teams in the game. - */ + /** @return an enumeration of the teams in the game. */ + @Deprecated Enumeration getTeams(); - /** - * @return An unused id - */ + /** @return The teams in the game. Implementations should make sure that this list can be safely modified. */ + List getTeamsList(); + + /** @return The number of teams in the game. */ + int getNoOfTeams(); + + /** @return The next free id for InGameObjects (units and others). */ int getNextEntityId(); /** - * @return the number of entities owned by the player, regardless of their + * @return the number of units owned by the player, regardless of their * status, as long as they are in the game. */ default int getEntitiesOwnedBy(Player player) { @@ -111,7 +112,7 @@ default Optional getInGameObject(int id) { /** @return A list of all InGameObjects of this game. This list is copied and may be safely modified. */ List getInGameObjects(); - /** @return A list of all InGameObjects of this game with the given ids. This list may be safely modified. */ + /** @return A list of all InGameObjects of this game with the given ids. The returned list may be safely modified. */ default List getInGameObjects(Collection idList) { return getInGameObjects().stream().filter(o -> idList.contains(o.getId())).collect(Collectors.toList()); } diff --git a/megamek/src/megamek/common/alphaStrike/ASCardDisplayable.java b/megamek/src/megamek/common/alphaStrike/ASCardDisplayable.java index fba6a4ee2ec..02973a1cd2c 100644 --- a/megamek/src/megamek/common/alphaStrike/ASCardDisplayable.java +++ b/megamek/src/megamek/common/alphaStrike/ASCardDisplayable.java @@ -146,7 +146,7 @@ default boolean hasMovementMode(String mode) { return getMovement().containsKey(mode); } - /** @return True if this AS element is a fighter (AF, CF). */ + /** @return True if this AS element is a fighter (AF, CF) or an Aero SV (Fixed Wing Support). */ default boolean isFighter() { return getASUnitType().isAnyOf(AF, CF) || isAerospaceSV(); } diff --git a/megamek/src/megamek/common/force/Force.java b/megamek/src/megamek/common/force/Force.java index 09fc0a00818..132c48a3554 100644 --- a/megamek/src/megamek/common/force/Force.java +++ b/megamek/src/megamek/common/force/Force.java @@ -192,11 +192,11 @@ public int getSubForceId(int index) { } /** - * Returns true if the provided entity is among the force's direct members. - * Does NOT check if the entity is part of any subforce. + * Returns true if the provided unit is among the force's direct members. + * Does NOT check if the unit is part of any subforce. */ - public boolean containsEntity(ForceAssignable entity) { - return containsEntity(entity.getId()); + public boolean containsEntity(ForceAssignable unit) { + return containsEntity(unit.getId()); } /** @@ -208,11 +208,11 @@ public boolean containsEntity(int id) { } /** - * Returns the index of the provided entity in the list of direct members of this force. - * Returns -1 if the entity is no direct member of this force. + * Returns the index of the provided unit in the list of direct members of this force. + * Returns -1 if the unit is no direct member of this force. */ - public int entityIndex(ForceAssignable entity) { - return entities.indexOf(entity.getId()); + public int entityIndex(ForceAssignable unit) { + return entities.indexOf(unit.getId()); } /** @@ -242,12 +242,12 @@ public List getSubForces() { return Collections.unmodifiableList(subForces); } - void addEntity(ForceAssignable entity) { - entities.add(entity.getId()); + void addEntity(ForceAssignable unit) { + entities.add(unit.getId()); } - void removeEntity(ForceAssignable entity) { - entities.remove((Integer) entity.getId()); + void removeEntity(ForceAssignable unit) { + entities.remove((Integer) unit.getId()); } /** Removes the given id from the list of subordinated entities. */ @@ -280,11 +280,11 @@ public String toString() { } /** Moves up the given entityId by one position if possible. Returns true when an actual change occurred. */ - boolean moveUp(int entityId) { - if (!containsEntity(entityId)) { + boolean moveUp(int unitId) { + if (!containsEntity(unitId)) { return false; } - int index = entities.indexOf(entityId); + int index = entities.indexOf(unitId); if (index > 0) { Collections.swap(entities, index, index - 1); return true; @@ -292,12 +292,12 @@ boolean moveUp(int entityId) { return false; } - /** Moves down the given entityId by one position if possible. Returns true when an actual change occurred. */ - boolean moveDown(int entityId) { - if (!containsEntity(entityId)) { + /** Moves down the given unitId by one position if possible. Returns true when an actual change occurred. */ + boolean moveDown(int unitId) { + if (!containsEntity(unitId)) { return false; } - int index = entities.indexOf(entityId); + int index = entities.indexOf(unitId); if (index < entities.size() - 1) { Collections.swap(entities, index, index + 1); return true; From f073aeefe311b0258f4c2d0fe18e9b0b8562d1da Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 8 Jan 2023 12:26:45 +0100 Subject: [PATCH 3/5] Remove old-style code and remove entity reference from Team --- .../ui/swing/lobby/TeamOverviewPanel.java | 2 +- megamek/src/megamek/common/AbstractGame.java | 30 +++++-------- megamek/src/megamek/common/Game.java | 21 ++------- megamek/src/megamek/common/IGame.java | 36 ++++++++------- megamek/src/megamek/common/Team.java | 17 +------ .../common/battlevalue/AeroBVCalculator.java | 3 +- .../CombatVehicleBVCalculator.java | 4 +- .../common/battlevalue/MekBVCalculator.java | 3 +- .../battlevalue/ProtoMekBVCalculator.java | 4 +- megamek/src/megamek/server/GameManager.java | 45 ++++++++++--------- .../server/commands/CheckBVTeamCommand.java | 4 +- 11 files changed, 65 insertions(+), 104 deletions(-) diff --git a/megamek/src/megamek/client/ui/swing/lobby/TeamOverviewPanel.java b/megamek/src/megamek/client/ui/swing/lobby/TeamOverviewPanel.java index d6b3583c958..031a0692ee1 100644 --- a/megamek/src/megamek/client/ui/swing/lobby/TeamOverviewPanel.java +++ b/megamek/src/megamek/client/ui/swing/lobby/TeamOverviewPanel.java @@ -196,7 +196,7 @@ public int getColumnCount() { /** Updates the stored data from the provided game. */ public void updateTable(Game game) { clearData(); - for (Team team: game.getTeamsVector()) { + for (Team team: game.getTeams()) { teams.add(team); teamID.add(team.getId()); teamNames.add(team.toString()); diff --git a/megamek/src/megamek/common/AbstractGame.java b/megamek/src/megamek/common/AbstractGame.java index c201af2b8f1..75c1121be7e 100644 --- a/megamek/src/megamek/common/AbstractGame.java +++ b/megamek/src/megamek/common/AbstractGame.java @@ -45,6 +45,11 @@ public abstract class AbstractGame implements IGame { */ protected Forces forces = new Forces(this); + @Override + public Forces getForces() { + return forces; + } + @Override public Player getPlayer(int id) { return players.get(id); @@ -56,22 +61,6 @@ public Vector getPlayersVector() { return new Vector<>(players.values()); } - @Override - public List getTeamsList() { - return new ArrayList<>(teams); - } - - @Override - @Deprecated - public Enumeration getTeams() { - return Collections.enumeration(teams); - } - - @Override - public int getNoOfTeams() { - return teams.size(); - } - @Override @Deprecated public Enumeration getPlayers() { @@ -89,8 +78,13 @@ public int getNoOfPlayers() { } @Override - public Forces getForces() { - return forces; + public List getTeams() { + return new ArrayList<>(teams); + } + + @Override + public int getNoOfTeams() { + return teams.size(); } @Override diff --git a/megamek/src/megamek/common/Game.java b/megamek/src/megamek/common/Game.java index ac87a311a40..52ed4638ffe 100644 --- a/megamek/src/megamek/common/Game.java +++ b/megamek/src/megamek/common/Game.java @@ -69,8 +69,6 @@ public class Game extends AbstractGame implements Serializable { */ private Vector vOutOfGame = new Vector<>(); -// private Vector teams = new Vector<>(); - private final Map> entityPosLookup = new HashMap<>(); /** @@ -330,14 +328,6 @@ public void setOptions(final @Nullable GameOptions options) { } } - /** - * @return an immutable clone of the vector of teams. Each element is one of the teams in the - * game. - */ - public List getTeamsVector() { - return Collections.unmodifiableList(teams); - } - /** * @return a player's team, which may be null if they do not have a team */ @@ -366,8 +356,7 @@ public void setupTeams() { // Get all NO_TEAM players. If team_initiative is false, all // players are on their own teams for initiative purposes. - for (Enumeration i = getPlayers(); i.hasMoreElements(); ) { - final Player player = i.nextElement(); + for (Player player : getPlayersList()) { // Ignore players not on a team if (player.getTeam() == Player.TEAM_UNASSIGNED) { continue; @@ -383,8 +372,7 @@ public void setupTeams() { // Now, go through all the teams, and add the appropriate player for (int t = Player.TEAM_NONE + 1; t < Player.TEAM_NAMES.length; t++) { Team new_team = null; - for (Enumeration i = getPlayers(); i.hasMoreElements(); ) { - final Player player = i.nextElement(); + for (Player player : getPlayersList()) { if (player.getTeam() == t) { if (new_team == null) { new_team = new Team(t); @@ -400,7 +388,7 @@ public void setupTeams() { } // May need to copy state over from previous teams, such as initiative - if ((teams != null) && !getPhase().isLounge()) { + if (!getPhase().isLounge()) { for (Team newTeam : initTeams) { for (Team oldTeam : teams) { if (newTeam.equals(oldTeam)) { @@ -1281,9 +1269,6 @@ public synchronized void setEntity(int id, Entity entity, Vector m } } - /** - * @return int containing an unused entity id - */ @Override public int getNextEntityId() { return lastEntityId + 1; diff --git a/megamek/src/megamek/common/IGame.java b/megamek/src/megamek/common/IGame.java index a3267173ba9..78b1c443b87 100644 --- a/megamek/src/megamek/common/IGame.java +++ b/megamek/src/megamek/common/IGame.java @@ -31,10 +31,23 @@ */ public interface IGame { + @Nullable + GameTurn getTurn(); + GameOptions getOptions(); GamePhase getPhase(); + /** + * @return Whether there is an active claim for victory. + */ + boolean isForceVictory(); + + /** @return The Forces present in this game. Can be empty, but not null. */ + Forces getForces(); + + // PLAYERS ////////////// + /** * @param id a player id * @return the individual player assigned the id parameter. @@ -70,16 +83,18 @@ public interface IGame { /** @return The current number of active players in the game. This includes observers but not ghosts. */ int getNoOfPlayers(); - /** @return an enumeration of the teams in the game. */ - @Deprecated - Enumeration getTeams(); + // TEAMS ////////////// /** @return The teams in the game. Implementations should make sure that this list can be safely modified. */ - List getTeamsList(); + List getTeams(); /** @return The number of teams in the game. */ int getNoOfTeams(); + void setupTeams(); + + // UNITS ////////////// + /** @return The next free id for InGameObjects (units and others). */ int getNextEntityId(); @@ -91,19 +106,6 @@ default int getEntitiesOwnedBy(Player player) { return (int) getInGameObjects().stream().filter(o -> o.getOwnerId() == player.getId()).count(); } - @Nullable - GameTurn getTurn(); - - void setupTeams(); - - /** - * @return Whether there is an active claim for victory. - */ - boolean isForceVictory(); - - /** @return The Forces present in this game. Can be empty, but not null. */ - Forces getForces(); - /** @return The InGameObject associated with the given id, if there is one. */ default Optional getInGameObject(int id) { return getInGameObjects().stream().filter(o -> o.getId() == id).findAny(); diff --git a/megamek/src/megamek/common/Team.java b/megamek/src/megamek/common/Team.java index 3aa4276cf78..f8eb8b11735 100644 --- a/megamek/src/megamek/common/Team.java +++ b/megamek/src/megamek/common/Team.java @@ -336,19 +336,4 @@ public void setInitCompensationBonus(int nNewValue) { player.setInitCompensationBonus(nNewValue); } } - - /** - * cycle through entities on team and collect all the airborne VTOL/WIGE - * - * @return a vector of relevant entity ids - */ - public Vector getAirborneVTOL() { - // a vector of unit ids - Vector units = new Vector<>(); - for (Enumeration loop = players.elements(); loop.hasMoreElements(); ) { - Player player = loop.nextElement(); - units.addAll(player.getAirborneVTOL()); - } - return units; - } -} +} \ No newline at end of file diff --git a/megamek/src/megamek/common/battlevalue/AeroBVCalculator.java b/megamek/src/megamek/common/battlevalue/AeroBVCalculator.java index 36b7dbbc252..63a289a40bd 100644 --- a/megamek/src/megamek/common/battlevalue/AeroBVCalculator.java +++ b/megamek/src/megamek/common/battlevalue/AeroBVCalculator.java @@ -597,8 +597,7 @@ public static int calculateBV(Aero aero, boolean ignoreC3, boolean ignoreSkill, if (tmpP.hasTAG()) { tagBV += atype.getBV(aero); } else if ((tmpP.getTeam() != Player.TEAM_NONE) && (aero.getGame() != null)) { - for (Enumeration e = aero.getGame().getTeams(); e.hasMoreElements();) { - Team m = e.nextElement(); + for (Team m : aero.getGame().getTeams()) { if (m.getId() == tmpP.getTeam()) { if (m.hasTAG(aero.getGame())) { tagBV += atype.getBV(aero); diff --git a/megamek/src/megamek/common/battlevalue/CombatVehicleBVCalculator.java b/megamek/src/megamek/common/battlevalue/CombatVehicleBVCalculator.java index a5cbf61721d..f907a8e843a 100644 --- a/megamek/src/megamek/common/battlevalue/CombatVehicleBVCalculator.java +++ b/megamek/src/megamek/common/battlevalue/CombatVehicleBVCalculator.java @@ -22,7 +22,6 @@ import megamek.common.*; import java.util.ArrayList; -import java.util.Enumeration; import java.util.HashMap; import java.util.Map; @@ -376,8 +375,7 @@ public static int calculateBV(Tank combatVee, boolean ignoreC3, boolean ignoreSk if (tmpP.hasTAG()) { tagBV += atype.getBV(combatVee); } else if ((tmpP.getTeam() != Player.TEAM_NONE) && (combatVee.getGame() != null)) { - for (Enumeration e = combatVee.getGame().getTeams(); e.hasMoreElements();) { - Team m = e.nextElement(); + for (Team m : combatVee.getGame().getTeams()) { if (m.getId() == tmpP.getTeam()) { if (m.hasTAG(combatVee.getGame())) { tagBV += atype.getBV(combatVee); diff --git a/megamek/src/megamek/common/battlevalue/MekBVCalculator.java b/megamek/src/megamek/common/battlevalue/MekBVCalculator.java index cac47372ea1..0069d24f90d 100644 --- a/megamek/src/megamek/common/battlevalue/MekBVCalculator.java +++ b/megamek/src/megamek/common/battlevalue/MekBVCalculator.java @@ -963,8 +963,7 @@ && hasExplosiveEquipmentPenalty(mek, l)) { if (tmpP.hasTAG()) { tagBV += atype.getBV(mek); } else if ((tmpP.getTeam() != Player.TEAM_NONE) && (mek.getGame() != null)) { - for (Enumeration e = mek.getGame().getTeams(); e.hasMoreElements(); ) { - Team m = e.nextElement(); + for (Team m : mek.getGame().getTeams()) { if (m.getId() == tmpP.getTeam()) { if (m.hasTAG(mek.getGame())) { tagBV += atype.getBV(mek); diff --git a/megamek/src/megamek/common/battlevalue/ProtoMekBVCalculator.java b/megamek/src/megamek/common/battlevalue/ProtoMekBVCalculator.java index e486f2400e6..63cd96a9c58 100644 --- a/megamek/src/megamek/common/battlevalue/ProtoMekBVCalculator.java +++ b/megamek/src/megamek/common/battlevalue/ProtoMekBVCalculator.java @@ -22,7 +22,6 @@ import megamek.common.*; import java.util.ArrayList; -import java.util.Enumeration; import java.util.HashMap; import java.util.Map; @@ -219,8 +218,7 @@ public static int calculateBV(Protomech protoMek, boolean ignoreSkill, Calculati if (tmpP.hasTAG()) { tagBV += atype.getBV(protoMek); } else if ((tmpP.getTeam() != Player.TEAM_NONE) && (protoMek.getGame() != null)) { - for (Enumeration e = protoMek.getGame().getTeams(); e.hasMoreElements();) { - Team m = e.nextElement(); + for (Team m : protoMek.getGame().getTeams()) { if (m.getId() == tmpP.getTeam()) { if (m.hasTAG(protoMek.getGame())) { tagBV += atype.getBV(protoMek); diff --git a/megamek/src/megamek/server/GameManager.java b/megamek/src/megamek/server/GameManager.java index ce0b6df1464..9c16307d636 100644 --- a/megamek/src/megamek/server/GameManager.java +++ b/megamek/src/megamek/server/GameManager.java @@ -2707,7 +2707,7 @@ private void rollInitiative() { TurnOrdered.rollInitiative(game.getEntitiesVector(), false); } else { // Roll for initiative on the teams. - TurnOrdered.rollInitiative(game.getTeamsVector(), + TurnOrdered.rollInitiative(game.getTeams(), game.getOptions().booleanOption(OptionsConstants.INIT_INITIATIVE_STREAK_COMPENSATION) && !game.shouldDeployThisRound()); } @@ -2969,8 +2969,7 @@ public boolean accept(Entity entity) { Hashtable allTeamTurns = new Hashtable<>(nTeams); Hashtable evenTrackers = new Hashtable<>(nTeams); int numTeamsMoving = 0; - for (Enumeration loop = game.getTeams(); loop.hasMoreElements(); ) { - final Team team = loop.nextElement(); + for (Team team : game.getTeams()) { allTeamTurns.put(team, team.determineTeamOrder(game)); // Track both the number of times we've checked the team for @@ -2985,7 +2984,7 @@ public boolean accept(Entity entity) { } // Now, generate the global order of all teams' turns. - TurnVectors team_order = TurnOrdered.generateTurnOrder(game.getTeamsVector(), game); + TurnVectors team_order = TurnOrdered.generateTurnOrder(game.getTeams(), game); // Now, we collect everything into a single vector. Vector turns = initGameTurnsWithStranded(team_order); @@ -3167,9 +3166,7 @@ private void writeInitiativeReport(boolean abbreviatedReport) { } } } else { - for (Enumeration i = game.getTeams(); i.hasMoreElements(); ) { - final Team team = i.nextElement(); - + for (Team team : game.getTeams()) { // Teams with no active players can be ignored if (team.isObserverTeam()) { continue; @@ -10966,11 +10963,7 @@ private void removeMinefield(Player player, Minefield mf) { * @param mf The Minefield to be revealed */ private void revealMinefield(Minefield mf) { - Enumeration teams = game.getTeams(); - while (teams.hasMoreElements()) { - Team team = teams.nextElement(); - revealMinefield(team, mf); - } + game.getTeams().forEach(team -> revealMinefield(team, mf)); } /** @@ -11012,12 +11005,10 @@ public void revealMinefield(Player player, Minefield mf) { * LOS. If so, then it reveals the mine */ private void checkForRevealMinefield(Minefield mf, Entity layer) { - Enumeration teams = game.getTeams(); // loop through each team and determine if they can see the mine, then // loop through players on team // and reveal the mine - while (teams.hasMoreElements()) { - Team team = teams.nextElement(); + for (Team team : game.getTeams()) { boolean canSee = false; // the players own team can always see the mine @@ -12665,9 +12656,7 @@ private void processDeployMinefields(Vector minefields) { int teamId = player.getTeam(); if (teamId != Player.TEAM_NONE) { - Enumeration teams = game.getTeams(); - while (teams.hasMoreElements()) { - Team team = teams.nextElement(); + for (Team team : game.getTeams()) { if (team.getId() == teamId) { Enumeration players = team.getPlayers(); while (players.hasMoreElements()) { @@ -34142,9 +34131,8 @@ private Vector resolveBlowingSandDamage() { int damage_bonus = Math.max(0, game.getPlanetaryConditions().getWindStrength() - PlanetaryConditions.WI_MOD_GALE); // cycle through each team and damage 1d6 airborne VTOL/WiGE - for (Enumeration loop = game.getTeams(); loop.hasMoreElements(); ) { - Team team = loop.nextElement(); - Vector airborne = team.getAirborneVTOL(); + for (Team team : game.getTeams()) { + Vector airborne = getAirborneVTOL(team); if (!airborne.isEmpty()) { // how many units are affected int unitsAffected = Math.min(Compute.d6(), airborne.size()); @@ -34166,6 +34154,21 @@ private Vector resolveBlowingSandDamage() { return vFullReport; } + /** + * cycle through entities on team and collect all the airborne VTOL/WIGE + * + * @return a vector of relevant entity ids + */ + public Vector getAirborneVTOL(Team team) { + // a vector of unit ids + Vector units = new Vector<>(); + for (Enumeration loop = team.getPlayers(); loop.hasMoreElements(); ) { + Player player = loop.nextElement(); + units.addAll(player.getAirborneVTOL()); + } + return units; + } + /** * let an entity lay a mine * diff --git a/megamek/src/megamek/server/commands/CheckBVTeamCommand.java b/megamek/src/megamek/server/commands/CheckBVTeamCommand.java index 45e32aeba26..0ddd03cd614 100644 --- a/megamek/src/megamek/server/commands/CheckBVTeamCommand.java +++ b/megamek/src/megamek/server/commands/CheckBVTeamCommand.java @@ -37,9 +37,7 @@ public void run(int connId, String[] args) { Player requestingPlayer = server.getGame().getPlayer(connId); server.sendServerChat(connId, "Remaining BV:"); - Enumeration teamEnum = server.getGame().getTeams(); - while (teamEnum.hasMoreElements()) { - Team team = teamEnum.nextElement(); + for (Team team : server.getGame().getTeams()) { int initialTeamBV = 0; int currentTeamBV = 0; Enumeration playersEnum = team.getPlayers(); From ddb1cf7a46bb8aa80ee23be2804ec81c654df260 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 8 Jan 2023 12:43:29 +0100 Subject: [PATCH 4/5] Aftermerge corrections --- megamek/src/megamek/client/ui/swing/MiniReportDisplay.java | 6 +++++- megamek/src/megamek/common/Game.java | 4 ---- megamek/src/megamek/common/Mech.java | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/megamek/src/megamek/client/ui/swing/MiniReportDisplay.java b/megamek/src/megamek/client/ui/swing/MiniReportDisplay.java index eeed62cf150..ee068e29656 100644 --- a/megamek/src/megamek/client/ui/swing/MiniReportDisplay.java +++ b/megamek/src/megamek/client/ui/swing/MiniReportDisplay.java @@ -34,7 +34,9 @@ import javax.swing.text.Document; import java.awt.*; import java.awt.event.*; +import java.util.Comparator; import java.util.Iterator; +import java.util.List; /** * Shows reports, with an Okay JButton @@ -192,7 +194,9 @@ private void updatePlayerChoice() { lastChoice = (lastChoice != null ? lastChoice : name); comboPlayer.removeAllItems(); comboPlayer.setEnabled(true); - for (Player player : currentClient.getGame().getPlayersVectorSorted()) { + List sortedPlayerList = currentClient.getGame().getPlayersList(); + sortedPlayerList.sort(Comparator.comparingInt(Player::getId)); + for (Player player : sortedPlayerList) { String playerDisplay = String.format("%-12s", player.getName()); comboPlayer.addItem(playerDisplay); } diff --git a/megamek/src/megamek/common/Game.java b/megamek/src/megamek/common/Game.java index 6c528ecee4e..52ed4638ffe 100644 --- a/megamek/src/megamek/common/Game.java +++ b/megamek/src/megamek/common/Game.java @@ -58,10 +58,6 @@ public class Game extends AbstractGame implements Serializable { */ public final Version version = MMConstants.VERSION; - private Vector players = new Vector<>(); - private Hashtable playerIds = new Hashtable<>(); - private Vector teams = new Vector<>(); - private GameOptions options = new GameOptions(); private Board board = new Board(); diff --git a/megamek/src/megamek/common/Mech.java b/megamek/src/megamek/common/Mech.java index c9cee154207..2b26ca2d838 100644 --- a/megamek/src/megamek/common/Mech.java +++ b/megamek/src/megamek/common/Mech.java @@ -6549,4 +6549,4 @@ public boolean isIndustrialMek() { public boolean getsAutoExternalSearchlight() { return true; } -} +} \ No newline at end of file From a799bb8729993315c62728ed852b4c6f94e4edf4 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 15 Jan 2023 10:09:41 +0100 Subject: [PATCH 5/5] PlayerListDialog: Aftermerge updates --- .../client/ui/swing/PlayerListDialog.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/megamek/src/megamek/client/ui/swing/PlayerListDialog.java b/megamek/src/megamek/client/ui/swing/PlayerListDialog.java index 2618f0d6e4a..d330aec500f 100644 --- a/megamek/src/megamek/client/ui/swing/PlayerListDialog.java +++ b/megamek/src/megamek/client/ui/swing/PlayerListDialog.java @@ -20,9 +20,6 @@ import megamek.common.IGame; import megamek.common.Player; import megamek.common.Team; -import megamek.common.event.GameListener; -import megamek.common.event.GameListenerAdapter; -import megamek.common.event.GamePhaseChangeEvent; import megamek.common.preference.IPreferenceChangeListener; import megamek.common.preference.PreferenceChangeEvent; @@ -69,8 +66,6 @@ public PlayerListDialog(JFrame parent, Client client, boolean modal) { this.client = client; this.modal = modal; - client.getGame().addGameListener(gameListener); - add(playerList, BorderLayout.CENTER); add(Box.createHorizontalStrut(20), BorderLayout.LINE_START); add(Box.createHorizontalStrut(20), BorderLayout.LINE_END); @@ -204,18 +199,6 @@ public void actionPerformed(ActionEvent ae) { } } - private GameListener gameListener = new GameListenerAdapter() { - @Override - public void gamePhaseChange(GamePhaseChangeEvent e) { - switch (e.getOldPhase()) { - case VICTORY: - break; - default: - break; - } - } - }; - @Override protected void processWindowEvent(WindowEvent e) { super.processWindowEvent(e);