/* * 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/>. * * @author: Dylan Myers <ralgith@gmail.com> */ package mekhq.campaign.personnel; import java.io.PrintWriter; import java.util.Collection; import java.util.Objects; import java.util.UUID; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; import org.joda.time.DateTime; import org.w3c.dom.Node; import mekhq.MekHQ; import mekhq.Utilities; import mekhq.adapter.DateAdapter; import mekhq.campaign.ExtraData; import mekhq.campaign.mod.am.InjuryTypes; // Injury class based on Jayof9s' <jayof9s@gmail.com> Advanced Medical documents @XmlRootElement(name="injury") @XmlAccessorType(XmlAccessType.FIELD) public class Injury { public static final int VERSION = 1; // Marshaller / unmarshaller instances private static Marshaller marshaller; private static Unmarshaller unmarshaller; static { try { JAXBContext context = JAXBContext.newInstance(Injury.class, BodyLocation.class, InjuryType.class); marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE); //marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); unmarshaller = context.createUnmarshaller(); // For debugging only! // unmarshaller.setEventHandler(new javax.xml.bind.helpers.DefaultValidationEventHandler()); } catch(JAXBException e) { MekHQ.logError(e); } } /** * Load from campaign file XML * <p> * Also used by the personnel exporter */ public static Injury generateInstanceFromXML(Node wn) { try { return unmarshaller.unmarshal(wn, Injury.class).getValue(); } catch (Exception ex) { MekHQ.logError(ex); } return null; } private String fluff; private int days; private int originalDays; @XmlJavaTypeAdapter(DateAdapter.class) private DateTime start; /** 0 = past injury, for scars, 1 = default, max depends on type */ private int hits; private BodyLocation location; private InjuryType type; private boolean permanent; /** Flag to indicate someone capable successfully treated this injury. */ private boolean workedOn; private boolean extended; private Hiding hidingState = Hiding.DEFAULT; @XmlElement(name="InjuryUUID") private UUID id; /** Generic extra data, for use with plugins and mods */ private ExtraData extraData = new ExtraData(); @XmlAttribute(name="v") private int version; // Base constructor, in reality should never be used public Injury() { this(0, "", BodyLocation.GENERIC, InjuryType.BAD_HEALTH, 1, false, false); } // Normal constructor for a new injury that has not been treated by a doctor & does not have extended time public Injury(int time, String text, BodyLocation loc, InjuryType type, int num, boolean perm) { this(time, text, loc, type, num, perm, false); } // Constructor if this injury has been treated by a doctor, but without extended time public Injury(int time, String text, BodyLocation loc, InjuryType type, int num, boolean perm, boolean workedOn) { this(time, text, loc, type, num, perm, workedOn, false); } // Constructor for when this injury has extended time, full options includng worked on by a doctor public Injury(int time, String text, BodyLocation loc, InjuryType type, int num, boolean perm, boolean workedOn, boolean extended) { setTime(time); setOriginalTime(time); setFluff(text); setLocation(loc); setType(type); setHits(num); setPermanent(perm); setWorkedOn(workedOn); setExtended(extended); id = UUID.randomUUID(); } // UUID Control Methods public UUID getUUID() { return id; } public void setUUID(UUID uuid) { id = uuid; } // End UUID Control Methods // Time Control Methods public DateTime getStart() { return start; } public void setStart(DateTime start) { this.start = Objects.requireNonNull(start); } public int getTime() { return days; } public void setTime(int time) { days = time; } public int getOriginalTime() { return originalDays; } public void setOriginalTime(int time) { originalDays = time; } // End Time Control Methods // Details Methods (Fluff, Location on Body, how many hits did it take, etc...) public String getFluff() { return fluff; } public void setFluff(String text) { fluff = text; } public BodyLocation getLocation() { return location; } public void setLocation(BodyLocation loc) { location = loc; } public int getHits() { return hits; } public void setHits(int num) { final int minSeverity = isPermanent() ? 1 : 0; final int maxSeverity = type.getMaxSeverity(); if(num < minSeverity) { num = minSeverity; } else if(num > maxSeverity) { num = maxSeverity; } hits = num; } public boolean isPermanent() { return permanent || type.isPermanent(); } public void setPermanent(boolean perm) { permanent = perm; } public boolean getExtended() { return extended; } public void setExtended(boolean ext) { extended = ext; } public boolean isWorkedOn() { return workedOn; } public void setWorkedOn(boolean wo) { workedOn = wo; } public InjuryType getType() { return type; } public void setType(InjuryType type) { this.type = Objects.requireNonNull(type); } public InjuryLevel getLevel() { return type.getLevel(this); } public Collection<Modifier> getModifiers() { return type.getModifiers(this); } public ExtraData getExtraData() { return extraData; } public void setVersion(int version) { this.version = version; } public boolean isHidden() { return (hidingState != Hiding.NO) && ((hidingState == Hiding.YES) || type.isHidden(this)); } public void setHidingState(Hiding hidingState) { this.hidingState = Objects.requireNonNull(hidingState); } // End Details Methods // Returns the full long name of this injury including location and type as applicable public String getName() { return type.getName(location, hits); } // Return the location name for the injury by passing location to the static overload public String getLocationName() { return Utilities.capitalize(location.readableName); } public String getTypeKey() { return type.getKey(); } public int getTypeId() { return type.getId(); } // Save to campaign file as XML // Also used by the personnel exporter public void writeToXml(PrintWriter pw1, int indent) { try { marshaller.marshal(this, pw1); } catch(JAXBException ex) { MekHQ.logError(ex); } } @SuppressWarnings({ "unused" }) private void afterUnmarshal(Unmarshaller unmarshaller, Object parent) { // Fix old-style "hits" into "severity". if(version < 1) { if(type == InjuryTypes.CONCUSSION) { hits -= 1; } else if(type == InjuryTypes.INTERNAL_BLEEDING) { hits -= 2; } else { hits = 1; } } // Fix hand/foot locations if(fluff.endsWith(" hand")) { switch(location) { case LEFT_ARM: location = BodyLocation.LEFT_HAND; break; case RIGHT_ARM: location = BodyLocation.RIGHT_HAND; break; default: // do nothing } } if(fluff.endsWith(" foot")) { switch(location) { case LEFT_LEG: location = BodyLocation.LEFT_FOOT; break; case RIGHT_LEG: location = BodyLocation.RIGHT_FOOT; break; default: // do nothing } } if (null == id) { // We didn't have an ID, so let's generate one! id = UUID.randomUUID(); } if(null == extraData) { extraData = new ExtraData(); } hidingState = Utilities.nonNull(hidingState, Hiding.DEFAULT); version = Injury.VERSION; } public static enum Hiding { YES, NO, DEFAULT } }