/* * MissingEquipmentPart.java * * Copyright (c) 2009 Jay Lawson <jaylawson39 at yahoo.com>. All rights reserved. * * This file is part of MekHQ. * * MekHQ 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. * * MekHQ 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 MekHQ. If not, see <http://www.gnu.org/licenses/>. */ package mekhq.campaign.parts.equipment; import java.io.PrintWriter; import megamek.common.CriticalSlot; import megamek.common.Entity; import megamek.common.EquipmentType; import megamek.common.MiscType; import megamek.common.Mounted; import megamek.common.WeaponType; import mekhq.MekHqXmlUtil; import mekhq.campaign.Campaign; import mekhq.campaign.parts.MissingPart; import mekhq.campaign.parts.Part; import mekhq.campaign.unit.Unit; import mekhq.campaign.universe.Era; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * * @author Jay Lawson <jaylawson39 at yahoo.com> */ public class MissingEquipmentPart extends MissingPart { private static final long serialVersionUID = 2892728320891712304L; //crap equipmenttype is not serialized! protected transient EquipmentType type; protected String typeName; protected int equipmentNum = -1; protected double equipTonnage; public EquipmentType getType() { return type; } public int getEquipmentNum() { return equipmentNum; } public void setEquipmentNum(int num) { equipmentNum = num; } public MissingEquipmentPart() { this(0, null, -1, null, 0, false); } public MissingEquipmentPart(int tonnage, EquipmentType et, int equipNum, Campaign c, double eTonnage) { this(tonnage, et, equipNum, c, eTonnage, false); } public MissingEquipmentPart(int tonnage, EquipmentType et, int equipNum, Campaign c, double eTonnage, boolean omniPodded) { // TODO Memorize all entity attributes needed to calculate cost // As it is a part bought with one entity can be used on another entity // on which it would have a different price (only tonnage is taken into // account for compatibility) super(tonnage, c); this.type =et; if(null != type) { this.name = type.getName(); this.typeName = type.getInternalName(); } this.equipmentNum = equipNum; this.equipTonnage = eTonnage; this.omniPodded = omniPodded; } @Override public int getBaseTime() { return isOmniPodded()? 30 : 120; } @Override public int getDifficulty() { return 0; } /** * Restores the equipment from the name */ public void restore() { if (typeName == null) { typeName = type.getName(); } else { type = EquipmentType.get(typeName); } if (type == null) { System.err .println("Mounted.restore: could not restore equipment type \"" + name + "\""); } } @Override public double getTonnage() { return equipTonnage; } @Override public void writeToXml(PrintWriter pw1, int indent) { writeToXmlBegin(pw1, indent); pw1.println(MekHqXmlUtil.indentStr(indent+1) +"<typeName>" +MekHqXmlUtil.escape(typeName) +"</typeName>"); pw1.println(MekHqXmlUtil.indentStr(indent+1) +"<equipmentNum>" +equipmentNum +"</equipmentNum>"); pw1.println(MekHqXmlUtil.indentStr(indent+1) +"<equipTonnage>" +equipTonnage +"</equipTonnage>"); writeToXmlEnd(pw1, indent); } @Override protected void loadFieldsFromXmlNode(Node wn) { NodeList nl = wn.getChildNodes(); for (int x=0; x<nl.getLength(); x++) { Node wn2 = nl.item(x); if (wn2.getNodeName().equalsIgnoreCase("equipmentNum")) { equipmentNum = Integer.parseInt(wn2.getTextContent()); } else if (wn2.getNodeName().equalsIgnoreCase("typeName")) { typeName = wn2.getTextContent(); } else if (wn2.getNodeName().equalsIgnoreCase("equipTonnage")) { equipTonnage = Double.parseDouble(wn2.getTextContent()); } } restore(); } @Override public int getAvailability(int era) { return type.getAvailability(Era.convertEra(era)); } @Override public int getIntroDate() { return getType().getIntroductionDate(); } @Override public int getExtinctDate() { return getType().getExtinctionDate(); } @Override public int getReIntroDate() { return getType().getReintruductionDate(); } @Override public int getTechRating() { return type.getTechRating(); } @Override public void fix() { Part replacement = findReplacement(false); if(null != replacement) { Part actualReplacement = replacement.clone(); unit.addPart(actualReplacement); campaign.addPart(actualReplacement, 0); replacement.decrementQuantity(); ((EquipmentPart)actualReplacement).setEquipmentNum(equipmentNum); remove(false); //assign the replacement part to the unit actualReplacement.updateConditionFromPart(); } } @Override public boolean isAcceptableReplacement(Part part, boolean refit) { //According to official answer, if sticker prices are different then //they are not acceptable substitutes, so we need to check for that as //well //http://bg.battletech.com/forums/strategic-operations/(answered)-can-a-lance-for-a-35-ton-mech-be-used-on-a-40-ton-mech-and-so-on/ Part newPart = getNewPart(); newPart.setUnit(unit); if(part instanceof EquipmentPart) { EquipmentPart eqpart = (EquipmentPart)part; EquipmentType et = eqpart.getType(); return type.equals(et) && getTonnage() == part.getTonnage() && part.getStickerPrice() == newPart.getStickerPrice(); } return false; } @Override public String checkFixable() { // The part is only fixable if the location is not destroyed. // be sure to check location and second location if(null != unit) { Mounted m = unit.getEntity().getEquipment(equipmentNum); if(null != m) { int loc = m.getLocation(); if(loc == -1) { } if (unit.isLocationBreached(loc)) { return unit.getEntity().getLocationName(loc) + " is breached."; } if (unit.isLocationDestroyed(loc)) { return unit.getEntity().getLocationName(loc) + " is destroyed."; } loc = m.getSecondLocation(); if(loc != Entity.LOC_NONE) { if (unit.isLocationBreached(loc)) { return unit.getEntity().getLocationName(loc) + " is breached."; } if (unit.isLocationDestroyed(loc)) { return unit.getEntity().getLocationName(loc) + " is destroyed."; } } } } return null; } @Override public boolean onBadHipOrShoulder() { if(null != unit) { for(int loc = 0; loc < unit.getEntity().locations(); loc++) { for (int i = 0; i < unit.getEntity().getNumberOfCriticals(loc); i++) { CriticalSlot slot = unit.getEntity().getCritical(loc, i); // ignore empty & system slots if ((slot == null) || (slot.getType() != CriticalSlot.TYPE_EQUIPMENT)) { continue; } Mounted equip = unit.getEntity().getEquipment(equipmentNum); Mounted m1 = slot.getMount(); Mounted m2 = slot.getMount2(); if (m1 == null && m2 == null) { continue; } if ((equip.equals(m1)) || (equip.equals(m2))) { if (unit.hasBadHipOrShoulder(loc)) { return true; } } } } } return false; } @Override public void setUnit(Unit u) { super.setUnit(u); if(null != unit) { equipTonnage = type.getTonnage(unit.getEntity()); } } @Override public Part getNewPart() { EquipmentPart epart = new EquipmentPart(getUnitTonnage(), type, -1, omniPodded, campaign); epart.setEquipTonnage(equipTonnage); return epart; } /* private boolean hasReallyCheckedToday() { return checkedToday; } @Override public boolean hasCheckedToday() { //if this unit has been checked for any other equipment of this same type //then return false, regardless of whether this one has been checked if(null != unit) { for(Part part : unit.getParts()) { if(part.getId() == getId()) { continue; } if(part instanceof MissingEquipmentPart && ((MissingEquipmentPart)part).getType().equals(type) && ((MissingEquipmentPart)part).hasReallyCheckedToday()) { return true; } } } return super.hasCheckedToday(); } */ public int getLocation() { if(null != unit) { Mounted mounted = unit.getEntity().getEquipment(equipmentNum); if(null != mounted) { return mounted.getLocation(); } } return -1; } public boolean isRearFacing() { if(null != unit) { Mounted mounted = unit.getEntity().getEquipment(equipmentNum); if(null != mounted) { return mounted.isRearMounted(); } } return false; } @Override public void updateConditionFromPart() { if(null != unit) { Mounted mounted = unit.getEntity().getEquipment(equipmentNum); if(null != mounted) { mounted.setHit(true); mounted.setDestroyed(true); mounted.setRepairable(false); unit.destroySystem(CriticalSlot.TYPE_EQUIPMENT, unit.getEntity().getEquipmentNum(mounted)); } } } @Override public boolean isOmniPoddable() { if (type.isOmniFixedOnly()) { return false; } if (type instanceof MiscType) { return type.hasFlag(MiscType.F_MECH_EQUIPMENT) || type.hasFlag(MiscType.F_TANK_EQUIPMENT) || type.hasFlag(MiscType.F_AERO_EQUIPMENT); } else if (type instanceof WeaponType) { return (type.hasFlag(WeaponType.F_MECH_WEAPON) || type.hasFlag(WeaponType.F_TANK_WEAPON) || type.hasFlag(WeaponType.F_AERO_WEAPON)) && !((WeaponType)type).isCapital(); } return true; } @Override public String getLocationName() { if(null != unit) { Mounted mounted = unit.getEntity().getEquipment(equipmentNum); if(null != mounted && mounted.getLocation() != -1) { return unit.getEntity().getLocationName(mounted.getLocation()); } } return null; } @Override public boolean isInLocation(String loc) { if(null == unit || null == unit.getEntity() || null == unit.getEntity().getEquipment(equipmentNum)) { return false; } Mounted mounted = unit.getEntity().getEquipment(equipmentNum); if(null == mounted) { return false; } int location = unit.getEntity().getLocationFromAbbr(loc); for (int i = 0; i < unit.getEntity().getNumberOfCriticals(location); i++) { CriticalSlot slot = unit.getEntity().getCritical(location, i); // ignore empty & non-hittable slots if ((slot == null) || !slot.isEverHittable() || slot.getType()!=CriticalSlot.TYPE_EQUIPMENT || null == slot.getMount()) { continue; } if(unit.getEntity().getEquipmentNum(slot.getMount()) == equipmentNum) { return true; } } //if we are still here, lets just double check by the mounted's location and secondary location if(mounted.getLocation() == location) { return true; } if(mounted.getSecondLocation() == location) { return true; } return false; } }