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
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()));
} }
......
Markdown is supported
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