This repository has been archived on 2022-12-21. You can view files and clone it, but cannot push or open issues or pull requests.
sdm03/src/main/java/com/github/dtschust/zork/parser/ZorkReader.java

289 lines
11 KiB
Java

package com.github.dtschust.zork.parser;
import com.github.dtschust.zork.*;
import com.github.dtschust.zork.types.*;
import org.w3c.dom.CharacterData;
import org.w3c.dom.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
public class ZorkReader {
private final String filename;
public ZorkReader(String filename) {
this.filename = filename;
}
/* Get a string from an element (XML parsing stuff)*/
public static String getString(Element e) {
Node child = e.getFirstChild();
if (child instanceof CharacterData) {
CharacterData cd = (CharacterData) child;
return cd.getData();
}
return "?";
}
public ZorkGame build() {
ZorkGame data = new ZorkGame();
File file = new File(filename);
if (!file.canRead()) {
System.out.println("Error opening file. Exiting...");
throw new RuntimeException();
}
try {
/* Open the xml file*/
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = builder.parse(file);
Element rootElement = doc.getDocumentElement();
/* Every single first generation child is a room, container, creature, or item. So load them in*/
for (Node node : iterNodes(rootElement.getChildNodes())) {
Element element;
if (node instanceof Element) {
element = (Element) node;
String tagType = element.getTagName();
switch (tagType) {
/* If it's a room ... */
case "room":
addRoom(data, element);
break;
/* If it's an item... */
case "item":
addItem(data, element);
break;
/* If it's a container... */
case "container":
addContainer(data, element);
break;
/* And finally, if it's a creature...*/
case "creature":
addCreature(data, element);
break;
}
}
}
} catch (Exception e) {
System.out.println("Invalid XML file, exiting");
System.exit(-1);
//e.printStackTrace();
}
return data;
}
private static void addCreature(ZorkGame data, Element element) {
/* Get all possible creature attributes*/
ZorkCreature tempCreature = (ZorkCreature) readZorkObjectAttributes(new ZorkCreature(), element);
for (Element vuln : iterElements(element.getElementsByTagName("vulnerability"))) {
tempCreature.vulnerability.add(getString(vuln));
}
NodeList attacks = element.getElementsByTagName("attack");
for (Element attack : iterElements(attacks)) {
readConditionsInTrigger(attack, tempCreature.conditions);
for (Element print : iterElements(attack.getElementsByTagName("print"))) {
tempCreature.print.add(getString(print));
}
for (Element action : iterElements(attack.getElementsByTagName("action"))) {
tempCreature.action.add(getString(action));
}
}
readTriggersInObject(element, tempCreature);
/* Put each creature in the creatures hashmap, the generic object hashmap, and the objectlookup hashmap*/
data.addObjectThroughLookup("creature", tempCreature);
}
private static void addContainer(ZorkGame data, Element element) {
/*Get all possible container attributes*/
ZorkContainer tempCont = (ZorkContainer) readZorkObjectAttributes(new ZorkContainer(), element);
/*Initially assume a closed container*/
tempCont.isOpen = false;
for (Element accept : iterElements(element.getElementsByTagName("accept"))) {
/* If container has an accepts attribute, then it is always open*/
tempCont.isOpen = true;
tempCont.accept.add(getString(accept));
}
for (Element item : iterElements(element.getElementsByTagName("item"))) {
String itemName = getString(item);
tempCont.item.add(itemName);
}
readTriggersInObject(element, tempCont);
/* Put each container in the containers hashmap, the generic object hashmap, and the objectlookup hashmap*/
data.addObjectThroughLookup("container", tempCont);
}
private static void addItem(ZorkGame data, Element element) {
/* Get all possible item attributes*/
ZorkItem tempItem = (ZorkItem) readZorkObjectAttributes(new ZorkItem(), element);
NodeList writing = element.getElementsByTagName("writing");
if (writing.getLength() > 0)
tempItem.writing = getString((Element) writing.item(0));
NodeList turnon = element.getElementsByTagName("turnon");
if (turnon.getLength() > 0) {
for (Element print : iterElements(element.getElementsByTagName("print"))) {
tempItem.turnOnPrint.add(getString(print));
}
for (Element action : iterElements(element.getElementsByTagName("action"))) {
tempItem.turnOnAction.add(getString(action));
}
}
readTriggersInObject(element, tempItem);
/* Put each item in the items hashmap, the generic objects hashmap, and store its type in objectlookup*/
data.addObjectThroughLookup("item", tempItem);
}
private static void addRoom(ZorkGame data, Element element) {
/*Get all possible Room attributes*/
ZorkRoom tempRoom = (ZorkRoom) readZorkObjectAttributes(new ZorkRoom(), element);
NodeList type = element.getElementsByTagName("type");
if (type.getLength() > 0) {
tempRoom.type = getString((Element) type.item(0));
} else {
tempRoom.type = "regular";
}
for (Element item : iterElements(element.getElementsByTagName("item"))) {
String itemName = getString(item);
tempRoom.item.add(itemName);
}
for (Element creature : iterElements(element.getElementsByTagName("creature"))) {
String creatureName = getString(creature);
tempRoom.creature.add(creatureName);
}
readTriggersInObject(element, tempRoom);
for (Element container : iterElements(element.getElementsByTagName("container"))) {
String containerName = getString(container);
tempRoom.container.add(containerName);
}
for (Element border : iterElements(element.getElementsByTagName("border"))) {
String borderDirection = getString((Element) border.getElementsByTagName("direction").item(0));
String borderName = getString((Element) border.getElementsByTagName("name").item(0));
tempRoom.border.put(borderDirection, borderName);
}
/*Add this room to the rooms hashmap, put it in the generic objects hashmap, and store it's type in the objectlookup hashmap*/
data.addObjectThroughLookup("room", tempRoom);
}
private static ZorkObject readZorkObjectAttributes(ZorkObject tempObject, Element element) {
NodeList name = element.getElementsByTagName("name");
tempObject.name = getString((Element) name.item(0));
NodeList status = element.getElementsByTagName("status");
tempObject.status = (status.getLength() > 0) ? getString((Element) status.item(0)) : "";
NodeList description = element.getElementsByTagName("description");
tempObject.description = (description.getLength() > 0) ? getString((Element) description.item(0)) : "";
return tempObject;
}
private static void readTriggersInObject(Element element, ZorkObject tempRoom) {
for (Element trigger : iterElements(element.getElementsByTagName("trigger"))) {
ZorkTrigger tempTrigger = new ZorkTrigger();
for (Element command : iterElements(trigger.getElementsByTagName("command"))) {
ZorkCommand tempCommand = new ZorkCommand(getString(command));
tempTrigger.conditions.add(tempCommand);
tempTrigger.hasCommand = true;
}
readConditionsInTrigger(trigger, tempTrigger.conditions);
NodeList ttype = element.getElementsByTagName("type");
if (ttype.getLength() > 0) {
tempTrigger.type = getString((Element) ttype.item(0));
} else {
tempTrigger.type = "single";
}
for (Element print : iterElements(trigger.getElementsByTagName("print"))) {
tempTrigger.print.add(getString(print));
}
for (Element action : iterElements(trigger.getElementsByTagName("action"))) {
tempTrigger.action.add(getString(action));
}
tempRoom.trigger.add(tempTrigger);
}
}
private static void readConditionsInTrigger(Element trigger, List<? super ZorkCondition> conditionsList) {
for (Element condition : iterElements(trigger.getElementsByTagName("condition"))) {
NodeList object = condition.getElementsByTagName("object");
NodeList has = condition.getElementsByTagName("has");
if (has.getLength() > 0) {
NodeList owner = condition.getElementsByTagName("owner");
ZorkConditionHas tempConditionHas = new ZorkConditionHas(
getString((Element) has.item(0)),
getString((Element) object.item(0)),
getString((Element) owner.item(0))
);
conditionsList.add(tempConditionHas);
} else {
NodeList sstatus = condition.getElementsByTagName("status");
ZorkConditionStatus tempConditionStatus = new ZorkConditionStatus(
getString((Element) sstatus.item(0)),
getString((Element) object.item(0))
);
conditionsList.add(tempConditionStatus);
}
}
}
private static <T> Iterable<T> iterable(final NodeList nodeList) {
return () -> new Iterator<>() {
private int index = 0;
@Override
public boolean hasNext() {
return index < nodeList.getLength();
}
@Override
public T next() {
if (!hasNext())
throw new NoSuchElementException();
return (T) nodeList.item(index++);
}
};
}
private static Iterable<Node> iterNodes(final NodeList nodeList) {
return iterable(nodeList);
}
private static Iterable<Element> iterElements(final NodeList nodeList) {
return iterable(nodeList);
}
}