📄 weaponattackaction.java
字号:
/* * MegaMek - Copyright (C) 2000,2001,2002,2003,2004 Ben Mazur (bmazur@sev.org) * * This program 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 2 of the License, or (at your option) * any later version. * * This program 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. */package megamek.common.actions;import java.util.Enumeration;import java.util.ArrayList;import megamek.common.AmmoType;import megamek.common.BattleArmor;import megamek.common.Compute;import megamek.common.CriticalSlot;import megamek.common.Entity;import megamek.common.EquipmentType;import megamek.common.GunEmplacement;import megamek.common.HexTarget;import megamek.common.IAimingModes;import megamek.common.IEntityMovementMode;import megamek.common.IEntityMovementType;import megamek.common.IGame;import megamek.common.IHex;import megamek.common.ILocationExposureStatus;import megamek.common.INarcPod;import megamek.common.Infantry;import megamek.common.LosEffects;import megamek.common.Mech;import megamek.common.MechWarrior;import megamek.common.MinefieldTarget;import megamek.common.Mounted;import megamek.common.Protomech;import megamek.common.RangeType;import megamek.common.Tank;import megamek.common.Targetable;import megamek.common.Terrains;import megamek.common.ToHitData;import megamek.common.WeaponType;import megamek.common.VTOL;import megamek.common.MiscType;/** * Represents intention to fire a weapon at the target. */public class WeaponAttackAction extends AbstractAttackAction { private int weaponId; private int ammoId = -1; private int aimedLocation = Mech.LOC_NONE; private int aimMode = IAimingModes.AIM_MODE_NONE; private int otherAttackInfo = -1; // private boolean nemesisConfused; private boolean swarmingMissiles; private int oldTargetId = -1; // equipment that affects this attack (AMS, ECM?, etc) // only used server-side private transient ArrayList vCounterEquipment; // default to attacking an entity public WeaponAttackAction(int entityId, int targetId, int weaponId) { super(entityId, targetId); this.weaponId = weaponId; } public WeaponAttackAction(int entityId, int targetType, int targetId, int weaponId) { super(entityId, targetType, targetId); this.weaponId = weaponId; } public int getWeaponId() { return weaponId; } public int getAmmoId() { return ammoId; } public int getAimedLocation() { return aimedLocation; } public int getAimingMode() { return aimMode; } public ArrayList getCounterEquipment() { return vCounterEquipment; } public void setWeaponId(int weaponId) { this.weaponId = weaponId; } public void setAmmoId(int ammoId) { this.ammoId = ammoId; } public void setAimedLocation(int aimedLocation) { this.aimedLocation = aimedLocation; } public void setAimingMode(int aimMode) { this.aimMode = aimMode; } public void addCounterEquipment(Mounted m) { if (vCounterEquipment == null) { vCounterEquipment = new ArrayList(); } vCounterEquipment.add(m); } public void setOtherAttackInfo(int newInfo) { otherAttackInfo = newInfo; } public int getOtherAttackInfo() { return otherAttackInfo; } public ToHitData toHit(IGame game) { return WeaponAttackAction.toHit(game, getEntityId(), game.getTarget(getTargetType(), getTargetId()), getWeaponId(), getAimedLocation(), getAimingMode(), nemesisConfused, swarmingMissiles, game.getEntity(oldTargetId)); } public static ToHitData toHit(IGame game, int attackerId, Targetable target, int weaponId) { return WeaponAttackAction.toHit(game, attackerId, target, weaponId, Mech.LOC_NONE, IAimingModes.AIM_MODE_NONE, false, false, null); } public static ToHitData toHit(IGame game, int attackerId, Targetable target, int weaponId, int aimingAt, int aimingMode) { return toHit(game, attackerId, target, weaponId, aimingAt, aimingMode, false, false, null); } /** * To-hit number for attacker firing a weapon at the target. */ private static ToHitData toHit(IGame game, int attackerId, Targetable target, int weaponId, int aimingAt, int aimingMode, boolean isNemesisConfused, boolean exchangeSwarmTarget, Entity oldTarget) { final Entity ae = game.getEntity(attackerId); final Mounted weapon = ae.getEquipment(weaponId); final WeaponType wtype = (WeaponType)weapon.getType(); if (exchangeSwarmTarget) { // Quick check, is the new target out of range for the weapon? if(RangeType.rangeBracket(ae.getPosition().distance(target.getPosition()), wtype.getRanges(), game.getOptions().booleanOption("maxtech_range")) == RangeType.RANGE_OUT) { return new ToHitData(ToHitData.AUTOMATIC_FAIL, "swarm target out of range"); } // this is a swarm attack against a new target // first, exchange old and new targets to get all mods // as if firing against old target. // at the end of this function, we remove target terrain // and movement mods, and add those for the new target Targetable tempTarget = target; target = oldTarget; oldTarget = (Entity)tempTarget; } Entity te = null; if (target.getTargetType() == Targetable.TYPE_ENTITY) { te = (Entity) target; } boolean isAttackerInfantry = ae instanceof Infantry; boolean isWeaponInfantry = wtype.hasFlag(WeaponType.F_INFANTRY); // 2003-01-02 BattleArmor MG and Small Lasers have unlimited ammo. // 2002-09-16 Infantry weapons have unlimited ammo. final boolean usesAmmo = wtype.getAmmoType() != AmmoType.T_NA && wtype.getAmmoType() != AmmoType.T_BA_MG && wtype.getAmmoType() != AmmoType.T_BA_SMALL_LASER && !isWeaponInfantry; final Mounted ammo = usesAmmo ? weapon.getLinked() : null; final AmmoType atype = ammo == null ? null : (AmmoType)ammo.getType(); final boolean targetInBuilding = Compute.isInBuilding( game, te ); boolean isIndirect = wtype.hasModes() && weapon.curMode().equals("Indirect"); boolean isInferno = atype != null && (atype.getAmmoType() == AmmoType.T_SRM || atype.getAmmoType() == AmmoType.T_BA_INFERNO) && atype.getMunitionType() == AmmoType.M_INFERNO || isWeaponInfantry && wtype.hasFlag(WeaponType.F_INFERNO); boolean isArtilleryDirect= wtype.hasFlag(WeaponType.F_ARTILLERY) && game.getPhase() == IGame.PHASE_FIRING; boolean isArtilleryIndirect = wtype.hasFlag(WeaponType.F_ARTILLERY) && (game.getPhase() == IGame.PHASE_TARGETING || game.getPhase() == IGame.PHASE_OFFBOARD);//hack, otherwise when actually resolves shot labeled impossible. boolean isArtilleryFLAK = isArtilleryDirect && target.getTargetType() == Targetable.TYPE_ENTITY && te.getMovementMode() == IEntityMovementMode.VTOL && te.getElevation() > 0 && (usesAmmo && atype.getMunitionType() == AmmoType.M_STANDARD); boolean isHaywireINarced = ae.isINarcedWith(INarcPod.HAYWIRE); boolean isINarcGuided = false; boolean isECMAffected = Compute.isAffectedByECM(ae, ae.getPosition(), target.getPosition()); boolean isTAG = wtype.hasFlag(WeaponType.F_TAG); boolean isHoming = false; if (te != null) { if (te.isINarcedBy(ae.getOwner().getTeam()) && atype != null && (atype.getAmmoType() == AmmoType.T_LRM || atype.getAmmoType() == AmmoType.T_SRM) && atype.getMunitionType() == AmmoType.M_NARC_CAPABLE && (wtype.getAmmoType() == AmmoType.T_LRM || wtype.getAmmoType() == AmmoType.T_SRM)) { isINarcGuided = true; } } int toSubtract = 0; final int ttype = target.getTargetType(); ToHitData toHit = null; String reason=null; reason = toHitIsImpossible (game, ae, target, weapon, atype, wtype, ttype, exchangeSwarmTarget, usesAmmo, te, isTAG, isInferno, isAttackerInfantry, isIndirect, attackerId, weaponId, isArtilleryIndirect, ammo, isArtilleryFLAK, targetInBuilding, isArtilleryDirect); if (reason!=null) { return new ToHitData(ToHitData.IMPOSSIBLE, reason); } long munition = AmmoType.M_STANDARD; if (atype != null) { munition = atype.getMunitionType(); } if (munition == AmmoType.M_HOMING) { //target type checked later because its different for direct/indirect (BMRr p77 on board arrow IV) isHoming = true; } int targEl; if (te == null) { targEl = game.getBoard().getHex(target.getPosition()).floor(); } else { targEl = te.absHeight(); } //TODO: mech making DFA could be higher if DFA target hex is higher // BMRr pg. 43, "attacking unit is considered to be in the air // above the hex, standing on an elevation 1 level higher than // the target hex or the elevation of the hex the attacker is // in, whichever is higher." // if we're doing indirect fire, find a spotter Entity spotter = null; if (isIndirect) { spotter = Compute.findSpotter(game, ae, target); } // EI system // 0 if no EI (or switched off) // 1 if no intervening light woods // 2 if intervening light woods (because target in woods + intervening woods is only +1 total) int eistatus=0; // check LOS (indirect LOS is from the spotter) LosEffects los; ToHitData losMods; if (!isIndirect) { los = LosEffects.calculateLos(game, attackerId, target); if(ae.hasActiveEiCockpit()) { if(los.getLightWoods() > 0) eistatus = 2; else eistatus = 1; } losMods = los.losModifiers(game, eistatus); if ((atype != null) && ((atype.getAmmoType() == AmmoType.T_LRM_TORPEDO) || (atype.getAmmoType() == AmmoType.T_SRM_TORPEDO)) && (los.getMinimumWaterDepth() < 1)) { return new ToHitData(ToHitData.IMPOSSIBLE, "Torpedos must follow water their entire LOS"); } } else { los = LosEffects.calculateLos(game, spotter.getId(), target); // do not count attacker partial cover in indirect fire los.setAttackerCover(LosEffects.COVER_NONE); if(spotter.hasActiveEiCockpit()) { if(los.getLightWoods() > 0) eistatus = 2; else eistatus = 1; } losMods = los.losModifiers(game); } // Leg attacks, Swarm attacks, and // Mine Launchers don't use gunnery. if ( Infantry.LEG_ATTACK.equals( wtype.getInternalName() ) ) { toHit = Compute.getLegAttackBaseToHit( ae, te ); // If the attacker has Assault claws, give a -1 modifier. // We can stop looking when we find our first match. for (Mounted mount : ae.getMisc()) { EquipmentType equip = mount.getType(); if ( BattleArmor.ASSAULT_CLAW.equals (equip.getInternalName()) ) { toHit.addModifier( -1, "attacker has assault claws" ); break; } } } else if ( Infantry.SWARM_MEK.equals( wtype.getInternalName() ) ) { toHit = Compute.getSwarmMekBaseToHit( ae, te ); // If the attacker has Assault claws, give a -1 modifier. // We can stop looking when we find our first match. for (Mounted mount : ae.getMisc()) { EquipmentType equip = mount.getType(); if ( BattleArmor.ASSAULT_CLAW.equals (equip.getInternalName()) ) { toHit.addModifier( -1, "attacker has assault claws" ); break; } } } else if ( Infantry.STOP_SWARM.equals( wtype.getInternalName() ) ) { // Can't stop if we're not swarming, otherwise automatic. return new ToHitData( ToHitData.AUTOMATIC_SUCCESS, "End swarm attack." ); } else if ( BattleArmor.MINE_LAUNCHER.equals(wtype.getInternalName()) ) { // Mine launchers can not hit infantry. toHit = new ToHitData(8, "magnetic mine attack"); } // Swarming infantry always hit their target, but
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -