From 901397a04e4acb31f03b36ac38da689e535cbebe Mon Sep 17 00:00:00 2001 From: flswld Date: Fri, 31 Mar 2023 16:03:29 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E4=B8=BB=E7=BA=BF=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1[=E5=BC=82=E5=B8=B8=E7=9A=84=E6=9D=83=E6=9F=84]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/constant/quest_type.go | 71 ++++++++++++ gdconf/quest_data.go | 209 ++++++++++++++++++++++++++++++++-- gs/game/game_tick_manager.go | 20 +++- gs/game/game_world_scene.go | 39 ++++++- gs/game/lua_func.go | 53 +++++++++ gs/game/lua_trigger.go | 55 +++++++-- gs/game/player_login.go | 2 +- gs/game/player_quest.go | 62 +++++++++- gs/game/player_scene.go | 68 +++++++++++ gs/model/db_quest.go | 4 +- 10 files changed, 551 insertions(+), 32 deletions(-) diff --git a/common/constant/quest_type.go b/common/constant/quest_type.go index 7445893c..31d78f87 100644 --- a/common/constant/quest_type.go +++ b/common/constant/quest_type.go @@ -176,3 +176,74 @@ const ( QUEST_FINISH_COND_TYPE_IRODORI_POETRY_REACH_MIN_PROGRESS = 152 QUEST_FINISH_COND_TYPE_IRODORI_POETRY_FINISH_FILL_POETRY = 153 ) + +const ( + QUEST_EXEC_TYPE_NONE = 0 + QUEST_EXEC_TYPE_DEL_PACK_ITEM = 1 + QUEST_EXEC_TYPE_UNLOCK_POINT = 2 + QUEST_EXEC_TYPE_UNLOCK_AREA = 3 + QUEST_EXEC_TYPE_UNLOCK_FORCE = 4 + QUEST_EXEC_TYPE_LOCK_FORCE = 5 + QUEST_EXEC_TYPE_CHANGE_AVATAR_ELEMET = 6 + QUEST_EXEC_TYPE_REFRESH_GROUP_MONSTER = 7 + QUEST_EXEC_TYPE_SET_IS_FLYABLE = 8 + QUEST_EXEC_TYPE_SET_IS_WEATHER_LOCKED = 9 + QUEST_EXEC_TYPE_SET_IS_GAME_TIME_LOCKED = 10 + QUEST_EXEC_TYPE_SET_IS_TRANSFERABLE = 11 + QUEST_EXEC_TYPE_GRANT_TRIAL_AVATAR = 12 + QUEST_EXEC_TYPE_OPEN_BORED = 13 + QUEST_EXEC_TYPE_ROLLBACK_QUEST = 14 + QUEST_EXEC_TYPE_NOTIFY_GROUP_LUA = 15 + QUEST_EXEC_TYPE_SET_OPEN_STATE = 16 + QUEST_EXEC_TYPE_LOCK_POINT = 17 + QUEST_EXEC_TYPE_DEL_PACK_ITEM_BATCH = 18 + QUEST_EXEC_TYPE_REFRESH_GROUP_SUITE = 19 + QUEST_EXEC_TYPE_REMOVE_TRIAL_AVATAR = 20 + QUEST_EXEC_TYPE_SET_GAME_TIME = 21 + QUEST_EXEC_TYPE_SET_WEATHER_GADGET = 22 + QUEST_EXEC_TYPE_ADD_QUEST_PROGRESS = 23 + QUEST_EXEC_TYPE_NOTIFY_DAILY_TASK = 24 + QUEST_EXEC_TYPE_CREATE_PATTERN_GROUP = 25 + QUEST_EXEC_TYPE_REMOVE_PATTERN_GROUP = 26 + QUEST_EXEC_TYPE_REFRESH_GROUP_SUITE_RANDOM = 27 + QUEST_EXEC_TYPE_ACTIVE_ITEM_GIVING = 28 + QUEST_EXEC_TYPE_DEL_ALL_SPECIFIC_PACK_ITEM = 29 + QUEST_EXEC_TYPE_ROLLBACK_PARENT_QUEST = 30 + QUEST_EXEC_TYPE_LOCK_AVATAR_TEAM = 31 + QUEST_EXEC_TYPE_UNLOCK_AVATAR_TEAM = 32 + QUEST_EXEC_TYPE_UPDATE_PARENT_QUEST_REWARD_INDEX = 33 + QUEST_EXEC_TYPE_SET_DAILY_TASK_VAR = 34 + QUEST_EXEC_TYPE_INC_DAILY_TASK_VAR = 35 + QUEST_EXEC_TYPE_DEC_DAILY_TASK_VAR = 36 + QUEST_EXEC_TYPE_ACTIVE_ACTIVITY_COND_STATE = 37 + QUEST_EXEC_TYPE_INACTIVE_ACTIVITY_COND_STATE = 38 + QUEST_EXEC_TYPE_ADD_CUR_AVATAR_ENERGY = 39 + QUEST_EXEC_TYPE_START_BARGAIN = 41 + QUEST_EXEC_TYPE_STOP_BARGAIN = 42 + QUEST_EXEC_TYPE_SET_QUEST_GLOBAL_VAR = 43 + QUEST_EXEC_TYPE_INC_QUEST_GLOBAL_VAR = 44 + QUEST_EXEC_TYPE_DEC_QUEST_GLOBAL_VAR = 45 + QUEST_EXEC_TYPE_REGISTER_DYNAMIC_GROUP = 46 + QUEST_EXEC_TYPE_UNREGISTER_DYNAMIC_GROUP = 47 + QUEST_EXEC_TYPE_SET_QUEST_VAR = 48 + QUEST_EXEC_TYPE_INC_QUEST_VAR = 49 + QUEST_EXEC_TYPE_DEC_QUEST_VAR = 50 + QUEST_EXEC_TYPE_RANDOM_QUEST_VAR = 51 + QUEST_EXEC_TYPE_ACTIVATE_SCANNING_PIC = 52 + QUEST_EXEC_TYPE_RELOAD_SCENE_TAG = 53 + QUEST_EXEC_TYPE_REGISTER_DYNAMIC_GROUP_ONLY = 54 + QUEST_EXEC_TYPE_CHANGE_SKILL_DEPOT = 55 + QUEST_EXEC_TYPE_ADD_SCENE_TAG = 56 + QUEST_EXEC_TYPE_DEL_SCENE_TAG = 57 + QUEST_EXEC_TYPE_INIT_TIME_VAR = 58 + QUEST_EXEC_TYPE_CLEAR_TIME_VAR = 59 + QUEST_EXEC_TYPE_MODIFY_CLIMATE_AREA = 60 + QUEST_EXEC_TYPE_GRANT_TRIAL_AVATAR_AND_LOCK_TEAM = 61 + QUEST_EXEC_TYPE_CHANGE_MAP_AREA_STATE = 62 + QUEST_EXEC_TYPE_DEACTIVE_ITEM_GIVING = 63 + QUEST_EXEC_TYPE_CHANGE_SCENE_LEVEL_TAG = 64 + QUEST_EXEC_TYPE_UNLOCK_PLAYER_WORLD_SCENE = 65 + QUEST_EXEC_TYPE_LOCK_PLAYER_WORLD_SCENE = 66 + QUEST_EXEC_TYPE_FAIL_MAINCOOP = 67 + QUEST_EXEC_TYPE_MODIFY_WEATHER_AREA = 68 +) diff --git a/gdconf/quest_data.go b/gdconf/quest_data.go index b4d77018..787f6946 100644 --- a/gdconf/quest_data.go +++ b/gdconf/quest_data.go @@ -11,6 +11,11 @@ type QuestCond struct { Count int32 } +type QuestExec struct { + Type int32 + Param []string +} + // QuestData 任务配置表 type QuestData struct { QuestId int32 `csv:"子任务ID"` @@ -51,23 +56,52 @@ type QuestData struct { FailCondCompose int32 `csv:"[失败条件]组合,omitempty"` FailCondType1 int32 `csv:"[失败条件]1类型,omitempty"` FailCondType1Param1 int32 `csv:"[失败条件]1参数1,omitempty"` - FailCondType1Param2 int32 `csv:"[失败条件]1参数2,omitempty"` FailCondType1ComplexParam string `csv:"[失败条件]1复杂参数,omitempty"` FailCondType1Count int32 `csv:"[失败条件]1次数,omitempty"` FailCondType2 int32 `csv:"[失败条件]2类型,omitempty"` FailCondType2Param1 int32 `csv:"[失败条件]2参数1,omitempty"` - FailCondType2Param2 int32 `csv:"[失败条件]2参数2,omitempty"` FailCondType2ComplexParam string `csv:"[失败条件]2复杂参数,omitempty"` FailCondType2Count int32 `csv:"[失败条件]2次数,omitempty"` - FailCondType3 int32 `csv:"[失败条件]3类型,omitempty"` - FailCondType3Param1 int32 `csv:"[失败条件]3参数1,omitempty"` - FailCondType3Param2 int32 `csv:"[失败条件]3参数2,omitempty"` - FailCondType3ComplexParam string `csv:"[失败条件]3复杂参数,omitempty"` - FailCondType3Count int32 `csv:"[失败条件]3次数,omitempty"` + // 执行 + ExecType1 int32 `csv:"[执行]1类型,omitempty"` + ExecType1Param1 string `csv:"[执行]1参数1,omitempty"` + ExecType1Param2 string `csv:"[执行]1参数2,omitempty"` + ExecType2 int32 `csv:"[执行]2类型,omitempty"` + ExecType2Param1 string `csv:"[执行]2参数1,omitempty"` + ExecType2Param2 string `csv:"[执行]2参数2,omitempty"` + ExecType3 int32 `csv:"[执行]3类型,omitempty"` + ExecType3Param1 string `csv:"[执行]3参数1,omitempty"` + ExecType3Param2 string `csv:"[执行]3参数2,omitempty"` + ExecType4 int32 `csv:"[执行]4类型,omitempty"` + ExecType4Param1 string `csv:"[执行]4参数1,omitempty"` + ExecType4Param2 string `csv:"[执行]4参数2,omitempty"` + // 失败执行 + FailExecType1 int32 `csv:"[失败执行]1类型,omitempty"` + FailExecType1Param1 string `csv:"[失败执行]1参数1,omitempty"` + FailExecType1Param2 string `csv:"[失败执行]1参数2,omitempty"` + FailExecType2 int32 `csv:"[失败执行]2类型,omitempty"` + FailExecType2Param1 string `csv:"[失败执行]2参数1,omitempty"` + FailExecType2Param2 string `csv:"[失败执行]2参数2,omitempty"` + FailExecType3 int32 `csv:"[失败执行]3类型,omitempty"` + FailExecType3Param1 string `csv:"[失败执行]3参数1,omitempty"` + FailExecType3Param2 string `csv:"[失败执行]3参数2,omitempty"` + // 开始执行 + StartExecType1 int32 `csv:"[开始执行]1类型,omitempty"` + StartExecType1Param1 string `csv:"[开始执行]1参数1,omitempty"` + StartExecType1Param2 string `csv:"[开始执行]1参数2,omitempty"` + StartExecType2 int32 `csv:"[开始执行]2类型,omitempty"` + StartExecType2Param1 string `csv:"[开始执行]2参数1,omitempty"` + StartExecType2Param2 string `csv:"[开始执行]2参数2,omitempty"` + StartExecType3 int32 `csv:"[开始执行]3类型,omitempty"` + StartExecType3Param1 string `csv:"[开始执行]3参数1,omitempty"` + StartExecType3Param2 string `csv:"[开始执行]3参数2,omitempty"` AcceptCondList []*QuestCond // 领取条件 FinishCondList []*QuestCond // 完成条件 FailCondList []*QuestCond // 失败条件 + ExecList []*QuestExec // 执行 + FailExecList []*QuestExec // 失败执行 + StartExecList []*QuestExec // 开始执行 } func (g *GameDataConfig) loadQuestData() { @@ -175,6 +209,167 @@ func (g *GameDataConfig) loadQuestData() { }) } // 失败条件 + questData.FailCondList = make([]*QuestCond, 0) + if questData.FailCondType1 != 0 { + paramList := make([]int32, 0) + if questData.FailCondType1Param1 != 0 { + paramList = append(paramList, questData.FailCondType1Param1) + } + questData.FailCondList = append(questData.FailCondList, &QuestCond{ + Type: questData.FailCondType1, + Param: paramList, + ComplexParam: questData.FailCondType1ComplexParam, + Count: questData.FailCondType1Count, + }) + } + if questData.FailCondType2 != 0 { + paramList := make([]int32, 0) + if questData.FailCondType2Param1 != 0 { + paramList = append(paramList, questData.FailCondType2Param1) + } + questData.FailCondList = append(questData.FailCondList, &QuestCond{ + Type: questData.FailCondType2, + Param: paramList, + ComplexParam: questData.FailCondType2ComplexParam, + Count: questData.FailCondType2Count, + }) + } + // 执行 + questData.ExecList = make([]*QuestExec, 0) + if questData.ExecType1 != 0 { + paramList := make([]string, 0) + if questData.ExecType1Param1 != "" { + paramList = append(paramList, questData.ExecType1Param1) + } + if questData.ExecType1Param2 != "" { + paramList = append(paramList, questData.ExecType1Param2) + } + questData.ExecList = append(questData.ExecList, &QuestExec{ + Type: questData.ExecType1, + Param: paramList, + }) + } + if questData.ExecType2 != 0 { + paramList := make([]string, 0) + if questData.ExecType2Param1 != "" { + paramList = append(paramList, questData.ExecType2Param1) + } + if questData.ExecType2Param2 != "" { + paramList = append(paramList, questData.ExecType2Param2) + } + questData.ExecList = append(questData.ExecList, &QuestExec{ + Type: questData.ExecType2, + Param: paramList, + }) + } + if questData.ExecType3 != 0 { + paramList := make([]string, 0) + if questData.ExecType3Param1 != "" { + paramList = append(paramList, questData.ExecType3Param1) + } + if questData.ExecType3Param2 != "" { + paramList = append(paramList, questData.ExecType3Param2) + } + questData.ExecList = append(questData.ExecList, &QuestExec{ + Type: questData.ExecType3, + Param: paramList, + }) + } + if questData.ExecType4 != 0 { + paramList := make([]string, 0) + if questData.ExecType4Param1 != "" { + paramList = append(paramList, questData.ExecType4Param1) + } + if questData.ExecType4Param2 != "" { + paramList = append(paramList, questData.ExecType4Param2) + } + questData.ExecList = append(questData.ExecList, &QuestExec{ + Type: questData.ExecType4, + Param: paramList, + }) + } + // 失败执行 + questData.FailExecList = make([]*QuestExec, 0) + if questData.FailExecType1 != 0 { + paramList := make([]string, 0) + if questData.FailExecType1Param1 != "" { + paramList = append(paramList, questData.FailExecType1Param1) + } + if questData.FailExecType1Param2 != "" { + paramList = append(paramList, questData.FailExecType1Param2) + } + questData.FailExecList = append(questData.FailExecList, &QuestExec{ + Type: questData.FailExecType1, + Param: paramList, + }) + } + if questData.FailExecType2 != 0 { + paramList := make([]string, 0) + if questData.FailExecType2Param1 != "" { + paramList = append(paramList, questData.FailExecType2Param1) + } + if questData.FailExecType2Param2 != "" { + paramList = append(paramList, questData.FailExecType2Param2) + } + questData.FailExecList = append(questData.FailExecList, &QuestExec{ + Type: questData.FailExecType2, + Param: paramList, + }) + } + if questData.FailExecType3 != 0 { + paramList := make([]string, 0) + if questData.FailExecType3Param1 != "" { + paramList = append(paramList, questData.FailExecType3Param1) + } + if questData.FailExecType3Param2 != "" { + paramList = append(paramList, questData.FailExecType3Param2) + } + questData.FailExecList = append(questData.FailExecList, &QuestExec{ + Type: questData.FailExecType3, + Param: paramList, + }) + } + // 开始执行 + questData.StartExecList = make([]*QuestExec, 0) + if questData.StartExecType1 != 0 { + paramList := make([]string, 0) + if questData.StartExecType1Param1 != "" { + paramList = append(paramList, questData.StartExecType1Param1) + } + if questData.StartExecType1Param2 != "" { + paramList = append(paramList, questData.StartExecType1Param2) + } + questData.StartExecList = append(questData.StartExecList, &QuestExec{ + Type: questData.StartExecType1, + Param: paramList, + }) + } + if questData.StartExecType2 != 0 { + paramList := make([]string, 0) + if questData.StartExecType2Param1 != "" { + paramList = append(paramList, questData.StartExecType2Param1) + } + if questData.StartExecType2Param2 != "" { + paramList = append(paramList, questData.StartExecType2Param2) + } + questData.StartExecList = append(questData.StartExecList, &QuestExec{ + Type: questData.StartExecType2, + Param: paramList, + }) + } + if questData.StartExecType3 != 0 { + paramList := make([]string, 0) + if questData.StartExecType3Param1 != "" { + paramList = append(paramList, questData.StartExecType3Param1) + } + if questData.StartExecType3Param2 != "" { + paramList = append(paramList, questData.StartExecType3Param2) + } + questData.StartExecList = append(questData.StartExecList, &QuestExec{ + Type: questData.StartExecType3, + Param: paramList, + }) + } g.QuestDataMap[questData.QuestId] = questData } } diff --git a/gs/game/game_tick_manager.go b/gs/game/game_tick_manager.go index b2bddcdb..da0312d0 100644 --- a/gs/game/game_tick_manager.go +++ b/gs/game/game_tick_manager.go @@ -21,6 +21,7 @@ const ( type UserTimer struct { timer *time.Timer action int + data []any } type UserTick struct { @@ -67,7 +68,7 @@ func (t *TickManager) DestroyUserGlobalTick(userId uint32) { } // CreateUserTimer 创建玩家定时任务 -func (t *TickManager) CreateUserTimer(userId uint32, action int, delay uint32) { +func (t *TickManager) CreateUserTimer(userId uint32, action int, delay uint32, data ...any) { userTick, exist := t.userTickMap[userId] if !exist { logger.Error("user not exist, uid: %v", userId) @@ -77,6 +78,7 @@ func (t *TickManager) CreateUserTimer(userId uint32, action int, delay uint32) { userTick.timerMap[userTick.timerIdCounter] = &UserTimer{ timer: time.NewTimer(time.Second * time.Duration(delay)), action: action, + data: data, } logger.Debug("create user timer, uid: %v, action: %v, time: %v", userId, action, time.Now().Add(time.Second*time.Duration(delay)).Format("2006-01-02 15:04:05")) @@ -103,12 +105,22 @@ func (t *TickManager) onUserTickMinute(userId uint32, now int64) { const ( UserTimerActionTest = iota + UserTimerActionLuaCreateMonster ) -func (t *TickManager) userTimerHandle(userId uint32, action int) { +func (t *TickManager) userTimerHandle(userId uint32, action int, data []any) { + player := USER_MANAGER.GetOnlineUser(userId) + if player == nil { + return + } switch action { case UserTimerActionTest: - logger.Debug("UserTimerActionTest, uid: %v", userId) + logger.Debug("UserTimerActionTest, data: %v, uid: %v", data[0], userId) + case UserTimerActionLuaCreateMonster: + logger.Debug("UserTimerActionLuaCreateMonster, groupId: %v, monsterConfigId: %v, uid: %v", data[0], data[1], userId) + groupId := data[0].(uint32) + monsterConfigId := data[1].(uint32) + GAME.AddSceneGroupMonster(player, groupId, monsterConfigId) } } @@ -168,7 +180,7 @@ func (t *TickManager) OnGameServerTick() { <-timer.timer.C timer.timer.Stop() delete(userTick.timerMap, timerId) - t.userTimerHandle(userId, timer.action) + t.userTimerHandle(userId, timer.action, timer.data) } } } diff --git a/gs/game/game_world_scene.go b/gs/game/game_world_scene.go index ed784c03..a9e29ed7 100644 --- a/gs/game/game_world_scene.go +++ b/gs/game/game_world_scene.go @@ -304,6 +304,33 @@ func (s *Scene) GetEntity(entityId uint32) *Entity { return s.entityMap[entityId] } +func (s *Scene) AddGroupSuiteMonster(groupId uint32, suiteId uint8, monsterConfigId uint32) uint32 { + group, exist := s.groupMap[groupId] + if !exist { + logger.Error("group not exist, groupId: %v", groupId) + return 0 + } + suite, exist := group.suiteMap[suiteId] + if !exist { + logger.Error("suite not exist, suiteId: %v", suiteId) + return 0 + } + groupConfig := gdconf.GetSceneGroup(int32(groupId)) + if groupConfig == nil { + logger.Error("get scene group config is nil, groupId: %v", groupId) + return 0 + } + monsterConfig, exist := groupConfig.MonsterMap[int32(monsterConfigId)] + if !exist { + logger.Error("monster config not exist, monsterConfigId: %v", monsterConfigId) + return 0 + } + entityId := s.createConfigEntity(uint32(groupConfig.Id), monsterConfig) + entity := s.GetEntity(entityId) + suite.entityMap[entityId] = entity + return entityId +} + func (s *Scene) AddGroupSuite(groupId uint32, suiteId uint8) { groupConfig := gdconf.GetSceneGroup(int32(groupId)) if groupConfig == nil { @@ -320,27 +347,27 @@ func (s *Scene) AddGroupSuite(groupId uint32, suiteId uint8) { entityMap: make(map[uint32]*Entity), } for _, monsterConfigId := range suiteConfig.MonsterConfigIdList { - monster, exist := groupConfig.MonsterMap[monsterConfigId] + monsterConfig, exist := groupConfig.MonsterMap[monsterConfigId] if !exist { logger.Error("monster config not exist, monsterConfigId: %v", monsterConfigId) continue } - entityId := s.createConfigEntity(uint32(groupConfig.Id), monster) + entityId := s.createConfigEntity(uint32(groupConfig.Id), monsterConfig) entity := s.GetEntity(entityId) suite.entityMap[entityId] = entity } for _, gadgetConfigId := range suiteConfig.GadgetConfigIdList { - gadget, exist := groupConfig.GadgetMap[gadgetConfigId] + gadgetConfig, exist := groupConfig.GadgetMap[gadgetConfigId] if !exist { logger.Error("gadget config not exist, gadgetConfigId: %v", gadgetConfigId) continue } - entityId := s.createConfigEntity(uint32(groupConfig.Id), gadget) + entityId := s.createConfigEntity(uint32(groupConfig.Id), gadgetConfig) entity := s.GetEntity(entityId) suite.entityMap[entityId] = entity } - for _, npc := range groupConfig.NpcMap { - entityId := s.createConfigEntity(uint32(groupConfig.Id), npc) + for _, npcConfig := range groupConfig.NpcMap { + entityId := s.createConfigEntity(uint32(groupConfig.Id), npcConfig) entity := s.GetEntity(entityId) suite.entityMap[entityId] = entity } diff --git a/gs/game/lua_func.go b/gs/game/lua_func.go index af3c8905..199b3ccd 100644 --- a/gs/game/lua_func.go +++ b/gs/game/lua_func.go @@ -112,6 +112,8 @@ func RegLuaScriptLibFunc() { gdconf.RegScriptLibFunc("ChangeGroupGadget", ChangeGroupGadget) gdconf.RegScriptLibFunc("SetGadgetStateByConfigId", SetGadgetStateByConfigId) gdconf.RegScriptLibFunc("MarkPlayerAction", MarkPlayerAction) + gdconf.RegScriptLibFunc("AddQuestProgress", AddQuestProgress) + gdconf.RegScriptLibFunc("CreateMonster", CreateMonster) } func GetEntityType(luaState *lua.LState) int { @@ -284,3 +286,54 @@ func MarkPlayerAction(luaState *lua.LState) int { luaState.Push(lua.LNumber(0)) return 1 } + +func AddQuestProgress(luaState *lua.LState) int { + ctx, ok := luaState.Get(1).(*lua.LTable) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + player := GetContextPlayer(ctx, luaState) + if player == nil { + luaState.Push(lua.LNumber(-1)) + return 1 + } + complexParam := luaState.ToString(2) + GAME.TriggerQuest(player, constant.QUEST_FINISH_COND_TYPE_LUA_NOTIFY, complexParam) + luaState.Push(lua.LNumber(0)) + return 1 +} + +type CreateMonsterInfo struct { + ConfigId int32 `json:"config_id"` + DelayTime int32 `json:"delay_time"` +} + +func CreateMonster(luaState *lua.LState) int { + ctx, ok := luaState.Get(1).(*lua.LTable) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + player := GetContextPlayer(ctx, luaState) + if player == nil { + luaState.Push(lua.LNumber(-1)) + return 1 + } + groupId, ok := luaState.GetField(ctx, "groupId").(lua.LNumber) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + createMonsterInfoTable, ok := luaState.Get(2).(*lua.LTable) + if !ok { + luaState.Push(lua.LNumber(-1)) + return 1 + } + createMonsterInfo := new(CreateMonsterInfo) + gdconf.ParseLuaTableToObject[*CreateMonsterInfo](createMonsterInfoTable, createMonsterInfo) + TICK_MANAGER.CreateUserTimer(player.PlayerID, UserTimerActionLuaCreateMonster, uint32(createMonsterInfo.DelayTime), + uint32(groupId), uint32(createMonsterInfo.ConfigId)) + luaState.Push(lua.LNumber(0)) + return 1 +} diff --git a/gs/game/lua_trigger.go b/gs/game/lua_trigger.go index 021496c9..d6d9d940 100644 --- a/gs/game/lua_trigger.go +++ b/gs/game/lua_trigger.go @@ -42,16 +42,8 @@ func (g *Game) SceneRegionTriggerCheck(player *model.Player, scene *Scene, oldPo shape.NewPolygon(&alg.Vector3{X: regionConfig.Pos.X, Y: regionConfig.Pos.Y, Z: regionConfig.Pos.Z}, vector2PointArray, regionConfig.Height) } - oldPosInRegion := shape.Contain(&alg.Vector3{ - X: float32(oldPos.X), - Y: float32(oldPos.Y), - Z: float32(oldPos.Z), - }) - newPosInRegion := shape.Contain(&alg.Vector3{ - X: float32(newPos.X), - Y: float32(newPos.Y), - Z: float32(newPos.Z), - }) + oldPosInRegion := shape.Contain(&alg.Vector3{X: float32(oldPos.X), Y: float32(oldPos.Y), Z: float32(oldPos.Z)}) + newPosInRegion := shape.Contain(&alg.Vector3{X: float32(newPos.X), Y: float32(newPos.Y), Z: float32(newPos.Z)}) if !oldPosInRegion && newPosInRegion { logger.Debug("player enter region: %v, uid: %v", regionConfig, player.PlayerID) for _, triggerName := range suiteConfig.TriggerNameList { @@ -150,3 +142,46 @@ func (g *Game) MonsterDieTriggerCheck(player *model.Player, groupId uint32, grou } } } + +// QuestStartTriggerCheck 任务开始触发器检测 +func (g *Game) QuestStartTriggerCheck(player *model.Player, questId uint32) { + world := WORLD_MANAGER.GetWorldByID(player.WorldId) + if world == nil { + return + } + scene := world.GetSceneById(player.SceneId) + for groupId, group := range scene.GetAllGroup() { + groupConfig := gdconf.GetSceneGroup(int32(groupId)) + if groupConfig == nil { + logger.Error("get group config is nil, groupId: %v, uid: %v", groupId, player.PlayerID) + continue + } + for suiteId := range group.GetAllSuite() { + suiteConfig := groupConfig.SuiteList[suiteId-1] + for _, triggerName := range suiteConfig.TriggerNameList { + triggerConfig := groupConfig.TriggerMap[triggerName] + if triggerConfig.Event != constant.LUA_EVENT_QUEST_START { + continue + } + if triggerConfig.Condition != "" { + cond := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Condition, + &LuaCtx{uid: player.PlayerID}, + &LuaEvt{param1: int32(questId)}) + if !cond { + continue + } + } + logger.Debug("scene group trigger fire, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) + if triggerConfig.Action != "" { + logger.Debug("scene group trigger do action, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) + ok := CallLuaFunc(groupConfig.GetLuaState(), triggerConfig.Action, + &LuaCtx{uid: player.PlayerID, groupId: groupId}, + &LuaEvt{}) + if !ok { + logger.Error("trigger action fail, trigger: %+v, uid: %v", triggerConfig, player.PlayerID) + } + } + } + } + } +} diff --git a/gs/game/player_login.go b/gs/game/player_login.go index 248f0674..c46f6885 100644 --- a/gs/game/player_login.go +++ b/gs/game/player_login.go @@ -114,7 +114,7 @@ func (g *Game) OnLoginOk(userId uint32, clientSeq uint32, gateAppId string, isRe }) TICK_MANAGER.CreateUserGlobalTick(userId) - TICK_MANAGER.CreateUserTimer(userId, UserTimerActionTest, 100) + TICK_MANAGER.CreateUserTimer(userId, UserTimerActionTest, 100, player.NickName) atomic.AddInt32(&ONLINE_PLAYER_NUM, 1) diff --git a/gs/game/player_quest.go b/gs/game/player_quest.go index 4203de5a..8eee4447 100644 --- a/gs/game/player_quest.go +++ b/gs/game/player_quest.go @@ -1,6 +1,9 @@ package game import ( + "strconv" + "strings" + "hk4e/common/constant" "hk4e/gdconf" "hk4e/gs/model" @@ -127,8 +130,6 @@ func (g *Game) AcceptQuest(player *model.Player, notifyClient bool) { } if canAccept { dbQuest.AddQuest(uint32(questData.QuestId)) - // TODO 判断任务是否能开始执行 - dbQuest.ExecQuest(uint32(questData.QuestId)) addQuestIdList = append(addQuestIdList, uint32(questData.QuestId)) } } @@ -144,9 +145,58 @@ func (g *Game) AcceptQuest(player *model.Player, notifyClient bool) { ntf.QuestList = append(ntf.QuestList, pbQuest) } g.SendMsg(cmd.QuestListUpdateNotify, player.PlayerID, player.ClientSeq, ntf) + // TODO 判断任务是否能开始 + for _, questId := range addQuestIdList { + g.StartQuest(player, questId) + } } } +// StartQuest 开始一个任务 +func (g *Game) StartQuest(player *model.Player, questId uint32) { + dbQuest := player.GetDbQuest() + dbQuest.StartQuest(questId) + ntf := &proto.QuestListUpdateNotify{ + QuestList: make([]*proto.Quest, 0), + } + pbQuest := g.PacketQuest(player, questId) + if pbQuest == nil { + return + } + ntf.QuestList = append(ntf.QuestList, pbQuest) + g.SendMsg(cmd.QuestListUpdateNotify, player.PlayerID, player.ClientSeq, ntf) + g.QuestExec(player, questId) + g.QuestStartTriggerCheck(player, questId) +} + +// QuestExec 任务开始执行触发操作 +func (g *Game) QuestExec(player *model.Player, questId uint32) { + questDataConfig := gdconf.GetQuestDataById(int32(questId)) + if questDataConfig == nil { + return + } + for _, questExec := range questDataConfig.StartExecList { + switch questExec.Type { + case constant.QUEST_EXEC_TYPE_NOTIFY_GROUP_LUA: + case constant.QUEST_EXEC_TYPE_REFRESH_GROUP_SUITE: + if len(questExec.Param) != 2 { + continue + } + split := strings.Split(questExec.Param[1], ",") + groupId, err := strconv.Atoi(split[0]) + if err != nil { + continue + } + suiteId, err := strconv.Atoi(split[0]) + if err != nil { + continue + } + g.AddSceneGroupSuite(player, uint32(groupId), uint8(suiteId)) + } + } +} + +// 通用参数匹配 func matchParamEqual(param1 []int32, param2 []int32, num int) bool { if len(param1) != num || len(param2) != num { return false @@ -204,6 +254,14 @@ func (g *Game) TriggerQuest(player *model.Player, cond int32, complexParam strin } dbQuest.ForceFinishQuest(quest.QuestId) updateQuestIdList = append(updateQuestIdList, quest.QuestId) + case constant.QUEST_FINISH_COND_TYPE_SKILL: + // 使用技能 参数1:技能id + ok := matchParamEqual(questCond.Param, param, 1) + if !ok { + continue + } + dbQuest.ForceFinishQuest(quest.QuestId) + updateQuestIdList = append(updateQuestIdList, quest.QuestId) } } } diff --git a/gs/game/player_scene.go b/gs/game/player_scene.go index 66d5b90f..4d650801 100644 --- a/gs/game/player_scene.go +++ b/gs/game/player_scene.go @@ -366,6 +366,7 @@ func (g *Game) SceneEntityDrownReq(player *model.Player, payloadMsg pb.Message) g.SendMsg(cmd.SceneEntityDrownRsp, player.PlayerID, player.ClientSeq, sceneEntityDrownRsp) } +// AddSceneEntityNotifyToPlayer 添加的场景实体同步给玩家 func (g *Game) AddSceneEntityNotifyToPlayer(player *model.Player, visionType proto.VisionType, entityList []*proto.SceneEntityInfo) { sceneEntityAppearNotify := &proto.SceneEntityAppearNotify{ AppearType: visionType, @@ -376,6 +377,7 @@ func (g *Game) AddSceneEntityNotifyToPlayer(player *model.Player, visionType pro player.PlayerID, sceneEntityAppearNotify.AppearType, len(sceneEntityAppearNotify.EntityList)) } +// AddSceneEntityNotifyBroadcast 添加的场景实体广播 func (g *Game) AddSceneEntityNotifyBroadcast(player *model.Player, scene *Scene, visionType proto.VisionType, entityList []*proto.SceneEntityInfo, aec bool) { sceneEntityAppearNotify := &proto.SceneEntityAppearNotify{ AppearType: visionType, @@ -391,6 +393,7 @@ func (g *Game) AddSceneEntityNotifyBroadcast(player *model.Player, scene *Scene, } } +// RemoveSceneEntityNotifyToPlayer 移除的场景实体同步给玩家 func (g *Game) RemoveSceneEntityNotifyToPlayer(player *model.Player, visionType proto.VisionType, entityIdList []uint32) { sceneEntityDisappearNotify := &proto.SceneEntityDisappearNotify{ EntityList: entityIdList, @@ -401,6 +404,7 @@ func (g *Game) RemoveSceneEntityNotifyToPlayer(player *model.Player, visionType player.PlayerID, sceneEntityDisappearNotify.DisappearType, len(sceneEntityDisappearNotify.EntityList)) } +// RemoveSceneEntityNotifyBroadcast 移除的场景实体广播 func (g *Game) RemoveSceneEntityNotifyBroadcast(scene *Scene, visionType proto.VisionType, entityIdList []uint32) { sceneEntityDisappearNotify := &proto.SceneEntityDisappearNotify{ EntityList: entityIdList, @@ -413,6 +417,7 @@ func (g *Game) RemoveSceneEntityNotifyBroadcast(scene *Scene, visionType proto.V } } +// AddSceneEntityNotify 添加的场景实体同步 封装接口 func (g *Game) AddSceneEntityNotify(player *model.Player, visionType proto.VisionType, entityIdList []uint32, broadcast bool, aec bool) { world := WORLD_MANAGER.GetWorldByID(player.WorldId) scene := world.GetSceneById(player.SceneId) @@ -471,6 +476,7 @@ func (g *Game) AddSceneEntityNotify(player *model.Player, visionType proto.Visio } } +// EntityFightPropUpdateNotifyBroadcast 场景实体战斗属性变更通知广播 func (g *Game) EntityFightPropUpdateNotifyBroadcast(world *World, entity *Entity) { ntf := &proto.EntityFightPropUpdateNotify{ FightPropMap: entity.GetFightProp(), @@ -479,6 +485,7 @@ func (g *Game) EntityFightPropUpdateNotifyBroadcast(world *World, entity *Entity g.SendToWorldA(world, cmd.EntityFightPropUpdateNotify, 0, ntf) } +// KillPlayerAvatar 杀死玩家活跃角色实体 func (g *Game) KillPlayerAvatar(player *model.Player, dieType proto.PlayerDieType) { world := WORLD_MANAGER.GetWorldByID(player.WorldId) if world == nil { @@ -510,6 +517,7 @@ func (g *Game) KillPlayerAvatar(player *model.Player, dieType proto.PlayerDieTyp g.SendToWorldA(world, cmd.AvatarLifeStateChangeNotify, 0, ntf) } +// RevivePlayerAvatar 复活玩家活跃角色实体 func (g *Game) RevivePlayerAvatar(player *model.Player) { world := WORLD_MANAGER.GetWorldByID(player.WorldId) if world == nil { @@ -543,6 +551,7 @@ func (g *Game) RevivePlayerAvatar(player *model.Player) { g.SendToWorldA(world, cmd.AvatarLifeStateChangeNotify, 0, ntf) } +// KillEntity 杀死实体 func (g *Game) KillEntity(player *model.Player, scene *Scene, entityId uint32, dieType proto.PlayerDieType) { entity := scene.GetEntity(entityId) if entity == nil { @@ -577,6 +586,7 @@ func (g *Game) KillEntity(player *model.Player, scene *Scene, entityId uint32, d } } +// ChangeGadgetState 改变物件实体状态 func (g *Game) ChangeGadgetState(player *model.Player, entityId uint32, state uint32) { world := WORLD_MANAGER.GetWorldByID(player.WorldId) if world == nil { @@ -603,6 +613,7 @@ func (g *Game) ChangeGadgetState(player *model.Player, entityId uint32, state ui g.SendMsg(cmd.GadgetStateNotify, player.PlayerID, player.ClientSeq, ntf) } +// GetVisionEntity 获取某位置视野内的全部实体 func (g *Game) GetVisionEntity(scene *Scene, pos *model.Vector) map[uint32]*Entity { visionEntity := make(map[uint32]*Entity) for _, entity := range scene.GetAllEntity() { @@ -615,6 +626,7 @@ func (g *Game) GetVisionEntity(scene *Scene, pos *model.Vector) map[uint32]*Enti return visionEntity } +// GetNeighborGroup 获取某位置附近的场景组 func (g *Game) GetNeighborGroup(sceneId uint32, pos *model.Vector) map[uint32]*gdconf.Group { aoiManager, exist := WORLD_MANAGER.GetSceneBlockAoiMap()[sceneId] if !exist { @@ -637,6 +649,7 @@ func (g *Game) GetNeighborGroup(sceneId uint32, pos *model.Vector) map[uint32]*g return neighborGroup } +// AddSceneGroup 加载场景组 func (g *Game) AddSceneGroup(player *model.Player, scene *Scene, groupConfig *gdconf.Group) { initSuiteId := int(groupConfig.GroupInitConfig.Suite) if initSuiteId < 1 || initSuiteId > len(groupConfig.SuiteList) { @@ -651,6 +664,7 @@ func (g *Game) AddSceneGroup(player *model.Player, scene *Scene, groupConfig *gd g.SendMsg(cmd.GroupSuiteNotify, player.PlayerID, player.ClientSeq, ntf) } +// RemoveSceneGroup 卸载场景组 func (g *Game) RemoveSceneGroup(player *model.Player, scene *Scene, groupConfig *gdconf.Group) { group := scene.GetGroupById(uint32(groupConfig.Id)) if group == nil { @@ -667,6 +681,58 @@ func (g *Game) RemoveSceneGroup(player *model.Player, scene *Scene, groupConfig g.SendMsg(cmd.GroupUnloadNotify, player.PlayerID, player.ClientSeq, ntf) } +func (g *Game) AddSceneGroupSuite(player *model.Player, groupId uint32, suiteId uint8) { + groupConfig := gdconf.GetSceneGroup(int32(groupId)) + if groupConfig == nil { + logger.Error("get group config is nil, groupId: %v, uid: %v", groupId, player.PlayerID) + return + } + if suiteId < 1 || suiteId > uint8(len(groupConfig.SuiteList)) { + logger.Error("invalid suite id: %v, uid: %v", suiteId, player.PlayerID) + return + } + world := WORLD_MANAGER.GetWorldByID(player.WorldId) + if world == nil { + return + } + scene := world.GetSceneById(player.SceneId) + scene.AddGroupSuite(uint32(groupConfig.Id), suiteId) + ntf := &proto.GroupSuiteNotify{ + GroupMap: make(map[uint32]uint32), + } + ntf.GroupMap[uint32(groupConfig.Id)] = uint32(suiteId) + g.SendMsg(cmd.GroupSuiteNotify, player.PlayerID, player.ClientSeq, ntf) + group := scene.GetGroupById(groupId) + suite := group.GetSuiteById(suiteId) + entityIdList := make([]uint32, 0) + for _, entity := range suite.GetAllEntity() { + entityIdList = append(entityIdList, entity.GetId()) + } + g.AddSceneEntityNotify(player, proto.VisionType_VISION_BORN, entityIdList, true, false) +} + +func (g *Game) AddSceneGroupMonster(player *model.Player, groupId uint32, monsterConfigId uint32) { + groupConfig := gdconf.GetSceneGroup(int32(groupId)) + if groupConfig == nil { + logger.Error("get group config is nil, groupId: %v, uid: %v", groupId, player.PlayerID) + return + } + initSuiteId := int(groupConfig.GroupInitConfig.Suite) + if initSuiteId < 1 || initSuiteId > len(groupConfig.SuiteList) { + logger.Error("invalid init suite id: %v, uid: %v", initSuiteId, player.PlayerID) + return + } + world := WORLD_MANAGER.GetWorldByID(player.WorldId) + if world == nil { + logger.Error("get world is nil, worldId: %v", player.WorldId) + return + } + scene := world.GetSceneById(player.SceneId) + entityId := scene.AddGroupSuiteMonster(groupId, uint8(initSuiteId), monsterConfigId) + g.AddSceneEntityNotify(player, proto.VisionType_VISION_BORN, []uint32{entityId}, true, false) +} + +// CreateDropGadget 创建掉落物的物件实体 func (g *Game) CreateDropGadget(player *model.Player, pos *model.Vector, gadgetId, itemId, count uint32) { world := WORLD_MANAGER.GetWorldByID(player.WorldId) if world == nil { @@ -690,6 +756,8 @@ func (g *Game) CreateDropGadget(player *model.Player, pos *model.Vector, gadgetI g.AddSceneEntityNotify(player, proto.VisionType_VISION_BORN, []uint32{entityId}, true, false) } +// 打包相关封装函数 + var SceneTransactionSeq uint32 = 0 func (g *Game) PacketPlayerEnterSceneNotifyLogin(player *model.Player, enterType proto.EnterType) *proto.PlayerEnterSceneNotify { diff --git a/gs/model/db_quest.go b/gs/model/db_quest.go index e0bbb8d5..3561b863 100644 --- a/gs/model/db_quest.go +++ b/gs/model/db_quest.go @@ -62,8 +62,8 @@ func (q *DbQuest) AddQuest(questId uint32) { } } -// ExecQuest 开始执行一个任务 -func (q *DbQuest) ExecQuest(questId uint32) { +// StartQuest 开始执行一个任务 +func (q *DbQuest) StartQuest(questId uint32) { quest, exist := q.QuestMap[questId] if !exist { logger.Error("get quest is nil, questId: %v", questId)