package misc; import java.util.Random; import java.util.Map; import java.util.EnumMap; import rescuecore2.config.Config; import rescuecore2.standard.entities.Building; import rescuecore2.standard.entities.Human; import rescuecore2.standard.entities.AmbulanceTeam; import rescuecore2.standard.entities.FireBrigade; import rescuecore2.standard.entities.PoliceForce; /** * Container for all misc simulator parameters. * @author Maitreyi Nanjanath * @author Cameron Skinner */ public class MiscParameters { private Config config; private Random rng; // All building classes indexed by building code and degree of collapse. The BuildingClass class knows about buriedness rates, injury rates etc. private Map<BuildingCode, Map<BrokennessDegree, BuildingClass>> buildingClasses; private DamageType collapseDamage; private DamageType buryDamage; private DamageType fireDamage; /** Create a new MiscParameters object based on a Config. @param config The Config to read. */ public MiscParameters(Config config) { this.config = config; rng = config.getRandom(); initBuildingData(); initInjuryData(); } /** Find out if an agent inside a building should be buried due to collapse. @param b The building to check. @return True if an agent inside the building should be buried, false otherwise. */ public boolean shouldBuryAgent(Building b) { if (!b.isBuildingCodeDefined() || !b.isBrokennessDefined() || b.getBrokenness() == 0) { return false; } BuildingClass clazz = getBuildingClass(b); return clazz.shouldBury(); } /** Get the buriedness of an agent inside a building. @param b The building to check. @return The buriedness of an agent inside the building. */ public int getBuriedness(Building b) { if (!b.isBuildingCodeDefined() || !b.isBrokennessDefined() || b.getBrokenness() == 0) { return 0; } BuildingClass clazz = getBuildingClass(b); return clazz.getAgentBuriedness(); } /** Get the amount of damage an agent should take as a result of being in a collapsing building. @param b The building. @param agent The agent being damaged. @return The amount of damage to add to the agent. */ public int getCollapseDamage(Building b, Human agent) { if (!b.isBuildingCodeDefined() || !b.isBrokennessDefined() || b.getBrokenness() == 0) { return 0; } BuildingClass clazz = getBuildingClass(b); Injury injury = clazz.getCollapseInjury(); return collapseDamage.getDamage(injury, agent); } /** Get the amount of damage an agent should take as a result of being buried in a collapsed building. @param b The building. @param agent The agent being damaged. @return The amount of damage to add to the agent. */ public int getBuryDamage(Building b, Human agent) { if (!b.isBuildingCodeDefined() || !b.isBrokennessDefined() || b.getBrokenness() == 0) { return 0; } BuildingClass clazz = getBuildingClass(b); Injury injury = clazz.getBuryInjury(); return buryDamage.getDamage(injury, agent); } /** Get the amount of damage an agent should take as a result of being in a burning building. @param b The building. @param agent The agent being damaged. @return The amount of damage to add to the agent. */ public int getFireDamage(Building b, Human agent) { if (!b.isBuildingCodeDefined()) { return 0; } BuildingClass clazz = getBuildingClass(b); Injury injury = clazz.getFireInjury(); return fireDamage.getDamage(injury, agent); } private void initBuildingData() { buildingClasses = new EnumMap<BuildingCode, Map<BrokennessDegree, BuildingClass>>(BuildingCode.class); for (BuildingCode code : BuildingCode.values()) { Map<BrokennessDegree, BuildingClass> codeMap = new EnumMap<BrokennessDegree, BuildingClass>(BrokennessDegree.class); for (BrokennessDegree degree : BrokennessDegree.values()) { codeMap.put(degree, new BuildingClass(config, code, degree)); } buildingClasses.put(code, codeMap); } } private void initInjuryData() { collapseDamage = new DamageType(config, "collapse"); buryDamage = new DamageType(config, "bury"); fireDamage = new DamageType(config, "fire"); } private BuildingClass getBuildingClass(Building b) { BuildingCode code = BuildingCode.values()[b.getBuildingCode()]; BrokennessDegree degree = BrokennessDegree.getBrokennessDegree(b); return buildingClasses.get(code).get(degree); } private class BuildingClass { private double buriedProbability; private int initialBuriedness; private Map<Injury, Double> collapseInjuryProbability; private Map<Injury, Double> buryInjuryProbability; private Map<Injury, Double> fireInjuryProbability; public BuildingClass(Config config, BuildingCode code, BrokennessDegree degree) { buriedProbability = config.getFloatValue("misc.buriedness." + code + "." + degree + ".rate"); initialBuriedness = config.getIntValue("misc.buriedness." + code + "." + degree + ".value"); collapseInjuryProbability = new EnumMap<Injury, Double>(Injury.class); buryInjuryProbability = new EnumMap<Injury, Double>(Injury.class); fireInjuryProbability = new EnumMap<Injury, Double>(Injury.class); collapseInjuryProbability.put(Injury.SLIGHT, config.getFloatValue("misc.injury.collapse." + code + "." + degree + ".slight")); collapseInjuryProbability.put(Injury.SERIOUS, config.getFloatValue("misc.injury.collapse." + code + "." + degree + ".serious")); collapseInjuryProbability.put(Injury.CRITICAL, config.getFloatValue("misc.injury.collapse." + code + "." + degree + ".critical")); buryInjuryProbability.put(Injury.SLIGHT, config.getFloatValue("misc.injury.bury." + code + "." + degree + ".slight")); buryInjuryProbability.put(Injury.SERIOUS, config.getFloatValue("misc.injury.bury." + code + "." + degree + ".serious")); buryInjuryProbability.put(Injury.CRITICAL, config.getFloatValue("misc.injury.bury." + code + "." + degree + ".critical")); fireInjuryProbability.put(Injury.SLIGHT, config.getFloatValue("misc.injury.fire." + code + "." + degree + ".slight")); fireInjuryProbability.put(Injury.SERIOUS, config.getFloatValue("misc.injury.fire." + code + "." + degree + ".serious")); fireInjuryProbability.put(Injury.CRITICAL, config.getFloatValue("misc.injury.fire." + code + "." + degree + ".critical")); } public int getAgentBuriedness() { return initialBuriedness; } public boolean shouldBury() { return rng.nextDouble() < buriedProbability; } public Injury getCollapseInjury() { return getInjury(collapseInjuryProbability); } public Injury getBuryInjury() { return getInjury(buryInjuryProbability); } public Injury getFireInjury() { return getInjury(fireInjuryProbability); } private Injury getInjury(Map<Injury, Double> table) { double d = rng.nextDouble(); double d1 = table.get(Injury.SLIGHT); double d2 = table.get(Injury.SERIOUS) + d1; double d3 = table.get(Injury.CRITICAL) + d2; if (d < d1) { return Injury.SLIGHT; } if (d < d2) { return Injury.SERIOUS; } if (d < d3) { return Injury.CRITICAL; } return Injury.NONE; } } private enum BuildingCode { WOOD, STEEL, CONCRETE; public String toString() { return super.toString().toLowerCase(); } } private enum BrokennessDegree { NONE(0, 0), PARTIAL(1, 25), HALF(26, 50), ALL(51, 100); private int min; private int max; private BrokennessDegree(int min, int max) { this.min = min; this.max = max; } @Override public String toString() { return super.toString().toLowerCase(); } public static BrokennessDegree getBrokennessDegree(Building b) { int brokenness = b.isBrokennessDefined() ? b.getBrokenness() : 0; for (BrokennessDegree next : BrokennessDegree.values()) { if (brokenness >= next.min && brokenness <= next.max) { return next; } } return BrokennessDegree.NONE; } } private enum Injury { NONE, SLIGHT, SERIOUS, CRITICAL; } private static class DamageType { private Map<Injury, Integer> damage; private double ambulanceMultiplier; private double policeMultiplier; private double fireMultiplier; public DamageType(Config config, String type) { damage = new EnumMap<Injury, Integer>(Injury.class); damage.put(Injury.NONE, 0); damage.put(Injury.SLIGHT, config.getIntValue("misc.injury." + type + ".slight")); damage.put(Injury.SERIOUS, config.getIntValue("misc.injury." + type + ".serious")); damage.put(Injury.CRITICAL, config.getIntValue("misc.injury." + type + ".critical")); ambulanceMultiplier = config.getFloatValue("misc.injury." + type + ".multiplier.ambulance"); policeMultiplier = config.getFloatValue("misc.injury." + type + ".multiplier.police"); fireMultiplier = config.getFloatValue("misc.injury." + type + ".multiplier.fire"); } public int getDamage(Injury injury, Human agent) { int result = damage.get(injury); if (agent instanceof AmbulanceTeam) { return (int)(result * ambulanceMultiplier); } if (agent instanceof PoliceForce) { return (int)(result * policeMultiplier); } if (agent instanceof FireBrigade) { return (int)(result * fireMultiplier); } return result; } } }