Removed selftest methods (moved to separate unit test project).

git-svn-id: https://andors-trail.googlecode.com/svn/trunk@212 08aca716-68be-ccc6-4d58-36f5abd142ac
This commit is contained in:
oskar.wiksten
2012-01-06 18:59:51 +00:00
parent f6f1353e52
commit ccedafa1ae
11 changed files with 21 additions and 639 deletions

View File

@@ -1,8 +1,6 @@
package com.gpl.rpg.AndorsTrail.context;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.VisualEffectCollection;
import com.gpl.rpg.AndorsTrail.conversation.ConversationCollection;
import com.gpl.rpg.AndorsTrail.conversation.ConversationLoader;
import com.gpl.rpg.AndorsTrail.model.ModelContainer;
import com.gpl.rpg.AndorsTrail.model.ability.ActorConditionTypeCollection;
@@ -16,7 +14,6 @@ import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager;
public class WorldContext {
//Objectcollections
//public final ConversationCollection conversations;
public final ConversationLoader conversationLoader;
public final ItemTypeCollection itemTypes;
public final MonsterTypeCollection monsterTypes;
@@ -61,42 +58,4 @@ public class WorldContext {
public void reset() {
maps.reset();
}
// Selftest method. Not part of the game logic.
public void verifyData(ConversationCollection conversations) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
assert(itemTypes.getItemType("gold") != null);
//Ensure that all phrases that require an item have some droplist that contains them
conversations.verifyData(dropLists);
//Ensure that all phrases are requested at least once, either by NPCs, mapobjects or by other phrases.
conversations.verifyData(monsterTypes, maps);
//Ensure that all required quest stages exist
conversations.verifyData(quests);
//Ensure that all quest stages are required and supplied.
conversations.verifyData(maps);
//Ensure that all conversations that require quest items have quest progress updates
conversations.verifyData(itemTypes);
//Ensure that all quest stages are reachable by phrases
quests.verifyData(conversations);
//Ensure that all NPCs that have a trading conversation also have a droplist
monsterTypes.verifyData(conversations);
//Ensure that all items have at least one corresponding droplist
itemTypes.verifyData(dropLists);
//Ensure that all droplists are used by monsters
dropLists.verifyData(monsterTypes, conversations, maps);
//Ensure that all monsters are used in spawnareas
monsterTypes.verifyData(maps);
}
}
}

View File

@@ -2,20 +2,8 @@ package com.gpl.rpg.AndorsTrail.conversation;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.conversation.Phrase.Reply;
import com.gpl.rpg.AndorsTrail.conversation.Phrase.Reward;
import com.gpl.rpg.AndorsTrail.model.actor.MonsterTypeCollection;
import com.gpl.rpg.AndorsTrail.model.item.DropList;
import com.gpl.rpg.AndorsTrail.model.item.DropListCollection;
import com.gpl.rpg.AndorsTrail.model.item.ItemType;
import com.gpl.rpg.AndorsTrail.model.item.ItemTypeCollection;
import com.gpl.rpg.AndorsTrail.model.map.MapCollection;
import com.gpl.rpg.AndorsTrail.model.quest.QuestCollection;
import com.gpl.rpg.AndorsTrail.model.quest.QuestProgress;
import com.gpl.rpg.AndorsTrail.resource.parsers.ConversationListParser;
import com.gpl.rpg.AndorsTrail.util.L;
@@ -28,15 +16,6 @@ public final class ConversationCollection {
private final HashMap<String, Phrase> phrases = new HashMap<String, Phrase>();
public boolean isValidPhraseID(String id) {
if (id.equals(PHRASE_CLOSE)) return true;
else if (id.equals(PHRASE_SHOP)) return true;
else if (id.equals(PHRASE_ATTACK)) return true;
else if (id.equals(PHRASE_REMOVE)) return true;
else if (phrases.containsKey(id)) return true;
else return false;
}
public Phrase getPhrase(String id) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
if (!phrases.containsKey(id)) {
@@ -50,200 +29,9 @@ public final class ConversationCollection {
public Collection<String> initialize(ConversationListParser parser, String input) {
return parser.parseRows(input, phrases);
}
// Selftest method. Not part of the game logic.
public void verifyData() {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
for (Entry<String, Phrase> e : phrases.entrySet()) {
final String phraseID = e.getKey();
for (Reply r : e.getValue().replies) {
if (!isValidPhraseID(r.nextPhrase)) {
L.log("WARNING: Phrase \"" + phraseID + "\" has reply to non-existing phrase \"" + r.nextPhrase + "\".");
} else if (r.nextPhrase == null || r.nextPhrase.length() <= 0) {
L.log("WARNING: Phrase \"" + phraseID + "\" has a reply that has no nextPhrase.");
} else if (r.nextPhrase.equals(e.getKey())) {
L.log("WARNING: Phrase \"" + phraseID + "\" has a reply that points to itself.");
}
}
boolean hasNextReply = false;
boolean hasOtherReply = false;
for (Reply r : e.getValue().replies) {
if (r.text.equalsIgnoreCase(REPLY_NEXT)) hasNextReply = true;
else hasOtherReply = true;
}
if (hasNextReply && hasOtherReply) {
L.log("WARNING: Phrase \"" + phraseID + "\" has both a \"" + REPLY_NEXT + "\" reply and some other reply.");
}
}
}
}
// Selftest method. Not part of the game logic.
public void verifyData(MapCollection maps) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
HashSet<String> requiredQuestStages = new HashSet<String>();
HashSet<String> suppliedQuestStages = new HashSet<String>();
this.DEBUG_getSuppliedQuestStages(suppliedQuestStages);
maps.DEBUG_getRequiredQuestStages(requiredQuestStages);
this.DEBUG_getRequiredQuestStages(requiredQuestStages);
for (String s : requiredQuestStages) {
if (!suppliedQuestStages.contains(s)) {
L.log("WARNING: Queststage \"" + s + "\" is required but never supplied by any phrases.");
}
}
}
}
// Selftest method. Not part of the game logic.
public void verifyData(DropListCollection droplists) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
for (Entry<String, Phrase> e : phrases.entrySet()) {
for (Reply r : e.getValue().replies) {
if (r.requiresItem()) {
if (!droplists.verifyExistsDroplistForItem(r.requiresItemTypeID)) {
L.log("WARNING: Phrase \"" + e.getKey() + "\" has reply that requires \"" + r.requiresItemTypeID + "\", which is not dropped by any droplist.");
}
}
}
}
}
}
// Selftest method. Not part of the game logic.
public void verifyData(MonsterTypeCollection monsterTypes, MapCollection maps) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
HashSet<String> requiredPhrases = monsterTypes.DEBUG_getRequiredPhrases();
maps.DEBUG_getUsedPhrases(requiredPhrases);
for (Entry<String, Phrase> e : phrases.entrySet()) {
for (Reply r : e.getValue().replies) {
requiredPhrases.add(r.nextPhrase);
}
}
requiredPhrases.remove(PHRASE_ATTACK);
requiredPhrases.remove(PHRASE_CLOSE);
requiredPhrases.remove(PHRASE_SHOP);
requiredPhrases.remove(PHRASE_REMOVE);
// Verify that all supplied phrases are required.
for (Entry<String, Phrase> e : phrases.entrySet()) {
if (!requiredPhrases.contains(e.getKey())) {
L.log("OPTIMIZE: Phrase \"" + e.getKey() + "\" cannot be reached by any monster or other phrase reply.");
}
}
}
}
// Selftest method. Not part of the game logic.
public void verifyData(QuestCollection quests) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
for (Phrase p : phrases.values()) {
if (p.rewards == null) continue;
for (Reward r : p.rewards) {
if (r.rewardType != Reward.REWARD_TYPE_QUEST_PROGRESS) continue;
quests.getQuestLogEntry(new QuestProgress(r.rewardID, r.value)); // Will warn inside if invalid.
}
}
}
}
// Selftest method. Not part of the game logic.
public void verifyData(ItemTypeCollection itemTypes) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
for (Entry<String, Phrase> e : phrases.entrySet()) {
for (Reply r : e.getValue().replies) {
if (!r.requiresItem()) continue;
ItemType itemType = itemTypes.getItemType(r.requiresItemTypeID);
if (r.itemRequirementType == Reply.ITEM_REQUIREMENT_TYPE_WEAR_KEEP) {
if (!itemType.isEquippable()) L.log("WARNING: Phrase \"" + e.getKey() + "\" has a reply that requires a worn \"" + itemType + "\", but the item is not wearable.");
}
if (!itemType.isQuestItem()) continue;
Phrase nextPhrase = getPhrase(r.nextPhrase);
if (!hasQuestProgressReward(nextPhrase)) {
L.log("WARNING: Phrase \"" + e.getKey() + "\" has a reply that requires a questitem, but the next phrase does not add quest progress.");
}
}
}
}
}
private boolean hasQuestProgressReward(Phrase nextPhrase) {
if (nextPhrase.rewards == null) return false;
for (Reward r : nextPhrase.rewards) {
if (r.rewardType == Reward.REWARD_TYPE_QUEST_PROGRESS) return true;
}
return false;
}
// Selftest method. Not part of the game logic.
public void DEBUG_getSuppliedQuestStages(HashSet<String> suppliedStages) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
for (Phrase p : phrases.values()) {
if (p.rewards == null) continue;
for (Reward r : p.rewards) {
if (r.rewardType != Reward.REWARD_TYPE_QUEST_PROGRESS) continue;
QuestProgress progressQuest = new QuestProgress(r.rewardID, r.value);
suppliedStages.add(progressQuest.toString());
}
}
}
}
// Selftest method. Not part of the game logic.
public void DEBUG_getRequiredQuestStages(HashSet<String> requiredStages) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
for (Phrase p : phrases.values()) {
for (Reply r : p.replies) {
if (r.requiresProgress != null) {
requiredStages.add(r.requiresProgress.toString());
}
}
}
}
}
// Selftest method. Not part of the game logic.
public boolean DEBUG_leadsToTradeReply(String phraseID) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
HashSet<String> visited = new HashSet<String>();
return DEBUG_leadsToTradeReply(phraseID, visited);
} else {
return false;
}
}
private boolean DEBUG_leadsToTradeReply(String phraseID, HashSet<String> visited) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
if (phraseID.equals(PHRASE_SHOP)) return true;
if (phraseID.equals(PHRASE_ATTACK)) return false;
if (phraseID.equals(PHRASE_CLOSE)) return false;
if (phraseID.equals(PHRASE_REMOVE)) return false;
if (visited.contains(phraseID)) return false;
visited.add(phraseID);
Phrase p = getPhrase(phraseID);
if (p == null) return false;
for (Reply r : p.replies) {
if (DEBUG_leadsToTradeReply(r.nextPhrase, visited)) return true;
}
}
return false;
}
public void DEBUG_getUsedDroplists(HashSet<DropList> usedDropLists, final DropListCollection dropListCollection) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
for (Phrase p : phrases.values()) {
if (p.rewards == null) continue;
for (Reward r : p.rewards) {
if (r.rewardType != Reward.REWARD_TYPE_DROPLIST) continue;
DropList d = dropListCollection.getDropList(r.rewardID);
if (d != null) usedDropLists.add(d);
}
}
}
// Unit test method. Not part of the game logic.
public HashMap<String, Phrase> UNITTEST_getAllPhrases() {
return phrases;
}
}

View File

@@ -2,20 +2,13 @@ package com.gpl.rpg.AndorsTrail.model.actor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.conversation.ConversationCollection;
import com.gpl.rpg.AndorsTrail.model.item.DropList;
import com.gpl.rpg.AndorsTrail.model.item.DropList.DropItem;
import com.gpl.rpg.AndorsTrail.model.map.MapCollection;
import com.gpl.rpg.AndorsTrail.resource.parsers.MonsterTypeParser;
import com.gpl.rpg.AndorsTrail.util.L;
public final class MonsterTypeCollection {
private final HashMap<String, MonsterType> monsterTypesById = new HashMap<String, MonsterType>();
public final HashMap<String, MonsterType> DEBUG_monsterTypesById = monsterTypesById;
public MonsterType getMonsterType(String id) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
@@ -44,85 +37,10 @@ public final class MonsterTypeCollection {
public void initialize(MonsterTypeParser parser, String input) {
parser.parseRows(input, monsterTypesById);
}
// Selftest method. Not part of the game logic.
public void verifyData(WorldContext world, ConversationCollection conversations) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
for (MonsterType t : monsterTypesById.values()) {
if (t.phraseID != null) {
if (!conversations.isValidPhraseID(t.phraseID)) {
L.log("WARNING: Cannot find phrase \"" + t.phraseID + "\" for MonsterType \"" + t.id + "\".");
}
}
if (t.dropList != null && t.isRespawnable && t.phraseID == null) {
int averageItemDropGold = 0;
for (DropItem item : t.dropList.DEBUG_items) {
averageItemDropGold += item.itemType.baseMarketCost * item.quantity.averagef() * item.chance.current / item.chance.max;
}
float goldPerExpReward = (float) averageItemDropGold / t.exp;
boolean warn = false;
if (goldPerExpReward > 0.5) warn = true;
else if (averageItemDropGold > 30 && goldPerExpReward > 0.3) warn = true;
if (warn) L.log("Monster type " + t.id + " rewards " + averageItemDropGold + " gold drop on average, which is a bit high for the exp: " + t.exp + " (average " + goldPerExpReward + " gold per exp)");
}
}
}
}
// Selftest method. Not part of the game logic.
public void verifyData(ConversationCollection conversations) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
for (MonsterType t : monsterTypesById.values()) {
if (t.phraseID != null && t.phraseID.length() > 0) {
if (conversations.DEBUG_leadsToTradeReply(t.phraseID)) {
if (t.dropList == null) {
L.log("WARNING: MonsterType \"" + t.id + "\" has conversation \"" + t.phraseID + "\" that leads to a trade, but the monster type does not have a droplist.");
}
}
}
}
}
}
// Selftest method. Not part of the game logic.
public void verifyData(MapCollection maps) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
HashSet<String> availableMonsterIDs = new HashSet<String>(monsterTypesById.keySet());
HashSet<String> usedSpawnedMonsterIDs = new HashSet<String>();
maps.DEBUG_getSpawnedMonsterIDs(usedSpawnedMonsterIDs);
availableMonsterIDs.removeAll(usedSpawnedMonsterIDs);
for (String monsterTypeID : availableMonsterIDs) {
L.log("WARNING: MonsterType \"" + monsterTypeID + "\" is never used on any spawnarea.");
}
}
}
// Selftest method. Not part of the game logic.
public HashSet<String> DEBUG_getRequiredPhrases() {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
HashSet<String> requiredPhrases = new HashSet<String>();
for (MonsterType t : monsterTypesById.values()) {
if (t.phraseID != null && t.phraseID.length() > 0) {
requiredPhrases.add(t.phraseID);
}
}
return requiredPhrases;
} else {
return null;
}
}
// Selftest method. Not part of the game logic.
public void DEBUG_getUsedDroplists(HashSet<DropList> usedDroplists) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
for (MonsterType t : monsterTypesById.values()) {
if (t.dropList != null) usedDroplists.add(t.dropList);
}
}
// Unit test method. Not part of the game logic.
public HashMap<String, MonsterType> UNITTEST_getAllMonsterTypes() {
return monsterTypesById;
}
}

View File

@@ -9,15 +9,12 @@ import com.gpl.rpg.AndorsTrail.util.ConstRange;
public final class DropList {
private final DropItem[] items;
public final DropItem[] DEBUG_items;
public DropList(DropItem[] items) {
this.items = items;
this.DEBUG_items = this.items;
}
public DropList(Collection<DropItem> items) {
this.items = items.toArray(new DropItem[items.size()]);
this.DEBUG_items = this.items;
}
public void createRandomLoot(Loot loot, Player player) {
for (DropItem item : items) {
@@ -38,13 +35,10 @@ public final class DropList {
}
}
}
// Selftest method. Not part of the game logic.
public boolean DEBUG_contains(String itemTypeID) {
for (DropItem item : items) {
if (item.itemType.id.equals(itemTypeID)) return true;
}
return false;
// Unit test method. Not part of the game logic.
public DropItem[] UNITTEST_getAllDropItems() {
return items;
}
public static class DropItem {

View File

@@ -1,13 +1,8 @@
package com.gpl.rpg.AndorsTrail.model.item;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.conversation.ConversationCollection;
import com.gpl.rpg.AndorsTrail.model.actor.MonsterTypeCollection;
import com.gpl.rpg.AndorsTrail.model.map.MapCollection;
import com.gpl.rpg.AndorsTrail.resource.parsers.DropListParser;
import com.gpl.rpg.AndorsTrail.util.L;
@@ -30,31 +25,9 @@ public final class DropListCollection {
public void initialize(final DropListParser parser, String input) {
parser.parseRows(input, droplists);
}
// Selftest method. Not part of the game logic.
public boolean verifyExistsDroplistForItem(String itemTypeID) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
for (DropList d : droplists.values()) {
if (d.DEBUG_contains(itemTypeID)) return true;
}
}
return false;
}
// Selftest method. Not part of the game logic.
public void verifyData(MonsterTypeCollection monsterTypes, ConversationCollection conversations, MapCollection maps) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
HashSet<DropList> usedDroplists = new HashSet<DropList>();
monsterTypes.DEBUG_getUsedDroplists(usedDroplists);
conversations.DEBUG_getUsedDroplists(usedDroplists, this);
maps.DEBUG_getUsedDroplists(usedDroplists);
usedDroplists.add(getDropList(DropListCollection.DROPLIST_STARTITEMS));
for (Entry<String, DropList> e : droplists.entrySet()) {
if (!usedDroplists.contains(e.getValue())) {
L.log("OPTIMIZE: Droplist " + e.getKey() + " is not used by any monster or conversation phrase.");
}
}
}
// Unit test method. Not part of the game logic.
public HashMap<String, DropList> UNITTEST_getAllDropLists() {
return droplists;
}
}

View File

@@ -1,5 +1,6 @@
package com.gpl.rpg.AndorsTrail.model.item;
import java.util.Collection;
import java.util.HashMap;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
@@ -28,52 +29,10 @@ public final class ItemTypeCollection {
public void initialize(final ItemTypeParser parser, String input) {
parser.parseRows(input, itemTypes);
}
// Selftest method. Not part of the game logic.
public void verifyData(DropListCollection dropLists) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
for (ItemType t : itemTypes.values()) {
if (!t.hasManualPrice) {
if (t.effects_hit != null || t.effects_kill != null) {
L.log("OPTIMIZE: Item " + t.id + " uses automatic pricing, but has kill- or hit effects. Should probably use manual pricing?");
}
if (t.effects_equip == null && t.effects_use == null) {
L.log("OPTIMIZE: Item " + t.id + " uses automatic pricing, but has no equip- or use effects. Should probably use manual pricing?");
} else if (!t.isUsable() && !t.isEquippable()) {
L.log("OPTIMIZE: Item " + t.id + " uses automatic pricing, but is neither usable nor equippable. Should probably use manual pricing?");
}
} else {
if (t.baseMarketCost != 0 && t.isQuestItem()) {
L.log("OPTIMIZE: Item " + t.id + " is a quest item, but has a base market price specified.");
} else if (t.baseMarketCost == 0 && t.isOrdinaryItem()) {
L.log("OPTIMIZE: Item " + t.id + " does not have a base market price specified (and is an ordinary item).");
}
}
if (t.isEquippable()) {
if (t.effects_equip == null && t.effects_hit == null && t.effects_kill == null ) {
L.log("OPTIMIZE: Item " + t.id + " is equippable, but has no equip effect.");
}
} else {
if (t.effects_equip != null || t.effects_hit != null || t.effects_kill != null ) {
L.log("OPTIMIZE: Item " + t.id + " is not equippable, but has equip, hit or kill effect.");
}
}
if (t.isUsable()) {
if (t.effects_use == null) {
L.log("OPTIMIZE: Item " + t.id + " is usable, but has no use effect.");
}
} else {
if (t.effects_use != null) {
L.log("OPTIMIZE: Item " + t.id + " is not usable, but has use effect.");
}
}
if (!dropLists.verifyExistsDroplistForItem(t.id)) {
L.log("OPTIMIZE: Item " + t.id + " is not dropped by any droplist.");
}
}
}
// Unit test method. Not part of the game logic.
public Collection<ItemType> UNITTEST_getAllItemTypes() {
return itemTypes.values();
}
}

View File

@@ -4,13 +4,9 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.context.WorldContext;
import com.gpl.rpg.AndorsTrail.conversation.ConversationCollection;
import com.gpl.rpg.AndorsTrail.model.item.DropList;
import com.gpl.rpg.AndorsTrail.util.L;
public final class MapCollection {
@@ -34,142 +30,6 @@ public final class MapCollection {
}
}
// Selftest method. Not part of the game logic.
public void verifyData(WorldContext world, ConversationCollection conversations) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
for (PredefinedMap m : predefinedMaps) {
for (MapObject o : m.eventObjects) {
if (o.type == MapObject.MAPEVENT_NEWMAP) {
if (!o.shouldHaveDestinationMap()) continue;
final String desc = "Map \"" + m.name + "\", place \"" + o.id + "\"";
if (o.map == null || o.map.length() <= 0) {
L.log("OPTIMIZE: " + desc + " has no destination map.");
} else if (o.place == null || o.place.length() <= 0) {
L.log("OPTIMIZE: " + desc + " has no destination place.");
} else {
PredefinedMap destination = findPredefinedMap(o.map);
if (destination == null) {
L.log("WARNING: " + desc + " references non-existing destination map \"" + o.map + "\".");
continue;
}
MapObject place = destination.findEventObject(MapObject.MAPEVENT_NEWMAP, o.place);
if (place == null) {
L.log("WARNING: " + desc + " references non-existing destination place \"" + o.place + "\" on map \"" + o.map + "\".");
continue;
}
if (!o.position.size.equals(place.position.size)) {
L.log("WARNING: " + desc + " references destination place \"" + o.place + "\" on map \"" + o.map + "\", with different mapchange size.");
continue;
}
if (place.shouldHaveDestinationMap()) {
if (!m.name.equalsIgnoreCase(place.map)) {
L.log("WARNING: " + desc + " references destination place \"" + o.place + "\" on map \"" + o.map + "\", but that place does not reference back to this map.");
continue;
}
if (!o.id.equalsIgnoreCase(place.place)) {
L.log("WARNING: " + desc + " references destination place \"" + o.place + "\" on map \"" + o.map + "\", but that place does not reference back to this place.");
continue;
}
}
}
if (m.findEventObject(MapObject.MAPEVENT_NEWMAP, o.id) != o) {
L.log("WARNING: Map \"" + m.name + "\" contains duplicate maparea with id \"" + o.id + "\".");
continue;
}
} else if (o.type == MapObject.MAPEVENT_KEYAREA) {
if (o.id == null || o.id.length() <= 0) {
L.log("WARNING: Map \"" + m.name + "\" contains keyarea without phraseid.");
continue;
}
conversations.getPhrase(o.id); // Will warn inside if not available.
} else if (o.type == MapObject.MAPEVENT_SIGN) {
if (o.id == null || o.id.length() <= 0) {
L.log("WARNING: Map \"" + m.name + "\" contains sign without phraseid.");
continue;
}
conversations.getPhrase(o.id); // Will warn inside if not available.
} else if (o.type == MapObject.MAPEVENT_REST) {
if (o.id == null || o.id.length() <= 0) {
L.log("WARNING: Map \"" + m.name + "\" contains rest area without id.");
continue;
}
if (m.findEventObject(MapObject.MAPEVENT_REST, o.id) != o) {
L.log("WARNING: Map \"" + m.name + "\" contains duplicate rest area with id \"" + o.id + "\".");
continue;
}
}
}
for (int i = 0; i < m.spawnAreas.length; ++i) {
MonsterSpawnArea uniqueArea = m.spawnAreas[i];
if (!uniqueArea.isUnique) continue;
for (int j = 0; j < i; ++j) {
MonsterSpawnArea nonUniqueArea = m.spawnAreas[j];
if (nonUniqueArea.isUnique) continue;
if (nonUniqueArea.area.intersects(uniqueArea.area)) {
L.log("WARNING: Map \"" + m.name + "\" contains unique spawnarea at " + uniqueArea.area.toString() + " that intersects a nonunique spawnarea. Consider placing the unique spawn first to make sure that this monster has a place to spawn.");
}
}
}
}
}
}
// Selftest method. Not part of the game logic.
public void DEBUG_getRequiredQuestStages(HashSet<String> requiredStages) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
for (PredefinedMap m : predefinedMaps) {
for (MapObject o : m.eventObjects) {
if (o.type == MapObject.MAPEVENT_KEYAREA) {
if (o.requireQuestProgress == null) continue;
requiredStages.add(o.requireQuestProgress.toString());
}
}
}
}
}
// Selftest method. Not part of the game logic.
public void DEBUG_getUsedPhrases(HashSet<String> usedPhrases) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
for (PredefinedMap m : predefinedMaps) {
for (MapObject o : m.eventObjects) {
if (o.type == MapObject.MAPEVENT_KEYAREA || o.type == MapObject.MAPEVENT_SIGN) {
if (o.id == null || o.id.length() <= 0) continue;
usedPhrases.add(o.id);
}
}
}
}
}
// Selftest method. Not part of the game logic.
public void DEBUG_getUsedDroplists(HashSet<DropList> usedDropLists) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
for (PredefinedMap m : predefinedMaps) {
for (MapObject o : m.eventObjects) {
if (o.dropList != null) usedDropLists.add(o.dropList);
}
}
}
}
// Selftest method. Not part of the game logic.
public void DEBUG_getSpawnedMonsterIDs(HashSet<String> usedMonsterTypeIDs) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
for (PredefinedMap m : predefinedMaps) {
for (MonsterSpawnArea a : m.spawnAreas) {
usedMonsterTypeIDs.addAll(Arrays.asList(a.monsterTypeIDs));
}
}
}
}
// ====== PARCELABLE ===================================================================

View File

@@ -44,10 +44,4 @@ public final class MapObject {
public static MapObject createNewContainerArea(final CoordRect position, final DropList dropList) {
return new MapObject(position, MAPEVENT_CONTAINER, null, null, null, null, dropList);
}
public boolean shouldHaveDestinationMap() {
if (type != MAPEVENT_NEWMAP) return false;
if (id.equals("exit")) return false;
return true;
}
}

View File

@@ -4,10 +4,8 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
import com.gpl.rpg.AndorsTrail.conversation.ConversationCollection;
import com.gpl.rpg.AndorsTrail.resource.parsers.QuestParser;
import com.gpl.rpg.AndorsTrail.util.L;
@@ -45,47 +43,4 @@ public final class QuestCollection {
public void initialize(QuestParser parser, String input) {
parser.parseRows(input, quests);
}
// Selftest method. Not part of the game logic.
public void verifyData() {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
for (Quest q : quests.values()) {
if (q.name.trim().length() <= 0) {
L.log("WARNING: Quest \"" + q.questID + "\" has empty name.");
}
if (q.stages.length <= 0) {
L.log("WARNING: Quest \"" + q.questID + "\" has no log entries.");
}
boolean hasFinishingEntry = false;
for (QuestLogEntry entry : q.stages) {
if (entry.finishesQuest) hasFinishingEntry = true;
if (entry.rewardExperience == 1) {
L.log("WARNING: Quest \"" + q.questID + "\" has stage " + entry.progress + " that rewards just 1 exp. Might be malformed resourcefile?");
}
}
if (q.showInLog) {
if (!hasFinishingEntry) {
L.log("WARNING: Quest \"" + q.questID + "\" is shown in log, but has no progress stage that finishes the quest.");
}
}
}
}
}
// Selftest method. Not part of the game logic.
public void verifyData(ConversationCollection conversations) {
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
final HashSet<String> suppliedStages = new HashSet<String>();
conversations.DEBUG_getSuppliedQuestStages(suppliedStages);
for (Quest q : quests.values()) {
for (QuestLogEntry e : q.stages) {
String s = q.questID + ":" + e.progress;
if (!suppliedStages.contains(s)) {
L.log("OPTIMIZE: Quest stage \"" + s + "\" cannot be reached by any conversation phrase.");
}
}
}
}
}
}

View File

@@ -112,9 +112,6 @@ public final class ResourceLoader {
for (int i = 0; i < questsToLoad.length(); ++i) {
world.quests.initialize(questParser, questsToLoad.getString(i));
}
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
world.quests.verifyData();
}
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) timingCheckpoint("QuestParser");
@@ -122,14 +119,11 @@ public final class ResourceLoader {
// Load conversations
final ConversationListParser conversationListParser = new ConversationListParser();
final TypedArray conversationsListsToLoad = r.obtainTypedArray(conversationsListsResourceId);
ConversationCollection conversations = new ConversationCollection();
for (int i = 0; i < conversationsListsToLoad.length(); ++i) {
ConversationCollection conversations = new ConversationCollection();
Collection<String> ids = conversations.initialize(conversationListParser, conversationsListsToLoad.getString(i));
world.conversationLoader.addIDs(conversationsListsToLoad.getResourceId(i, -1), ids);
}
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
conversations.verifyData();
}
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) timingCheckpoint("ConversationListParser");
@@ -140,10 +134,6 @@ public final class ResourceLoader {
for (int i = 0; i < monstersToLoad.length(); ++i) {
world.monsterTypes.initialize(monsterTypeParser, monstersToLoad.getString(i));
}
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
world.monsterTypes.verifyData(world, conversations);
}
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) timingCheckpoint("MonsterTypeParser");
@@ -160,10 +150,6 @@ public final class ResourceLoader {
world.maps.predefinedMaps.addAll(mapReader.transformMaps(loader, world.monsterTypes, world.dropLists));
mapReader = null;
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) timingCheckpoint("mapReader.transformMaps");
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
world.maps.verifyData(world, conversations);
}
// ========================================================================
@@ -174,11 +160,6 @@ public final class ResourceLoader {
// ========================================================================
if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) {
world.verifyData(conversations);
}
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) timingCheckpoint("world.verifyData()");
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
long duration = System.currentTimeMillis() - start;
L.log("ResourceLoader ran for " + duration + " ms.");

View File

@@ -44,7 +44,8 @@ public final class ConversationListParser extends ResourceParserFor<Phrase> {
if (questProgress != null) rewards.add(new Reward(Reward.REWARD_TYPE_QUEST_PROGRESS, questProgress.questID, questProgress.progress));
String rewardDroplist = ResourceParserUtils.parseNullableString(parts[3]);
if (rewardDroplist != null) rewards.add(new Reward(Reward.REWARD_TYPE_DROPLIST, rewardDroplist, 0));
final Reward[] _rewards = rewards.toArray(new Reward[rewards.size()]);
Reward[] _rewards = rewards.toArray(new Reward[rewards.size()]);
if (_rewards.length == 0) _rewards = null;
return new Pair<String, Phrase>(parts[0], new Phrase(
ResourceParserUtils.parseNullableString(parts[1]) // message