Skip to content
Snippets Groups Projects
Commit 12318021 authored by Melledy's avatar Melledy
Browse files

Implement basic quest condition handling

Quests that require talking to npcs now work.
parent 7befebe3
Branches
Tags
No related merge requests found
Showing
with 566 additions and 95 deletions
package emu.grasscutter.data.custom; package emu.grasscutter.data.custom;
import emu.grasscutter.game.quest.enums.LogicType; import emu.grasscutter.game.quest.enums.LogicType;
import emu.grasscutter.game.quest.enums.QuestCondType; import emu.grasscutter.game.quest.enums.QuestTriggerType;
import emu.grasscutter.game.quest.enums.QuestType; import emu.grasscutter.game.quest.enums.QuestType;
public class QuestConfigData { public class QuestConfigData {
...@@ -90,10 +90,10 @@ public class QuestConfigData { ...@@ -90,10 +90,10 @@ public class QuestConfigData {
} }
public class QuestCondition { public class QuestCondition {
private QuestCondType type; private QuestTriggerType type;
private int[] param; private int[] param;
public QuestCondType getType() { public QuestTriggerType getType() {
return type; return type;
} }
......
...@@ -3,10 +3,13 @@ package emu.grasscutter.game.quest; ...@@ -3,10 +3,13 @@ package emu.grasscutter.game.quest;
import dev.morphia.annotations.Entity; import dev.morphia.annotations.Entity;
import dev.morphia.annotations.Transient; import dev.morphia.annotations.Transient;
import emu.grasscutter.data.custom.QuestConfig; import emu.grasscutter.data.custom.QuestConfig;
import emu.grasscutter.data.custom.QuestConfigData.QuestCondition;
import emu.grasscutter.data.custom.QuestConfigData.SubQuestConfigData; import emu.grasscutter.data.custom.QuestConfigData.SubQuestConfigData;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.quest.enums.LogicType;
import emu.grasscutter.game.quest.enums.QuestState; import emu.grasscutter.game.quest.enums.QuestState;
import emu.grasscutter.net.proto.QuestOuterClass.Quest; import emu.grasscutter.net.proto.QuestOuterClass.Quest;
import emu.grasscutter.server.packet.send.PacketQuestListUpdateNotify;
import emu.grasscutter.server.packet.send.PacketQuestProgressUpdateNotify; import emu.grasscutter.server.packet.send.PacketQuestProgressUpdateNotify;
import emu.grasscutter.utils.Utils; import emu.grasscutter.utils.Utils;
...@@ -137,19 +140,34 @@ public class GameQuest { ...@@ -137,19 +140,34 @@ public class GameQuest {
} }
this.getOwner().getSession().send(new PacketQuestProgressUpdateNotify(this)); this.getOwner().getSession().send(new PacketQuestProgressUpdateNotify(this));
this.getOwner().getSession().send(new PacketQuestListUpdateNotify(this));
// Finish main quest if all child quests are done
this.tryFinishMainQuest();
this.save(); this.save();
this.tryAcceptQuestLine();
} }
public boolean tryFinishMainQuest() { public boolean tryAcceptQuestLine() {
try { try {
SubQuestConfigData subQuestData = getConfig().getMainQuest().getSubQuests()[getConfig().getMainQuest().getSubQuests().length - 1]; for (SubQuestConfigData questData : getConfig().getMainQuest().getSubQuests()) {
GameQuest quest = getMainQuest().getChildQuestById(questData.getSubId());
if (quest == null) {
int[] accept = new int[questData.getAcceptCond().length];
if (subQuestData.getSubId() == this.getQuestId()) { // TODO
getMainQuest().finish(); for (int i = 0; i < questData.getAcceptCond().length; i++) {
return true; QuestCondition condition = questData.getAcceptCond()[i];
boolean result = getOwner().getServer().getQuestHandler().triggerCondition(this, condition);
accept[i] = result ? 1 : 0;
}
boolean shouldAccept = LogicType.calculate(questData.getAcceptCondComb(), accept);
if (shouldAccept) {
this.getOwner().getQuestManager().addQuest(questData.getSubId());
}
}
} }
} catch (Exception e) { } catch (Exception e) {
......
package emu.grasscutter.game.quest; package emu.grasscutter.game.quest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import emu.grasscutter.data.GameData; import emu.grasscutter.data.GameData;
import emu.grasscutter.data.custom.QuestConfig; import emu.grasscutter.data.custom.QuestConfig;
import emu.grasscutter.data.custom.QuestConfigData.QuestCondition;
import emu.grasscutter.data.custom.QuestConfigData.SubQuestConfigData;
import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.database.DatabaseHelper;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.quest.enums.QuestTriggerType;
import emu.grasscutter.game.quest.enums.LogicType;
import emu.grasscutter.game.quest.enums.QuestState; import emu.grasscutter.game.quest.enums.QuestState;
import emu.grasscutter.server.packet.send.PacketFinishedParentQuestUpdateNotify; import emu.grasscutter.server.packet.send.PacketFinishedParentQuestUpdateNotify;
import emu.grasscutter.server.packet.send.PacketQuestListUpdateNotify; import emu.grasscutter.server.packet.send.PacketQuestListUpdateNotify;
import emu.grasscutter.server.packet.send.PacketQuestProgressUpdateNotify;
import emu.grasscutter.server.packet.send.PacketServerCondMeetQuestListUpdateNotify; import emu.grasscutter.server.packet.send.PacketServerCondMeetQuestListUpdateNotify;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
...@@ -59,6 +68,17 @@ public class QuestManager { ...@@ -59,6 +68,17 @@ public class QuestManager {
} }
} }
// TODO
public void forEachActiveQuest(Consumer<GameQuest> callback) {
for (GameMainQuest mainQuest : getQuests().values()) {
for (GameQuest quest : mainQuest.getChildQuests().values()) {
if (quest.getState() != QuestState.QUEST_STATE_FINISHED) {
callback.accept(quest);
}
}
}
}
public GameMainQuest addMainQuest(QuestConfig questConfig) { public GameMainQuest addMainQuest(QuestConfig questConfig) {
GameMainQuest mainQuest = new GameMainQuest(getPlayer(), questConfig.getMainQuest().getId()); GameMainQuest mainQuest = new GameMainQuest(getPlayer(), questConfig.getMainQuest().getId());
getQuests().put(mainQuest.getParentQuestId(), mainQuest); getQuests().put(mainQuest.getParentQuestId(), mainQuest);
...@@ -102,6 +122,50 @@ public class QuestManager { ...@@ -102,6 +122,50 @@ public class QuestManager {
return quest; return quest;
} }
public void triggerEvent(QuestTriggerType condType, int... params) {
Set<GameQuest> changedQuests = new HashSet<>();
this.forEachActiveQuest(quest -> {
SubQuestConfigData data = quest.getConfig().getSubQuest();
for (int i = 0; i < data.getFinishCond().length; i++) {
if (quest.getFinishProgressList()[i] == 1) {
continue;
}
QuestCondition condition = data.getFinishCond()[i];
if (condition.getType() != condType) {
continue;
}
boolean result = getPlayer().getServer().getQuestHandler().triggerContent(quest, condition, params);
if (result) {
quest.getFinishProgressList()[i] = 1;
changedQuests.add(quest);
}
}
});
for (GameQuest quest : changedQuests) {
LogicType logicType = quest.getConfig().getSubQuest().getFailCondComb();
int[] progress = quest.getFinishProgressList();
// Handle logical comb
boolean finish = LogicType.calculate(logicType, progress);
// Finish
if (finish) {
quest.finish();
} else {
getPlayer().sendPacket(new PacketQuestProgressUpdateNotify(quest));
quest.save();
}
}
}
public void loadFromDatabase() { public void loadFromDatabase() {
List<GameMainQuest> quests = DatabaseHelper.getAllQuests(getPlayer()); List<GameMainQuest> quests = DatabaseHelper.getAllQuests(getPlayer());
......
package emu.grasscutter.game.quest;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import emu.grasscutter.game.quest.enums.QuestTriggerType;
@Retention(RetentionPolicy.RUNTIME)
public @interface QuestValue {
QuestTriggerType value();
}
package emu.grasscutter.game.quest;
import java.util.Set;
import org.reflections.Reflections;
import emu.grasscutter.data.custom.QuestConfigData.QuestCondition;
import emu.grasscutter.game.quest.enums.QuestTriggerType;
import emu.grasscutter.game.quest.handlers.QuestBaseHandler;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.server.game.GameServer;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
@SuppressWarnings("unchecked")
public class ServerQuestHandler {
private final Int2ObjectMap<QuestBaseHandler> condHandlers;
private final Int2ObjectMap<QuestBaseHandler> contHandlers;
private final Int2ObjectMap<QuestBaseHandler> execHandlers;
public ServerQuestHandler() {
this.condHandlers = new Int2ObjectOpenHashMap<>();
this.contHandlers = new Int2ObjectOpenHashMap<>();
this.execHandlers = new Int2ObjectOpenHashMap<>();
this.registerHandlers();
}
public void registerHandlers() {
this.registerHandlers(this.condHandlers, "emu.grasscutter.game.quest.conditions");
this.registerHandlers(this.contHandlers, "emu.grasscutter.game.quest.content");
this.registerHandlers(this.execHandlers, "emu.grasscutter.game.quest.exec");
}
public void registerHandlers(Int2ObjectMap<QuestBaseHandler> map, String packageName) {
Reflections reflections = new Reflections(packageName);
Set<?> handlerClasses = reflections.getSubTypesOf(QuestBaseHandler.class);
for (Object obj : handlerClasses) {
this.registerPacketHandler(map, (Class<? extends QuestBaseHandler>) obj);
}
}
public void registerPacketHandler(Int2ObjectMap<QuestBaseHandler> map, Class<? extends QuestBaseHandler> handlerClass) {
try {
QuestValue opcode = handlerClass.getAnnotation(QuestValue.class);
if (opcode == null || opcode.value().getValue() <= 0) {
return;
}
QuestBaseHandler packetHandler = (QuestBaseHandler) handlerClass.newInstance();
map.put(opcode.value().getValue(), packetHandler);
} catch (Exception e) {
e.printStackTrace();
}
}
// TODO make cleaner
public boolean triggerCondition(GameQuest quest, QuestCondition condition, int... params) {
QuestBaseHandler handler = condHandlers.get(condition.getType().getValue());
if (handler == null || quest.getConfig() == null) {
return false;
}
return handler.execute(quest, condition, params);
}
public boolean triggerContent(GameQuest quest, QuestCondition condition, int... params) {
QuestBaseHandler handler = contHandlers.get(condition.getType().getValue());
if (handler == null || quest.getConfig() == null) {
return false;
}
return handler.execute(quest, condition, params);
}
public boolean triggerExec(GameQuest quest, QuestCondition condition, int... params) {
QuestBaseHandler handler = execHandlers.get(condition.getType().getValue());
if (handler == null || quest.getConfig() == null) {
return false;
}
return handler.execute(quest, condition, params);
}
}
package emu.grasscutter.game.quest.conditions;
import emu.grasscutter.data.custom.QuestConfigData.QuestCondition;
import emu.grasscutter.game.quest.QuestValue;
import emu.grasscutter.game.quest.GameQuest;
import emu.grasscutter.game.quest.enums.QuestTriggerType;
import emu.grasscutter.game.quest.handlers.QuestBaseHandler;
@QuestValue(QuestTriggerType.QUEST_CONTENT_NONE)
public class BaseCondition extends QuestBaseHandler {
@Override
public boolean execute(GameQuest quest, QuestCondition condition, int... params) {
// TODO Auto-generated method stub
return false;
}
}
package emu.grasscutter.game.quest.conditions;
import emu.grasscutter.data.custom.QuestConfigData.QuestCondition;
import emu.grasscutter.game.quest.QuestValue;
import emu.grasscutter.game.quest.GameQuest;
import emu.grasscutter.game.quest.enums.QuestTriggerType;
import emu.grasscutter.game.quest.handlers.QuestBaseHandler;
@QuestValue(QuestTriggerType.QUEST_COND_PLAYER_LEVEL_EQUAL_GREATER)
public class ConditionPlayerLevelEqualGreater extends QuestBaseHandler {
@Override
public boolean execute(GameQuest quest, QuestCondition condition, int... params) {
return quest.getOwner().getLevel() >= condition.getParam()[0];
}
}
package emu.grasscutter.game.quest.conditions;
import emu.grasscutter.data.custom.QuestConfigData.QuestCondition;
import emu.grasscutter.game.quest.QuestValue;
import emu.grasscutter.game.quest.GameQuest;
import emu.grasscutter.game.quest.enums.QuestTriggerType;
import emu.grasscutter.game.quest.handlers.QuestBaseHandler;
@QuestValue(QuestTriggerType.QUEST_COND_STATE_EQUAL)
public class ConditionStateEqual extends QuestBaseHandler {
@Override
public boolean execute(GameQuest quest, QuestCondition condition, int... params) {
GameQuest checkQuest = quest.getOwner().getQuestManager().getQuestById(condition.getParam()[0]);
if (checkQuest != null) {
return checkQuest.getState().getValue() == condition.getParam()[1];
}
return false;
}
}
package emu.grasscutter.game.quest.content;
import emu.grasscutter.data.custom.QuestConfigData.QuestCondition;
import emu.grasscutter.game.quest.QuestValue;
import emu.grasscutter.game.quest.GameQuest;
import emu.grasscutter.game.quest.enums.QuestTriggerType;
import emu.grasscutter.game.quest.handlers.QuestBaseHandler;
@QuestValue(QuestTriggerType.QUEST_CONTENT_NONE)
public class BaseContent extends QuestBaseHandler {
@Override
public boolean execute(GameQuest quest, QuestCondition condition, int... params) {
// TODO Auto-generated method stub
return false;
}
}
package emu.grasscutter.game.quest.content;
import emu.grasscutter.data.custom.QuestConfigData.QuestCondition;
import emu.grasscutter.game.quest.QuestValue;
import emu.grasscutter.game.quest.GameQuest;
import emu.grasscutter.game.quest.enums.QuestTriggerType;
import emu.grasscutter.game.quest.handlers.QuestBaseHandler;
@QuestValue(QuestTriggerType.QUEST_CONTENT_COMPLETE_TALK)
public class ContentCompleteTalk extends QuestBaseHandler {
@Override
public boolean execute(GameQuest quest, QuestCondition condition, int... params) {
return condition.getParam()[0] == params[0];
}
}
package emu.grasscutter.game.quest.enums; package emu.grasscutter.game.quest.enums;
import java.util.Arrays;
public enum LogicType { public enum LogicType {
LOGIC_NONE (0), LOGIC_NONE (0),
LOGIC_AND (1), LOGIC_AND (1),
...@@ -20,4 +22,22 @@ public enum LogicType { ...@@ -20,4 +22,22 @@ public enum LogicType {
public int getValue() { public int getValue() {
return value; return value;
} }
public static boolean calculate(LogicType logicType, int[] progress) {
if (logicType == null) {
return progress[0] == 1;
}
switch (logicType) {
case LOGIC_AND -> {
return Arrays.stream(progress).allMatch(i -> i == 1);
}
case LOGIC_OR -> {
return Arrays.stream(progress).anyMatch(i -> i == 1);
}
default -> {
return Arrays.stream(progress).anyMatch(i -> i == 1);
}
}
}
} }
package emu.grasscutter.game.quest.enums;
public enum QuestExecType {
QUEST_EXEC_NONE (0),
QUEST_EXEC_DEL_PACK_ITEM (1),
QUEST_EXEC_UNLOCK_POINT (2),
QUEST_EXEC_UNLOCK_AREA (3),
QUEST_EXEC_UNLOCK_FORCE (4),
QUEST_EXEC_LOCK_FORCE (5),
QUEST_EXEC_CHANGE_AVATAR_ELEMET (6),
QUEST_EXEC_REFRESH_GROUP_MONSTER (7),
QUEST_EXEC_SET_IS_FLYABLE (8),
QUEST_EXEC_SET_IS_WEATHER_LOCKED (9),
QUEST_EXEC_SET_IS_GAME_TIME_LOCKED (10),
QUEST_EXEC_SET_IS_TRANSFERABLE (11),
QUEST_EXEC_GRANT_TRIAL_AVATAR (12),
QUEST_EXEC_OPEN_BORED (13),
QUEST_EXEC_ROLLBACK_QUEST (14),
QUEST_EXEC_NOTIFY_GROUP_LUA (15),
QUEST_EXEC_SET_OPEN_STATE (16),
QUEST_EXEC_LOCK_POINT (17),
QUEST_EXEC_DEL_PACK_ITEM_BATCH (18),
QUEST_EXEC_REFRESH_GROUP_SUITE (19),
QUEST_EXEC_REMOVE_TRIAL_AVATAR (20),
QUEST_EXEC_SET_GAME_TIME (21),
QUEST_EXEC_SET_WEATHER_GADGET (22),
QUEST_EXEC_ADD_QUEST_PROGRESS (23),
QUEST_EXEC_NOTIFY_DAILY_TASK (24),
QUEST_EXEC_CREATE_PATTERN_GROUP (25),
QUEST_EXEC_REMOVE_PATTERN_GROUP (26),
QUEST_EXEC_REFRESH_GROUP_SUITE_RANDOM (27),
QUEST_EXEC_ACTIVE_ITEM_GIVING (28),
QUEST_EXEC_DEL_ALL_SPECIFIC_PACK_ITEM (29),
QUEST_EXEC_ROLLBACK_PARENT_QUEST (30),
QUEST_EXEC_LOCK_AVATAR_TEAM (31),
QUEST_EXEC_UNLOCK_AVATAR_TEAM (32),
QUEST_EXEC_UPDATE_PARENT_QUEST_REWARD_INDEX (33),
QUEST_EXEC_SET_DAILY_TASK_VAR (34),
QUEST_EXEC_INC_DAILY_TASK_VAR (35),
QUEST_EXEC_DEC_DAILY_TASK_VAR (36),
QUEST_EXEC_ACTIVE_ACTIVITY_COND_STATE (37),
QUEST_EXEC_INACTIVE_ACTIVITY_COND_STATE (38),
QUEST_EXEC_ADD_CUR_AVATAR_ENERGY (39),
QUEST_EXEC_START_BARGAIN (41),
QUEST_EXEC_STOP_BARGAIN (42),
QUEST_EXEC_SET_QUEST_GLOBAL_VAR (43),
QUEST_EXEC_INC_QUEST_GLOBAL_VAR (44),
QUEST_EXEC_DEC_QUEST_GLOBAL_VAR (45),
QUEST_EXEC_REGISTER_DYNAMIC_GROUP (46),
QUEST_EXEC_UNREGISTER_DYNAMIC_GROUP (47),
QUEST_EXEC_SET_QUEST_VAR (48),
QUEST_EXEC_INC_QUEST_VAR (49),
QUEST_EXEC_DEC_QUEST_VAR (50),
QUEST_EXEC_RANDOM_QUEST_VAR (51),
QUEST_EXEC_ACTIVATE_SCANNING_PIC (52),
QUEST_EXEC_RELOAD_SCENE_TAG (53),
QUEST_EXEC_REGISTER_DYNAMIC_GROUP_ONLY (54),
QUEST_EXEC_CHANGE_SKILL_DEPOT (55),
QUEST_EXEC_ADD_SCENE_TAG (56),
QUEST_EXEC_DEL_SCENE_TAG (57),
QUEST_EXEC_INIT_TIME_VAR (58),
QUEST_EXEC_CLEAR_TIME_VAR (59),
QUEST_EXEC_MODIFY_CLIMATE_AREA (60),
QUEST_EXEC_GRANT_TRIAL_AVATAR_AND_LOCK_TEAM (61),
QUEST_EXEC_CHANGE_MAP_AREA_STATE (62),
QUEST_EXEC_DEACTIVE_ITEM_GIVING (63),
QUEST_EXEC_CHANGE_SCENE_LEVEL_TAG (64),
QUEST_EXEC_UNLOCK_PLAYER_WORLD_SCENE (65),
QUEST_EXEC_LOCK_PLAYER_WORLD_SCENE (66),
QUEST_EXEC_FAIL_MAINCOOP (67),
QUEST_EXEC_MODIFY_WEATHER_AREA (68);
private final int value;
QuestExecType(int id) {
this.value = id;
}
public int getValue() {
return value;
}
}
package emu.grasscutter.game.quest.enums; package emu.grasscutter.game.quest.enums;
public enum QuestCondType { public enum QuestTriggerType {
QUEST_COND_NONE (0), QUEST_COND_NONE (0),
QUEST_COND_STATE_EQUAL (1), QUEST_COND_STATE_EQUAL (1),
QUEST_COND_STATE_NOT_EQUAL (2), QUEST_COND_STATE_NOT_EQUAL (2),
...@@ -78,11 +78,154 @@ public enum QuestCondType { ...@@ -78,11 +78,154 @@ public enum QuestCondType {
QUEST_COND_LUNARITE_MARK_ALL_FINISH (74), QUEST_COND_LUNARITE_MARK_ALL_FINISH (74),
QUEST_COND_NEW_HOMEWORLD_SHOP_ITEM (75), QUEST_COND_NEW_HOMEWORLD_SHOP_ITEM (75),
QUEST_COND_SCENE_POINT_UNLOCK (76), QUEST_COND_SCENE_POINT_UNLOCK (76),
QUEST_COND_SCENE_LEVEL_TAG_EQ (77); QUEST_COND_SCENE_LEVEL_TAG_EQ (77),
QUEST_CONTENT_NONE (0),
QUEST_CONTENT_KILL_MONSTER (1),
QUEST_CONTENT_COMPLETE_TALK (2),
QUEST_CONTENT_MONSTER_DIE (3),
QUEST_CONTENT_FINISH_PLOT (4),
QUEST_CONTENT_OBTAIN_ITEM (5),
QUEST_CONTENT_TRIGGER_FIRE (6),
QUEST_CONTENT_CLEAR_GROUP_MONSTER (7),
QUEST_CONTENT_NOT_FINISH_PLOT (8),
QUEST_CONTENT_ENTER_DUNGEON (9),
QUEST_CONTENT_ENTER_MY_WORLD (10),
QUEST_CONTENT_FINISH_DUNGEON (11),
QUEST_CONTENT_DESTROY_GADGET (12),
QUEST_CONTENT_OBTAIN_MATERIAL_WITH_SUBTYPE (13),
QUEST_CONTENT_NICK_NAME (14),
QUEST_CONTENT_WORKTOP_SELECT (15),
QUEST_CONTENT_SEAL_BATTLE_RESULT (16),
QUEST_CONTENT_ENTER_ROOM (17),
QUEST_CONTENT_GAME_TIME_TICK (18),
QUEST_CONTENT_FAIL_DUNGEON (19),
QUEST_CONTENT_LUA_NOTIFY (20),
QUEST_CONTENT_TEAM_DEAD (21),
QUEST_CONTENT_COMPLETE_ANY_TALK (22),
QUEST_CONTENT_UNLOCK_TRANS_POINT (23),
QUEST_CONTENT_ADD_QUEST_PROGRESS (24),
QUEST_CONTENT_INTERACT_GADGET (25),
QUEST_CONTENT_DAILY_TASK_COMP_FINISH (26),
QUEST_CONTENT_FINISH_ITEM_GIVING (27),
QUEST_CONTENT_SKILL (107),
QUEST_CONTENT_CITY_LEVEL_UP (109),
QUEST_CONTENT_PATTERN_GROUP_CLEAR_MONSTER (110),
QUEST_CONTENT_ITEM_LESS_THAN (111),
QUEST_CONTENT_PLAYER_LEVEL_UP (112),
QUEST_CONTENT_DUNGEON_OPEN_STATUE (113),
QUEST_CONTENT_UNLOCK_AREA (114),
QUEST_CONTENT_OPEN_CHEST_WITH_GADGET_ID (115),
QUEST_CONTENT_UNLOCK_TRANS_POINT_WITH_TYPE (116),
QUEST_CONTENT_FINISH_DAILY_DUNGEON (117),
QUEST_CONTENT_FINISH_WEEKLY_DUNGEON (118),
QUEST_CONTENT_QUEST_VAR_EQUAL (119),
QUEST_CONTENT_QUEST_VAR_GREATER (120),
QUEST_CONTENT_QUEST_VAR_LESS (121),
QUEST_CONTENT_OBTAIN_VARIOUS_ITEM (122),
QUEST_CONTENT_FINISH_TOWER_LEVEL (123),
QUEST_CONTENT_BARGAIN_SUCC (124),
QUEST_CONTENT_BARGAIN_FAIL (125),
QUEST_CONTENT_ITEM_LESS_THAN_BARGAIN (126),
QUEST_CONTENT_ACTIVITY_TRIGGER_FAILED (127),
QUEST_CONTENT_MAIN_COOP_ENTER_SAVE_POINT (128),
QUEST_CONTENT_ANY_MANUAL_TRANSPORT (129),
QUEST_CONTENT_USE_ITEM (130),
QUEST_CONTENT_MAIN_COOP_ENTER_ANY_SAVE_POINT (131),
QUEST_CONTENT_ENTER_MY_HOME_WORLD (132),
QUEST_CONTENT_ENTER_MY_WORLD_SCENE (133),
QUEST_CONTENT_TIME_VAR_GT_EQ (134),
QUEST_CONTENT_TIME_VAR_PASS_DAY (135),
QUEST_CONTENT_QUEST_STATE_EQUAL (136),
QUEST_CONTENT_QUEST_STATE_NOT_EQUAL (137),
QUEST_CONTENT_UNLOCKED_RECIPE (138),
QUEST_CONTENT_NOT_UNLOCKED_RECIPE (139),
QUEST_CONTENT_FISHING_SUCC (140),
QUEST_CONTENT_ENTER_ROGUE_DUNGEON (141),
QUEST_CONTENT_USE_WIDGET (142),
QUEST_CONTENT_CAPTURE_SUCC (143),
QUEST_CONTENT_CAPTURE_USE_CAPTURETAG_LIST (144),
QUEST_CONTENT_CAPTURE_USE_MATERIAL_LIST (145),
QUEST_CONTENT_ENTER_VEHICLE (147),
QUEST_CONTENT_SCENE_LEVEL_TAG_EQ (148),
QUEST_CONTENT_LEAVE_SCENE (149),
QUEST_CONTENT_LEAVE_SCENE_RANGE (150),
QUEST_CONTENT_IRODORI_FINISH_FLOWER_COMBINATION (151),
QUEST_CONTENT_IRODORI_POETRY_REACH_MIN_PROGRESS (152),
QUEST_CONTENT_IRODORI_POETRY_FINISH_FILL_POETRY (153),
QUEST_EXEC_NONE (0),
QUEST_EXEC_DEL_PACK_ITEM (1),
QUEST_EXEC_UNLOCK_POINT (2),
QUEST_EXEC_UNLOCK_AREA (3),
QUEST_EXEC_UNLOCK_FORCE (4),
QUEST_EXEC_LOCK_FORCE (5),
QUEST_EXEC_CHANGE_AVATAR_ELEMET (6),
QUEST_EXEC_REFRESH_GROUP_MONSTER (7),
QUEST_EXEC_SET_IS_FLYABLE (8),
QUEST_EXEC_SET_IS_WEATHER_LOCKED (9),
QUEST_EXEC_SET_IS_GAME_TIME_LOCKED (10),
QUEST_EXEC_SET_IS_TRANSFERABLE (11),
QUEST_EXEC_GRANT_TRIAL_AVATAR (12),
QUEST_EXEC_OPEN_BORED (13),
QUEST_EXEC_ROLLBACK_QUEST (14),
QUEST_EXEC_NOTIFY_GROUP_LUA (15),
QUEST_EXEC_SET_OPEN_STATE (16),
QUEST_EXEC_LOCK_POINT (17),
QUEST_EXEC_DEL_PACK_ITEM_BATCH (18),
QUEST_EXEC_REFRESH_GROUP_SUITE (19),
QUEST_EXEC_REMOVE_TRIAL_AVATAR (20),
QUEST_EXEC_SET_GAME_TIME (21),
QUEST_EXEC_SET_WEATHER_GADGET (22),
QUEST_EXEC_ADD_QUEST_PROGRESS (23),
QUEST_EXEC_NOTIFY_DAILY_TASK (24),
QUEST_EXEC_CREATE_PATTERN_GROUP (25),
QUEST_EXEC_REMOVE_PATTERN_GROUP (26),
QUEST_EXEC_REFRESH_GROUP_SUITE_RANDOM (27),
QUEST_EXEC_ACTIVE_ITEM_GIVING (28),
QUEST_EXEC_DEL_ALL_SPECIFIC_PACK_ITEM (29),
QUEST_EXEC_ROLLBACK_PARENT_QUEST (30),
QUEST_EXEC_LOCK_AVATAR_TEAM (31),
QUEST_EXEC_UNLOCK_AVATAR_TEAM (32),
QUEST_EXEC_UPDATE_PARENT_QUEST_REWARD_INDEX (33),
QUEST_EXEC_SET_DAILY_TASK_VAR (34),
QUEST_EXEC_INC_DAILY_TASK_VAR (35),
QUEST_EXEC_DEC_DAILY_TASK_VAR (36),
QUEST_EXEC_ACTIVE_ACTIVITY_COND_STATE (37),
QUEST_EXEC_INACTIVE_ACTIVITY_COND_STATE (38),
QUEST_EXEC_ADD_CUR_AVATAR_ENERGY (39),
QUEST_EXEC_START_BARGAIN (41),
QUEST_EXEC_STOP_BARGAIN (42),
QUEST_EXEC_SET_QUEST_GLOBAL_VAR (43),
QUEST_EXEC_INC_QUEST_GLOBAL_VAR (44),
QUEST_EXEC_DEC_QUEST_GLOBAL_VAR (45),
QUEST_EXEC_REGISTER_DYNAMIC_GROUP (46),
QUEST_EXEC_UNREGISTER_DYNAMIC_GROUP (47),
QUEST_EXEC_SET_QUEST_VAR (48),
QUEST_EXEC_INC_QUEST_VAR (49),
QUEST_EXEC_DEC_QUEST_VAR (50),
QUEST_EXEC_RANDOM_QUEST_VAR (51),
QUEST_EXEC_ACTIVATE_SCANNING_PIC (52),
QUEST_EXEC_RELOAD_SCENE_TAG (53),
QUEST_EXEC_REGISTER_DYNAMIC_GROUP_ONLY (54),
QUEST_EXEC_CHANGE_SKILL_DEPOT (55),
QUEST_EXEC_ADD_SCENE_TAG (56),
QUEST_EXEC_DEL_SCENE_TAG (57),
QUEST_EXEC_INIT_TIME_VAR (58),
QUEST_EXEC_CLEAR_TIME_VAR (59),
QUEST_EXEC_MODIFY_CLIMATE_AREA (60),
QUEST_EXEC_GRANT_TRIAL_AVATAR_AND_LOCK_TEAM (61),
QUEST_EXEC_CHANGE_MAP_AREA_STATE (62),
QUEST_EXEC_DEACTIVE_ITEM_GIVING (63),
QUEST_EXEC_CHANGE_SCENE_LEVEL_TAG (64),
QUEST_EXEC_UNLOCK_PLAYER_WORLD_SCENE (65),
QUEST_EXEC_LOCK_PLAYER_WORLD_SCENE (66),
QUEST_EXEC_FAIL_MAINCOOP (67),
QUEST_EXEC_MODIFY_WEATHER_AREA (68);
private final int value; private final int value;
QuestCondType(int id) { QuestTriggerType(int id) {
this.value = id; this.value = id;
} }
......
package emu.grasscutter.game.quest.handlers;
import emu.grasscutter.data.custom.QuestConfigData.QuestCondition;
import emu.grasscutter.game.quest.GameQuest;
public abstract class QuestBaseHandler {
public abstract boolean execute(GameQuest quest, QuestCondition condition, int... params);
}
...@@ -14,6 +14,8 @@ import emu.grasscutter.game.managers.ChatManager; ...@@ -14,6 +14,8 @@ import emu.grasscutter.game.managers.ChatManager;
import emu.grasscutter.game.managers.InventoryManager; import emu.grasscutter.game.managers.InventoryManager;
import emu.grasscutter.game.managers.MultiplayerManager; import emu.grasscutter.game.managers.MultiplayerManager;
import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.quest.ServerQuestHandler;
import emu.grasscutter.game.quest.handlers.QuestBaseHandler;
import emu.grasscutter.game.shop.ShopManager; import emu.grasscutter.game.shop.ShopManager;
import emu.grasscutter.game.tower.TowerScheduleManager; import emu.grasscutter.game.tower.TowerScheduleManager;
import emu.grasscutter.game.world.World; import emu.grasscutter.game.world.World;
...@@ -37,6 +39,7 @@ import static emu.grasscutter.Configuration.*; ...@@ -37,6 +39,7 @@ import static emu.grasscutter.Configuration.*;
public final class GameServer extends KcpServer { public final class GameServer extends KcpServer {
private final InetSocketAddress address; private final InetSocketAddress address;
private final GameServerPacketHandler packetHandler; private final GameServerPacketHandler packetHandler;
private final ServerQuestHandler questHandler;
private final Map<Integer, Player> players; private final Map<Integer, Player> players;
private final Set<World> worlds; private final Set<World> worlds;
...@@ -68,6 +71,7 @@ public final class GameServer extends KcpServer { ...@@ -68,6 +71,7 @@ public final class GameServer extends KcpServer {
this.setServerInitializer(new GameServerInitializer(this)); this.setServerInitializer(new GameServerInitializer(this));
this.address = address; this.address = address;
this.packetHandler = new GameServerPacketHandler(PacketHandler.class); this.packetHandler = new GameServerPacketHandler(PacketHandler.class);
this.questHandler = new ServerQuestHandler();
this.players = new ConcurrentHashMap<>(); this.players = new ConcurrentHashMap<>();
this.worlds = Collections.synchronizedSet(new HashSet<>()); this.worlds = Collections.synchronizedSet(new HashSet<>());
...@@ -91,6 +95,10 @@ public final class GameServer extends KcpServer { ...@@ -91,6 +95,10 @@ public final class GameServer extends KcpServer {
return packetHandler; return packetHandler;
} }
public ServerQuestHandler getQuestHandler() {
return questHandler;
}
public Map<Integer, Player> getPlayers() { public Map<Integer, Player> getPlayers() {
return players; return players;
} }
......
package emu.grasscutter.server.packet.recv; package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.inventory.GameItem;
import emu.grasscutter.game.quest.enums.QuestTriggerType;
import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.NpcTalkReqOuterClass.NpcTalkReq; import emu.grasscutter.net.proto.NpcTalkReqOuterClass.NpcTalkReq;
...@@ -15,6 +16,8 @@ public class HandlerNpcTalkReq extends PacketHandler { ...@@ -15,6 +16,8 @@ public class HandlerNpcTalkReq extends PacketHandler {
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
NpcTalkReq req = NpcTalkReq.parseFrom(payload); NpcTalkReq req = NpcTalkReq.parseFrom(payload);
session.getPlayer().getQuestManager().triggerEvent(QuestTriggerType.QUEST_CONTENT_COMPLETE_TALK, req.getTalkId());
session.send(new PacketNpcTalkRsp(req.getNpcEntityId(), req.getTalkId(), req.getEntityId())); session.send(new PacketNpcTalkRsp(req.getNpcEntityId(), req.getTalkId(), req.getEntityId()));
} }
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment