Add experimental global quest Options

This commit is contained in:
PikaMug 2025-02-20 22:46:19 -05:00
parent d4f784de86
commit 223a0ce2fc
8 changed files with 304 additions and 25 deletions

View File

@ -50,4 +50,16 @@ public interface Options {
boolean canIgnoreBlockReplace();
void setIgnoreBlockReplace(final boolean ignoreBlockReplace);
boolean canGiveGloballyAtLogin();
void setGiveGloballyAtLogin(final boolean giveGloballyAtLogin);
boolean canAllowStackingGlobal();
void setAllowStackingGlobal(final boolean allowStackingGlobal);
boolean canInformOnStart();
void setInformOnStart(final boolean informOnStart);
}

View File

@ -148,9 +148,12 @@ public class Key {
public static final String OPT_USE_PARTIES_PLUGIN = "usePartiesPluginOpt";
public static final String OPT_SHARE_PROGRESS_LEVEL = "shareProgressLevelOpt";
public static final String OPT_SHARE_SAME_QUEST_ONLY = "shareSameQuestOnlyOpt";
public static final String OPT_SHARE_DISTANCE = "shareDistance";
public static final String OPT_HANDLE_OFFLINE_PLAYERS = "handleOfflinePlayers";
public static final String OPT_IGNORE_BLOCK_REPLACE = "ignoreBlockReplace";
public static final String OPT_SHARE_DISTANCE = "shareDistanceOpt";
public static final String OPT_HANDLE_OFFLINE_PLAYERS = "handleOfflinePlayersOpt";
public static final String OPT_IGNORE_BLOCK_REPLACE = "ignoreBlockReplaceOpt";
public static final String OPT_GIVE_GLOBALLY_AT_LOGIN = "giveGloballyAtLoginOpt";
public static final String OPT_ALLOW_STACKING_GLOBAL = "allowStackingGlobalOpt";
public static final String OPT_INFORM_QUEST_START = "informQuestStartOpt";
// Actions
public static final String A_OLD_ACTION = "oldAction";
public static final String A_NAME = "actName";

View File

@ -37,7 +37,7 @@ public class QuestOptionsPrompt extends QuestsEditorNumericPrompt {
this.plugin = (BukkitQuestsPlugin)context.getPlugin();
}
private final int size = 3;
private final int size = 4;
@Override
public int getSize() {
@ -55,8 +55,9 @@ public class QuestOptionsPrompt extends QuestsEditorNumericPrompt {
switch (number) {
case 1:
case 2:
return ChatColor.BLUE;
case 3:
return ChatColor.BLUE;
case 4:
return ChatColor.GREEN;
default:
return null;
@ -71,6 +72,8 @@ public class QuestOptionsPrompt extends QuestsEditorNumericPrompt {
case 2:
return ChatColor.GOLD + BukkitLang.get("optMultiplayer");
case 3:
return ChatColor.GOLD + "Server (Global)";
case 4:
return ChatColor.YELLOW + BukkitLang.get("done");
default:
return null;
@ -106,6 +109,8 @@ public class QuestOptionsPrompt extends QuestsEditorNumericPrompt {
case 2:
return new QuestOptionsMultiplayerPrompt(context);
case 3:
return new QuestOptionsGlobalPrompt(context);
case 4:
return plugin.getQuestFactory().returnToMenu(context);
default:
return new QuestOptionsPrompt(context);
@ -736,4 +741,143 @@ public class QuestOptionsPrompt extends QuestsEditorNumericPrompt {
}
}
}
public class QuestOptionsGlobalPrompt extends QuestsEditorNumericPrompt {
public QuestOptionsGlobalPrompt(final ConversationContext context) {
super(context);
}
private final int size = 4;
@Override
public int getSize() {
return size;
}
@Override
public String getTitle(final ConversationContext context) {
return ChatColor.DARK_GREEN + "Server (Global)";
}
@Override
public ChatColor getNumberColor(final ConversationContext context, final int number) {
switch (number) {
case 1:
case 2:
case 3:
return ChatColor.BLUE;
case 4:
return ChatColor.GREEN;
default:
return null;
}
}
@Override
public String getSelectionText(final ConversationContext context, final int number) {
switch (number) {
case 1:
return ChatColor.YELLOW + "Give quest globally at login";
case 2:
return ChatColor.YELLOW + "Allow stacking with global quests";
case 3:
return ChatColor.YELLOW + "Inform players on quest start";
case 4:
return ChatColor.YELLOW + BukkitLang.get("done");
default:
return null;
}
}
@Override
public String getAdditionalText(final ConversationContext context, final int number) {
switch (number) {
case 1:
final Boolean globalOpt = (Boolean) context.getSessionData(Key.OPT_GIVE_GLOBALLY_AT_LOGIN);
if (globalOpt == null) {
final boolean defaultOpt = new BukkitOptions().canGiveGloballyAtLogin();
return ChatColor.GRAY + "(" + (defaultOpt ? ChatColor.GREEN
+ BukkitLang.get(String.valueOf(defaultOpt)) : ChatColor.RED
+ BukkitLang.get(String.valueOf(defaultOpt))) + ChatColor.GRAY + ")";
} else {
return ChatColor.GRAY + "(" + (globalOpt ? ChatColor.GREEN
+ BukkitLang.get(String.valueOf(globalOpt)) : ChatColor.RED
+ BukkitLang.get(String.valueOf(globalOpt))) + ChatColor.GRAY + ")";
}
case 2:
final Boolean stackOpt = (Boolean) context.getSessionData(Key.OPT_ALLOW_STACKING_GLOBAL);
if (stackOpt == null) {
final boolean defaultOpt = new BukkitOptions().canAllowStackingGlobal();
return ChatColor.GRAY + "(" + (defaultOpt ? ChatColor.GREEN
+ BukkitLang.get(String.valueOf(defaultOpt)) : ChatColor.RED
+ BukkitLang.get(String.valueOf(defaultOpt))) + ChatColor.GRAY + ")";
} else {
return ChatColor.GRAY + "(" + (stackOpt ? ChatColor.GREEN
+ BukkitLang.get(String.valueOf(stackOpt)) : ChatColor.RED
+ BukkitLang.get(String.valueOf(stackOpt))) + ChatColor.GRAY + ")";
}
case 3:
final Boolean informOpt = (Boolean) context.getSessionData(Key.OPT_INFORM_QUEST_START);
if (informOpt == null) {
final boolean defaultOpt = new BukkitOptions().canInformOnStart();
return ChatColor.GRAY + "(" + (defaultOpt ? ChatColor.GREEN
+ BukkitLang.get(String.valueOf(defaultOpt)) : ChatColor.RED
+ BukkitLang.get(String.valueOf(defaultOpt))) + ChatColor.GRAY + ")";
} else {
return ChatColor.GRAY + "(" + (informOpt ? ChatColor.GREEN
+ BukkitLang.get(String.valueOf(informOpt)) : ChatColor.RED
+ BukkitLang.get(String.valueOf(informOpt))) + ChatColor.GRAY + ")";
}
case 4:
return "";
default:
return null;
}
}
@Override
public @NotNull String getBasicPromptText(final @NotNull ConversationContext context) {
final QuestsEditorPostOpenNumericPromptEvent event
= new QuestsEditorPostOpenNumericPromptEvent(context, this);
plugin.getServer().getPluginManager().callEvent(event);
final StringBuilder text = new StringBuilder(ChatColor.DARK_GREEN + "- " + getTitle(context) + " -");
for (int i = 1; i <= size; i++) {
text.append("\n").append(getNumberColor(context, i)).append(ChatColor.BOLD).append(i)
.append(ChatColor.RESET).append(" - ").append(getSelectionText(context, i)).append(" ")
.append(getAdditionalText(context, i));
}
return text.toString();
}
@Override
public Prompt acceptValidatedInput(final @NotNull ConversationContext context, final Number input) {
switch (input.intValue()) {
case 1:
tempKey = Key.OPT_GIVE_GLOBALLY_AT_LOGIN;
tempPrompt = new QuestOptionsGlobalPrompt(context);
return new QuestOptionsTrueFalsePrompt(context);
case 2:
tempKey = Key.OPT_ALLOW_STACKING_GLOBAL;
tempPrompt = new QuestOptionsGlobalPrompt(context);
return new QuestOptionsTrueFalsePrompt(context);
case 3:
tempKey = Key.OPT_INFORM_QUEST_START;
tempPrompt = new QuestOptionsGlobalPrompt(context);
return new QuestOptionsTrueFalsePrompt(context);
case 4:
tempKey = null;
tempPrompt = null;
try {
return new QuestOptionsPrompt(context);
} catch (final Exception e) {
context.getForWhom().sendRawMessage(ChatColor.RED + BukkitLang.get("itemCreateCriticalError"));
return Prompt.END_OF_CONVERSATION;
}
default:
return null;
}
}
}
}

View File

@ -907,6 +907,28 @@ public class BukkitPlayerListener implements Listener {
}
}
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
boolean alreadyHasAtLeastOneGlobalQuest = false;
for (final Quest cq : quester.getCurrentQuests().keySet()) {
if (cq.getOptions().canGiveGloballyAtLogin()) {
alreadyHasAtLeastOneGlobalQuest = true;
break;
}
}
for (final Quest quest : plugin.getLoadedQuests()) {
if (quest.getOptions().canGiveGloballyAtLogin()) {
if (!quest.getOptions().canAllowStackingGlobal() && alreadyHasAtLeastOneGlobalQuest) {
if (plugin.getConfigSettings().getConsoleLogging() > 3) {
plugin.getLogger().info(quester.getUUID() + " denied global quest ID "
+ quest.getId() + " because it was not stackable");
}
continue;
}
if (quester.canAcceptOffer(quest, quest.getOptions().canInformOnStart())) {
alreadyHasAtLeastOneGlobalQuest = true;
quester.takeQuest(quest, false);
}
}
}
if (quester.hasJournal()) {
quester.updateJournal();
}

View File

@ -714,12 +714,17 @@ public class BukkitQuester implements Quester {
return;
}
}
final boolean isGlobalQuest = quest.getOptions().canGiveGloballyAtLogin();
if (bukkitQuest.testRequirements(offlinePlayer) || ignoreRequirements) {
addEmptiesFor(bukkitQuest, 0);
try {
currentQuests.put(bukkitQuest, 0);
if (plugin.getConfigSettings().getConsoleLogging() > 1) {
plugin.getLogger().info(getPlayer().getUniqueId() + " started quest " + bukkitQuest.getName());
if (isGlobalQuest) {
plugin.getLogger().info(getPlayer().getUniqueId() + " started global quest " + bukkitQuest.getName());
} else {
plugin.getLogger().info(getPlayer().getUniqueId() + " started quest " + bukkitQuest.getName());
}
}
} catch (final NullPointerException npe) {
plugin.getLogger().severe("Unable to add quest" + bukkitQuest.getName() + " for player "
@ -752,15 +757,17 @@ public class BukkitQuester implements Quester {
}
}
}
String accepted = BukkitLang.get(p, "questAccepted");
accepted = accepted.replace("<quest>", bukkitQuest.getName());
sendMessage(ChatColor.GREEN + accepted);
p.sendMessage("");
if (plugin.getConfigSettings().canShowQuestTitles()) {
final String title = ChatColor.GOLD + BukkitLang.get(p, "quest") + " "
+ BukkitLang.get(p, "accepted");
final String subtitle = ChatColor.YELLOW + bukkitQuest.getName();
BukkitTitleProvider.sendTitle(p, title, subtitle);
if (!isGlobalQuest || quest.getOptions().canInformOnStart()) {
String accepted = BukkitLang.get(p, "questAccepted");
accepted = accepted.replace("<quest>", bukkitQuest.getName());
sendMessage(ChatColor.GREEN + accepted);
p.sendMessage("");
if (plugin.getConfigSettings().canShowQuestTitles()) {
final String title = ChatColor.GOLD + BukkitLang.get(p, "quest") + " "
+ BukkitLang.get(p, "accepted");
final String subtitle = ChatColor.YELLOW + bukkitQuest.getName();
BukkitTitleProvider.sendTitle(p, title, subtitle);
}
}
}
}
@ -787,10 +794,16 @@ public class BukkitQuester implements Quester {
setCompassTarget(bukkitQuest);
bukkitQuest.updateCompass(this, stage);
} else {
if (offlinePlayer.isOnline()) {
sendMessage(ChatColor.DARK_AQUA + BukkitLang.get("requirements"));
for (final String s : getCurrentRequirements(bukkitQuest, false)) {
sendMessage("- " + ChatColor.GRAY + s);
if (!isGlobalQuest || quest.getOptions().canInformOnStart()) {
if (offlinePlayer.isOnline()) {
if (isGlobalQuest) {
sendMessage(ChatColor.RED + BukkitConfigUtil.parseString(BukkitLang.get("questObjectivesTitle"))
.replace("<quest>", quest.getName()));
}
sendMessage(ChatColor.DARK_AQUA + BukkitLang.get("requirements"));
for (final String s : getCurrentRequirements(bukkitQuest, false)) {
sendMessage("- " + ChatColor.GRAY + s);
}
}
}
}
@ -804,7 +817,7 @@ public class BukkitQuester implements Quester {
* End a quest for this Quester, but ask permission first if possible<p>
*
* @param quest The quest to check and then offer
* @param message Messages to send Quester upon quit, can be left null or empty
* @param message Message to send Quester upon quit, can be left null or empty
* @return true if successful
*/
public boolean abandonQuest(final Quest quest, final String message) {
@ -4283,7 +4296,23 @@ public class BukkitQuester implements Quester {
final Set<String> appliedQuestIDs = new HashSet<>();
if (quest != null) {
try {
if (quest.getOptions().getShareProgressLevel() == 1) {
if (quest.getOptions().canGiveGloballyAtLogin()) {
final List<Quester> mq = getGlobalQuesters(quest);
if (mq == null) {
return appliedQuestIDs;
}
for (final Quester q : mq) {
if (q == null) {
continue;
}
q.getCurrentQuests().forEach((otherQuest, i) -> {
if (otherQuest.getStage(i).containsObjective(type)) {
fun.apply(q, otherQuest);
appliedQuestIDs.add(otherQuest.getId());
}
});
}
} else if (quest.getOptions().getShareProgressLevel() == 1) {
final List<Quester> mq = getMultiplayerQuesters(quest);
if (mq == null) {
return appliedQuestIDs;
@ -4453,6 +4482,34 @@ public class BukkitQuester implements Quester {
return mq;
}
/**
* Get a list of fellow Questers participating in a global quest
*
* @param quest The server-wide, global quest
* @return Potentially empty list of Questers or null for invalid quest
*/
public List<Quester> getGlobalQuesters(final Quest quest) {
if (quest == null) {
return null;
}
final List<Quester> mq = new LinkedList<>();
if (quest.getOptions().canGiveGloballyAtLogin()) {
for (final Quester oq : plugin.getOnlineQuesters()) {
if (oq.getUUID().equals(getUUID())) {
continue;
}
if (oq.getCurrentQuests().containsKey(quest)) {
mq.add(oq);
}
}
if (mq.size() > 0 && plugin.getConfigSettings().getConsoleLogging() > 3) {
plugin.getLogger().info("Found " + mq.size() + " global members for quest ID "
+ quest.getId());
}
}
return mq;
}
/**
* Whether this Quester meets condition of given quest
*

View File

@ -272,6 +272,9 @@ public class BukkitQuestFactory implements QuestFactory, ConversationAbandonedLi
context.setSessionData(Key.OPT_SHARE_DISTANCE, opt.getShareDistance());
context.setSessionData(Key.OPT_HANDLE_OFFLINE_PLAYERS, opt.canHandleOfflinePlayers());
context.setSessionData(Key.OPT_IGNORE_BLOCK_REPLACE, opt.canIgnoreBlockReplace());
context.setSessionData(Key.OPT_GIVE_GLOBALLY_AT_LOGIN, opt.canGiveGloballyAtLogin());
context.setSessionData(Key.OPT_ALLOW_STACKING_GLOBAL, opt.canAllowStackingGlobal());
context.setSessionData(Key.OPT_INFORM_QUEST_START, opt.canInformOnStart());
// Stages (Objectives)
int index = 1;
for (final Stage stage : bukkitQuest.getStages()) {
@ -917,6 +920,12 @@ public class BukkitQuestFactory implements QuestFactory, ConversationAbandonedLi
? context.getSessionData(Key.OPT_HANDLE_OFFLINE_PLAYERS) : null);
opts.set("ignore-block-replace", context.getSessionData(Key.OPT_IGNORE_BLOCK_REPLACE) != null
? context.getSessionData(Key.OPT_IGNORE_BLOCK_REPLACE) : null);
opts.set("give-at-login", context.getSessionData(Key.OPT_GIVE_GLOBALLY_AT_LOGIN) != null
? context.getSessionData(Key.OPT_GIVE_GLOBALLY_AT_LOGIN) : null);
opts.set("allow-stacking-global", context.getSessionData(Key.OPT_ALLOW_STACKING_GLOBAL) != null
? context.getSessionData(Key.OPT_ALLOW_STACKING_GLOBAL) : null);
opts.set("inform-on-start", context.getSessionData(Key.OPT_INFORM_QUEST_START) != null
? context.getSessionData(Key.OPT_INFORM_QUEST_START) : null);
if (opts.getKeys(false).isEmpty()) {
section.set("options", null);
}

View File

@ -10,8 +10,6 @@
package me.pikamug.quests.quests.components;
import me.pikamug.quests.quests.components.Options;
public class BukkitOptions implements Options {
private boolean allowCommands = true;
private boolean allowQuitting = true;
@ -23,6 +21,9 @@ public class BukkitOptions implements Options {
private int shareProgressLevel = 1;
private boolean shareSameQuestOnly = true;
private boolean ignoreBlockReplace = true;
private boolean giveGloballyAtLogin = false;
private boolean allowStackingGlobal = true;
private boolean informOnStart = true;
public boolean canAllowCommands() {
return allowCommands;
@ -103,4 +104,28 @@ public class BukkitOptions implements Options {
public void setIgnoreBlockReplace(final boolean ignoreBlockReplace) {
this.ignoreBlockReplace = ignoreBlockReplace;
}
public boolean canGiveGloballyAtLogin() {
return giveGloballyAtLogin;
}
public void setGiveGloballyAtLogin(final boolean giveGloballyAtLogin) {
this.giveGloballyAtLogin = giveGloballyAtLogin;
}
public boolean canAllowStackingGlobal() {
return allowStackingGlobal;
}
public void setAllowStackingGlobal(final boolean allowStackingGlobal) {
this.allowStackingGlobal = allowStackingGlobal;
}
public boolean canInformOnStart() {
return informOnStart;
}
public void setInformOnStart(final boolean informOnStart) {
this.informOnStart = informOnStart;
}
}

View File

@ -296,8 +296,6 @@ public class BukkitQuestYamlStorage implements QuestStorageImpl {
if (config.contains("quests." + questId + ".options")) {
loadQuestOptions(config, quest, questId);
}
// TODO was this necessary?
//quest.setPlugin(this);
loadQuestStages(quest, config, questId);
loadQuestRewards(config, quest, questId);
final Collection<Quest> loadedQuests = plugin.getLoadedQuests();
@ -769,6 +767,15 @@ public class BukkitQuestYamlStorage implements QuestStorageImpl {
if (config.contains("quests." + questKey + ".options.ignore-block-replace")) {
opts.setIgnoreBlockReplace(config.getBoolean("quests." + questKey + ".options.ignore-block-replace"));
}
if (config.contains("quests." + questKey + ".options.give-at-login")) {
opts.setGiveGloballyAtLogin(config.getBoolean("quests." + questKey + ".options.give-at-login"));
}
if (config.contains("quests." + questKey + ".options.allow-stacking-global")) {
opts.setAllowStackingGlobal(config.getBoolean("quests." + questKey + ".options.allow-stacking-global"));
}
if (config.contains("quests." + questKey + ".options.inform-on-start")) {
opts.setInformOnStart(config.getBoolean("quests." + questKey + ".options.inform-on-start"));
}
}
@SuppressWarnings({ "unchecked", "unused"})