mirror of
https://github.com/milimoe/FunGame-Testing.git
synced 2026-04-20 05:25:02 +00:00
添加 rogue
This commit is contained in:
parent
512d7d7d6a
commit
727f13aba6
@ -9,11 +9,10 @@ using Oshima.FunGame.OshimaServers.Service;
|
||||
using Oshima.FunGame.WebAPI.Controllers;
|
||||
|
||||
//_ = new Milimoe.FunGame.Testing.Solutions.Novels();
|
||||
//Console.ReadKey();
|
||||
|
||||
//_ = new Milimoe.FunGame.Testing.Tests.CheckDLL();
|
||||
|
||||
Console.WriteLine();
|
||||
|
||||
//_ = new Milimoe.FunGame.Testing.Tests.WebSocketTest();
|
||||
|
||||
CharacterModule cm = new();
|
||||
@ -23,10 +22,22 @@ sm.Load();
|
||||
ItemModule im = new();
|
||||
im.Load();
|
||||
|
||||
Milimoe.FunGame.Testing.Tests.RogueLikeTest rogue = new();
|
||||
await rogue.RogueLike.StartGame();
|
||||
|
||||
FunGameConstant.InitFunGame();
|
||||
FunGameSimulation.InitFunGameSimulation();
|
||||
FunGameController controller = new(new Logger<FunGameController>(new LoggerFactory()));
|
||||
|
||||
//foreach (OshimaRegion or in FunGameConstant.Regions)
|
||||
//{
|
||||
// Console.WriteLine(or.ToString());
|
||||
//}
|
||||
//Console.ReadKey();
|
||||
|
||||
//await Milimoe.FunGame.Testing.Tests.FunGameBO5.StartBO5();
|
||||
//Console.ReadKey();
|
||||
|
||||
//foreach (Character c in FunGameSimulation.CharacterStatistics.Keys)
|
||||
//{
|
||||
// Console.WriteLine(controller.GetStats((int)c.Id));
|
||||
|
||||
248
Library/Solutions/RogueLike.cs
Normal file
248
Library/Solutions/RogueLike.cs
Normal file
@ -0,0 +1,248 @@
|
||||
using Milimoe.FunGame.Core.Entity;
|
||||
using Milimoe.FunGame.Core.Library.Constant;
|
||||
using Milimoe.FunGame.Core.Model;
|
||||
using Milimoe.FunGame.Testing.Tests;
|
||||
using Oshima.FunGame.OshimaModules.Characters;
|
||||
using Oshima.FunGame.OshimaServers.Service;
|
||||
|
||||
namespace Milimoe.FunGame.Testing.Solutions
|
||||
{
|
||||
/// <summary>
|
||||
/// 客户端逻辑层
|
||||
/// </summary>
|
||||
/// <param name="dispatcher"></param>
|
||||
public class RogueLike(RogueLikeDispatcher dispatcher)
|
||||
{
|
||||
public RogueLikeDispatcher Dispatcher { get; set; } = dispatcher;
|
||||
|
||||
public Dictionary<string, Func<string[], Task>> Commands { get; set; } = [];
|
||||
public Dictionary<string, string> CommandAlias { get; set; } = [];
|
||||
public User User { get; set; } = General.UnknownUserInstance;
|
||||
public bool Running { get; set; } = false;
|
||||
public bool InGame { get; set; } = false;
|
||||
public Lock Lock { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// 为空表示没有正在进行的询问
|
||||
/// </summary>
|
||||
private Guid _currentRequestGuid = Guid.Empty;
|
||||
/// <summary>
|
||||
/// 询问结果,和上面的字段配合使用
|
||||
/// </summary>
|
||||
private TaskCompletionSource<DataRequestArgs> _requestTcs = new();
|
||||
|
||||
public async Task StartGame()
|
||||
{
|
||||
Running = true;
|
||||
Dispatcher.StartServer();
|
||||
AddDialog("???", "探索者,欢迎入职【永恒方舟计划】,我是您的专属 AI,协助您前往指定任务地点开展勘测工作。请问您的名字是?");
|
||||
string username;
|
||||
do
|
||||
{
|
||||
username = await GetTextResultsAsync([]);
|
||||
if (username == "")
|
||||
{
|
||||
WriteLine("请输入不为空的字符串。");
|
||||
}
|
||||
}
|
||||
while (username == "");
|
||||
DataRequestArgs response = await DataRequest(new("createuser")
|
||||
{
|
||||
Data = new()
|
||||
{
|
||||
{ "username", username }
|
||||
}
|
||||
});
|
||||
if (response.Data.TryGetValue("user", out object? value) && value is User user)
|
||||
{
|
||||
User = user;
|
||||
}
|
||||
// 初始化菜单指令
|
||||
Commands["quit"] = async (args) =>
|
||||
{
|
||||
Running = false;
|
||||
WriteLine("游戏结束!");
|
||||
};
|
||||
AddCommandAlias("quit", "退出", "exit", "!q");
|
||||
Commands["test"] = async (args) =>
|
||||
{
|
||||
WriteLine("打木桩测试");
|
||||
Character enemy = new CustomCharacter(0, "木桩")
|
||||
{
|
||||
Level = User.Inventory.MainCharacter.Level,
|
||||
CharacterState = CharacterState.NotActionable
|
||||
};
|
||||
enemy.Recovery();
|
||||
List<string> strings = (await FunGameActionQueue.NewAndStartGame([User.Inventory.MainCharacter, enemy], showAllRound: true)).Result;
|
||||
foreach (string str in strings)
|
||||
{
|
||||
WriteLine(str);
|
||||
}
|
||||
};
|
||||
Commands["help"] = Help;
|
||||
Commands["start"] = async (args) =>
|
||||
{
|
||||
if (InGame)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InGame = true;
|
||||
await Start();
|
||||
InGame = false;
|
||||
};
|
||||
AddCommandAlias("help", "菜单", "h", "帮助");
|
||||
AddCommandAlias("start", "开局");
|
||||
AddDialog("柔哥", $"让我再次欢迎您,{username}。入职手续已办理完毕,接下来,您可以使用菜单了。请您记住我的名字:【柔哥】。");
|
||||
await Help([]);
|
||||
while (Running)
|
||||
{
|
||||
if (InGame)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
continue;
|
||||
}
|
||||
string input = await GetTextResultsAsync([]);
|
||||
string[] strings = input.Split(" ", StringSplitOptions.RemoveEmptyEntries);
|
||||
if (strings.Length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
string command = strings[0];
|
||||
string[] args = [.. strings.Skip(1)];
|
||||
if (Commands.TryGetValue(command.ToLower(), out Func<string[], Task>? func) && func != null)
|
||||
{
|
||||
await func.Invoke(args);
|
||||
}
|
||||
else if (CommandAlias.TryGetValue(command.ToLower(), out string? actualCommand) && actualCommand != null)
|
||||
{
|
||||
if (Commands.TryGetValue(actualCommand, out Func<string[], Task>? func2) && func2 != null)
|
||||
{
|
||||
await func2.Invoke(args);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLine("未知指令");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Action<string> WriteLineHandler
|
||||
{
|
||||
get => field ?? Console.WriteLine;
|
||||
set => field = value;
|
||||
}
|
||||
|
||||
public delegate Task ReadInput<T>(Dictionary<string, object> args, List<T> results);
|
||||
public delegate Task<InquiryResponse> ReadInputInGameResponse(InquiryOptions options);
|
||||
public event ReadInput<string>? ReadInputStringHandler;
|
||||
public event ReadInput<double>? ReadInputNumberHandler;
|
||||
public event ReadInputInGameResponse? ReadInputInGameResponseHandler;
|
||||
|
||||
public async Task<List<string>> GetChoiceResultsAsync(InquiryOptions options, Dictionary<string, object> args)
|
||||
{
|
||||
int index = 0;
|
||||
Dictionary<int, string> indexToChoice = [];
|
||||
foreach (string choice in options.Choices.Keys)
|
||||
{
|
||||
index++;
|
||||
indexToChoice[index] = choice;
|
||||
WriteLine($"{index}. {choice}:{options.Choices[choice]}");
|
||||
}
|
||||
WriteLine($"--- {options.Topic} ---");
|
||||
List<string> results = [];
|
||||
if (ReadInputStringHandler != null)
|
||||
{
|
||||
await ReadInputStringHandler.Invoke(args, results);
|
||||
}
|
||||
return [.. indexToChoice.Where(kv => results.Contains(kv.Key.ToString())).Select(kv => kv.Value)];
|
||||
}
|
||||
|
||||
public async Task<List<double>> GetNumberResultsAsync(Dictionary<string, object> args)
|
||||
{
|
||||
List<double> results = [];
|
||||
if (ReadInputNumberHandler != null)
|
||||
{
|
||||
await ReadInputNumberHandler.Invoke(args, results);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public async Task<string> GetTextResultsAsync(Dictionary<string, object> args)
|
||||
{
|
||||
List<string> results = [];
|
||||
if (ReadInputStringHandler != null)
|
||||
{
|
||||
await ReadInputStringHandler.Invoke(args, results);
|
||||
}
|
||||
return results.FirstOrDefault() ?? "";
|
||||
}
|
||||
|
||||
public async Task<DataRequestArgs> DataRequest(DataRequestArgs args)
|
||||
{
|
||||
_requestTcs.TrySetCanceled();
|
||||
_currentRequestGuid = Guid.NewGuid();
|
||||
|
||||
_requestTcs = new TaskCompletionSource<DataRequestArgs>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
||||
await Dispatcher.DataRequest(_currentRequestGuid, args);
|
||||
|
||||
return await _requestTcs.Task;
|
||||
}
|
||||
|
||||
public async Task DataRequestComplete(Guid guid, DataRequestArgs response)
|
||||
{
|
||||
if (guid == _currentRequestGuid)
|
||||
{
|
||||
_currentRequestGuid = Guid.Empty;
|
||||
_requestTcs.TrySetResult(response);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<InquiryResponse> GetInGameResponse(InquiryOptions options)
|
||||
{
|
||||
if (ReadInputInGameResponseHandler is null) return new(options);
|
||||
return await ReadInputInGameResponseHandler.Invoke(options);
|
||||
}
|
||||
|
||||
public void WriteLine(string message = "")
|
||||
{
|
||||
WriteLineHandler(message);
|
||||
}
|
||||
|
||||
public void AddDialog(string speaker, string message)
|
||||
{
|
||||
WriteLine(BuildSpeakerDialog(speaker, message));
|
||||
}
|
||||
|
||||
public static string BuildSpeakerDialog(string speaker, string message)
|
||||
{
|
||||
return $"【{speaker}】{message}";
|
||||
}
|
||||
|
||||
private void AddCommandAlias(string command, params string[] aliases)
|
||||
{
|
||||
foreach (string alias in aliases)
|
||||
{
|
||||
CommandAlias[alias] = command;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetCommandAliases(string command)
|
||||
{
|
||||
string[] alias = [.. CommandAlias.Where(kv => kv.Value == command).Select(kv => kv.Key)];
|
||||
return alias.Length > 0 ? $"(替代:{string.Join(",", alias)})" : "";
|
||||
}
|
||||
|
||||
private async Task Help(string[] args)
|
||||
{
|
||||
WriteLine($"可用指令:{string.Join(",", Commands.Keys.Select(c => $"{c}{GetCommandAliases(c)}"))}");
|
||||
}
|
||||
|
||||
private async Task Start()
|
||||
{
|
||||
await Dispatcher.CreateGameLoop(User.Username);
|
||||
}
|
||||
}
|
||||
}
|
||||
387
Library/Solutions/RogueLikeServer.cs
Normal file
387
Library/Solutions/RogueLikeServer.cs
Normal file
@ -0,0 +1,387 @@
|
||||
using Milimoe.FunGame.Core.Api.Utility;
|
||||
using Milimoe.FunGame.Core.Entity;
|
||||
using Milimoe.FunGame.Core.Library.Constant;
|
||||
using Milimoe.FunGame.Core.Model;
|
||||
using Milimoe.FunGame.Testing.Tests;
|
||||
using Oshima.FunGame.OshimaModules.Characters;
|
||||
using Oshima.FunGame.OshimaModules.Models;
|
||||
using Oshima.FunGame.OshimaModules.Regions;
|
||||
|
||||
namespace Milimoe.FunGame.Testing.Solutions
|
||||
{
|
||||
public class RogueLikeServer(RogueLikeDispatcher dispatcher)
|
||||
{
|
||||
public bool Running => Dispatcher.Running;
|
||||
public Task? Guard { get; set; } = null;
|
||||
public RogueLikeDispatcher Dispatcher { get; set; } = dispatcher;
|
||||
public ConcurrentQueue<(Guid Guid, DataRequestArgs Args)> Inquiries { get; } = [];
|
||||
public Dictionary<string, User> Users { get; set; } = [];
|
||||
public Dictionary<string, RogueLikeGameData> RogueLikeGameDatas { get; set; } = [];
|
||||
|
||||
public void ReceiveDataRequest(Guid guid, DataRequestArgs args)
|
||||
{
|
||||
Inquiries.Add((guid, args));
|
||||
}
|
||||
|
||||
public void WriteLine(string message = "") => Dispatcher.WriteLine(message);
|
||||
|
||||
public async Task DataRequestGuard()
|
||||
{
|
||||
while (Running)
|
||||
{
|
||||
if (!Inquiries.IsEmpty && Inquiries.GetFirst(out var obj))
|
||||
{
|
||||
DataRequestArgs response = await HandleDataRequest(obj.Args);
|
||||
await DataRequestCallback(obj.Guid, response);
|
||||
}
|
||||
await Task.Delay(50);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CreateGameLoop(string username)
|
||||
{
|
||||
Users.TryGetValue(username, out User? user);
|
||||
user ??= General.UnknownUserInstance;
|
||||
Character character = user.Inventory.MainCharacter;
|
||||
RogueLikeGameData data = new(character);
|
||||
RogueLikeGameDatas[username] = data;
|
||||
await GameLoop(data);
|
||||
}
|
||||
|
||||
private async Task GameLoop(RogueLikeGameData data)
|
||||
{
|
||||
while (data.RogueState != RogueState.Finish)
|
||||
{
|
||||
data.RogueState = await NextRogueState(data, data.RogueState);
|
||||
if (data.RogueState == RogueState.Init)
|
||||
{
|
||||
data.RogueState = RogueState.Finish;
|
||||
}
|
||||
await Task.Delay(100);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<DataRequestArgs> HandleDataRequest(DataRequestArgs args)
|
||||
{
|
||||
DataRequestArgs response = new(args.RequestType);
|
||||
|
||||
switch (response.RequestType)
|
||||
{
|
||||
case "createuser":
|
||||
{
|
||||
string username = "";
|
||||
if (args.Data.TryGetValue("username", out object? value) && value is string s)
|
||||
{
|
||||
username = s;
|
||||
}
|
||||
User user = Factory.GetUser(1, username);
|
||||
Character character = new CustomCharacter(user.Id, username)
|
||||
{
|
||||
Level = 1
|
||||
};
|
||||
character.Recovery();
|
||||
user.Inventory.Characters.Add(character);
|
||||
user.Inventory.MainCharacter = character;
|
||||
Users[username] = user;
|
||||
response.Data["user"] = user;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private async Task DataRequestCallback(Guid guid, DataRequestArgs response)
|
||||
{
|
||||
await Dispatcher.DataRequestComplete(guid, response);
|
||||
}
|
||||
|
||||
private async Task<RogueState> NextRogueState(RogueLikeGameData data, RogueState state)
|
||||
{
|
||||
RogueState newState = RogueState.Init;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case RogueState.Init:
|
||||
{
|
||||
newState = RogueState.InArk;
|
||||
}
|
||||
break;
|
||||
case RogueState.InArk:
|
||||
{
|
||||
OshimaRegion? region = await ChooseRegion(1);
|
||||
if (region != null)
|
||||
{
|
||||
WriteLine("-- 【永恒方舟计划】进程·Ⅰ:启动 --");
|
||||
data.CurrentRegion = region;
|
||||
data.Chapter1Region = region;
|
||||
newState = RogueState.Chapter1InArk;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLine("未选择地区,永恒方舟计划终止。");
|
||||
newState = RogueState.Finish;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RogueState.Chapter1InArk:
|
||||
{
|
||||
WriteLine("探索前的准备。");
|
||||
await RestInArk();
|
||||
newState = RogueState.ExploringChapter1Area1;
|
||||
}
|
||||
break;
|
||||
case RogueState.Chapter2InArk:
|
||||
{
|
||||
WriteLine("回到方舟后,我们得到了新的任务。");
|
||||
// TODO:提供一个菜单,玩家可以选择第二章的地区(随机从3-4★的地区里抽取3个来选一个)
|
||||
OshimaRegion? region = await ChooseRegion(2);
|
||||
if (region != null)
|
||||
{
|
||||
WriteLine("-- 【永恒方舟计划】进程·Ⅱ:启动 --");
|
||||
data.CurrentRegion = region;
|
||||
data.Chapter2Region = region;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLine("未选择地区,永恒方舟计划终止。");
|
||||
newState = RogueState.Finish;
|
||||
WriteLine("结算到目前为止的奖励。");
|
||||
break;
|
||||
}
|
||||
await RestInArk();
|
||||
newState = RogueState.ExploringChapter2Area1;
|
||||
}
|
||||
break;
|
||||
case RogueState.Chapter3InArk:
|
||||
{
|
||||
OshimaRegion? region = await ChooseRegion(3);
|
||||
if (region != null)
|
||||
{
|
||||
WriteLine("-- 【永恒方舟计划】进程·Ⅲ:启动 --");
|
||||
data.CurrentRegion = region;
|
||||
data.Chapter3Region = region;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLine("未选择地区,永恒方舟计划终止。");
|
||||
newState = RogueState.Finish;
|
||||
WriteLine("结算到目前为止的奖励。");
|
||||
break;
|
||||
}
|
||||
await RestInArk();
|
||||
newState = RogueState.ExploringChapter3Area1;
|
||||
}
|
||||
break;
|
||||
case RogueState.FinalInArk:
|
||||
WriteLine("-- 【永恒方舟计划】紧急事件·夺还:启动 --");
|
||||
newState = RogueState.ExploringArk;
|
||||
break;
|
||||
case RogueState.ExploringChapter1Area1:
|
||||
newState = await ExploreRegion(data, 1, 1);
|
||||
break;
|
||||
case RogueState.ExploringChapter1Area2:
|
||||
newState = await ExploreRegion(data, 1, 2);
|
||||
break;
|
||||
case RogueState.ExploringChapter2Area1:
|
||||
newState = await ExploreRegion(data, 2, 1);
|
||||
break;
|
||||
case RogueState.ExploringChapter2Area2:
|
||||
newState = await ExploreRegion(data, 2, 2);
|
||||
break;
|
||||
case RogueState.ExploringChapter3Area1:
|
||||
newState = await ExploreRegion(data, 3, 1);
|
||||
break;
|
||||
case RogueState.ExploringChapter3Area2:
|
||||
newState = await ExploreRegion(data, 3, 2);
|
||||
break;
|
||||
case RogueState.ExploringArk:
|
||||
await ExploreArk();
|
||||
newState = RogueState.FinalBossBattle;
|
||||
break;
|
||||
case RogueState.Chapter1BossBattle:
|
||||
{
|
||||
WriteLine("剧情过后,战斗一触即发。");
|
||||
// TODO:调用FunGameActionQueue的战斗系统
|
||||
WriteLine("战胜了BOSS,返回方舟汇报工作,并进行战后整备!");
|
||||
newState = RogueState.Chapter2InArk;
|
||||
}
|
||||
break;
|
||||
case RogueState.Chapter2BossBattle:
|
||||
{
|
||||
WriteLine("剧情过后,战斗一触即发。");
|
||||
// TODO:调用FunGameActionQueue的战斗系统
|
||||
WriteLine("战胜了BOSS,返回方舟汇报工作,并进行战后整备!");
|
||||
newState = RogueState.Chapter3InArk;
|
||||
}
|
||||
break;
|
||||
case RogueState.Chapter3BossBattle:
|
||||
{
|
||||
WriteLine("剧情过后,战斗一触即发。");
|
||||
// TODO:调用FunGameActionQueue的战斗系统
|
||||
WriteLine("战胜了BOSS,返回方舟汇报工作,并进行战后整备!");
|
||||
newState = RogueState.FinalInArk;
|
||||
}
|
||||
break;
|
||||
case RogueState.FinalBossBattle:
|
||||
{
|
||||
WriteLine("剧情过后,战斗一触即发。");
|
||||
// TODO:调用FunGameActionQueue的战斗系统
|
||||
WriteLine("战胜了BOSS,永恒方舟成功夺还!");
|
||||
WriteLine("本次【永恒方舟计划】成功!");
|
||||
newState = RogueState.Finish;
|
||||
}
|
||||
break;
|
||||
case RogueState.Finish:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return newState;
|
||||
}
|
||||
|
||||
private async Task<OshimaRegion?> ChooseRegion(int chapter)
|
||||
{
|
||||
string topic = chapter switch
|
||||
{
|
||||
1 => "选择初始探索地区",
|
||||
_ => "选择下一个探索地区",
|
||||
};
|
||||
Func<OshimaRegion, bool> predicate = chapter switch
|
||||
{
|
||||
2 => r => (int)r.Difficulty >= (int)RarityType.ThreeStar && (int)r.Difficulty <= (int)RarityType.FourStar,
|
||||
3 => r => (int)r.Difficulty == (int)RarityType.FiveStar,
|
||||
_ => r => (int)r.Difficulty <= (int)RarityType.TwoStar
|
||||
};
|
||||
InquiryOptions options = new(InquiryType.Choice, topic)
|
||||
{
|
||||
Choices = FunGameConstant.Regions.Where(predicate).ToDictionary(r => r.Name, r => r.ToString())
|
||||
};
|
||||
InquiryResponse response = await Dispatcher.GetInGameResponse(options);
|
||||
if (!response.Cancel)
|
||||
{
|
||||
if (response.Choices.FirstOrDefault() is string regionName)
|
||||
{
|
||||
OshimaRegion? region = FunGameConstant.Regions.FirstOrDefault(r => r.Name == regionName);
|
||||
if (region != null && region.Areas.Count > 0)
|
||||
{
|
||||
return region;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private async Task<RogueState> ExploreRegion(RogueLikeGameData data, int chapter, int areaSeq)
|
||||
{
|
||||
RogueState newState = RogueState.Finish;
|
||||
if (data.CurrentRegion is null)
|
||||
{
|
||||
WriteLine("突发!小队和方舟失联了!永恒方舟计划终止。");
|
||||
return newState;
|
||||
}
|
||||
if (areaSeq == 1)
|
||||
{
|
||||
WriteLine("正在降落...");
|
||||
data.CurrentArea = data.CurrentRegion.Areas.OrderByDescending(o => Random.Shared.Next()).First();
|
||||
WriteLine($"在【{data.CurrentRegion.Name}】的【{data.CurrentArea}】区域完成降落!");
|
||||
}
|
||||
else if (areaSeq == 2)
|
||||
{
|
||||
WriteLine("该地区的第一个探索区域任务已完成!正在前往第二个区域……");
|
||||
data.CurrentArea = data.CurrentRegion.Areas.OrderByDescending(o => Random.Shared.Next()).First(a => a != data.CurrentArea);
|
||||
WriteLine($"在【{data.CurrentRegion.Name}】的【{data.CurrentArea}】区域完成降落!");
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLine("你误入了神秘地带,与方舟失联,游戏结束。");
|
||||
return newState;
|
||||
}
|
||||
bool fin = false;
|
||||
while (!fin)
|
||||
{
|
||||
// TODO:开始探索区域,主要抉择
|
||||
fin = true;
|
||||
}
|
||||
if (areaSeq == 1)
|
||||
{
|
||||
newState = chapter switch
|
||||
{
|
||||
1 => RogueState.ExploringChapter1Area2,
|
||||
2 => RogueState.ExploringChapter2Area2,
|
||||
3 => RogueState.ExploringChapter3Area2,
|
||||
_ => RogueState.Finish,
|
||||
};
|
||||
}
|
||||
else if (areaSeq == 2)
|
||||
{
|
||||
WriteLine("BOSS房间出现了!做好准备再继续出发吧。");
|
||||
fin = false;
|
||||
while (!fin)
|
||||
{
|
||||
// TODO:BOSS房前的准备,提供菜单
|
||||
fin = true;
|
||||
}
|
||||
newState = chapter switch
|
||||
{
|
||||
1 => RogueState.Chapter1BossBattle,
|
||||
2 => RogueState.Chapter2BossBattle,
|
||||
3 => RogueState.Chapter3BossBattle,
|
||||
_ => RogueState.Finish,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLine("你误入了神秘地带,与方舟失联,游戏结束。");
|
||||
}
|
||||
return newState;
|
||||
}
|
||||
|
||||
private async Task RestInArk()
|
||||
{
|
||||
bool fin = false;
|
||||
while (!fin)
|
||||
{
|
||||
// TODO:战后整备,提供菜单回复和提升等
|
||||
fin = true;
|
||||
}
|
||||
WriteLine("出发!");
|
||||
}
|
||||
|
||||
private async Task ExploreArk()
|
||||
{
|
||||
bool fin = false;
|
||||
while (!fin)
|
||||
{
|
||||
// TODO:方舟事变,需进行方舟探索和收复功能房间并找到最终BOSS房间
|
||||
fin = true;
|
||||
}
|
||||
WriteLine("出发!");
|
||||
}
|
||||
}
|
||||
|
||||
public enum RogueState
|
||||
{
|
||||
Init,
|
||||
InArk,
|
||||
Chapter1InArk,
|
||||
Chapter2InArk,
|
||||
Chapter3InArk,
|
||||
FinalInArk,
|
||||
ExploringChapter1Area1,
|
||||
ExploringChapter1Area2,
|
||||
ExploringChapter2Area1,
|
||||
ExploringChapter2Area2,
|
||||
ExploringChapter3Area1,
|
||||
ExploringChapter3Area2,
|
||||
ExploringArk,
|
||||
Chapter1BossBattle,
|
||||
Chapter2BossBattle,
|
||||
Chapter3BossBattle,
|
||||
FinalBossBattle,
|
||||
Finish
|
||||
}
|
||||
}
|
||||
@ -100,6 +100,24 @@ namespace Milimoe.FunGame.Testing.Tests
|
||||
Console.WriteLine($"{userTeams[u2]} 禁用了 {x}");
|
||||
}
|
||||
}
|
||||
else if (i == 6 || i == 7)
|
||||
{
|
||||
if (ban.Count < 4)
|
||||
{
|
||||
Character? x = xx.FirstOrDefault(c => !ban.Contains(c));
|
||||
if (x is null) continue;
|
||||
if (i % 2 != 0)
|
||||
{
|
||||
ban.Add(x);
|
||||
Console.WriteLine($"{userTeams[u1]} 禁用了 {x}");
|
||||
}
|
||||
else if (i % 2 == 0)
|
||||
{
|
||||
ban.Add(x);
|
||||
Console.WriteLine($"{userTeams[u2]} 禁用了 {x}");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 选秀
|
||||
@ -109,7 +127,7 @@ namespace Milimoe.FunGame.Testing.Tests
|
||||
c.Level = 60;
|
||||
c.NormalAttack.Level = 8;
|
||||
FunGameService.AddCharacterSkills(c, 1, 6, 6);
|
||||
if (i % 2 == 0 && t1.Count < 5)
|
||||
if ((i < 7 ? i % 2 == 0 : i % 2 != 0) && t1.Count < 5)
|
||||
{
|
||||
User? uu = u1.FirstOrDefault(u => !t1.ContainsKey(u));
|
||||
if (uu is null) continue;
|
||||
@ -119,7 +137,7 @@ namespace Milimoe.FunGame.Testing.Tests
|
||||
Console.WriteLine($"{userTeams[u1]}.{uu} 选择了 {c}");
|
||||
c.User = uu;
|
||||
}
|
||||
if (i % 2 != 0 && t2.Count < 5)
|
||||
if ((i < 7 ? i % 2 != 0 : i % 2 == 0) && t2.Count < 5)
|
||||
{
|
||||
User? uu = u2.FirstOrDefault(u => !t2.ContainsKey(u));
|
||||
if (uu is null) continue;
|
||||
@ -148,8 +166,8 @@ namespace Milimoe.FunGame.Testing.Tests
|
||||
DropItems(team2.Members);
|
||||
team1.Members.ForEach(c => c.Recovery());
|
||||
team2.Members.ForEach(c => c.Recovery());
|
||||
FunGameActionQueue queue = new();
|
||||
List<string> msgs = await queue.StartTeamGame(teams, -1, 30);
|
||||
FunGameActionQueue queue = await FunGameActionQueue.NewAndStartTeamGame(teams, -1, 30);
|
||||
List<string> msgs = queue.Result;
|
||||
foreach (Character character in queue.GamingQueue.CharacterStatistics.Keys)
|
||||
{
|
||||
FunGameTesting.UpdateStatistics(stats[character.User], queue.GamingQueue.CharacterStatistics[character]);
|
||||
|
||||
264
Library/Tests/RogueLikeTest.cs
Normal file
264
Library/Tests/RogueLikeTest.cs
Normal file
@ -0,0 +1,264 @@
|
||||
using Milimoe.FunGame.Core.Entity;
|
||||
using Milimoe.FunGame.Core.Model;
|
||||
using Milimoe.FunGame.Testing.Solutions;
|
||||
using Oshima.FunGame.OshimaModules.Regions;
|
||||
|
||||
namespace Milimoe.FunGame.Testing.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// 肉鸽客户端原型测试
|
||||
/// </summary>
|
||||
public class RogueLikeTest
|
||||
{
|
||||
public RogueLike RogueLike { get; set; }
|
||||
public RogueLikeServer RogueLikeServer { get; set; }
|
||||
|
||||
public RogueLikeTest()
|
||||
{
|
||||
RogueLikeDispatcher dispatcher = new();
|
||||
RogueLike = new(dispatcher);
|
||||
RogueLikeServer = new(dispatcher);
|
||||
dispatcher.RogueLikeInstance = RogueLike;
|
||||
dispatcher.RogueLikeServer = RogueLikeServer;
|
||||
RogueLike.ReadInputStringHandler += RogueLike_ReadInputStringHandler;
|
||||
RogueLike.ReadInputNumberHandler += RogueLike_ReadInputNumberHandler;
|
||||
RogueLike.ReadInputInGameResponseHandler += RogueLike_ReadInputInGameResponseHandler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 此方法完全自主处理options并输入
|
||||
/// </summary>
|
||||
/// <param name="options"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<InquiryResponse> RogueLike_ReadInputInGameResponseHandler(InquiryOptions options)
|
||||
{
|
||||
InquiryResponse response = new(options);
|
||||
|
||||
switch (options.InquiryType)
|
||||
{
|
||||
case Core.Library.Constant.InquiryType.Choice:
|
||||
case Core.Library.Constant.InquiryType.BinaryChoice:
|
||||
{
|
||||
int index = 0;
|
||||
Dictionary<int, string> indexToChoice = [];
|
||||
foreach (string choice in options.Choices.Keys)
|
||||
{
|
||||
index++;
|
||||
indexToChoice[index] = choice;
|
||||
RogueLike.WriteLine($"{index}. {choice}:{options.Choices[choice]}");
|
||||
}
|
||||
RogueLike.WriteLine($"--- {options.Topic} ---");
|
||||
bool resolve = false;
|
||||
while (!resolve)
|
||||
{
|
||||
RogueLike.WriteLine($"选择一个选项(输入序号,输入 !c 表示取消):");
|
||||
string result = (await Console.In.ReadLineAsync())?.Trim() ?? "";
|
||||
if (result == "!c")
|
||||
{
|
||||
response.Cancel = true;
|
||||
resolve = true;
|
||||
}
|
||||
else if (int.TryParse(result, out int inputIndex) && indexToChoice.TryGetValue(inputIndex, out string? value))
|
||||
{
|
||||
response.Choices = [value];
|
||||
resolve = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Core.Library.Constant.InquiryType.MultipleChoice:
|
||||
{
|
||||
int index = 0;
|
||||
Dictionary<int, string> indexToChoice = [];
|
||||
foreach (string choice in options.Choices.Keys)
|
||||
{
|
||||
index++;
|
||||
indexToChoice[index] = choice;
|
||||
RogueLike.WriteLine($"{index}. {choice}:{options.Choices[choice]}");
|
||||
}
|
||||
RogueLike.WriteLine($"--- {options.Topic} ---");
|
||||
bool resolve = false;
|
||||
while (!resolve)
|
||||
{
|
||||
RogueLike.WriteLine($"选择多个选项(输入序号,空格分隔,包含 !c 时表示取消):");
|
||||
string result = (await Console.In.ReadLineAsync())?.Trim() ?? "";
|
||||
if (result.Contains("!c"))
|
||||
{
|
||||
response.Cancel = true;
|
||||
break;
|
||||
}
|
||||
string[] strings = result.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (string str in strings)
|
||||
{
|
||||
if (int.TryParse(str, out int inputIndex) && indexToChoice.TryGetValue(inputIndex, out string? value))
|
||||
{
|
||||
response.Choices.Add(value);
|
||||
}
|
||||
}
|
||||
if (response.Choices.Count > 0)
|
||||
{
|
||||
resolve = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Core.Library.Constant.InquiryType.TextInput:
|
||||
{
|
||||
RogueLike.WriteLine($"--- {options.Topic} ---");
|
||||
bool resolve = false;
|
||||
while (!resolve)
|
||||
{
|
||||
RogueLike.WriteLine("输入回应(输入 !c 表示取消):");
|
||||
string result = (await Console.In.ReadLineAsync())?.Trim() ?? "";
|
||||
if (result == "!c")
|
||||
{
|
||||
response.Cancel = true;
|
||||
resolve = true;
|
||||
}
|
||||
else if (result != "")
|
||||
{
|
||||
response.TextResult = result;
|
||||
resolve = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Core.Library.Constant.InquiryType.NumberInput:
|
||||
{
|
||||
RogueLike.WriteLine($"--- {options.Topic} ---");
|
||||
bool resolve = false;
|
||||
while (!resolve)
|
||||
{
|
||||
RogueLike.WriteLine("输入结果(输入 !c 表示取消):");
|
||||
string result = await Console.In.ReadLineAsync() ?? "";
|
||||
if (result.Trim() == "!c")
|
||||
{
|
||||
response.Cancel = true;
|
||||
resolve = true;
|
||||
}
|
||||
else if (double.TryParse(result, out double doubleResult))
|
||||
{
|
||||
response.NumberResult = doubleResult;
|
||||
resolve = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Core.Library.Constant.InquiryType.Custom:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private async Task RogueLike_ReadInputStringHandler(Dictionary<string, object> args, List<string> results)
|
||||
{
|
||||
string input = await Console.In.ReadLineAsync() ?? "";
|
||||
if (input.Trim().Equals("!c", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
args["cancel"] = true;
|
||||
}
|
||||
results.Add(input.Trim());
|
||||
}
|
||||
|
||||
private async Task RogueLike_ReadInputNumberHandler(Dictionary<string, object> args, List<double> results)
|
||||
{
|
||||
string input = await Console.In.ReadLineAsync() ?? "";
|
||||
if (input.Trim().Equals("!c", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
args["cancel"] = true;
|
||||
}
|
||||
if (double.TryParse(input.Trim(), out double result))
|
||||
{
|
||||
results.Add(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 仅本地测试原型用,实际使用时需替换为网络层
|
||||
/// </summary>
|
||||
public class RogueLikeDispatcher
|
||||
{
|
||||
public RogueLike? RogueLikeInstance { get; set; } = null;
|
||||
public RogueLikeServer? RogueLikeServer { get; set; } = null;
|
||||
|
||||
public bool Running => RogueLikeInstance?.Running ?? false;
|
||||
|
||||
public void WriteLine(string str)
|
||||
{
|
||||
if (RogueLikeInstance is null) return;
|
||||
RogueLikeInstance.WriteLine(str);
|
||||
}
|
||||
|
||||
public async Task<List<string>> GetChoiceResultsAsync(InquiryOptions options, Dictionary<string, object> args)
|
||||
{
|
||||
if (RogueLikeInstance is null) return [];
|
||||
return await RogueLikeInstance.GetChoiceResultsAsync(options, args);
|
||||
}
|
||||
|
||||
public async Task<List<double>> GetNumberResultsAsync(Dictionary<string, object> args)
|
||||
{
|
||||
if (RogueLikeInstance is null) return [];
|
||||
return await RogueLikeInstance.GetNumberResultsAsync(args);
|
||||
}
|
||||
|
||||
public async Task<string> GetTextResultsAsync(Dictionary<string, object> args)
|
||||
{
|
||||
if (RogueLikeInstance is null) return "";
|
||||
return await RogueLikeInstance.GetTextResultsAsync(args);
|
||||
}
|
||||
|
||||
public async Task<InquiryResponse> GetInGameResponse(InquiryOptions options)
|
||||
{
|
||||
if (RogueLikeInstance is null) return new(options);
|
||||
return await RogueLikeInstance.GetInGameResponse(options);
|
||||
}
|
||||
|
||||
public async Task DataRequestComplete(Guid guid, DataRequestArgs response)
|
||||
{
|
||||
if (RogueLikeInstance is null) return;
|
||||
await RogueLikeInstance.DataRequestComplete(guid, response);
|
||||
}
|
||||
|
||||
public async Task DataRequest(Guid guid, DataRequestArgs args)
|
||||
{
|
||||
if (RogueLikeServer is null) return;
|
||||
RogueLikeServer.ReceiveDataRequest(guid, args);
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void StartServer()
|
||||
{
|
||||
RogueLikeServer?.Guard ??= Task.Run(RogueLikeServer.DataRequestGuard);
|
||||
}
|
||||
|
||||
public async Task CreateGameLoop(string username)
|
||||
{
|
||||
if (RogueLikeServer is null) return;
|
||||
await RogueLikeServer.CreateGameLoop(username);
|
||||
}
|
||||
}
|
||||
|
||||
public class RogueLikeGameData(Character character)
|
||||
{
|
||||
public RogueState RogueState { get; set; } = RogueState.Init;
|
||||
public Character Character { get; set; } = character;
|
||||
public int Chapter { get; set; } = 1;
|
||||
public OshimaRegion? CurrentRegion { get; set; } = null;
|
||||
public string CurrentArea { get; set; } = "";
|
||||
public int RoomId { get; set; } = -1;
|
||||
public OshimaRegion? Chapter1Region { get; set; } = null;
|
||||
public OshimaRegion? Chapter2Region { get; set; } = null;
|
||||
public OshimaRegion? Chapter3Region { get; set; } = null;
|
||||
}
|
||||
|
||||
public class DataRequestArgs(string type)
|
||||
{
|
||||
public string RequestType { get; } = type;
|
||||
public bool Success { get; set; } = true;
|
||||
public Dictionary<string, object> Data { get; set; } = [];
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user