mekhq.campaign.universe.Faction.java Source code

Java tutorial

Introduction

Here is the source code for mekhq.campaign.universe.Faction.java

Source

/*
 * Faction.java
 *
 * Copyright (C) 2009-2016 MegaMek team
 * 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.universe;

import java.awt.Color;
import java.io.FileInputStream;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.joda.time.DateTime;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import megamek.common.EquipmentType;
import mekhq.MekHQ;
import mekhq.Utilities;
import mekhq.campaign.Campaign;
import mekhq.campaign.parts.Part;

/**
 *
 * @author Jay Lawson <jaylawson39 at yahoo.com>
 */
public class Faction {
    private static Map<String, Faction> factions;
    private static Map<Integer, Faction> factionIdMap;
    public static String[] choosableFactionCodes = { "MERC", "CC", "DC", "FS", "FWL", "LA", "FC", "ROS", "CS",
            "WOB", "FRR", "SIC", "MOC", "MH", "OA", "TC", "CDS", "CGB", "CHH", "CJF", "CNC", "CSJ", "CSV", "CW",
            "TH", "RWR" };

    private String shortname;
    private String fullname;
    private String[] altNames;
    private Color color;
    private String nameGenerator;
    private String[] startingPlanet;
    private int[] eraMods;
    private Integer id;
    private Set<Tag> tags;
    // Start and end years (inclusive)
    private int start;
    private int end;

    public Faction() {
        this("???", "Unknown");
    }

    public Faction(String sname, String fname) {
        shortname = sname;
        fullname = fname;
        nameGenerator = "General";
        color = Color.LIGHT_GRAY;
        startingPlanet = new String[] { "Terra", "Terra", "Terra", "Terra", "Terra", "Terra", "Terra", "Terra",
                "Terra" };
        altNames = new String[] { "", "", "", "", "", "", "", "", "" };
        eraMods = new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        tags = EnumSet.noneOf(Faction.Tag.class);
        start = 0;
        end = 9999;
    }

    public String getShortName() {
        return shortname;
    }

    public String getFullName(int era) {
        String alt = "";
        if (altNames.length > era) {
            alt = altNames[era];
        }
        if (alt.trim().length() == 0) {
            return fullname;
        } else {
            return alt;
        }
    }

    public Color getColor() {
        return color;
    }

    public boolean isClan() {
        return is(Tag.CLAN);
    }

    public boolean isPeriphery() {
        return is(Tag.PERIPHERY);
    }

    public String getNameGenerator() {
        return nameGenerator;
    }

    public String getStartingPlanet(int era) {
        if (startingPlanet.length > era) {
            return startingPlanet[era];
        } else if (startingPlanet.length > 0) {
            return startingPlanet[startingPlanet.length - 1];
        }
        return "Terra";
    }

    public int getEraMod(int era) {
        if (eraMods.length > era) {
            return eraMods[era];
        }
        return 0;
    }

    public int getTechMod(Part part, Campaign campaign) {
        int currentYear = campaign.getCalendar().get(Calendar.YEAR);

        //TODO: This seems hacky - we shouldn't hardcode in universe details
        //like this
        int factionMod = 0;
        if (part.getTechBase() == Part.T_CLAN && !isClan()) {
            // Availability of clan tech for IS
            if (currentYear < 3050)
                // Impossible to buy before clan invasion
                factionMod = 12;
            else if (currentYear <= 3052)
                // Between begining of clan invasiuon and tukayyid, very very hard to buy
                factionMod = 5;
            else if (currentYear <= 3060)
                // Between tukayyid and great refusal, very hard to buy
                factionMod = 4;
            else
                // After great refusal, hard to buy
                factionMod = 3;
        }
        if (part.getTechBase() == Part.T_IS && isPeriphery()) {
            // Availability of high tech rating equipment in low tech areas (periphery)
            switch (part.getTechRating()) {
            case (EquipmentType.RATING_E):
                factionMod += 1;
                break;
            case (EquipmentType.RATING_F):
                factionMod += 2;
                break;
            }
        }

        return factionMod;
    }

    public boolean is(Faction.Tag tag) {
        return tags.contains(tag);
    }

    public boolean validIn(int year) {
        return (year >= start) && (year <= end);
    }

    public boolean validIn(DateTime time) {
        return validIn(time.getYear());
    }

    public Integer getId() {
        return id;
    }

    public static Collection<Faction> getFactions() {
        return factions.values();
    }

    public static Collection<String> getFactionList() {
        return new ArrayList<>(factions.keySet());
    }

    public static Faction getFaction(String sname) {
        return factions.get(sname);
    }

    public static Faction getFactionFromFullName(String fname, int year) {
        return getFactionFromFullNameAndEra(fname, Era.getEra(year));
    }

    public static Faction getFactionFromFullNameAndEra(String fname, int era) {
        Faction faction = null;
        for (Faction f : factions.values()) {
            if (f.getFullName(era).equals(fname)) {
                faction = f;
                break;
            }
        }
        return faction;
    }

    public static String getFactionCode(int faction) {
        Faction f = factionIdMap.get(faction);
        return (null != f) ? f.getShortName() : "IND"; //$NON-NLS-1$
    }

    public static Faction getFactionFromXML(Node wn) throws DOMException, ParseException {
        Faction retVal = new Faction();
        NodeList nl = wn.getChildNodes();

        for (int x = 0; x < nl.getLength(); x++) {
            Node wn2 = nl.item(x);
            if (wn2.getNodeName().equalsIgnoreCase("shortname")) {
                retVal.shortname = wn2.getTextContent();
            } else if (wn2.getNodeName().equalsIgnoreCase("fullname")) {
                retVal.fullname = wn2.getTextContent();
            } else if (wn2.getNodeName().equalsIgnoreCase("nameGenerator")) {
                retVal.nameGenerator = wn2.getTextContent();
            } else if (wn2.getNodeName().equalsIgnoreCase("clan")) {
                if (wn2.getTextContent().equalsIgnoreCase("true")) {
                    retVal.tags.add(Tag.CLAN);
                } else {
                    retVal.tags.remove(Tag.CLAN);
                }
            } else if (wn2.getNodeName().equalsIgnoreCase("periphery")) {
                if (wn2.getTextContent().equalsIgnoreCase("true")) {
                    retVal.tags.add(Tag.PERIPHERY);
                } else {
                    retVal.tags.remove(Tag.PERIPHERY);
                }
            } else if (wn2.getNodeName().equalsIgnoreCase("startingPlanet")) {
                retVal.startingPlanet = wn2.getTextContent().split(",", -2);
            } else if (wn2.getNodeName().equalsIgnoreCase("altNames")) {
                retVal.altNames = wn2.getTextContent().split(",", -2);
            } else if (wn2.getNodeName().equalsIgnoreCase("eraMods")) {
                String[] values = wn2.getTextContent().split(",", -2);
                for (int i = 0; i < values.length; i++) {
                    retVal.eraMods[i] = Integer.parseInt(values[i]);
                }
            } else if (wn2.getNodeName().equalsIgnoreCase("colorRGB")) {
                String[] values = wn2.getTextContent().split(",");
                if (values.length == 3) {
                    int colorRed = Integer.parseInt(values[0]);
                    int colorGreen = Integer.parseInt(values[1]);
                    int colorBlue = Integer.parseInt(values[2]);
                    retVal.color = new Color(colorRed, colorGreen, colorBlue);
                }
            } else if (wn2.getNodeName().equalsIgnoreCase("id")) {
                retVal.id = Integer.valueOf(wn2.getTextContent());
            } else if (wn2.getNodeName().equalsIgnoreCase("start")) {
                retVal.start = Integer.valueOf(wn2.getTextContent());
            } else if (wn2.getNodeName().equalsIgnoreCase("end")) {
                retVal.end = Integer.valueOf(wn2.getTextContent());
            } else if (wn2.getNodeName().equalsIgnoreCase("tags")) {
                Arrays.stream(wn2.getTextContent().split(",")).map(tag -> tag.toUpperCase(Locale.ROOT))
                        .map(Tag::valueOf).forEach(tag -> retVal.tags.add(tag));
            }
        }

        if (retVal.altNames.length < Era.E_NUM) {
            MekHQ.logMessage(retVal.fullname + " faction did not have a long enough altNames vector");
        }
        if (retVal.eraMods.length < Era.E_NUM) {
            MekHQ.logMessage(retVal.fullname + " faction did not have a long enough eraMods vector");
        }
        if (!retVal.is(Tag.PIRATE) && !retVal.is(Tag.MERC) && !retVal.is(Tag.TRADER)) {
            // Planet checks
            if (retVal.startingPlanet.length < Era.E_NUM) {
                MekHQ.logMessage(retVal.fullname + " faction did not have a long enough startingPlanet vector");
            }
        }

        return retVal;
    }

    public static void generateFactions() throws DOMException, ParseException {
        MekHQ.logMessage("Starting load of faction data from XML...");
        // Initialize variables.
        factions = new HashMap<>();
        factionIdMap = new HashMap<>();
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        Document xmlDoc = null;

        try (FileInputStream fis = new FileInputStream("data/universe/factions.xml")) {
            // Using factory get an instance of document builder
            DocumentBuilder db = dbf.newDocumentBuilder();

            // Parse using builder to get DOM representation of the XML file
            xmlDoc = db.parse(fis);
        } catch (Exception ex) {
            MekHQ.logError(ex);
        }

        Element factionEle = xmlDoc.getDocumentElement();
        NodeList nl = factionEle.getChildNodes();

        // Get rid of empty text nodes and adjacent text nodes...
        // Stupid weird parsing of XML.  At least this cleans it up.
        factionEle.normalize();

        // Okay, lets iterate through the children, eh?
        for (int x = 0; x < nl.getLength(); x++) {
            Node wn = nl.item(x);

            if (wn.getParentNode() != factionEle)
                continue;

            int xc = wn.getNodeType();

            if (xc == Node.ELEMENT_NODE) {
                // This is what we really care about.
                // All the meat of our document is in this node type, at this
                // level.
                // Okay, so what element is it?
                String xn = wn.getNodeName();

                if (xn.equalsIgnoreCase("faction")) {
                    Faction f = getFactionFromXML(wn);
                    if (!factions.containsKey(f.getShortName())) {
                        factions.put(f.getShortName(), f);
                        if (null != f.getId()) {
                            if (!factionIdMap.containsKey(f.getId())) {
                                factionIdMap.put(f.getId(), f);
                            } else {
                                MekHQ.logError(String.format(
                                        "Faction id \"%d\" already used for faction %s, can't re-use it for %s",
                                        f.getId().intValue(), factionIdMap.get(f.getId()).getFullName(0),
                                        f.getFullName(0)));
                            }
                        }
                    } else {
                        MekHQ.logError(String.format(
                                "Faction code \"%s\" already used for faction %s, can't re-use it for %s",
                                f.getShortName(), factions.get(f.getShortName()).getFullName(0), f.getFullName(0)));
                    }
                } else if (xn.equalsIgnoreCase("choosableFactionCodes")) {
                    choosableFactionCodes = wn.getTextContent().split(",");
                }
            }
        }
        MekHQ.logMessage("Loaded a total of " + factions.size() + " factions");
    }

    /** @return Sorted list of faction names as one string */
    public static String getFactionNames(Collection<Faction> factions, int era) {
        if (null == factions) {
            return "-"; //$NON-NLS-1$
        }
        List<String> factionNames = new ArrayList<>(factions.size());
        for (Faction f : factions) {
            factionNames.add(f.getFullName(era));
        }
        Collections.sort(factionNames);
        return Utilities.combineString(factionNames, "/"); //$NON-NLS-1$
    }

    public static enum Tag {
        /** Inner sphere */
        IS, PERIPHERY, CLAN,
        /** A bunch of dirty pirates */
        PIRATE,
        /** Major mercenary bands */
        MERC,
        /** Major trading company */
        TRADER,
        /** Faction is limited to a single star system, or potentially just a part of a planet */
        MINOR,
        /** Faction is rebelling against the superior ("parent") faction */
        REBEL,
        /** Faction isn't overtly acting on the political/military scale; think ComStar before clan invasion */
        INACTIVE,
        /** Faction represents empty space */
        ABANDONED,
        /** Faction represents a lack of unified government */
        CHAOS,
        /** Faction is campaign-specific, generated on the fly */
        GENERATED,
        /** Faction is hidden from view */
        HIDDEN
    }
}