diff --git a/src/main/java/betterquesting/api/properties/NativeProps.java b/src/main/java/betterquesting/api/properties/NativeProps.java index df73341a5..5efd968fe 100644 --- a/src/main/java/betterquesting/api/properties/NativeProps.java +++ b/src/main/java/betterquesting/api/properties/NativeProps.java @@ -34,6 +34,7 @@ public class NativeProps { public static final IPropertyType LOCKED_PROGRESS = new PropertyTypeBoolean(new ResourceLocation(ModReference.MODID, "lockedProgress"), false); public static final IPropertyType SIMULTANEOUS = new PropertyTypeBoolean(new ResourceLocation(ModReference.MODID, "simultaneous"), false); public static final IPropertyType IGNORES_VIEW_MODE = new PropertyTypeBoolean(new ResourceLocation(ModReference.MODID, "ignoresView"), false); + public static final IPropertyType SKIP_COMPLETION_COUNT = new PropertyTypeBoolean(new ResourceLocation(ModReference.MODID, "skipCompletionCount"), false); public static final IPropertyType VISIBILITY = new PropertyTypeEnum<>(new ResourceLocation(ModReference.MODID, "visibility"), findVisibility()); public static final IPropertyType LOGIC_TASK = new PropertyTypeEnum<>(new ResourceLocation(ModReference.MODID, "taskLogic"), EnumLogic.AND); diff --git a/src/main/java/betterquesting/client/gui2/GuiQuestLines.java b/src/main/java/betterquesting/client/gui2/GuiQuestLines.java index 71387fdd9..fd00e48a1 100644 --- a/src/main/java/betterquesting/client/gui2/GuiQuestLines.java +++ b/src/main/java/betterquesting/client/gui2/GuiQuestLines.java @@ -53,21 +53,24 @@ import betterquesting.network.handlers.NetQuestAction; import betterquesting.questing.QuestDatabase; import betterquesting.questing.QuestLineDatabase; +import it.unimi.dsi.fastutil.ints.IntArraySet; +import it.unimi.dsi.fastutil.ints.IntSet; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.GuiScreen; -import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.Tuple; import net.minecraft.util.text.TextComponentTranslation; import net.minecraftforge.common.config.Configuration; import org.lwjgl.util.vector.Vector4f; import javax.annotation.Nonnull; +import java.text.DecimalFormat; import java.util.*; public class GuiQuestLines extends GuiScreenCanvas implements IPEventListener, INeedsRefresh { private static OpenTray openTray = OpenTray.NONE; + private static final DecimalFormat PERCENT_FORMAT = new DecimalFormat("0.##"); private final ScrollPosition scrollPosition; @@ -91,6 +94,7 @@ public class GuiQuestLines extends GuiScreenCanvas implements IPEventListener, I private PanelTextBox txTitle; private PanelTextBox txDesc; private PanelTextBox completionText; + private PanelTextBox globalCompletionText; private PanelButton claimAll; @@ -198,9 +202,13 @@ public void initPanel() { }); cvBackground.addPanel(cvChapterTray); - cvLines = new CanvasScrolling(new GuiTransform(GuiAlign.FULL_BOX, new GuiPadding(8, 8, 16, 8), 0)); + cvLines = new CanvasScrolling(new GuiTransform(GuiAlign.FULL_BOX, new GuiPadding(8, 20, 16, 8), 0)); cvChapterTray.getCanvasOpen().addPanel(cvLines); + globalCompletionText = new PanelTextBox(new GuiTransform(new Vector4f(0F, 0F, 1F, 0F), new GuiPadding(24, 8, 16, -20), 0), ""); + globalCompletionText.setColor(PresetColor.TEXT_HEADER.getColor()); + cvChapterTray.getCanvasOpen().addPanel(globalCompletionText); + scLines = new PanelVScrollBar(new GuiTransform(GuiAlign.RIGHT_EDGE, new GuiPadding(-16, 8, 8, 8), 0)); cvLines.setScrollDriverY(scLines); cvChapterTray.getCanvasOpen().addPanel(scLines); @@ -470,7 +478,9 @@ private void refreshChapterVisibility() { for (DBEntry dbEntry : lineList) { IQuestLine ql = dbEntry.getValue(); EnumQuestVisibility vis = ql.getProperty(NativeProps.VISIBILITY); - if (!canEdit && vis == EnumQuestVisibility.HIDDEN) continue; + + if (!canEdit && vis == EnumQuestVisibility.HIDDEN && (!viewMode || ql.getProperty(NativeProps.IGNORES_VIEW_MODE))) + continue; boolean show = false; boolean unlocked = false; @@ -513,11 +523,13 @@ private void refreshChapterVisibility() { } if (cvChapterTray.isTrayOpen()) buildChapterList(); + refreshGlobalCompletion(); } private boolean isQuestCompletedForQuestline(UUID playerID, @Nonnull IQuest q) { if (q.isComplete(playerID)) return true; // Completed quest - if (q.getProperty(NativeProps.VISIBILITY) == EnumQuestVisibility.HIDDEN) return true; // Always hidden quest + if (q.getProperty(NativeProps.SKIP_COMPLETION_COUNT)) return true; // Always counted as true + if (q.getProperty(NativeProps.VISIBILITY) == EnumQuestVisibility.HIDDEN && q.getProperty(NativeProps.IGNORES_VIEW_MODE)) return true; // Always hidden quest if (q.getProperty(NativeProps.LOGIC_QUEST) == EnumLogic.XOR) { // Quest with choice int reqCount = 0; for (int qRequirementId : q.getRequirements()) { @@ -578,31 +590,71 @@ private void buildChapterList() { } private void refreshQuestCompletion() { - UUID playerUUID = QuestingAPI.getQuestingUUID(mc.player); + if (selectedLine == null) return; - if (selectedLine == null) { - return; - } + UUID playerUUID = QuestingAPI.getQuestingUUID(mc.player); - int questsCompleted = 0; - int totalQuests = 0; var database = Objects.requireNonNull(QuestingAPI.getAPI(ApiReference.QUEST_DB)); + int completed = 0; + int total = 0; for (DBEntry entry : selectedLine.getEntries()) { IQuest quest = database.getValue(entry.getID()); + if (quest.getProperty(NativeProps.SKIP_COMPLETION_COUNT)) continue; + if (quest.getProperty(NativeProps.VISIBILITY) == EnumQuestVisibility.HIDDEN && quest.getProperty(NativeProps.IGNORES_VIEW_MODE)) continue; if (quest.getProperty(NativeProps.LOGIC_QUEST) == EnumLogic.XOR) { // Subtract the number of requirements - 1 to simulate only doing 1 task for XOR requirements - totalQuests = totalQuests - Math.max(0, quest.getRequirements().length - 1); + total = total - Math.max(0, quest.getRequirements().length - 1); } - totalQuests++; + total++; if (quest.isComplete(playerUUID)) { - questsCompleted++; + completed++; } } - completionText.setText(QuestTranslation.translate("betterquesting.title.completion", questsCompleted, totalQuests)); + completionText.setText(completionText("betterquesting.title.completion", completed, total)); + } + + private void refreshGlobalCompletion() { + if (globalCompletionText == null) return; + + UUID playerUUID = QuestingAPI.getQuestingUUID(mc.player); + var database = Objects.requireNonNull(QuestingAPI.getAPI(ApiReference.QUEST_DB)); + IntSet seen = new IntArraySet(); + int completed = 0; + int total = 0; + + for (var visChapter : visChapters) { + IQuestLine line = visChapter.getFirst().getValue(); + if (line.getProperty(NativeProps.VISIBILITY) == EnumQuestVisibility.HIDDEN && line.getProperty(NativeProps.IGNORES_VIEW_MODE)) continue; + for (var entry : line.getEntries()) { + int questId = entry.getID(); + if (!seen.add(questId)) continue; // already counted in another visible line + IQuest quest = database.getValue(questId); + + if (quest.getProperty(NativeProps.SKIP_COMPLETION_COUNT)) continue; + if (quest.getProperty(NativeProps.VISIBILITY) == EnumQuestVisibility.HIDDEN && quest.getProperty(NativeProps.IGNORES_VIEW_MODE)) continue; + if (quest.getProperty(NativeProps.LOGIC_QUEST) == EnumLogic.XOR) { + // Subtract the number of requirements - 1 to simulate only doing 1 task for XOR requirements + total = total - Math.max(0, quest.getRequirements().length - 1); + } + + total++; + + if (quest.isComplete(playerUUID)) { + completed++; + } + } + } + + globalCompletionText.setText(completionText("betterquesting.title.completion_total", completed, total)); + } + + private static String completionText(String key, int completed, int total) { + String percent = total > 0 ? PERCENT_FORMAT.format(completed * 100.0 / total) : "0"; + return QuestTranslation.translate(key, completed, total, percent); } private void openQuestLine(DBEntry q) { @@ -707,7 +759,7 @@ enum OpenTray { NONE, CHAPTER, DESCRIPTION } - public static class ScrollPosition{ + public static class ScrollPosition { public ScrollPosition(int chapterScrollY) { this.chapterScrollY = chapterScrollY; } diff --git a/src/main/java/betterquesting/questing/QuestInstance.java b/src/main/java/betterquesting/questing/QuestInstance.java index e63a8825d..2dc0141d2 100644 --- a/src/main/java/betterquesting/questing/QuestInstance.java +++ b/src/main/java/betterquesting/questing/QuestInstance.java @@ -74,6 +74,7 @@ private void setupProps() { setupValue(NativeProps.GLOBAL_SHARE, false); setupValue(NativeProps.SIMULTANEOUS, false); setupValue(NativeProps.IGNORES_VIEW_MODE, false); + setupValue(NativeProps.SKIP_COMPLETION_COUNT, false); setupValue(NativeProps.VISIBILITY, NativeProps.VISIBILITY.getDefault()); } diff --git a/src/main/java/betterquesting/questing/QuestLine.java b/src/main/java/betterquesting/questing/QuestLine.java index 1a526e95c..07baa8dd7 100644 --- a/src/main/java/betterquesting/questing/QuestLine.java +++ b/src/main/java/betterquesting/questing/QuestLine.java @@ -27,6 +27,7 @@ private void setupProps() { this.setupValue(NativeProps.DESC, "No Description"); this.setupValue(NativeProps.ICON, new BigItemStack(Items.BOOK)); this.setupValue(NativeProps.VISIBILITY, NativeProps.VISIBILITY.getDefault()); + this.setupValue(NativeProps.IGNORES_VIEW_MODE, false); this.setupValue(NativeProps.BG_IMAGE); this.setupValue(NativeProps.BG_SIZE); } diff --git a/src/main/resources/assets/betterquesting/lang/en_us.lang b/src/main/resources/assets/betterquesting/lang/en_us.lang index 3247df161..7a03357ae 100644 --- a/src/main/resources/assets/betterquesting/lang/en_us.lang +++ b/src/main/resources/assets/betterquesting/lang/en_us.lang @@ -19,7 +19,8 @@ betterquesting.title.party_invite=Invite Users betterquesting.title.select_theme=Select Theme betterquesting.title.importers=Importers betterquesting.title.submit_station=Submit Station -betterquesting.title.completion=Completion: %d/%d +betterquesting.title.completion=Completion: %d/%d (%s%%) +betterquesting.title.completion_total=Total: %d/%d (%s%%) betterquesting.btn.rewards=Rewards betterquesting.btn.tasks=Tasks diff --git a/src/main/resources/assets/betterquesting/lang/ja_jp.lang b/src/main/resources/assets/betterquesting/lang/ja_jp.lang index 77a40acaa..25baad766 100644 --- a/src/main/resources/assets/betterquesting/lang/ja_jp.lang +++ b/src/main/resources/assets/betterquesting/lang/ja_jp.lang @@ -18,7 +18,7 @@ betterquesting.title.party_invite=ユーザーを招待 betterquesting.title.select_theme=テーマを選択 betterquesting.title.importers=インポーター betterquesting.title.submit_station=提出ステーション -betterquesting.title.completion=%d/%d : 完了 +betterquesting.title.completion=%d/%d : 完了 (%s%%) betterquesting.btn.rewards=報酬 betterquesting.btn.tasks=タスク diff --git a/src/main/resources/assets/betterquesting/lang/ru_ru.lang b/src/main/resources/assets/betterquesting/lang/ru_ru.lang index 709c1843d..92d0f9904 100644 --- a/src/main/resources/assets/betterquesting/lang/ru_ru.lang +++ b/src/main/resources/assets/betterquesting/lang/ru_ru.lang @@ -18,7 +18,7 @@ betterquesting.title.party_invite=Пригласить игроков betterquesting.title.select_theme=Выбрать тему betterquesting.title.importers=Импортеры betterquesting.title.submit_station=Станция отправки -betterquesting.title.completion=Завершение: %d/%d +betterquesting.title.completion=Завершение: %d/%d (%s%%) betterquesting.btn.rewards=Награды betterquesting.btn.tasks=Задания