📄 loseffects.java
字号:
/* * MegaMek - Copyright (C) 2002-2003 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. *//* * LosEffects.java * * Created on October 14, 2002, 11:19 PM */package megamek.common;import java.util.ArrayList;/** * Keeps track of the cumulative effects of intervening terrain on LOS * * @author Ben */public class LosEffects { public static class AttackInfo { public boolean attUnderWater; public boolean attInWater; public boolean attOnLand; public boolean targetUnderWater; public boolean targetInWater; public boolean targetOnLand; public boolean underWaterCombat; public boolean targetEntity = true; public boolean targetInfantry; public boolean attOffBoard; public Coords attackPos; public Coords targetPos; public int attackAbsHeight; public int targetAbsHeight; public int attackHeight; public int targetHeight; int minimumWaterDepth = -1; } // MAXTECH BMR public static final int COVER_NONE = 0; //no cover (none) public static final int COVER_LOWLEFT = 0x1; //25% cover (partial) public static final int COVER_LOWRIGHT = 0x2; //25% cover (partial) public static final int COVER_LEFT = 0x4; //vertical cover (blocked) public static final int COVER_RIGHT = 0x8; //vertical cover (blocked) public static final int COVER_HORIZONTAL = 0x3; //50% cover (partial) public static final int COVER_UPPER = 0xC; //blocked (blocked) - in case of future rule where only legs are exposed public static final int COVER_FULL = 0xF; //blocked (blocked) public static final int COVER_75LEFT = 0x7; //75% cover (blocked) public static final int COVER_75RIGHT = 0xB; //75% cover (blocked) boolean blocked = false; boolean infProtected = false; boolean hasLoS = true; int lightWoods = 0; int heavyWoods = 0; int ultraWoods = 0; int lightSmoke = 0; int heavySmoke = 0; // heavySmoke is also standard for normal L2 smoke int targetCover = COVER_NONE; // that means partial cover int attackerCover = COVER_NONE; // ditto Building thruBldg = null; int minimumWaterDepth = -1; /** Creates a new instance of LosEffects */ public LosEffects() { } public int getMinimumWaterDepth() { return minimumWaterDepth; } public void setMinimumWaterDepth(int inVal) { minimumWaterDepth = inVal; } public void add(LosEffects other) { this.blocked |= other.blocked; this.infProtected |= other.infProtected; this.lightWoods += other.lightWoods; this.heavyWoods += other.heavyWoods; this.ultraWoods += other.ultraWoods; this.lightSmoke += other.lightSmoke; this.heavySmoke += other.heavySmoke; this.targetCover |= other.targetCover; this.attackerCover |= other.attackerCover; if ( null != this.thruBldg && !this.thruBldg.equals(other.thruBldg) ) { this.thruBldg = null; } } public int getLightWoods() { return lightWoods; } public int getHeavyWoods() { return heavyWoods; } public int getUltraWoods() { return ultraWoods; } public int getLightSmoke() { return lightSmoke; } public int getHeavySmoke() { return heavySmoke; } public boolean isBlocked() { return blocked; } /** Getter for property targetCover. * @return Value of property targetCover. */ public boolean isTargetCover() { return targetCover >= COVER_HORIZONTAL; } public int getTargetCover() { return targetCover; } /** Setter for property targetCover. * @param targetCover New value of property targetCover. */ public void setTargetCover(int targetCover) { this.targetCover = targetCover; } /** Getter for property attackerCover. * @return Value of property attackerCover. */ public boolean isAttackerCover() { return attackerCover >= COVER_HORIZONTAL; } public int getAttackerCover() { return attackerCover; } /** Setter for property attackerCover. * @param attackerCover New value of property attackerCover. */ public void setAttackerCover(int attackerCover) { this.attackerCover = attackerCover; } /** Getter for property thruBldg. * @return Value of property thruBldg. */ public Building getThruBldg() { return thruBldg; } /** Setter for property thruBldg. * @param thruBldg New value of property thruBldg. */ public void setThruBldg(Building thruBldg) { this.thruBldg = thruBldg; } /** * LOS check from ae to te. */ public boolean canSee() { return hasLoS;//!blocked && (lightWoods + lightSmoke) + ((heavyWoods + heavySmoke) * 2) < 3; } /** * Returns a LosEffects object representing the LOS effects of interveing * terrain between the attacker and target. * * Checks to see if the attacker and target are at an angle where the LOS * line will pass between two hexes. If so, calls losDivided, otherwise * calls losStraight. */ public static LosEffects calculateLos(IGame game, int attackerId, Targetable target) { final Entity ae = game.getEntity(attackerId); // LOS fails if one of the entities is not deployed. if (null == ae.getPosition() || null == target.getPosition() || ae.isOffBoard()) { LosEffects los = new LosEffects(); los.blocked = true; // TODO: come up with a better "impossible" los.hasLoS = false; return los; } final AttackInfo ai = new AttackInfo(); ai.attackPos = ae.getPosition(); ai.targetPos = target.getPosition(); ai.targetEntity = target.getTargetType() == Targetable.TYPE_ENTITY; ai.targetInfantry = target instanceof Infantry; ai.attackHeight = ae.getHeight(); ai.targetHeight = target.getHeight(); IHex attHex = game.getBoard().getHex(ae.getPosition()); IHex targetHex = game.getBoard().getHex(target.getPosition()); int attEl = ae.absHeight() + attHex.getElevation(); int targEl; if (target.getTargetType() == Targetable.TYPE_ENTITY || target.getTargetType() == Targetable.TYPE_FUEL_TANK || target.getTargetType() == Targetable.TYPE_FUEL_TANK_IGNITE || target.getTargetType() == Targetable.TYPE_BUILDING || target.getTargetType() == Targetable.TYPE_BLDG_IGNITE) { targEl = target.absHeight() + targetHex.getElevation(); } else { targEl = game.getBoard().getHex(target.getPosition()).surface(); } ai.attackAbsHeight = attEl; ai.targetAbsHeight = targEl; boolean attOffBoard = ae.isOffBoard(); boolean attUnderWater; boolean attInWater; boolean attOnLand; if (attOffBoard) { attUnderWater = true; attInWater = false; attOnLand = true; } else { attUnderWater = attHex.containsTerrain(Terrains.WATER) && attHex.depth() > 0 && attEl < attHex.surface(); attInWater = attHex.containsTerrain(Terrains.WATER) && attHex.depth() > 0 && attEl == attHex.surface(); attOnLand = !(attUnderWater || attInWater); } boolean targetOffBoard = !game.getBoard().contains(target.getPosition()); boolean targetUnderWater; boolean targetInWater; boolean targetOnLand; if (targetOffBoard) { targetUnderWater = true; targetInWater = false; targetOnLand = true; } else { targetUnderWater = targetHex.containsTerrain(Terrains.WATER) && targetHex.depth() > 0 && targEl < targetHex.surface(); targetInWater = targetHex.containsTerrain(Terrains.WATER) && targetHex.depth() > 0 && targEl == targetHex.surface(); targetOnLand = !(targetUnderWater || targetInWater); } boolean underWaterCombat = targetUnderWater || attUnderWater; ai.attUnderWater = attUnderWater; ai.attInWater = attInWater; ai.attOnLand = attOnLand; ai.targetUnderWater = targetUnderWater; ai.targetInWater = targetInWater; ai.targetOnLand = targetOnLand; ai.underWaterCombat = underWaterCombat; ai.attOffBoard = attOffBoard; // Handle minimum water depth. // Applies to Torpedos. if(ai.attOnLand || ai.targetOnLand) ai.minimumWaterDepth = 0; else if (ai.attInWater || ai.targetInWater) ai.minimumWaterDepth = 1; else if (ai.attUnderWater || ai.targetUnderWater) ai.minimumWaterDepth = Math.min(attHex.terrainLevel(Terrains.WATER), targetHex.terrainLevel(Terrains.WATER)); LosEffects finalLoS = calculateLos(game, ai); finalLoS.setMinimumWaterDepth(ai.minimumWaterDepth); finalLoS.hasLoS = !finalLoS.blocked && (finalLoS.lightWoods + finalLoS.lightSmoke) + ((finalLoS.heavyWoods + finalLoS.heavySmoke) * 2) + (finalLoS.ultraWoods * 3) < 3; /* * Torren (MekWars) * If LOS is blocked * And the Attacker has BAP that is working * i.e. not effect by ECM or destoyed/damaged/breached/Shutdown * And the target is a Non-Infantry Unit * And the target is not under water * And the target is in range of the Attackers BAP * Then remove the Block. * * Note code was done with 2 version of BMR and maxtech rules from various user sources * anything that is wrong please let me know for feature refence. * * This will not detect hidden units(not coded yet anyways) * This was designed for double blind. * * */ final int probeRange = ae.getBAPRange(); if ( !finalLoS.canSee()&& ae.hasBAP() && ai.targetEntity && !(ai.targetInfantry && !(target instanceof BattleArmor) && probeRange!=8) && !ai.underWaterCombat && ae.getPosition().distance(ai.targetPos) <= probeRange && !Compute.isAffectedByECM(ae, ae.getPosition(), ai.targetPos) && !Compute.isAffectedByAngelECM(ae, ae.getPosition(), ai.targetPos)) { Entity te = (Entity)target; if(probeRange==8 || !(te.isStealthActive())) finalLoS.hasLoS = true; } return finalLoS; } public static LosEffects calculateLos(IGame game, AttackInfo ai) { if (ai.attOffBoard) { LosEffects los = new LosEffects(); los.blocked = true; los.hasLoS = false; return los; } if (ai.attOnLand && ai.targetUnderWater || ai.attUnderWater && ai.targetOnLand) { LosEffects los = new LosEffects(); los.blocked = true; los.hasLoS = false; return los; } double degree = ai.attackPos.degree(ai.targetPos); if (degree % 60 == 30) { return LosEffects.losDivided(game, ai); } return LosEffects.losStraight(game, ai); } /** * Returns ToHitData indicating the modifiers to fire for the specified * LOS effects data. */ public ToHitData losModifiers(IGame game) { return losModifiers(game, 0); } public ToHitData losModifiers(IGame game, int eistatus) { ToHitData modifiers = new ToHitData(); if (blocked) { return new ToHitData(ToHitData.IMPOSSIBLE, "LOS blocked by terrain."); } if (infProtected) { return new ToHitData(ToHitData.IMPOSSIBLE, "Infantry protected by building."); } if (ultraWoods >= 1 || lightWoods + (heavyWoods * 2) > 2) { return new ToHitData(ToHitData.IMPOSSIBLE, "LOS blocked by woods."); } if (lightSmoke + (heavySmoke * 2) > 2) { return new ToHitData(ToHitData.IMPOSSIBLE, "LOS blocked by smoke."); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -