diff --git a/Service/Application.Domain.Entity/game/user/unit_user_task.cs b/Service/Application.Domain.Entity/game/user/unit_user_task.cs index 651a21b..599819d 100644 --- a/Service/Application.Domain.Entity/game/user/unit_user_task.cs +++ b/Service/Application.Domain.Entity/game/user/unit_user_task.cs @@ -29,6 +29,9 @@ namespace Application.Domain.Entity /// [SugarColumn(IsNullable = true)] public int? itemId { get; set; } + + [SugarColumn(IsNullable = true)] + public int? lev { get; set; } /// /// name diff --git a/Service/Application.Domain/BusEvents/BusEventsEnum.cs b/Service/Application.Domain/BusEvents/BusEventsEnum.cs index 1f7fccf..126ee20 100644 --- a/Service/Application.Domain/BusEvents/BusEventsEnum.cs +++ b/Service/Application.Domain/BusEvents/BusEventsEnum.cs @@ -18,6 +18,8 @@ namespace Application.Domain HandleCreateMonster,//处理创建的怪物 HandleFightData,//处理战斗日志数据 HandleExchangeData,//处理兑换数据 + HandleTaskLog,//处理任务日志 + HandelTaskUser,//处理角色任务 } } diff --git a/Service/Application.Domain/BusEvents/BusEventsSubscriber.cs b/Service/Application.Domain/BusEvents/BusEventsSubscriber.cs index 44a064b..b99ef8d 100644 --- a/Service/Application.Domain/BusEvents/BusEventsSubscriber.cs +++ b/Service/Application.Domain/BusEvents/BusEventsSubscriber.cs @@ -85,5 +85,25 @@ var exchangeService = App.GetService(); await exchangeService.HandleExchangeLogData(); } + /// + /// 处理任务日志 + /// + /// + [EventSubscribe(BusEventsEnum.BusEventsName.HandleTaskLog, NumRetries = 0,RetryTimeout = 999999999)] + public async Task HandleTaskLog(EventHandlerExecutingContext context) + { + var taskService = App.GetService(); + await taskService.HandleUserTaskLog(); + } + /// + /// 处理角色任务 + /// + /// + [EventSubscribe(BusEventsEnum.BusEventsName.HandelTaskUser, NumRetries = 0,RetryTimeout = 999999999)] + public async Task HandelTaskUser(EventHandlerExecutingContext context) + { + var taskService = App.GetService(); + await taskService.HandleUserTask(); + } } } \ No newline at end of file diff --git a/Service/Application.Domain/Enum/GameEnum.cs b/Service/Application.Domain/Enum/GameEnum.cs index be6179e..054172b 100644 --- a/Service/Application.Domain/Enum/GameEnum.cs +++ b/Service/Application.Domain/Enum/GameEnum.cs @@ -15,6 +15,8 @@ public static class GameEnum UpdateCreateMonster,//更新创建得怪物 UpdateFightData,//更新战斗信息 UpdateExchangeData,//更新兑换的记录 + UpdateTaskLog,//更新任务日志 + UpdateTaskUser,//更新角色任务 } public enum PropCode//游戏资源编码 { diff --git a/Service/Application.Domain/Enum/MonsterEnum.cs b/Service/Application.Domain/Enum/MonsterEnum.cs index cd501cf..abec428 100644 --- a/Service/Application.Domain/Enum/MonsterEnum.cs +++ b/Service/Application.Domain/Enum/MonsterEnum.cs @@ -7,5 +7,10 @@ public static class MonsterEnum Default, } - + public enum MonsterCode + { + Default, + Dup, + Task + } } \ No newline at end of file diff --git a/Service/Application.Domain/Services/Interface/Monster/IGameMonsterService.cs b/Service/Application.Domain/Services/Interface/Monster/IGameMonsterService.cs index 3b8db25..dcdd08b 100644 --- a/Service/Application.Domain/Services/Interface/Monster/IGameMonsterService.cs +++ b/Service/Application.Domain/Services/Interface/Monster/IGameMonsterService.cs @@ -16,6 +16,8 @@ public interface IGameMonsterService Task GetCreateMonsterInfo(string umId); Task RemoveCreateMonster(string umId); Task RemoveCreateMonster(unit_user_monster data); + Task ClearCreateMonster(string userId,string code, string par, string monsterId, string mapId); + Task GetUserMonsterCount(string userId, string monsterId, int state); Task HandleCreateMonster(); Task> GetMapMonster(string userId, string mapId, string teamId); diff --git a/Service/Application.Domain/Services/Interface/Task/IGameTaskService.cs b/Service/Application.Domain/Services/Interface/Task/IGameTaskService.cs index 2749dcc..8ad806f 100644 --- a/Service/Application.Domain/Services/Interface/Task/IGameTaskService.cs +++ b/Service/Application.Domain/Services/Interface/Task/IGameTaskService.cs @@ -12,10 +12,14 @@ public interface IGameTaskService #region 个人任务 + Task> GetUserTaskData(string userId); Task GetUserTaskInfo(string userId, int taskId); Task UpdateUserTaskInfo(string userId, int itemId); Task GetUserTaskCount(string userId, int taskId); + Task ResetNextTask(string userId, int nextId); Task GetUserTaskModel(string userId, game_task_item task); + Task HandleUserTaskLog(); + Task HandleUserTask(); #endregion } \ No newline at end of file diff --git a/Service/Application.Domain/Services/Service/Business/GameAutoJobService.cs b/Service/Application.Domain/Services/Service/Business/GameAutoJobService.cs index 4a75a42..3cfde59 100644 --- a/Service/Application.Domain/Services/Service/Business/GameAutoJobService.cs +++ b/Service/Application.Domain/Services/Service/Business/GameAutoJobService.cs @@ -91,5 +91,17 @@ public class GameAutoJobService(ISqlSugarClient DbClient, IRedisCache redis, ITi await _eventPublisher.PublishAsync(new ChannelEventSource(BusEventsEnum.BusEventsName.HandleExchangeData, data)); } + else if (data.code == nameof(GameEnum.JobCode.UpdateTaskLog)) //更新任务日志 + { + var _eventPublisher = App.GetService(); + await _eventPublisher.PublishAsync(new ChannelEventSource(BusEventsEnum.BusEventsName.HandleTaskLog, + data)); + } + else if (data.code == nameof(GameEnum.JobCode.UpdateTaskUser)) //更新角色任务 + { + var _eventPublisher = App.GetService(); + await _eventPublisher.PublishAsync(new ChannelEventSource(BusEventsEnum.BusEventsName.HandelTaskUser, + data)); + } } } \ No newline at end of file diff --git a/Service/Application.Domain/Services/Service/Monster/GameMonsterService.cs b/Service/Application.Domain/Services/Service/Monster/GameMonsterService.cs index fc7c8f3..aba2a27 100644 --- a/Service/Application.Domain/Services/Service/Monster/GameMonsterService.cs +++ b/Service/Application.Domain/Services/Service/Monster/GameMonsterService.cs @@ -152,6 +152,26 @@ public class GameMonsterService(ISqlSugarClient DbClient, IRedisCache redis) : I return result; } + public async Task ClearCreateMonster(string userId, string code, string par, string monsterId, string mapId) + { + var db = DbClient.AsTenant().GetConnectionWithAttr(); + bool result = await db.Deleteable() + .Where(it => it.userId == userId && it.code == code && it.par == par && it.monsterId == monsterId) + .ExecuteCommandAsync() > 0; + if (result) + { + await ClearCreateMonster(mapId); + } + } + + public async Task GetUserMonsterCount(string userId, string monsterId, int state) + { + var db = DbClient.AsTenant().GetConnectionWithAttr(); + return await db.Queryable() + .Where(it => it.userId == userId && it.monsterId == monsterId && it.state == state).CountAsync(); + } + + public async Task HandleCreateMonster() { var endTime = TimeExtend.GetTimeStampSeconds; diff --git a/Service/Application.Domain/Services/Service/Task/GameTaskService.cs b/Service/Application.Domain/Services/Service/Task/GameTaskService.cs index 08c3d94..c1924a1 100644 --- a/Service/Application.Domain/Services/Service/Task/GameTaskService.cs +++ b/Service/Application.Domain/Services/Service/Task/GameTaskService.cs @@ -64,6 +64,20 @@ public class GameTaskService(ISqlSugarClient DbClient, IRedisCache redis) : IGam #region 个人任务 + public async Task> GetUserTaskData(string userId) + { + string key = string.Format(UserCache.BaseCacheKeys, "TaskCache", "UserTaskData"); + if (await redis.HExistsHashAsync(key, userId)) + { + return await redis.GetHashAsync>(key, userId); + } + + var db = DbClient.AsTenant().GetConnectionWithAttr(); + var data = await db.Queryable().Where(it => it.userId == userId).ToListAsync(); + await redis.AddHashAsync(key, userId, data); + return data; + } + public async Task GetUserTaskInfo(string userId, int taskId) { string utId = $"{userId}_{taskId}"; @@ -80,6 +94,17 @@ public class GameTaskService(ISqlSugarClient DbClient, IRedisCache redis) : IGam return data; } + private async Task ClearUserTaskCache(string userId, string utId = "") + { + string key = string.Format(UserCache.BaseCacheKeys, "TaskCache", "UserTaskData"); + await redis.DelHashAsync(key, userId); + if (!string.IsNullOrEmpty(utId)) + { + key = string.Format(UserCache.BaseCacheKeys, "TaskCache", "UserTaskInfo"); + await redis.DelHashAsync(key, utId); + } + } + public async Task UpdateUserTaskInfo(string userId, int itemId) { bool result = false; @@ -93,8 +118,7 @@ public class GameTaskService(ISqlSugarClient DbClient, IRedisCache redis) : IGam result = await db.Deleteable().Where(it => it.utId == utId).ExecuteCommandAsync() > 0; if (result) { - string key = string.Format(UserCache.BaseCacheKeys, "TaskCache", "UserTaskInfo"); - await redis.DelHashAsync(key, utId); + await ClearUserTaskCache(userId, utId); } } else @@ -107,6 +131,7 @@ public class GameTaskService(ISqlSugarClient DbClient, IRedisCache redis) : IGam onTask.userId = userId; onTask.taskId = taskInfo.taskId; onTask.itemId = taskInfo.tiId; + onTask.lev = taskInfo.lev; onTask.name = taskInfo.name; onTask.code = taskInfo.code; onTask.endTime = await GetItemEndTime((int)taskInfo.taskId, (int)taskInfo.time); @@ -117,6 +142,7 @@ public class GameTaskService(ISqlSugarClient DbClient, IRedisCache redis) : IGam { onTask.itemId = taskInfo.tiId; onTask.name = taskInfo.name; + onTask.lev = taskInfo.lev; onTask.code = taskInfo.code; onTask.endTime = await GetItemEndTime((int)taskInfo.taskId, (int)taskInfo.time); var db = DbClient.AsTenant().GetConnectionWithAttr(); @@ -127,17 +153,36 @@ public class GameTaskService(ISqlSugarClient DbClient, IRedisCache redis) : IGam { string key = string.Format(UserCache.BaseCacheKeys, "TaskCache", "UserTaskInfo"); await redis.AddHashAsync(key, utId, onTask); + await ClearUserTaskCache(userId); } } } if (result) { + //清理遗留数据,如怪物 + if (taskInfo.needData.Count > 0) + { + var monsterService = App.GetService(); + foreach (var item in taskInfo.needData) + { + if (item.code == nameof(GameEnum.PropCode.Monster)) + { + if (!string.IsNullOrEmpty(item.mapId)) + { + await monsterService.ClearCreateMonster(userId, nameof(MonsterEnum.MonsterCode.Task), + taskInfo.tiId.ToString(), item.parameter, item.mapId); + } + } + } + } + if (taskInfo.itemType == 0) { await AddUserTaskLog(userId, (int)taskInfo.taskId); } - else if (taskInfo.itemType == 1) + + if (taskInfo.itemType != 2) { //初始化下一环任务 await ResetNextTask(userId, taskInfo.tiId + 1); @@ -169,7 +214,7 @@ public class GameTaskService(ISqlSugarClient DbClient, IRedisCache redis) : IGam long endTime = await GetEndTime(taskId); unit_user_task_log log = new unit_user_task_log() { - utId = utId, + utId = StringAssist.NewGuid, userId = userId, taskId = taskId, addTime = DateTime.Now, @@ -184,9 +229,35 @@ public class GameTaskService(ISqlSugarClient DbClient, IRedisCache redis) : IGam } } - private async Task ResetNextTask(string userId, int nextId) + public async Task ResetNextTask(string userId, int nextId) { - await Task.CompletedTask; + var taskInfo = await GetTaskItemInfo(nextId); + if (taskInfo != null) + { + if (taskInfo.needData.Count > 0) + { + var monsterService = App.GetService(); + var monster = taskInfo.needData.FindAll(it => it.code == nameof(GameEnum.PropCode.Monster)); + if (monster.Count > 0) + { + foreach (var item in monster) + { + if (!string.IsNullOrEmpty(item.mapId) && !string.IsNullOrEmpty(item.parameter)) + { + int opCount = 0; + int count = await monsterService.GetUserMonsterCount(userId, item.parameter, 0); + if (count < item.count) + { + opCount = (int)item.count - count; + await monsterService.CreateMonsterToMap(userId, item.mapId, item.areaCode, + item.parameter, + opCount, (int)taskInfo.time, nextId.ToString()); + } + } + } + } + } + } } public async Task GetUserTaskModel(string userId, game_task_item task) @@ -268,6 +339,68 @@ public class GameTaskService(ISqlSugarClient DbClient, IRedisCache redis) : IGam return model; } + + public async Task HandleUserTaskLog() + { + //处理任务日志 + var db = DbClient.AsTenant().GetConnectionWithAttr(); + List uts = new List(); + long endTime = TimeExtend.GetTimeStampSeconds; + var data = await db.Queryable().Where(it => it.endTime < endTime).ToListAsync(); + foreach (var item in data) + { + string utId = $"{item.userId}_{item.taskId}"; + if (uts.Any(it => it == utId)) + { + continue; + } + + uts.Add(utId); + } + + if (uts.Count > 0) + { + bool result = + await db.Deleteable().Where(it => it.endTime < endTime).ExecuteCommandAsync() > 0; + if (result) + { + string key = string.Format(UserCache.BaseCacheKeys, "TaskCache", "UserTaskCount"); + await redis.DelHashAsync(key, uts.ToArray()); + } + } + } + + public async Task HandleUserTask() + { + var db = DbClient.AsTenant().GetConnectionWithAttr(); + List users = new List(); + List uts = new List(); + long endTime = TimeExtend.GetTimeStampSeconds; + var data = await db.Queryable().Where(it => it.endTime < endTime).ToListAsync(); + foreach (var item in data) + { + if (users.Any(it => it == item.userId) == false) + { + users.Add(item.userId); + } + + uts.Add($"{item.userId}_{item.taskId}"); + } + + if (users.Count > 0) + { + bool result = + await db.Deleteable().Where(it => it.endTime < endTime).ExecuteCommandAsync() > 0; + if (result) + { + string key = string.Format(UserCache.BaseCacheKeys, "TaskCache", "UserTaskData"); + await redis.DelHashAsync(key, users.ToArray()); + key = string.Format(UserCache.BaseCacheKeys, "TaskCache", "UserTaskInfo"); + await redis.DelHashAsync(key, uts.ToArray()); + } + } + } + #endregion #region 辅助 diff --git a/Service/Application.Domain/Tool/Base/GameBus.cs b/Service/Application.Domain/Tool/Base/GameBus.cs index c6f0e21..bfc5746 100644 --- a/Service/Application.Domain/Tool/Base/GameBus.cs +++ b/Service/Application.Domain/Tool/Base/GameBus.cs @@ -220,6 +220,18 @@ public static class GameBus isok = false; } } + else if (item.code == nameof(GameEnum.PropCode.Monster)) + { + var monsterService = App.GetService(); + var onCount = await monsterService.GetUserMonsterCount(userId,item.parameter,1); + item.count = item.count; + item.onCount = onCount; + if (onCount < item.count) + { + item.isAsk = 0; + isok = false; + } + } result.result = isok; result.isDeal = isDeal; diff --git a/Service/Application.Web/Controllers/Login/LoginController.cs b/Service/Application.Web/Controllers/Login/LoginController.cs index 6b62704..69cf40a 100644 --- a/Service/Application.Web/Controllers/Login/LoginController.cs +++ b/Service/Application.Web/Controllers/Login/LoginController.cs @@ -28,17 +28,37 @@ namespace Application.Web.Controllers.Login _attrService = attrService; } + [HttpGet] + public string GetExp() + { + string html = string.Empty; + decimal sum = 0M; + decimal addsum = 0; + for (int i = 1; i < 121; i++) + { + Decimal exp = GameTool.GetUserUpExp(i); + if (i > 160 && i < 221) + { + addsum += exp; + } + sum += exp; + html += string.Format("当前等级:{0},升级经验:{1};总经验:{2}\n\r", i, exp, sum); + } + html += String.Format("总经验:{0}", sum); + html += String.Format("升级经验:{0}", addsum); + return html; + } /// /// 登录接口 /// /// /// - [HttpPost] - public async Task Login([FromBody] LoginParms parms) - { - return PoAction.Ok(parms.code); - } + // [HttpPost] + // public async Task Login([FromBody] LoginParms parms) + // { + // return PoAction.Ok(parms.code); + // } /// /// 探玩自动登录 diff --git a/Service/Application.Web/Controllers/Map/MapController.cs b/Service/Application.Web/Controllers/Map/MapController.cs index c310e03..87bae68 100644 --- a/Service/Application.Web/Controllers/Map/MapController.cs +++ b/Service/Application.Web/Controllers/Map/MapController.cs @@ -152,7 +152,7 @@ public class MapController : ControllerBase string fightId = userFight.Count > 0 ? userFight[0] : ""; var mapGoods = await _fightService.GetMapFightGoods(mapInfo.mapId); mapGoods = mapGoods.FindAll(it => it.userId == "0" || it.userId == userId).Take(3).ToList(); - + var taskData = await _taskService.GetUserTaskData(userId); int isHook = 0; //挂机处理 var onHook = await _hookService.GetUserOnHook(userId); isHook = (int)onHook.status; @@ -173,7 +173,8 @@ public class MapController : ControllerBase monster = monsterData, fightId, gameTips, - isHook + isHook, + taskCount = taskData.Count }; diff --git a/Service/Application.Web/Controllers/Map/TaskController.cs b/Service/Application.Web/Controllers/Map/TaskController.cs index c851694..354e455 100644 --- a/Service/Application.Web/Controllers/Map/TaskController.cs +++ b/Service/Application.Web/Controllers/Map/TaskController.cs @@ -103,6 +103,94 @@ public class TaskController : ControllerBase { npc = npcInfo, data = data, talkMsg, taskState, btnTips = taskInfo.btnTips, toGoods, retGoods }); } + /// + /// 获取个人任务 + /// + /// + [HttpGet] + public async Task GetUserTask() + { + string userId = StateHelper.userId; + var data = await _taskService.GetUserTaskData(userId); + return PoAction.Ok(data); + } + + /// + /// 重置任务 + /// + /// + /// + [HttpGet] + public async Task RestTask(int task) + { + string userId = StateHelper.userId; + var onTaskInfo = await _taskService.GetUserTaskInfo(userId,task); + if (onTaskInfo == null) + { + return PoAction.Message("暂无任务!"); + } + + int nextId = (int)onTaskInfo.itemId + 1; + var nextTask = await _taskService.GetTaskItemInfo(nextId); + if (nextTask == null) + { + return PoAction.Message("当前任务已结束,无需重置!"); + } + + var result = await _taskService.GetUserTaskModel(userId, nextTask); + if (result.result.result) + { + return PoAction.Message("任务可完成,无需重置!"); + } + + await _taskService.ResetNextTask(userId, nextId); + return PoAction.Ok(true); + } + + /// + /// 获取个人任务详情 + /// + /// + /// + [HttpGet] + public async Task GetUserTaskInfo(int taskId) + { + string userId = StateHelper.userId; + + var taskInfo = await _taskService.GetTaskItemInfo(taskId); + if (taskInfo == null) + { + return PoAction.Message("任务不存在!"); + } + + string talkMsg = taskInfo.taskTips; + int taskState = 1; + var userOnTask = await _taskService.GetUserTaskInfo(userId, (int)taskInfo.taskId); + if (userOnTask != null) + { + if (userOnTask.itemId == taskId) + { + var nextInfo = await _taskService.GetTaskItemInfo(taskId + 1); + if (taskInfo == null) + { + taskState = 100; + } + else + { + talkMsg = taskInfo.nextTips; + taskInfo = nextInfo; + } + } + } + + var data = await _taskService.GetUserTaskModel(userId, taskInfo); + + int toGoods = await _goodsService.GetUserGoodsCount(userId, GameConfig.GameGetTaskGoods); + int retGoods = await _goodsService.GetUserGoodsCount(userId, GameConfig.GameRetTaskGoods); + return PoAction.Ok(new + { data = data, talkMsg, taskState, toGoods, retGoods }); + } + /// /// 完成任务 /// @@ -175,6 +263,7 @@ public class TaskController : ControllerBase } message = message.TrimEnd(','); + await GameBus.UpdateBag(userId, 1, award, "完成任务");//发放奖励 } return PoAction.Ok(true, message); diff --git a/Service/Application.Web/Controllers/Pub/FightController.cs b/Service/Application.Web/Controllers/Pub/FightController.cs index 19f1f7f..febf5b9 100644 --- a/Service/Application.Web/Controllers/Pub/FightController.cs +++ b/Service/Application.Web/Controllers/Pub/FightController.cs @@ -20,11 +20,12 @@ public class FightController : ControllerBase private readonly IUnitUserService _userService; private readonly IOnHookService _hookService; private readonly IUnitUserRelationService _relationService; + private readonly IGameTaskService _taskService; public FightController(IGameFightService fightService, IGameMonsterService monsterService, IUnitUserAttrService attrService, IGameMapService mapService, IUnitUserAccService accService, IGameGoodsService goodsService, IUnitUserService userService, IOnHookService hookService, - IUnitUserRelationService relationService) + IUnitUserRelationService relationService, IGameTaskService taskService) { _fightService = fightService; _monsterService = monsterService; @@ -35,6 +36,7 @@ public class FightController : ControllerBase _userService = userService; _hookService = hookService; _relationService = relationService; + _taskService = taskService; } /// @@ -162,16 +164,18 @@ public class FightController : ControllerBase return PoAction.Message("该地图不允许跨服战斗!"); } } + string fightId = StringAssist.NewGuid; string areaCode = nameof(GameEnum.AreaCode.Own); string code = nameof(GameEnum.FightCode.PVP); - string keyId = StringAssist.GetSortKey(userId,otUser.userId); + string keyId = StringAssist.GetSortKey(userId, otUser.userId); long exp = 0; long copper = 0; long petExp = 0; string award = string.Empty; string pars = ""; - bool result = await _fightService.AddFight(fightId, areaCode, keyId, otUser.userId, code, onMapInfo.code, onMapInfo.mapId, userId, exp, + bool result = await _fightService.AddFight(fightId, areaCode, keyId, otUser.userId, code, onMapInfo.code, + onMapInfo.mapId, userId, exp, copper, petExp, award, pars); if (result) { @@ -229,17 +233,6 @@ public class FightController : ControllerBase #endregion //更新攻击 - if (fightResult.result == 0) - { - myHarm = fightResult.myHarm; - myHarm += await _fightService.GetUserFightHarm(userId); - otHarm = fightResult.otHarm; - await _attrService.UpdateUserBlood(userId, 1, fightResult.myHarm); - await _attrService.AddUserLoadState(userId, fightResult.myStateData); - await _fightService.HandelFightEnd(userId, fightResult.myRemData); - } - - var myAttr = await _attrService.GetUserAttrModel(userId, fight.scene); UserAttrModel otAttr = new UserAttrModel(); if (fight.code == nameof(GameEnum.FightCode.PVE)) { @@ -264,6 +257,20 @@ public class FightController : ControllerBase otAttr = await _attrService.GetUserAttrModel(fight.mainId, fight.scene); } + if (fightResult.result == 0) + { + if (otAttr.blood >0) + { + myHarm = fightResult.myHarm; + myHarm += await _fightService.GetUserFightHarm(userId); + otHarm = fightResult.otHarm; + await _attrService.UpdateUserBlood(userId, 1, fightResult.myHarm); + await _attrService.AddUserLoadState(userId, fightResult.myStateData); + await _fightService.HandelFightEnd(userId, fightResult.myRemData); + } + } + + var myAttr = await _attrService.GetUserAttrModel(userId, fight.scene); //结束战斗都此处直接返回 if (otAttr.blood < 1 || myAttr.blood < 1) @@ -545,10 +552,26 @@ public class FightController : ControllerBase } } + string figArea = nameof(MonsterEnum.MonsterCode.Default); var myAttr = await _attrService.GetUserAttrModel(userId, fight.scene); + var parsData = JsonConvert.DeserializeObject(fight.pars); + object figResult = new object(); + if (Convert.ToString(parsData.type) == "Create") + { + if (Convert.ToString(parsData.code) == nameof(MonsterEnum.MonsterCode.Task)) + { + int itemId = Convert.ToInt32(parsData.par); + var taskInfo = await _taskService.GetTaskItemInfo(itemId); + if (taskInfo != null) + { + figArea = nameof(MonsterEnum.MonsterCode.Task); + figResult = await _taskService.GetUserTaskModel(userId, taskInfo); + } + } + } - - return PoAction.Ok(new { isWin, otName, blood = myAttr.blood, upBlood = myAttr.upBlood, fight, isCopy }); + return PoAction.Ok(new + { isWin, otName, blood = myAttr.blood, upBlood = myAttr.upBlood, fight, isCopy, figArea, figResult }); } #region 挂机相关 diff --git a/Web/src/pages/fight/result.vue b/Web/src/pages/fight/result.vue index 59d036f..86eb63e 100644 --- a/Web/src/pages/fight/result.vue +++ b/Web/src/pages/fight/result.vue @@ -27,6 +27,15 @@
+
+
+ 任务要求:
+ +
+
+ ➢我要传送 +
+
\ No newline at end of file +const retTask = async (btnData: any) => { + MessageExtend.LoadingToast("传送中..."); + let result = await TaskService.ReturnTask(Number(figAreaData.value.itemId)); + MessageExtend.LoadingClose(); + if (result.code == 0) { + PageExtend.RedirectTo("/map"); + } + else { + MessageExtend.Notify(result.msg, "danger"); + } +} + diff --git a/Web/src/pages/map/index.vue b/Web/src/pages/map/index.vue index ba94e1a..54ffce6 100644 --- a/Web/src/pages/map/index.vue +++ b/Web/src/pages/map/index.vue @@ -9,7 +9,7 @@
{{ cityInfo.cityName }}·{{ mapInfo.mapName }}({{ mapInfo.x }},{{ mapInfo.y }}) 刷新 - 任务 + 任务{{ taskCount > 0 ? "(" + taskCount + ")" : "" }} 消息{{ messageCount > 0 ? "(" + messageCount + ")" : "" }}
@@ -146,6 +146,7 @@ const broadcast = ref>([]); const gameTips = ref(''); const isHook = ref(0); const mapGoods = ref>([]); +const taskCount = ref(0); // 城内地图显示 const showCity = ref(false); @@ -181,6 +182,7 @@ const BindData = async (map: string): Promise => { gameTips.value = result.data.gameTips; mapGoods.value = result.data.mapGoods; isHook.value = result.data.isHook; + taskCount.value = result.data.taskCount; // console.log(result) } else if (result.code == 103) { diff --git a/Web/src/pages/map/npc/index.vue b/Web/src/pages/map/npc/index.vue index aa0c0f4..063bfe2 100644 --- a/Web/src/pages/map/npc/index.vue +++ b/Web/src/pages/map/npc/index.vue @@ -16,11 +16,16 @@
当前任务:
- - + + [{{ item.code }}]{{ item.name }}
+
+
+ ◈{{ item.name }} +
+
\ No newline at end of file diff --git a/Web/src/pages/task/info.vue b/Web/src/pages/task/info.vue index 1af2992..dd94ebe 100644 --- a/Web/src/pages/task/info.vue +++ b/Web/src/pages/task/info.vue @@ -3,7 +3,7 @@ {{ npcData.npcName }}:{{ talkMsg }}
- 等待开放下一环任务! + 恭喜,任务已全部完成!
diff --git a/Web/src/pages/task/look.vue b/Web/src/pages/task/look.vue new file mode 100644 index 0000000..bc00d3d --- /dev/null +++ b/Web/src/pages/task/look.vue @@ -0,0 +1,118 @@ + + \ No newline at end of file diff --git a/Web/src/services/map/TaskService.ts b/Web/src/services/map/TaskService.ts index 38c82ac..7d34b1c 100644 --- a/Web/src/services/map/TaskService.ts +++ b/Web/src/services/map/TaskService.ts @@ -7,6 +7,30 @@ export class TaskService { return await ApiService.Request("get", "/Map/Task/GetTaskByNpc", { npcId, taskId }); } + /** + * 获取个人任务 + * GET /Map/Task/GetUserTask + */ + static async GetUserTask() { + return await ApiService.Request("get", "/Map/Task/GetUserTask"); + } + + /** + * 重置任务 + * GET /Map/Task/RestTask + */ + static async RestTask(task: number) { + return await ApiService.Request("get", "/Map/Task/RestTask", { task }); + } + + /** + * 获取个人任务详情 + * GET /Map/Task/GetUserTaskInfo + */ + static async GetUserTaskInfo(taskId: number) { + return await ApiService.Request("get", "/Map/Task/GetUserTaskInfo", { taskId }); + } + /** * 完成任务 * GET /Map/Task/OverTask diff --git a/任务生成/create.zip b/任务生成/create.zip new file mode 100644 index 0000000..b715032 Binary files /dev/null and b/任务生成/create.zip differ diff --git a/任务生成/create/goods.xls b/任务生成/create/goods.xls new file mode 100644 index 0000000..42befb5 Binary files /dev/null and b/任务生成/create/goods.xls differ diff --git a/任务生成/create/monster.xls b/任务生成/create/monster.xls new file mode 100644 index 0000000..eaf811c Binary files /dev/null and b/任务生成/create/monster.xls differ diff --git a/任务生成/create/npc.xls b/任务生成/create/npc.xls new file mode 100644 index 0000000..358c6e8 Binary files /dev/null and b/任务生成/create/npc.xls differ diff --git a/任务生成/create/store.xls b/任务生成/create/store.xls new file mode 100644 index 0000000..d9547b7 Binary files /dev/null and b/任务生成/create/store.xls differ diff --git a/任务生成/create/task.xls b/任务生成/create/task.xls new file mode 100644 index 0000000..aadd709 Binary files /dev/null and b/任务生成/create/task.xls differ diff --git a/任务生成/requirement.md b/任务生成/requirement.md new file mode 100644 index 0000000..23be56a --- /dev/null +++ b/任务生成/requirement.md @@ -0,0 +1,158 @@ +# 生成任务说明 +你需要进行游戏任务的生成,游戏是一个以大航海时代为背景的wap游戏,按照提示的任务故事,进行生成任务,生成标准按照本文档。 + +## 任务设计方案 +本任务设计模式采用只完成模式,玩家没有接任务状态,当完成任务时自动记录当前完成的任务ID,下一环任务ID为当前完成任务的ID + 1,默认相当于自动接取下一环任务,所以在设计任务时,注意NPC的串联,以及相关下一环任务描述的合理性。 + +## 数据文件说明 +在当前目录下,共有4个文件夹,他们的作用分别是: + +1. resource 文件夹:包含游戏的场景等数据,用于生成必要数据的填充使用。 +2. create 文件夹: 生成数据的数据文件模板。 +3. resutlt 文件夹: 生成的数据excel 放在本文件夹。 +4. temp 文件夹:生成的脚本、记录等AI辅助文件全部放在该文件夹下 + +## 数据结构说明 + +以下针对数据结构进行说明,生成任务时要参考数据结构。 + +### resource 文件夹数据结构说明 +- map.xls : 这是地图资源文件,包含当前任务可用的所有地图点,具体字段意思如下: +地图ID:地图主键ID,关联相关数据时使用。 +地图名称:地图点的名称。 +城市名称:地图点所在城市的名称。 + + + +### create 文件夹数据结构说明 +- task.xls : 这是生成任务模板,具体每个字段意思如下: +任务ID:数字ID,生成时自动生成,从1001开始,每环任务+1。 +任务名称:该任务的简要名称。 +NPCID:根据NPC规则,对应任务绑定的NPCID。 +任务提示:指NPC说出的内容,即任务串联起来的故事。 +我的回答:指玩家应该回答的内容。 +下一环任务摘要:指玩家完成该任务后,下一环任务的摘要,摘要需要包含城市和地图名称,例如"去威尼斯广场和某某NPC兑换";如果下一环任务要求中是击杀怪物获得的道具作为任务要求的,要在任务中说明去哪里击杀怪物收集哪些物品交给哪个NPC,同时要内容丰富的介绍下一环完成条件(如果有条件)。 +任务要求:任务可以需要任务物品/或者击杀怪物,当本环任务没有任务要求,仅对话任务时,该字段内容为:“[]”,如果有要求时该字段为数组json结构,结构模型如下: +[ + { + "code":"Monster",//要求类型:Monster:怪物,Goods:物品,copper:铜贝 + "name":"病鸡",//相关名称:为怪物名称或者物品名称,如果是铜贝名称为“铜贝” + "parameter":"0AA26D21-B220-A830-A355-63C344C54079",//物品参数,怪物的怪物ID或者物品ID, + "count":3,//要求的属灵 + "mapId":"10_19",//怪物所在的地图ID,如果是怪物掉落物品的话,为怪物所在的地图ID,如果需要购买的物品为NPC所在的地图ID;非怪物或物品,该参数值为空 + "areaCode":"Own", //如果是怪物类型的话,仅个人击杀怪物参数为“Own”,如果是队伍都可以击杀为“Team”,非怪物类型该参数为空。 + "isOp":0//如果是物品或者铜贝需要扣除的该参数值为1,否则为0;如果时任务物品,且后续任务环不再需要该物品,要进行扣除处理,如果后续还需要,且后续不再给该道具,则不要进行扣除,要保证任务连贯性。 + } +] + +任务奖励: 任务奖励是完成该环任务发放的奖励,如果该环不发奖励,该值为空;否则按照数组json格式生成,格式如下: + +[ + { + "code": "exp",//发放奖励类型:copper:铜贝 renown :声望 exp:经验 Goods:物品 + "name": "经验",//物品道具名称 + "parameter": null,//物品道具参数 + "count": 230 //数量 + }, + { + "code":"copper", + "name":"铜贝", + "parameter":null, + "count":200 + }, + { + "code":"renown", + "name":"声望", + "parameter":null, + "count":1 + }, + { + "code":"Goods", + "name":"领路蝶", + "parameter":"10033", + "count":100 + }, + { + "code":"Goods", + "name":"引路蜂", + "parameter":"10034", + "count":100 + } +] + + +- npc.xls :生成任务的NPC数据结构,当进行任务生成时,同时任务对应的NPC数据结构,结构参数说明如下: +NPCID:生成的NPCID,为数字类型,参考提示要求的数字起始值进行叠加1生成。 +npc名称:生成任务时对话的NPC名称。 +地图ID:NPC所在地图点ID,参考任务生成npc所在地图。 +npc类型:类型值为“Task”。 +是否拥有业务: 如果该npc提供玩家购买物品,则该值为“商店”,否则为空。 +npc介绍: 对生成的该npc有一个性格或者人物的背景介绍,要求不超过50字。 + + +- goods.xls : 任务需要的物品,为串联任务或怪物掉落或任务剧情道具物品生成在该表格,参数说明: +物品ID:物品的主键ID,为数组类型,生成按照提示进行+1生成设计。 +物品名称: 物品或道具名称 +物品介绍:该物品的简单说明,不超过30字。 +获取途径:说明该物品如何获取。 + + +- monster.xls : 怪物表格,任务进行中如果有击杀怪物要求,对应的怪物表格 +怪物ID:生成的怪物ID,为数组类型,生成按照提示进行+1生成设计。 +怪物名称:怪物的名称 +等级: 生成怪物对应的等级,根据提示要求范围进行合理生成等级。 +最小攻击: 怪物的最小攻击,生成的公式:怪物等级*2 +最大攻击:怪物最大攻击,生成的公式:按照最小攻击*1.5 +防御:怪物防御值,生成的公式:按照最小攻击*0.8 +敏捷:怪物敏捷值,生成的公式:按照最小攻击*0.8 +体力:怪物的生命值,生成的公式:按照最大攻击*5 +经验:击杀怪物获得的经验,生成公式:怪物等级*3 +说明:怪物背景的说明,简要说明,不超过30字。 +怪物掉落:在设计的任务中,如果需要击杀怪物掉落物品,则需要配置该字段,否则为空。如果需要进行掉落,则掉落的参数配置为json,结构样例如下: +{ + "type":"Default", + "award": + { + "code":"Chance", + "name":"", + "empty":100,//掉落几率,在任务怪物中该值为100 + "data": + [ + { + "code":"Goods",//掉落类型,Goods:物品 + "name":"情书",//物品名称 + "par":"200001",//物品ID + "minCount":1,//掉落最小数量 + "maxCount":1,//掉落最大数量 + "chance":100.0//概率,最大100,最小0,在任务中该值永远为100 + } + ] + } +} + +- store.xls :NPC商店数据表,如果任务要求需要玩家找特性npc进行购买时,生成的数据要放在这里,其中每个参数的意思如下: +售卖ID:商店ID,按照NPCID+0001,叠加+1生成即可,数字类型。 +NPCID:对应的NPCID +物品名称:对应售卖的物品名称 +物品ID:对应生成的物品ID +物品价格:按照提示中要求的物品价格区间进行随机生成。 + + + +### resutlt 文件夹数据结构说明 + +参考 create文件夹中包含的文件模板,把生成的数据分类放在result文件夹下,文件名称和模板对应的文件名称保持一致。 + +## 特别说明和注意事项 +1. 当下一环任务要求提供的物品,如果该物品不是击杀怪物掉落同时也不是商城购买,则需要在下一环任务开始之前通过其他环任务发放奖励的方式给与玩家,保证玩家在完成该环任务时不缺少道具。 +2. 如果在提示中,没有要求奖励指定道具物品,则任务奖励除了必要的任务所需道具物品外,任务奖励只发放经验、声望、铜贝,具体数值参考提示(按照提示中给的总额度,进行设计分配)。 +3. 按照提示,结合本文档的相关说明生成任务数据。 +4. 生成之后要对数据进行效验比较,认真检查。 +5. 如果该任务完成后发放奖励,则任务奖励中的每一项奖励的count不能小于0。 +6. 如果怪物掉落任务物品,那么掉落的数量大于任务要求数量,例如:如果任务要求3个物品,怪物设置了1个,那么这个怪物击杀后奖励必须为最少3个,可以设置击多个怪物数量。 +7. 如果是怪物掉落的物品作为任务道具,则怪物也要同时作为任务完成条件。 +8. 一定要检查下一环任务摘要中的描述和下一环实际场景是否对战,如果下一环有击杀任务要求,要验证是否和描述中的地图点是否一致。 + + +## 验证 +完成所有生成后,对生成数据的每个细节点、逻辑点等进行最后全面检查。 \ No newline at end of file diff --git a/任务生成/resource.zip b/任务生成/resource.zip new file mode 100644 index 0000000..bfeda0e Binary files /dev/null and b/任务生成/resource.zip differ diff --git a/任务生成/resource/map.xls b/任务生成/resource/map.xls new file mode 100644 index 0000000..a9d6b50 Binary files /dev/null and b/任务生成/resource/map.xls differ