Quests fournit une API simple pour créer des exigences, des récompenses et des objectifs personnalisés. Pour commencer, assurez-vous que vous compilez avec la version 4.0.0 ou supérieure. Une fois que vous avez fini de suivre ce guide, utilisez le dossier /Quests/modules comme destination pour votre fichier jar fini et compilé. Si vous distribuez votre module, assurez-vous d'informer l'utilisateur de l'emplacement final et correct du dossier.
Les exemples suivants supposent que vous créez un projet pour un logiciel basé sur Bukkit.
API des exigences
Construire une exigence de quêtes est très simple. Pour commencer, créez une classe Java qui étend la classe CustomRequirement. Après cela, consultez cet exemple d'exigence personnalisée où le joueur doit avoir un nom particulier pour entreprendre la quête :
packagexyz.janedoe;importjava.util.Map;importorg.bukkit.entity.Player;importme.pikamug.quests.module.BukkitCustomRequirement;publicclassNameRequirementextendsBukkitCustomRequirement {// Construire l'exigencepublicNameRequirement() {setName("Exigence de nom");setAuthor("Jane Doe");setItem("NAME_TAG", (short)0);addStringPrompt("Name","Entrez la valeur que le nom du joueur doit contenir afin de prendre la quête",null);addStringPrompt("Case-Sensitive","La vérification doit-elle être sensible à la casse ou non ? (Entrer \'true\' ou \'false\')",null);setDisplay("Désolé, vous n'êtes pas sur la liste."); }// Tester si un joueur a satisfait à l'exigence @OverridepublicbooleantestRequirement(Player player,Map<String,Object> data) {String caseSensitive = (String) data.get("Case-Sensitive");// Vérifiez si le nom doit être sensible à la casseif (caseSensitive.equalsIgnoreCase("true")) {// Marquer l'exigence comme satisfaite si le nom correspondreturnplayer.getName().contains((String)data.get("Name")); } else {// Marquer l'exigence comme satisfaite si le nom correspond, en ignorant la cassereturnplayer.getName().toLowerCase().contains(((String)data.get("Name")).toLowerCase()); } }}
Dans le constructeur de votre classe, vous pouvez utiliser l'une des méthodes suivantes :
Méthode
Description
setName()
Définit le nom de l'objectif personnalisé.
setAuthor()
Définit l'auteur de l'objectif personnalisé (vous !).
setItem()
Définissez un élément qui peut apparaître dans les plugins de superposition comme QuestsGUI.
setDisplay
Définit le mode d'affichage de l'exigence en cas d'échec.
addStringPrompt()
Ajoute une nouvelle invite d'éditeur avec le titre, la description et la valeur par défaut spécifiés pour votre objectif personnalisé. Les éditeurs de quête peuvent saisir une chaîne que vous devez analyser.
À l'intérieur de #testRequirement, vous exécutez votre logique pour déterminer si le joueur satisfait à l'exigence, renvoyant true s'il le fait et false s'il ne le fait pas.
La carte de données contient les données que la personne qui a créé la quête lui a données. Dans cet exemple, la carte de données contient les deux valeurs pour 'Name' et 'Case-Sensitive'. Notez également que même si les valeurs sont de type Object, elles ont été converties en type String en interne. Vous devez effectuer une conversion de type manuelle si vous souhaitez obtenir des entiers, des booléens, etc.
API de récompense
Construire une récompense de quêtes est très simple. Pour commencer, créez une classe Java qui étend la classe CustomReward. Après cela, consultez cet exemple de récompense personnalisée où un joueur obtient un inventaire GUI contenant du fer, de l'or et des diamants :
packagexyz.janedoe;importjava.util.Map;importorg.bukkit.Bukkit;importorg.bukkit.Material;importorg.bukkit.entity.Player;importorg.bukkit.inventory.Inventory;importorg.bukkit.inventory.ItemStack;importme.pikamug.quests.module.BukkitCustomReward;importjava.util.UUID;publicclassLootRewardextendsBukkitCustomReward {// Construire la récompensepublicLootReward() {setName("Butin de récompense");setAuthor("Jane Doe");setItem("CHEST", (short)0);setDisplay("Coffre de butin: %Title%");addStringPrompt("Title","Titre de l'interface d'inventaire de butin.",null);addStringPrompt("NumIron","Entrez le nombre de lingots de fer à donner dans le coffre à butin.",null);addStringPrompt("NumGold","Entrez le nombre de lingots d'or à donner dans le coffre à butin.",null);addStringPrompt("NumDiamond","Entrez le nombre de diamants à donner dans le coffre à butin.",null); }// Donner une récompense de butin à un joueur @OverridepublicvoidgiveReward(UUID uuid,Map<String,Object> data) {finalPlayer player =Bukkit.getPlayer(uuid);if (player ==null) {Bukkit.getLogger().severe("Player was null for UUID "+ uuid);return; }String title = (String) data.get("Title");int numIron =0;int numGold =0;int numDiamond =0;// Tentative de chargement de l'entrée utilisateur sous forme d'entierstry { numIron =Integer.parseInt((String) data.get("NumIron")); } catch (NumberFormatException nfe) {Bukkit.getLogger().severe("La récompense de butin a un numéro de fer invalide: "+ numIron); }try { numGold =Integer.parseInt((String) data.get("NumGold")); } catch (NumberFormatException nfe) {Bukkit.getLogger().severe("La récompense de butin a un numéro d'or invalide: "+ numGold); }try { numDiamond =Integer.parseInt((String) data.get("NumDiamond")); } catch (NumberFormatException nfe) {Bukkit.getLogger().severe("La récompense de butin a un numéro de diamands invalide: "+ numDiamond); }// Créer un inventaire temporaire pour y ajouter des objetsInventory inv =Bukkit.getServer().createInventory(player,3, title);int slot =0;// Vérifier si le montant est supérieur à la valeur par défautif (numIron >0) {// Ajoutez un objet à l'emplacement actuel dans l'inventaire temporaire, puis préparez l'emplacement suivantinv.setItem(slot,newItemStack(Material.IRON_INGOT, numIron >64?64: numIron)); slot++; }if (numGold >0) {inv.setItem(slot,newItemStack(Material.GOLD_INGOT, numGold >64?64: numGold)); slot++; }if (numDiamond >0) {inv.setItem(slot,newItemStack(Material.DIAMOND, numDiamond >64?64: numDiamond)); }// Ouvrir l'inventaire temporaire pour que le joueur accepte les objetsplayer.openInventory(inv); }}
Dans le constructeur de votre classe, vous pouvez utiliser l'une des méthodes suivantes :
Méthode
Description
setName
Définit le nom de l'objectif personnalisé.
setAuthor
Définit l'auteur de l'objectif personnalisé (vous !).
setItem
Définissez un élément qui pourrait apparaître dans les plugins de superposition comme QuestsGUI.
setDisplay
Définit le nom de la récompense (texte qui apparaîtra lorsque le joueur termine la quête) de la récompense personnalisée.
addStringPrompt
Ajoute une nouvelle invite d'éditeur avec le titre, la description et la valeur par défaut spécifiés pour votre objectif personnalisé. Les éditeurs de quête peuvent saisir une chaîne que vous devez analyser.
À l'intérieur de #giveReward est l'endroit où vous exécutez votre logique pour donner au joueur tout ce que votre récompense personnalisée donne. La carte de données contient les données que la personne qui a créé la quête lui a données. Dans cet exemple, la carte de données contient quatre valeurs : une pour le titre de l'interface graphique et trois pour la quantité de fer/or/diamants. Notez également que même si les valeurs sont de type Object, elles ont été converties en type String en interne. Vous devez effectuer une conversion de type manuelle si vous souhaitez obtenir des entiers, des booléens, etc.
API des objectifs
Construire un objectif de quête est un peu plus compliqué que les exigences ou les récompenses. Pour commencer, créez une classe Java qui étend la classe CustomObjective. Si vous souhaitez capturer l'un des événements de Bukkit, vous devrez implémenter la classe d'écoute (Les quêtes se chargeront de l'enregistrer pour vous). Après cela, consultez ces exemples d'objectif personnalisé :
// Le joueur doit acquérir une certaine expérience pour avancerpackagexyz.janedoe;importme.pikamug.quests.module.BukkitCustomObjective;importme.pikamug.quests.Quest;importme.pikamug.quests.Quests;importorg.bukkit.Bukkit;importorg.bukkit.event.EventHandler;importorg.bukkit.event.player.PlayerExpChangeEvent;publicclassExperienceObjectiveextendsBukkitCustomObjective {// Obtenir le plugin QuêtesQuests qp = (Quests) Bukkit.getServer().getPluginManager().getPlugin("Quests");// Construire l'objectifpublicExperienceObjective() {setName("Objectif d'expérience");setAuthor("Jane Doe");setItem("BOOK", (short)0);setShowCount(true);setCountPrompt("Saisissez les points d'expérience que le joueur doit acquérir:");setDisplay("Acquérir des points d'expérience : %count%"); }// Attrapez l'événement Bukkit pour un joueur gagnant / perdant de l'expérience @EventHandlerpublicvoidonPlayerExpChange(PlayerExpChangeEvent evt) {Quester quester =qp.getQuester(evt.getPlayer().getUniqueId());// Assurez-vous d'évaluer toutes les quêtes actuelles du joueurfor (Quest quest :qp.getQuester(evt.getPlayer().getUniqueId()).getCurrentQuests().keySet()) {// Vérifie si le joueur a gagné plus d'expérience qu'il n'en a perduif (evt.getAmount() >0) {// Ajoutez à la progression de l'objectif, en le complétant si les exigences ont été rempliesincrementObjective(evt.getPlayer(),this, quest,evt.getAmount());// Facultatif : partagez la progression avec les membres du groupe (le cas échéant)quester.dispatchMultiplayerEverything(quest,ObjectiveType.CUSTOM, (finalQuester q,finalQuest cq) -> {incrementObjective(q.getUUID(),this, quest,evt.getAmount());returnnull; }); } } }}
// Exiger que le joueur laisse tomber un certain nombre d'un certain type d'objet.packagexyz.janedoe;importme.pikamug.quests.module.BukkitCustomObjective;importme.pikamug.quests.Quest;importme.pikamug.quests.Quests;importorg.bukkit.Bukkit;importorg.bukkit.entity.EntityType;importorg.bukkit.event.EventHandler;importorg.bukkit.event.player.PlayerDropItemEvent;importorg.bukkit.inventory.ItemStack;publicclassDropItemObjectiveextendsBukkitCustomObjective {// Obtenir le plugin QuêtesQuests qp = (Quests) Bukkit.getServer().getPluginManager().getPlugin("Quests");// Construire l'objectifpublicDropItemObjective() {setName("Objectif de l'objet à jeter");setAuthor("Jane Doe");addItem("ANVIL", (short)0); // Quests 4.0.0+ uniquementsetShowCount(true);setCountPrompt("Entrez le montant que le joueur doit déposer:");setDisplay("Jeter %Item Name%: %count%");addStringPrompt("Item Name","Entrez le nom de l'objet que le joueur doit déposer","DIRT"); }// Attrapez l'événement Bukkit pour un joueur laissant tomber un objet @EventHandlerpublicvoidonPlayerDropItem(PlayerDropItemEvent evt){// Assurez-vous d'évaluer toutes les quêtes actuelles du joueurfor (Quest quest :qp.getQuester(evt.getPlayer().getUniqueId()).getCurrentQuests().keySet()) {Map<String,Object> map =getDataForPlayer(evt.getPlayer(),this, quest);if (map ==null) {continue; }ItemStack stack =evt.getItemDrop().getItemStack();String userInput = (String) map.get("Item Name");EntityType type =EntityType.fromName(userInput);// Erreur d'affichage si le nom d'élément spécifié par l'utilisateur n'est pas valideif (type ==null) {Bukkit.getLogger().severe("L'objectif d'élément àjeter a un nom d'élément non valide: "+ userInput);continue; }// Vérifiez si l'élément que le joueur a déposé est celui spécifié par l'utilisateurif (evt.getItemDrop().getItemStack().getType().equals(type)) {// Ajouter à la progression de l'objectif, en le complétant si les exigences ont été rempliesincrementObjective(evt.getPlayer().getUniqueId(),this, quest,stack.getAmount()); } } }}
// Autoriser le joueur à casser N'IMPORTE QUEL bloc plutôt qu'un spécifiquepackagexyz.janedoe;importme.pikamug.quests.module.BukkitCustomObjective;importme.pikamug.quests.Quest;importme.pikamug.quests.Quests;importorg.bukkit.Bukkit;importorg.bukkit.entity.Player;importorg.bukkit.event.EventHandler;importorg.bukkit.event.EventPriority;importorg.bukkit.event.block.BlockBreakEvent;publicclassAnyBreakBlockObjectiveextendsBukkitCustomObjective {// Récupérer le plugin QuêtesprivatestaticQuests quests = (Quests) Bukkit.getServer().getPluginManager().getPlugin("Quests");publicAnyBreakBlockObjective() {setName("Objectif casser des blocs");setAuthor("Jane Doe");addItem("DIRT", (short)0);setShowCount(true);addStringPrompt("Obj Name","Définir un nom pour l'objectif","Casser tous les bocs");setCountPrompt("Définir le nombre de blocs à casser");setDisplay("%Obj Name%: %count%"); } @EventHandler(priority =EventPriority.LOW)publicvoidonBlockBreak(BlockBreakEvent event) {Player player =event.getPlayer();for (Quest q :quests.getQuester(player.getUniqueId()).getCurrentQuests().keySet()) {incrementObjective(player.getUniqueId(),this, q,1);return; } }}
Dans le constructeur de votre classe, vous pouvez utiliser l'une des méthodes suivantes :
Méthode
Description
setName
Définit le nom de l'objectif personnalisé.
setAuthor
Sets l'auteur de l'objectif personnalisé (vous !).
setItem
Définissez un élément qui pourrait apparaître dans les plugins de superposition comme QuestsGUI.
setShowCount
Définit si l'éditeur de quête peut définir le décompte (nombre de fois où le joueur doit répéter la tâche). La valeur par défaut est "vrai". Cela s'appliquera à toutes les invites ajoutées avec #addStringPrompt, sauf si elles sont désactivées.
setCountPrompt
Définit la description de l'invite permettant à l'utilisateur d'entrer le nombre pour l'objectif. La valeur par défaut est "Entrer le numéro".
setDisplay
Définit la façon dont l'objectif est affiché dans la liste /quests et le journal des quêtes. Pour les espaces réservés, utilisez %count% pour obtenir la valeur de #setShowCount et les titres #addStringPrompt pour l'entrée utilisateur (comme %Item Name% dans le deuxième exemple). La valeur par défaut est « Progression : %count% ».
addStringPrompt
Ajoute une nouvelle invite d'éditeur avec le titre, la description et la valeur par défaut spécifiés pour votre objectif personnalisé. Les éditeurs de quête peuvent saisir une chaîne que vous devez analyser.
À l'intérieur de vos EventHandlers (le cas échéant), déterminez si le joueur a atteint tout ou partie de l'objectif, puis utilisez #incrementObjective pour faire avancer le joueur. Le premier et le deuxième argument de #incrementObjective doivent toujours être respectivement le joueur et 'this'. Le troisième argument est de combien incrémenter l'objectif, tandis que le dernier est la quête à laquelle appliquer l'incrément. Même si votre objectif n'a pas de décompte, vous devez toujours utiliser #incrementObjective - utilisez un incrément de 1 pour signaler que l'objectif a été atteint.
Le Map<String, Object> contient les données fournies par l'éditeur de quête. Dans cet exemple, les clés de données sont les noms des éléments, tandis que les valeurs sont l'entrée de l'utilisateur pour votre invite (qui peut être null). Notez également que même si les valeurs sont de type objets, elles ont été converties en type String en interne. Vous devez effectuer une conversion de type manuelle si vous souhaitez obtenir des entiers, des booléens, etc.