diff --git a/src/engine/QuestSystem/QuestManager.java b/src/engine/QuestSystem/QuestManager.java new file mode 100644 index 00000000..a24b38af --- /dev/null +++ b/src/engine/QuestSystem/QuestManager.java @@ -0,0 +1,112 @@ +package engine.QuestSystem; + +import engine.InterestManagement.WorldGrid; +import engine.net.client.msg.ErrorPopupMsg; +import engine.objects.*; +import engine.server.MBServerStatics; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Random; + +public class QuestManager { + public static HashMap acceptedQuests; + public static HashMap> completedQuests; + + public static boolean grantsQuest(NPC npc){ + if(npc == null) + return false; + + if(npc.contract == null) + return false; + + return npc.contract.getName().contains("ZoneLore") || npc.contract.getName().equals("Barrowlands Sentry"); + } + + public static void displayCurrentQuest(PlayerCharacter pc){ + if(acceptedQuests.containsKey(pc)){ + QuestObject obj = acceptedQuests.get(pc); + String output = "You have embarked on the noble quest: "; + output += obj.QuestName + ". "; + output += obj.description; + output += ". " + obj.objectiveCount + " / " + obj.objectiveCountRequired; + ErrorPopupMsg.sendErrorMsg(pc, output); + }else{ + ErrorPopupMsg.sendErrorMsg(pc, "You have no active quest."); + } + } + + public static void acceptQuest(PlayerCharacter pc, QuestObject obj){ + if (completedQuests.containsKey(pc)) { + if(completedQuests.get(pc).contains(obj.QuestName)){ + ErrorPopupMsg.sendErrorMsg(pc, "You have already completed the quest: " + obj.QuestName); + return; + } + } + + if(acceptedQuests.containsKey(pc)){ + if(acceptedQuests.get(pc)!= null){ + ErrorPopupMsg.sendErrorMsg(pc, "You have already embarked on a noble quest."); + return; + } + } + + acceptedQuests.put(pc,obj); + } + + public static void completeQuest(PlayerCharacter pc, QuestObject obj){ + //notify the player they have completed their quest + ErrorPopupMsg.sendErrorMsg(pc, "You have completed the quest: " + obj.QuestName); + + //add completed quest to completion log + if (completedQuests.containsKey(pc)) { + completedQuests.get(pc).add(obj.QuestName); + }else{ + ArrayList completed = new ArrayList<>(); + completed.add(obj.QuestName); + completedQuests.put(pc,completed); + } + + //remove current quest from active log + if(acceptedQuests.containsKey(pc)) + acceptedQuests.remove(pc); + + //grant rewards + pc.grantXP((int) (Experience.maxXPPerKill(pc.getLevel()) * 10)); + pc.getCharItemManager().addGoldToInventory((int) Experience.maxXPPerKill(pc.getLevel()),false); + pc.getCharItemManager().updateInventory(); + } + + public static QuestObject getQuestForContract(NPC npc){ + QuestObject obj = new QuestObject(); + obj.QuestName = npc.getFirstName() + "'s Quest"; + + HashSet mobs = WorldGrid.getObjectsInRangePartial(npc.loc,2048, MBServerStatics.MASK_MOB); + if (mobs.isEmpty()) + return null; // Handle the case where the set is empty + + // Convert HashSet to a List + ArrayList mobList = new ArrayList<>(mobs); + + // Generate a random index + Random random = new Random(); + int randomIndex = random.nextInt(mobList.size()); + + + if(mobList.get(randomIndex) == null) { + return null; + } + + Mob mob = (Mob) mobList.get(randomIndex); + + obj.progressionNames = new ArrayList<>(); + obj.progressionNames.add(mob.getFirstName()); + + obj.objectiveCountRequired = 10; + obj.objectiveCount = 0; + + obj.description = "These lands are plagued with " + mob.getFirstName() + " complete the quest by slaying 10 of them!"; + return obj; + } +} diff --git a/src/engine/QuestSystem/QuestObject.java b/src/engine/QuestSystem/QuestObject.java new file mode 100644 index 00000000..802b79a6 --- /dev/null +++ b/src/engine/QuestSystem/QuestObject.java @@ -0,0 +1,31 @@ +package engine.QuestSystem; + +import engine.objects.ItemBase; +import engine.objects.NPC; +import engine.objects.PlayerCharacter; + +import java.util.ArrayList; + +public class QuestObject { + + public String QuestName; + public String description; + public int objectiveCount; + public int objectiveCountRequired; + public ArrayList progressionNames; + public PlayerCharacter owner; + + public QuestObject(){ + + } + public void tryProgress(String option){ + if(this.progressionNames.contains(option)) + this.objectiveCount++; + else + return; + + if(this.objectiveCount >= this.objectiveCountRequired){ + QuestManager.completeQuest(this.owner,this); + } + } +} diff --git a/src/engine/gameManager/ChatManager.java b/src/engine/gameManager/ChatManager.java index 496cfb6c..cf6ff551 100644 --- a/src/engine/gameManager/ChatManager.java +++ b/src/engine/gameManager/ChatManager.java @@ -14,6 +14,7 @@ import engine.Enum.GameObjectType; import engine.Enum.ModType; import engine.Enum.SourceType; import engine.InterestManagement.WorldGrid; +import engine.QuestSystem.QuestManager; import engine.db.archive.BaneRecord; import engine.db.archive.PvpRecord; import engine.net.Dispatch; @@ -108,9 +109,9 @@ public enum ChatManager { ChatManager.chatIC(pc, (ChatICMsg) msg); return; case LEADERCHANNELMESSAGE: + case GLOBALCHANNELMESSAGE: ChatManager.chatGlobal(pc, msg.getMessage(), isFlood); return; - case GLOBALCHANNELMESSAGE: case CHATPVP: case CHATCITY: case CHATINFO: @@ -199,6 +200,11 @@ public enum ChatManager { return; } + if(text.equalsIgnoreCase("show_quest()")){ + QuestManager.displayCurrentQuest(pcSender); + return; + } + if (ChatManager.isVersionRequest(text) == true) { sendSystemMessage(pcSender, ConfigManager.MB_WORLD_GREETING.getValue()); return; diff --git a/src/engine/net/client/msg/VendorDialogMsg.java b/src/engine/net/client/msg/VendorDialogMsg.java index 119be892..b457cd68 100644 --- a/src/engine/net/client/msg/VendorDialogMsg.java +++ b/src/engine/net/client/msg/VendorDialogMsg.java @@ -11,6 +11,7 @@ package engine.net.client.msg; import engine.Enum.DispatchChannel; import engine.Enum.GuildHistoryType; +import engine.QuestSystem.QuestManager; import engine.exception.MsgSendException; import engine.gameManager.BuildingManager; import engine.gameManager.DbManager; @@ -125,18 +126,22 @@ public class VendorDialogMsg extends ClientNetMsg { vd = Contract.HandleBaneCommanderOptions(msg.unknown03, npc, playerCharacter); msg.updateMessage(3, vd); }else { - - if (contract == null) - vd = VendorDialog.getHostileVendorDialog(); - else if (npc.getBuilding() != null) { - if (npc.getBuilding() != null && BuildingManager.IsPlayerHostile(npc.getBuilding(), playerCharacter)) + if(QuestManager.grantsQuest(npc)){ + vd = Contract.HandleQuestOptions(msg.unknown03, npc, playerCharacter); + msg.updateMessage(3, vd); + }else { + if (contract == null) vd = VendorDialog.getHostileVendorDialog(); - else + else if (npc.getBuilding() != null) { + if (npc.getBuilding() != null && BuildingManager.IsPlayerHostile(npc.getBuilding(), playerCharacter)) + vd = VendorDialog.getHostileVendorDialog(); + else + vd = contract.getVendorDialog(); + } else vd = contract.getVendorDialog(); - } else - vd = contract.getVendorDialog(); - if (vd == null) - vd = VendorDialog.getHostileVendorDialog(); + if (vd == null) + vd = VendorDialog.getHostileVendorDialog(); + } if (msg.messageType == 1 || msg.unknown03 == vd.getObjectUUID()) { msg.updateMessage(3, vd); } else { diff --git a/src/engine/objects/Contract.java b/src/engine/objects/Contract.java index f506d399..ee79f95d 100644 --- a/src/engine/objects/Contract.java +++ b/src/engine/objects/Contract.java @@ -11,6 +11,7 @@ package engine.objects; import ch.claude_martin.enumbitset.EnumBitSet; import engine.Enum; +import engine.QuestSystem.QuestManager; import engine.gameManager.*; import engine.net.Dispatch; import engine.net.DispatchMessage; @@ -477,6 +478,23 @@ public class Contract extends AbstractGameObject { return vd; } + public static VendorDialog HandleQuestOptions(int optionId, NPC npc, PlayerCharacter pc){ + VendorDialog vd = new VendorDialog(npc.contract.getVendorDialog().getDialogType(),npc.contract.getVendorDialog().getIntro(),-1); + //vd.getOptions().clear(); + switch(optionId) { + default: + if (pc.isBoxed) { + MenuOption optionAcceptQuest = new MenuOption(25020401, "Accept Quest", 25020401); + vd.getOptions().add(optionAcceptQuest); + } + break; + case 25020401: + QuestManager.acceptQuest(pc,QuestManager.getQuestForContract(npc)); + break; + } + return vd; + } + public ArrayList getNPCMenuOptions() { return this.npcMenuOptions; }