Fixes for alchemy dude's quest (#2352)

* Add drops for gadgets

Gadgets only have drop_id when they are not chests (chest_drop_id). When drop_id is not set (0), handleChestDrop quickly exits

* Implement QUEST_COND_ITEM_GIVING_FINISHED

Took the oppertunity to Rename ContentFinishGivingItem to ItemGiving

* Store accept conditions like fail and finish content are

Took the oppertunity to clean up some old code as well

conditions are stored in QuestManager

* Update src/main/java/emu/grasscutter/game/quest/QuestManager.java

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>

* Update ConditionItemGivingFinished.java

---------

Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>
This commit is contained in:
Nazrin 2023-09-10 16:20:28 -07:00 committed by GitHub
parent 47c96fd964
commit fbe2b138ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 55 additions and 76 deletions

View File

@ -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<GameQuest> 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<GameQuest> 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));
}

View File

@ -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) {

View File

@ -26,6 +26,7 @@ public final class QuestManager extends BasePlayerManager {
@Getter private final Player player;
@Getter private final Int2ObjectMap<GameMainQuest> mainQuests;
@Getter private Int2ObjectMap<int[]> acceptProgressLists;
@Getter private final List<Integer> 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());
}
});
}

View File

@ -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]);
}
}

View File

@ -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]);
}
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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<Integer>();
@ -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));
}
}
}