package gis2; import org.dom4j.DocumentHelper; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.Namespace; import org.dom4j.QName; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.ArrayList; import java.util.Set; import rescuecore2.worldmodel.EntityID; import rescuecore2.worldmodel.Entity; import rescuecore2.log.Logger; import rescuecore2.config.Config; import rescuecore2.standard.entities.StandardWorldModel; import rescuecore2.standard.entities.StandardEntity; import rescuecore2.standard.entities.Building; import rescuecore2.standard.entities.Refuge; import rescuecore2.standard.entities.Area; import rescuecore2.standard.entities.Civilian; import rescuecore2.standard.entities.FireBrigade; import rescuecore2.standard.entities.PoliceForce; import rescuecore2.standard.entities.AmbulanceTeam; import rescuecore2.standard.entities.FireStation; import rescuecore2.standard.entities.PoliceOffice; import rescuecore2.standard.entities.AmbulanceCentre; import rescuecore2.standard.entities.Human; /** This class knows how to read scenario files and apply them to StandardWorldModels. */ public class Scenario { private static final String SCENARIO_NAMESPACE_URI = "urn:roborescue:map:scenario"; private static final Namespace SCENARIO_NAMESPACE = DocumentHelper.createNamespace("scenario", SCENARIO_NAMESPACE_URI); private static final int DEFAULT_HP = 10000; private static final int DEFAULT_STAMINA = 10000; private static final String WATER_QUANTITY_KEY = "fire.tank.maximum"; private static final QName ROOT_QNAME = DocumentHelper.createQName("scenario", SCENARIO_NAMESPACE); private static final QName ID_QNAME = DocumentHelper.createQName("id", SCENARIO_NAMESPACE); private static final QName LOCATION_QNAME = DocumentHelper.createQName("location", SCENARIO_NAMESPACE); private static final QName SCENARIO_QNAME = DocumentHelper.createQName("scenario", SCENARIO_NAMESPACE); private static final QName REFUGE_QNAME = DocumentHelper.createQName("refuge", SCENARIO_NAMESPACE); private static final QName CIV_QNAME = DocumentHelper.createQName("civilian", SCENARIO_NAMESPACE); private static final QName FB_QNAME = DocumentHelper.createQName("firebrigade", SCENARIO_NAMESPACE); private static final QName AT_QNAME = DocumentHelper.createQName("ambulanceteam", SCENARIO_NAMESPACE); private static final QName PF_QNAME = DocumentHelper.createQName("policeforce", SCENARIO_NAMESPACE); private static final QName FS_QNAME = DocumentHelper.createQName("firestation", SCENARIO_NAMESPACE); private static final QName AC_QNAME = DocumentHelper.createQName("ambulancecentre", SCENARIO_NAMESPACE); private static final QName PO_QNAME = DocumentHelper.createQName("policeoffice", SCENARIO_NAMESPACE); private static final QName FIRE_QNAME = DocumentHelper.createQName("fire", SCENARIO_NAMESPACE); private Set<Integer> refuges; private Set<Integer> fires; private Collection<Integer> civLocations; private Collection<Integer> fbLocations; private Collection<Integer> atLocations; private Collection<Integer> pfLocations; private Collection<Integer> fsLocations; private Collection<Integer> acLocations; private Collection<Integer> poLocations; /** Create an empty scenario. */ public Scenario() { refuges = new HashSet<Integer>(); fires = new HashSet<Integer>(); civLocations = new ArrayList<Integer>(); fbLocations = new ArrayList<Integer>(); pfLocations = new ArrayList<Integer>(); atLocations = new ArrayList<Integer>(); fsLocations = new ArrayList<Integer>(); poLocations = new ArrayList<Integer>(); acLocations = new ArrayList<Integer>(); } /** Create a scenario from an XML document. @param doc The document to read. @throws ScenarioException If the scenario is invalid. */ public Scenario(Document doc) throws ScenarioException { this(); read(doc); } /** Read scenario data from an XML document. @param doc The document to read. @throws ScenarioException If the scenario is invalid. */ public void read(Document doc) throws ScenarioException { refuges.clear(); fires.clear(); civLocations.clear(); fbLocations.clear(); pfLocations.clear(); atLocations.clear(); fsLocations.clear(); poLocations.clear(); acLocations.clear(); Element root = doc.getRootElement(); if (!root.getQName().equals(SCENARIO_QNAME)) { throw new ScenarioException("Scenario document has wrong root element: expecting " + SCENARIO_QNAME + "; not " + root.getQName()); } for (Object next : root.elements(REFUGE_QNAME)) { Element e = (Element)next; refuges.add(Integer.parseInt(e.attributeValue(LOCATION_QNAME))); } for (Object next : root.elements(CIV_QNAME)) { Element e = (Element)next; civLocations.add(Integer.parseInt(e.attributeValue(LOCATION_QNAME))); } for (Object next : root.elements(FB_QNAME)) { Element e = (Element)next; fbLocations.add(Integer.parseInt(e.attributeValue(LOCATION_QNAME))); } for (Object next : root.elements(PF_QNAME)) { Element e = (Element)next; pfLocations.add(Integer.parseInt(e.attributeValue(LOCATION_QNAME))); } for (Object next : root.elements(AT_QNAME)) { Element e = (Element)next; atLocations.add(Integer.parseInt(e.attributeValue(LOCATION_QNAME))); } for (Object next : root.elements(FS_QNAME)) { Element e = (Element)next; fsLocations.add(Integer.parseInt(e.attributeValue(LOCATION_QNAME))); } for (Object next : root.elements(PO_QNAME)) { Element e = (Element)next; poLocations.add(Integer.parseInt(e.attributeValue(LOCATION_QNAME))); } for (Object next : root.elements(AC_QNAME)) { Element e = (Element)next; acLocations.add(Integer.parseInt(e.attributeValue(LOCATION_QNAME))); } for (Object next : root.elements(FIRE_QNAME)) { Element e = (Element)next; fires.add(Integer.parseInt(e.attributeValue(LOCATION_QNAME))); } } /** Write scenario data to an XML document. @param doc The document to write to. */ public void write(Document doc) { Element root = DocumentHelper.createElement(SCENARIO_QNAME); doc.setRootElement(root); for (int next : refuges) { root.addElement(REFUGE_QNAME).addAttribute(LOCATION_QNAME, String.valueOf(next)); } for (int next : fires) { root.addElement(FIRE_QNAME).addAttribute(LOCATION_QNAME, String.valueOf(next)); } for (int next : civLocations) { root.addElement(CIV_QNAME).addAttribute(LOCATION_QNAME, String.valueOf(next)); } for (int next : fbLocations) { root.addElement(FB_QNAME).addAttribute(LOCATION_QNAME, String.valueOf(next)); } for (int next : fsLocations) { root.addElement(FS_QNAME).addAttribute(LOCATION_QNAME, String.valueOf(next)); } for (int next : pfLocations) { root.addElement(PF_QNAME).addAttribute(LOCATION_QNAME, String.valueOf(next)); } for (int next : poLocations) { root.addElement(PO_QNAME).addAttribute(LOCATION_QNAME, String.valueOf(next)); } for (int next : atLocations) { root.addElement(AT_QNAME).addAttribute(LOCATION_QNAME, String.valueOf(next)); } for (int next : acLocations) { root.addElement(AC_QNAME).addAttribute(LOCATION_QNAME, String.valueOf(next)); } root.addNamespace("scenario", SCENARIO_NAMESPACE_URI); } /** Apply this scenario to a world model. @param model The world model to alter. @param config The configuration. @throws ScenarioException if this scenario is invalid. */ public void apply(StandardWorldModel model, Config config) throws ScenarioException { Logger.debug("Creating " + refuges.size() + " refuges"); for (int next : refuges) { Logger.debug("Converting building " + next + " to a refuge"); Building b = (Building)model.getEntity(new EntityID(next)); if (b == null) { throw new ScenarioException("Building " + next + " does not exist"); } Refuge r = new Refuge(b); model.removeEntity(b); model.addEntity(r); Logger.debug("Converted " + b + " into " + r); } Logger.debug("Igniting " + fires.size() + " fires"); for (int next : fires) { Logger.debug("Igniting " + next); Building b = (Building)model.getEntity(new EntityID(next)); if (b == null) { throw new ScenarioException("Building " + next + " does not exist"); } b.setIgnition(true); } int nextID = 0; for (StandardEntity next : model) { nextID = Math.max(nextID, next.getID().getValue()); } Logger.debug("Creating " + fbLocations.size() + " fire brigades"); for (int next : fbLocations) { EntityID id = new EntityID(next); FireBrigade f = new FireBrigade(new EntityID(++nextID)); setupAgent(f, id, model, config); } Logger.debug("Creating " + pfLocations.size() + " police forces"); for (int next : pfLocations) { EntityID id = new EntityID(next); PoliceForce p = new PoliceForce(new EntityID(++nextID)); setupAgent(p, id, model, config); } Logger.debug("Creating " + atLocations.size() + " ambulance teams"); for (int next : atLocations) { EntityID id = new EntityID(next); AmbulanceTeam a = new AmbulanceTeam(new EntityID(++nextID)); setupAgent(a, id, model, config); } Logger.debug("Creating " + fsLocations.size() + " fire stations"); for (int next : fsLocations) { EntityID id = new EntityID(next); Logger.debug("Coverting building " + next + " to a fire station"); Building b = (Building)model.getEntity(id); if (b == null) { throw new ScenarioException("Building " + next + " does not exist"); } FireStation f = new FireStation(b); model.removeEntity(b); model.addEntity(f); Logger.debug("Converted " + b + " into " + f); } Logger.debug("Creating " + poLocations.size() + " police offices"); for (int next : poLocations) { EntityID id = new EntityID(next); Logger.debug("Coverting building " + next + " to a police office"); Building b = (Building)model.getEntity(id); if (b == null) { throw new ScenarioException("Building " + next + " does not exist"); } PoliceOffice p = new PoliceOffice(b); model.removeEntity(b); model.addEntity(p); Logger.debug("Converted " + b + " into " + p); } Logger.debug("Creating " + acLocations.size() + " ambulance centres"); for (int next : acLocations) { EntityID id = new EntityID(next); Logger.debug("Coverting building " + next + " to an ambulance centre"); Building b = (Building)model.getEntity(id); if (b == null) { throw new ScenarioException("Building " + next + " does not exist"); } AmbulanceCentre a = new AmbulanceCentre(b); model.removeEntity(b); model.addEntity(a); Logger.debug("Converted " + b + " into " + a); } Logger.debug("Creating " + civLocations.size() + " civilians"); for (int next : civLocations) { EntityID id = new EntityID(next); Civilian c = new Civilian(new EntityID(++nextID)); setupAgent(c, id, model, config); } } /** Get the set of fire locations. @return The set of fire locations. */ public Set<Integer> getFires() { return Collections.unmodifiableSet(fires); } /** Get the set of refuge locations. @return The set of refuge locations. */ public Set<Integer> getRefuges() { return Collections.unmodifiableSet(refuges); } /** Get the list of civilian locations. @return The list of civilian locations. */ public Collection<Integer> getCivilians() { return Collections.unmodifiableCollection(civLocations); } /** Get the list of fire brigade locations. @return The list of fire brigade locations. */ public Collection<Integer> getFireBrigades() { return Collections.unmodifiableCollection(fbLocations); } /** Get the list of fire station locations. @return The list of fire station locations. */ public Collection<Integer> getFireStations() { return Collections.unmodifiableCollection(fsLocations); } /** Get the list of police force locations. @return The list of police force locations. */ public Collection<Integer> getPoliceForces() { return Collections.unmodifiableCollection(pfLocations); } /** Get the list of police office locations. @return The list of police office locations. */ public Collection<Integer> getPoliceOffices() { return Collections.unmodifiableCollection(poLocations); } /** Get the list of ambulance team locations. @return The list of ambulance team locations. */ public Collection<Integer> getAmbulanceTeams() { return Collections.unmodifiableCollection(atLocations); } /** Get the list of ambulance centre locations. @return The list of ambulance centre locations. */ public Collection<Integer> getAmbulanceCentres() { return Collections.unmodifiableCollection(acLocations); } /** Set the set of fire locations. @param newLocations The new set of locations. */ public void setFires(Set<Integer> newLocations) { fires.clear(); fires.addAll(newLocations); } /** Set the set of refuge locations. @param newLocations The new set of locations. */ public void setRefuges(Set<Integer> newLocations) { refuges.clear(); refuges.addAll(newLocations); } /** Set the list of civilian locations. @param newLocations The new list of locations. */ public void setCivilians(Collection<Integer> newLocations) { civLocations.clear(); civLocations.addAll(newLocations); } /** Set the list of fire brigade locations. @param newLocations The new list of locations. */ public void setFireBrigades(Collection<Integer> newLocations) { fbLocations.clear(); fbLocations.addAll(newLocations); } /** Set the list of fire station locations. @param newLocations The new list of locations. */ public void setFireStations(Collection<Integer> newLocations) { fsLocations.clear(); fsLocations.addAll(newLocations); } /** Set the list of police force locations. @param newLocations The new list of locations. */ public void setPoliceForces(Collection<Integer> newLocations) { pfLocations.clear(); pfLocations.addAll(newLocations); } /** Set the list of police office locations. @param newLocations The new list of locations. */ public void setPoliceOffices(Collection<Integer> newLocations) { poLocations.clear(); poLocations.addAll(newLocations); } /** Set the list of ambulance team locations. @param newLocations The new list of locations. */ public void setAmbulanceTeams(Collection<Integer> newLocations) { atLocations.clear(); atLocations.addAll(newLocations); } /** Set the list of ambulance centre locations. @param newLocations The new list of locations. */ public void setAmbulanceCentres(Collection<Integer> newLocations) { acLocations.clear(); acLocations.addAll(newLocations); } /** Add a fire. @param location The new fire location. */ public void addFire(int location) { fires.add(location); } /** Remove a fire. @param location The fire location to remove. */ public void removeFire(int location) { fires.remove(location); } /** Add a refuge. @param location The new refuge location. */ public void addRefuge(int location) { refuges.add(location); } /** Remove a refuge. @param location The refuge location to remove. */ public void removeRefuge(int location) { refuges.remove(location); } /** Add a civilian. @param location The new civilian location. */ public void addCivilian(int location) { civLocations.add(location); } /** Remove a civilian. @param location The civilian location to remove. */ public void removeCivilian(int location) { civLocations.remove(location); } /** Add a fire brigade. @param location The new fire brigade location. */ public void addFireBrigade(int location) { fbLocations.add(location); } /** Remove a fire brigade. @param location The fire brigade location to remove. */ public void removeFireBrigade(int location) { fbLocations.remove(location); } /** Add a fire station. @param location The new fire station location. */ public void addFireStation(int location) { fsLocations.add(location); } /** Remove a fire station. @param location The fire station location to remove. */ public void removeFireStation(int location) { fsLocations.remove(location); } /** Add a police force. @param location The new police force location. */ public void addPoliceForce(int location) { pfLocations.add(location); } /** Remove a police force. @param location The police force location to remove. */ public void removePoliceForce(int location) { pfLocations.remove(location); } /** Add a police office. @param location The new police office location. */ public void addPoliceOffice(int location) { poLocations.add(location); } /** Remove a police office. @param location The police office location to remove. */ public void removePoliceOffice(int location) { poLocations.remove(location); } /** Add an ambulance team. @param location The new ambulance team location. */ public void addAmbulanceTeam(int location) { atLocations.add(location); } /** Remove an ambulance team. @param location The ambulance team location to remove. */ public void removeAmbulanceTeam(int location) { atLocations.remove(location); } /** Add an ambulance centre. @param location The new ambulance centre location. */ public void addAmbulanceCentre(int location) { acLocations.add(location); } /** Remove an ambulance centre. @param location The ambulance centre location to remove. */ public void removeAmbulanceCentre(int location) { acLocations.remove(location); } private void setupAgent(Human h, EntityID position, StandardWorldModel model, Config config) throws ScenarioException { Entity areaEntity = model.getEntity(position); if (areaEntity == null) { throw new ScenarioException("Area " + position + " does not exist"); } if (!(areaEntity instanceof Area)) { throw new ScenarioException("Entity " + position + " is not an area: " + areaEntity); } Area area = (Area)areaEntity; h.setX(area.getX()); h.setY(area.getY()); h.setPosition(position); h.setStamina(DEFAULT_STAMINA); h.setHP(DEFAULT_HP); h.setDamage(0); h.setBuriedness(0); h.setDirection(0); h.setTravelDistance(0); h.setPositionHistory(new int[0]); if (h instanceof FireBrigade) { ((FireBrigade)h).setWater(config.getIntValue(WATER_QUANTITY_KEY)); } model.addEntity(h); Logger.debug("Created " + h); } }