diff --git a/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java b/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java index 06acd48e3..b258b8310 100644 --- a/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java +++ b/src/main/java/emu/grasscutter/game/quest/GameMainQuest.java @@ -169,23 +169,6 @@ public class GameMainQuest { this.state = ParentQuestState.PARENT_QUEST_STATE_FINISHED; } - /* - * We also need to check for unfinished childQuests in this MainQuest - * force them to complete and send a packet about this to the user, - * because at some points there are special "invisible" child quests that control - * some situations. - * - * For example, subQuest 35312 is responsible for the event of leaving the territory - * of the island with a statue and automatically returns the character back, - * quest 35311 completes the main quest line 353 and starts 35501 from - * new MainQuest 355 but if 35312 is not completed after the completion - * of the main quest 353 - the character will not be able to leave place - * (return again and again) - */ - // this.getChildQuests().values().stream() - // .filter(p -> p.state != QuestState.QUEST_STATE_FINISHED) - // .forEach(GameQuest::finish); - this.getOwner().getSession().send(new PacketFinishedParentQuestUpdateNotify(this)); this.getOwner().getSession().send(new PacketCodexDataUpdateNotify(this)); @@ -383,46 +366,6 @@ public class GameMainQuest { } } - public void tryAcceptSubQuests(QuestCond condType, String paramStr, int... params) { - try { - List subQuestsWithCond = - getChildQuests().values().stream() - .filter( - p -> - p.getState() == QuestState.QUEST_STATE_UNSTARTED - || p.getState() == QuestState.UNFINISHED) - .filter( - p -> - p.getQuestData().getAcceptCond().stream() - .anyMatch( - q -> - condType == QuestCond.QUEST_COND_NONE || q.getType() == condType)) - .toList(); - var questSystem = owner.getServer().getQuestSystem(); - - for (GameQuest subQuestWithCond : subQuestsWithCond) { - var acceptCond = subQuestWithCond.getQuestData().getAcceptCond(); - int[] accept = new int[acceptCond.size()]; - - for (int i = 0; i < subQuestWithCond.getQuestData().getAcceptCond().size(); i++) { - var condition = acceptCond.get(i); - boolean result = - questSystem.triggerCondition( - getOwner(), subQuestWithCond.getQuestData(), condition, paramStr, params); - accept[i] = result ? 1 : 0; - } - - boolean shouldAccept = - LogicType.calculate(subQuestWithCond.getQuestData().getAcceptCondComb(), accept); - - if (shouldAccept) subQuestWithCond.start(); - } - this.save(); - } catch (Exception e) { - Grasscutter.getLogger().error("An error occurred while trying to accept quest.", e); - } - } - public void tryFailSubQuests(QuestContent condType, String paramStr, int... params) { try { List subQuestsWithCond = @@ -437,7 +380,7 @@ public class GameMainQuest { for (GameQuest subQuestWithCond : subQuestsWithCond) { val failCond = subQuestWithCond.getQuestData().getFailCond(); - for (int i = 0; i < subQuestWithCond.getQuestData().getFailCond().size(); i++) { + for (int i = 0; i < failCond.size(); i++) { val condition = failCond.get(i); if (condition.getType() == condType) { boolean result = @@ -445,7 +388,7 @@ public class GameMainQuest { .getServer() .getQuestSystem() .triggerContent(subQuestWithCond, condition, paramStr, params); - subQuestWithCond.getFailProgressList()[i] = result ? 1 : 0; + subQuestWithCond.setFailProgress(i, result ? 1 : 0); if (result) { getOwner().getSession().send(new PacketQuestProgressUpdateNotify(subQuestWithCond)); } diff --git a/src/main/java/emu/grasscutter/game/quest/GameQuest.java b/src/main/java/emu/grasscutter/game/quest/GameQuest.java index c62b3c0ef..3cfd362a2 100644 --- a/src/main/java/emu/grasscutter/game/quest/GameQuest.java +++ b/src/main/java/emu/grasscutter/game/quest/GameQuest.java @@ -158,6 +158,10 @@ public class GameQuest { public boolean clearProgress(boolean notifyDelete) { // TODO improve var oldState = state; + if (questData.getAcceptCond() != null && questData.getAcceptCond().size() != 0) { + this.getMainQuest().getQuestManager().getAcceptProgressLists().put(this.getSubQuestId(), new int[questData.getAcceptCond().size()]); + } + if (questData.getFinishCond() != null && questData.getFinishCond().size() != 0) { for (var condition : questData.getFinishCond()) { if (condition.getType() == QuestContent.QUEST_CONTENT_LUA_NOTIFY) { diff --git a/src/main/java/emu/grasscutter/game/quest/QuestManager.java b/src/main/java/emu/grasscutter/game/quest/QuestManager.java index 6611da1c7..16a3b1188 100644 --- a/src/main/java/emu/grasscutter/game/quest/QuestManager.java +++ b/src/main/java/emu/grasscutter/game/quest/QuestManager.java @@ -26,6 +26,7 @@ public final class QuestManager extends BasePlayerManager { @Getter private final Player player; @Getter private final Int2ObjectMap mainQuests; + @Getter private Int2ObjectMap acceptProgressLists; @Getter private final List loggedQuests; private long lastHourCheck = 0; @@ -52,6 +53,7 @@ public final class QuestManager extends BasePlayerManager { this.player = player; this.mainQuests = new Int2ObjectOpenHashMap<>(); this.loggedQuests = new ArrayList<>(); + this.acceptProgressLists = new Int2ObjectOpenHashMap<>(); if (DEBUG) { this.loggedQuests.addAll( @@ -484,8 +486,6 @@ public final class QuestManager extends BasePlayerManager { eventExecutor.submit(() -> triggerEvent(condType, paramStr, params)); } - // QUEST_EXEC are handled directly by each subQuest - public void triggerEvent(QuestCond condType, String paramStr, int... params) { Grasscutter.getLogger().trace("Trigger Event {}, {}, {}", condType, paramStr, params); var potentialQuests = GameData.getQuestDataByConditions(condType, params[0], paramStr); @@ -502,15 +502,17 @@ public final class QuestManager extends BasePlayerManager { return; } val acceptCond = questData.getAcceptCond(); - int[] accept = new int[acceptCond.size()]; + acceptProgressLists.putIfAbsent(questData.getId(), new int[acceptCond.size()]); for (int i = 0; i < acceptCond.size(); i++) { val condition = acceptCond.get(i); - boolean result = - questSystem.triggerCondition(owner, questData, condition, paramStr, params); - accept[i] = result ? 1 : 0; + if (condition.getType() == condType) { + boolean result = + questSystem.triggerCondition(owner, questData, condition, paramStr, params); + acceptProgressLists.get(questData.getId())[i] = result ? 1 : 0; + } } - boolean shouldAccept = LogicType.calculate(questData.getAcceptCondComb(), accept); + boolean shouldAccept = LogicType.calculate(questData.getAcceptCondComb(), acceptProgressLists.get(questData.getId())); if (this.loggedQuests.contains(questData.getId())) { Grasscutter.getLogger() .debug( @@ -522,7 +524,7 @@ public final class QuestManager extends BasePlayerManager { Arrays.stream(params) .mapToObj(String::valueOf) .collect(Collectors.joining(", "))); - for (var i = 0; i < accept.length; i++) { + for (var i = 0; i < acceptCond.size(); i++) { var condition = acceptCond.get(i); Grasscutter.getLogger() .debug( @@ -532,14 +534,14 @@ public final class QuestManager extends BasePlayerManager { .filter(value -> value > 0) .mapToObj(String::valueOf) .collect(Collectors.joining(", ")), - accept[i] == 1 ? "success" : "failure"); + acceptProgressLists.get(questData.getId())[i] == 1 ? "success" : "failure"); } } if (shouldAccept) { GameQuest quest = owner.getQuestManager().addQuest(questData); Grasscutter.getLogger() - .debug("Added quest {} result {}", questData.getSubId(), quest != null); + .debug("Added quest {}", questData.getSubId()); } }); } diff --git a/src/main/java/emu/grasscutter/game/quest/conditions/ConditionItemGivingFinished.java b/src/main/java/emu/grasscutter/game/quest/conditions/ConditionItemGivingFinished.java new file mode 100644 index 000000000..37d543b42 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/quest/conditions/ConditionItemGivingFinished.java @@ -0,0 +1,20 @@ +package emu.grasscutter.game.quest.conditions; + +import emu.grasscutter.data.excels.quest.QuestData; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.quest.QuestValueCond; +import emu.grasscutter.game.quest.enums.QuestCond; + +@QuestValueCond(QuestCond.QUEST_COND_ITEM_GIVING_FINISHED) +public class ConditionItemGivingFinished extends BaseCondition { + + @Override + public boolean execute( + Player owner, + QuestData questData, + QuestData.QuestAcceptCondition condition, + String paramStr, + int... params) { + return condition.getParam()[0] == params[0] && (condition.getParam()[1] == 0 || condition.getParam()[1] == params[1]); + } +} diff --git a/src/main/java/emu/grasscutter/game/quest/content/ContentFinishGivingItem.java b/src/main/java/emu/grasscutter/game/quest/content/ContentFinishItemGiving.java similarity index 68% rename from src/main/java/emu/grasscutter/game/quest/content/ContentFinishGivingItem.java rename to src/main/java/emu/grasscutter/game/quest/content/ContentFinishItemGiving.java index cd9ed53cd..b73626b7d 100644 --- a/src/main/java/emu/grasscutter/game/quest/content/ContentFinishGivingItem.java +++ b/src/main/java/emu/grasscutter/game/quest/content/ContentFinishItemGiving.java @@ -5,10 +5,10 @@ import emu.grasscutter.game.quest.*; import emu.grasscutter.game.quest.enums.QuestContent; @QuestValueContent(QuestContent.QUEST_CONTENT_FINISH_ITEM_GIVING) -public final class ContentFinishGivingItem extends BaseContent { +public final class ContentFinishItemGiving extends BaseContent { @Override public boolean execute( GameQuest quest, QuestData.QuestContentCondition condition, String paramStr, int... params) { - return condition.getParam()[0] == params[0] && condition.getParam()[1] == params[1]; + return condition.getParam()[0] == params[0] && (condition.getParam()[1] == 0 || condition.getParam()[1] == params[1]); } } diff --git a/src/main/java/emu/grasscutter/game/quest/enums/QuestCond.java b/src/main/java/emu/grasscutter/game/quest/enums/QuestCond.java index 190b313e2..7b43c442d 100644 --- a/src/main/java/emu/grasscutter/game/quest/enums/QuestCond.java +++ b/src/main/java/emu/grasscutter/game/quest/enums/QuestCond.java @@ -25,7 +25,7 @@ public enum QuestCond implements QuestTrigger { QUEST_COND_PLAYER_LEVEL_EQUAL_GREATER(17), QUEST_COND_SCENE_AREA_UNLOCKED(18), // missing, only NPC groups/talks QUEST_COND_ITEM_GIVING_ACTIVED(19), // missing - QUEST_COND_ITEM_GIVING_FINISHED(20), // missing + QUEST_COND_ITEM_GIVING_FINISHED(20), QUEST_COND_IS_DAYTIME(21), // only NPC groups QUEST_COND_CURRENT_AVATAR(22), // missing QUEST_COND_CURRENT_AREA(23), // missing diff --git a/src/main/java/emu/grasscutter/game/world/Scene.java b/src/main/java/emu/grasscutter/game/world/Scene.java index eb0bd86ce..ea3d186b1 100644 --- a/src/main/java/emu/grasscutter/game/world/Scene.java +++ b/src/main/java/emu/grasscutter/game/world/Scene.java @@ -535,7 +535,13 @@ public class Scene { "Can not solve monster drop: drop_id = {}, drop_tag = {}. Falling back to legacy drop system.", monster.getMetaMonster().drop_id, monster.getMetaMonster().drop_tag); - getWorld().getServer().getDropSystemLegacy().callDrop(monster); + world.getServer().getDropSystemLegacy().callDrop(monster); + } + } + + if (target instanceof EntityGadget gadget) { + if (gadget.getMetaGadget() != null) { + world.getServer().getDropSystem().handleChestDrop(gadget.getMetaGadget().drop_id, gadget.getMetaGadget().drop_count, gadget); } } diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneGadget.java b/src/main/java/emu/grasscutter/scripts/data/SceneGadget.java index 253a67e7d..8c8821ca7 100644 --- a/src/main/java/emu/grasscutter/scripts/data/SceneGadget.java +++ b/src/main/java/emu/grasscutter/scripts/data/SceneGadget.java @@ -7,6 +7,7 @@ import lombok.*; public class SceneGadget extends SceneObject { public int gadget_id; public int chest_drop_id; + public int drop_id; public int drop_count; public String drop_tag; boolean showcutscene; diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerItemGivingReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerItemGivingReq.java index 15b73fcf0..ebf368885 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerItemGivingReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerItemGivingReq.java @@ -2,6 +2,7 @@ package emu.grasscutter.server.packet.recv; import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; +import emu.grasscutter.game.quest.enums.QuestCond; import emu.grasscutter.game.quest.enums.QuestContent; import emu.grasscutter.net.packet.*; import emu.grasscutter.net.proto.ItemGivingReqOuterClass.ItemGivingReq; @@ -50,8 +51,9 @@ public final class HandlerItemGivingReq extends PacketHandler { player.sendPacket(new PacketItemGivingRsp(giveId, Mode.EXACT_SUCCESS)); // Remove the action from the active givings. questManager.removeGivingItemAction(giveId); - // Queue the content action. + // Queue the content and condition actions. questManager.queueEvent(QuestContent.QUEST_CONTENT_FINISH_ITEM_GIVING, giveId, 0); + questManager.queueEvent(QuestCond.QUEST_COND_ITEM_GIVING_FINISHED, giveId, 0); } case GIVING_METHOD_VAGUE_GROUP -> { var matchedGroups = new ArrayList(); @@ -96,8 +98,9 @@ public final class HandlerItemGivingReq extends PacketHandler { player.sendPacket(new PacketItemGivingRsp(matchedGroups.get(0), Mode.GROUP_SUCCESS)); // Mark the giving action as completed. questManager.markCompleted(giveId); - // Queue the content action. - questManager.queueEvent(QuestContent.QUEST_CONTENT_FINISH_ITEM_GIVING, giveId, 0); + // Queue the content and condition actions. + questManager.queueEvent(QuestContent.QUEST_CONTENT_FINISH_ITEM_GIVING, giveId, matchedGroups.get(0)); + questManager.queueEvent(QuestCond.QUEST_COND_ITEM_GIVING_FINISHED, giveId, matchedGroups.get(0)); } } }