This commit is contained in:
Putoo
2026-07-10 16:39:52 +08:00
parent cfe6612a7a
commit 9de24634e3
31 changed files with 760 additions and 39 deletions

View File

@@ -30,6 +30,9 @@ namespace Application.Domain.Entity
[SugarColumn(IsNullable = true)] [SugarColumn(IsNullable = true)]
public int? itemId { get; set; } public int? itemId { get; set; }
[SugarColumn(IsNullable = true)]
public int? lev { get; set; }
/// <summary> /// <summary>
/// name /// name
/// </summary> /// </summary>

View File

@@ -18,6 +18,8 @@ namespace Application.Domain
HandleCreateMonster,//处理创建的怪物 HandleCreateMonster,//处理创建的怪物
HandleFightData,//处理战斗日志数据 HandleFightData,//处理战斗日志数据
HandleExchangeData,//处理兑换数据 HandleExchangeData,//处理兑换数据
HandleTaskLog,//处理任务日志
HandelTaskUser,//处理角色任务
} }
} }

View File

@@ -85,5 +85,25 @@
var exchangeService = App.GetService<IExchangeService>(); var exchangeService = App.GetService<IExchangeService>();
await exchangeService.HandleExchangeLogData(); await exchangeService.HandleExchangeLogData();
} }
/// <summary>
/// 处理任务日志
/// </summary>
/// <param name="context"></param>
[EventSubscribe(BusEventsEnum.BusEventsName.HandleTaskLog, NumRetries = 0,RetryTimeout = 999999999)]
public async Task HandleTaskLog(EventHandlerExecutingContext context)
{
var taskService = App.GetService<IGameTaskService>();
await taskService.HandleUserTaskLog();
}
/// <summary>
/// 处理角色任务
/// </summary>
/// <param name="context"></param>
[EventSubscribe(BusEventsEnum.BusEventsName.HandelTaskUser, NumRetries = 0,RetryTimeout = 999999999)]
public async Task HandelTaskUser(EventHandlerExecutingContext context)
{
var taskService = App.GetService<IGameTaskService>();
await taskService.HandleUserTask();
}
} }
} }

View File

@@ -15,6 +15,8 @@ public static class GameEnum
UpdateCreateMonster,//更新创建得怪物 UpdateCreateMonster,//更新创建得怪物
UpdateFightData,//更新战斗信息 UpdateFightData,//更新战斗信息
UpdateExchangeData,//更新兑换的记录 UpdateExchangeData,//更新兑换的记录
UpdateTaskLog,//更新任务日志
UpdateTaskUser,//更新角色任务
} }
public enum PropCode//游戏资源编码 public enum PropCode//游戏资源编码
{ {

View File

@@ -7,5 +7,10 @@ public static class MonsterEnum
Default, Default,
} }
public enum MonsterCode
{
Default,
Dup,
Task
}
} }

View File

@@ -16,6 +16,8 @@ public interface IGameMonsterService
Task<unit_user_monster> GetCreateMonsterInfo(string umId); Task<unit_user_monster> GetCreateMonsterInfo(string umId);
Task<bool> RemoveCreateMonster(string umId); Task<bool> RemoveCreateMonster(string umId);
Task<bool> RemoveCreateMonster(unit_user_monster data); Task<bool> RemoveCreateMonster(unit_user_monster data);
Task ClearCreateMonster(string userId,string code, string par, string monsterId, string mapId);
Task<int> GetUserMonsterCount(string userId, string monsterId, int state);
Task HandleCreateMonster(); Task HandleCreateMonster();
Task<List<MapMonsterModel>> GetMapMonster(string userId, string mapId, string teamId); Task<List<MapMonsterModel>> GetMapMonster(string userId, string mapId, string teamId);

View File

@@ -12,10 +12,14 @@ public interface IGameTaskService
#region #region
Task<List<unit_user_task>> GetUserTaskData(string userId);
Task<unit_user_task> GetUserTaskInfo(string userId, int taskId); Task<unit_user_task> GetUserTaskInfo(string userId, int taskId);
Task<bool> UpdateUserTaskInfo(string userId, int itemId); Task<bool> UpdateUserTaskInfo(string userId, int itemId);
Task<int> GetUserTaskCount(string userId, int taskId); Task<int> GetUserTaskCount(string userId, int taskId);
Task ResetNextTask(string userId, int nextId);
Task<UserTaskModel> GetUserTaskModel(string userId, game_task_item task); Task<UserTaskModel> GetUserTaskModel(string userId, game_task_item task);
Task HandleUserTaskLog();
Task HandleUserTask();
#endregion #endregion
} }

View File

@@ -91,5 +91,17 @@ public class GameAutoJobService(ISqlSugarClient DbClient, IRedisCache redis, ITi
await _eventPublisher.PublishAsync(new ChannelEventSource(BusEventsEnum.BusEventsName.HandleExchangeData, await _eventPublisher.PublishAsync(new ChannelEventSource(BusEventsEnum.BusEventsName.HandleExchangeData,
data)); data));
} }
else if (data.code == nameof(GameEnum.JobCode.UpdateTaskLog)) //更新任务日志
{
var _eventPublisher = App.GetService<IEventPublisher>();
await _eventPublisher.PublishAsync(new ChannelEventSource(BusEventsEnum.BusEventsName.HandleTaskLog,
data));
}
else if (data.code == nameof(GameEnum.JobCode.UpdateTaskUser)) //更新角色任务
{
var _eventPublisher = App.GetService<IEventPublisher>();
await _eventPublisher.PublishAsync(new ChannelEventSource(BusEventsEnum.BusEventsName.HandelTaskUser,
data));
}
} }
} }

View File

@@ -152,6 +152,26 @@ public class GameMonsterService(ISqlSugarClient DbClient, IRedisCache redis) : I
return result; return result;
} }
public async Task ClearCreateMonster(string userId, string code, string par, string monsterId, string mapId)
{
var db = DbClient.AsTenant().GetConnectionWithAttr<unit_user_monster>();
bool result = await db.Deleteable<unit_user_monster>()
.Where(it => it.userId == userId && it.code == code && it.par == par && it.monsterId == monsterId)
.ExecuteCommandAsync() > 0;
if (result)
{
await ClearCreateMonster(mapId);
}
}
public async Task<int> GetUserMonsterCount(string userId, string monsterId, int state)
{
var db = DbClient.AsTenant().GetConnectionWithAttr<unit_user_monster>();
return await db.Queryable<unit_user_monster>()
.Where(it => it.userId == userId && it.monsterId == monsterId && it.state == state).CountAsync();
}
public async Task HandleCreateMonster() public async Task HandleCreateMonster()
{ {
var endTime = TimeExtend.GetTimeStampSeconds; var endTime = TimeExtend.GetTimeStampSeconds;

View File

@@ -64,6 +64,20 @@ public class GameTaskService(ISqlSugarClient DbClient, IRedisCache redis) : IGam
#region #region
public async Task<List<unit_user_task>> GetUserTaskData(string userId)
{
string key = string.Format(UserCache.BaseCacheKeys, "TaskCache", "UserTaskData");
if (await redis.HExistsHashAsync(key, userId))
{
return await redis.GetHashAsync<List<unit_user_task>>(key, userId);
}
var db = DbClient.AsTenant().GetConnectionWithAttr<unit_user_task>();
var data = await db.Queryable<unit_user_task>().Where(it => it.userId == userId).ToListAsync();
await redis.AddHashAsync(key, userId, data);
return data;
}
public async Task<unit_user_task> GetUserTaskInfo(string userId, int taskId) public async Task<unit_user_task> GetUserTaskInfo(string userId, int taskId)
{ {
string utId = $"{userId}_{taskId}"; string utId = $"{userId}_{taskId}";
@@ -80,6 +94,17 @@ public class GameTaskService(ISqlSugarClient DbClient, IRedisCache redis) : IGam
return data; 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<bool> UpdateUserTaskInfo(string userId, int itemId) public async Task<bool> UpdateUserTaskInfo(string userId, int itemId)
{ {
bool result = false; bool result = false;
@@ -93,8 +118,7 @@ public class GameTaskService(ISqlSugarClient DbClient, IRedisCache redis) : IGam
result = await db.Deleteable<unit_user_task>().Where(it => it.utId == utId).ExecuteCommandAsync() > 0; result = await db.Deleteable<unit_user_task>().Where(it => it.utId == utId).ExecuteCommandAsync() > 0;
if (result) if (result)
{ {
string key = string.Format(UserCache.BaseCacheKeys, "TaskCache", "UserTaskInfo"); await ClearUserTaskCache(userId, utId);
await redis.DelHashAsync(key, utId);
} }
} }
else else
@@ -107,6 +131,7 @@ public class GameTaskService(ISqlSugarClient DbClient, IRedisCache redis) : IGam
onTask.userId = userId; onTask.userId = userId;
onTask.taskId = taskInfo.taskId; onTask.taskId = taskInfo.taskId;
onTask.itemId = taskInfo.tiId; onTask.itemId = taskInfo.tiId;
onTask.lev = taskInfo.lev;
onTask.name = taskInfo.name; onTask.name = taskInfo.name;
onTask.code = taskInfo.code; onTask.code = taskInfo.code;
onTask.endTime = await GetItemEndTime((int)taskInfo.taskId, (int)taskInfo.time); 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.itemId = taskInfo.tiId;
onTask.name = taskInfo.name; onTask.name = taskInfo.name;
onTask.lev = taskInfo.lev;
onTask.code = taskInfo.code; onTask.code = taskInfo.code;
onTask.endTime = await GetItemEndTime((int)taskInfo.taskId, (int)taskInfo.time); onTask.endTime = await GetItemEndTime((int)taskInfo.taskId, (int)taskInfo.time);
var db = DbClient.AsTenant().GetConnectionWithAttr<unit_user_task>(); var db = DbClient.AsTenant().GetConnectionWithAttr<unit_user_task>();
@@ -127,17 +153,36 @@ public class GameTaskService(ISqlSugarClient DbClient, IRedisCache redis) : IGam
{ {
string key = string.Format(UserCache.BaseCacheKeys, "TaskCache", "UserTaskInfo"); string key = string.Format(UserCache.BaseCacheKeys, "TaskCache", "UserTaskInfo");
await redis.AddHashAsync(key, utId, onTask); await redis.AddHashAsync(key, utId, onTask);
await ClearUserTaskCache(userId);
} }
} }
} }
if (result) if (result)
{ {
//清理遗留数据,如怪物
if (taskInfo.needData.Count > 0)
{
var monsterService = App.GetService<IGameMonsterService>();
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) if (taskInfo.itemType == 0)
{ {
await AddUserTaskLog(userId, (int)taskInfo.taskId); await AddUserTaskLog(userId, (int)taskInfo.taskId);
} }
else if (taskInfo.itemType == 1)
if (taskInfo.itemType != 2)
{ {
//初始化下一环任务 //初始化下一环任务
await ResetNextTask(userId, taskInfo.tiId + 1); await ResetNextTask(userId, taskInfo.tiId + 1);
@@ -169,7 +214,7 @@ public class GameTaskService(ISqlSugarClient DbClient, IRedisCache redis) : IGam
long endTime = await GetEndTime(taskId); long endTime = await GetEndTime(taskId);
unit_user_task_log log = new unit_user_task_log() unit_user_task_log log = new unit_user_task_log()
{ {
utId = utId, utId = StringAssist.NewGuid,
userId = userId, userId = userId,
taskId = taskId, taskId = taskId,
addTime = DateTime.Now, 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<IGameMonsterService>();
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<UserTaskModel> GetUserTaskModel(string userId, game_task_item task) public async Task<UserTaskModel> GetUserTaskModel(string userId, game_task_item task)
@@ -268,6 +339,68 @@ public class GameTaskService(ISqlSugarClient DbClient, IRedisCache redis) : IGam
return model; return model;
} }
public async Task HandleUserTaskLog()
{
//处理任务日志
var db = DbClient.AsTenant().GetConnectionWithAttr<unit_user_task_log>();
List<string> uts = new List<string>();
long endTime = TimeExtend.GetTimeStampSeconds;
var data = await db.Queryable<unit_user_task_log>().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<unit_user_task_log>().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<unit_user_task>();
List<string> users = new List<string>();
List<string> uts = new List<string>();
long endTime = TimeExtend.GetTimeStampSeconds;
var data = await db.Queryable<unit_user_task>().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<unit_user_task>().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 #endregion
#region #region

View File

@@ -220,6 +220,18 @@ public static class GameBus
isok = false; isok = false;
} }
} }
else if (item.code == nameof(GameEnum.PropCode.Monster))
{
var monsterService = App.GetService<IGameMonsterService>();
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.result = isok;
result.isDeal = isDeal; result.isDeal = isDeal;

View File

@@ -28,17 +28,37 @@ namespace Application.Web.Controllers.Login
_attrService = attrService; _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;
}
/// <summary> /// <summary>
/// 登录接口 /// 登录接口
/// </summary> /// </summary>
/// <param name="parms"></param> /// <param name="parms"></param>
/// <returns></returns> /// <returns></returns>
[HttpPost] // [HttpPost]
public async Task<IPoAction> Login([FromBody] LoginParms parms) // public async Task<IPoAction> Login([FromBody] LoginParms parms)
{ // {
return PoAction.Ok(parms.code); // return PoAction.Ok(parms.code);
} // }
/// <summary> /// <summary>
/// 探玩自动登录 /// 探玩自动登录

View File

@@ -152,7 +152,7 @@ public class MapController : ControllerBase
string fightId = userFight.Count > 0 ? userFight[0] : ""; string fightId = userFight.Count > 0 ? userFight[0] : "";
var mapGoods = await _fightService.GetMapFightGoods(mapInfo.mapId); var mapGoods = await _fightService.GetMapFightGoods(mapInfo.mapId);
mapGoods = mapGoods.FindAll(it => it.userId == "0" || it.userId == userId).Take(3).ToList(); mapGoods = mapGoods.FindAll(it => it.userId == "0" || it.userId == userId).Take(3).ToList();
var taskData = await _taskService.GetUserTaskData(userId);
int isHook = 0; //挂机处理 int isHook = 0; //挂机处理
var onHook = await _hookService.GetUserOnHook(userId); var onHook = await _hookService.GetUserOnHook(userId);
isHook = (int)onHook.status; isHook = (int)onHook.status;
@@ -173,7 +173,8 @@ public class MapController : ControllerBase
monster = monsterData, monster = monsterData,
fightId, fightId,
gameTips, gameTips,
isHook isHook,
taskCount = taskData.Count
}; };

View File

@@ -103,6 +103,94 @@ public class TaskController : ControllerBase
{ npc = npcInfo, data = data, talkMsg, taskState, btnTips = taskInfo.btnTips, toGoods, retGoods }); { npc = npcInfo, data = data, talkMsg, taskState, btnTips = taskInfo.btnTips, toGoods, retGoods });
} }
/// <summary>
/// 获取个人任务
/// </summary>
/// <returns></returns>
[HttpGet]
public async Task<IPoAction> GetUserTask()
{
string userId = StateHelper.userId;
var data = await _taskService.GetUserTaskData(userId);
return PoAction.Ok(data);
}
/// <summary>
/// 重置任务
/// </summary>
/// <param name="task"></param>
/// <returns></returns>
[HttpGet]
public async Task<IPoAction> 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);
}
/// <summary>
/// 获取个人任务详情
/// </summary>
/// <param name="taskId"></param>
/// <returns></returns>
[HttpGet]
public async Task<IPoAction> 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 });
}
/// <summary> /// <summary>
/// 完成任务 /// 完成任务
/// </summary> /// </summary>
@@ -175,6 +263,7 @@ public class TaskController : ControllerBase
} }
message = message.TrimEnd(','); message = message.TrimEnd(',');
await GameBus.UpdateBag(userId, 1, award, "完成任务");//发放奖励
} }
return PoAction.Ok(true, message); return PoAction.Ok(true, message);

View File

@@ -20,11 +20,12 @@ public class FightController : ControllerBase
private readonly IUnitUserService _userService; private readonly IUnitUserService _userService;
private readonly IOnHookService _hookService; private readonly IOnHookService _hookService;
private readonly IUnitUserRelationService _relationService; private readonly IUnitUserRelationService _relationService;
private readonly IGameTaskService _taskService;
public FightController(IGameFightService fightService, IGameMonsterService monsterService, public FightController(IGameFightService fightService, IGameMonsterService monsterService,
IUnitUserAttrService attrService, IGameMapService mapService, IUnitUserAccService accService, IUnitUserAttrService attrService, IGameMapService mapService, IUnitUserAccService accService,
IGameGoodsService goodsService, IUnitUserService userService, IOnHookService hookService, IGameGoodsService goodsService, IUnitUserService userService, IOnHookService hookService,
IUnitUserRelationService relationService) IUnitUserRelationService relationService, IGameTaskService taskService)
{ {
_fightService = fightService; _fightService = fightService;
_monsterService = monsterService; _monsterService = monsterService;
@@ -35,6 +36,7 @@ public class FightController : ControllerBase
_userService = userService; _userService = userService;
_hookService = hookService; _hookService = hookService;
_relationService = relationService; _relationService = relationService;
_taskService = taskService;
} }
/// <summary> /// <summary>
@@ -162,16 +164,18 @@ public class FightController : ControllerBase
return PoAction.Message("该地图不允许跨服战斗!"); return PoAction.Message("该地图不允许跨服战斗!");
} }
} }
string fightId = StringAssist.NewGuid; string fightId = StringAssist.NewGuid;
string areaCode = nameof(GameEnum.AreaCode.Own); string areaCode = nameof(GameEnum.AreaCode.Own);
string code = nameof(GameEnum.FightCode.PVP); string code = nameof(GameEnum.FightCode.PVP);
string keyId = StringAssist.GetSortKey(userId,otUser.userId); string keyId = StringAssist.GetSortKey(userId, otUser.userId);
long exp = 0; long exp = 0;
long copper = 0; long copper = 0;
long petExp = 0; long petExp = 0;
string award = string.Empty; string award = string.Empty;
string pars = ""; 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); copper, petExp, award, pars);
if (result) if (result)
{ {
@@ -229,17 +233,6 @@ public class FightController : ControllerBase
#endregion #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(); UserAttrModel otAttr = new UserAttrModel();
if (fight.code == nameof(GameEnum.FightCode.PVE)) if (fight.code == nameof(GameEnum.FightCode.PVE))
{ {
@@ -264,6 +257,20 @@ public class FightController : ControllerBase
otAttr = await _attrService.GetUserAttrModel(fight.mainId, fight.scene); 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) 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 myAttr = await _attrService.GetUserAttrModel(userId, fight.scene);
var parsData = JsonConvert.DeserializeObject<dynamic>(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
return PoAction.Ok(new { isWin, otName, blood = myAttr.blood, upBlood = myAttr.upBlood, fight, isCopy }); { isWin, otName, blood = myAttr.blood, upBlood = myAttr.upBlood, fight, isCopy, figArea, figResult });
} }
#region #region

View File

@@ -27,6 +27,15 @@
<div class="item" v-if="fight.award != ''" v-html="AwardTips"> <div class="item" v-if="fight.award != ''" v-html="AwardTips">
</div> </div>
</div> </div>
<div class="common" v-if="figArea == 'Task'">
<div class="content" v-if="needs.length > 0">
任务要求:<br>
<GamePropVerify :data="verifyData.needs" ></GamePropVerify>
</div>
<div class="content" v-if="verifyData.result">
<Abutton @click="retTask">我要传送</Abutton>
</div>
</div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -42,6 +51,10 @@ const upBlood = ref(0);
const fight = ref<any>({}); const fight = ref<any>({});
const AwardTips = ref(''); const AwardTips = ref('');
const isCopy = ref(0); const isCopy = ref(0);
const figArea = ref('');
const figAreaData = ref<any>({});
const verifyData = ref<any>({});
const needs = ref<Array<any>>([]);
let fightId = PageExtend.QueryString("f"); let fightId = PageExtend.QueryString("f");
onMounted(async () => { onMounted(async () => {
@@ -62,9 +75,15 @@ const BindData = async (): Promise<void> => {
upBlood.value = result.data.upBlood; upBlood.value = result.data.upBlood;
fight.value = result.data.fight; fight.value = result.data.fight;
isCopy.value = result.data.isCopy; isCopy.value = result.data.isCopy;
figArea.value = result.data.figArea;
if (fight.value.award != '') { if (fight.value.award != '') {
AwardTips.value = awardTipsStr(JSON.parse(fight.value.award)) AwardTips.value = awardTipsStr(JSON.parse(fight.value.award))
} }
if (figArea.value == 'Task') {
figAreaData.value = result.data.figResult;
verifyData.value = figAreaData.value.result;
needs.value = verifyData.value.needs;
}
} }
else if (result.code == 100) { else if (result.code == 100) {
PageExtend.RedirectTo("/fight?f=" + fightId); PageExtend.RedirectTo("/fight?f=" + fightId);
@@ -107,5 +126,15 @@ const onHook = async () => {
MessageExtend.Notify(result.msg, "danger"); MessageExtend.Notify(result.msg, "danger");
} }
} }
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");
}
}
</script> </script>

View File

@@ -9,7 +9,7 @@
<div class="content"> <div class="content">
{{ cityInfo.cityName }}·{{ mapInfo.mapName }}({{ mapInfo.x }},{{ mapInfo.y }}) {{ cityInfo.cityName }}·{{ mapInfo.mapName }}({{ mapInfo.x }},{{ mapInfo.y }})
<Abutton @click="Refresh">刷新</Abutton> <Abutton @click="Refresh">刷新</Abutton>
<Abar href="/task/">任务</Abar> <Abar href="/task/">任务{{ taskCount > 0 ? "(" + taskCount + ")" : "" }}</Abar>
<Abar href="/user/message/">消息{{ messageCount > 0 ? "(" + messageCount + ")" : "" }}</Abar> <Abar href="/user/message/">消息{{ messageCount > 0 ? "(" + messageCount + ")" : "" }}</Abar>
</div> </div>
<div class="content" v-if="gameTips != ''" style="color: red;font-size: 16px;"> <div class="content" v-if="gameTips != ''" style="color: red;font-size: 16px;">
@@ -146,6 +146,7 @@ const broadcast = ref<Array<any>>([]);
const gameTips = ref(''); const gameTips = ref('');
const isHook = ref(0); const isHook = ref(0);
const mapGoods = ref<Array<any>>([]); const mapGoods = ref<Array<any>>([]);
const taskCount = ref(0);
// 城内地图显示 // 城内地图显示
const showCity = ref(false); const showCity = ref(false);
@@ -181,6 +182,7 @@ const BindData = async (map: string): Promise<void> => {
gameTips.value = result.data.gameTips; gameTips.value = result.data.gameTips;
mapGoods.value = result.data.mapGoods; mapGoods.value = result.data.mapGoods;
isHook.value = result.data.isHook; isHook.value = result.data.isHook;
taskCount.value = result.data.taskCount;
// console.log(result) // console.log(result)
} }
else if (result.code == 103) { else if (result.code == 103) {

View File

@@ -16,11 +16,16 @@
<div class="common" v-if="task.length > 0"> <div class="common" v-if="task.length > 0">
当前任务:<br> 当前任务:<br>
<div class="item" v-for="item in task"> <div class="item" v-for="item in task">
<img src="/images/site/tg.gif" v-if="item.state==0" /> <img src="/images/site/tg.gif" v-if="item.state == 0" />
<img src="/images/site/tr.gif" v-if="item.state==1" /> <img src="/images/site/tr.gif" v-if="item.state == 1" />
<Abar :href='"/task/info?task=" + item.itemId'>[{{ item.code }}]{{ item.name }}</Abar> <Abar :href='"/task/info?task=" + item.itemId'>[{{ item.code }}]{{ item.name }}</Abar>
</div> </div>
</div> </div>
<div>
<div class="item" v-for="item in data.bus">
<Abar :href="item.url">{{ item.name }}</Abar>
</div>
</div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -41,7 +46,6 @@ onMounted(async () => {
}) })
const BindData = async (): Promise<void> => { const BindData = async (): Promise<void> => {
let npc = PageExtend.QueryString("npc"); let npc = PageExtend.QueryString("npc");
let result = await MapService.GetNpcInfo(Number(npc)); let result = await MapService.GetNpcInfo(Number(npc));

View File

@@ -1,3 +1,41 @@
<template> <template>
<div class="content">
我的任务
</div>
<div class="content">
<div class="item" v-for="(item,index) in data" :key="index">
{{index+1}}.<Abar :href='"/task/look?id="+item.itemId'>[{{item.code}}]{{item.name}}</Abar>({{item.lev}})
</div>
<span v-if="data.length==0">
暂无任务.
</span>
</div>
</template> </template>
<script setup lang="ts">
definePageMeta({
layout: layout.default,
middleware: 'page-loading'
})
const data = ref<Array<any>>({});
onMounted(async () => {
try {
await BindData();
}
finally {
PageLoading.Close();
}
})
const BindData = async (): Promise<void> => {
let result = await TaskService.GetUserTask();
if (result.code == 0) {
data.value = result.data;
}
else {
MessageExtend.ShowDialog("提示",result.msg);
}
};
</script>

View File

@@ -3,7 +3,7 @@
<strong>{{ npcData.npcName }}</strong>:{{ talkMsg }} <strong>{{ npcData.npcName }}</strong>:{{ talkMsg }}
</div> </div>
<div class="content" v-if="taskState == 100"> <div class="content" v-if="taskState == 100">
等待开放下一环任务! 恭喜,任务已全部完成!
</div> </div>
<div v-else> <div v-else>
<div v-if="data.state != -1"> <div v-if="data.state != -1">

118
Web/src/pages/task/look.vue Normal file
View File

@@ -0,0 +1,118 @@
<template>
<div class="content">
[{{ data.code }}]{{ data.name }}({{ data.lev }})
</div>
<div class="content" v-if="taskState == 100">
当前任务已暂停,等待任务更新!
</div>
<div v-else>
<div class="content">
{{ talkMsg }}
</div>
<div v-if="data.state != -1">
<div class="content" v-if="needs.length > 0">
任务要求:<br>
<GameTaskPropVerify :data="verifyData.needs" @mapTo="mapTo"></GameTaskPropVerify>
</div>
<div class="content" v-if="verifyData.result">
<Abutton @click="retTask">我要传送</Abutton>(领路蝶:{{ retGoods }})
</div>
<div class="content" v-else>
<Abutton @click="restTask">重置任务</Abutton>
</div>
</div>
</div>
</template>
<script setup lang="ts">
definePageMeta({
layout: layout.default,
middleware: 'page-loading'
})
const data = ref<any>({});
const verifyData = ref<any>({});
const needs = ref<Array<any>>([]);
const talkMsg = ref('');
const taskState = ref(-1);
const toGoods = ref(0);
const retGoods = ref(0);
let taskId = PageExtend.QueryString("id");
let npcId = LocalStorageHelper.GetOnNpc();
onMounted(async () => {
try {
await BindData();
}
finally {
PageLoading.Close();
}
})
const BindData = async (): Promise<void> => {
let result = await TaskService.GetUserTaskInfo(Number(taskId));
if (result.code == 0) {
data.value = result.data.data;
talkMsg.value = result.data.talkMsg;
taskState.value = result.data.taskState;
toGoods.value = result.data.toGoods;
retGoods.value = result.data.retGoods;
verifyData.value = data.value.result;
needs.value = verifyData.value.needs;
taskId = data.value.itemId;
}
else {
PageExtend.RedirectTo("/task")
}
};
const ReturnTask = async () => {
MessageExtend.LoadingToast("提交任务中...");
let result = await TaskService.OverTask(Number(npcId), Number(data.value.itemId));
MessageExtend.LoadingClose();
if (result.code == 0) {
await BindData();
if (result.msg != '') {
MessageExtend.Notify(result.msg, "success");
}
}
else {
MessageExtend.Notify(result.msg, "danger");
}
}
const mapTo = async (btnData: any) => {
MessageExtend.LoadingToast("传送中...");
let result = await TaskService.NeedMapTo(Number(data.value.itemId), btnData.num);
MessageExtend.LoadingClose();
if (result.code == 0) {
PageExtend.RedirectTo("/map");
}
else {
MessageExtend.Notify(result.msg, "danger");
}
}
const retTask = async (btnData: any) => {
MessageExtend.LoadingToast("传送中...");
let result = await TaskService.ReturnTask(Number(data.value.itemId));
MessageExtend.LoadingClose();
if (result.code == 0) {
PageExtend.RedirectTo("/map");
}
else {
MessageExtend.Notify(result.msg, "danger");
}
}
const restTask = async (btnData: any) => {
MessageExtend.LoadingToast("任务重置中...");
let result = await TaskService.RestTask(Number(data.value.taskId));
MessageExtend.LoadingClose();
if (result.code == 0) {
MessageExtend.Notify("任务重置成功!","success");
}
else {
MessageExtend.Notify(result.msg, "danger");
}
}
</script>

View File

@@ -7,6 +7,30 @@ export class TaskService {
return await ApiService.Request("get", "/Map/Task/GetTaskByNpc", { npcId, taskId }); 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 * GET /Map/Task/OverTask

BIN
任务生成/create.zip Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
任务生成/create/npc.xls Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

158
任务生成/requirement.md Normal file
View File

@@ -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名称。
地图IDNPC所在地图点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. 一定要检查下一环任务摘要中的描述和下一环实际场景是否对战,如果下一环有击杀任务要求,要验证是否和描述中的地图点是否一致。
## 验证
完成所有生成后,对生成数据的每个细节点、逻辑点等进行最后全面检查。

BIN
任务生成/resource.zip Normal file

Binary file not shown.

Binary file not shown.