From: oskar.wiksten Date: Thu, 5 Jan 2012 20:14:53 +0000 (+0000) Subject: Updated reward system for conversations. Rewards can now be skills or actorconditions... X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=e5e119936ebe2a1ee0896c3730c134ee102b1b2c;p=users%2Fmchehab%2Fandors-trail.git Updated reward system for conversations. Rewards can now be skills or actorconditions and not just items and quest progress as before. Item requirements for selecting conversation replies now also support rrequring the player to be wearing a specific item, and having a requirement without removing the item when selecting the reply. git-svn-id: https://andors-trail.googlecode.com/svn/trunk@210 08aca716-68be-ccc6-4d58-36f5abd142ac --- diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ConversationActivity.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ConversationActivity.java index 7ac388e..2807c07 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ConversationActivity.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/ConversationActivity.java @@ -207,9 +207,9 @@ public final class ConversationActivity extends Activity implements OnKeyListene phrase = world.conversationLoader.loadPhrase(phraseID, conversationCollection, getResources()); if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) { - if (phrase == null) phrase = new Phrase("(phrase \"" + phraseID + "\" not implemented yet)", null, null, null); + if (phrase == null) phrase = new Phrase("(phrase \"" + phraseID + "\" not implemented yet)", null, null); } - Loot loot = ConversationController.applyPhraseEffect(player, phrase, world.quests, world.dropLists); + Loot loot = ConversationController.applyPhraseRewards(player, phrase, world); if (phrase.message == null) { for (Reply r : phrase.replies) { diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity_Skills.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity_Skills.java index 37fe200..15be691 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity_Skills.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/activity/HeroinfoActivity_Skills.java @@ -57,7 +57,7 @@ public final class HeroinfoActivity_Skills extends Activity { if (resultCode != RESULT_OK) break; int skillID = data.getExtras().getInt("skillID"); - player.addSkillLevel(skillID); + player.addSkillLevel(skillID, true); break; } } diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/ActorStatsController.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/ActorStatsController.java index eba2f07..25cd011 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/ActorStatsController.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/ActorStatsController.java @@ -47,20 +47,48 @@ public class ActorStatsController { } } - private static void applyActorCondition(Actor actor, ActorConditionEffect e) { applyActorCondition(actor, e, e.duration); } + public static void applyActorCondition(Actor actor, ActorConditionEffect e) { applyActorCondition(actor, e, e.duration); } private static void applyActorCondition(Actor actor, ActorConditionEffect e, int duration) { - final ActorConditionType type = e.conditionType; if (e.isRemovalEffect()) { - removeAllConditionsOfType(actor, type.conditionTypeID); + removeAllConditionsOfType(actor, e.conditionType.conditionTypeID); } else if (e.magnitude > 0) { - if (!e.conditionType.isStacking) { - if (actor.hasCondition(type.conditionTypeID)) return; - //TODO: Maybe only keep the one with the highest magnitude? + if (e.conditionType.isStacking) { + addStackableActorCondition(actor, e, duration); + } else { + addNonStackableActorCondition(actor, e, duration); } - actor.conditions.add(e.createCondition(duration)); } } + private static void addStackableActorCondition(Actor actor, ActorConditionEffect e, int duration) { + final ActorConditionType type = e.conditionType; + int magnitude = e.magnitude; + + for(int i = actor.conditions.size() - 1; i >= 0; --i) { + ActorCondition c = actor.conditions.get(i); + if (!type.conditionTypeID.equals(c.conditionType.conditionTypeID)) continue; + if (c.duration == duration) { + // If the actor already has a condition of this type and the same duration, just increase the magnitude instead. + actor.conditions.remove(i); + magnitude += c.magnitude; + break; + } + } + actor.conditions.add(new ActorCondition(type, magnitude, duration)); + } + private static void addNonStackableActorCondition(Actor actor, ActorConditionEffect e, int duration) { + final ActorConditionType type = e.conditionType; + + for(int i = actor.conditions.size() - 1; i >= 0; --i) { + ActorCondition c = actor.conditions.get(i); + if (!type.conditionTypeID.equals(c.conditionType.conditionTypeID)) continue; + if (c.magnitude > e.magnitude) return; + // If the actor already has this condition, but of a lower magnitude, we remove the old one and add this higher magnitude. + actor.conditions.remove(i); + } + actor.conditions.add(e.createCondition(duration)); + } + public static void removeAllTemporaryConditions(final Actor actor) { for(int i = actor.conditions.size() - 1; i >= 0; --i) { if (!actor.conditions.get(i).isTemporaryEffect()) continue; diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/ConversationController.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/ConversationController.java index 4a86afd..44bbb3a 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/ConversationController.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/controller/ConversationController.java @@ -1,53 +1,78 @@ package com.gpl.rpg.AndorsTrail.controller; +import com.gpl.rpg.AndorsTrail.context.WorldContext; import com.gpl.rpg.AndorsTrail.conversation.Phrase; import com.gpl.rpg.AndorsTrail.conversation.Phrase.Reply; +import com.gpl.rpg.AndorsTrail.conversation.Phrase.Reward; +import com.gpl.rpg.AndorsTrail.model.ability.ActorCondition; +import com.gpl.rpg.AndorsTrail.model.ability.ActorConditionEffect; +import com.gpl.rpg.AndorsTrail.model.ability.ActorConditionType; import com.gpl.rpg.AndorsTrail.model.actor.Player; -import com.gpl.rpg.AndorsTrail.model.item.DropListCollection; import com.gpl.rpg.AndorsTrail.model.item.ItemTypeCollection; import com.gpl.rpg.AndorsTrail.model.item.Loot; -import com.gpl.rpg.AndorsTrail.model.quest.QuestCollection; import com.gpl.rpg.AndorsTrail.model.quest.QuestLogEntry; import com.gpl.rpg.AndorsTrail.model.quest.QuestProgress; +import com.gpl.rpg.AndorsTrail.util.ConstRange; public final class ConversationController { - public static Loot applyPhraseEffect(final Player player, final Phrase phrase, final QuestCollection questcollection, final DropListCollection dropListCollection) { - if (phrase.rewardDropListID == null && phrase.progressQuest == null) return null; + private static final ConstRange always = new ConstRange(1, 1); + + public static Loot applyPhraseRewards(final Player player, final Phrase phrase, final WorldContext world) { + if (phrase.rewards == null || phrase.rewards.length == 0) return null; final Loot loot = new Loot(); - if (phrase.rewardDropListID != null) { - dropListCollection.getDropList(phrase.rewardDropListID).createRandomLoot(loot, player); - player.inventory.add(loot); - } - if (phrase.progressQuest != null) { - boolean added = player.addQuestProgress(phrase.progressQuest); - if (added) { // Only apply exp reward if the quest stage was reached just now (and not re-reached) - QuestLogEntry stage = questcollection.getQuestLogEntry(phrase.progressQuest); - if (stage != null) { - loot.exp = stage.rewardExperience; - player.addExperience(stage.rewardExperience); + for (Reward reward : phrase.rewards) { + switch (reward.rewardType) { + case Reward.REWARD_TYPE_ACTOR_CONDITION: + int magnitude = 1; + int duration = reward.value; + if (reward.value == ActorCondition.DURATION_FOREVER) duration = ActorCondition.DURATION_FOREVER; + else if (reward.value == ActorCondition.MAGNITUDE_REMOVE_ALL) magnitude = ActorCondition.MAGNITUDE_REMOVE_ALL; + + ActorConditionType conditionType = world.actorConditionsTypes.getActorConditionType(reward.rewardID); + ActorConditionEffect e = new ActorConditionEffect(conditionType, magnitude, duration, always); + ActorStatsController.applyActorCondition(player, e); + break; + case Reward.REWARD_TYPE_SKILL_INCREASE: + player.addSkillLevel(Integer.parseInt(reward.rewardID), false); + break; + case Reward.REWARD_TYPE_DROPLIST: + world.dropLists.getDropList(reward.rewardID).createRandomLoot(loot, player); + break; + case Reward.REWARD_TYPE_QUEST_PROGRESS: + QuestProgress progress = new QuestProgress(reward.rewardID, reward.value); + boolean added = player.addQuestProgress(progress); + if (added) { // Only apply exp reward if the quest stage was reached just now (and not re-reached) + QuestLogEntry stage = world.quests.getQuestLogEntry(progress); + if (stage != null) { + loot.exp += stage.rewardExperience; + } } + break; } } + + player.inventory.add(loot); + player.addExperience(loot.exp); return loot; } public static void applyReplyEffect(final Player player, final Reply reply) { if (!reply.requiresItem()) return; - if (ItemTypeCollection.isGoldItemType(reply.requiresItemTypeID)) { - player.inventory.gold -= reply.requiresItemQuantity; - } else { - player.inventory.removeItem(reply.requiresItemTypeID, reply.requiresItemQuantity); + if (reply.itemRequirementType == Reply.ITEM_REQUIREMENT_TYPE_INVENTORY_REMOVE) { + if (ItemTypeCollection.isGoldItemType(reply.requiresItemTypeID)) { + player.inventory.gold -= reply.requiresItemQuantity; + } else { + player.inventory.removeItem(reply.requiresItemTypeID, reply.requiresItemQuantity); + } } } public static boolean canSelectReply(final Player player, final Reply reply) { if (!hasRequiredQuestProgress(player, reply.requiresProgress)) return false; - if (reply.requiresItem()) { - if (!hasRequiredItems(player, reply.requiresItemTypeID, reply.requiresItemQuantity)) return false; - } + if (!hasRequiredItems(player, reply)) return false; return true; } @@ -56,10 +81,16 @@ public final class ConversationController { return player.hasExactQuestProgress(progress); } - private static boolean hasRequiredItems(final Player player, String requiresItemTypeID, int requiresItemQuantity) { - if (ItemTypeCollection.isGoldItemType(requiresItemTypeID)) return player.inventory.gold >= requiresItemQuantity; - - return player.inventory.hasItem(requiresItemTypeID, requiresItemQuantity); + private static boolean hasRequiredItems(final Player player, Reply reply) { + if (!reply.requiresItem()) return true; + + if (ItemTypeCollection.isGoldItemType(reply.requiresItemTypeID)) { + return player.inventory.gold >= reply.requiresItemQuantity; + } else if (reply.itemRequirementType == Reply.ITEM_REQUIREMENT_TYPE_WEAR_KEEP) { + return player.inventory.isWearing(reply.requiresItemTypeID); + } else { + return player.inventory.hasItem(reply.requiresItemTypeID, reply.requiresItemQuantity); + } } public static String getDisplayMessage(Phrase phrase, Player player) { return replacePlayerName(phrase.message, player); } diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/ConversationCollection.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/ConversationCollection.java index f290862..5c08588 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/ConversationCollection.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/ConversationCollection.java @@ -7,6 +7,7 @@ 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; @@ -14,6 +15,7 @@ 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; @@ -137,9 +139,11 @@ public final class ConversationCollection { public void verifyData(QuestCollection quests) { if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) { for (Phrase p : phrases.values()) { - if (p.progressQuest != null) { - quests.getQuestLogEntry(p.progressQuest); // Will warn inside if invalid. - } + 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. + } } } } @@ -151,10 +155,15 @@ public final class ConversationCollection { 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 (nextPhrase.progressQuest == null) { + 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."); } } @@ -162,12 +171,24 @@ public final class ConversationCollection { } } + 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 suppliedStages) { if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) { for (Phrase p : phrases.values()) { - if (p.progressQuest == null) continue; - suppliedStages.add(p.progressQuest.toString()); + 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()); + } } } } @@ -215,8 +236,11 @@ public final class ConversationCollection { public void DEBUG_getUsedDroplists(HashSet usedDropLists, final DropListCollection dropListCollection) { if (AndorsTrailApplication.DEVELOPMENT_VALIDATEDATA) { for (Phrase p : phrases.values()) { - if (p.rewardDropListID != null) { - DropList d = dropListCollection.getDropList(p.rewardDropListID); + 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); } } diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/Phrase.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/Phrase.java index e5f8e4e..f9915a0 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/Phrase.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/conversation/Phrase.java @@ -7,23 +7,26 @@ public final class Phrase { public final String message; public final Reply[] replies; - public final QuestProgress progressQuest; // If this phrase is reached, this quest will be updated. - public final String rewardDropListID; // If this phrase is reached, player will be awarded all these items + public final Reward[] rewards; // If this phrase is reached, player will be awarded all these rewards - public Phrase(String message, Reply[] replies, QuestProgress progressQuest, String rewardDropListID) { + public Phrase(String message, Reply[] replies, Reward[] rewards) { this.message = message; if (replies == null) replies = NO_REPLIES; this.replies = replies; - this.progressQuest = progressQuest; - this.rewardDropListID = rewardDropListID; + this.rewards = rewards; } public static final class Reply { + public static final int ITEM_REQUIREMENT_TYPE_INVENTORY_REMOVE = 0; // Player must have item(s) in inventory. Items will be removed when selecting reply. + public static final int ITEM_REQUIREMENT_TYPE_INVENTORY_KEEP = 1; // Player must have item(s) in inventory. Items will NOT be removed when selecting reply. + public static final int ITEM_REQUIREMENT_TYPE_WEAR_KEEP = 2; // Player must be wearing item(s). Items will NOT be removed when selecting reply. + public final String text; public final String nextPhrase; public final QuestProgress requiresProgress; public final String requiresItemTypeID; public final int requiresItemQuantity; + public final int itemRequirementType; public boolean requiresItem() { if (requiresItemTypeID == null) return false; @@ -31,12 +34,30 @@ public final class Phrase { return true; } - public Reply(String text, String nextPhrase, QuestProgress requiresProgress, String requiresItemTypeID, int requiresItemQuantity) { + public Reply(String text, String nextPhrase, QuestProgress requiresProgress, String requiresItemTypeID, int requiresItemQuantity, int itemRequirementType) { this.text = text; this.nextPhrase = nextPhrase; this.requiresProgress = requiresProgress; this.requiresItemTypeID = requiresItemTypeID; this.requiresItemQuantity = requiresItemQuantity; + this.itemRequirementType = itemRequirementType; + } + } + + public static final class Reward { + public static final int REWARD_TYPE_QUEST_PROGRESS = 0; + public static final int REWARD_TYPE_DROPLIST = 1; + public static final int REWARD_TYPE_SKILL_INCREASE = 2; + public static final int REWARD_TYPE_ACTOR_CONDITION = 3; + + public final int rewardType; + public final String rewardID; + public final int value; + + public Reward(int rewardType, String rewardID, int value) { + this.rewardType = rewardType; + this.rewardID = rewardID; + this.value = value; } } } diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Player.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Player.java index d8f0cb7..23a9ec0 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Player.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/actor/Player.java @@ -136,11 +136,13 @@ public final class Player extends Actor { public boolean hasSkill(int skillID) { return getSkillLevel(skillID) > 0; } - public void addSkillLevel(int skillID) { - if (!hasAvailableSkillpoints()) return; + public void addSkillLevel(int skillID, boolean requireAvailableSkillpoint) { + if (requireAvailableSkillpoint) { + if (!hasAvailableSkillpoints()) return; + --availableSkillIncreases; + } if (!skillLevels.containsKey(skillID)) skillLevels.put(skillID, 1); else skillLevels.put(skillID, skillLevels.get(skillID) + 1); - --availableSkillIncreases; ActorStatsController.recalculatePlayerCombatTraits(this); } public boolean nextLevelAddsNewSkillpoint() { diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/Inventory.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/Inventory.java index e1e9fb2..807c507 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/Inventory.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/model/item/Inventory.java @@ -24,6 +24,14 @@ public final class Inventory extends ItemContainer { public boolean isEmptySlot(int slot) { return wear[slot] == null; } + + public boolean isWearing(String itemTypeID) { + for(int i = 0; i < NUM_WORN_SLOTS; ++i) { + if (wear[i] == null) continue; + if (wear[i].id.equals(itemTypeID)) return true; + } + return false; + } // ====== PARCELABLE =================================================================== diff --git a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/parsers/ConversationListParser.java b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/parsers/ConversationListParser.java index ef6245f..06980dd 100644 --- a/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/parsers/ConversationListParser.java +++ b/AndorsTrail/src/com/gpl/rpg/AndorsTrail/resource/parsers/ConversationListParser.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import com.gpl.rpg.AndorsTrail.conversation.Phrase; import com.gpl.rpg.AndorsTrail.conversation.Phrase.Reply; +import com.gpl.rpg.AndorsTrail.conversation.Phrase.Reward; import com.gpl.rpg.AndorsTrail.model.quest.QuestProgress; import com.gpl.rpg.AndorsTrail.resource.ResourceFileTokenizer; import com.gpl.rpg.AndorsTrail.resource.ResourceFileTokenizer.ResourceParserFor; @@ -25,6 +26,7 @@ public final class ConversationListParser extends ResourceParserFor { , QuestProgress.parseQuestProgress(parts[2]) // requiresProgress , ResourceParserUtils.parseNullableString(parts[3]) // requiresItemType , ResourceParserUtils.parseInt(parts[4], 0) // requiresItemQuantity + , Reply.ITEM_REQUIREMENT_TYPE_INVENTORY_REMOVE // itemRequirementType ); } }; @@ -37,11 +39,17 @@ public final class ConversationListParser extends ResourceParserFor { replyResourceTokenizer.tokenizeArray(parts[4], replies, replyParser); final Reply[] _replies = replies.toArray(new Reply[replies.size()]); + final ArrayList rewards = new ArrayList(); + QuestProgress questProgress = QuestProgress.parseQuestProgress(parts[2]); + 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()]); + return new Pair(parts[0], new Phrase( ResourceParserUtils.parseNullableString(parts[1]) // message , _replies // replies - , QuestProgress.parseQuestProgress(parts[2]) // questProgress - , ResourceParserUtils.parseNullableString(parts[3]) // rewardDroplist + , _rewards // rewards )); } }