mirror of
https://github.com/project-redbud/FunGame-Core.git
synced 2025-12-05 08:09:02 +00:00
Compare commits
63 Commits
1.0.0-rc.1
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| dcb1ffc23b | |||
|
|
080d546a97 | ||
| 774e26240b | |||
| 6ebeb53674 | |||
| c91829313d | |||
| ef3738d07e | |||
| ad4a9a4346 | |||
|
|
2c39f46dd9 | ||
| 09eea71cb6 | |||
| 030ef179e8 | |||
| 67f357a1cb | |||
| 607d36e23a | |||
| fab341d001 | |||
| 46620aefd7 | |||
| 13a6adb41b | |||
| ccf09b478e | |||
| 29bf7e4c3d | |||
| e1cc31110b | |||
| 9693accdd1 | |||
| d0f6cb6c2e | |||
|
|
32f8dfa43d | ||
| 9c792ed781 | |||
| f55fda4c86 | |||
| a181fb653c | |||
| bc2f180106 | |||
| 482f281d36 | |||
| 00429c2de0 | |||
| 742936e260 | |||
| b1bfcc5577 | |||
| 79801ee594 | |||
| 42abf38b27 | |||
| a3d3dc7df1 | |||
| bda1124af1 | |||
| 86066ba0f0 | |||
| 72d29cff5f | |||
| 8b3d4aa0d7 | |||
| d4aa6adf97 | |||
| 160c691780 | |||
| b59291be3f | |||
| c4ea6a7c90 | |||
| d163e00730 | |||
| 9f020247bb | |||
| 425b46ac02 | |||
| 236c12a5f4 | |||
| 2ed01700ef | |||
| 155b846aa5 | |||
| 9b1a62c6bf | |||
| b5a12ad18d | |||
| 0a1bb0b2a5 | |||
| 88d6d9a8c9 | |||
| 7f2b6466e2 | |||
| ed222e3e1b | |||
| 496f5d0675 | |||
|
|
6bf3bb09a9 | ||
|
|
a2fcbce157 | ||
| 17914f1128 | |||
| 984a7fd5a1 | |||
|
|
5445ea141b | ||
|
|
914f6c6b4a | ||
|
|
aebd64e6e3 | ||
| 82538b9d93 | |||
| cb44cb5672 | |||
|
|
f8f7df94b7 |
4
.github/workflows/dotnet.yml
vendored
4
.github/workflows/dotnet.yml
vendored
@ -21,7 +21,7 @@ jobs:
|
|||||||
- name: Setup .NET
|
- name: Setup .NET
|
||||||
uses: actions/setup-dotnet@v4
|
uses: actions/setup-dotnet@v4
|
||||||
with:
|
with:
|
||||||
dotnet-version: 9.0.x
|
dotnet-version: 10.0.x
|
||||||
- name: Restore dependencies
|
- name: Restore dependencies
|
||||||
run: dotnet restore
|
run: dotnet restore
|
||||||
- name: Build
|
- name: Build
|
||||||
@ -31,7 +31,7 @@ jobs:
|
|||||||
- name: Prepare files for latest branch
|
- name: Prepare files for latest branch
|
||||||
run: |
|
run: |
|
||||||
mkdir -p latest
|
mkdir -p latest
|
||||||
cp -r ./bin/Release/net9.0/FunGame.Core.dll ./bin/Release/net9.0/FunGame.Core.xml ./bin/Release/net9.0/FunGame.Core.deps.json ./latest/
|
cp -r ./bin/Release/net10.0/FunGame.Core.dll ./bin/Release/net10.0/FunGame.Core.xml ./bin/Release/net10.0/FunGame.Core.deps.json ./latest/
|
||||||
- name: Commit and push to latest
|
- name: Commit and push to latest
|
||||||
if: success()
|
if: success()
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@ -59,6 +59,10 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
if (runtime == FunGameInfo.FunGame.FunGame_Desktop)
|
if (runtime == FunGameInfo.FunGame.FunGame_Desktop)
|
||||||
{
|
{
|
||||||
AddonManager.LoadGameMaps(loader.Maps, otherobjs);
|
AddonManager.LoadGameMaps(loader.Maps, otherobjs);
|
||||||
|
foreach (GameMap map in loader.Maps.Values.ToList())
|
||||||
|
{
|
||||||
|
map.AfterLoad(loader, otherobjs);
|
||||||
|
}
|
||||||
AddonManager.LoadGameModules(loader.Modules, loader.Characters, loader.Skills, loader.Items, delegates, otherobjs);
|
AddonManager.LoadGameModules(loader.Modules, loader.Characters, loader.Skills, loader.Items, delegates, otherobjs);
|
||||||
foreach (GameModule module in loader.Modules.Values.ToList())
|
foreach (GameModule module in loader.Modules.Values.ToList())
|
||||||
{
|
{
|
||||||
@ -71,6 +75,10 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
else if (runtime == FunGameInfo.FunGame.FunGame_Server)
|
else if (runtime == FunGameInfo.FunGame.FunGame_Server)
|
||||||
{
|
{
|
||||||
AddonManager.LoadGameMaps(loader.Maps, otherobjs);
|
AddonManager.LoadGameMaps(loader.Maps, otherobjs);
|
||||||
|
foreach (GameMap map in loader.Maps.Values.ToList())
|
||||||
|
{
|
||||||
|
map.AfterLoad(loader, otherobjs);
|
||||||
|
}
|
||||||
AddonManager.LoadGameModulesForServer(loader.ModuleServers, loader.Characters, loader.Skills, loader.Items, delegates, otherobjs);
|
AddonManager.LoadGameModulesForServer(loader.ModuleServers, loader.Characters, loader.Skills, loader.Items, delegates, otherobjs);
|
||||||
foreach (GameModuleServer server in loader.ModuleServers.Values.ToList())
|
foreach (GameModuleServer server in loader.ModuleServers.Values.ToList())
|
||||||
{
|
{
|
||||||
|
|||||||
@ -780,7 +780,9 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static double Round(double value, int digits)
|
public static double Round(double value, int digits)
|
||||||
{
|
{
|
||||||
return Math.Round(value, digits, MidpointRounding.AwayFromZero);
|
value = Math.Round(value, digits, MidpointRounding.AwayFromZero);
|
||||||
|
if (IsApproximatelyZero(value)) value = 0;
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
17
Api/Utility/LINQExtension.cs
Normal file
17
Api/Utility/LINQExtension.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace Milimoe.FunGame.Core.Api.Utility
|
||||||
|
{
|
||||||
|
public static class LINQExtension
|
||||||
|
{
|
||||||
|
public static IEnumerable<T> GetPage<T>(this IEnumerable<T> list, int showPage, int pageSize)
|
||||||
|
{
|
||||||
|
return [.. list.Skip((showPage - 1) * pageSize).Take(pageSize)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int MaxPage<T>(this IEnumerable<T> list, int pageSize)
|
||||||
|
{
|
||||||
|
if (pageSize <= 0) pageSize = 1;
|
||||||
|
int page = (int)Math.Ceiling((double)list.Count() / pageSize);
|
||||||
|
return page > 0 ? page : 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -110,7 +110,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 确保目录存在
|
// 确保目录存在
|
||||||
ExistsDirectoryAndCreate(novelName);
|
DirectoryExistsAndCreate(novelName);
|
||||||
|
|
||||||
// 复制文件内容
|
// 复制文件内容
|
||||||
string json = File.ReadAllText(path, General.DefaultEncoding);
|
string json = File.ReadAllText(path, General.DefaultEncoding);
|
||||||
@ -276,7 +276,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="novelName"></param>
|
/// <param name="novelName"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static bool ExistsDirectory(string novelName)
|
public static bool DirectoryExists(string novelName)
|
||||||
{
|
{
|
||||||
string dpath = $@"{AppDomain.CurrentDomain.BaseDirectory}{RootPath}/{novelName}";
|
string dpath = $@"{AppDomain.CurrentDomain.BaseDirectory}{RootPath}/{novelName}";
|
||||||
return Directory.Exists(dpath);
|
return Directory.Exists(dpath);
|
||||||
@ -287,7 +287,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="novelName"></param>
|
/// <param name="novelName"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static bool ExistsDirectoryAndCreate(string novelName)
|
public static bool DirectoryExistsAndCreate(string novelName)
|
||||||
{
|
{
|
||||||
string dpath = $@"{AppDomain.CurrentDomain.BaseDirectory}{RootPath}/{novelName}";
|
string dpath = $@"{AppDomain.CurrentDomain.BaseDirectory}{RootPath}/{novelName}";
|
||||||
bool result = Directory.Exists(dpath);
|
bool result = Directory.Exists(dpath);
|
||||||
@ -304,7 +304,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
/// <param name="novelName"></param>
|
/// <param name="novelName"></param>
|
||||||
/// <param name="fileName"></param>
|
/// <param name="fileName"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static bool ExistsFile(string novelName, string fileName)
|
public static bool FileExists(string novelName, string fileName)
|
||||||
{
|
{
|
||||||
string dpath = $@"{AppDomain.CurrentDomain.BaseDirectory}{RootPath}/{novelName}";
|
string dpath = $@"{AppDomain.CurrentDomain.BaseDirectory}{RootPath}/{novelName}";
|
||||||
string fpath = $@"{dpath}/{fileName}.json";
|
string fpath = $@"{dpath}/{fileName}.json";
|
||||||
|
|||||||
@ -85,6 +85,18 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
{
|
{
|
||||||
if (TryGetValue(key, out object? value) && value != null)
|
if (TryGetValue(key, out object? value) && value != null)
|
||||||
{
|
{
|
||||||
|
if (value is T typeValue)
|
||||||
|
{
|
||||||
|
return typeValue;
|
||||||
|
}
|
||||||
|
if (value is List<object> listValue)
|
||||||
|
{
|
||||||
|
return NetworkUtility.JsonDeserialize<T>(NetworkUtility.JsonSerialize(listValue));
|
||||||
|
}
|
||||||
|
if (value is Dictionary<object, object> dictValue)
|
||||||
|
{
|
||||||
|
return NetworkUtility.JsonDeserialize<T>(NetworkUtility.JsonSerialize(dictValue));
|
||||||
|
}
|
||||||
return NetworkUtility.JsonDeserialize<T>(value.ToString() ?? "");
|
return NetworkUtility.JsonDeserialize<T>(value.ToString() ?? "");
|
||||||
}
|
}
|
||||||
return default;
|
return default;
|
||||||
@ -186,10 +198,10 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Json数组反序列化的方法。不支持<see cref="object"/>数组。
|
/// JSON 数组反序列化的方法,支持特定类型数组和混合类型数组(包括嵌套对象和数组)。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key"></param>
|
/// <param name="key">字典的键</param>
|
||||||
/// <param name="obj"></param>
|
/// <param name="obj">JSON 数组的枚举器</param>
|
||||||
private void AddValues(string key, JsonElement.ArrayEnumerator obj)
|
private void AddValues(string key, JsonElement.ArrayEnumerator obj)
|
||||||
{
|
{
|
||||||
List<long> longList = [];
|
List<long> longList = [];
|
||||||
@ -197,34 +209,162 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
List<decimal> decList = [];
|
List<decimal> decList = [];
|
||||||
List<string> strList = [];
|
List<string> strList = [];
|
||||||
List<bool> bolList = [];
|
List<bool> bolList = [];
|
||||||
foreach (JsonElement array_e in obj)
|
List<object> resultList = [];
|
||||||
|
// 标记是否为混合类型
|
||||||
|
bool isMixed = false;
|
||||||
|
// 记录第一个非 null 元素的类型
|
||||||
|
JsonValueKind? firstValueKind = null;
|
||||||
|
|
||||||
|
foreach (JsonElement arrayElement in obj)
|
||||||
{
|
{
|
||||||
if (array_e.ValueKind == JsonValueKind.Number && array_e.TryGetInt64(out long longValue))
|
switch (arrayElement.ValueKind)
|
||||||
{
|
{
|
||||||
longList.Add(longValue);
|
case JsonValueKind.Number when arrayElement.TryGetInt64(out long longValue):
|
||||||
}
|
longList.Add(longValue);
|
||||||
else if (array_e.ValueKind == JsonValueKind.Number && array_e.TryGetDouble(out double douValue))
|
resultList.Add(longValue);
|
||||||
{
|
firstValueKind ??= JsonValueKind.Number;
|
||||||
douList.Add(douValue);
|
if (firstValueKind != JsonValueKind.Number) isMixed = true;
|
||||||
}
|
break;
|
||||||
else if (array_e.ValueKind == JsonValueKind.Number && array_e.TryGetDecimal(out decimal decValue))
|
|
||||||
{
|
case JsonValueKind.Number when arrayElement.TryGetDouble(out double doubleValue):
|
||||||
decList.Add(decValue);
|
douList.Add(doubleValue);
|
||||||
}
|
resultList.Add(doubleValue);
|
||||||
else if (array_e.ValueKind == JsonValueKind.String)
|
firstValueKind ??= JsonValueKind.Number;
|
||||||
{
|
if (firstValueKind != JsonValueKind.Number) isMixed = true;
|
||||||
strList.Add(array_e.GetString() ?? "");
|
break;
|
||||||
}
|
|
||||||
else if (array_e.ValueKind == JsonValueKind.True || array_e.ValueKind == JsonValueKind.False)
|
case JsonValueKind.Number when arrayElement.TryGetDecimal(out decimal decimalValue):
|
||||||
{
|
decList.Add(decimalValue);
|
||||||
bolList.Add(array_e.GetBoolean());
|
resultList.Add(decimalValue);
|
||||||
|
firstValueKind ??= JsonValueKind.Number;
|
||||||
|
if (firstValueKind != JsonValueKind.Number) isMixed = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JsonValueKind.String:
|
||||||
|
string strValue = arrayElement.GetString() ?? "";
|
||||||
|
strList.Add(strValue);
|
||||||
|
resultList.Add(strValue);
|
||||||
|
firstValueKind ??= JsonValueKind.String;
|
||||||
|
if (firstValueKind != JsonValueKind.String) isMixed = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JsonValueKind.True:
|
||||||
|
case JsonValueKind.False:
|
||||||
|
bool boolValue = arrayElement.GetBoolean();
|
||||||
|
bolList.Add(boolValue);
|
||||||
|
resultList.Add(boolValue);
|
||||||
|
firstValueKind ??= arrayElement.ValueKind;
|
||||||
|
if (firstValueKind != arrayElement.ValueKind) isMixed = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JsonValueKind.Null:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JsonValueKind.Object:
|
||||||
|
Dictionary<string, object> objValue = ParseObject(arrayElement);
|
||||||
|
resultList.Add(objValue);
|
||||||
|
isMixed = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JsonValueKind.Array:
|
||||||
|
List<object> arrayValue = ParseArray(arrayElement);
|
||||||
|
resultList.Add(arrayValue);
|
||||||
|
isMixed = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
isMixed = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (longList.Count > 0) base.Add(key, longList);
|
|
||||||
if (douList.Count > 0) base.Add(key, douList);
|
// 根据类型一致性选择存储的列表
|
||||||
if (decList.Count > 0) base.Add(key, decList);
|
if (resultList.Count > 0)
|
||||||
if (strList.Count > 0) base.Add(key, strList);
|
{
|
||||||
if (bolList.Count > 0) base.Add(key, bolList);
|
if (!isMixed)
|
||||||
|
{
|
||||||
|
// 所有元素类型一致,存储到对应的特定类型列表
|
||||||
|
switch (firstValueKind)
|
||||||
|
{
|
||||||
|
case JsonValueKind.Number when longList.Count == resultList.Count:
|
||||||
|
base.Add(key, longList);
|
||||||
|
break;
|
||||||
|
case JsonValueKind.Number when douList.Count == resultList.Count:
|
||||||
|
base.Add(key, douList);
|
||||||
|
break;
|
||||||
|
case JsonValueKind.Number when decList.Count == resultList.Count:
|
||||||
|
base.Add(key, decList);
|
||||||
|
break;
|
||||||
|
case JsonValueKind.String:
|
||||||
|
base.Add(key, strList);
|
||||||
|
break;
|
||||||
|
case JsonValueKind.True:
|
||||||
|
case JsonValueKind.False:
|
||||||
|
base.Add(key, bolList);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
base.Add(key, resultList); // 包含 null 或未知情况
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 混合类型或包含对象/数组,存储为 List<object>
|
||||||
|
base.Add(key, resultList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 递归解析 JSON 对象
|
||||||
|
/// </summary>
|
||||||
|
private Dictionary<string, object> ParseObject(JsonElement element)
|
||||||
|
{
|
||||||
|
Dictionary<string, object> dict = [];
|
||||||
|
foreach (JsonProperty property in element.EnumerateObject())
|
||||||
|
{
|
||||||
|
object? value = property.Value.ValueKind switch
|
||||||
|
{
|
||||||
|
JsonValueKind.Number when property.Value.TryGetInt64(out long longValue) => longValue,
|
||||||
|
JsonValueKind.Number when property.Value.TryGetDouble(out double doubleValue) => doubleValue,
|
||||||
|
JsonValueKind.Number when property.Value.TryGetDecimal(out decimal decimalValue) => decimalValue,
|
||||||
|
JsonValueKind.String => property.Value.GetString() ?? "",
|
||||||
|
JsonValueKind.True => true,
|
||||||
|
JsonValueKind.False => false,
|
||||||
|
JsonValueKind.Null => null,
|
||||||
|
JsonValueKind.Object => ParseObject(property.Value),
|
||||||
|
JsonValueKind.Array => ParseArray(property.Value),
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
if (value != null) dict.Add(property.Name, value);
|
||||||
|
}
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 递归解析 JSON 数组
|
||||||
|
/// </summary>
|
||||||
|
private List<object> ParseArray(JsonElement element)
|
||||||
|
{
|
||||||
|
List<object> list = [];
|
||||||
|
foreach (JsonElement arrayElement in element.EnumerateArray())
|
||||||
|
{
|
||||||
|
object? value = arrayElement.ValueKind switch
|
||||||
|
{
|
||||||
|
JsonValueKind.Number when arrayElement.TryGetInt64(out long longValue) => longValue,
|
||||||
|
JsonValueKind.Number when arrayElement.TryGetDouble(out double doubleValue) => doubleValue,
|
||||||
|
JsonValueKind.Number when arrayElement.TryGetDecimal(out decimal decimalValue) => decimalValue,
|
||||||
|
JsonValueKind.String => arrayElement.GetString() ?? "",
|
||||||
|
JsonValueKind.True => true,
|
||||||
|
JsonValueKind.False => false,
|
||||||
|
JsonValueKind.Null => null,
|
||||||
|
JsonValueKind.Object => ParseObject(arrayElement),
|
||||||
|
JsonValueKind.Array => ParseArray(arrayElement),
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
if (value != null) list.Add(value);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,7 +15,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="single">单例对象</param>
|
/// <param name="single">单例对象</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static bool IsExist(object single)
|
public static bool Exists(object single)
|
||||||
{
|
{
|
||||||
Type type = single.GetType();
|
Type type = single.GetType();
|
||||||
string name = type.FullName ?? type.ToString();
|
string name = type.FullName ?? type.ToString();
|
||||||
|
|||||||
@ -35,17 +35,16 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
/// <param name="name"></param>
|
/// <param name="name"></param>
|
||||||
/// <param name="timeOfDay"></param>
|
/// <param name="timeOfDay"></param>
|
||||||
/// <param name="action"></param>
|
/// <param name="action"></param>
|
||||||
public void AddTask(string name, TimeSpan timeOfDay, Action action)
|
/// <param name="error"></param>
|
||||||
|
public void AddTask(string name, TimeSpan timeOfDay, Action action, Action<Exception>? error = null)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
using Lock.Scope scope = _lock.EnterScope();
|
||||||
|
ScheduledTask task = new(name, timeOfDay, action, error);
|
||||||
|
if (DateTime.Now > DateTime.Today.Add(timeOfDay))
|
||||||
{
|
{
|
||||||
ScheduledTask task = new(name, timeOfDay, action);
|
task.LastRun = DateTime.Today.Add(timeOfDay);
|
||||||
if (DateTime.Now > DateTime.Today.Add(timeOfDay))
|
|
||||||
{
|
|
||||||
task.LastRun = DateTime.Today.Add(timeOfDay);
|
|
||||||
}
|
|
||||||
_tasks.Add(task);
|
|
||||||
}
|
}
|
||||||
|
_tasks.Add(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -55,19 +54,18 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
/// <param name="interval"></param>
|
/// <param name="interval"></param>
|
||||||
/// <param name="action"></param>
|
/// <param name="action"></param>
|
||||||
/// <param name="startNow"></param>
|
/// <param name="startNow"></param>
|
||||||
public void AddRecurringTask(string name, TimeSpan interval, Action action, bool startNow = false)
|
/// <param name="error"></param>
|
||||||
|
public void AddRecurringTask(string name, TimeSpan interval, Action action, bool startNow = false, Action<Exception>? error = null)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
using Lock.Scope scope = _lock.EnterScope();
|
||||||
|
DateTime now = DateTime.Now;
|
||||||
|
now = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0);
|
||||||
|
DateTime nextRun = startNow ? now : now.Add(interval);
|
||||||
|
RecurringTask recurringTask = new(name, interval, action, error)
|
||||||
{
|
{
|
||||||
DateTime now = DateTime.Now;
|
NextRun = nextRun
|
||||||
now = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0);
|
};
|
||||||
DateTime nextRun = startNow ? now : now.Add(interval);
|
_recurringTasks.Add(recurringTask);
|
||||||
RecurringTask recurringTask = new(name, interval, action)
|
|
||||||
{
|
|
||||||
NextRun = nextRun
|
|
||||||
};
|
|
||||||
_recurringTasks.Add(recurringTask);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -76,11 +74,9 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
/// <param name="name"></param>
|
/// <param name="name"></param>
|
||||||
public void RemoveTask(string name)
|
public void RemoveTask(string name)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
using Lock.Scope scope = _lock.EnterScope();
|
||||||
{
|
int removeTasks = _tasks.RemoveAll(t => t.Name == name);
|
||||||
int removeTasks = _tasks.RemoveAll(t => t.Name == name);
|
int removeRecurringTasks = _recurringTasks.RemoveAll(t => t.Name == name);
|
||||||
int removeRecurringTasks = _recurringTasks.RemoveAll(t => t.Name == name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -165,52 +161,54 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void CheckAndRunTasks()
|
private void CheckAndRunTasks()
|
||||||
{
|
{
|
||||||
lock (_lock)
|
using Lock.Scope scope = _lock.EnterScope();
|
||||||
|
DateTime now = DateTime.Now;
|
||||||
|
|
||||||
|
foreach (ScheduledTask task in _tasks)
|
||||||
{
|
{
|
||||||
DateTime now = DateTime.Now;
|
if (!task.IsTodayRun)
|
||||||
|
|
||||||
foreach (ScheduledTask task in _tasks)
|
|
||||||
{
|
{
|
||||||
if (!task.IsTodayRun)
|
if (now.TimeOfDay >= task.TimeOfDay && now.TimeOfDay < task.TimeOfDay.Add(TimeSpan.FromSeconds(10)))
|
||||||
{
|
{
|
||||||
if (now.TimeOfDay >= task.TimeOfDay && now.TimeOfDay < task.TimeOfDay.Add(TimeSpan.FromSeconds(10)))
|
task.LastRun = now;
|
||||||
{
|
|
||||||
task.LastRun = now;
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
task.Action();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
task.Error = ex;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (RecurringTask recurringTask in _recurringTasks)
|
|
||||||
{
|
|
||||||
if (now >= recurringTask.NextRun)
|
|
||||||
{
|
|
||||||
recurringTask.LastRun = now;
|
|
||||||
recurringTask.NextRun = recurringTask.NextRun.Add(recurringTask.Interval);
|
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
recurringTask.Action();
|
task.Action();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
recurringTask.Error = ex;
|
task.Error = ex;
|
||||||
|
TXTHelper.AppendErrorLog(ex.ToString());
|
||||||
|
task.ErrorHandler?.Invoke(ex);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (RecurringTask recurringTask in _recurringTasks)
|
||||||
|
{
|
||||||
|
if (now >= recurringTask.NextRun)
|
||||||
|
{
|
||||||
|
recurringTask.LastRun = now;
|
||||||
|
recurringTask.NextRun = recurringTask.NextRun.Add(recurringTask.Interval);
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
recurringTask.Action();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
recurringTask.Error = ex;
|
||||||
|
TXTHelper.AppendErrorLog(ex.ToString());
|
||||||
|
recurringTask.ErrorHandler?.Invoke(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Milimoe.FunGame.Core.Library.Constant;
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
using Milimoe.FunGame.Core.Library.Exception;
|
||||||
|
|
||||||
namespace Milimoe.FunGame.Core.Api.Utility
|
namespace Milimoe.FunGame.Core.Api.Utility
|
||||||
{
|
{
|
||||||
@ -50,7 +51,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="FileName">文件名,缺省为FunGame.ini</param>
|
/// <param name="FileName">文件名,缺省为FunGame.ini</param>
|
||||||
/// <returns>是否存在</returns>
|
/// <returns>是否存在</returns>
|
||||||
public static bool ExistINIFile(string FileName = DefaultFileName) => File.Exists($@"{AppDomain.CurrentDomain.BaseDirectory}{FileName}");
|
public static bool INIFileExists(string FileName = DefaultFileName) => File.Exists($@"{AppDomain.CurrentDomain.BaseDirectory}{FileName}");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始化ini模板文件
|
/// 初始化ini模板文件
|
||||||
@ -180,7 +181,7 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||||
path = Path.Combine(path, filename);
|
path = Path.Combine(path, filename);
|
||||||
}
|
}
|
||||||
else path = $@"{AppDomain.CurrentDomain.BaseDirectory}{filename}";
|
else path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, filename);
|
||||||
// 写入内容
|
// 写入内容
|
||||||
StreamWriter writer = File.Exists(path) ? new(path, !overwrite, General.DefaultEncoding) : new(path, false, General.DefaultEncoding);
|
StreamWriter writer = File.Exists(path) ? new(path, !overwrite, General.DefaultEncoding) : new(path, false, General.DefaultEncoding);
|
||||||
writer.WriteLine(content);
|
writer.WriteLine(content);
|
||||||
@ -200,5 +201,11 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="msg"></param>
|
/// <param name="msg"></param>
|
||||||
public static void AppendErrorLog(string msg) => WriteTXT(DateTimeUtility.GetDateTimeToString(TimeType.General) + ": " + msg + "\r\n", DateTimeUtility.GetDateTimeToString("yyyy-MM-dd") + ".log", "logs");
|
public static void AppendErrorLog(string msg) => WriteTXT(DateTimeUtility.GetDateTimeToString(TimeType.General) + ": " + msg + "\r\n", DateTimeUtility.GetDateTimeToString("yyyy-MM-dd") + ".log", "logs");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 追加错误日志 默认写入logs文件夹下的当日日期.log文件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e"></param>
|
||||||
|
public static void AppendErrorLog(Exception e) => AppendErrorLog(e.GetErrorInfo());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,6 +52,14 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnWebAPIStarted(params object[] objs)
|
||||||
|
{
|
||||||
|
Parallel.ForEach(Plugins.Values, plugin =>
|
||||||
|
{
|
||||||
|
plugin.OnWebAPIStarted(objs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void OnBeforeConnectEvent(object sender, ConnectEventArgs e)
|
public void OnBeforeConnectEvent(object sender, ConnectEventArgs e)
|
||||||
{
|
{
|
||||||
Parallel.ForEach(Plugins.Values, plugin =>
|
Parallel.ForEach(Plugins.Values, plugin =>
|
||||||
|
|||||||
325
Controller/AIController.cs
Normal file
325
Controller/AIController.cs
Normal file
@ -0,0 +1,325 @@
|
|||||||
|
using Milimoe.FunGame.Core.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Interface.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Library.Common.Addon;
|
||||||
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
using Milimoe.FunGame.Core.Model;
|
||||||
|
|
||||||
|
namespace Milimoe.FunGame.Core.Controller
|
||||||
|
{
|
||||||
|
public class AIController(GamingQueue queue, GameMap map)
|
||||||
|
{
|
||||||
|
private readonly GamingQueue _queue = queue;
|
||||||
|
private readonly GameMap _map = map;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// AI的核心决策方法,根据当前游戏状态为角色选择最佳行动。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character">当前行动的AI角色。</param>
|
||||||
|
/// <param name="startGrid">角色的起始格子。</param>
|
||||||
|
/// <param name="allPossibleMoveGrids">从起始格子可达的所有移动格子(包括起始格子本身)。</param>
|
||||||
|
/// <param name="availableSkills">角色所有可用的技能(已过滤CD和EP/MP)。</param>
|
||||||
|
/// <param name="availableItems">角色所有可用的物品(已过滤CD和EP/MP)。</param>
|
||||||
|
/// <param name="allEnemysInGame">场上所有敌人。</param>
|
||||||
|
/// <param name="allTeammatesInGame">场上所有队友。</param>
|
||||||
|
/// <param name="selectableEnemys">场上能够选取的敌人。</param>
|
||||||
|
/// <param name="selectableTeammates">场上能够选取的队友。</param>
|
||||||
|
/// <returns>包含最佳行动的AIDecision对象。</returns>
|
||||||
|
public async Task<AIDecision> DecideAIActionAsync(Character character, Grid startGrid, List<Grid> allPossibleMoveGrids,
|
||||||
|
List<Skill> availableSkills, List<Item> availableItems, List<Character> allEnemysInGame, List<Character> allTeammatesInGame,
|
||||||
|
List<Character> selectableEnemys, List<Character> selectableTeammates)
|
||||||
|
{
|
||||||
|
// 初始化一个默认的“结束回合”决策作为基准
|
||||||
|
AIDecision bestDecision = new()
|
||||||
|
{
|
||||||
|
ActionType = CharacterActionType.EndTurn,
|
||||||
|
TargetMoveGrid = startGrid,
|
||||||
|
Targets = [],
|
||||||
|
Score = -1000.0
|
||||||
|
};
|
||||||
|
|
||||||
|
// 遍历所有可能的移动目标格子 (包括起始格子本身)
|
||||||
|
foreach (Grid potentialMoveGrid in allPossibleMoveGrids)
|
||||||
|
{
|
||||||
|
// 计算移动到这个格子的代价(曼哈顿距离)
|
||||||
|
int moveDistance = GameMap.CalculateManhattanDistance(startGrid, potentialMoveGrid);
|
||||||
|
double movePenalty = moveDistance * 0.5; // 每移动一步扣0.5分
|
||||||
|
|
||||||
|
if (CanCharacterNormalAttack(character))
|
||||||
|
{
|
||||||
|
// 计算普通攻击的可达格子
|
||||||
|
List<Grid> normalAttackReachableGrids = _map.GetGridsByRange(potentialMoveGrid, character.ATR, true);
|
||||||
|
|
||||||
|
List<Character> normalAttackReachableEnemys = [.. allEnemysInGame
|
||||||
|
.Where(c => normalAttackReachableGrids.SelectMany(g => g.Characters).Contains(c) && !c.IsUnselectable && selectableEnemys.Contains(c))
|
||||||
|
.Distinct()];
|
||||||
|
List<Character> normalAttackReachableTeammates = [.. allTeammatesInGame
|
||||||
|
.Where(c => normalAttackReachableGrids.SelectMany(g => g.Characters).Contains(c) && selectableTeammates.Contains(c))
|
||||||
|
.Distinct()];
|
||||||
|
|
||||||
|
if (normalAttackReachableEnemys.Count > 0)
|
||||||
|
{
|
||||||
|
// 将筛选后的目标列表传递给 SelectTargets
|
||||||
|
List<Character> targets = SelectTargets(character, character.NormalAttack, normalAttackReachableEnemys, normalAttackReachableTeammates);
|
||||||
|
if (targets.Count > 0)
|
||||||
|
{
|
||||||
|
double currentScore = EvaluateNormalAttack(character, targets) - movePenalty;
|
||||||
|
if (currentScore > bestDecision.Score)
|
||||||
|
{
|
||||||
|
bestDecision = new AIDecision
|
||||||
|
{
|
||||||
|
ActionType = CharacterActionType.NormalAttack,
|
||||||
|
TargetMoveGrid = potentialMoveGrid,
|
||||||
|
SkillToUse = character.NormalAttack,
|
||||||
|
Targets = targets,
|
||||||
|
Score = currentScore
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Skill skill in availableSkills)
|
||||||
|
{
|
||||||
|
if (CanCharacterUseSkill(character) && _queue.CheckCanCast(character, skill, out double cost))
|
||||||
|
{
|
||||||
|
// 计算当前技能的可达格子
|
||||||
|
List<Grid> skillReachableGrids = _map.GetGridsByRange(potentialMoveGrid, skill.CastRange, true);
|
||||||
|
|
||||||
|
List<Character> skillReachableEnemys = [.. allEnemysInGame
|
||||||
|
.Where(c => skillReachableGrids.SelectMany(g => g.Characters).Contains(c) && !c.IsUnselectable && selectableEnemys.Contains(c))
|
||||||
|
.Distinct()];
|
||||||
|
List<Character> skillReachableTeammates = [.. allTeammatesInGame
|
||||||
|
.Where(c => skillReachableGrids.SelectMany(g => g.Characters).Contains(c) && selectableTeammates.Contains(c))
|
||||||
|
.Distinct()];
|
||||||
|
|
||||||
|
// 检查是否有可用的目标(敌人或队友,取决于技能类型)
|
||||||
|
if (skillReachableEnemys.Count > 0 || skillReachableTeammates.Count > 0)
|
||||||
|
{
|
||||||
|
// 将筛选后的目标列表传递给 SelectTargets
|
||||||
|
List<Character> targets = SelectTargets(character, skill, skillReachableEnemys, skillReachableTeammates);
|
||||||
|
if (targets.Count > 0)
|
||||||
|
{
|
||||||
|
double currentScore = EvaluateSkill(character, skill, targets, cost) - movePenalty;
|
||||||
|
if (currentScore > bestDecision.Score)
|
||||||
|
{
|
||||||
|
bestDecision = new AIDecision
|
||||||
|
{
|
||||||
|
ActionType = CharacterActionType.PreCastSkill,
|
||||||
|
TargetMoveGrid = potentialMoveGrid,
|
||||||
|
SkillToUse = skill,
|
||||||
|
Targets = targets,
|
||||||
|
Score = currentScore
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Item item in availableItems)
|
||||||
|
{
|
||||||
|
if (item.Skills.Active != null && CanCharacterUseItem(character, item) && _queue.CheckCanCast(character, item.Skills.Active, out double cost))
|
||||||
|
{
|
||||||
|
Skill itemSkill = item.Skills.Active;
|
||||||
|
|
||||||
|
// 计算当前物品技能的可达格子
|
||||||
|
List<Grid> itemSkillReachableGrids = _map.GetGridsByRange(potentialMoveGrid, itemSkill.CastRange, true);
|
||||||
|
|
||||||
|
List<Character> itemSkillReachableEnemys = [.. allEnemysInGame
|
||||||
|
.Where(c => itemSkillReachableGrids.SelectMany(g => g.Characters).Contains(c) && !c.IsUnselectable && selectableEnemys.Contains(c))
|
||||||
|
.Distinct()];
|
||||||
|
List<Character> itemSkillReachableTeammates = [.. allTeammatesInGame
|
||||||
|
.Where(c => itemSkillReachableGrids.SelectMany(g => g.Characters).Contains(c) && selectableTeammates.Contains(c))
|
||||||
|
.Distinct()];
|
||||||
|
|
||||||
|
// 检查是否有可用的目标
|
||||||
|
if (itemSkillReachableEnemys.Count > 0 || itemSkillReachableTeammates.Count > 0)
|
||||||
|
{
|
||||||
|
// 将筛选后的目标列表传递给 SelectTargets
|
||||||
|
List<Character> targetsForItem = SelectTargets(character, itemSkill, itemSkillReachableEnemys, itemSkillReachableTeammates);
|
||||||
|
if (targetsForItem.Count > 0)
|
||||||
|
{
|
||||||
|
double currentScore = EvaluateItem(character, item, targetsForItem, cost) - movePenalty;
|
||||||
|
if (currentScore > bestDecision.Score)
|
||||||
|
{
|
||||||
|
bestDecision = new AIDecision
|
||||||
|
{
|
||||||
|
ActionType = CharacterActionType.UseItem,
|
||||||
|
TargetMoveGrid = potentialMoveGrid,
|
||||||
|
ItemToUse = item,
|
||||||
|
SkillToUse = itemSkill,
|
||||||
|
Targets = targetsForItem,
|
||||||
|
Score = currentScore
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果从该格子没有更好的行动,但移动本身有价值
|
||||||
|
// 只有当当前最佳决策是“结束回合”或分数很低时,才考虑纯粹的移动。
|
||||||
|
if (potentialMoveGrid != startGrid && bestDecision.Score < 0) // 如果当前最佳决策是负分(即什么都不做)
|
||||||
|
{
|
||||||
|
double pureMoveScore = -movePenalty; // 移动本身有代价
|
||||||
|
|
||||||
|
// 为纯粹移动逻辑重新计算综合可达敌人列表
|
||||||
|
List<Grid> tempAttackGridsForPureMove = _map.GetGridsByRange(potentialMoveGrid, character.ATR, true);
|
||||||
|
List<Grid> tempCastGridsForPureMove = [];
|
||||||
|
foreach (Skill skill in availableSkills)
|
||||||
|
{
|
||||||
|
tempCastGridsForPureMove.AddRange(_map.GetGridsByRange(potentialMoveGrid, skill.CastRange, true));
|
||||||
|
}
|
||||||
|
foreach (Item item in availableItems)
|
||||||
|
{
|
||||||
|
if (item.Skills.Active != null)
|
||||||
|
{
|
||||||
|
tempCastGridsForPureMove.AddRange(_map.GetGridsByRange(potentialMoveGrid, item.Skills.Active.CastRange, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<Grid> tempAllReachableGridsForPureMove = [.. tempAttackGridsForPureMove.Union(tempCastGridsForPureMove).Distinct()];
|
||||||
|
List<Character> tempCurrentReachableEnemysForPureMove = [.. allEnemysInGame
|
||||||
|
.Where(c => tempAllReachableGridsForPureMove.SelectMany(g => g.Characters).Contains(c) && !c.IsUnselectable && selectableEnemys.Contains(c))
|
||||||
|
.Distinct()];
|
||||||
|
|
||||||
|
// 如果当前位置无法攻击任何敌人,但地图上还有敌人,尝试向最近的敌人移动
|
||||||
|
if (tempCurrentReachableEnemysForPureMove.Count == 0 && allEnemysInGame.Count > 0) // 使用新计算的列表
|
||||||
|
{
|
||||||
|
Character? target = allEnemysInGame
|
||||||
|
.OrderBy(e => GameMap.CalculateManhattanDistance(potentialMoveGrid, _map.GetCharacterCurrentGrid(e)!))
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
if (target != null)
|
||||||
|
{
|
||||||
|
Grid? nearestEnemyGrid = _map.GetCharacterCurrentGrid(target);
|
||||||
|
if (nearestEnemyGrid != null)
|
||||||
|
{
|
||||||
|
// 奖励靠近敌人
|
||||||
|
pureMoveScore += (10 - GameMap.CalculateManhattanDistance(potentialMoveGrid, nearestEnemyGrid)) * 0.1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果纯粹移动比当前最佳(什么都不做)更好
|
||||||
|
if (pureMoveScore > bestDecision.Score)
|
||||||
|
{
|
||||||
|
bestDecision = new AIDecision
|
||||||
|
{
|
||||||
|
ActionType = CharacterActionType.Move,
|
||||||
|
TargetMoveGrid = potentialMoveGrid,
|
||||||
|
Targets = [],
|
||||||
|
Score = pureMoveScore,
|
||||||
|
IsPureMove = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return await Task.FromResult(bestDecision);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- AI 决策辅助方法 ---
|
||||||
|
|
||||||
|
// 检查角色是否能进行普通攻击(基于状态)
|
||||||
|
private static bool CanCharacterNormalAttack(Character character)
|
||||||
|
{
|
||||||
|
return character.CharacterState != CharacterState.NotActionable &&
|
||||||
|
character.CharacterState != CharacterState.ActionRestricted &&
|
||||||
|
character.CharacterState != CharacterState.BattleRestricted &&
|
||||||
|
character.CharacterState != CharacterState.AttackRestricted;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查角色是否能使用某个技能(基于状态)
|
||||||
|
private static bool CanCharacterUseSkill(Character character)
|
||||||
|
{
|
||||||
|
return character.CharacterState != CharacterState.NotActionable &&
|
||||||
|
character.CharacterState != CharacterState.ActionRestricted &&
|
||||||
|
character.CharacterState != CharacterState.BattleRestricted &&
|
||||||
|
character.CharacterState != CharacterState.SkillRestricted;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查角色是否能使用某个物品(基于状态)
|
||||||
|
private static bool CanCharacterUseItem(Character character, Item item)
|
||||||
|
{
|
||||||
|
return character.CharacterState != CharacterState.NotActionable &&
|
||||||
|
(character.CharacterState != CharacterState.ActionRestricted || item.ItemType == ItemType.Consumable) && // 行动受限只能用消耗品
|
||||||
|
character.CharacterState != CharacterState.BattleRestricted;
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// 选择技能的最佳目标
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character"></param>
|
||||||
|
/// <param name="skill"></param>
|
||||||
|
/// <param name="enemys"></param>
|
||||||
|
/// <param name="teammates"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static List<Character> SelectTargets(Character character, ISkill skill, List<Character> enemys, List<Character> teammates)
|
||||||
|
{
|
||||||
|
List<Character> targets = skill.GetSelectableTargets(character, enemys, teammates);
|
||||||
|
int count = skill.RealCanSelectTargetCount(enemys, teammates);
|
||||||
|
return [.. targets.OrderBy(o => Random.Shared.Next()).Take(count)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 评估普通攻击的价值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character"></param>
|
||||||
|
/// <param name="targets"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static double EvaluateNormalAttack(Character character, List<Character> targets)
|
||||||
|
{
|
||||||
|
double score = 0;
|
||||||
|
foreach (Character target in targets)
|
||||||
|
{
|
||||||
|
double damage = character.NormalAttack.Damage * (1 - target.PDR);
|
||||||
|
score += damage;
|
||||||
|
if (target.HP <= damage) score += 100;
|
||||||
|
}
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 评估技能的价值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character"></param>
|
||||||
|
/// <param name="skill"></param>
|
||||||
|
/// <param name="targets"></param>
|
||||||
|
/// <param name="cost"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static double EvaluateSkill(Character character, Skill skill, List<Character> targets, double cost)
|
||||||
|
{
|
||||||
|
double score = 0;
|
||||||
|
score += targets.Sum(t => CalculateTargetValue(t, skill));
|
||||||
|
//score -= cost * 5;
|
||||||
|
//score -= skill.RealCD * 2;
|
||||||
|
//score -= skill.HardnessTime * 2;
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 评估物品的价值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character"></param>
|
||||||
|
/// <param name="item"></param>
|
||||||
|
/// <param name="targets"></param>
|
||||||
|
/// <param name="cost"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static double EvaluateItem(Character character, Item item, List<Character> targets, double cost)
|
||||||
|
{
|
||||||
|
double score = Random.Shared.Next(1000);
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 辅助函数:计算单个目标在某个技能下的价值
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target"></param>
|
||||||
|
/// <param name="skill"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static double CalculateTargetValue(Character target, ISkill skill)
|
||||||
|
{
|
||||||
|
double value = Random.Shared.Next(1000);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
using Milimoe.FunGame.Core.Interface.Entity;
|
using System.Text.Json.Serialization;
|
||||||
|
using Milimoe.FunGame.Core.Interface.Entity;
|
||||||
using Milimoe.FunGame.Core.Library.Constant;
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
using Milimoe.FunGame.Core.Model;
|
using Milimoe.FunGame.Core.Model;
|
||||||
|
|
||||||
@ -29,6 +30,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 实体所用的游戏平衡常数
|
/// 实体所用的游戏平衡常数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
public EquilibriumConstant GameplayEquilibriumConstant { get; set; } = General.GameplayEquilibriumConstant;
|
public EquilibriumConstant GameplayEquilibriumConstant { get; set; } = General.GameplayEquilibriumConstant;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -77,28 +77,28 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// 获取对 <paramref name="enemy"/> 造成伤害的最后时间
|
/// 获取对 <paramref name="enemy"/> 造成伤害的最后时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="enemy"></param>
|
/// <param name="enemy"></param>
|
||||||
/// <returns>-1 意味着没有时间</returns>
|
/// <returns><see cref="double.MinValue"/> 意味着没有时间</returns>
|
||||||
public double GetLastTime(Character enemy)
|
public double GetLastTime(Character enemy)
|
||||||
{
|
{
|
||||||
if (DamageLastTime.TryGetValue(enemy, out double time))
|
if (DamageLastTime.TryGetValue(enemy, out double time))
|
||||||
{
|
{
|
||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
return -1;
|
return double.MinValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取对某角色友方非伤害辅助的最后时间
|
/// 获取对某角色友方非伤害辅助的最后时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="character"></param>
|
/// <param name="character"></param>
|
||||||
/// <returns>-1 意味着没有时间</returns>
|
/// <returns><see cref="double.MinValue"/> 意味着没有时间</returns>
|
||||||
public double GetNotDamageAssistLastTime(Character character)
|
public double GetNotDamageAssistLastTime(Character character)
|
||||||
{
|
{
|
||||||
if (NotDamageAssistLastTime.TryGetValue(character, out double time))
|
if (NotDamageAssistLastTime.TryGetValue(character, out double time))
|
||||||
{
|
{
|
||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
return -1;
|
return double.MinValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -129,9 +129,13 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
int past = _Level;
|
||||||
_Level = Math.Min(Math.Max(1, value), GameplayEquilibriumConstant.MaxLevel);
|
_Level = Math.Min(Math.Max(1, value), GameplayEquilibriumConstant.MaxLevel);
|
||||||
OnAttributeChanged();
|
if (past != _Level)
|
||||||
Recovery();
|
{
|
||||||
|
OnAttributeChanged();
|
||||||
|
Recovery();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +219,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 最大生命值 = 基础生命值 + 额外生命值 + 额外生命值2 + 额外生命值3
|
/// 最大生命值 = 基础生命值 + 额外生命值 + 额外生命值2 + 额外生命值3
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double MaxHP => BaseHP + ExHP + ExHP2 + ExHP3;
|
public double MaxHP => Math.Max(1, BaseHP + ExHP + ExHP2 + ExHP3);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当前生命值 [ 战斗相关 ]
|
/// 当前生命值 [ 战斗相关 ]
|
||||||
@ -234,6 +238,12 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否有魔法值 [ 初始设定 ]
|
||||||
|
/// </summary>
|
||||||
|
[InitRequired]
|
||||||
|
public bool HasMP { get; set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始魔法值 [ 初始设定 ]
|
/// 初始魔法值 [ 初始设定 ]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -268,7 +278,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 最大魔法值 = 基础魔法值 + 额外魔法值 + 额外魔法值2 + 额外魔法值3
|
/// 最大魔法值 = 基础魔法值 + 额外魔法值 + 额外魔法值2 + 额外魔法值3
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double MaxMP => BaseMP + ExMP + ExMP2 + ExMP3;
|
public double MaxMP => Math.Max(1, BaseMP + ExMP + ExMP2 + ExMP3);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当前魔法值 [ 战斗相关 ]
|
/// 当前魔法值 [ 战斗相关 ]
|
||||||
@ -662,16 +672,19 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 力量成长值(+BaseSTR/Lv)
|
/// 力量成长值(+BaseSTR/Lv)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[InitOptional]
|
||||||
public double STRGrowth { get; set; } = 0;
|
public double STRGrowth { get; set; } = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 敏捷成长值(+BaseAGI/Lv)
|
/// 敏捷成长值(+BaseAGI/Lv)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[InitOptional]
|
||||||
public double AGIGrowth { get; set; } = 0;
|
public double AGIGrowth { get; set; } = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 智力成长值(+BaseINT/Lv)
|
/// 智力成长值(+BaseINT/Lv)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[InitOptional]
|
||||||
public double INTGrowth { get; set; } = 0;
|
public double INTGrowth { get; set; } = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -683,7 +696,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 行动速度 = [ 与初始设定相关 ][ 与敏捷相关 ] + 额外行动速度
|
/// 行动速度 = [ 与初始设定相关 ][ 与敏捷相关 ] + 额外行动速度
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double SPD => InitialSPD + AGI * GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD;
|
public double SPD => Math.Max(0, InitialSPD + AGI * GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 额外行动速度 [ 与技能和物品相关 ]
|
/// 额外行动速度 [ 与技能和物品相关 ]
|
||||||
@ -715,7 +728,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
double value = INT * GameplayEquilibriumConstant.INTtoAccelerationCoefficientMultiplier + ExAccelerationCoefficient;
|
double value = INT * GameplayEquilibriumConstant.INTtoAccelerationCoefficientMultiplier + ExAccelerationCoefficient;
|
||||||
return Calculation.PercentageCheck(value);
|
return Math.Min(1, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -732,7 +745,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
double value = INT * GameplayEquilibriumConstant.INTtoCDRMultiplier + ExCDR;
|
double value = INT * GameplayEquilibriumConstant.INTtoCDRMultiplier + ExCDR;
|
||||||
return Calculation.PercentageCheck(value);
|
return Math.Min(1, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -742,10 +755,68 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
public double ExCDR { get; set; } = 0;
|
public double ExCDR { get; set; } = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 攻击距离 [ 与技能和物品相关 ] [ 单位:格 ]
|
/// 攻击距离 [ 与武器相关 ] [ 单位:格(半径) ]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[InitOptional]
|
public int ATR
|
||||||
public double ATR { get; set; } = 1;
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
int baseATR = 1;
|
||||||
|
if (EquipSlot.Weapon != null)
|
||||||
|
{
|
||||||
|
baseATR = EquipSlot.Weapon.WeaponType switch
|
||||||
|
{
|
||||||
|
WeaponType.OneHandedSword => GameplayEquilibriumConstant.OneHandedSwordAttackRange,
|
||||||
|
WeaponType.TwoHandedSword => GameplayEquilibriumConstant.TwoHandedSwordAttackRange,
|
||||||
|
WeaponType.Bow => GameplayEquilibriumConstant.BowAttackRange,
|
||||||
|
WeaponType.Pistol => GameplayEquilibriumConstant.PistolAttackRange,
|
||||||
|
WeaponType.Rifle => GameplayEquilibriumConstant.RifleAttackRange,
|
||||||
|
WeaponType.DualDaggers => GameplayEquilibriumConstant.DualDaggersAttackRange,
|
||||||
|
WeaponType.Talisman => GameplayEquilibriumConstant.TalismanAttackRange,
|
||||||
|
WeaponType.Staff => GameplayEquilibriumConstant.StaffAttackRange,
|
||||||
|
WeaponType.Polearm => GameplayEquilibriumConstant.PolearmAttackRange,
|
||||||
|
WeaponType.Gauntlet => GameplayEquilibriumConstant.GauntletAttackRange,
|
||||||
|
WeaponType.HiddenWeapon => GameplayEquilibriumConstant.HiddenWeaponAttackRange,
|
||||||
|
_ => baseATR
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return Math.Max(1, baseATR + ExATR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 额外攻击距离 [ 与技能和物品相关 ] [ 单位:格(半径) ]
|
||||||
|
/// </summary>
|
||||||
|
public int ExATR { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 行动力/可移动距离 [ 与第一定位相关 ] [ 单位:格(半径) ]
|
||||||
|
/// </summary>
|
||||||
|
public int MOV
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
int baseMOV = 3;
|
||||||
|
if (EquipSlot.Weapon != null)
|
||||||
|
{
|
||||||
|
baseMOV = FirstRoleType switch
|
||||||
|
{
|
||||||
|
RoleType.Core => GameplayEquilibriumConstant.RoleMOV_Core,
|
||||||
|
RoleType.Vanguard => GameplayEquilibriumConstant.RoleMOV_Vanguard,
|
||||||
|
RoleType.Guardian => GameplayEquilibriumConstant.RoleMOV_Guardian,
|
||||||
|
RoleType.Support => GameplayEquilibriumConstant.RoleMOV_Support,
|
||||||
|
RoleType.Medic => GameplayEquilibriumConstant.RoleMOV_Medic,
|
||||||
|
_ => baseMOV
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return Math.Max(1, baseMOV + ExMOV);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 行动力/可移动距离 [ 与技能和物品相关 ] [ 单位:格(半径) ]
|
||||||
|
/// </summary>
|
||||||
|
public int ExMOV { get; set; } = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 暴击率(%) = [ 与敏捷相关 ] + 额外暴击率(%)
|
/// 暴击率(%) = [ 与敏捷相关 ] + 额外暴击率(%)
|
||||||
@ -900,8 +971,8 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
{
|
{
|
||||||
if (time > 0)
|
if (time > 0)
|
||||||
{
|
{
|
||||||
HP = Math.Min(MaxHP, HP + HR * time);
|
HP += HR * time;
|
||||||
MP = Math.Min(MaxMP, MP + MR * time);
|
MP += MR * time;
|
||||||
if (EP != -1) this.EP = EP;
|
if (EP != -1) this.EP = EP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -915,10 +986,16 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <param name="pastMaxMP"></param>
|
/// <param name="pastMaxMP"></param>
|
||||||
public void Recovery(double pastHP, double pastMP, double pastMaxHP, double pastMaxMP)
|
public void Recovery(double pastHP, double pastMP, double pastMaxHP, double pastMaxMP)
|
||||||
{
|
{
|
||||||
double pHP = pastHP / pastMaxHP;
|
if (pastHP > 0 && pastMaxHP > 0)
|
||||||
double pMP = pastMP / pastMaxMP;
|
{
|
||||||
HP = MaxHP * pHP;
|
double pHP = pastHP / pastMaxHP;
|
||||||
MP = MaxMP * pMP;
|
HP = MaxHP * pHP;
|
||||||
|
}
|
||||||
|
if (pastMP > 0 && pastMaxMP > 0)
|
||||||
|
{
|
||||||
|
double pMP = pastMP / pastMaxMP;
|
||||||
|
MP = MaxMP * pMP;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -1147,6 +1224,32 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置角色等级,并默认完全回复状态
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="level">新的等级</param>
|
||||||
|
/// <param name="recovery">false 为按百分比回复</param>
|
||||||
|
public void SetLevel(int level, bool recovery = true)
|
||||||
|
{
|
||||||
|
if (!recovery)
|
||||||
|
{
|
||||||
|
double pastHP = HP;
|
||||||
|
double pastMP = MP;
|
||||||
|
double pastMaxHP = MaxHP;
|
||||||
|
double pastMaxMP = MaxMP;
|
||||||
|
int pastLevel = Level;
|
||||||
|
Level = level;
|
||||||
|
if (pastLevel != Level)
|
||||||
|
{
|
||||||
|
Recovery(pastHP, pastMP, pastMaxHP, pastMaxMP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Level = level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 角色升级
|
/// 角色升级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -1154,6 +1257,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <param name="checkLevelBreak"></param>
|
/// <param name="checkLevelBreak"></param>
|
||||||
public void OnLevelUp(int level = 0, bool checkLevelBreak = true)
|
public void OnLevelUp(int level = 0, bool checkLevelBreak = true)
|
||||||
{
|
{
|
||||||
|
bool isUp = false;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
@ -1177,6 +1281,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
{
|
{
|
||||||
EXP -= need;
|
EXP -= need;
|
||||||
Level++;
|
Level++;
|
||||||
|
isUp = true;
|
||||||
OnAttributeChanged();
|
OnAttributeChanged();
|
||||||
Recovery();
|
Recovery();
|
||||||
}
|
}
|
||||||
@ -1185,6 +1290,14 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isUp)
|
||||||
|
{
|
||||||
|
Effect[] effects = [.. Effects.Where(e => e.IsInEffect)];
|
||||||
|
foreach (Effect e in effects)
|
||||||
|
{
|
||||||
|
e.OnOwnerLevelUp(this, Level);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -1213,6 +1326,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
{
|
{
|
||||||
effect.OnAttributeChanged(this);
|
effect.OnAttributeChanged(this);
|
||||||
}
|
}
|
||||||
|
NormalAttack.SetMagicType(null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -1332,7 +1446,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// 获取角色的详细信息
|
/// 获取角色的详细信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public string GetInfo(bool showUser = true, bool showGrowth = true, bool showEXP = false)
|
public string GetInfo(bool showUser = true, bool showGrowth = true, bool showEXP = false, bool showMapRelated = false)
|
||||||
{
|
{
|
||||||
StringBuilder builder = new();
|
StringBuilder builder = new();
|
||||||
|
|
||||||
@ -1340,12 +1454,13 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
if (showEXP)
|
if (showEXP)
|
||||||
{
|
{
|
||||||
builder.AppendLine($"等级:{Level} / {GameplayEquilibriumConstant.MaxLevel}(突破进度:{LevelBreak + 1} / {GameplayEquilibriumConstant.LevelBreakList.Count})");
|
builder.AppendLine($"等级:{Level} / {GameplayEquilibriumConstant.MaxLevel}(突破进度:{LevelBreak + 1} / {GameplayEquilibriumConstant.LevelBreakList.Count})");
|
||||||
builder.AppendLine($"经验值:{EXP}{(Level != GameplayEquilibriumConstant.MaxLevel && GameplayEquilibriumConstant.EXPUpperLimit.TryGetValue(Level, out double need) ? " / " + need : "")}");
|
builder.AppendLine($"经验值:{EXP:0.##}{(Level != GameplayEquilibriumConstant.MaxLevel && GameplayEquilibriumConstant.EXPUpperLimit.TryGetValue(Level, out double need) ? " / " + need : "")}");
|
||||||
}
|
}
|
||||||
double exHP = ExHP + ExHP2 + ExHP3;
|
double exHP = ExHP + ExHP2 + ExHP3;
|
||||||
List<string> shield = [];
|
List<string> shield = [];
|
||||||
if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}");
|
if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}");
|
||||||
if (Shield.TotalMagicial > 0) shield.Add($"魔法:{Shield.TotalMagicial:0.##}");
|
if (Shield.TotalMagical > 0) shield.Add($"魔法:{Shield.TotalMagical:0.##}");
|
||||||
|
if (Shield.TotalMix > 0) shield.Add($"混合:{Shield.TotalMix:0.##}");
|
||||||
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : ""));
|
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : ""));
|
||||||
double exMP = ExMP + ExMP2 + ExMP3;
|
double exMP = ExMP + ExMP2 + ExMP3;
|
||||||
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
|
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
|
||||||
@ -1353,8 +1468,8 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
double exATK = ExATK + ExATK2 + ExATK3;
|
double exATK = ExATK + ExATK2 + ExATK3;
|
||||||
builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
|
builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
|
||||||
double exDEF = ExDEF + ExDEF2 + ExDEF3;
|
double exDEF = ExDEF + ExDEF2 + ExDEF3;
|
||||||
builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)");
|
builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exDEF >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)");
|
||||||
builder.AppendLine($"魔法抗性:{MDF.Avg:0.##}%(平均)");
|
builder.AppendLine(GetMagicResistanceInfo().Trim());
|
||||||
double exSPD = AGI * GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD;
|
double exSPD = AGI * GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD;
|
||||||
builder.AppendLine($"行动速度:{SPD:0.##}" + (exSPD != 0 ? $" [{InitialSPD:0.##} {(exSPD >= 0 ? "+" : "-")} {Math.Abs(exSPD):0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)");
|
builder.AppendLine($"行动速度:{SPD:0.##}" + (exSPD != 0 ? $" [{InitialSPD:0.##} {(exSPD >= 0 ? "+" : "-")} {Math.Abs(exSPD):0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)");
|
||||||
builder.AppendLine($"核心属性:{CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)}");
|
builder.AppendLine($"核心属性:{CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)}");
|
||||||
@ -1377,20 +1492,13 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
builder.AppendLine($"魔法消耗减少:{INT * GameplayEquilibriumConstant.INTtoCastMPReduce * 100:0.##}%");
|
builder.AppendLine($"魔法消耗减少:{INT * GameplayEquilibriumConstant.INTtoCastMPReduce * 100:0.##}%");
|
||||||
builder.AppendLine($"能量消耗减少:{INT * GameplayEquilibriumConstant.INTtoCastEPReduce * 100:0.##}%");
|
builder.AppendLine($"能量消耗减少:{INT * GameplayEquilibriumConstant.INTtoCastEPReduce * 100:0.##}%");
|
||||||
|
|
||||||
if (CharacterState != CharacterState.Actionable)
|
if (showMapRelated)
|
||||||
{
|
{
|
||||||
builder.AppendLine(CharacterSet.GetCharacterState(CharacterState));
|
builder.AppendLine($"移动距离:{MOV}");
|
||||||
|
builder.AppendLine($"攻击距离:{ATR}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsNeutral)
|
GetStatusInfo(builder);
|
||||||
{
|
|
||||||
builder.AppendLine("角色是无敌的");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsUnselectable)
|
|
||||||
{
|
|
||||||
builder.AppendLine("角色是不可选中的");
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.AppendLine("== 普通攻击 ==");
|
builder.AppendLine("== 普通攻击 ==");
|
||||||
builder.Append(NormalAttack.ToString());
|
builder.Append(NormalAttack.ToString());
|
||||||
@ -1406,46 +1514,12 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
|
|
||||||
if (EquipSlot.Any())
|
if (EquipSlot.Any())
|
||||||
{
|
{
|
||||||
builder.AppendLine("== 装备栏 ==");
|
builder.AppendLine(GetEquipSlotInfo().Trim());
|
||||||
if (EquipSlot.MagicCardPack != null)
|
|
||||||
{
|
|
||||||
builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.MagicCardPack.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.MagicCardPack) + ":" + EquipSlot.MagicCardPack.Name);
|
|
||||||
builder.AppendLine(EquipSlot.MagicCardPack.Description);
|
|
||||||
}
|
|
||||||
if (EquipSlot.Weapon != null)
|
|
||||||
{
|
|
||||||
builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Weapon.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Weapon) + ":" + EquipSlot.Weapon.Name);
|
|
||||||
builder.AppendLine(EquipSlot.Weapon.Description);
|
|
||||||
}
|
|
||||||
if (EquipSlot.Armor != null)
|
|
||||||
{
|
|
||||||
builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Armor.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Armor) + ":" + EquipSlot.Armor.Name);
|
|
||||||
builder.AppendLine(EquipSlot.Armor.Description);
|
|
||||||
}
|
|
||||||
if (EquipSlot.Shoes != null)
|
|
||||||
{
|
|
||||||
builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Shoes.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Shoes) + ":" + EquipSlot.Shoes.Name);
|
|
||||||
builder.AppendLine(EquipSlot.Shoes.Description);
|
|
||||||
}
|
|
||||||
if (EquipSlot.Accessory1 != null)
|
|
||||||
{
|
|
||||||
builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Accessory1.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Accessory1) + ":" + EquipSlot.Accessory1.Name);
|
|
||||||
builder.AppendLine(EquipSlot.Accessory1.Description);
|
|
||||||
}
|
|
||||||
if (EquipSlot.Accessory2 != null)
|
|
||||||
{
|
|
||||||
builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Accessory2.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Accessory2) + ":" + EquipSlot.Accessory2.Name);
|
|
||||||
builder.AppendLine(EquipSlot.Accessory2.Description);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Items.Count > 0)
|
if (Items.Count > 0)
|
||||||
{
|
{
|
||||||
builder.AppendLine("== 角色背包 ==");
|
builder.AppendLine(GetBackpackItemsInfo().Trim());
|
||||||
foreach (Item item in Items)
|
|
||||||
{
|
|
||||||
builder.Append(item.ToString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Effect[] effects = [.. Effects.Where(e => e.ShowInStatusBar)];
|
Effect[] effects = [.. Effects.Where(e => e.ShowInStatusBar)];
|
||||||
@ -1465,7 +1539,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// 获取角色的简略信息
|
/// 获取角色的简略信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public string GetSimpleInfo(bool showUser = true, bool showGrowth = true, bool showEXP = false, bool showBasicOnly = false)
|
public string GetSimpleInfo(bool showUser = true, bool showGrowth = true, bool showEXP = false, bool showBasicOnly = false, bool showMapRelated = false)
|
||||||
{
|
{
|
||||||
StringBuilder builder = new();
|
StringBuilder builder = new();
|
||||||
|
|
||||||
@ -1473,12 +1547,13 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
if (showEXP)
|
if (showEXP)
|
||||||
{
|
{
|
||||||
builder.AppendLine($"等级:{Level} / {GameplayEquilibriumConstant.MaxLevel}(突破进度:{LevelBreak + 1} / {GameplayEquilibriumConstant.LevelBreakList.Count})");
|
builder.AppendLine($"等级:{Level} / {GameplayEquilibriumConstant.MaxLevel}(突破进度:{LevelBreak + 1} / {GameplayEquilibriumConstant.LevelBreakList.Count})");
|
||||||
builder.AppendLine($"经验值:{EXP}{(Level != GameplayEquilibriumConstant.MaxLevel && GameplayEquilibriumConstant.EXPUpperLimit.TryGetValue(Level, out double need) ? " / " + need : "")}");
|
builder.AppendLine($"经验值:{EXP:0.##}{(Level != GameplayEquilibriumConstant.MaxLevel && GameplayEquilibriumConstant.EXPUpperLimit.TryGetValue(Level, out double need) ? " / " + need : "")}");
|
||||||
}
|
}
|
||||||
double exHP = ExHP + ExHP2 + ExHP3;
|
double exHP = ExHP + ExHP2 + ExHP3;
|
||||||
List<string> shield = [];
|
List<string> shield = [];
|
||||||
if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}");
|
if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}");
|
||||||
if (Shield.TotalMagicial > 0) shield.Add($"魔法:{Shield.TotalMagicial:0.##}");
|
if (Shield.TotalMagical > 0) shield.Add($"魔法:{Shield.TotalMagical:0.##}");
|
||||||
|
if (Shield.TotalMix > 0) shield.Add($"混合:{Shield.TotalMix:0.##}");
|
||||||
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : ""));
|
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : ""));
|
||||||
double exMP = ExMP + ExMP2 + ExMP3;
|
double exMP = ExMP + ExMP2 + ExMP3;
|
||||||
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
|
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
|
||||||
@ -1486,8 +1561,8 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
double exATK = ExATK + ExATK2 + ExATK3;
|
double exATK = ExATK + ExATK2 + ExATK3;
|
||||||
builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
|
builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
|
||||||
double exDEF = ExDEF + ExDEF2 + ExDEF3;
|
double exDEF = ExDEF + ExDEF2 + ExDEF3;
|
||||||
builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)");
|
builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exDEF >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)");
|
||||||
builder.AppendLine($"魔法抗性:{MDF.Avg:0.##}%(平均)");
|
builder.AppendLine(GetMagicResistanceInfo().Trim());
|
||||||
if (showBasicOnly)
|
if (showBasicOnly)
|
||||||
{
|
{
|
||||||
builder.AppendLine($"核心属性:{PrimaryAttributeValue:0.##}({CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)})");
|
builder.AppendLine($"核心属性:{PrimaryAttributeValue:0.##}({CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)})");
|
||||||
@ -1507,22 +1582,15 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
builder.AppendLine($"生命回复:{HR:0.##}" + (ExHR != 0 ? $" [{InitialHR + STR * GameplayEquilibriumConstant.STRtoHRFactor:0.##} {(ExHR >= 0 ? "+" : "-")} {Math.Abs(ExHR):0.##}]" : ""));
|
builder.AppendLine($"生命回复:{HR:0.##}" + (ExHR != 0 ? $" [{InitialHR + STR * GameplayEquilibriumConstant.STRtoHRFactor:0.##} {(ExHR >= 0 ? "+" : "-")} {Math.Abs(ExHR):0.##}]" : ""));
|
||||||
builder.AppendLine($"魔法回复:{MR:0.##}" + (ExMR != 0 ? $" [{InitialMR + INT * GameplayEquilibriumConstant.INTtoMRFactor:0.##} {(ExMR >= 0 ? "+" : "-")} {Math.Abs(ExMR):0.##}]" : ""));
|
builder.AppendLine($"魔法回复:{MR:0.##}" + (ExMR != 0 ? $" [{InitialMR + INT * GameplayEquilibriumConstant.INTtoMRFactor:0.##} {(ExMR >= 0 ? "+" : "-")} {Math.Abs(ExMR):0.##}]" : ""));
|
||||||
|
|
||||||
|
if (showMapRelated)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"移动距离:{MOV}");
|
||||||
|
builder.AppendLine($"攻击距离:{ATR}");
|
||||||
|
}
|
||||||
|
|
||||||
if (!showBasicOnly)
|
if (!showBasicOnly)
|
||||||
{
|
{
|
||||||
if (CharacterState != CharacterState.Actionable)
|
GetStatusInfo(builder);
|
||||||
{
|
|
||||||
builder.AppendLine(CharacterSet.GetCharacterState(CharacterState));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsNeutral)
|
|
||||||
{
|
|
||||||
builder.AppendLine("角色是无敌的");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsUnselectable)
|
|
||||||
{
|
|
||||||
builder.AppendLine("角色是不可选中的");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Skills.Count > 0)
|
if (Skills.Count > 0)
|
||||||
{
|
{
|
||||||
@ -1585,7 +1653,8 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
double exHP = ExHP + ExHP2 + ExHP3;
|
double exHP = ExHP + ExHP2 + ExHP3;
|
||||||
List<string> shield = [];
|
List<string> shield = [];
|
||||||
if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}");
|
if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}");
|
||||||
if (Shield.TotalMagicial > 0) shield.Add($"魔法:{Shield.TotalMagicial:0.##}");
|
if (Shield.TotalMagical > 0) shield.Add($"魔法:{Shield.TotalMagical:0.##}");
|
||||||
|
if (Shield.TotalMix > 0) shield.Add($"混合:{Shield.TotalMix:0.##}");
|
||||||
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : ""));
|
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : ""));
|
||||||
double exMP = ExMP + ExMP2 + ExMP3;
|
double exMP = ExMP + ExMP2 + ExMP3;
|
||||||
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
|
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
|
||||||
@ -1594,20 +1663,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
|
builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
|
||||||
builder.AppendLine($"核心属性:{PrimaryAttributeValue:0.##}" + (ExPrimaryAttributeValue != 0 ? $" [{BasePrimaryAttributeValue:0.##} {(ExPrimaryAttributeValue >= 0 ? "+" : "-")} {Math.Abs(ExPrimaryAttributeValue):0.##}]" : ""));
|
builder.AppendLine($"核心属性:{PrimaryAttributeValue:0.##}" + (ExPrimaryAttributeValue != 0 ? $" [{BasePrimaryAttributeValue:0.##} {(ExPrimaryAttributeValue >= 0 ? "+" : "-")} {Math.Abs(ExPrimaryAttributeValue):0.##}]" : ""));
|
||||||
|
|
||||||
if (CharacterState != CharacterState.Actionable)
|
GetStatusInfo(builder);
|
||||||
{
|
|
||||||
builder.AppendLine(CharacterSet.GetCharacterState(CharacterState));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsNeutral)
|
|
||||||
{
|
|
||||||
builder.AppendLine("角色是中立单位,处于无敌状态");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsUnselectable)
|
|
||||||
{
|
|
||||||
builder.AppendLine("角色是不可选中的");
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.AppendLine($"硬直时间:{hardnessTimes:0.##}");
|
builder.AppendLine($"硬直时间:{hardnessTimes:0.##}");
|
||||||
|
|
||||||
@ -1637,7 +1693,8 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
double exHP = ExHP + ExHP2 + ExHP3;
|
double exHP = ExHP + ExHP2 + ExHP3;
|
||||||
List<string> shield = [];
|
List<string> shield = [];
|
||||||
if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}");
|
if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}");
|
||||||
if (Shield.TotalMagicial > 0) shield.Add($"魔法:{Shield.TotalMagicial:0.##}");
|
if (Shield.TotalMagical > 0) shield.Add($"魔法:{Shield.TotalMagical:0.##}");
|
||||||
|
if (Shield.TotalMix > 0) shield.Add($"混合:{Shield.TotalMix:0.##}");
|
||||||
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : ""));
|
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : ""));
|
||||||
double exMP = ExMP + ExMP2 + ExMP3;
|
double exMP = ExMP + ExMP2 + ExMP3;
|
||||||
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
|
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
|
||||||
@ -1667,20 +1724,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
|
|
||||||
builder.AppendLine((HP == 0 ? "[ 死亡 ] " : "") + (showUser ? ToStringWithLevel() : ToStringWithLevelWithOutUser()));
|
builder.AppendLine((HP == 0 ? "[ 死亡 ] " : "") + (showUser ? ToStringWithLevel() : ToStringWithLevelWithOutUser()));
|
||||||
|
|
||||||
if (CharacterState != CharacterState.Actionable)
|
GetStatusInfo(builder);
|
||||||
{
|
|
||||||
builder.AppendLine(CharacterSet.GetCharacterState(CharacterState));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsNeutral)
|
|
||||||
{
|
|
||||||
builder.AppendLine("角色是无敌的");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsUnselectable)
|
|
||||||
{
|
|
||||||
builder.AppendLine("角色是不可选中的");
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.AppendLine("== 普通攻击 ==");
|
builder.AppendLine("== 普通攻击 ==");
|
||||||
builder.Append(NormalAttack.ToString());
|
builder.Append(NormalAttack.ToString());
|
||||||
@ -1711,7 +1755,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// 获取角色的物品信息
|
/// 获取角色的物品信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public string GetItemInfo(bool showUser = true, bool showGrowth = true, bool showEXP = false)
|
public string GetItemInfo(bool showUser = true, bool showGrowth = true, bool showEXP = false, bool showMapRelated = false)
|
||||||
{
|
{
|
||||||
StringBuilder builder = new();
|
StringBuilder builder = new();
|
||||||
|
|
||||||
@ -1719,12 +1763,13 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
if (showEXP)
|
if (showEXP)
|
||||||
{
|
{
|
||||||
builder.AppendLine($"等级:{Level} / {GameplayEquilibriumConstant.MaxLevel}(突破进度:{LevelBreak + 1} / {GameplayEquilibriumConstant.LevelBreakList.Count})");
|
builder.AppendLine($"等级:{Level} / {GameplayEquilibriumConstant.MaxLevel}(突破进度:{LevelBreak + 1} / {GameplayEquilibriumConstant.LevelBreakList.Count})");
|
||||||
builder.AppendLine($"经验值:{EXP}{(Level != GameplayEquilibriumConstant.MaxLevel && GameplayEquilibriumConstant.EXPUpperLimit.TryGetValue(Level, out double need) ? " / " + need : "")}");
|
builder.AppendLine($"经验值:{EXP:0.##}{(Level != GameplayEquilibriumConstant.MaxLevel && GameplayEquilibriumConstant.EXPUpperLimit.TryGetValue(Level, out double need) ? " / " + need : "")}");
|
||||||
}
|
}
|
||||||
double exHP = ExHP + ExHP2 + ExHP3;
|
double exHP = ExHP + ExHP2 + ExHP3;
|
||||||
List<string> shield = [];
|
List<string> shield = [];
|
||||||
if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}");
|
if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}");
|
||||||
if (Shield.TotalMagicial > 0) shield.Add($"魔法:{Shield.TotalMagicial:0.##}");
|
if (Shield.TotalMagical > 0) shield.Add($"魔法:{Shield.TotalMagical:0.##}");
|
||||||
|
if (Shield.TotalMix > 0) shield.Add($"混合:{Shield.TotalMix:0.##}");
|
||||||
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : ""));
|
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : ""));
|
||||||
double exMP = ExMP + ExMP2 + ExMP3;
|
double exMP = ExMP + ExMP2 + ExMP3;
|
||||||
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
|
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
|
||||||
@ -1732,8 +1777,8 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
double exATK = ExATK + ExATK2 + ExATK3;
|
double exATK = ExATK + ExATK2 + ExATK3;
|
||||||
builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
|
builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
|
||||||
double exDEF = ExDEF + ExDEF2 + ExDEF3;
|
double exDEF = ExDEF + ExDEF2 + ExDEF3;
|
||||||
builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)");
|
builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exDEF >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)");
|
||||||
builder.AppendLine($"魔法抗性:{MDF.Avg:0.##}%(平均)");
|
builder.AppendLine(GetMagicResistanceInfo().Trim());
|
||||||
double exSPD = AGI * GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD;
|
double exSPD = AGI * GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD;
|
||||||
builder.AppendLine($"行动速度:{SPD:0.##}" + (exSPD != 0 ? $" [{InitialSPD:0.##} {(exSPD >= 0 ? "+" : "-")} {Math.Abs(exSPD):0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)");
|
builder.AppendLine($"行动速度:{SPD:0.##}" + (exSPD != 0 ? $" [{InitialSPD:0.##} {(exSPD >= 0 ? "+" : "-")} {Math.Abs(exSPD):0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)");
|
||||||
builder.AppendLine($"核心属性:{CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)}");
|
builder.AppendLine($"核心属性:{CharacterSet.GetPrimaryAttributeName(PrimaryAttribute)}");
|
||||||
@ -1756,53 +1801,155 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
builder.AppendLine($"魔法消耗减少:{INT * GameplayEquilibriumConstant.INTtoCastMPReduce * 100:0.##}%");
|
builder.AppendLine($"魔法消耗减少:{INT * GameplayEquilibriumConstant.INTtoCastMPReduce * 100:0.##}%");
|
||||||
builder.AppendLine($"能量消耗减少:{INT * GameplayEquilibriumConstant.INTtoCastEPReduce * 100:0.##}%");
|
builder.AppendLine($"能量消耗减少:{INT * GameplayEquilibriumConstant.INTtoCastEPReduce * 100:0.##}%");
|
||||||
|
|
||||||
|
if (showMapRelated)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"移动距离:{MOV}");
|
||||||
|
builder.AppendLine($"攻击距离:{ATR}");
|
||||||
|
}
|
||||||
|
|
||||||
if (EquipSlot.Any())
|
if (EquipSlot.Any())
|
||||||
{
|
{
|
||||||
builder.AppendLine("== 装备栏 ==");
|
builder.AppendLine(GetEquipSlotInfo().Trim());
|
||||||
if (EquipSlot.MagicCardPack != null)
|
|
||||||
{
|
|
||||||
builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.MagicCardPack.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.MagicCardPack) + ":" + EquipSlot.MagicCardPack.Name);
|
|
||||||
builder.AppendLine(EquipSlot.MagicCardPack.Description);
|
|
||||||
}
|
|
||||||
if (EquipSlot.Weapon != null)
|
|
||||||
{
|
|
||||||
builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Weapon.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Weapon) + ":" + EquipSlot.Weapon.Name);
|
|
||||||
builder.AppendLine(EquipSlot.Weapon.Description);
|
|
||||||
}
|
|
||||||
if (EquipSlot.Armor != null)
|
|
||||||
{
|
|
||||||
builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Armor.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Armor) + ":" + EquipSlot.Armor.Name);
|
|
||||||
builder.AppendLine(EquipSlot.Armor.Description);
|
|
||||||
}
|
|
||||||
if (EquipSlot.Shoes != null)
|
|
||||||
{
|
|
||||||
builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Shoes.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Shoes) + ":" + EquipSlot.Shoes.Name);
|
|
||||||
builder.AppendLine(EquipSlot.Shoes.Description);
|
|
||||||
}
|
|
||||||
if (EquipSlot.Accessory1 != null)
|
|
||||||
{
|
|
||||||
builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Accessory1.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Accessory1) + ":" + EquipSlot.Accessory1.Name);
|
|
||||||
builder.AppendLine(EquipSlot.Accessory1.Description);
|
|
||||||
}
|
|
||||||
if (EquipSlot.Accessory2 != null)
|
|
||||||
{
|
|
||||||
builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Accessory2.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Accessory2) + ":" + EquipSlot.Accessory2.Name);
|
|
||||||
builder.AppendLine(EquipSlot.Accessory2.Description);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Items.Count > 0)
|
if (Items.Count > 0)
|
||||||
{
|
{
|
||||||
builder.AppendLine("== 角色背包 ==");
|
builder.AppendLine(GetBackpackItemsInfo().Trim());
|
||||||
foreach (Item item in Items)
|
}
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetStatusInfo(StringBuilder builder)
|
||||||
|
{
|
||||||
|
if (CharacterState != CharacterState.Actionable)
|
||||||
|
{
|
||||||
|
builder.AppendLine(CharacterSet.GetCharacterState(CharacterState));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ImmuneType & ImmuneType.Physical) != ImmuneType.None)
|
||||||
|
{
|
||||||
|
builder.AppendLine("角色现在物理免疫");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ImmuneType & ImmuneType.Magical) != ImmuneType.None)
|
||||||
|
{
|
||||||
|
builder.AppendLine("角色现在魔法免疫");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ImmuneType & ImmuneType.Skilled) != ImmuneType.None)
|
||||||
|
{
|
||||||
|
builder.AppendLine("角色现在技能免疫");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ImmuneType & ImmuneType.All) != ImmuneType.None)
|
||||||
|
{
|
||||||
|
builder.AppendLine("角色现在完全免疫");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsNeutral)
|
||||||
|
{
|
||||||
|
builder.AppendLine("角色是无敌的");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsUnselectable)
|
||||||
|
{
|
||||||
|
builder.AppendLine("角色是不可选中的");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取角色装备栏信息
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public string GetEquipSlotInfo()
|
||||||
|
{
|
||||||
|
StringBuilder builder = new();
|
||||||
|
|
||||||
|
builder.AppendLine("== 装备栏 ==");
|
||||||
|
if (EquipSlot.MagicCardPack != null)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.MagicCardPack.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.MagicCardPack) + ":" + EquipSlot.MagicCardPack.Name);
|
||||||
|
builder.AppendLine(EquipSlot.MagicCardPack.Description);
|
||||||
|
}
|
||||||
|
if (EquipSlot.Weapon != null)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Weapon.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Weapon) + ":" + EquipSlot.Weapon.Name);
|
||||||
|
builder.AppendLine(EquipSlot.Weapon.Description);
|
||||||
|
}
|
||||||
|
if (EquipSlot.Armor != null)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Armor.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Armor) + ":" + EquipSlot.Armor.Name);
|
||||||
|
builder.AppendLine(EquipSlot.Armor.Description);
|
||||||
|
}
|
||||||
|
if (EquipSlot.Shoes != null)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Shoes.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Shoes) + ":" + EquipSlot.Shoes.Name);
|
||||||
|
builder.AppendLine(EquipSlot.Shoes.Description);
|
||||||
|
}
|
||||||
|
if (EquipSlot.Accessory1 != null)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Accessory1.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Accessory1) + ":" + EquipSlot.Accessory1.Name);
|
||||||
|
builder.AppendLine(EquipSlot.Accessory1.Description);
|
||||||
|
}
|
||||||
|
if (EquipSlot.Accessory2 != null)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Accessory2.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Accessory2) + ":" + EquipSlot.Accessory2.Name);
|
||||||
|
builder.AppendLine(EquipSlot.Accessory2.Description);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取角色背包信息
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public string GetBackpackItemsInfo()
|
||||||
|
{
|
||||||
|
StringBuilder builder = new();
|
||||||
|
|
||||||
|
builder.AppendLine("== 角色背包 ==");
|
||||||
|
foreach (Item item in Items)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"[{ItemSet.GetQualityTypeName(item.QualityType)}]" + ItemSet.GetItemTypeName(item.ItemType) + ":" + item.Name);
|
||||||
|
builder.AppendLine(item.Description);
|
||||||
|
if (item.Skills.Active != null)
|
||||||
{
|
{
|
||||||
builder.Append(item.ToString());
|
Skill skill = item.Skills.Active;
|
||||||
|
List<string> strings = [];
|
||||||
|
if (skill.RealMPCost > 0) strings.Add($"魔法消耗:{skill.RealMPCost}");
|
||||||
|
if (skill.RealEPCost > 0) strings.Add($"能量消耗:{skill.RealEPCost}");
|
||||||
|
if (skill.RealCD > 0) strings.Add($"冷却时间:{skill.RealCD}{(skill.CurrentCD > 0 ? $"(正在冷却:剩余 {skill.CurrentCD} {GameplayEquilibriumConstant.InGameTime})" : "")}");
|
||||||
|
if (skill.RealHardnessTime > 0) strings.Add($"硬直时间:{skill.RealHardnessTime}");
|
||||||
|
builder.AppendLine($"技能【{skill.Name}】描述:{skill.Description.Trim()}{(strings.Count > 0 ? $"({string.Join(";", strings)})" : "")}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取魔法抗性信息
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public string GetMagicResistanceInfo()
|
||||||
|
{
|
||||||
|
StringBuilder builder = new();
|
||||||
|
|
||||||
|
if (GameplayEquilibriumConstant.UseMagicType.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (MagicType magicType in GameplayEquilibriumConstant.UseMagicType)
|
||||||
|
{
|
||||||
|
builder.Append(CharacterSet.GetMagicResistanceName(magicType));
|
||||||
|
builder.AppendLine($":{Calculation.Round4Digits(MDF[magicType] * 100):0.##}%");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else builder.AppendLine($"魔法抗性:{Calculation.Round4Digits(MDF.Avg * 100):0.##}%(平均)");
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 更新角色的状态,参见 <see cref="CharacterEffectStates"/>、<see cref="CharacterEffectTypes"/> 用法
|
/// 更新角色的状态,参见 <see cref="CharacterEffectStates"/>、<see cref="CharacterEffectTypes"/> 用法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -1822,30 +1969,27 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
IsUnselectable = types.Any(type => type == EffectType.Unselectable);
|
IsUnselectable = types.Any(type => type == EffectType.Unselectable);
|
||||||
|
|
||||||
IEnumerable<ImmuneType> immunes = CharacterImmuneTypes.Values.SelectMany(list => list);
|
IEnumerable<ImmuneType> immunes = CharacterImmuneTypes.Values.SelectMany(list => list);
|
||||||
// 判断角色的免疫状态
|
// 判断角色的免疫状态,需要注意的是 All 不会覆盖任何其他类型,因为它是一种独立的类型
|
||||||
bool isAllImmune = immunes.Any(type => type == ImmuneType.All);
|
bool isAllImmune = immunes.Any(type => type == ImmuneType.All);
|
||||||
bool isPhysicalImmune = immunes.Any(type => type == ImmuneType.Physical);
|
bool isPhysicalImmune = immunes.Any(type => type == ImmuneType.Physical);
|
||||||
bool isMagicalImmune = immunes.Any(type => type == ImmuneType.Magical);
|
bool isMagicalImmune = immunes.Any(type => type == ImmuneType.Magical);
|
||||||
bool isSkilledImmune = immunes.Any(type => type == ImmuneType.Skilled);
|
bool isSkilledImmune = immunes.Any(type => type == ImmuneType.Skilled);
|
||||||
|
ImmuneType = ImmuneType.None;
|
||||||
if (isAllImmune)
|
if (isAllImmune)
|
||||||
{
|
{
|
||||||
ImmuneType = ImmuneType.All;
|
ImmuneType |= ImmuneType.All;
|
||||||
}
|
}
|
||||||
else if (isPhysicalImmune)
|
if (isPhysicalImmune)
|
||||||
{
|
{
|
||||||
ImmuneType = ImmuneType.Physical;
|
ImmuneType |= ImmuneType.Physical;
|
||||||
}
|
}
|
||||||
else if (isMagicalImmune)
|
if (isMagicalImmune)
|
||||||
{
|
{
|
||||||
ImmuneType = ImmuneType.Magical;
|
ImmuneType |= ImmuneType.Magical;
|
||||||
}
|
}
|
||||||
else if (isSkilledImmune)
|
if (isSkilledImmune)
|
||||||
{
|
{
|
||||||
ImmuneType = ImmuneType.Skilled;
|
ImmuneType |= ImmuneType.Skilled;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ImmuneType = ImmuneType.None;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isControl = isNotActionable || isActionRestricted || isBattleRestricted || isSkillRestricted || isAttackRestricted;
|
bool isControl = isNotActionable || isActionRestricted || isBattleRestricted || isSkillRestricted || isAttackRestricted;
|
||||||
@ -1890,7 +2034,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// [ 推荐从模组中复制后使用对象 ]
|
/// [ 推荐从模组中复制后使用对象 ]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Character Copy(bool copyEx = false)
|
public Character Copy(bool copyEx = false, bool copyMagic = false, bool copyItem = false)
|
||||||
{
|
{
|
||||||
Character c = new()
|
Character c = new()
|
||||||
{
|
{
|
||||||
@ -1900,13 +2044,11 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
FirstName = FirstName,
|
FirstName = FirstName,
|
||||||
NickName = NickName,
|
NickName = NickName,
|
||||||
Profile = Profile.Copy(),
|
Profile = Profile.Copy(),
|
||||||
MagicType = MagicType,
|
|
||||||
FirstRoleType = FirstRoleType,
|
FirstRoleType = FirstRoleType,
|
||||||
SecondRoleType = SecondRoleType,
|
SecondRoleType = SecondRoleType,
|
||||||
ThirdRoleType = ThirdRoleType,
|
ThirdRoleType = ThirdRoleType,
|
||||||
Promotion = Promotion,
|
Promotion = Promotion,
|
||||||
PrimaryAttribute = PrimaryAttribute,
|
PrimaryAttribute = PrimaryAttribute,
|
||||||
ImmuneType = ImmuneType,
|
|
||||||
Level = Level,
|
Level = Level,
|
||||||
LevelBreak = LevelBreak,
|
LevelBreak = LevelBreak,
|
||||||
EXP = EXP,
|
EXP = EXP,
|
||||||
@ -1915,9 +2057,6 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
EP = EP,
|
EP = EP,
|
||||||
InitialATK = InitialATK,
|
InitialATK = InitialATK,
|
||||||
InitialDEF = InitialDEF,
|
InitialDEF = InitialDEF,
|
||||||
MDF = MDF.Copy(),
|
|
||||||
PhysicalPenetration = PhysicalPenetration,
|
|
||||||
MagicalPenetration = MagicalPenetration,
|
|
||||||
InitialHR = InitialHR,
|
InitialHR = InitialHR,
|
||||||
InitialMR = InitialMR,
|
InitialMR = InitialMR,
|
||||||
ER = ER,
|
ER = ER,
|
||||||
@ -1927,10 +2066,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
STRGrowth = STRGrowth,
|
STRGrowth = STRGrowth,
|
||||||
AGIGrowth = AGIGrowth,
|
AGIGrowth = AGIGrowth,
|
||||||
INTGrowth = INTGrowth,
|
INTGrowth = INTGrowth,
|
||||||
InitialSPD = InitialSPD,
|
InitialSPD = InitialSPD
|
||||||
ATR = ATR,
|
|
||||||
Lifesteal = Lifesteal,
|
|
||||||
Shield = Shield.Copy()
|
|
||||||
};
|
};
|
||||||
if (copyEx)
|
if (copyEx)
|
||||||
{
|
{
|
||||||
@ -1957,18 +2093,33 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
c.ExCritRate = ExCritRate;
|
c.ExCritRate = ExCritRate;
|
||||||
c.ExCritDMG = ExCritDMG;
|
c.ExCritDMG = ExCritDMG;
|
||||||
c.ExEvadeRate = ExEvadeRate;
|
c.ExEvadeRate = ExEvadeRate;
|
||||||
|
c.PhysicalPenetration = PhysicalPenetration;
|
||||||
|
c.MagicalPenetration = MagicalPenetration;
|
||||||
|
c.MDF = MDF.Copy();
|
||||||
|
c.Lifesteal = Lifesteal;
|
||||||
|
c.Shield = Shield.Copy();
|
||||||
|
c.ExATR = ExATR;
|
||||||
|
c.ExMOV = ExMOV;
|
||||||
|
c.MagicType = MagicType;
|
||||||
|
c.ImmuneType = ImmuneType;
|
||||||
}
|
}
|
||||||
foreach (Skill skill in Skills)
|
foreach (Skill skill in Skills)
|
||||||
{
|
{
|
||||||
Skill newskill = skill.Copy();
|
if (skill.SkillType != SkillType.Magic || copyMagic)
|
||||||
newskill.Character = c;
|
{
|
||||||
c.Skills.Add(newskill);
|
Skill newskill = skill.Copy();
|
||||||
|
newskill.Character = c;
|
||||||
|
c.Skills.Add(newskill);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
foreach (Item item in Items)
|
if (copyItem)
|
||||||
{
|
{
|
||||||
Item newitem = item.Copy();
|
foreach (Item item in Items)
|
||||||
newitem.Character = c;
|
{
|
||||||
c.Items.Add(newitem);
|
Item newitem = item.Copy();
|
||||||
|
newitem.Character = c;
|
||||||
|
c.Items.Add(newitem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
c.Recovery();
|
c.Recovery();
|
||||||
return c;
|
return c;
|
||||||
@ -2028,8 +2179,10 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
EP = c.EP;
|
EP = c.EP;
|
||||||
InitialATK = c.InitialATK;
|
InitialATK = c.InitialATK;
|
||||||
ExATK2 = c.ExATK2;
|
ExATK2 = c.ExATK2;
|
||||||
|
ExATKPercentage = c.ExATKPercentage;
|
||||||
InitialDEF = c.InitialDEF;
|
InitialDEF = c.InitialDEF;
|
||||||
ExDEF2 = c.ExDEF2;
|
ExDEF2 = c.ExDEF2;
|
||||||
|
ExDEFPercentage = c.ExDEFPercentage;
|
||||||
MDF = c.MDF.Copy();
|
MDF = c.MDF.Copy();
|
||||||
PhysicalPenetration = c.PhysicalPenetration;
|
PhysicalPenetration = c.PhysicalPenetration;
|
||||||
MagicalPenetration = c.MagicalPenetration;
|
MagicalPenetration = c.MagicalPenetration;
|
||||||
@ -2042,8 +2195,11 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
InitialAGI = c.InitialAGI;
|
InitialAGI = c.InitialAGI;
|
||||||
InitialINT = c.InitialINT;
|
InitialINT = c.InitialINT;
|
||||||
ExSTR = c.ExSTR;
|
ExSTR = c.ExSTR;
|
||||||
|
ExSTRPercentage = c.ExSTRPercentage;
|
||||||
ExAGI = c.ExAGI;
|
ExAGI = c.ExAGI;
|
||||||
|
ExAGIPercentage = c.ExAGIPercentage;
|
||||||
ExINT = c.ExINT;
|
ExINT = c.ExINT;
|
||||||
|
ExINTPercentage = c.ExINTPercentage;
|
||||||
STRGrowth = c.STRGrowth;
|
STRGrowth = c.STRGrowth;
|
||||||
AGIGrowth = c.AGIGrowth;
|
AGIGrowth = c.AGIGrowth;
|
||||||
INTGrowth = c.INTGrowth;
|
INTGrowth = c.INTGrowth;
|
||||||
@ -2052,7 +2208,8 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
ExActionCoefficient = c.ExActionCoefficient;
|
ExActionCoefficient = c.ExActionCoefficient;
|
||||||
ExAccelerationCoefficient = c.ExAccelerationCoefficient;
|
ExAccelerationCoefficient = c.ExAccelerationCoefficient;
|
||||||
ExCDR = c.ExCDR;
|
ExCDR = c.ExCDR;
|
||||||
ATR = c.ATR;
|
ExATR = c.ExATR;
|
||||||
|
ExMOV = c.ExMOV;
|
||||||
ExCritRate = c.ExCritRate;
|
ExCritRate = c.ExCritRate;
|
||||||
ExCritDMG = c.ExCritDMG;
|
ExCritDMG = c.ExCritDMG;
|
||||||
ExEvadeRate = c.ExEvadeRate;
|
ExEvadeRate = c.ExEvadeRate;
|
||||||
|
|||||||
@ -147,12 +147,12 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
Item newitem;
|
Item newitem;
|
||||||
if (itemsDefined != null && itemsDefined.FirstOrDefault(i => i.GetIdName() == item.GetIdName()) is Item itemDefined)
|
if (itemsDefined != null && itemsDefined.FirstOrDefault(i => i.GetIdName() == item.GetIdName()) is Item itemDefined)
|
||||||
{
|
{
|
||||||
newitem = itemDefined.Copy(true, !newItemGuid, true, itemsDefined, skillsDefined);
|
newitem = itemDefined.Copy(true, !newItemGuid, true, true, itemsDefined, skillsDefined);
|
||||||
item.SetPropertyToItemModuleNew(newitem);
|
item.SetPropertyToItemModuleNew(newitem);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
newitem = item.Copy(true, !newItemGuid, true, itemsDefined, skillsDefined);
|
newitem = item.Copy(true, !newItemGuid, true, true, itemsDefined, skillsDefined);
|
||||||
}
|
}
|
||||||
newitem.Character = character;
|
newitem.Character = character;
|
||||||
character.Items.Add(newitem);
|
character.Items.Add(newitem);
|
||||||
@ -196,32 +196,32 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
{
|
{
|
||||||
if (mcp != null)
|
if (mcp != null)
|
||||||
{
|
{
|
||||||
mcp = mcp.Copy(true, !newItemGuid, true, itemsDefined, skillsDefined);
|
mcp = mcp.Copy(true, !newItemGuid, true, true, itemsDefined, skillsDefined);
|
||||||
character.Equip(mcp);
|
character.Equip(mcp);
|
||||||
}
|
}
|
||||||
if (w != null)
|
if (w != null)
|
||||||
{
|
{
|
||||||
w = w.Copy(true, !newItemGuid, true, itemsDefined, skillsDefined);
|
w = w.Copy(true, !newItemGuid, true, true, itemsDefined, skillsDefined);
|
||||||
character.Equip(w);
|
character.Equip(w);
|
||||||
}
|
}
|
||||||
if (a != null)
|
if (a != null)
|
||||||
{
|
{
|
||||||
a = a.Copy(true, !newItemGuid, true, itemsDefined, skillsDefined);
|
a = a.Copy(true, !newItemGuid, true, true, itemsDefined, skillsDefined);
|
||||||
character.Equip(a);
|
character.Equip(a);
|
||||||
}
|
}
|
||||||
if (s != null)
|
if (s != null)
|
||||||
{
|
{
|
||||||
s = s.Copy(true, !newItemGuid, true, itemsDefined, skillsDefined);
|
s = s.Copy(true, !newItemGuid, true, true, itemsDefined, skillsDefined);
|
||||||
character.Equip(s);
|
character.Equip(s);
|
||||||
}
|
}
|
||||||
if (ac1 != null)
|
if (ac1 != null)
|
||||||
{
|
{
|
||||||
ac1 = ac1.Copy(true, !newItemGuid, true, itemsDefined, skillsDefined);
|
ac1 = ac1.Copy(true, !newItemGuid, true, true, itemsDefined, skillsDefined);
|
||||||
character.Equip(ac1);
|
character.Equip(ac1);
|
||||||
}
|
}
|
||||||
if (ac2 != null)
|
if (ac2 != null)
|
||||||
{
|
{
|
||||||
ac2 = ac2.Copy(true, !newItemGuid, true, itemsDefined, skillsDefined);
|
ac2 = ac2.Copy(true, !newItemGuid, true, true, itemsDefined, skillsDefined);
|
||||||
character.Equip(ac2);
|
character.Equip(ac2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,12 +237,13 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <param name="reference"></param>
|
/// <param name="reference"></param>
|
||||||
/// <param name="newItemGuid"></param>
|
/// <param name="newItemGuid"></param>
|
||||||
/// <param name="copyLevel"></param>
|
/// <param name="copyLevel"></param>
|
||||||
/// <param name="inventory"></param>
|
/// <param name="inventory">高危数据警告:传入此项会修改库存中物品的角色引用</param>
|
||||||
/// <param name="itemsDefined">对于动态扩展的物品而言,传入已定义的物品表,不使用被复制物品的数据</param>
|
/// <param name="itemsDefined">对于动态扩展的物品而言,传入已定义的物品表,不使用被复制物品的数据</param>
|
||||||
/// <param name="skillsDefined">对于动态扩展的技能而言,传入已定义的技能表,不使用被复制技能的数据</param>
|
/// <param name="skillsDefined">对于动态扩展的技能而言,传入已定义的技能表,不使用被复制技能的数据</param>
|
||||||
/// <param name="recovery"></param>
|
/// <param name="recovery"></param>
|
||||||
|
/// <param name="copyEP"></param>
|
||||||
/// <returns>构建的新角色</returns>
|
/// <returns>构建的新角色</returns>
|
||||||
public static Character Build(Character reference, bool newItemGuid = true, bool copyLevel = true, Inventory? inventory = null, IEnumerable<Item>? itemsDefined = null, IEnumerable<Skill>? skillsDefined = null, bool recovery = true)
|
public static Character Build(Character reference, bool newItemGuid = true, bool copyLevel = true, Inventory? inventory = null, IEnumerable<Item>? itemsDefined = null, IEnumerable<Skill>? skillsDefined = null, bool recovery = true, bool copyEP = true)
|
||||||
{
|
{
|
||||||
Character character = new CharacterBuilder(reference).Build(reference.Skills, reference.Items, newItemGuid, reference.EquipSlot, inventory, itemsDefined, skillsDefined);
|
Character character = new CharacterBuilder(reference).Build(reference.Skills, reference.Items, newItemGuid, reference.EquipSlot, inventory, itemsDefined, skillsDefined);
|
||||||
if (copyLevel)
|
if (copyLevel)
|
||||||
@ -252,13 +253,17 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
character.EXP = reference.EXP;
|
character.EXP = reference.EXP;
|
||||||
}
|
}
|
||||||
character.NormalAttack.Level = reference.NormalAttack.Level;
|
character.NormalAttack.Level = reference.NormalAttack.Level;
|
||||||
character.NormalAttack.HardnessTime = reference.NormalAttack.HardnessTime;
|
character.NormalAttack.ExDamage = reference.NormalAttack.ExDamage;
|
||||||
character.NormalAttack.SetMagicType(reference.NormalAttack.IsMagic, reference.NormalAttack.MagicType);
|
character.NormalAttack.ExDamage2 = reference.NormalAttack.ExDamage2;
|
||||||
|
character.NormalAttack.ExHardnessTime = reference.NormalAttack.ExHardnessTime;
|
||||||
|
character.NormalAttack.ExHardnessTime2 = reference.NormalAttack.ExHardnessTime2;
|
||||||
|
character.NormalAttack.SetMagicType(null, null, null);
|
||||||
if (!recovery)
|
if (!recovery)
|
||||||
{
|
{
|
||||||
character.HP = reference.HP;
|
character.HP = reference.HP;
|
||||||
character.MP = reference.MP;
|
character.MP = reference.MP;
|
||||||
}
|
}
|
||||||
|
if (copyEP) character.EP = reference.EP;
|
||||||
return character;
|
return character;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,12 +46,12 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 紫宛魔法抗性
|
/// 紫宛魔法抗性
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double Fleabane { get; set; } = 0;
|
public double Aster { get; set; } = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 时空魔法抗性
|
/// 时空魔法抗性
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double Particle { get; set; } = 0;
|
public double SpatioTemporal { get; set; } = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 平均魔法抗性
|
/// 平均魔法抗性
|
||||||
@ -60,7 +60,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
double mdf = Calculation.Round4Digits((None + Starmark + PurityNatural + PurityContemporary + Bright + Shadow + Element + Fleabane + Particle) / 9) * 100;
|
double mdf = Calculation.Round4Digits((None + Starmark + PurityNatural + PurityContemporary + Bright + Shadow + Element + Aster + SpatioTemporal) / 9);
|
||||||
if (Calculation.IsApproximatelyZero(mdf)) mdf = 0;
|
if (Calculation.IsApproximatelyZero(mdf)) mdf = 0;
|
||||||
return mdf;
|
return mdf;
|
||||||
}
|
}
|
||||||
@ -83,8 +83,8 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
MagicType.Bright => Bright,
|
MagicType.Bright => Bright,
|
||||||
MagicType.Shadow => Shadow,
|
MagicType.Shadow => Shadow,
|
||||||
MagicType.Element => Element,
|
MagicType.Element => Element,
|
||||||
MagicType.Fleabane => Fleabane,
|
MagicType.Aster => Aster,
|
||||||
MagicType.Particle => Particle,
|
MagicType.SpatioTemporal => SpatioTemporal,
|
||||||
_ => None
|
_ => None
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -110,11 +110,11 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
case MagicType.Element:
|
case MagicType.Element:
|
||||||
Element = value;
|
Element = value;
|
||||||
break;
|
break;
|
||||||
case MagicType.Fleabane:
|
case MagicType.Aster:
|
||||||
Fleabane = value;
|
Aster = value;
|
||||||
break;
|
break;
|
||||||
case MagicType.Particle:
|
case MagicType.SpatioTemporal:
|
||||||
Particle = value;
|
SpatioTemporal = value;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
None = value;
|
None = value;
|
||||||
@ -123,39 +123,6 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 对所有抗性赋值
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value"></param>
|
|
||||||
/// <param name="assignment"></param>
|
|
||||||
public void SetAllValue(double value, bool assignment = true)
|
|
||||||
{
|
|
||||||
if (assignment)
|
|
||||||
{
|
|
||||||
None = value;
|
|
||||||
Particle = value;
|
|
||||||
Fleabane = value;
|
|
||||||
Element = value;
|
|
||||||
Shadow = value;
|
|
||||||
Bright = value;
|
|
||||||
PurityContemporary = value;
|
|
||||||
PurityNatural = value;
|
|
||||||
Starmark = value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
None += value;
|
|
||||||
Particle += value;
|
|
||||||
Fleabane += value;
|
|
||||||
Element += value;
|
|
||||||
Shadow += value;
|
|
||||||
Bright += value;
|
|
||||||
PurityContemporary += value;
|
|
||||||
PurityNatural += value;
|
|
||||||
Starmark += value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 增加所有抗性,传入负数来减少
|
/// 增加所有抗性,传入负数来减少
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -163,14 +130,14 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
public void AddAllValue(double value)
|
public void AddAllValue(double value)
|
||||||
{
|
{
|
||||||
None += value;
|
None += value;
|
||||||
Particle += value;
|
|
||||||
Fleabane += value;
|
|
||||||
Element += value;
|
|
||||||
Shadow += value;
|
|
||||||
Bright += value;
|
|
||||||
PurityContemporary += value;
|
|
||||||
PurityNatural += value;
|
|
||||||
Starmark += value;
|
Starmark += value;
|
||||||
|
PurityNatural += value;
|
||||||
|
PurityContemporary += value;
|
||||||
|
Element += value;
|
||||||
|
Bright += value;
|
||||||
|
Shadow += value;
|
||||||
|
Aster += value;
|
||||||
|
SpatioTemporal += value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -188,8 +155,8 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
Bright = Bright,
|
Bright = Bright,
|
||||||
Shadow = Shadow,
|
Shadow = Shadow,
|
||||||
Element = Element,
|
Element = Element,
|
||||||
Fleabane = Fleabane,
|
Aster = Aster,
|
||||||
Particle = Particle
|
SpatioTemporal = SpatioTemporal
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,11 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Shield
|
public class Shield
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 绑定到特效的护盾对象。键为特效,值为对应的护盾对象。
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<Effect, ShieldOfEffect> ShieldOfEffects { get; } = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 物理护盾
|
/// 物理护盾
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -50,22 +55,32 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 紫宛护盾
|
/// 紫宛护盾
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double Fleabane { get; set; } = 0;
|
public double Aster { get; set; } = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 时空护盾
|
/// 时空护盾
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double Particle { get; set; } = 0;
|
public double SpatioTemporal { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 混合护盾
|
||||||
|
/// </summary>
|
||||||
|
public double Mix { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 总计混合护盾
|
||||||
|
/// </summary>
|
||||||
|
public double TotalMix => Mix + ShieldOfEffects.Values.Where(soe => soe.ShieldType == ShieldType.Mix && soe.Shield > 0).Sum(soe => soe.Shield);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 总计物理护盾
|
/// 总计物理护盾
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double TotalPhysical => Physical;
|
public double TotalPhysical => Physical + ShieldOfEffects.Values.Where(soe => soe.ShieldType == ShieldType.Physical && soe.Shield > 0).Sum(soe => soe.Shield);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 总计魔法护盾
|
/// 总计魔法护盾
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double TotalMagicial => None + Starmark + PurityNatural + PurityContemporary + Bright + Shadow + Element + Fleabane + Particle;
|
public double TotalMagical => None + Starmark + PurityNatural + PurityContemporary + Bright + Shadow + Element + Aster + SpatioTemporal + ShieldOfEffects.Values.Where(soe => soe.ShieldType == ShieldType.Magical && soe.Shield > 0).Sum(soe => soe.Shield);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取或设置护盾值
|
/// 获取或设置护盾值
|
||||||
@ -73,7 +88,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <param name="isMagic"></param>
|
/// <param name="isMagic"></param>
|
||||||
/// <param name="type"></param>
|
/// <param name="type"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public double this[bool isMagic = false, MagicType type = MagicType.None]
|
public double this[bool isMagic, MagicType type = MagicType.None]
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@ -87,8 +102,8 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
MagicType.Bright => Bright,
|
MagicType.Bright => Bright,
|
||||||
MagicType.Shadow => Shadow,
|
MagicType.Shadow => Shadow,
|
||||||
MagicType.Element => Element,
|
MagicType.Element => Element,
|
||||||
MagicType.Fleabane => Fleabane,
|
MagicType.Aster => Aster,
|
||||||
MagicType.Particle => Particle,
|
MagicType.SpatioTemporal => SpatioTemporal,
|
||||||
_ => None
|
_ => None
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -118,11 +133,11 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
case MagicType.Element:
|
case MagicType.Element:
|
||||||
Element = value;
|
Element = value;
|
||||||
break;
|
break;
|
||||||
case MagicType.Fleabane:
|
case MagicType.Aster:
|
||||||
Fleabane = value;
|
Aster = value;
|
||||||
break;
|
break;
|
||||||
case MagicType.Particle:
|
case MagicType.SpatioTemporal:
|
||||||
Particle = value;
|
SpatioTemporal = value;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
None = value;
|
None = value;
|
||||||
@ -137,7 +152,45 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 复制一个护盾对象
|
/// 添加一个绑定到特效的护盾,注意:如果特效已经存在护盾,则会覆盖原有护盾。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="soe"></param>
|
||||||
|
public void AddShieldOfEffect(ShieldOfEffect soe)
|
||||||
|
{
|
||||||
|
ShieldOfEffects[soe.Effect] = soe;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除某个特效的护盾
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="effect"></param>
|
||||||
|
public void RemoveShieldOfEffect(Effect effect)
|
||||||
|
{
|
||||||
|
ShieldOfEffects.Remove(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 计算并更新特效的护盾值,如果护盾值小于等于 0,则移除该特效的护盾。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="effect"></param>
|
||||||
|
/// <param name="damage"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public double CalculateShieldOfEffect(Effect effect, double damage)
|
||||||
|
{
|
||||||
|
if (ShieldOfEffects.TryGetValue(effect, out ShieldOfEffect? soe))
|
||||||
|
{
|
||||||
|
soe.Calculate(damage);
|
||||||
|
if (soe.Shield <= 0)
|
||||||
|
{
|
||||||
|
soe.Shield = 0;
|
||||||
|
ShieldOfEffects.Remove(effect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return soe?.Shield ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 复制一个护盾对象。注意:不会复制绑定到特效的护盾对象。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Shield Copy()
|
public Shield Copy()
|
||||||
@ -152,9 +205,31 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
Bright = Bright,
|
Bright = Bright,
|
||||||
Shadow = Shadow,
|
Shadow = Shadow,
|
||||||
Element = Element,
|
Element = Element,
|
||||||
Fleabane = Fleabane,
|
Aster = Aster,
|
||||||
Particle = Particle
|
SpatioTemporal = SpatioTemporal,
|
||||||
|
Mix = Mix
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 绑定到特效的护盾对象。这个类没有 JSON 转换器支持。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="effect"></param>
|
||||||
|
/// <param name="shield"></param>
|
||||||
|
/// <param name="shieldType"></param>
|
||||||
|
/// <param name="magicType"></param>
|
||||||
|
public class ShieldOfEffect(Effect effect, double shield, ShieldType shieldType, MagicType magicType = MagicType.None)
|
||||||
|
{
|
||||||
|
public Effect Effect { get; } = effect;
|
||||||
|
public ShieldType ShieldType { get; set; } = shieldType;
|
||||||
|
public MagicType MagicType { get; set; } = magicType;
|
||||||
|
public double Shield { get; set; } = shield;
|
||||||
|
|
||||||
|
public double Calculate(double damage)
|
||||||
|
{
|
||||||
|
Shield -= damage;
|
||||||
|
return Shield;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,24 +47,25 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// 获取单位的详细信息
|
/// 获取单位的详细信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public new string GetInfo(bool showUser = true, bool showGrowth = true, bool showEXP = false)
|
public new string GetInfo(bool showUser = true, bool showGrowth = true, bool showEXP = false, bool showMapRelated = false)
|
||||||
{
|
{
|
||||||
StringBuilder builder = new();
|
StringBuilder builder = new();
|
||||||
|
|
||||||
builder.AppendLine(showUser ? ToStringWithLevel() : ToStringWithLevelWithOutUser());
|
builder.AppendLine(showUser ? ToStringWithLevel() : ToStringWithLevelWithOutUser());
|
||||||
builder.AppendLine($"等级:{Level} / {GameplayEquilibriumConstant.MaxLevel}");
|
builder.AppendLine($"等级:{Level} / {GameplayEquilibriumConstant.MaxLevel}");
|
||||||
double exHP = ExHP + ExHP2 + ExHP3;
|
double exHP = ExHP + ExHP2 + ExHP3;
|
||||||
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : ""));
|
List<string> shield = [];
|
||||||
|
if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}");
|
||||||
|
if (Shield.TotalMagical > 0) shield.Add($"魔法:{Shield.TotalMagical:0.##}");
|
||||||
|
if (Shield.Mix > 0) shield.Add($"混合:{Shield.Mix:0.##}");
|
||||||
|
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : ""));
|
||||||
double exMP = ExMP + ExMP2 + ExMP3;
|
double exMP = ExMP + ExMP2 + ExMP3;
|
||||||
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
|
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
|
||||||
double exATK = ExATK + ExATK2 + ExATK3;
|
double exATK = ExATK + ExATK2 + ExATK3;
|
||||||
builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
|
builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
|
||||||
double exDEF = ExDEF + ExDEF2 + ExDEF3;
|
double exDEF = ExDEF + ExDEF2 + ExDEF3;
|
||||||
builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)");
|
builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)");
|
||||||
double mdf = Calculation.Round4Digits((MDF.None + MDF.Starmark + MDF.PurityNatural + MDF.PurityContemporary +
|
builder.AppendLine($"魔法抗性:{MDF.Avg:0.##}%(平均)");
|
||||||
MDF.Bright + MDF.Shadow + MDF.Element + MDF.Fleabane + MDF.Particle) / 9) * 100;
|
|
||||||
if (Calculation.IsApproximatelyZero(mdf)) mdf = 0;
|
|
||||||
builder.AppendLine($"魔法抗性:{mdf:0.##}%(平均)");
|
|
||||||
double exSPD = AGI * GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD;
|
double exSPD = AGI * GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD;
|
||||||
builder.AppendLine($"行动速度:{SPD:0.##}" + (exSPD != 0 ? $" [{InitialSPD:0.##} {(exSPD >= 0 ? "+" : "-")} {Math.Abs(exSPD):0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)");
|
builder.AppendLine($"行动速度:{SPD:0.##}" + (exSPD != 0 ? $" [{InitialSPD:0.##} {(exSPD >= 0 ? "+" : "-")} {Math.Abs(exSPD):0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)");
|
||||||
builder.AppendLine($"生命回复:{HR:0.##}" + (ExHR != 0 ? $" [{InitialHR + STR * GameplayEquilibriumConstant.STRtoHRFactor:0.##} {(ExHR >= 0 ? "+" : "-")} {Math.Abs(ExHR):0.##}]" : ""));
|
builder.AppendLine($"生命回复:{HR:0.##}" + (ExHR != 0 ? $" [{InitialHR + STR * GameplayEquilibriumConstant.STRtoHRFactor:0.##} {(ExHR >= 0 ? "+" : "-")} {Math.Abs(ExHR):0.##}]" : ""));
|
||||||
@ -77,6 +78,12 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
builder.AppendLine($"物理穿透:{PhysicalPenetration * 100:0.##}%");
|
builder.AppendLine($"物理穿透:{PhysicalPenetration * 100:0.##}%");
|
||||||
builder.AppendLine($"魔法穿透:{MagicalPenetration * 100:0.##}%");
|
builder.AppendLine($"魔法穿透:{MagicalPenetration * 100:0.##}%");
|
||||||
|
|
||||||
|
if (showMapRelated)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"移动距离:{MOV}");
|
||||||
|
builder.AppendLine($"攻击距离:{ATR}");
|
||||||
|
}
|
||||||
|
|
||||||
if (CharacterState != CharacterState.Actionable)
|
if (CharacterState != CharacterState.Actionable)
|
||||||
{
|
{
|
||||||
builder.AppendLine(CharacterSet.GetCharacterState(CharacterState));
|
builder.AppendLine(CharacterSet.GetCharacterState(CharacterState));
|
||||||
@ -173,29 +180,36 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// 获取单位的简略信息
|
/// 获取单位的简略信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public new string GetSimpleInfo(bool showUser = true, bool showGrowth = true, bool showEXP = false, bool showBasicOnly = false)
|
public new string GetSimpleInfo(bool showUser = true, bool showGrowth = true, bool showEXP = false, bool showBasicOnly = false, bool showMapRelated = false)
|
||||||
{
|
{
|
||||||
StringBuilder builder = new();
|
StringBuilder builder = new();
|
||||||
|
|
||||||
builder.AppendLine(showUser ? ToStringWithLevel() : ToStringWithLevelWithOutUser());
|
builder.AppendLine(showUser ? ToStringWithLevel() : ToStringWithLevelWithOutUser());
|
||||||
builder.AppendLine($"等级:{Level} / {GameplayEquilibriumConstant.MaxLevel}");
|
builder.AppendLine($"等级:{Level} / {GameplayEquilibriumConstant.MaxLevel}");
|
||||||
double exHP = ExHP + ExHP2 + ExHP3;
|
double exHP = ExHP + ExHP2 + ExHP3;
|
||||||
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : ""));
|
List<string> shield = [];
|
||||||
|
if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}");
|
||||||
|
if (Shield.TotalMagical > 0) shield.Add($"魔法:{Shield.TotalMagical:0.##}");
|
||||||
|
if (Shield.Mix > 0) shield.Add($"混合:{Shield.Mix:0.##}");
|
||||||
|
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : ""));
|
||||||
double exMP = ExMP + ExMP2 + ExMP3;
|
double exMP = ExMP + ExMP2 + ExMP3;
|
||||||
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
|
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
|
||||||
double exATK = ExATK + ExATK2 + ExATK3;
|
double exATK = ExATK + ExATK2 + ExATK3;
|
||||||
builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
|
builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
|
||||||
double exDEF = ExDEF + ExDEF2 + ExDEF3;
|
double exDEF = ExDEF + ExDEF2 + ExDEF3;
|
||||||
builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)");
|
builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)");
|
||||||
double mdf = Calculation.Round4Digits((MDF.None + MDF.Starmark + MDF.PurityNatural + MDF.PurityContemporary +
|
builder.AppendLine($"魔法抗性:{MDF.Avg:0.##}%(平均)");
|
||||||
MDF.Bright + MDF.Shadow + MDF.Element + MDF.Fleabane + MDF.Particle) / 9) * 100;
|
|
||||||
if (Calculation.IsApproximatelyZero(mdf)) mdf = 0;
|
|
||||||
builder.AppendLine($"魔法抗性:{mdf:0.##}%(平均)");
|
|
||||||
double exSPD = AGI * GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD;
|
double exSPD = AGI * GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD;
|
||||||
builder.AppendLine($"行动速度:{SPD:0.##}" + (exSPD != 0 ? $" [{InitialSPD:0.##} {(exSPD >= 0 ? "+" : "-")} {Math.Abs(exSPD):0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)");
|
builder.AppendLine($"行动速度:{SPD:0.##}" + (exSPD != 0 ? $" [{InitialSPD:0.##} {(exSPD >= 0 ? "+" : "-")} {Math.Abs(exSPD):0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)");
|
||||||
builder.AppendLine($"生命回复:{HR:0.##}" + (ExHR != 0 ? $" [{InitialHR + STR * GameplayEquilibriumConstant.STRtoHRFactor:0.##} {(ExHR >= 0 ? "+" : "-")} {Math.Abs(ExHR):0.##}]" : ""));
|
builder.AppendLine($"生命回复:{HR:0.##}" + (ExHR != 0 ? $" [{InitialHR + STR * GameplayEquilibriumConstant.STRtoHRFactor:0.##} {(ExHR >= 0 ? "+" : "-")} {Math.Abs(ExHR):0.##}]" : ""));
|
||||||
builder.AppendLine($"魔法回复:{MR:0.##}" + (ExMR != 0 ? $" [{InitialMR + INT * GameplayEquilibriumConstant.INTtoMRFactor:0.##} {(ExMR >= 0 ? "+" : "-")} {Math.Abs(ExMR):0.##}]" : ""));
|
builder.AppendLine($"魔法回复:{MR:0.##}" + (ExMR != 0 ? $" [{InitialMR + INT * GameplayEquilibriumConstant.INTtoMRFactor:0.##} {(ExMR >= 0 ? "+" : "-")} {Math.Abs(ExMR):0.##}]" : ""));
|
||||||
|
|
||||||
|
if (showMapRelated)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"移动距离:{MOV}");
|
||||||
|
builder.AppendLine($"攻击距离:{ATR}");
|
||||||
|
}
|
||||||
|
|
||||||
if (!showBasicOnly)
|
if (!showBasicOnly)
|
||||||
{
|
{
|
||||||
if (CharacterState != CharacterState.Actionable)
|
if (CharacterState != CharacterState.Actionable)
|
||||||
@ -280,7 +294,11 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
|
|
||||||
builder.AppendLine(ToStringWithLevel());
|
builder.AppendLine(ToStringWithLevel());
|
||||||
double exHP = ExHP + ExHP2 + ExHP3;
|
double exHP = ExHP + ExHP2 + ExHP3;
|
||||||
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : ""));
|
List<string> shield = [];
|
||||||
|
if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}");
|
||||||
|
if (Shield.TotalMagical > 0) shield.Add($"魔法:{Shield.TotalMagical:0.##}");
|
||||||
|
if (Shield.Mix > 0) shield.Add($"混合:{Shield.Mix:0.##}");
|
||||||
|
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : ""));
|
||||||
double exMP = ExMP + ExMP2 + ExMP3;
|
double exMP = ExMP + ExMP2 + ExMP3;
|
||||||
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
|
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
|
||||||
double exATK = ExATK + ExATK2 + ExATK3;
|
double exATK = ExATK + ExATK2 + ExATK3;
|
||||||
@ -327,7 +345,11 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
|
|
||||||
builder.AppendLine(ToStringWithLevel());
|
builder.AppendLine(ToStringWithLevel());
|
||||||
double exHP = ExHP + ExHP2 + ExHP3;
|
double exHP = ExHP + ExHP2 + ExHP3;
|
||||||
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : ""));
|
List<string> shield = [];
|
||||||
|
if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}");
|
||||||
|
if (Shield.TotalMagical > 0) shield.Add($"魔法:{Shield.TotalMagical:0.##}");
|
||||||
|
if (Shield.Mix > 0) shield.Add($"混合:{Shield.Mix:0.##}");
|
||||||
|
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : ""));
|
||||||
double exMP = ExMP + ExMP2 + ExMP3;
|
double exMP = ExMP + ExMP2 + ExMP3;
|
||||||
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
|
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
|
||||||
double exATK = ExATK + ExATK2 + ExATK3;
|
double exATK = ExATK + ExATK2 + ExATK3;
|
||||||
@ -398,24 +420,25 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// 获取单位的物品信息
|
/// 获取单位的物品信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public new string GetItemInfo(bool showUser = true, bool showGrowth = true, bool showEXP = false)
|
public new string GetItemInfo(bool showUser = true, bool showGrowth = true, bool showEXP = false, bool showMapRelated = false)
|
||||||
{
|
{
|
||||||
StringBuilder builder = new();
|
StringBuilder builder = new();
|
||||||
|
|
||||||
builder.AppendLine(showUser ? ToStringWithLevel() : ToStringWithLevelWithOutUser());
|
builder.AppendLine(showUser ? ToStringWithLevel() : ToStringWithLevelWithOutUser());
|
||||||
builder.AppendLine($"等级:{Level} / {GameplayEquilibriumConstant.MaxLevel}");
|
builder.AppendLine($"等级:{Level} / {GameplayEquilibriumConstant.MaxLevel}");
|
||||||
double exHP = ExHP + ExHP2 + ExHP3;
|
double exHP = ExHP + ExHP2 + ExHP3;
|
||||||
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : ""));
|
List<string> shield = [];
|
||||||
|
if (Shield.TotalPhysical > 0) shield.Add($"物理:{Shield.TotalPhysical:0.##}");
|
||||||
|
if (Shield.TotalMagical > 0) shield.Add($"魔法:{Shield.TotalMagical:0.##}");
|
||||||
|
if (Shield.Mix > 0) shield.Add($"混合:{Shield.Mix:0.##}");
|
||||||
|
builder.AppendLine($"生命值:{HP:0.##} / {MaxHP:0.##}" + (exHP != 0 ? $" [{BaseHP:0.##} {(exHP >= 0 ? "+" : "-")} {Math.Abs(exHP):0.##}]" : "") + (shield.Count > 0 ? $"({string.Join(",", shield)})" : ""));
|
||||||
double exMP = ExMP + ExMP2 + ExMP3;
|
double exMP = ExMP + ExMP2 + ExMP3;
|
||||||
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
|
builder.AppendLine($"魔法值:{MP:0.##} / {MaxMP:0.##}" + (exMP != 0 ? $" [{BaseMP:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exMP):0.##}]" : ""));
|
||||||
double exATK = ExATK + ExATK2 + ExATK3;
|
double exATK = ExATK + ExATK2 + ExATK3;
|
||||||
builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
|
builder.AppendLine($"攻击力:{ATK:0.##}" + (exATK != 0 ? $" [{BaseATK:0.##} {(exATK >= 0 ? "+" : "-")} {Math.Abs(exATK):0.##}]" : ""));
|
||||||
double exDEF = ExDEF + ExDEF2 + ExDEF3;
|
double exDEF = ExDEF + ExDEF2 + ExDEF3;
|
||||||
builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)");
|
builder.AppendLine($"物理护甲:{DEF:0.##}" + (exDEF != 0 ? $" [{BaseDEF:0.##} {(exMP >= 0 ? "+" : "-")} {Math.Abs(exDEF):0.##}]" : "") + $" ({PDR * 100:0.##}%)");
|
||||||
double mdf = Calculation.Round4Digits((MDF.None + MDF.Starmark + MDF.PurityNatural + MDF.PurityContemporary +
|
builder.AppendLine($"魔法抗性:{MDF.Avg:0.##}%(平均)");
|
||||||
MDF.Bright + MDF.Shadow + MDF.Element + MDF.Fleabane + MDF.Particle) / 9) * 100;
|
|
||||||
if (Calculation.IsApproximatelyZero(mdf)) mdf = 0;
|
|
||||||
builder.AppendLine($"魔法抗性:{mdf:0.##}%(平均)");
|
|
||||||
double exSPD = AGI * GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD;
|
double exSPD = AGI * GameplayEquilibriumConstant.AGItoSPDMultiplier + ExSPD;
|
||||||
builder.AppendLine($"行动速度:{SPD:0.##}" + (exSPD != 0 ? $" [{InitialSPD:0.##} {(exSPD >= 0 ? "+" : "-")} {Math.Abs(exSPD):0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)");
|
builder.AppendLine($"行动速度:{SPD:0.##}" + (exSPD != 0 ? $" [{InitialSPD:0.##} {(exSPD >= 0 ? "+" : "-")} {Math.Abs(exSPD):0.##}]" : "") + $" ({ActionCoefficient * 100:0.##}%)");
|
||||||
builder.AppendLine($"生命回复:{HR:0.##}" + (ExHR != 0 ? $" [{InitialHR + STR * GameplayEquilibriumConstant.STRtoHRFactor:0.##} {(ExHR >= 0 ? "+" : "-")} {Math.Abs(ExHR):0.##}]" : ""));
|
builder.AppendLine($"生命回复:{HR:0.##}" + (ExHR != 0 ? $" [{InitialHR + STR * GameplayEquilibriumConstant.STRtoHRFactor:0.##} {(ExHR >= 0 ? "+" : "-")} {Math.Abs(ExHR):0.##}]" : ""));
|
||||||
@ -428,6 +451,12 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
builder.AppendLine($"物理穿透:{PhysicalPenetration * 100:0.##}%");
|
builder.AppendLine($"物理穿透:{PhysicalPenetration * 100:0.##}%");
|
||||||
builder.AppendLine($"魔法穿透:{MagicalPenetration * 100:0.##}%");
|
builder.AppendLine($"魔法穿透:{MagicalPenetration * 100:0.##}%");
|
||||||
|
|
||||||
|
if (showMapRelated)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"移动距离:{MOV}");
|
||||||
|
builder.AppendLine($"攻击距离:{ATR}");
|
||||||
|
}
|
||||||
|
|
||||||
if (EquipSlot.Any())
|
if (EquipSlot.Any())
|
||||||
{
|
{
|
||||||
builder.AppendLine("== 装备栏 ==");
|
builder.AppendLine("== 装备栏 ==");
|
||||||
|
|||||||
179
Entity/Explore/Activity.cs
Normal file
179
Entity/Explore/Activity.cs
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
using System.Text;
|
||||||
|
using Milimoe.FunGame.Core.Interface.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Library.Common.Event;
|
||||||
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
|
||||||
|
namespace Milimoe.FunGame.Core.Entity
|
||||||
|
{
|
||||||
|
public class Activity : BaseEntity
|
||||||
|
{
|
||||||
|
public DateTime? StartTime { get; set; } = null;
|
||||||
|
public DateTime? EndTime { get; set; } = null;
|
||||||
|
public string Description { get; set; } = "";
|
||||||
|
public ActivityState Status { get; private set; } = ActivityState.Future;
|
||||||
|
public HashSet<Quest> Quests { get; set; } = [];
|
||||||
|
public long Predecessor { get; set; } = -1;
|
||||||
|
public ActivityState PredecessorStatus { get; set; } = ActivityState.Future;
|
||||||
|
|
||||||
|
public Activity(long id, string name, DateTime? startTime = null, DateTime? endTime = null)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
Name = name;
|
||||||
|
StartTime = startTime;
|
||||||
|
EndTime = endTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Activity() { }
|
||||||
|
|
||||||
|
// 事件
|
||||||
|
public event Action<ActivityEventArgs>? UserAccess;
|
||||||
|
public event Action<ActivityEventArgs>? UserGetActivityInfo;
|
||||||
|
|
||||||
|
public void UnRegisterUserAccess()
|
||||||
|
{
|
||||||
|
UserAccess = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnRegisterUserGetActivityInfo()
|
||||||
|
{
|
||||||
|
UserGetActivityInfo = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateState()
|
||||||
|
{
|
||||||
|
ActivityState newState;
|
||||||
|
DateTime now = DateTime.Now;
|
||||||
|
DateTime? upComingTime = StartTime?.AddHours(-6);
|
||||||
|
|
||||||
|
if (Predecessor != -1 && PredecessorStatus != ActivityState.Ended)
|
||||||
|
{
|
||||||
|
// 如果有前置活动且前置活动未结束,则当前活动状态为未来
|
||||||
|
newState = ActivityState.Future;
|
||||||
|
Status = newState;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (upComingTime != null && now < upComingTime)
|
||||||
|
{
|
||||||
|
newState = ActivityState.Future;
|
||||||
|
}
|
||||||
|
else if (upComingTime != null && now >= upComingTime && now < StartTime)
|
||||||
|
{
|
||||||
|
newState = ActivityState.Upcoming;
|
||||||
|
}
|
||||||
|
else if ((StartTime is null || now >= StartTime) && (EndTime is null || now < EndTime))
|
||||||
|
{
|
||||||
|
newState = ActivityState.InProgress;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newState = ActivityState.Ended;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Status != newState)
|
||||||
|
{
|
||||||
|
Status = newState;
|
||||||
|
foreach (Quest quest in Quests)
|
||||||
|
{
|
||||||
|
if (newState == ActivityState.InProgress)
|
||||||
|
{
|
||||||
|
if (quest.Status == QuestState.NotStarted && quest.QuestType == QuestType.Progressive)
|
||||||
|
{
|
||||||
|
quest.Status = QuestState.InProgress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (newState == ActivityState.Ended)
|
||||||
|
{
|
||||||
|
if (quest.Status == QuestState.NotStarted || quest.Status == QuestState.InProgress)
|
||||||
|
{
|
||||||
|
quest.Status = QuestState.Missed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AllowUserAccess(long userId, long questId = 0)
|
||||||
|
{
|
||||||
|
UpdateState();
|
||||||
|
ActivityEventArgs args = new(userId, questId, this);
|
||||||
|
UserAccess?.Invoke(args);
|
||||||
|
return args.AllowAccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetActivityInfo(long userId, long questId = 0)
|
||||||
|
{
|
||||||
|
UpdateState();
|
||||||
|
ActivityEventArgs args = new(userId, questId, this);
|
||||||
|
UserGetActivityInfo?.Invoke(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToString(bool showQuests)
|
||||||
|
{
|
||||||
|
UpdateState();
|
||||||
|
StringBuilder builder = new();
|
||||||
|
|
||||||
|
builder.AppendLine($"☆--- {Name} ---☆");
|
||||||
|
builder.AppendLine($"{Description}");
|
||||||
|
builder.AppendLine($"活动状态:{CommonSet.GetActivityStatus(Status)}");
|
||||||
|
builder.AppendLine(GetTimeString());
|
||||||
|
|
||||||
|
if (showQuests && Quests.Count > 0)
|
||||||
|
{
|
||||||
|
builder.AppendLine("=== 任务列表 ===");
|
||||||
|
builder.AppendLine(string.Join("\r\n", Quests));
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.ToString().Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetTimeString(bool full = true)
|
||||||
|
{
|
||||||
|
if (Predecessor != -1 && PredecessorStatus != ActivityState.Ended)
|
||||||
|
{
|
||||||
|
return $"在前置活动结束后开启";
|
||||||
|
}
|
||||||
|
if (full)
|
||||||
|
{
|
||||||
|
if (StartTime != null && EndTime != null)
|
||||||
|
{
|
||||||
|
return $"开始时间:{StartTime.Value.ToString(General.GeneralDateTimeFormatChinese)}\r\n结束时间:{EndTime.Value.ToString(General.GeneralDateTimeFormatChinese)}";
|
||||||
|
}
|
||||||
|
else if (StartTime != null && EndTime is null)
|
||||||
|
{
|
||||||
|
return $"活动时间:{StartTime.Value.ToString(General.GeneralDateTimeFormatChinese)} 起";
|
||||||
|
}
|
||||||
|
else if (StartTime is null && EndTime != null)
|
||||||
|
{
|
||||||
|
return $"活动将在 {EndTime.Value.ToString(General.GeneralDateTimeFormatChinese)} 结束";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (StartTime != null && EndTime != null)
|
||||||
|
{
|
||||||
|
return $"活动时间:{StartTime.Value.ToString(General.GeneralDateTimeFormatChinese)} - {EndTime.Value.ToString(General.GeneralDateTimeFormatChinese)}";
|
||||||
|
}
|
||||||
|
else if (StartTime != null && EndTime is null)
|
||||||
|
{
|
||||||
|
return $"活动时间:{StartTime.Value.ToString(General.GeneralDateTimeFormatChinese)} 起";
|
||||||
|
}
|
||||||
|
else if (StartTime is null && EndTime != null)
|
||||||
|
{
|
||||||
|
return $"截止于 {EndTime.Value.ToString(General.GeneralDateTimeFormatChinese)}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "活动时间:长期";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return ToString(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(IBaseEntity? other)
|
||||||
|
{
|
||||||
|
return other is Activity && GetIdName() == other?.GetIdName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,9 +6,12 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
public class Quest : BaseEntity
|
public class Quest : BaseEntity
|
||||||
{
|
{
|
||||||
public string Description { get; set; } = "";
|
public string Description { get; set; } = "";
|
||||||
public QuestState Status { get; set; } = 0;
|
public QuestState Status { get; set; } = QuestState.NotStarted;
|
||||||
public long CharacterId { get; set; } = 0;
|
public long CharacterId { get; set; } = 0;
|
||||||
public long RegionId { get; set; } = 0;
|
public long RegionId { get; set; } = 0;
|
||||||
|
public string NeedyExploreCharacterName { get; set; } = "";
|
||||||
|
public string NeedyExploreItemName { get; set; } = "";
|
||||||
|
public string NeedyExploreEventName { get; set; } = "";
|
||||||
public double CreditsAward { get; set; } = 0;
|
public double CreditsAward { get; set; } = 0;
|
||||||
public double MaterialsAward { get; set; } = 0;
|
public double MaterialsAward { get; set; } = 0;
|
||||||
public HashSet<Item> Awards { get; set; } = [];
|
public HashSet<Item> Awards { get; set; } = [];
|
||||||
@ -28,7 +31,12 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
}
|
}
|
||||||
foreach (Item item in Awards)
|
foreach (Item item in Awards)
|
||||||
{
|
{
|
||||||
awards.Add($"[{ItemSet.GetQualityTypeName(item.QualityType)}|{ItemSet.GetItemTypeName(item.ItemType)}] {item.Name} * {AwardsCount[item.Name]}");
|
int count = 1;
|
||||||
|
if (AwardsCount.TryGetValue(item.Name, out int value))
|
||||||
|
{
|
||||||
|
count = value;
|
||||||
|
}
|
||||||
|
awards.Add($"[{ItemSet.GetQualityTypeName(item.QualityType)}|{ItemSet.GetItemTypeName(item.ItemType)}] {item.Name} * {count}");
|
||||||
}
|
}
|
||||||
return string.Join(",", awards);
|
return string.Join(",", awards);
|
||||||
}
|
}
|
||||||
@ -11,10 +11,13 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
public HashSet<Character> Characters { get; } = [];
|
public HashSet<Character> Characters { get; } = [];
|
||||||
public HashSet<Unit> Units { get; } = [];
|
public HashSet<Unit> Units { get; } = [];
|
||||||
public HashSet<Item> Crops { get; } = [];
|
public HashSet<Item> Crops { get; } = [];
|
||||||
|
public HashSet<Item> Items { get; } = [];
|
||||||
public string Weather { get; set; } = "";
|
public string Weather { get; set; } = "";
|
||||||
public int Temperature { get; set; } = 15;
|
public int Temperature { get; set; } = 15;
|
||||||
public Dictionary<string, int> Weathers { get; } = [];
|
public Dictionary<string, int> Weathers { get; } = [];
|
||||||
public RarityType Difficulty { get; set; } = RarityType.OneStar;
|
public RarityType Difficulty { get; set; } = RarityType.OneStar;
|
||||||
|
public List<string> NPCs { get; set; } = [];
|
||||||
|
public List<string> Areas { get; set; } = [];
|
||||||
|
|
||||||
public bool ChangeWeather(string weather)
|
public bool ChangeWeather(string weather)
|
||||||
{
|
{
|
||||||
@ -47,25 +50,37 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
builder.AppendLine($"☆--- {Name} ---☆");
|
builder.AppendLine($"☆--- {Name} ---☆");
|
||||||
builder.AppendLine($"编号:{Id}");
|
builder.AppendLine($"编号:{Id}");
|
||||||
builder.AppendLine($"天气:{Weather}");
|
builder.AppendLine($"天气:{Weather}");
|
||||||
builder.AppendLine($"温度:{Temperature} °C");
|
builder.AppendLine($"温度:{Temperature} ℃");
|
||||||
builder.AppendLine($"{Description}");
|
builder.AppendLine($"{Description}");
|
||||||
|
|
||||||
if (Characters.Count > 0)
|
if (Characters.Count > 0)
|
||||||
{
|
{
|
||||||
builder.AppendLine($"== 头目 ==");
|
builder.AppendLine($"== 头目 ==");
|
||||||
builder.AppendLine(string.Join(",", Characters.Select(o => o.Name)));
|
builder.AppendLine(string.Join(",", Characters.Select(c => c.Name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Units.Count > 0)
|
if (Units.Count > 0)
|
||||||
{
|
{
|
||||||
builder.AppendLine($"== 生物 ==");
|
builder.AppendLine($"== 生物 ==");
|
||||||
builder.AppendLine(string.Join(",", Units.Select(o => o.Name)));
|
builder.AppendLine(string.Join(",", Units.Select(u => u.Name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Crops.Count > 0)
|
if (Crops.Count > 0)
|
||||||
{
|
{
|
||||||
builder.AppendLine($"== 作物 ==");
|
builder.AppendLine($"== 作物 ==");
|
||||||
builder.AppendLine(string.Join(",", Crops.Select(c => c.Name)));
|
builder.AppendLine(string.Join(",", Crops.Select(c => c.Name + (c.Description != "" ? $":{c.Description}" : "") + (c.BackgroundStory != "" ? $"\"{c.BackgroundStory}\"" : ""))));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Items.Count > 0)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"== 掉落 ==");
|
||||||
|
builder.AppendLine(string.Join(",", Items.Select(i =>
|
||||||
|
{
|
||||||
|
string itemquality = ItemSet.GetQualityTypeName(i.QualityType);
|
||||||
|
string itemtype = ItemSet.GetItemTypeName(i.ItemType) + (i.ItemType == ItemType.Weapon && i.WeaponType != WeaponType.None ? "-" + ItemSet.GetWeaponTypeName(i.WeaponType) : "");
|
||||||
|
if (itemtype != "") itemtype = $"|{itemtype}";
|
||||||
|
return $"[{itemquality + itemtype}]{i.Name}";
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.AppendLine($"探索难度:{CharacterSet.GetRarityTypeName(Difficulty)}");
|
builder.AppendLine($"探索难度:{CharacterSet.GetRarityTypeName(Difficulty)}");
|
||||||
@ -2,6 +2,7 @@
|
|||||||
using Milimoe.FunGame.Core.Api.Utility;
|
using Milimoe.FunGame.Core.Api.Utility;
|
||||||
using Milimoe.FunGame.Core.Interface.Base;
|
using Milimoe.FunGame.Core.Interface.Base;
|
||||||
using Milimoe.FunGame.Core.Interface.Entity;
|
using Milimoe.FunGame.Core.Interface.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Library.Common.Addon;
|
||||||
using Milimoe.FunGame.Core.Library.Constant;
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
|
||||||
namespace Milimoe.FunGame.Core.Entity
|
namespace Milimoe.FunGame.Core.Entity
|
||||||
@ -176,18 +177,10 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
foreach (Skill skill in Skills.Passives)
|
foreach (Skill skill in Skills.Passives)
|
||||||
{
|
{
|
||||||
skill.Character = _character;
|
skill.Character = _character;
|
||||||
foreach (Effect e in skill.Effects)
|
|
||||||
{
|
|
||||||
e.Source = _character;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
foreach (Skill skill in Skills.Magics)
|
foreach (Skill skill in Skills.Magics)
|
||||||
{
|
{
|
||||||
skill.Character = _character;
|
skill.Character = _character;
|
||||||
foreach (Effect e in skill.Effects)
|
|
||||||
{
|
|
||||||
e.Source = _character;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -248,7 +241,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
{
|
{
|
||||||
foreach (Skill skill in Skills.Passives)
|
foreach (Skill skill in Skills.Passives)
|
||||||
{
|
{
|
||||||
List<Effect> effects = [.. Character.Effects.Where(e => e.Skill == skill && e.Level > 0 && !e.IsBeingTemporaryDispelled)];
|
List<Effect> effects = [.. Character.Effects.Where(e => e.Skill == skill && e.IsInEffect)];
|
||||||
foreach (Effect e in effects)
|
foreach (Effect e in effects)
|
||||||
{
|
{
|
||||||
Character.Effects.Remove(e);
|
Character.Effects.Remove(e);
|
||||||
@ -318,7 +311,13 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
}
|
}
|
||||||
if (result && Skills.Active != null)
|
if (result && Skills.Active != null)
|
||||||
{
|
{
|
||||||
used = await queue.UseItemAsync(this, character, enemys, teammates);
|
List<Grid> castRange = [];
|
||||||
|
if (Skills.Active.GamingQueue != null && Skills.Active.GamingQueue.Map != null)
|
||||||
|
{
|
||||||
|
Grid? grid = Skills.Active.GamingQueue.Map.GetCharacterCurrentGrid(character);
|
||||||
|
castRange = grid is null ? [] : Skills.Active.GamingQueue.Map.GetGridsByRange(grid, Skills.Active.CastRange, true);
|
||||||
|
}
|
||||||
|
used = await queue.UseItemAsync(this, character, enemys, teammates, castRange);
|
||||||
}
|
}
|
||||||
if (used)
|
if (used)
|
||||||
{
|
{
|
||||||
@ -332,11 +331,11 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// 局外(库存)使用物品触发
|
/// 局外(库存)使用物品触发
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public bool UseItem(Dictionary<string, object> args)
|
public bool UseItem(User user, int times, Dictionary<string, object> args)
|
||||||
{
|
{
|
||||||
if (User != null)
|
if (User != null)
|
||||||
{
|
{
|
||||||
bool result = OnItemUsed(args);
|
bool result = OnItemUsed(user, times, args);
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
EntityState = EntityState.Modified;
|
EntityState = EntityState.Modified;
|
||||||
@ -347,19 +346,19 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReduceTimesAndRemove()
|
/// <summary>
|
||||||
|
/// 使用后减少使用次数或删除物品
|
||||||
|
/// </summary>
|
||||||
|
public void ReduceTimesAndRemove(int times = 1)
|
||||||
{
|
{
|
||||||
if (User != null)
|
if (IsReduceTimesAfterUse)
|
||||||
{
|
{
|
||||||
if (IsReduceTimesAfterUse)
|
RemainUseTimes -= times;
|
||||||
{
|
}
|
||||||
RemainUseTimes--;
|
if (RemainUseTimes < 0) RemainUseTimes = 0;
|
||||||
}
|
if (IsRemoveAfterUse && RemainUseTimes == 0)
|
||||||
if (RemainUseTimes < 0) RemainUseTimes = 0;
|
{
|
||||||
if (IsRemoveAfterUse && RemainUseTimes == 0)
|
EntityState = EntityState.Deleted;
|
||||||
{
|
|
||||||
EntityState = EntityState.Deleted;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,9 +377,11 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当物品被玩家使用时
|
/// 当物品被玩家使用时
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="user"></param>
|
||||||
|
/// <param name="times"></param>
|
||||||
/// <param name="args"></param>
|
/// <param name="args"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected virtual bool OnItemUsed(Dictionary<string, object> args)
|
protected virtual bool OnItemUsed(User user, int times, Dictionary<string, object> args)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -407,6 +408,14 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 物品完成复制后触发
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void AfterCopy()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected Item(ItemType type, bool isInGame = true)
|
protected Item(ItemType type, bool isInGame = true)
|
||||||
{
|
{
|
||||||
ItemType = type;
|
ItemType = type;
|
||||||
@ -434,7 +443,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
{
|
{
|
||||||
StringBuilder builder = new();
|
StringBuilder builder = new();
|
||||||
|
|
||||||
builder.AppendLine($"【{Name}】");
|
builder.AppendLine($"【{Name}】{(IsLock ? " [锁定]" : "")}");
|
||||||
|
|
||||||
string itemquality = ItemSet.GetQualityTypeName(QualityType);
|
string itemquality = ItemSet.GetQualityTypeName(QualityType);
|
||||||
string itemtype = ItemSet.GetItemTypeName(ItemType) + (ItemType == ItemType.Weapon && WeaponType != WeaponType.None ? "-" + ItemSet.GetWeaponTypeName(WeaponType) : "");
|
string itemtype = ItemSet.GetItemTypeName(ItemType) + (ItemType == ItemType.Weapon && WeaponType != WeaponType.None ? "-" + ItemSet.GetWeaponTypeName(WeaponType) : "");
|
||||||
@ -444,11 +453,11 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
|
|
||||||
if (isShowInStore && Price > 0)
|
if (isShowInStore && Price > 0)
|
||||||
{
|
{
|
||||||
builder.AppendLine($"售价:{Price} {GameplayEquilibriumConstant.InGameCurrency}");
|
builder.AppendLine($"售价:{Price:0.##} {GameplayEquilibriumConstant.InGameCurrency}");
|
||||||
}
|
}
|
||||||
else if (Price > 0)
|
else if (Price > 0)
|
||||||
{
|
{
|
||||||
builder.AppendLine($"回收价:{Price} {GameplayEquilibriumConstant.InGameCurrency}");
|
builder.AppendLine($"回收价:{Price:0.##} {GameplayEquilibriumConstant.InGameCurrency}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RemainUseTimes > 0)
|
if (RemainUseTimes > 0)
|
||||||
@ -471,36 +480,47 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
List<string> sellandtrade = [];
|
List<string> sellandtrade = [];
|
||||||
|
bool useRN = false;
|
||||||
|
|
||||||
if (IsSellable)
|
if (IsLock)
|
||||||
{
|
|
||||||
sellandtrade.Add("可出售");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsSellable && NextSellableTime != DateTime.MinValue)
|
|
||||||
{
|
|
||||||
sellandtrade.Add($"此物品将在 {NextSellableTime.ToString(General.GeneralDateTimeFormatChinese)} 后可出售");
|
|
||||||
}
|
|
||||||
else if (!IsSellable)
|
|
||||||
{
|
{
|
||||||
sellandtrade.Add("不可出售");
|
sellandtrade.Add("不可出售");
|
||||||
}
|
|
||||||
|
|
||||||
if (IsTradable)
|
|
||||||
{
|
|
||||||
sellandtrade.Add("可交易");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsTradable && NextTradableTime != DateTime.MinValue)
|
|
||||||
{
|
|
||||||
sellandtrade.Add($"此物品将在 {NextTradableTime.ToString(General.GeneralDateTimeFormatChinese)} 后可交易");
|
|
||||||
}
|
|
||||||
else if (!IsTradable)
|
|
||||||
{
|
|
||||||
sellandtrade.Add("不可交易");
|
sellandtrade.Add("不可交易");
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (IsSellable)
|
||||||
|
{
|
||||||
|
sellandtrade.Add("可出售");
|
||||||
|
}
|
||||||
|
|
||||||
if (sellandtrade.Count > 0) builder.AppendLine(string.Join(" ", sellandtrade).Trim());
|
if (!IsSellable && NextSellableTime != DateTime.MinValue)
|
||||||
|
{
|
||||||
|
useRN = true;
|
||||||
|
sellandtrade.Add($"此物品将在 {NextSellableTime.ToString(General.GeneralDateTimeFormatChinese)} 后可出售");
|
||||||
|
}
|
||||||
|
else if (!IsSellable)
|
||||||
|
{
|
||||||
|
sellandtrade.Add("不可出售");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsTradable)
|
||||||
|
{
|
||||||
|
sellandtrade.Add("可交易");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsTradable && NextTradableTime != DateTime.MinValue)
|
||||||
|
{
|
||||||
|
useRN = true;
|
||||||
|
sellandtrade.Add($"此物品将在 {NextTradableTime.ToString(General.GeneralDateTimeFormatChinese)} 后可交易");
|
||||||
|
}
|
||||||
|
else if (!IsTradable)
|
||||||
|
{
|
||||||
|
sellandtrade.Add("不可交易");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sellandtrade.Count > 0) builder.AppendLine(string.Join(useRN ? "\r\n" : " ", sellandtrade).Trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isShowGeneralDescription && GeneralDescription != "")
|
if (isShowGeneralDescription && GeneralDescription != "")
|
||||||
@ -567,6 +587,11 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
sellandtrade.Add("不可交易");
|
sellandtrade.Add("不可交易");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsLock)
|
||||||
|
{
|
||||||
|
builder.AppendLine("此物品已锁定");
|
||||||
|
}
|
||||||
|
|
||||||
if (sellandtrade.Count > 0) builder.AppendLine(string.Join(" ", sellandtrade).Trim());
|
if (sellandtrade.Count > 0) builder.AppendLine(string.Join(" ", sellandtrade).Trim());
|
||||||
if (Description != "") builder.AppendLine($"{Description}");
|
if (Description != "") builder.AppendLine($"{Description}");
|
||||||
if (IsEquipment && Character != null) builder.AppendLine($"装备于:{Character.ToStringWithLevelWithOutUser()}");
|
if (IsEquipment && Character != null) builder.AppendLine($"装备于:{Character.ToStringWithLevelWithOutUser()}");
|
||||||
@ -609,7 +634,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// 复制一个物品
|
/// 复制一个物品
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Item Copy(bool copyLevel = false, bool copyGuid = false, bool copyProperty = true, IEnumerable<Item>? itemsDefined = null, IEnumerable<Skill>? skillsDefined = null)
|
public Item Copy(bool copyLevel = false, bool copyGuid = false, bool copyProperty = true, bool copyOthers = true, IEnumerable<Item>? itemsDefined = null, IEnumerable<Skill>? skillsDefined = null)
|
||||||
{
|
{
|
||||||
Item item = Factory.OpenFactory.GetInstance<Item>(Id, Name, []);
|
Item item = Factory.OpenFactory.GetInstance<Item>(Id, Name, []);
|
||||||
Item? itemDefined = null;
|
Item? itemDefined = null;
|
||||||
@ -657,6 +682,18 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
item.Skills.Magics.Add(newskill);
|
item.Skills.Magics.Add(newskill);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
foreach (string key in itemDefined.Others.Keys)
|
||||||
|
{
|
||||||
|
item.Others[key] = itemDefined.Others[key];
|
||||||
|
}
|
||||||
|
if (copyOthers)
|
||||||
|
{
|
||||||
|
foreach (string key in Others.Keys)
|
||||||
|
{
|
||||||
|
item.Others[key] = Others[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item.AfterCopy();
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
using Milimoe.FunGame.Core.Api.Utility;
|
using Milimoe.FunGame.Core.Api.Utility;
|
||||||
using Milimoe.FunGame.Core.Interface.Base;
|
using Milimoe.FunGame.Core.Interface.Base;
|
||||||
using Milimoe.FunGame.Core.Interface.Entity;
|
using Milimoe.FunGame.Core.Interface.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Library.Common.Addon;
|
||||||
using Milimoe.FunGame.Core.Library.Constant;
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
|
||||||
namespace Milimoe.FunGame.Core.Entity
|
namespace Milimoe.FunGame.Core.Entity
|
||||||
@ -55,15 +56,25 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool DurativeWithoutDuration { get; set; } = false;
|
public virtual bool DurativeWithoutDuration { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 附属于某个特效
|
||||||
|
/// </summary>
|
||||||
|
public Effect? ParentEffect { get; set; } = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否是某个特效的附属
|
/// 是否是某个特效的附属
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool IsSubsidiary { get; set; } = false;
|
public bool IsSubsidiary => ParentEffect != null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否强制在状态栏中隐藏
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool ForceHideInStatusBar { get; set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否显示在状态栏
|
/// 是否显示在状态栏
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ShowInStatusBar => Skill.Item is null || (Durative && Duration > 0) || DurationTurn > 0 || DurativeWithoutDuration || IsSubsidiary;
|
public bool ShowInStatusBar => !ForceHideInStatusBar && (Skill.Item is null || (Durative && Duration > 0) || DurationTurn > 0 || DurativeWithoutDuration);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 特效是否生效
|
/// 特效是否生效
|
||||||
@ -208,9 +219,9 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <param name="character"></param>
|
/// <param name="character"></param>
|
||||||
/// <param name="enemy"></param>
|
/// <param name="enemy"></param>
|
||||||
/// <param name="isNormalAttack"></param>
|
/// <param name="isNormalAttack"></param>
|
||||||
/// <param name="isMagicDamage"></param>
|
/// <param name="damageType"></param>
|
||||||
/// <param name="magicType"></param>
|
/// <param name="magicType"></param>
|
||||||
public virtual void AlterDamageTypeBeforeCalculation(Character character, Character enemy, ref bool isNormalAttack, ref bool isMagicDamage, ref MagicType magicType)
|
public virtual void AlterDamageTypeBeforeCalculation(Character character, Character enemy, ref bool isNormalAttack, ref DamageType damageType, ref MagicType magicType)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -222,11 +233,11 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <param name="enemy"></param>
|
/// <param name="enemy"></param>
|
||||||
/// <param name="damage"></param>
|
/// <param name="damage"></param>
|
||||||
/// <param name="isNormalAttack"></param>
|
/// <param name="isNormalAttack"></param>
|
||||||
/// <param name="isMagicDamage"></param>
|
/// <param name="damageType"></param>
|
||||||
/// <param name="magicType"></param>
|
/// <param name="magicType"></param>
|
||||||
/// <param name="totalDamageBonus"></param>
|
/// <param name="totalDamageBonus"></param>
|
||||||
/// <returns>返回伤害增减值</returns>
|
/// <returns>返回伤害增减值</returns>
|
||||||
public virtual double AlterExpectedDamageBeforeCalculation(Character character, Character enemy, double damage, bool isNormalAttack, bool isMagicDamage, MagicType magicType, Dictionary<Effect, double> totalDamageBonus)
|
public virtual double AlterExpectedDamageBeforeCalculation(Character character, Character enemy, double damage, bool isNormalAttack, DamageType damageType, MagicType magicType, Dictionary<Effect, double> totalDamageBonus)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -238,17 +249,49 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <param name="enemy"></param>
|
/// <param name="enemy"></param>
|
||||||
/// <param name="damage"></param>
|
/// <param name="damage"></param>
|
||||||
/// <param name="isNormalAttack"></param>
|
/// <param name="isNormalAttack"></param>
|
||||||
/// <param name="isMagicDamage"></param>
|
/// <param name="damageType"></param>
|
||||||
/// <param name="magicType"></param>
|
/// <param name="magicType"></param>
|
||||||
/// <param name="damageResult"></param>
|
/// <param name="damageResult"></param>
|
||||||
/// <param name="isEvaded"></param>
|
/// <param name="isEvaded"></param>
|
||||||
/// <param name="totalDamageBonus"></param>
|
/// <param name="totalDamageBonus"></param>
|
||||||
/// <returns>返回伤害增减值</returns>
|
/// <returns>返回伤害增减值</returns>
|
||||||
public virtual double AlterActualDamageAfterCalculation(Character character, Character enemy, double damage, bool isNormalAttack, bool isMagicDamage, MagicType magicType, DamageResult damageResult, ref bool isEvaded, Dictionary<Effect, double> totalDamageBonus)
|
public virtual double AlterActualDamageAfterCalculation(Character character, Character enemy, double damage, bool isNormalAttack, DamageType damageType, MagicType magicType, DamageResult damageResult, ref bool isEvaded, Dictionary<Effect, double> totalDamageBonus)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在应用真实伤害前修改伤害 [ 允许取消伤害 ]
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character"></param>
|
||||||
|
/// <param name="enemy"></param>
|
||||||
|
/// <param name="damage"></param>
|
||||||
|
/// <param name="isNormalAttack"></param>
|
||||||
|
/// <param name="damageResult"></param>
|
||||||
|
/// <returns>返回 true 取消伤害</returns>
|
||||||
|
public virtual bool BeforeApplyTrueDamage(Character character, Character enemy, double damage, bool isNormalAttack, DamageResult damageResult)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 伤害应用时触发
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character"></param>
|
||||||
|
/// <param name="enemy"></param>
|
||||||
|
/// <param name="damage"></param>
|
||||||
|
/// <param name="actualDamage"></param>
|
||||||
|
/// <param name="isNormalAttack"></param>
|
||||||
|
/// <param name="damageType"></param>
|
||||||
|
/// <param name="magicType"></param>
|
||||||
|
/// <param name="damageResult"></param>
|
||||||
|
/// <param name="shieldMessage"></param>
|
||||||
|
/// <param name="originalMessage"></param>
|
||||||
|
public virtual void OnApplyDamage(Character character, Character enemy, double damage, double actualDamage, bool isNormalAttack, DamageType damageType, MagicType magicType, DamageResult damageResult, string shieldMessage, ref string originalMessage)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 在完成普通攻击动作之后修改硬直时间
|
/// 在完成普通攻击动作之后修改硬直时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -325,11 +368,12 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 对目标触发技能效果
|
/// 对目标触发技能效果(局外)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="user"></param>
|
||||||
/// <param name="targets"></param>
|
/// <param name="targets"></param>
|
||||||
/// <param name="others"></param>
|
/// <param name="others"></param>
|
||||||
public virtual void OnSkillCasted(List<Character> targets, Dictionary<string, object> others)
|
public virtual void OnSkillCasted(User user, List<Character> targets, Dictionary<string, object> others)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -344,17 +388,28 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 时间流逝时 [ 地图用 ]
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="grid"></param>
|
||||||
|
/// <param name="elapsed"></param>
|
||||||
|
public virtual void OnTimeElapsed(Grid grid, double elapsed)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 在完成伤害结算后
|
/// 在完成伤害结算后
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="character"></param>
|
/// <param name="character"></param>
|
||||||
/// <param name="enemy"></param>
|
/// <param name="enemy"></param>
|
||||||
/// <param name="damage"></param>
|
/// <param name="damage"></param>
|
||||||
|
/// <param name="actualDamage"></param>
|
||||||
/// <param name="isNormalAttack"></param>
|
/// <param name="isNormalAttack"></param>
|
||||||
/// <param name="isMagicDamage"></param>
|
/// <param name="damageType"></param>
|
||||||
/// <param name="magicType"></param>
|
/// <param name="magicType"></param>
|
||||||
/// <param name="damageResult"></param>
|
/// <param name="damageResult"></param>
|
||||||
public virtual void AfterDamageCalculation(Character character, Character enemy, double damage, bool isNormalAttack, bool isMagicDamage, MagicType magicType, DamageResult damageResult)
|
public virtual void AfterDamageCalculation(Character character, Character enemy, double damage, double actualDamage, bool isNormalAttack, DamageType damageType, MagicType magicType, DamageResult damageResult)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -498,6 +553,19 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开始选择移动目标前
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character"></param>
|
||||||
|
/// <param name="enemys"></param>
|
||||||
|
/// <param name="teammates"></param>
|
||||||
|
/// <param name="map"></param>
|
||||||
|
/// <param name="moveRange"></param>
|
||||||
|
public virtual void BeforeSelectTargetGrid(Character character, List<Character> enemys, List<Character> teammates, GameMap map, List<Grid> moveRange)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 开始选择目标前,修改可选择的 <paramref name="enemys"/>, <paramref name="teammates"/> 列表<para/>
|
/// 开始选择目标前,修改可选择的 <paramref name="enemys"/>, <paramref name="teammates"/> 列表<para/>
|
||||||
/// <see cref="ISkill"/> 有两种,使用时注意判断是 <see cref="Entity.Skill"/> 还是 <see cref="NormalAttack"/>
|
/// <see cref="ISkill"/> 有两种,使用时注意判断是 <see cref="Entity.Skill"/> 还是 <see cref="NormalAttack"/>
|
||||||
@ -521,8 +589,9 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <param name="pUseItem"></param>
|
/// <param name="pUseItem"></param>
|
||||||
/// <param name="pCastSkill"></param>
|
/// <param name="pCastSkill"></param>
|
||||||
/// <param name="pNormalAttack"></param>
|
/// <param name="pNormalAttack"></param>
|
||||||
|
/// <param name="forceAction"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public virtual CharacterActionType AlterActionTypeBeforeAction(Character character, CharacterState state, ref bool canUseItem, ref bool canCastSkill, ref double pUseItem, ref double pCastSkill, ref double pNormalAttack)
|
public virtual CharacterActionType AlterActionTypeBeforeAction(Character character, CharacterState state, ref bool canUseItem, ref bool canCastSkill, ref double pUseItem, ref double pCastSkill, ref double pNormalAttack, ref bool forceAction)
|
||||||
{
|
{
|
||||||
return CharacterActionType.None;
|
return CharacterActionType.None;
|
||||||
}
|
}
|
||||||
@ -564,19 +633,22 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
if (effect.DurativeWithoutDuration || (effect.Durative && effect.Duration > 0) || effect.DurationTurn > 0)
|
if (effect.DurativeWithoutDuration || (effect.Durative && effect.Duration > 0) || effect.DurationTurn > 0)
|
||||||
{
|
{
|
||||||
// 先从角色身上移除特效类型
|
// 先从角色身上移除特效类型
|
||||||
if (target.CharacterEffectTypes.TryGetValue(effect, out List<EffectType>? types) && types != null)
|
if (isEnemy != effect.IsDebuff)
|
||||||
{
|
{
|
||||||
RemoveEffectTypesByDispel(types, isEnemy);
|
if (target.CharacterEffectTypes.TryGetValue(effect, out List<EffectType>? types) && types != null)
|
||||||
if (types.Count == 0)
|
{
|
||||||
|
RemoveEffectTypesByDispel(types, isEnemy);
|
||||||
|
if (types.Count == 0)
|
||||||
|
{
|
||||||
|
target.CharacterEffectTypes.Remove(effect);
|
||||||
|
removeEffectTypes = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
target.CharacterEffectTypes.Remove(effect);
|
|
||||||
removeEffectTypes = true;
|
removeEffectTypes = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
removeEffectTypes = true;
|
|
||||||
}
|
|
||||||
// 友方移除控制状态
|
// 友方移除控制状态
|
||||||
if (!isEnemy && effect.IsDebuff)
|
if (!isEnemy && effect.IsDebuff)
|
||||||
{
|
{
|
||||||
@ -644,29 +716,53 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="character"></param>
|
/// <param name="character"></param>
|
||||||
/// <param name="attacker"></param>
|
/// <param name="attacker"></param>
|
||||||
/// <param name="isMagic"></param>
|
/// <param name="damageType"></param>
|
||||||
/// <param name="magicType"></param>
|
/// <param name="magicType"></param>
|
||||||
/// <param name="damage"></param>
|
/// <param name="damage"></param>
|
||||||
/// <param name="shield"></param>
|
/// <param name="damageReduce"></param>
|
||||||
/// <param name="message"></param>
|
/// <param name="message"></param>
|
||||||
/// <returns>返回 false 可以阻止后续扣除角色护盾</returns>
|
/// <returns>返回 false 可以跳过护盾结算</returns>
|
||||||
public virtual bool BeforeShieldCalculation(Character character, Character attacker, bool isMagic, MagicType magicType, double damage, double shield, ref string message)
|
public virtual bool BeforeShieldCalculation(Character character, Character attacker, DamageType damageType, MagicType magicType, double damage, ref double damageReduce, ref string message)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当角色护盾破碎时
|
/// 在角色护盾有效防御时 [ 破碎本身不会触发此钩子,但破碎后化解可触发 ]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="character"></param>
|
/// <param name="character"></param>
|
||||||
/// <param name="attacker"></param>
|
/// <param name="attacker"></param>
|
||||||
/// <param name="isMagic"></param>
|
/// <param name="damageType"></param>
|
||||||
/// <param name="magicType"></param>
|
/// <param name="magicType"></param>
|
||||||
/// <param name="damage"></param>
|
/// <param name="damage"></param>
|
||||||
/// <param name="shield"></param>
|
/// <param name="shieldType"></param>
|
||||||
|
public virtual void OnShieldNeutralizeDamage(Character character, Character attacker, DamageType damageType, MagicType magicType, double damage, ShieldType shieldType)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当角色护盾破碎时 [ 非绑定特效,只有同种类型的总护盾值小于等于 0 时触发 ]
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character"></param>
|
||||||
|
/// <param name="attacker"></param>
|
||||||
|
/// <param name="type"></param>
|
||||||
/// <param name="overFlowing"></param>
|
/// <param name="overFlowing"></param>
|
||||||
/// <returns>返回 false 可以阻止后续扣除角色生命值</returns>
|
/// <returns>返回 false 可以阻止后续扣除角色生命值</returns>
|
||||||
public virtual bool OnShieldBroken(Character character, Character attacker, bool isMagic, MagicType magicType, double damage, double shield, double overFlowing)
|
public virtual bool OnShieldBroken(Character character, Character attacker, ShieldType type, double overFlowing)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当角色护盾破碎时 [ 绑定特效的护盾值小于等于 0 时便会触发 ]
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character"></param>
|
||||||
|
/// <param name="attacker"></param>
|
||||||
|
/// <param name="effect"></param>
|
||||||
|
/// <param name="overFlowing"></param>
|
||||||
|
/// <returns>返回 false 可以阻止后续扣除角色生命值</returns>
|
||||||
|
public virtual bool OnShieldBroken(Character character, Character attacker, Effect effect, double overFlowing)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -674,12 +770,12 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 在免疫检定时
|
/// 在免疫检定时
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="actor"></param>
|
/// <param name="character"></param>
|
||||||
/// <param name="enemy"></param>
|
/// <param name="target"></param>
|
||||||
/// <param name="skill"></param>
|
/// <param name="skill"></param>
|
||||||
/// <param name="item"></param>
|
/// <param name="item"></param>
|
||||||
/// <returns>false:免疫检定不通过</returns>
|
/// <returns>false:免疫检定不通过</returns>
|
||||||
public virtual bool OnImmuneCheck(Character actor, Character enemy, ISkill skill, Item? item = null)
|
public virtual bool OnImmuneCheck(Character character, Character target, ISkill skill, Item? item = null)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -690,11 +786,11 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <param name="actor"></param>
|
/// <param name="actor"></param>
|
||||||
/// <param name="enemy"></param>
|
/// <param name="enemy"></param>
|
||||||
/// <param name="isNormalAttack"></param>
|
/// <param name="isNormalAttack"></param>
|
||||||
/// <param name="isMagic"></param>
|
/// <param name="damageType"></param>
|
||||||
/// <param name="magicType"></param>
|
/// <param name="magicType"></param>
|
||||||
/// <param name="damage"></param>
|
/// <param name="damage"></param>
|
||||||
/// <returns>false:免疫检定不通过</returns>
|
/// <returns>false:免疫检定不通过</returns>
|
||||||
public virtual bool OnDamageImmuneCheck(Character actor, Character enemy, bool isNormalAttack, bool isMagic, MagicType magicType, double damage)
|
public virtual bool OnDamageImmuneCheck(Character actor, Character enemy, bool isNormalAttack, DamageType damageType, MagicType magicType, double damage)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -704,16 +800,22 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="actor"></param>
|
/// <param name="actor"></param>
|
||||||
/// <param name="enemy"></param>
|
/// <param name="enemy"></param>
|
||||||
/// <param name="isMagic"></param>
|
/// <param name="damageType"></param>
|
||||||
/// <param name="magicType"></param>
|
/// <param name="magicType"></param>
|
||||||
/// <param name="expectedDamage"></param>
|
/// <param name="expectedDamage"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public DamageResult DamageToEnemy(Character actor, Character enemy, bool isMagic, MagicType magicType, double expectedDamage)
|
public DamageResult DamageToEnemy(Character actor, Character enemy, DamageType damageType, MagicType magicType, double expectedDamage)
|
||||||
{
|
{
|
||||||
if (GamingQueue is null) return DamageResult.Evaded;
|
if (GamingQueue is null) return DamageResult.Evaded;
|
||||||
int changeCount = 0;
|
int changeCount = 0;
|
||||||
DamageResult result = !isMagic ? GamingQueue.CalculatePhysicalDamage(actor, enemy, false, expectedDamage, out double damage, ref changeCount) : GamingQueue.CalculateMagicalDamage(actor, enemy, false, MagicType, expectedDamage, out damage, ref changeCount);
|
DamageResult result = DamageResult.Normal;
|
||||||
GamingQueue.DamageToEnemyAsync(actor, enemy, damage, false, isMagic, magicType, result);
|
double damage = expectedDamage;
|
||||||
|
if (damageType != DamageType.True)
|
||||||
|
{
|
||||||
|
result = damageType == DamageType.Physical ? GamingQueue.CalculatePhysicalDamage(actor, enemy, false, expectedDamage, out damage, ref changeCount) : GamingQueue.CalculateMagicalDamage(actor, enemy, false, MagicType, expectedDamage, out damage, ref changeCount);
|
||||||
|
}
|
||||||
|
// 注意此方法在后台线程运行
|
||||||
|
GamingQueue.DamageToEnemyAsync(actor, enemy, damage, false, damageType, magicType, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -945,6 +1047,17 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
GamingQueue?.ChangeCharacterHardnessTime(character, addValue, isPercentage, isCheckProtected);
|
GamingQueue?.ChangeCharacterHardnessTime(character, addValue, isPercentage, isCheckProtected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置角色为 AI 控制 [ 系统控制 ]
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancel"></param>
|
||||||
|
/// <param name="characters"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public void SetCharactersToAIControl(bool cancel = false, params IEnumerable<Character> characters)
|
||||||
|
{
|
||||||
|
GamingQueue?.SetCharactersToAIControl(true, cancel, characters);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 检查角色是否在 AI 控制状态
|
/// 检查角色是否在 AI 控制状态
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -955,6 +1068,19 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
return GamingQueue?.IsCharacterInAIControlling(character) ?? false;
|
return GamingQueue?.IsCharacterInAIControlling(character) ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加角色应用的特效类型到回合记录中
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character"></param>
|
||||||
|
/// <param name="types"></param>
|
||||||
|
public void RecordCharacterApplyEffects(Character character, params List<EffectType> types)
|
||||||
|
{
|
||||||
|
if (GamingQueue?.LastRound.ApplyEffects.TryAdd(character, types) ?? false)
|
||||||
|
{
|
||||||
|
GamingQueue?.LastRound.ApplyEffects[character].AddRange(types);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 返回特效详情
|
/// 返回特效详情
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -981,6 +1107,11 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
builder.Append($"({dispels})");
|
builder.Append($"({dispels})");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsBeingTemporaryDispelled)
|
||||||
|
{
|
||||||
|
builder.Append("(已被临时驱散)");
|
||||||
|
}
|
||||||
|
|
||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,17 +16,77 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 普通攻击说明
|
/// 普通攻击说明
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Description => $"对目标敌人造成 {(1.0 + 0.05 * (Level - 1)) * 100:0.##}% 攻击力 [ {Damage:0.##} ] 点{(IsMagic ? CharacterSet.GetMagicDamageName(MagicType) : "物理伤害")}。";
|
public string Description => $"对目标敌人造成 {BaseDamageMultiplier * 100:0.##}% 攻击力 [ {Damage:0.##} ] 点{(IsMagic ? CharacterSet.GetMagicDamageName(MagicType) : "物理伤害")}。";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 普通攻击的通用说明
|
||||||
|
/// </summary>
|
||||||
|
public string GeneralDescription => $"对目标敌人造成基于总攻击力的{(IsMagic ? CharacterSet.GetMagicDamageName(MagicType) : "物理伤害")}。";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 所属的角色
|
/// 所属的角色
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Character Character { get; } = character;
|
public Character Character { get; } = character;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 基础普通攻击伤害倍率 [ 武器类型相关 ]
|
||||||
|
/// </summary>
|
||||||
|
private double BaseDamageMultiplier
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
double baseMultiplier = 1.0 + 0.05 * (Level - 1);
|
||||||
|
if (Character.EquipSlot.Weapon != null)
|
||||||
|
{
|
||||||
|
baseMultiplier = Character.EquipSlot.Weapon.WeaponType switch
|
||||||
|
{
|
||||||
|
WeaponType.OneHandedSword => GameplayEquilibriumConstant.OneHandedSwordBaseMultiplier,
|
||||||
|
WeaponType.TwoHandedSword => GameplayEquilibriumConstant.TwoHandedSwordBaseMultiplier,
|
||||||
|
WeaponType.Bow => GameplayEquilibriumConstant.BowBaseMultiplier,
|
||||||
|
WeaponType.Pistol => GameplayEquilibriumConstant.PistolBaseMultiplier,
|
||||||
|
WeaponType.Rifle => GameplayEquilibriumConstant.RifleBaseMultiplier,
|
||||||
|
WeaponType.DualDaggers => GameplayEquilibriumConstant.DualDaggersBaseMultiplier,
|
||||||
|
WeaponType.Talisman => GameplayEquilibriumConstant.TalismanBaseMultiplier,
|
||||||
|
WeaponType.Staff => GameplayEquilibriumConstant.StaffBaseMultiplier,
|
||||||
|
WeaponType.Polearm => GameplayEquilibriumConstant.PolearmBaseMultiplier,
|
||||||
|
WeaponType.Gauntlet => GameplayEquilibriumConstant.GauntletBaseMultiplier,
|
||||||
|
WeaponType.HiddenWeapon => GameplayEquilibriumConstant.HiddenWeaponBaseMultiplier,
|
||||||
|
_ => 1.0
|
||||||
|
};
|
||||||
|
double levelBonus = Character.EquipSlot.Weapon.WeaponType switch
|
||||||
|
{
|
||||||
|
WeaponType.OneHandedSword => GameplayEquilibriumConstant.OneHandedSwordLevelBonus,
|
||||||
|
WeaponType.TwoHandedSword => GameplayEquilibriumConstant.TwoHandedSwordLevelBonus,
|
||||||
|
WeaponType.Bow => GameplayEquilibriumConstant.BowLevelBonus,
|
||||||
|
WeaponType.Pistol => GameplayEquilibriumConstant.PistolLevelBonus,
|
||||||
|
WeaponType.Rifle => GameplayEquilibriumConstant.RifleLevelBonus,
|
||||||
|
WeaponType.DualDaggers => GameplayEquilibriumConstant.DualDaggersLevelBonus,
|
||||||
|
WeaponType.Staff => GameplayEquilibriumConstant.StaffLevelBonus,
|
||||||
|
WeaponType.Polearm => GameplayEquilibriumConstant.PolearmLevelBonus,
|
||||||
|
WeaponType.Gauntlet => GameplayEquilibriumConstant.GauntletLevelBonus,
|
||||||
|
WeaponType.HiddenWeapon => GameplayEquilibriumConstant.HiddenWeaponLevelBonus,
|
||||||
|
_ => 0.05
|
||||||
|
};
|
||||||
|
baseMultiplier += levelBonus * (Level - 1);
|
||||||
|
}
|
||||||
|
return baseMultiplier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 普通攻击的伤害
|
/// 普通攻击的伤害
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double Damage => Character.ATK * (1.0 + 0.05 * (Level - 1));
|
public double Damage => Character.ATK * BaseDamageMultiplier * (1 + ExDamage2) + ExDamage;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 额外普通攻击伤害 [ 技能和物品相关 ]
|
||||||
|
/// </summary>
|
||||||
|
public double ExDamage { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 额外普通攻击伤害% [ 技能和物品相关 ]
|
||||||
|
/// </summary>
|
||||||
|
public double ExDamage2 { get; set; } = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 普通攻击等级
|
/// 普通攻击等级
|
||||||
@ -53,15 +113,60 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public MagicType MagicType => _MagicType;
|
public MagicType MagicType => _MagicType;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否可用
|
||||||
|
/// </summary>
|
||||||
|
public bool Enable { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否在持续生效,为 true 时不允许再次使用。普通攻击始终为 false
|
||||||
|
/// </summary>
|
||||||
|
public bool IsInEffect => false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 无视免疫类型
|
/// 无视免疫类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ImmuneType IgnoreImmune { get; set; } = ImmuneType.None;
|
public ImmuneType IgnoreImmune { get; set; } = ImmuneType.None;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 硬直时间
|
/// 硬直时间 [ 武器类型相关 ]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double HardnessTime { get; set; } = 10;
|
public double HardnessTime
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
double ht = 10;
|
||||||
|
if (Character.EquipSlot.Weapon != null)
|
||||||
|
{
|
||||||
|
ht = Character.EquipSlot.Weapon.WeaponType switch
|
||||||
|
{
|
||||||
|
WeaponType.OneHandedSword => GameplayEquilibriumConstant.OneHandedSwordHardness,
|
||||||
|
WeaponType.TwoHandedSword => GameplayEquilibriumConstant.TwoHandedSwordHardness,
|
||||||
|
WeaponType.Bow => GameplayEquilibriumConstant.BowHardness,
|
||||||
|
WeaponType.Pistol => GameplayEquilibriumConstant.PistolHardness,
|
||||||
|
WeaponType.Rifle => GameplayEquilibriumConstant.RifleHardness,
|
||||||
|
WeaponType.DualDaggers => GameplayEquilibriumConstant.DualDaggersHardness,
|
||||||
|
WeaponType.Talisman => GameplayEquilibriumConstant.TalismanHardness,
|
||||||
|
WeaponType.Staff => GameplayEquilibriumConstant.StaffHardness,
|
||||||
|
WeaponType.Polearm => GameplayEquilibriumConstant.PolearmHardness,
|
||||||
|
WeaponType.Gauntlet => GameplayEquilibriumConstant.GauntletHardness,
|
||||||
|
WeaponType.HiddenWeapon => GameplayEquilibriumConstant.HiddenWeaponHardness,
|
||||||
|
_ => 10,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return ht * (1 + ExHardnessTime2) + ExHardnessTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 额外硬直时间 [ 技能和物品相关 ]
|
||||||
|
/// </summary>
|
||||||
|
public double ExHardnessTime { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 额外硬直时间% [ 技能和物品相关 ]
|
||||||
|
/// </summary>
|
||||||
|
public double ExHardnessTime2 { get; set; } = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 实际硬直时间
|
/// 实际硬直时间
|
||||||
@ -83,44 +188,149 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CanSelectTeammate { get; set; } = false;
|
public bool CanSelectTeammate { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 选取所有敌对角色,优先级大于 <see cref="CanSelectTargetCount"/>
|
||||||
|
/// </summary>
|
||||||
|
public bool SelectAllEnemies { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 选取所有友方角色,优先级大于 <see cref="CanSelectTargetCount"/>,默认包含自身
|
||||||
|
/// </summary>
|
||||||
|
public bool SelectAllTeammates { get; set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 可选取的作用目标数量
|
/// 可选取的作用目标数量
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int CanSelectTargetCount { get; set; } = 1;
|
public int CanSelectTargetCount { get; set; } = 1;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 可选取的作用范围
|
/// 可选取的作用范围 [ 单位:格 ]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double CanSelectTargetRange { get; set; } = 0;
|
public int CanSelectTargetRange { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 普通攻击没有魔法消耗
|
||||||
|
/// </summary>
|
||||||
|
public double RealMPCost => 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 普通攻击没有吟唱时间
|
||||||
|
/// </summary>
|
||||||
|
public double RealCastTime => 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 普通攻击没有能量消耗
|
||||||
|
/// </summary>
|
||||||
|
public double RealEPCost => 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 普通攻击没有冷却时间
|
||||||
|
/// </summary>
|
||||||
|
public double RealCD => 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 普通攻击没有冷却时间
|
||||||
|
/// </summary>
|
||||||
|
public double CurrentCD => 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 游戏中的行动顺序表实例,使用时需要判断其是否存在
|
||||||
|
/// </summary>
|
||||||
|
public IGamingQueue? GamingQueue { get; set; } = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 绑定到特效的普通攻击扩展。键为特效,值为对应的普攻扩展对象。
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<Effect, NormalAttackOfEffect> NormalAttackOfEffects { get; } = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取可选择的目标列表
|
/// 获取可选择的目标列表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="caster"></param>
|
/// <param name="attacker"></param>
|
||||||
/// <param name="enemys"></param>
|
/// <param name="enemys"></param>
|
||||||
/// <param name="teammates"></param>
|
/// <param name="teammates"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public List<Character> GetSelectableTargets(Character caster, List<Character> enemys, List<Character> teammates)
|
public List<Character> GetSelectableTargets(Character attacker, List<Character> enemys, List<Character> teammates)
|
||||||
{
|
{
|
||||||
List<Character> selectable = [];
|
List<Character> selectable = [];
|
||||||
|
|
||||||
if (CanSelectSelf)
|
if (CanSelectSelf)
|
||||||
{
|
{
|
||||||
selectable.Add(caster);
|
selectable.Add(attacker);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CanSelectEnemy)
|
foreach (Character character in enemys)
|
||||||
{
|
{
|
||||||
selectable.AddRange(enemys);
|
if (CanSelectEnemy && ((character.ImmuneType & ImmuneType.All) != ImmuneType.All || IgnoreImmune == ImmuneType.All))
|
||||||
|
{
|
||||||
|
selectable.Add(character);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (CanSelectTeammate)
|
|
||||||
|
foreach (Character character in teammates)
|
||||||
{
|
{
|
||||||
selectable.AddRange(teammates);
|
if (CanSelectTeammate)
|
||||||
|
{
|
||||||
|
selectable.Add(character);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return selectable;
|
return selectable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 实际可选取的目标数量
|
||||||
|
/// </summary>
|
||||||
|
public int RealCanSelectTargetCount(List<Character> enemys, List<Character> teammates)
|
||||||
|
{
|
||||||
|
int count = CanSelectTargetCount;
|
||||||
|
if (SelectAllTeammates)
|
||||||
|
{
|
||||||
|
return teammates.Count + 1;
|
||||||
|
}
|
||||||
|
if (SelectAllEnemies)
|
||||||
|
{
|
||||||
|
return enemys.Count;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 选取普攻目标
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="attacker"></param>
|
||||||
|
/// <param name="enemys"></param>
|
||||||
|
/// <param name="teammates"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public List<Character> SelectTargets(Character attacker, List<Character> enemys, List<Character> teammates)
|
||||||
|
{
|
||||||
|
List<Character> tobeSelected = GetSelectableTargets(attacker, enemys, teammates);
|
||||||
|
|
||||||
|
List<Character> targets = [];
|
||||||
|
|
||||||
|
if (SelectAllTeammates || SelectAllEnemies)
|
||||||
|
{
|
||||||
|
if (SelectAllTeammates)
|
||||||
|
{
|
||||||
|
targets.AddRange(tobeSelected.Where(c => c == attacker || teammates.Contains(c)));
|
||||||
|
}
|
||||||
|
if (SelectAllEnemies)
|
||||||
|
{
|
||||||
|
targets.AddRange(tobeSelected.Where(enemys.Contains));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (tobeSelected.Count <= CanSelectTargetCount)
|
||||||
|
{
|
||||||
|
targets.AddRange(tobeSelected);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
targets.AddRange(tobeSelected.OrderBy(x => Random.Shared.Next()).Take(CanSelectTargetCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [.. targets.Distinct()];
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 对目标(或多个目标)发起普通攻击
|
/// 对目标(或多个目标)发起普通攻击
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -129,28 +339,99 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <param name="enemys"></param>
|
/// <param name="enemys"></param>
|
||||||
public void Attack(IGamingQueue queue, Character attacker, params IEnumerable<Character> enemys)
|
public void Attack(IGamingQueue queue, Character attacker, params IEnumerable<Character> enemys)
|
||||||
{
|
{
|
||||||
|
if (!Enable)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
foreach (Character enemy in enemys)
|
foreach (Character enemy in enemys)
|
||||||
{
|
{
|
||||||
if (enemy.HP > 0)
|
if (enemy.HP > 0)
|
||||||
{
|
{
|
||||||
queue.WriteLine("[ " + Character + $" ] 对 [ {enemy} ] 发起了普通攻击!");
|
queue.WriteLine($"[ {Character} ] 对 [ {enemy} ] 发起了普通攻击!");
|
||||||
double expected = Damage;
|
double expected = Damage;
|
||||||
int changeCount = 0;
|
int changeCount = 0;
|
||||||
DamageResult result = IsMagic ? queue.CalculateMagicalDamage(attacker, enemy, true, MagicType, expected, out double damage, ref changeCount) : queue.CalculatePhysicalDamage(attacker, enemy, true, expected, out damage, ref changeCount);
|
DamageResult result = IsMagic ? queue.CalculateMagicalDamage(attacker, enemy, true, MagicType, expected, out double damage, ref changeCount) : queue.CalculatePhysicalDamage(attacker, enemy, true, expected, out damage, ref changeCount);
|
||||||
queue.DamageToEnemyAsync(attacker, enemy, damage, true, IsMagic, MagicType, result);
|
queue.DamageToEnemyAsync(attacker, enemy, damage, true, IsMagic ? DamageType.Magical : DamageType.Physical, MagicType, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 修改伤害类型
|
/// 修改基础伤害类型。不一定转换成功,要看是否有特效覆盖
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="isMagic"></param>
|
/// <param name="isMagic"></param>
|
||||||
/// <param name="magicType"></param>
|
/// <param name="magicType"></param>
|
||||||
public void SetMagicType(bool isMagic, MagicType magicType)
|
/// <param name="queue"></param>
|
||||||
|
public void SetMagicType(bool? isMagic, MagicType? magicType = null, IGamingQueue? queue = null)
|
||||||
{
|
{
|
||||||
_IsMagic = isMagic;
|
_ExIsMagic = isMagic;
|
||||||
_MagicType = magicType;
|
if (isMagic.HasValue && isMagic.Value)
|
||||||
|
{
|
||||||
|
magicType ??= MagicType.None;
|
||||||
|
}
|
||||||
|
_ExMagicType = magicType;
|
||||||
|
ResolveMagicType(queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 修改伤害类型。不一定转换成功,要看是否有其他特效覆盖
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="naoe"></param>
|
||||||
|
/// <param name="queue"></param>
|
||||||
|
public void SetMagicType(NormalAttackOfEffect naoe, IGamingQueue? queue = null)
|
||||||
|
{
|
||||||
|
NormalAttackOfEffects[naoe.Effect] = naoe;
|
||||||
|
ResolveMagicType(queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除特效对伤害类型的更改
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="effect"></param>
|
||||||
|
/// <param name="queue"></param>
|
||||||
|
public void UnsetMagicType(Effect effect, IGamingQueue? queue = null)
|
||||||
|
{
|
||||||
|
NormalAttackOfEffects.Remove(effect);
|
||||||
|
ResolveMagicType(queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 计算是否是魔法伤害和当前的魔法类型
|
||||||
|
/// </summary>
|
||||||
|
internal void ResolveMagicType(IGamingQueue? queue = null)
|
||||||
|
{
|
||||||
|
bool past = _IsMagic;
|
||||||
|
MagicType pastType = _MagicType;
|
||||||
|
if (NormalAttackOfEffects.Count > 0)
|
||||||
|
{
|
||||||
|
if (NormalAttackOfEffects.Values.OrderByDescending(n => n.Priority).FirstOrDefault() is NormalAttackOfEffect naoe)
|
||||||
|
{
|
||||||
|
_IsMagic = naoe.IsMagic;
|
||||||
|
_MagicType = naoe.MagicType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (_ExIsMagic.HasValue && _ExMagicType.HasValue)
|
||||||
|
{
|
||||||
|
_IsMagic = _ExIsMagic.Value;
|
||||||
|
_MagicType = _ExMagicType.Value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_IsMagic = false;
|
||||||
|
_MagicType = MagicType.None;
|
||||||
|
if (Character.EquipSlot.Weapon != null)
|
||||||
|
{
|
||||||
|
WeaponType type = Character.EquipSlot.Weapon.WeaponType;
|
||||||
|
if (type == WeaponType.Talisman || type == WeaponType.Staff)
|
||||||
|
{
|
||||||
|
_IsMagic = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (queue != null && (past != _IsMagic || pastType != _MagicType))
|
||||||
|
{
|
||||||
|
queue.WriteLine($"[ {Character} ] 的普通攻击类型已转变为:{(_IsMagic ? CharacterSet.GetMagicDamageName(_MagicType) : "物理伤害")}!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -174,6 +455,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
|
|
||||||
builder.AppendLine($"{Name} - 等级 {Level}");
|
builder.AppendLine($"{Name} - 等级 {Level}");
|
||||||
builder.AppendLine($"描述:{Description}");
|
builder.AppendLine($"描述:{Description}");
|
||||||
|
if (GamingQueue?.Map != null) builder.AppendLine($"攻击距离:{Character.ATR}");
|
||||||
builder.AppendLine($"硬直时间:{RealHardnessTime:0.##}{(showOriginal && RealHardnessTime != HardnessTime ? $"(原始值:{HardnessTime})" : "")}");
|
builder.AppendLine($"硬直时间:{RealHardnessTime:0.##}{(showOriginal && RealHardnessTime != HardnessTime ? $"(原始值:{HardnessTime})" : "")}");
|
||||||
|
|
||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
@ -191,13 +473,34 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
private int _Level = 0;
|
private int _Level = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否是魔法伤害
|
/// 是否是魔法伤害 [ 生效型 ]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool _IsMagic = isMagic;
|
private bool _IsMagic = isMagic;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 魔法类型
|
/// 魔法类型 [ 生效型 ]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private MagicType _MagicType = magicType;
|
private MagicType _MagicType = magicType;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否是魔法伤害 [ 修改型 ]
|
||||||
|
/// </summary>
|
||||||
|
private bool? _ExIsMagic = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 魔法类型 [ 修改型 ]
|
||||||
|
/// </summary>
|
||||||
|
private MagicType? _ExMagicType = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 绑定到特效的普通攻击扩展。这个类没有 JSON 转换器支持。
|
||||||
|
/// </summary>
|
||||||
|
public class NormalAttackOfEffect(Effect effect, bool isMagic, MagicType type, int priority)
|
||||||
|
{
|
||||||
|
public Effect Effect { get; set; } = effect;
|
||||||
|
public bool IsMagic { get; set; } = isMagic;
|
||||||
|
public MagicType MagicType { get; set; } = type;
|
||||||
|
public int Priority { get; set; } = priority;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,6 +44,21 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
CanSelectTeammate = teammate;
|
CanSelectTeammate = teammate;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "allenemy":
|
||||||
|
case "allenemys":
|
||||||
|
case "allenemies":
|
||||||
|
if (bool.TryParse(args[str].ToString(), out bool allenemy))
|
||||||
|
{
|
||||||
|
SelectAllEnemies = allenemy;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "allteammate":
|
||||||
|
case "allteammates":
|
||||||
|
if (bool.TryParse(args[str].ToString(), out bool allteammate))
|
||||||
|
{
|
||||||
|
SelectAllTeammates = allteammate;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "count":
|
case "count":
|
||||||
if (int.TryParse(args[str].ToString(), out int count) && count > 0)
|
if (int.TryParse(args[str].ToString(), out int count) && count > 0)
|
||||||
{
|
{
|
||||||
@ -56,6 +71,19 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
CanSelectTargetRange = range;
|
CanSelectTargetRange = range;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "nd":
|
||||||
|
case "nondirectional":
|
||||||
|
if (bool.TryParse(args[str].ToString(), out bool nondirectional))
|
||||||
|
{
|
||||||
|
IsNonDirectional = nondirectional;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "rangetype":
|
||||||
|
if (int.TryParse(args[str].ToString(), out int rangetype) && rangetype > 0)
|
||||||
|
{
|
||||||
|
SkillRangeType = (SkillRangeType)rangetype;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "mpcost":
|
case "mpcost":
|
||||||
if (double.TryParse(args[str].ToString(), out double mpcost) && mpcost > 0)
|
if (double.TryParse(args[str].ToString(), out double mpcost) && mpcost > 0)
|
||||||
{
|
{
|
||||||
@ -69,12 +97,14 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "costall":
|
case "costall":
|
||||||
|
case "costallep":
|
||||||
if (bool.TryParse(args[str].ToString(), out bool costall) && costall)
|
if (bool.TryParse(args[str].ToString(), out bool costall) && costall)
|
||||||
{
|
{
|
||||||
CostAllEP = costall;
|
CostAllEP = costall;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "mincost":
|
case "mincost":
|
||||||
|
case "mincostep":
|
||||||
if (double.TryParse(args[str].ToString(), out double mincost) && mincost > 0)
|
if (double.TryParse(args[str].ToString(), out double mincost) && mincost > 0)
|
||||||
{
|
{
|
||||||
MinCostEP = mincost;
|
MinCostEP = mincost;
|
||||||
@ -87,12 +117,28 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "cast":
|
case "cast":
|
||||||
|
case "casttime":
|
||||||
if (double.TryParse(args[str].ToString(), out double cast) && cast > 0)
|
if (double.TryParse(args[str].ToString(), out double cast) && cast > 0)
|
||||||
{
|
{
|
||||||
CastTime = cast;
|
CastTime = cast;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case "cr":
|
||||||
|
case "castrange":
|
||||||
|
if (int.TryParse(args[str].ToString(), out int castrange) && castrange > 0)
|
||||||
|
{
|
||||||
|
CastRange = castrange;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "caw":
|
||||||
|
case "castanywhere":
|
||||||
|
if (bool.TryParse(args[str].ToString(), out bool castanywhere))
|
||||||
|
{
|
||||||
|
CastAnywhere = castanywhere;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "ht":
|
case "ht":
|
||||||
|
case "hardnesstime":
|
||||||
if (double.TryParse(args[str].ToString(), out double ht) && ht > 0)
|
if (double.TryParse(args[str].ToString(), out double ht) && ht > 0)
|
||||||
{
|
{
|
||||||
HardnessTime = ht;
|
HardnessTime = ht;
|
||||||
|
|||||||
@ -68,7 +68,6 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否是主动技能 [ 此项为高优先级 ]
|
/// 是否是主动技能 [ 此项为高优先级 ]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[InitRequired]
|
|
||||||
public bool IsActive => SkillType != SkillType.Passive;
|
public bool IsActive => SkillType != SkillType.Passive;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -84,15 +83,28 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否是爆发技 [ 此项为高优先级 ]
|
/// 是否是爆发技 [ 此项为高优先级 ]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[InitRequired]
|
|
||||||
public bool IsSuperSkill => SkillType == SkillType.SuperSkill;
|
public bool IsSuperSkill => SkillType == SkillType.SuperSkill;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否属于魔法 [ <see cref="IsActive"/> 必须为 true ],反之为战技
|
/// 是否属于魔法 [ <see cref="IsActive"/> 必须为 true ],反之为战技
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[InitRequired]
|
|
||||||
public bool IsMagic => SkillType == SkillType.Magic;
|
public bool IsMagic => SkillType == SkillType.Magic;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否无视施法距离(全图施法),魔法默认为 true,战技默认为 false
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool CastAnywhere { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 施法距离 [ 单位:格 ]
|
||||||
|
/// </summary>
|
||||||
|
[InitOptional]
|
||||||
|
public int CastRange
|
||||||
|
{
|
||||||
|
get => Math.Max(1, CastAnywhere ? (GamingQueue?.Map != null ? GamingQueue.Map.Grids.Count : 999) : _CastRange);
|
||||||
|
set => _CastRange = Math.Max(1, value);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 可选取自身
|
/// 可选取自身
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -108,15 +120,43 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual bool CanSelectTeammate { get; set; } = false;
|
public virtual bool CanSelectTeammate { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 选取所有敌对角色,优先级大于 <see cref="CanSelectTargetCount"/>
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool SelectAllEnemies { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 选取所有友方角色,优先级大于 <see cref="CanSelectTargetCount"/>,默认包含自身
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool SelectAllTeammates { get; set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 可选取的作用目标数量
|
/// 可选取的作用目标数量
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual int CanSelectTargetCount { get; set; } = 1;
|
public virtual int CanSelectTargetCount { get; set; } = 1;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 可选取的作用范围
|
/// 可选取的作用范围 [ 单位:格 ]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual double CanSelectTargetRange { get; set; } = 0;
|
public virtual int CanSelectTargetRange { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 如果为 true,表示非指向性技能,可以任意选取一个范围(<see cref="CanSelectTargetRange"/> = 0 时为单个格子)。<para/>
|
||||||
|
/// 如果为 false,表示必须选取一个角色作为目标,当 <see cref="CanSelectTargetRange"/> > 0 时,技能作用范围将根据目标位置覆盖 <see cref="SkillRangeType"/> 形状的区域;= 0 时正常选取目标。
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool IsNonDirectional { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 作用范围形状<para/>
|
||||||
|
/// <see cref="SkillRangeType.Diamond"/> - 菱形。默认的曼哈顿距离正方形<para/>
|
||||||
|
/// <see cref="SkillRangeType.Circle"/> - 圆形。基于欧几里得距离的圆形<para/>
|
||||||
|
/// <see cref="SkillRangeType.Square"/> - 正方形<para/>
|
||||||
|
/// <see cref="SkillRangeType.Line"/> - 施法者与目标之前的直线<para/>
|
||||||
|
/// <see cref="SkillRangeType.LinePass"/> - 施法者与目标所在的直线,贯穿至地图边缘<para/>
|
||||||
|
/// <see cref="SkillRangeType.Sector"/> - 扇形<para/>
|
||||||
|
/// 注意,该属性不影响选取目标的范围。选取目标的范围由 <see cref="Library.Common.Addon.GameMap"/> 决定。
|
||||||
|
/// </summary>
|
||||||
|
public virtual SkillRangeType SkillRangeType { get; set; } = SkillRangeType.Diamond;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 选取角色的条件
|
/// 选取角色的条件
|
||||||
@ -198,10 +238,20 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
[InitRequired]
|
[InitRequired]
|
||||||
public virtual double HardnessTime { get; set; } = 0;
|
public virtual double HardnessTime { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 额外硬直时间 [ 技能和物品相关 ]
|
||||||
|
/// </summary>
|
||||||
|
public double ExHardnessTime { get; set; } = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 额外硬直时间% [ 技能和物品相关 ]
|
||||||
|
/// </summary>
|
||||||
|
public double ExHardnessTime2 { get; set; } = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 实际硬直时间
|
/// 实际硬直时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double RealHardnessTime => Math.Max(0, HardnessTime * (1 - Calculation.PercentageCheck(Character?.ActionCoefficient ?? 0)));
|
public double RealHardnessTime => Math.Max(0, (HardnessTime + ExHardnessTime) * (1 + ExHardnessTime2) * (1 - Calculation.PercentageCheck(Character?.ActionCoefficient ?? 0)));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 效果列表
|
/// 效果列表
|
||||||
@ -231,6 +281,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
protected Skill(SkillType type, Character? character = null)
|
protected Skill(SkillType type, Character? character = null)
|
||||||
{
|
{
|
||||||
SkillType = type;
|
SkillType = type;
|
||||||
|
CastAnywhere = SkillType == SkillType.Magic;
|
||||||
Character = character;
|
Character = character;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,6 +319,14 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (Level > 0 && Character != null)
|
||||||
|
{
|
||||||
|
Effect[] effects = [.. Character.Effects.Where(e => e.IsInEffect)];
|
||||||
|
foreach (Effect e in effects)
|
||||||
|
{
|
||||||
|
e.OnSkillLevelUp(Character, Level);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -309,19 +368,54 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
selectable.Add(caster);
|
selectable.Add(caster);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CanSelectEnemy)
|
ImmuneType checkType = ImmuneType.Skilled | ImmuneType.All;
|
||||||
|
if (IsMagic)
|
||||||
{
|
{
|
||||||
selectable.AddRange(enemys);
|
checkType |= ImmuneType.Magical;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CanSelectTeammate)
|
foreach (Character character in enemys)
|
||||||
{
|
{
|
||||||
selectable.AddRange(teammates);
|
IEnumerable<Effect> effects = character.Effects.Where(e => e.IsInEffect);
|
||||||
|
if (CanSelectEnemy && ((character.ImmuneType & checkType) == ImmuneType.None ||
|
||||||
|
effects.Any(e => e.IgnoreImmune == ImmuneType.All || e.IgnoreImmune == ImmuneType.Skilled || (IsMagic && e.IgnoreImmune == ImmuneType.Magical))))
|
||||||
|
{
|
||||||
|
selectable.Add(character);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (Character character in teammates)
|
||||||
|
{
|
||||||
|
IEnumerable<Effect> effects = character.Effects.Where(e => e.IsInEffect);
|
||||||
|
if (CanSelectTeammate)
|
||||||
|
{
|
||||||
|
selectable.Add(character);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 其他条件
|
||||||
|
selectable = [.. selectable.Where(c => SelectTargetPredicates.All(f => f(c)))];
|
||||||
|
|
||||||
return selectable;
|
return selectable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 实际可选取的目标数量
|
||||||
|
/// </summary>
|
||||||
|
public int RealCanSelectTargetCount(List<Character> enemys, List<Character> teammates)
|
||||||
|
{
|
||||||
|
int count = CanSelectTargetCount;
|
||||||
|
if (SelectAllTeammates)
|
||||||
|
{
|
||||||
|
return teammates.Count + 1;
|
||||||
|
}
|
||||||
|
if (SelectAllEnemies)
|
||||||
|
{
|
||||||
|
return enemys.Count;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 选取技能目标
|
/// 选取技能目标
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -333,12 +427,20 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
{
|
{
|
||||||
List<Character> tobeSelected = GetSelectableTargets(caster, enemys, teammates);
|
List<Character> tobeSelected = GetSelectableTargets(caster, enemys, teammates);
|
||||||
|
|
||||||
// 筛选出符合条件的角色
|
|
||||||
tobeSelected = [.. tobeSelected.Where(c => SelectTargetPredicates.All(f => f(c)))];
|
|
||||||
|
|
||||||
List<Character> targets = [];
|
List<Character> targets = [];
|
||||||
|
|
||||||
if (tobeSelected.Count <= CanSelectTargetCount)
|
if (SelectAllTeammates || SelectAllEnemies)
|
||||||
|
{
|
||||||
|
if (SelectAllTeammates)
|
||||||
|
{
|
||||||
|
targets.AddRange(tobeSelected.Where(c => c == caster || teammates.Contains(c)));
|
||||||
|
}
|
||||||
|
if (SelectAllEnemies)
|
||||||
|
{
|
||||||
|
targets.AddRange(tobeSelected.Where(enemys.Contains));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (tobeSelected.Count <= CanSelectTargetCount)
|
||||||
{
|
{
|
||||||
targets.AddRange(tobeSelected);
|
targets.AddRange(tobeSelected);
|
||||||
}
|
}
|
||||||
@ -394,12 +496,13 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 对目标触发技能效果
|
/// 对目标触发技能效果
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="user"></param>
|
||||||
/// <param name="targets"></param>
|
/// <param name="targets"></param>
|
||||||
public void OnSkillCasted(List<Character> targets)
|
public void OnSkillCasted(User user, List<Character> targets)
|
||||||
{
|
{
|
||||||
foreach (Effect e in Effects)
|
foreach (Effect e in Effects)
|
||||||
{
|
{
|
||||||
e.OnSkillCasted(targets, Values);
|
e.OnSkillCasted(user, targets, Values);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,8 +529,10 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// 返回技能的详细说明
|
/// 返回技能的详细说明
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="showOriginal"></param>
|
/// <param name="showOriginal"></param>
|
||||||
|
/// <param name="showCD"></param>
|
||||||
|
/// <param name="showHardness"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public string GetInfo(bool showOriginal = false)
|
public string GetInfo(bool showOriginal = false, bool showCD = true, bool showHardness = true)
|
||||||
{
|
{
|
||||||
StringBuilder builder = new();
|
StringBuilder builder = new();
|
||||||
|
|
||||||
@ -451,40 +556,50 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
{
|
{
|
||||||
builder.AppendLine($"{DispelDescription}");
|
builder.AppendLine($"{DispelDescription}");
|
||||||
}
|
}
|
||||||
|
if (GamingQueue?.Map != null && SkillType != SkillType.Passive)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"施法距离:{(CastAnywhere ? "全图" : CastRange)}");
|
||||||
|
}
|
||||||
if (IsActive && (Item?.IsInGameItem ?? true))
|
if (IsActive && (Item?.IsInGameItem ?? true))
|
||||||
{
|
{
|
||||||
if (SkillType == SkillType.Item)
|
if (SkillType == SkillType.Item)
|
||||||
{
|
{
|
||||||
if (RealMPCost > 0)
|
if (RealMPCost > 0)
|
||||||
{
|
{
|
||||||
builder.AppendLine($"魔法消耗:{RealMPCost:0.##}{(showOriginal && RealMPCost != MPCost ? $"(原始值:{MPCost})" : "")}");
|
builder.AppendLine($"魔法消耗:{RealMPCost:0.##}{(showOriginal && RealMPCost != MPCost ? $"(原始值:{MPCost:0.##})" : "")}");
|
||||||
}
|
}
|
||||||
if (RealEPCost > 0)
|
if (RealEPCost > 0)
|
||||||
{
|
{
|
||||||
builder.AppendLine($"能量消耗:{RealEPCost:0.##}{(showOriginal && RealEPCost != EPCost ? $"(原始值:{EPCost})" : "")}");
|
builder.AppendLine($"能量消耗:{RealEPCost:0.##}{(showOriginal && RealEPCost != EPCost ? $"(原始值:{EPCost:0.##})" : "")}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (IsSuperSkill)
|
if (IsSuperSkill)
|
||||||
{
|
{
|
||||||
builder.AppendLine($"能量消耗:{RealEPCost:0.##}{(showOriginal && RealEPCost != EPCost ? $"(原始值:{EPCost})" : "")}");
|
builder.AppendLine($"能量消耗:{RealEPCost:0.##}{(showOriginal && RealEPCost != EPCost ? $"(原始值:{EPCost:0.##})" : "")}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (IsMagic)
|
if (IsMagic)
|
||||||
{
|
{
|
||||||
builder.AppendLine($"魔法消耗:{RealMPCost:0.##}{(showOriginal && RealMPCost != MPCost ? $"(原始值:{MPCost})" : "")}");
|
builder.AppendLine($"魔法消耗:{RealMPCost:0.##}{(showOriginal && RealMPCost != MPCost ? $"(原始值:{MPCost:0.##})" : "")}");
|
||||||
builder.AppendLine($"吟唱时间:{RealCastTime:0.##}{(showOriginal && RealCastTime != CastTime ? $"(原始值:{CastTime})" : "")}");
|
builder.AppendLine($"吟唱时间:{RealCastTime:0.##}{(showOriginal && RealCastTime != CastTime ? $"(原始值:{CastTime:0.##})" : "")}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
builder.AppendLine($"能量消耗:{RealEPCost:0.##}{(showOriginal && RealEPCost != EPCost ? $"(原始值:{EPCost})" : "")}");
|
builder.AppendLine($"能量消耗:{RealEPCost:0.##}{(showOriginal && RealEPCost != EPCost ? $"(原始值:{EPCost:0.##})" : "")}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
builder.AppendLine($"冷却时间:{RealCD:0.##}{(showOriginal && RealCD != CD ? $"(原始值:{CD})" : "")}");
|
if (showCD && CD > 0)
|
||||||
builder.AppendLine($"硬直时间:{RealHardnessTime:0.##}{(showOriginal && RealHardnessTime != HardnessTime ? $"(原始值:{HardnessTime})" : "")}");
|
{
|
||||||
|
builder.AppendLine($"冷却时间:{RealCD:0.##}{(showOriginal && RealCD != CD ? $"(原始值:{CD:0.##})" : "")}");
|
||||||
|
}
|
||||||
|
if (showHardness && HardnessTime > 0)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"硬直时间:{RealHardnessTime:0.##}{(showOriginal && RealHardnessTime != HardnessTime ? $"(原始值:{HardnessTime:0.##})" : "")}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.ToString();
|
return builder.ToString();
|
||||||
@ -496,6 +611,18 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public override string ToString() => GetInfo(true);
|
public override string ToString() => GetInfo(true);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回技能的详细说明,有选项
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="showOriginal"></param>
|
||||||
|
/// <param name="showCD"></param>
|
||||||
|
/// <param name="showHardness"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public string ToString(bool showOriginal, bool showCD, bool showHardness)
|
||||||
|
{
|
||||||
|
return GetInfo(showOriginal, showCD, showHardness);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 判断两个技能是否相同 检查Id.Name
|
/// 判断两个技能是否相同 检查Id.Name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -560,5 +687,10 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// 等级
|
/// 等级
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private int _Level = 0;
|
private int _Level = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 施法距离
|
||||||
|
/// </summary>
|
||||||
|
private int _CastRange = 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,20 @@
|
|||||||
namespace Milimoe.FunGame.Core.Entity
|
namespace Milimoe.FunGame.Core.Entity
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 技能和它的目标结构体
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="skill"></param>
|
||||||
|
/// <param name="targets"></param>
|
||||||
public struct SkillTarget(Skill skill, List<Character> targets)
|
public struct SkillTarget(Skill skill, List<Character> targets)
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 技能实例
|
||||||
|
/// </summary>
|
||||||
public Skill Skill { get; set; } = skill;
|
public Skill Skill { get; set; } = skill;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 技能的目标列表
|
||||||
|
/// </summary>
|
||||||
public List<Character> Targets { get; set; } = targets;
|
public List<Character> Targets { get; set; } = targets;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,21 +5,23 @@
|
|||||||
public double TotalDamage { get; set; } = 0;
|
public double TotalDamage { get; set; } = 0;
|
||||||
public double TotalPhysicalDamage { get; set; } = 0;
|
public double TotalPhysicalDamage { get; set; } = 0;
|
||||||
public double TotalMagicDamage { get; set; } = 0;
|
public double TotalMagicDamage { get; set; } = 0;
|
||||||
public double TotalRealDamage { get; set; } = 0;
|
public double TotalTrueDamage { get; set; } = 0;
|
||||||
public double TotalTakenDamage { get; set; } = 0;
|
public double TotalTakenDamage { get; set; } = 0;
|
||||||
public double TotalTakenPhysicalDamage { get; set; } = 0;
|
public double TotalTakenPhysicalDamage { get; set; } = 0;
|
||||||
public double TotalTakenMagicDamage { get; set; } = 0;
|
public double TotalTakenMagicDamage { get; set; } = 0;
|
||||||
public double TotalTakenRealDamage { get; set; } = 0;
|
public double TotalTakenTrueDamage { get; set; } = 0;
|
||||||
public double AvgDamage { get; set; } = 0;
|
public double AvgDamage { get; set; } = 0;
|
||||||
public double AvgPhysicalDamage { get; set; } = 0;
|
public double AvgPhysicalDamage { get; set; } = 0;
|
||||||
public double AvgMagicDamage { get; set; } = 0;
|
public double AvgMagicDamage { get; set; } = 0;
|
||||||
public double AvgRealDamage { get; set; } = 0;
|
public double AvgTrueDamage { get; set; } = 0;
|
||||||
public double AvgTakenDamage { get; set; } = 0;
|
public double AvgTakenDamage { get; set; } = 0;
|
||||||
public double AvgTakenPhysicalDamage { get; set; } = 0;
|
public double AvgTakenPhysicalDamage { get; set; } = 0;
|
||||||
public double AvgTakenMagicDamage { get; set; } = 0;
|
public double AvgTakenMagicDamage { get; set; } = 0;
|
||||||
public double AvgTakenRealDamage { get; set; } = 0;
|
public double AvgTakenTrueDamage { get; set; } = 0;
|
||||||
public double TotalHeal { get; set; } = 0;
|
public double TotalHeal { get; set; } = 0;
|
||||||
public double AvgHeal { get; set; } = 0;
|
public double AvgHeal { get; set; } = 0;
|
||||||
|
public double TotalShield { get; set; } = 0;
|
||||||
|
public double AvgShield { get; set; } = 0;
|
||||||
public int LiveRound { get; set; } = 0;
|
public int LiveRound { get; set; } = 0;
|
||||||
public int AvgLiveRound { get; set; } = 0;
|
public int AvgLiveRound { get; set; } = 0;
|
||||||
public int ActionTurn { get; set; } = 0;
|
public int ActionTurn { get; set; } = 0;
|
||||||
|
|||||||
@ -1,15 +1,15 @@
|
|||||||
namespace Milimoe.FunGame.Core.Entity
|
namespace Milimoe.FunGame.Core.Entity
|
||||||
{
|
{
|
||||||
public class GameStatistics
|
public class GameStatistics(Room Room)
|
||||||
{
|
{
|
||||||
public long Id => Room.Id;
|
public long Id => Room.Id;
|
||||||
public Room Room { get; }
|
public Room Room { get; } = Room;
|
||||||
public DateTime RecordTime { get; set; } = DateTime.Now;
|
public DateTime RecordTime { get; set; } = DateTime.Now;
|
||||||
public string Record { get; set; } = "";
|
public string Record { get; set; } = "";
|
||||||
public Dictionary<User, double> DamageStats { get; set; } = new();
|
public Dictionary<User, double> DamageStats { get; set; } = [];
|
||||||
public Dictionary<User, double> PhysicalDamageStats { get; } = new();
|
public Dictionary<User, double> PhysicalDamageStats { get; } = [];
|
||||||
public Dictionary<User, double> MagicDamageStats { get; } = new();
|
public Dictionary<User, double> MagicDamageStats { get; } = [];
|
||||||
public Dictionary<User, double> RealDamageStats { get; } = new();
|
public Dictionary<User, double> TrueDamageStats { get; } = [];
|
||||||
public double AvgDamageStats
|
public double AvgDamageStats
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -46,30 +46,25 @@
|
|||||||
return Math.Round(total / MagicDamageStats.Count, 2);
|
return Math.Round(total / MagicDamageStats.Count, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public double AvgRealDamageStats
|
public double AvgTrueDamageStats
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
double total = 0;
|
double total = 0;
|
||||||
foreach (User user in RealDamageStats.Keys)
|
foreach (User user in TrueDamageStats.Keys)
|
||||||
{
|
{
|
||||||
total += RealDamageStats[user];
|
total += TrueDamageStats[user];
|
||||||
}
|
}
|
||||||
return Math.Round(total / RealDamageStats.Count, 2);
|
return Math.Round(total / TrueDamageStats.Count, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Dictionary<User, double> KillStats { get; } = new();
|
public Dictionary<User, double> KillStats { get; } = [];
|
||||||
public Dictionary<User, Dictionary<User, int>> KillDetailStats { get; } = new(); // 子字典记录的是被击杀者以及被击杀次数
|
public Dictionary<User, Dictionary<User, int>> KillDetailStats { get; } = []; // 子字典记录的是被击杀者以及被击杀次数
|
||||||
public Dictionary<User, double> DeathStats { get; } = new();
|
public Dictionary<User, double> DeathStats { get; } = [];
|
||||||
public Dictionary<User, Dictionary<User, int>> DeathDetailStats { get; } = new(); // 子字典记录的是击杀者以及击杀次数
|
public Dictionary<User, Dictionary<User, int>> DeathDetailStats { get; } = []; // 子字典记录的是击杀者以及击杀次数
|
||||||
public Dictionary<User, long> AssistStats { get; } = new();
|
public Dictionary<User, long> AssistStats { get; } = [];
|
||||||
public Dictionary<User, double> RatingStats { get; } = new(); // 结算后的Rating
|
public Dictionary<User, double> RatingStats { get; } = []; // 结算后的Rating
|
||||||
public Dictionary<User, double> EloStats { get; } = new(); // Elo分数变化(+/-)
|
public Dictionary<User, double> EloStats { get; } = []; // Elo分数变化(+/-)
|
||||||
public Dictionary<User, string> RankStats { get; } = new(); // 结算后的Rank(非比赛前)
|
public Dictionary<User, string> RankStats { get; } = []; // 结算后的Rank(非比赛前)
|
||||||
|
|
||||||
public GameStatistics(Room Room)
|
|
||||||
{
|
|
||||||
this.Room = Room;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
public Dictionary<long, double> DamageStats { get; } = [];
|
public Dictionary<long, double> DamageStats { get; } = [];
|
||||||
public Dictionary<long, double> PhysicalDamageStats { get; } = [];
|
public Dictionary<long, double> PhysicalDamageStats { get; } = [];
|
||||||
public Dictionary<long, double> MagicDamageStats { get; } = [];
|
public Dictionary<long, double> MagicDamageStats { get; } = [];
|
||||||
public Dictionary<long, double> RealDamageStats { get; } = [];
|
public Dictionary<long, double> TrueDamageStats { get; } = [];
|
||||||
public Dictionary<long, double> AvgDamageStats
|
public Dictionary<long, double> AvgDamageStats
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -66,7 +66,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
return avgdamage;
|
return avgdamage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Dictionary<long, double> AvgRealDamageStats
|
public Dictionary<long, double> AvgTrueDamageStats
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@ -75,9 +75,9 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
{
|
{
|
||||||
long plays = Plays[key];
|
long plays = Plays[key];
|
||||||
double total = 0;
|
double total = 0;
|
||||||
if (RealDamageStats.ContainsKey(key))
|
if (TrueDamageStats.ContainsKey(key))
|
||||||
{
|
{
|
||||||
total = RealDamageStats.Values.Sum();
|
total = TrueDamageStats.Values.Sum();
|
||||||
}
|
}
|
||||||
avgdamage.Add(key, Math.Round(total / plays, 2));
|
avgdamage.Add(key, Math.Round(total / plays, 2));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,122 +0,0 @@
|
|||||||
using System.Text;
|
|
||||||
using Milimoe.FunGame.Core.Library.Common.Event;
|
|
||||||
using Milimoe.FunGame.Core.Library.Constant;
|
|
||||||
|
|
||||||
namespace Milimoe.FunGame.Core.Entity
|
|
||||||
{
|
|
||||||
public class Activity(long id, string name, DateTime startTime, DateTime endTime)
|
|
||||||
{
|
|
||||||
public long Id { get; set; } = id;
|
|
||||||
public string Name { get; set; } = name;
|
|
||||||
public DateTime StartTime { get; set; } = startTime;
|
|
||||||
public DateTime EndTime { get; set; } = endTime;
|
|
||||||
public ActivityState Status { get; private set; } = ActivityState.Future;
|
|
||||||
public HashSet<Quest> Quests { get; set; } = [];
|
|
||||||
|
|
||||||
// 事件
|
|
||||||
public event Action<ActivityEventArgs>? UserAccess;
|
|
||||||
public event Action<ActivityEventArgs>? UserGetActivityInfo;
|
|
||||||
|
|
||||||
public void UnRegisterUserAccess()
|
|
||||||
{
|
|
||||||
UserAccess = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UnRegisterUserGetActivityInfo()
|
|
||||||
{
|
|
||||||
UserGetActivityInfo = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateState()
|
|
||||||
{
|
|
||||||
ActivityState newState;
|
|
||||||
DateTime now = DateTime.Now;
|
|
||||||
DateTime upComingTime = StartTime.AddHours(-6);
|
|
||||||
|
|
||||||
if (now < upComingTime)
|
|
||||||
{
|
|
||||||
newState = ActivityState.Future;
|
|
||||||
}
|
|
||||||
else if (now >= upComingTime && now < StartTime)
|
|
||||||
{
|
|
||||||
newState = ActivityState.Upcoming;
|
|
||||||
}
|
|
||||||
else if (now >= StartTime && now < EndTime)
|
|
||||||
{
|
|
||||||
newState = ActivityState.InProgress;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
newState = ActivityState.Ended;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Status != newState)
|
|
||||||
{
|
|
||||||
Status = newState;
|
|
||||||
foreach (Quest quest in Quests)
|
|
||||||
{
|
|
||||||
if (newState == ActivityState.InProgress)
|
|
||||||
{
|
|
||||||
if (quest.Status == QuestState.NotStarted && quest.QuestType == QuestType.Progressive)
|
|
||||||
{
|
|
||||||
quest.Status = QuestState.InProgress;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (newState == ActivityState.Ended)
|
|
||||||
{
|
|
||||||
if (quest.Status == QuestState.NotStarted || quest.Status == QuestState.InProgress)
|
|
||||||
{
|
|
||||||
quest.Status = QuestState.Missed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool AllowUserAccess(long userId, long questId = 0)
|
|
||||||
{
|
|
||||||
UpdateState();
|
|
||||||
ActivityEventArgs args = new(userId, questId, this);
|
|
||||||
UserAccess?.Invoke(args);
|
|
||||||
return args.AllowAccess;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void GetActivityInfo(long userId, long questId = 0)
|
|
||||||
{
|
|
||||||
UpdateState();
|
|
||||||
ActivityEventArgs args = new(userId, questId, this);
|
|
||||||
UserGetActivityInfo?.Invoke(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ToString(bool showQuests)
|
|
||||||
{
|
|
||||||
UpdateState();
|
|
||||||
StringBuilder builder = new();
|
|
||||||
|
|
||||||
builder.AppendLine($"☆--- [{Name}] ---☆");
|
|
||||||
string status = Status switch
|
|
||||||
{
|
|
||||||
ActivityState.Future => "预告中",
|
|
||||||
ActivityState.Upcoming => "即将开始",
|
|
||||||
ActivityState.InProgress => "进行中",
|
|
||||||
_ => "已结束"
|
|
||||||
};
|
|
||||||
builder.AppendLine($"活动状态:{status}");
|
|
||||||
builder.AppendLine($"开始时间:{StartTime.ToString(General.GeneralDateTimeFormatChinese)}");
|
|
||||||
builder.AppendLine($"结束时间:{EndTime.ToString(General.GeneralDateTimeFormatChinese)}");
|
|
||||||
|
|
||||||
if (showQuests && Quests.Count > 0)
|
|
||||||
{
|
|
||||||
builder.AppendLine("=== 任务列表 ===");
|
|
||||||
builder.AppendLine(string.Join("\r\n", Quests));
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder.ToString().Trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return ToString(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,4 +1,5 @@
|
|||||||
using Milimoe.FunGame.Core.Interface.Entity;
|
using Milimoe.FunGame.Core.Interface.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
|
||||||
namespace Milimoe.FunGame.Core.Entity
|
namespace Milimoe.FunGame.Core.Entity
|
||||||
{
|
{
|
||||||
@ -10,12 +11,19 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
public bool IsNeedApproval { get; set; } = false;
|
public bool IsNeedApproval { get; set; } = false;
|
||||||
public bool IsPublic { get; set; } = false;
|
public bool IsPublic { get; set; } = false;
|
||||||
public double ClubPoins { get; set; } = 0;
|
public double ClubPoins { get; set; } = 0;
|
||||||
public User? Master { get; set; }
|
public User Master { get; set; } = General.UnknownUserInstance;
|
||||||
public Dictionary<long, User> Admins { get; set; } = [];
|
public Dictionary<long, User> Admins { get; set; } = [];
|
||||||
public Dictionary<long, User> Members { get; set; } = [];
|
public Dictionary<long, User> Members { get; set; } = [];
|
||||||
public Dictionary<long, User> Applicants { get; set; } = [];
|
public Dictionary<long, User> Applicants { get; set; } = [];
|
||||||
|
public Dictionary<long, User> Invitees { get; set; } = [];
|
||||||
public Dictionary<long, DateTime> MemberJoinTime { get; set; } = [];
|
public Dictionary<long, DateTime> MemberJoinTime { get; set; } = [];
|
||||||
public Dictionary<long, DateTime> ApplicationTime { get; set; } = [];
|
public Dictionary<long, DateTime> ApplicationTime { get; set; } = [];
|
||||||
|
public Dictionary<long, DateTime> InvitedTime { get; set; } = [];
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{Name} [{Prefix}]";
|
||||||
|
}
|
||||||
|
|
||||||
public override bool Equals(IBaseEntity? other)
|
public override bool Equals(IBaseEntity? other)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -42,6 +42,11 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
Statistics = new(this);
|
Statistics = new(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"[ {Roomid} ] {Name}";
|
||||||
|
}
|
||||||
|
|
||||||
public override bool Equals(IBaseEntity? other)
|
public override bool Equals(IBaseEntity? other)
|
||||||
{
|
{
|
||||||
return other is Room r && r.Roomid == Roomid;
|
return other is Room r && r.Roomid == Roomid;
|
||||||
|
|||||||
@ -1,110 +0,0 @@
|
|||||||
using System.Text;
|
|
||||||
using Milimoe.FunGame.Core.Interface.Entity;
|
|
||||||
using Milimoe.FunGame.Core.Library.Constant;
|
|
||||||
|
|
||||||
namespace Milimoe.FunGame.Core.Entity
|
|
||||||
{
|
|
||||||
public class Store : BaseEntity
|
|
||||||
{
|
|
||||||
public User User { get; set; } = General.UnknownUserInstance;
|
|
||||||
public DateTime? StartTime { get; set; } = null;
|
|
||||||
public DateTime? EndTime { get; set; } = null;
|
|
||||||
public Dictionary<long, Goods> Goods { get; } = [];
|
|
||||||
|
|
||||||
public Store(string name, User? user = null)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
if (user != null)
|
|
||||||
{
|
|
||||||
User = user;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
StringBuilder builder = new();
|
|
||||||
|
|
||||||
builder.AppendLine($"☆★☆ {Name} ☆★☆");
|
|
||||||
if (StartTime.HasValue && EndTime.HasValue)
|
|
||||||
{
|
|
||||||
builder.AppendLine($"营业时间:{StartTime.Value.ToString(General.GeneralDateTimeFormatChinese)}至{EndTime.Value.ToString(General.GeneralDateTimeFormatChinese)}");
|
|
||||||
}
|
|
||||||
else if (StartTime.HasValue && !EndTime.HasValue)
|
|
||||||
{
|
|
||||||
builder.AppendLine($"开始营业时间:{StartTime.Value.ToString(General.GeneralDateTimeFormatChinese)}");
|
|
||||||
}
|
|
||||||
else if (!StartTime.HasValue && EndTime.HasValue)
|
|
||||||
{
|
|
||||||
builder.AppendLine($"停止营业时间:{EndTime.Value.ToString(General.GeneralDateTimeFormatChinese)}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
builder.AppendLine($"[ 24H ] 全年无休,永久开放");
|
|
||||||
}
|
|
||||||
builder.AppendLine($"☆--- 商品列表 ---☆");
|
|
||||||
foreach (Goods goods in Goods.Values)
|
|
||||||
{
|
|
||||||
builder.AppendLine(goods.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder.ToString().Trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddItem(Item item, int stock, string name = "", string description = "")
|
|
||||||
{
|
|
||||||
long id = Goods.Count > 0 ? Goods.Keys.Max() + 1 : 1;
|
|
||||||
if (name.Trim() == "")
|
|
||||||
{
|
|
||||||
name = item.Name;
|
|
||||||
}
|
|
||||||
if (description.Trim() == "")
|
|
||||||
{
|
|
||||||
description = item.Description;
|
|
||||||
}
|
|
||||||
Goods goods = new(id, item, stock, name, description);
|
|
||||||
goods.SetPrice(GameplayEquilibriumConstant.InGameCurrency, item.Price);
|
|
||||||
Goods.Add(id, goods);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddItems(IEnumerable<Item> items, int stock)
|
|
||||||
{
|
|
||||||
foreach (Item item in items)
|
|
||||||
{
|
|
||||||
AddItem(item, stock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetPrice(long id, string needy, double price)
|
|
||||||
{
|
|
||||||
if (Goods.TryGetValue(id, out Goods? goods) && goods != null)
|
|
||||||
{
|
|
||||||
goods.SetPrice(needy, price);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool GetPrice(long id, string needy, out double price)
|
|
||||||
{
|
|
||||||
price = 0;
|
|
||||||
if (Goods.TryGetValue(id, out Goods? goods) && goods != null)
|
|
||||||
{
|
|
||||||
return goods.GetPrice(needy, out price);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double GetPrice(long id)
|
|
||||||
{
|
|
||||||
double price = 0;
|
|
||||||
if (Goods.TryGetValue(id, out Goods? goods) && goods != null)
|
|
||||||
{
|
|
||||||
goods.GetPrice(GameplayEquilibriumConstant.InGameCurrency, out price);
|
|
||||||
}
|
|
||||||
return price;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(IBaseEntity? other)
|
|
||||||
{
|
|
||||||
return other is Store && other.GetIdName() == GetIdName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,19 +1,17 @@
|
|||||||
using Milimoe.FunGame.Core.Interface.Base;
|
namespace Milimoe.FunGame.Core.Entity
|
||||||
|
|
||||||
namespace Milimoe.FunGame.Core.Entity
|
|
||||||
{
|
{
|
||||||
public class Team(string name, IEnumerable<Character> charaters)
|
public class Team(string name, IEnumerable<Character> charaters)
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; } = Guid.Empty;
|
public Guid Id { get; set; } = Guid.Empty;
|
||||||
public string Name { get; set; } = name;
|
public string Name { get; set; } = name;
|
||||||
public List<Character> Members { get; } = new(charaters);
|
public List<Character> Members { get; } = [.. charaters];
|
||||||
public int Score { get; set; } = 0;
|
public int Score { get; set; } = 0;
|
||||||
public bool IsWinner { get; set; } = false;
|
public bool IsWinner { get; set; } = false;
|
||||||
public int Count => Members.Count;
|
public int Count => Members.Count;
|
||||||
|
|
||||||
public List<Character> GetActiveCharacters(IGamingQueue queue)
|
public List<Character> GetActiveCharacters()
|
||||||
{
|
{
|
||||||
return [.. Members.Where(queue.Queue.Contains)];
|
return [.. Members.Where(c => c.HP > 0)];
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Character> GetTeammates(Character character)
|
public List<Character> GetTeammates(Character character)
|
||||||
@ -21,9 +19,9 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
return [.. Members.Where(c => c != character)];
|
return [.. Members.Where(c => c != character)];
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Character> GetActiveTeammates(IGamingQueue queue, Character character)
|
public List<Character> GetActiveTeammates(Character character)
|
||||||
{
|
{
|
||||||
return [.. Members.Where(c => queue.Queue.Contains(c) && c != character)];
|
return [.. Members.Where(c => c.HP > 0 && c != character)];
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsOnThisTeam(Character character)
|
public bool IsOnThisTeam(Character character)
|
||||||
|
|||||||
@ -11,37 +11,57 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
public string Description { get; set; } = "";
|
public string Description { get; set; } = "";
|
||||||
public Dictionary<string, double> Prices { get; } = [];
|
public Dictionary<string, double> Prices { get; } = [];
|
||||||
public int Stock { get; set; }
|
public int Stock { get; set; }
|
||||||
|
public int Quota { get; set; }
|
||||||
|
public Dictionary<long, int> UsersBuyCount { get; } = [];
|
||||||
|
public DateTime? ExpireTime { get; set; } = null;
|
||||||
|
|
||||||
public Goods() { }
|
public Goods() { }
|
||||||
|
|
||||||
public Goods(long id, Item item, int stock, string name, string description, Dictionary<string, double>? prices = null)
|
public Goods(long id, Item item, int stock, string name, string description, Dictionary<string, double>? prices = null, int quota = 0)
|
||||||
{
|
{
|
||||||
Id = id;
|
Id = id;
|
||||||
Items.Add(item);
|
Items.Add(item);
|
||||||
Stock = stock;
|
Stock = stock;
|
||||||
|
Quota = quota;
|
||||||
Name = name;
|
Name = name;
|
||||||
Description = description;
|
Description = description;
|
||||||
if (prices != null) Prices = prices;
|
if (prices != null) Prices = prices;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Goods(long id, List<Item> items, int stock, string name, string description, Dictionary<string, double>? prices = null)
|
public Goods(long id, List<Item> items, int stock, string name, string description, Dictionary<string, double>? prices = null, int quota = 0)
|
||||||
{
|
{
|
||||||
Id = id;
|
Id = id;
|
||||||
Items = items;
|
Items = items;
|
||||||
Stock = stock;
|
Stock = stock;
|
||||||
|
Quota = quota;
|
||||||
Name = name;
|
Name = name;
|
||||||
Description = description;
|
Description = description;
|
||||||
if (prices != null) Prices = prices;
|
if (prices != null) Prices = prices;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return ToString(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToString(User? user = null)
|
||||||
{
|
{
|
||||||
StringBuilder builder = new();
|
StringBuilder builder = new();
|
||||||
builder.AppendLine($"{Id}. {Name}");
|
builder.AppendLine($"{Id}. {Name}");
|
||||||
|
if (ExpireTime.HasValue) builder.AppendLine($"限时购买:{ExpireTime.Value.ToString(General.GeneralDateTimeFormatChinese)} 截止");
|
||||||
builder.AppendLine($"商品描述:{Description}");
|
builder.AppendLine($"商品描述:{Description}");
|
||||||
builder.AppendLine($"商品售价:{(Prices.Count > 0 ? string.Join("、", Prices.Select(kv => $"{kv.Value} {kv.Key}")) : "免费")}");
|
builder.AppendLine($"商品售价:{(Prices.Count > 0 ? string.Join("、", Prices.Select(kv => $"{kv.Value} {kv.Key}")) : "免费")}");
|
||||||
builder.AppendLine($"包含物品:{string.Join("、", Items.Select(i => $"[{ItemSet.GetQualityTypeName(i.QualityType)}|{ItemSet.GetItemTypeName(i.ItemType)}] {i.Name}"))}");
|
builder.AppendLine($"包含物品:{string.Join("、", Items.Select(i => $"[{ItemSet.GetQualityTypeName(i.QualityType)}|{ItemSet.GetItemTypeName(i.ItemType)}] {i.Name}"))}");
|
||||||
builder.AppendLine($"剩余库存:{Stock}");
|
int buyCount = 0;
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
UsersBuyCount.TryGetValue(user.Id, out buyCount);
|
||||||
|
}
|
||||||
|
builder.AppendLine($"剩余库存:{(Stock == -1 ? "不限" : Stock)}(已购:{buyCount})");
|
||||||
|
if (Quota > 0)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"限购数量:{Quota}");
|
||||||
|
}
|
||||||
return builder.ToString().Trim();
|
return builder.ToString().Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
67
Entity/Trade/Market.cs
Normal file
67
Entity/Trade/Market.cs
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
using Milimoe.FunGame.Core.Interface.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
|
||||||
|
namespace Milimoe.FunGame.Core.Entity
|
||||||
|
{
|
||||||
|
public class Market : BaseEntity
|
||||||
|
{
|
||||||
|
public string Description { get; set; } = "";
|
||||||
|
public DateTime? StartTime { get; set; } = null;
|
||||||
|
public DateTime? EndTime { get; set; } = null;
|
||||||
|
public DateTime? StartTimeOfDay { get; set; } = null;
|
||||||
|
public DateTime? EndTimeOfDay { get; set; } = null;
|
||||||
|
public Dictionary<long, MarketItem> MarketItems { get; } = [];
|
||||||
|
|
||||||
|
public Market(string name)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddItem(User user, Item item, double price, int stock, string name = "")
|
||||||
|
{
|
||||||
|
if (MarketItems.Values.FirstOrDefault(m => m.Item.Id == item.Id && m.Item.Name == item.Name && m.Price == price && m.User == user.Id && m.Status == MarketItemState.Listed) is MarketItem marketItem)
|
||||||
|
{
|
||||||
|
marketItem.Stock += stock;
|
||||||
|
marketItem.Item.Price = (marketItem.Item.Price + item.Price) / marketItem.Stock;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
long id = MarketItems.Count > 0 ? MarketItems.Keys.Max() + 1 : 1;
|
||||||
|
if (name.Trim() == "")
|
||||||
|
{
|
||||||
|
name = item.Name;
|
||||||
|
}
|
||||||
|
marketItem = new()
|
||||||
|
{
|
||||||
|
Id = id,
|
||||||
|
User = user.Id,
|
||||||
|
Username = user.Username,
|
||||||
|
Item = item,
|
||||||
|
Price = price,
|
||||||
|
Stock = stock,
|
||||||
|
Name = name
|
||||||
|
};
|
||||||
|
MarketItems.Add(id, marketItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddItems(User user, Item[] items, double price)
|
||||||
|
{
|
||||||
|
for (int index = 0; index < items.Length; index++)
|
||||||
|
{
|
||||||
|
Item item = items[index];
|
||||||
|
AddItem(user, item, price, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(IBaseEntity? other)
|
||||||
|
{
|
||||||
|
return other is Market && other.GetIdName() == GetIdName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,13 +6,20 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
{
|
{
|
||||||
public class MarketItem : BaseEntity
|
public class MarketItem : BaseEntity
|
||||||
{
|
{
|
||||||
public User User { get; set; }
|
public long User { get; set; } = 0;
|
||||||
|
public string Username { get; set; } = "";
|
||||||
public Item Item { get; set; }
|
public Item Item { get; set; }
|
||||||
public double Price { get; set; } = 0;
|
public double Price { get; set; } = 0;
|
||||||
|
public int Stock { get; set; } = 0;
|
||||||
public DateTime CreateTime { get; set; } = DateTime.Now;
|
public DateTime CreateTime { get; set; } = DateTime.Now;
|
||||||
public DateTime? FinishTime { get; set; } = null;
|
public DateTime? FinishTime { get; set; } = null;
|
||||||
public MarketItemState Status { get; set; } = MarketItemState.Listed;
|
public MarketItemState Status { get; set; } = MarketItemState.Listed;
|
||||||
public User? Buyer { get; set; } = null;
|
public HashSet<long> Buyers { get; set; } = [];
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Item.Name;
|
||||||
|
}
|
||||||
|
|
||||||
public override bool Equals(IBaseEntity? other)
|
public override bool Equals(IBaseEntity? other)
|
||||||
{
|
{
|
||||||
@ -21,7 +28,6 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
|
|
||||||
public MarketItem()
|
public MarketItem()
|
||||||
{
|
{
|
||||||
User = Factory.GetUser();
|
|
||||||
Item = Factory.GetItem();
|
Item = Factory.GetItem();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
200
Entity/Trade/Store.cs
Normal file
200
Entity/Trade/Store.cs
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
using System.Text;
|
||||||
|
using Milimoe.FunGame.Core.Interface.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
|
||||||
|
namespace Milimoe.FunGame.Core.Entity
|
||||||
|
{
|
||||||
|
public class Store : BaseEntity
|
||||||
|
{
|
||||||
|
public User User { get; set; } = General.UnknownUserInstance;
|
||||||
|
public string Description { get; set; } = "";
|
||||||
|
public DateTime? StartTime { get; set; } = null;
|
||||||
|
public DateTime? EndTime { get; set; } = null;
|
||||||
|
public DateTime? StartTimeOfDay { get; set; } = null;
|
||||||
|
public DateTime? EndTimeOfDay { get; set; } = null;
|
||||||
|
public Dictionary<long, Goods> Goods { get; } = [];
|
||||||
|
public bool AutoRefresh { get; set; } = false;
|
||||||
|
public DateTime NextRefreshDate { get; set; } = DateTime.MinValue;
|
||||||
|
public Dictionary<long, Goods> NextRefreshGoods { get; } = [];
|
||||||
|
public int RefreshInterval { get; set; } = 1; // Days
|
||||||
|
public bool GetNewerGoodsOnVisiting { get; set; } = false;
|
||||||
|
public bool GlobalStock { get; set; } = false;
|
||||||
|
public DateTime? ExpireTime { get; set; } = null;
|
||||||
|
|
||||||
|
public Store(string name, User? user = null)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
User = user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return ToString(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToString(User? user = null)
|
||||||
|
{
|
||||||
|
StringBuilder builder = new();
|
||||||
|
|
||||||
|
builder.AppendLine($"☆★☆ {Name} ☆★☆");
|
||||||
|
if (Description != "") builder.AppendLine($"{Description}");
|
||||||
|
if (StartTime.HasValue && EndTime.HasValue)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"开放时间:{StartTime.Value.ToString(General.GeneralDateTimeFormatChinese)} 至 {EndTime.Value.ToString(General.GeneralDateTimeFormatChinese)}");
|
||||||
|
}
|
||||||
|
else if (StartTime.HasValue && !EndTime.HasValue)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"开始开放时间:{StartTime.Value.ToString(General.GeneralDateTimeFormatChinese)}");
|
||||||
|
}
|
||||||
|
else if (!StartTime.HasValue && EndTime.HasValue)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"停止开放时间:{EndTime.Value.ToString(General.GeneralDateTimeFormatChinese)}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.AppendLine($"开放时间:全年无休,永久开放");
|
||||||
|
}
|
||||||
|
if (StartTimeOfDay.HasValue && EndTimeOfDay.HasValue)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"每日营业时间:{StartTimeOfDay.Value.ToString(General.GeneralDateTimeFormatTimeOnly)} 至 {EndTimeOfDay.Value.ToString(General.GeneralDateTimeFormatTimeOnly)}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.AppendLine($"[ 24H ] 全天营业");
|
||||||
|
}
|
||||||
|
DateTime now = DateTime.Now;
|
||||||
|
TimeSpan nowTimeOfDay = now.TimeOfDay;
|
||||||
|
bool isStoreOpen = true;
|
||||||
|
bool isStoreOpenInDate = true;
|
||||||
|
if (StartTime.HasValue && StartTime.Value > now || EndTime.HasValue && EndTime.Value < now)
|
||||||
|
{
|
||||||
|
isStoreOpen = false;
|
||||||
|
isStoreOpenInDate = false;
|
||||||
|
}
|
||||||
|
if (isStoreOpen && StartTimeOfDay.HasValue && EndTimeOfDay.HasValue)
|
||||||
|
{
|
||||||
|
TimeSpan startTimeSpan = StartTimeOfDay.Value.TimeOfDay;
|
||||||
|
TimeSpan endTimeSpan = EndTimeOfDay.Value.TimeOfDay;
|
||||||
|
if (startTimeSpan <= endTimeSpan)
|
||||||
|
{
|
||||||
|
isStoreOpen = nowTimeOfDay >= startTimeSpan && nowTimeOfDay <= endTimeSpan;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
isStoreOpen = nowTimeOfDay >= startTimeSpan || nowTimeOfDay <= endTimeSpan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isStoreOpen)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"商店现在不在营业时间内。");
|
||||||
|
}
|
||||||
|
builder.AppendLine($"☆--- 商品列表 ---☆");
|
||||||
|
Goods[] goodsValid = [.. Goods.Values.Where(g => !g.ExpireTime.HasValue || g.ExpireTime.Value > DateTime.Now)];
|
||||||
|
if (!isStoreOpen || goodsValid.Length == 0)
|
||||||
|
{
|
||||||
|
builder.AppendLine("当前没有商品可供购买,过一段时间再来吧。");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (Goods goods in goodsValid)
|
||||||
|
{
|
||||||
|
builder.AppendLine(goods.ToString(user));
|
||||||
|
}
|
||||||
|
builder.AppendLine("提示:使用【商店查看+序号】查看商品详细信息,使用【商店购买+序号】购买商品(指令在 2 分钟内可用)。");
|
||||||
|
}
|
||||||
|
if (isStoreOpenInDate && AutoRefresh)
|
||||||
|
{
|
||||||
|
builder.AppendLine($"商品将在 {NextRefreshDate.ToString(General.GeneralDateTimeFormatChinese)} 刷新。");
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.ToString().Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddItem(Item item, int stock, string name = "", string description = "")
|
||||||
|
{
|
||||||
|
long id = Goods.Count > 0 ? Goods.Keys.Max() + 1 : 1;
|
||||||
|
if (name.Trim() == "")
|
||||||
|
{
|
||||||
|
name = item.Name;
|
||||||
|
}
|
||||||
|
if (description.Trim() == "")
|
||||||
|
{
|
||||||
|
description = item.Description;
|
||||||
|
}
|
||||||
|
Goods goods = new(id, item, stock, name, description);
|
||||||
|
goods.SetPrice(GameplayEquilibriumConstant.InGameCurrency, item.Price);
|
||||||
|
Goods.Add(id, goods);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddItems(IEnumerable<Item> items, int stock)
|
||||||
|
{
|
||||||
|
foreach (Item item in items)
|
||||||
|
{
|
||||||
|
AddItem(item, stock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetPrice(long id, string needy, double price)
|
||||||
|
{
|
||||||
|
if (Goods.TryGetValue(id, out Goods? goods) && goods != null)
|
||||||
|
{
|
||||||
|
goods.SetPrice(needy, price);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool GetPrice(long id, string needy, out double price)
|
||||||
|
{
|
||||||
|
price = 0;
|
||||||
|
if (Goods.TryGetValue(id, out Goods? goods) && goods != null)
|
||||||
|
{
|
||||||
|
return goods.GetPrice(needy, out price);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double GetPrice(long id)
|
||||||
|
{
|
||||||
|
double price = 0;
|
||||||
|
if (Goods.TryGetValue(id, out Goods? goods) && goods != null)
|
||||||
|
{
|
||||||
|
goods.GetPrice(GameplayEquilibriumConstant.InGameCurrency, out price);
|
||||||
|
}
|
||||||
|
return price;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateRefreshTime(DateTime? time = null)
|
||||||
|
{
|
||||||
|
if (AutoRefresh)
|
||||||
|
{
|
||||||
|
DateTime now = DateTime.Now;
|
||||||
|
time ??= NextRefreshDate;
|
||||||
|
if (now > time)
|
||||||
|
{
|
||||||
|
NextRefreshDate = time.Value.AddDays(RefreshInterval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NextRefreshDate = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyGoodsToNextRefreshGoods(Dictionary<long, Goods>? goods = null)
|
||||||
|
{
|
||||||
|
goods ??= Goods;
|
||||||
|
NextRefreshGoods.Clear();
|
||||||
|
foreach (long goodsId in goods.Keys)
|
||||||
|
{
|
||||||
|
NextRefreshGoods.Add(goodsId, goods[goodsId]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(IBaseEntity? other)
|
||||||
|
{
|
||||||
|
return other is Store && other.GetIdName() == GetIdName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,6 +7,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
public class User : BaseEntity
|
public class User : BaseEntity
|
||||||
{
|
{
|
||||||
public static readonly User Empty = new();
|
public static readonly User Empty = new();
|
||||||
|
public override string Name => Username;
|
||||||
public string Username { get; set; } = "";
|
public string Username { get; set; } = "";
|
||||||
public DateTime RegTime { get; set; }
|
public DateTime RegTime { get; set; }
|
||||||
public DateTime LastTime { get; set; }
|
public DateTime LastTime { get; set; }
|
||||||
|
|||||||
@ -1,54 +1,54 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net10.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<BaseOutputPath>bin\</BaseOutputPath>
|
<BaseOutputPath>bin\</BaseOutputPath>
|
||||||
<Company>$(Author)</Company>
|
<Company>$(Author)</Company>
|
||||||
<Authors>Project Redbud</Authors>
|
<Authors>Project Redbud</Authors>
|
||||||
<AssemblyVersion>1.0.0</AssemblyVersion>
|
<AssemblyVersion>2.0.0</AssemblyVersion>
|
||||||
<FileVersion>1.0.0</FileVersion>
|
<FileVersion>2.0.0</FileVersion>
|
||||||
<PackageOutputPath>bin</PackageOutputPath>
|
<PackageOutputPath>bin</PackageOutputPath>
|
||||||
<Title>FunGame Core</Title>
|
<Title>FunGame Core</Title>
|
||||||
<RootNamespace>Milimoe.$(MSBuildProjectName.Replace(" ", "_"))</RootNamespace>
|
<RootNamespace>Milimoe.$(MSBuildProjectName.Replace(" ", "_"))</RootNamespace>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<AssemblyName>$(MSBuildProjectName)</AssemblyName>
|
<AssemblyName>$(MSBuildProjectName)</AssemblyName>
|
||||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||||
<DocumentationFile></DocumentationFile>
|
<DocumentationFile></DocumentationFile>
|
||||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||||
<Copyright>Project Redbud and Contributors</Copyright>
|
<Copyright>©2023-Present Project Redbud and Contributors.</Copyright>
|
||||||
<PackageId>$(AssemblyName)</PackageId>
|
<PackageId>$(AssemblyName)</PackageId>
|
||||||
<Description>FunGame.Core: A C#.NET library for turn-based games.</Description>
|
<Description>FunGame.Core: A C#.NET library for turn-based games.</Description>
|
||||||
<PackageTags>game;turn-based;server;framework;dotnet;csharp;gamedev</PackageTags>
|
<PackageTags>game;turn-based;server;framework;dotnet;csharp;gamedev</PackageTags>
|
||||||
<PackageReleaseNotes>
|
<PackageReleaseNotes>
|
||||||
- Initial release candidate 1 (1.0.0-rc.1)
|
See github releases for details on the latest changes.
|
||||||
</PackageReleaseNotes>
|
</PackageReleaseNotes>
|
||||||
<RepositoryUrl>https://github.com/project-redbud/FunGame-Core</RepositoryUrl>
|
<RepositoryUrl>https://github.com/project-redbud/FunGame-Core</RepositoryUrl>
|
||||||
<PackageProjectUrl>https://github.com/project-redbud</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/project-redbud</PackageProjectUrl>
|
||||||
<PackageLicenseExpression>LGPL-3.0-or-later</PackageLicenseExpression>
|
<PackageLicenseExpression>LGPL-3.0-or-later</PackageLicenseExpression>
|
||||||
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||||
<VersionPrefix>1.0.0-rc.1</VersionPrefix>
|
<VersionPrefix>2.0.0-dev</VersionPrefix>
|
||||||
<VersionSuffix Condition="'$(VersionSuffix)' == ''">$([System.DateTime]::Now.ToString("MMdd"))</VersionSuffix>
|
<VersionSuffix Condition="'$(VersionSuffix)' == ''">$([System.DateTime]::Now.ToString("MMdd"))</VersionSuffix>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
<NoWarn>1701;1702;CS1591;CS1587;IDE0130</NoWarn>
|
<NoWarn>1701;1702;CS1591;CS1587;IDE0130</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
<DebugType>embedded</DebugType>
|
<DebugType>embedded</DebugType>
|
||||||
<NoWarn>1701;1702;CS1591;CS1587;IDE0130</NoWarn>
|
<NoWarn>1701;1702;CS1591;CS1587;IDE0130</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="README.md">
|
<None Update="README.md">
|
||||||
<Pack>True</Pack>
|
<Pack>True</Pack>
|
||||||
<PackagePath>\</PackagePath>
|
<PackagePath>\</PackagePath>
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using Milimoe.FunGame.Core.Entity;
|
using Milimoe.FunGame.Core.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Library.Common.Addon;
|
||||||
using Milimoe.FunGame.Core.Library.Constant;
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
using Milimoe.FunGame.Core.Model;
|
using Milimoe.FunGame.Core.Model;
|
||||||
|
|
||||||
@ -24,6 +25,11 @@ namespace Milimoe.FunGame.Core.Interface.Base
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<Guid, Character> Original { get; }
|
public Dictionary<Guid, Character> Original { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 参与本次游戏的所有角色列表
|
||||||
|
/// </summary>
|
||||||
|
public List<Character> AllCharacters { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当前的行动顺序
|
/// 当前的行动顺序
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -60,6 +66,11 @@ namespace Milimoe.FunGame.Core.Interface.Base
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int TotalRound { get; }
|
public int TotalRound { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 使用的地图
|
||||||
|
/// </summary>
|
||||||
|
public GameMap? Map { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 显示队列信息
|
/// 显示队列信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -79,10 +90,10 @@ namespace Milimoe.FunGame.Core.Interface.Base
|
|||||||
/// <param name="enemy"></param>
|
/// <param name="enemy"></param>
|
||||||
/// <param name="damage"></param>
|
/// <param name="damage"></param>
|
||||||
/// <param name="isNormalAttack"></param>
|
/// <param name="isNormalAttack"></param>
|
||||||
/// <param name="isMagicDamage"></param>
|
/// <param name="damageType"></param>
|
||||||
/// <param name="magicType"></param>
|
/// <param name="magicType"></param>
|
||||||
/// <param name="damageResult"></param>
|
/// <param name="damageResult"></param>
|
||||||
public Task DamageToEnemyAsync(Character actor, Character enemy, double damage, bool isNormalAttack, bool isMagicDamage = false, MagicType magicType = MagicType.None, DamageResult damageResult = DamageResult.Normal);
|
public Task DamageToEnemyAsync(Character actor, Character enemy, double damage, bool isNormalAttack, DamageType damageType = DamageType.Physical, MagicType magicType = MagicType.None, DamageResult damageResult = DamageResult.Normal);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 治疗一个目标
|
/// 治疗一个目标
|
||||||
@ -145,8 +156,30 @@ namespace Milimoe.FunGame.Core.Interface.Base
|
|||||||
/// <param name="caster"></param>
|
/// <param name="caster"></param>
|
||||||
/// <param name="enemys"></param>
|
/// <param name="enemys"></param>
|
||||||
/// <param name="teammates"></param>
|
/// <param name="teammates"></param>
|
||||||
|
/// <param name="castRange"></param>
|
||||||
|
/// <param name="desiredTargets"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Task<bool> UseItemAsync(Item item, Character caster, List<Character> enemys, List<Character> teammates);
|
public Task<bool> UseItemAsync(Item item, Character caster, List<Character> enemys, List<Character> teammates, List<Grid> castRange, List<Character>? desiredTargets = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色移动
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character"></param>
|
||||||
|
/// <param name="target"></param>
|
||||||
|
/// <param name="startGrid"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Task<bool> CharacterMoveAsync(Character character, Grid target, Grid? startGrid);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 选取移动目标
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character"></param>
|
||||||
|
/// <param name="enemys"></param>
|
||||||
|
/// <param name="teammates"></param>
|
||||||
|
/// <param name="map"></param>
|
||||||
|
/// <param name="moveRange"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Task<Grid> SelectTargetGridAsync(Character character, List<Character> enemys, List<Character> teammates, GameMap map, List<Grid> moveRange);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 选取技能目标
|
/// 选取技能目标
|
||||||
@ -155,8 +188,9 @@ namespace Milimoe.FunGame.Core.Interface.Base
|
|||||||
/// <param name="skill"></param>
|
/// <param name="skill"></param>
|
||||||
/// <param name="enemys"></param>
|
/// <param name="enemys"></param>
|
||||||
/// <param name="teammates"></param>
|
/// <param name="teammates"></param>
|
||||||
|
/// <param name="castRange"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Task<List<Character>> SelectTargetsAsync(Character caster, Skill skill, List<Character> enemys, List<Character> teammates);
|
public Task<List<Character>> SelectTargetsAsync(Character caster, Skill skill, List<Character> enemys, List<Character> teammates, List<Grid> castRange);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 选取普通攻击目标
|
/// 选取普通攻击目标
|
||||||
@ -165,8 +199,31 @@ namespace Milimoe.FunGame.Core.Interface.Base
|
|||||||
/// <param name="attack"></param>
|
/// <param name="attack"></param>
|
||||||
/// <param name="enemys"></param>
|
/// <param name="enemys"></param>
|
||||||
/// <param name="teammates"></param>
|
/// <param name="teammates"></param>
|
||||||
|
/// <param name="attackRange"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Task<List<Character>> SelectTargetsAsync(Character character, NormalAttack attack, List<Character> enemys, List<Character> teammates);
|
public Task<List<Character>> SelectTargetsAsync(Character character, NormalAttack attack, List<Character> enemys, List<Character> teammates, List<Grid> attackRange);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 判断目标对于某个角色是否是队友
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character"></param>
|
||||||
|
/// <param name="target"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool IsTeammate(Character character, Character target);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取目标对于某个角色是否是队友的字典
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character"></param>
|
||||||
|
/// <param name="targets"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Dictionary<Character, bool> GetIsTeammateDictionary(Character character, IEnumerable<Character> targets);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置角色为 AI 控制
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public void SetCharactersToAIControl(bool bySystem = true, bool cancel = false, params IEnumerable<Character> characters);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 检查角色是否在 AI 控制状态
|
/// 检查角色是否在 AI 控制状态
|
||||||
@ -182,5 +239,15 @@ namespace Milimoe.FunGame.Core.Interface.Base
|
|||||||
/// <param name="isPercentage">是否是百分比</param>
|
/// <param name="isPercentage">是否是百分比</param>
|
||||||
/// <param name="isCheckProtected">是否使用插队保护机制</param>
|
/// <param name="isCheckProtected">是否使用插队保护机制</param>
|
||||||
public void ChangeCharacterHardnessTime(Character character, double addValue, bool isPercentage, bool isCheckProtected);
|
public void ChangeCharacterHardnessTime(Character character, double addValue, bool isPercentage, bool isCheckProtected);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 计算角色的数据
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character"></param>
|
||||||
|
/// <param name="characterTaken"></param>
|
||||||
|
/// <param name="damage"></param>
|
||||||
|
/// <param name="damageType"></param>
|
||||||
|
/// <param name="takenDamage"></param>
|
||||||
|
public void CalculateCharacterDamageStatistics(Character character, Character characterTaken, double damage, DamageType damageType, double takenDamage = -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,10 +2,25 @@
|
|||||||
{
|
{
|
||||||
public interface IBaseEntity : IEquatable<IBaseEntity>
|
public interface IBaseEntity : IEquatable<IBaseEntity>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 实体的数字标识符
|
||||||
|
/// </summary>
|
||||||
public long Id { get; }
|
public long Id { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 实体的唯一标识符
|
||||||
|
/// </summary>
|
||||||
public Guid Guid { get; }
|
public Guid Guid { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 实体的名称
|
||||||
|
/// </summary>
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取实体的 Id.Name
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
public string GetIdName();
|
public string GetIdName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,48 @@
|
|||||||
using Milimoe.FunGame.Core.Entity;
|
using Milimoe.FunGame.Core.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Interface.Base;
|
||||||
|
|
||||||
namespace Milimoe.FunGame.Core.Interface.Entity
|
namespace Milimoe.FunGame.Core.Interface.Entity
|
||||||
{
|
{
|
||||||
public interface ISkill
|
/// <summary>
|
||||||
|
/// ISkill 是技能的通用接口,包含一些基本属性,实现类:<see cref="NormalAttack"/> 和 <see cref="Skill"/>
|
||||||
|
/// </summary>
|
||||||
|
public interface ISkill : IBaseEntity
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 所属的行动顺序表实例
|
||||||
|
/// </summary>
|
||||||
|
public IGamingQueue? GamingQueue { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 此技能所属的角色
|
||||||
|
/// </summary>
|
||||||
|
public Character? Character { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 技能描述
|
||||||
|
/// </summary>
|
||||||
|
public string Description { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 技能的通用描述
|
||||||
|
/// </summary>
|
||||||
|
public string GeneralDescription { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 技能等级,等于 0 时可以称之为尚未学习
|
||||||
|
/// </summary>
|
||||||
|
public int Level { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否可用 [ 此项为高优先级 ]
|
||||||
|
/// </summary>
|
||||||
|
public bool Enable { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 效果持续生效中 [ 此项为高优先级 ] [ 此项设置为true后不允许再次释放,防止重复释放 ]
|
||||||
|
/// </summary>
|
||||||
|
public bool IsInEffect { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 可选取自身
|
/// 可选取自身
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -18,15 +57,56 @@ namespace Milimoe.FunGame.Core.Interface.Entity
|
|||||||
/// 可选取友方角色
|
/// 可选取友方角色
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CanSelectTeammate { get; }
|
public bool CanSelectTeammate { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 选取所有敌对角色,优先级大于 <see cref="CanSelectTargetCount"/>
|
||||||
|
/// </summary>
|
||||||
|
public bool SelectAllEnemies { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 选取所有友方角色,优先级大于 <see cref="CanSelectTargetCount"/>,默认包含自身
|
||||||
|
/// </summary>
|
||||||
|
public bool SelectAllTeammates { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 可选取的作用目标数量
|
/// 可选取的作用目标数量
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int CanSelectTargetCount { get; }
|
public int CanSelectTargetCount { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 可选取的作用范围
|
/// 可选取的作用范围 [ 单位:格 ]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double CanSelectTargetRange { get; }
|
public int CanSelectTargetRange { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 实际魔法消耗 [ 魔法 ]
|
||||||
|
/// </summary>
|
||||||
|
public double RealMPCost { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 实际吟唱时间 [ 魔法 ]
|
||||||
|
/// </summary>
|
||||||
|
public double RealCastTime { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 实际能量消耗 [ 战技 ]
|
||||||
|
/// </summary>
|
||||||
|
public double RealEPCost { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 实际冷却时间
|
||||||
|
/// </summary>
|
||||||
|
public double RealCD { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 剩余冷却时间
|
||||||
|
/// </summary>
|
||||||
|
public double CurrentCD { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 实际硬直时间
|
||||||
|
/// </summary>
|
||||||
|
public double RealHardnessTime { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取可选择的目标列表
|
/// 获取可选择的目标列表
|
||||||
@ -36,5 +116,13 @@ namespace Milimoe.FunGame.Core.Interface.Entity
|
|||||||
/// <param name="teammates"></param>
|
/// <param name="teammates"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public List<Character> GetSelectableTargets(Character caster, List<Character> enemys, List<Character> teammates);
|
public List<Character> GetSelectableTargets(Character caster, List<Character> enemys, List<Character> teammates);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 实际可选取的目标数量
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="enemys"></param>
|
||||||
|
/// <param name="teammates"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public int RealCanSelectTargetCount(List<Character> enemys, List<Character> teammates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -319,13 +319,37 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon.Example
|
|||||||
|
|
||||||
public override string Author => "FunGamer";
|
public override string Author => "FunGamer";
|
||||||
|
|
||||||
public override float Length => 12.0f;
|
public override int Length => 12;
|
||||||
|
|
||||||
public override float Width => 12.0f;
|
public override int Width => 12;
|
||||||
|
|
||||||
public override float Height => 6.0f;
|
public override int Height => 6;
|
||||||
|
|
||||||
public override float Size => 4.0f;
|
public override float Size => 4.0f;
|
||||||
|
|
||||||
|
public override GameMap InitGamingQueue(IGamingQueue queue)
|
||||||
|
{
|
||||||
|
// 因为模组在模组管理器中都是单例的,所以每次游戏都需要返回一个新的地图对象给队列
|
||||||
|
GameMap map = new ExampleGameMap();
|
||||||
|
map.Load();
|
||||||
|
|
||||||
|
// 做一些绑定,以便介入游戏队列
|
||||||
|
/// 但是,传入的 queue 可能不是 <see cref="GamingQueue"/>,要做类型检查
|
||||||
|
// 不使用框架的实现时,需要地图作者与游戏队列的作者做好适配
|
||||||
|
if (queue is GamingQueue gq)
|
||||||
|
{
|
||||||
|
gq.SelectTargetGrid += Gq_SelectTargetGrid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Grid> Gq_SelectTargetGrid(GamingQueue queue, Character character, List<Character> enemys, List<Character> teammates, GameMap map, List<Grid> canMoveGrids)
|
||||||
|
{
|
||||||
|
// 介入选择,假设这里更新界面,让玩家选择目的地
|
||||||
|
await Task.CompletedTask;
|
||||||
|
return Grid.Empty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
|
using Milimoe.FunGame.Core.Api.Utility;
|
||||||
|
using Milimoe.FunGame.Core.Entity;
|
||||||
using Milimoe.FunGame.Core.Interface.Addons;
|
using Milimoe.FunGame.Core.Interface.Addons;
|
||||||
|
using Milimoe.FunGame.Core.Interface.Base;
|
||||||
|
|
||||||
namespace Milimoe.FunGame.Core.Library.Common.Addon
|
namespace Milimoe.FunGame.Core.Library.Common.Addon
|
||||||
{
|
{
|
||||||
@ -27,17 +30,17 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 长度
|
/// 长度
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract float Length { get; }
|
public abstract int Length { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 宽度
|
/// 宽度
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract float Width { get; }
|
public abstract int Width { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 高度
|
/// 高度
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract float Height { get; }
|
public abstract int Height { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 格子大小
|
/// 格子大小
|
||||||
@ -49,6 +52,16 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<long, Grid> Grids { get; } = [];
|
public Dictionary<long, Grid> Grids { get; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 格子集(基于坐标)
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<(int x, int y, int z), Grid> GridsByCoordinate { get; } = [];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 角色集
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<Character, Grid> Characters { get; } = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 使用坐标获取格子,0号格子的坐标是(0, 0),如果你还有高度的话,则是(0, 0, 0)
|
/// 使用坐标获取格子,0号格子的坐标是(0, 0),如果你还有高度的话,则是(0, 0, 0)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -56,14 +69,34 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
|
|||||||
/// <param name="y"></param>
|
/// <param name="y"></param>
|
||||||
/// <param name="z"></param>
|
/// <param name="z"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Grid this[float x, float y, float z = 0] => Grids.Values.Where(g => g.X == x && g.Y == y && g.Z == z).FirstOrDefault();
|
public Grid? this[int x, int y, int z = 0]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (GridsByCoordinate.TryGetValue((x, y, z), out Grid? grid))
|
||||||
|
{
|
||||||
|
return grid;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 使用坐标获取格子,从0号开始
|
/// 使用编号获取格子,从0号开始
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id"></param>
|
/// <param name="id"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Grid this[int id] => Grids[id];
|
public Grid? this[long id]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Grids.TryGetValue(id, out Grid? grid))
|
||||||
|
{
|
||||||
|
return grid;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加载标记
|
/// 加载标记
|
||||||
@ -87,26 +120,26 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
|
|||||||
// 地图加载后,不允许再次加载此地图
|
// 地图加载后,不允许再次加载此地图
|
||||||
IsLoaded = true;
|
IsLoaded = true;
|
||||||
// 生成格子
|
// 生成格子
|
||||||
for (float x = 0; x < Length; x++)
|
for (int x = 0; x < Length; x++)
|
||||||
{
|
{
|
||||||
for (float y = 0; y < Width; y++)
|
for (int y = 0; y < Width; y++)
|
||||||
{
|
{
|
||||||
for (float z = 0; z < Height; z++)
|
for (int z = 0; z < Height; z++)
|
||||||
{
|
{
|
||||||
Grids.Add(Grids.Count, new(Grids.Count, x, y, z));
|
Grid grid = new(Grids.Count, x, y, z);
|
||||||
|
Grids.Add(Grids.Count, grid);
|
||||||
|
GridsByCoordinate.Add((x, y, z), grid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 如果加载后需要执行代码,请重写AfterLoad方法
|
|
||||||
AfterLoad();
|
|
||||||
}
|
}
|
||||||
return IsLoaded;
|
return IsLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加载后需要做的事
|
/// 地图完全加载后需要做的事
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void AfterLoad()
|
public virtual void AfterLoad(GameModuleLoader loader, params object[] args)
|
||||||
{
|
{
|
||||||
// override
|
// override
|
||||||
}
|
}
|
||||||
@ -119,5 +152,460 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化游戏队列,要求返回一个新的地图实例,而不是 this
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="queue"></param>
|
||||||
|
public abstract GameMap InitGamingQueue(IGamingQueue queue);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取角色当前所在的格子
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Grid? GetCharacterCurrentGrid(Character character)
|
||||||
|
{
|
||||||
|
if (Characters.TryGetValue(character, out Grid? current))
|
||||||
|
{
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 强制设置角色当前所在的格子
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character"></param>
|
||||||
|
/// <param name="target"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool SetCharacterCurrentGrid(Character character, Grid target)
|
||||||
|
{
|
||||||
|
Grid? current = GetCharacterCurrentGrid(character);
|
||||||
|
current?.Characters.Remove(character);
|
||||||
|
if (Grids.ContainsValue(target))
|
||||||
|
{
|
||||||
|
target.Characters.Add(character);
|
||||||
|
Characters[character] = target;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将角色从地图中移除
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public void RemoveCharacter(Character character)
|
||||||
|
{
|
||||||
|
Grid? current = GetCharacterCurrentGrid(character);
|
||||||
|
current?.Characters.Remove(character);
|
||||||
|
Characters[character] = Grid.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取以某个格子为中心,一定范围内的格子(曼哈顿距离),只考虑同一平面的格子。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="grid"></param>
|
||||||
|
/// <param name="range"></param>
|
||||||
|
/// <param name="includeCharacter"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public virtual List<Grid> GetGridsByRange(Grid grid, int range, bool includeCharacter = false)
|
||||||
|
{
|
||||||
|
List<Grid> grids = [];
|
||||||
|
|
||||||
|
for (int dx = -range; dx <= range; ++dx)
|
||||||
|
{
|
||||||
|
for (int dy = -range; dy <= range; ++dy)
|
||||||
|
{
|
||||||
|
//限制在中心点周围范围内
|
||||||
|
if (Math.Abs(dx) + Math.Abs(dy) <= range)
|
||||||
|
{
|
||||||
|
//检查是否在棋盘范围内
|
||||||
|
int x = grid.X + dx;
|
||||||
|
int y = grid.Y + dy;
|
||||||
|
int z = grid.Z;
|
||||||
|
if (GridsByCoordinate.TryGetValue((x, y, z), out Grid? select) && select != null)
|
||||||
|
{
|
||||||
|
if (includeCharacter || select.Characters.Count == 0)
|
||||||
|
{
|
||||||
|
grids.Add(select);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return grids;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取以某个格子为中心,最远距离的格子(曼哈顿距离),只考虑同一平面的格子。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="grid"></param>
|
||||||
|
/// <param name="range"></param>
|
||||||
|
/// <param name="includeCharacter"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public virtual List<Grid> GetOuterGridsByRange(Grid grid, int range, bool includeCharacter = false)
|
||||||
|
{
|
||||||
|
List<Grid> grids = [];
|
||||||
|
|
||||||
|
if (range < 0)
|
||||||
|
{
|
||||||
|
return grids;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历以中心格子为中心的方形区域
|
||||||
|
// dx和dy的范围从 -range 到 +range
|
||||||
|
for (int dx = -range; dx <= range; ++dx)
|
||||||
|
{
|
||||||
|
for (int dy = -range; dy <= range; ++dy)
|
||||||
|
{
|
||||||
|
// 只有当曼哈顿距离恰好等于 range 时,才认为是最远距离的格子
|
||||||
|
if (Math.Abs(dx) + Math.Abs(dy) == range)
|
||||||
|
{
|
||||||
|
int x = grid.X + dx;
|
||||||
|
int y = grid.Y + dy;
|
||||||
|
int z = grid.Z; // 只考虑同一平面
|
||||||
|
|
||||||
|
// 检查格子是否存在于地图中
|
||||||
|
if (GridsByCoordinate.TryGetValue((x, y, z), out Grid? select) && select != null)
|
||||||
|
{
|
||||||
|
if (includeCharacter || select.Characters.Count == 0)
|
||||||
|
{
|
||||||
|
grids.Add(select);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return grids;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取以某个格子为中心,一定半径内的格子(圆形范围,欧几里得距离),只考虑同一平面的格子。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="grid"></param>
|
||||||
|
/// <param name="range"></param>
|
||||||
|
/// <param name="includeCharacter"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public virtual List<Grid> GetGridsByCircleRange(Grid grid, int range, bool includeCharacter = false)
|
||||||
|
{
|
||||||
|
List<Grid> grids = [];
|
||||||
|
|
||||||
|
// 预计算半径的平方
|
||||||
|
int rangeSquared = range * range;
|
||||||
|
|
||||||
|
// 遍历以中心格子为中心的区域
|
||||||
|
// 范围从 -range 到 +range,覆盖所有可能的圆形区域内的格子
|
||||||
|
for (int dx = -range; dx <= range; ++dx)
|
||||||
|
{
|
||||||
|
for (int dy = -range; dy <= range; ++dy)
|
||||||
|
{
|
||||||
|
// 计算当前格子与中心格子的欧几里得距离的平方
|
||||||
|
if ((dx * dx) + (dy * dy) <= rangeSquared)
|
||||||
|
{
|
||||||
|
int x = grid.X + dx;
|
||||||
|
int y = grid.Y + dy;
|
||||||
|
int z = grid.Z;
|
||||||
|
|
||||||
|
if (GridsByCoordinate.TryGetValue((x, y, z), out Grid? select) && select != null)
|
||||||
|
{
|
||||||
|
if (includeCharacter || select.Characters.Count == 0)
|
||||||
|
{
|
||||||
|
grids.Add(select);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return grids;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取以某个格子为中心,最远距离的格子(圆形范围,欧几里得距离),只考虑同一平面的格子。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="grid"></param>
|
||||||
|
/// <param name="range"></param>
|
||||||
|
/// <param name="includeCharacter"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public virtual List<Grid> GetOuterGridsByCircleRange(Grid grid, int range, bool includeCharacter = false)
|
||||||
|
{
|
||||||
|
List<Grid> grids = [];
|
||||||
|
|
||||||
|
// 预计算半径的平方
|
||||||
|
int rangeSquared = range * range;
|
||||||
|
|
||||||
|
// 遍历以中心格子为中心的区域
|
||||||
|
// 范围从 -range 到 +range,覆盖所有可能的圆形区域内的格子
|
||||||
|
for (int dx = -range; dx <= range; ++dx)
|
||||||
|
{
|
||||||
|
for (int dy = -range; dy <= range; ++dy)
|
||||||
|
{
|
||||||
|
// 计算当前格子与中心格子的欧几里得距离的平方
|
||||||
|
if ((dx * dx) + (dy * dy) == rangeSquared)
|
||||||
|
{
|
||||||
|
int x = grid.X + dx;
|
||||||
|
int y = grid.Y + dy;
|
||||||
|
int z = grid.Z;
|
||||||
|
|
||||||
|
if (GridsByCoordinate.TryGetValue((x, y, z), out Grid? select) && select != null)
|
||||||
|
{
|
||||||
|
if (includeCharacter || select.Characters.Count == 0)
|
||||||
|
{
|
||||||
|
grids.Add(select);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return grids;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置角色移动
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character"></param>
|
||||||
|
/// <param name="current"></param>
|
||||||
|
/// <param name="target"></param>
|
||||||
|
/// <returns>移动的步数,只算平面移动步数</returns>
|
||||||
|
public virtual int CharacterMove(Character character, Grid? current, Grid target)
|
||||||
|
{
|
||||||
|
if (current is null || current.Id < 0 || target.Id < 0 || !Grids.ContainsValue(target))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Grid? realGrid = GetCharacterCurrentGrid(character);
|
||||||
|
Grid startGrid = current;
|
||||||
|
if (realGrid != null && current.Id != realGrid.Id)
|
||||||
|
{
|
||||||
|
startGrid = realGrid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startGrid.Id == target.Id)
|
||||||
|
{
|
||||||
|
SetCharacterCurrentGrid(character, startGrid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录走到某个格子时的步数
|
||||||
|
Queue<(Grid grid, int steps)> queue = new();
|
||||||
|
// 记录已访问的格子
|
||||||
|
HashSet<long> visited = [];
|
||||||
|
|
||||||
|
// 将起始格子加入队列,步数为0,并标记为已访问
|
||||||
|
queue.Enqueue((startGrid, 0));
|
||||||
|
visited.Add(startGrid.Id);
|
||||||
|
|
||||||
|
while (queue.Count > 0)
|
||||||
|
{
|
||||||
|
var (currentGrid, currentSteps) = queue.Dequeue();
|
||||||
|
|
||||||
|
// 如果当前格子就是目标格子,则找到了最短路径
|
||||||
|
if (currentGrid.Id == target.Id)
|
||||||
|
{
|
||||||
|
realGrid?.Characters.Remove(character);
|
||||||
|
SetCharacterCurrentGrid(character, target);
|
||||||
|
return currentSteps;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义平面移动的四个方向
|
||||||
|
(int dx, int dy)[] directions = [
|
||||||
|
(0, 1), // 上
|
||||||
|
(0, -1), // 下
|
||||||
|
(1, 0), // 右
|
||||||
|
(-1, 0) // 左
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach (var (dx, dy) in directions)
|
||||||
|
{
|
||||||
|
int nextX = currentGrid.X + dx;
|
||||||
|
int nextY = currentGrid.Y + dy;
|
||||||
|
int nextZ = currentGrid.Z;
|
||||||
|
|
||||||
|
// 尝试获取相邻格子
|
||||||
|
Grid? neighborGrid = this[nextX, nextY, nextZ];
|
||||||
|
|
||||||
|
// 如果相邻格子存在且未被访问过
|
||||||
|
if (neighborGrid != null && !visited.Contains(neighborGrid.Id))
|
||||||
|
{
|
||||||
|
visited.Add(neighborGrid.Id);
|
||||||
|
queue.Enqueue((neighborGrid, currentSteps + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置角色移动。如果不能达到目标格子,则移动到离目标格子最近的一个可达格子上。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="character"></param>
|
||||||
|
/// <param name="current"></param>
|
||||||
|
/// <param name="target"></param>
|
||||||
|
/// <returns>移动的步数,只算平面移动步数</returns>
|
||||||
|
public virtual int CharacterMoveToClosestReachable(Character character, Grid? current, Grid target)
|
||||||
|
{
|
||||||
|
if (current is null || current.Id < 0 || target.Id < 0 || !Grids.ContainsValue(target))
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Grid? realGrid = GetCharacterCurrentGrid(character);
|
||||||
|
Grid startGrid = current;
|
||||||
|
if (realGrid != null && current.Id != realGrid.Id)
|
||||||
|
{
|
||||||
|
startGrid = realGrid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startGrid.Id == target.Id)
|
||||||
|
{
|
||||||
|
SetCharacterCurrentGrid(character, startGrid);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 BFS 算法探索所有可达格子,并记录它们到起点的步数
|
||||||
|
Queue<(Grid grid, int steps)> queue = new();
|
||||||
|
|
||||||
|
// 记录已访问的格子ID
|
||||||
|
HashSet<long> visited = [];
|
||||||
|
|
||||||
|
// 初始化 BFS 队列,将起始格子加入,步数为0
|
||||||
|
queue.Enqueue((startGrid, 0));
|
||||||
|
visited.Add(startGrid.Id);
|
||||||
|
|
||||||
|
Grid? bestReachableGrid = current;
|
||||||
|
int minDistanceToTarget = CalculateManhattanDistance(startGrid, target);
|
||||||
|
int stepsToBestReachable = 0;
|
||||||
|
|
||||||
|
// 定义平面移动的四个方向
|
||||||
|
(int dx, int dy)[] directions = [
|
||||||
|
(0, 1), (0, -1), (1, 0), (-1, 0)
|
||||||
|
];
|
||||||
|
|
||||||
|
while (queue.Count > 0)
|
||||||
|
{
|
||||||
|
var (currentGrid, currentSteps) = queue.Dequeue();
|
||||||
|
|
||||||
|
// 计算当前可达格子到目标格子的曼哈顿距离
|
||||||
|
int distToTarget = CalculateManhattanDistance(currentGrid, target);
|
||||||
|
|
||||||
|
// 如果当前格子比之前找到的 bestReachableGrid 更接近目标
|
||||||
|
if (distToTarget < minDistanceToTarget)
|
||||||
|
{
|
||||||
|
minDistanceToTarget = distToTarget;
|
||||||
|
bestReachableGrid = currentGrid;
|
||||||
|
stepsToBestReachable = currentSteps;
|
||||||
|
}
|
||||||
|
// 如果距离相同,优先选择到达步数更少的格子(作为一种 tie-breaking 规则)
|
||||||
|
else if (distToTarget == minDistanceToTarget && currentSteps < stepsToBestReachable)
|
||||||
|
{
|
||||||
|
bestReachableGrid = currentGrid;
|
||||||
|
stepsToBestReachable = currentSteps;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 探索相邻格子
|
||||||
|
foreach (var (dx, dy) in directions)
|
||||||
|
{
|
||||||
|
int nextX = currentGrid.X + dx;
|
||||||
|
int nextY = currentGrid.Y + dy;
|
||||||
|
int nextZ = currentGrid.Z;
|
||||||
|
|
||||||
|
Grid? neighborGrid = this[nextX, nextY, nextZ];
|
||||||
|
|
||||||
|
// 如果相邻格子存在且未被访问过
|
||||||
|
if (neighborGrid != null && !visited.Contains(neighborGrid.Id))
|
||||||
|
{
|
||||||
|
visited.Add(neighborGrid.Id);
|
||||||
|
queue.Enqueue((neighborGrid, currentSteps + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 理论上 bestReachableGrid 不会是 null,因为 current 至少是可达的
|
||||||
|
if (bestReachableGrid == null)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新角色的实际位置
|
||||||
|
realGrid?.Characters.Remove(character);
|
||||||
|
SetCharacterCurrentGrid(character, bestReachableGrid);
|
||||||
|
|
||||||
|
return stepsToBestReachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 计算两个格子之间的曼哈顿距离
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="g1"></param>
|
||||||
|
/// <param name="g2"></param>
|
||||||
|
/// <returns>两个格子之间的曼哈顿距离</returns>
|
||||||
|
public static int CalculateManhattanDistance(Grid g1, Grid g2)
|
||||||
|
{
|
||||||
|
return Math.Abs(g1.X - g2.X) + Math.Abs(g1.Y - g2.Y) + Math.Abs(g1.Z - g2.Z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在事件流逝前处理
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="timeToReduce"></param>
|
||||||
|
protected virtual void BeforeTimeElapsed(ref double timeToReduce)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在事件流逝后处理
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="timeToReduce"></param>
|
||||||
|
protected virtual void AfterTimeElapsed(ref double timeToReduce)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 时间流逝时,处理格子上的特效
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="timeToReduce"></param>
|
||||||
|
public void OnTimeElapsed(double timeToReduce)
|
||||||
|
{
|
||||||
|
BeforeTimeElapsed(ref timeToReduce);
|
||||||
|
|
||||||
|
foreach (Grid grid in Grids.Values)
|
||||||
|
{
|
||||||
|
List<Effect> effects = [.. grid.Effects];
|
||||||
|
foreach (Effect effect in effects)
|
||||||
|
{
|
||||||
|
if (effect.Durative)
|
||||||
|
{
|
||||||
|
if (effect.RemainDuration < timeToReduce)
|
||||||
|
{
|
||||||
|
// 移除特效前也完成剩余时间内的效果
|
||||||
|
effect.OnTimeElapsed(grid, effect.RemainDuration);
|
||||||
|
effect.RemainDuration = 0;
|
||||||
|
grid.Effects.Remove(effect);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
effect.RemainDuration -= timeToReduce;
|
||||||
|
effect.OnTimeElapsed(grid, timeToReduce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
effect.OnTimeElapsed(grid, timeToReduce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AfterTimeElapsed(ref timeToReduce);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using Milimoe.FunGame.Core.Api.Utility;
|
||||||
using Milimoe.FunGame.Core.Controller;
|
using Milimoe.FunGame.Core.Controller;
|
||||||
using Milimoe.FunGame.Core.Interface.Addons;
|
using Milimoe.FunGame.Core.Interface.Addons;
|
||||||
using Milimoe.FunGame.Core.Interface.Base;
|
using Milimoe.FunGame.Core.Interface.Base;
|
||||||
@ -149,7 +150,7 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 模组完全加载后需要做的事
|
/// 模组完全加载后需要做的事
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void AfterLoad(params object[] args)
|
public virtual void AfterLoad(GameModuleLoader loader, params object[] args)
|
||||||
{
|
{
|
||||||
// override
|
// override
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,8 +3,13 @@ using Milimoe.FunGame.Core.Entity;
|
|||||||
|
|
||||||
namespace Milimoe.FunGame.Core.Library.Common.Addon
|
namespace Milimoe.FunGame.Core.Library.Common.Addon
|
||||||
{
|
{
|
||||||
public struct Grid(int id, float x, float y, float z)
|
public class Grid(int id, int x, int y, int z)
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 空格子
|
||||||
|
/// </summary>
|
||||||
|
public static Grid Empty { get; } = new Grid(-1, 0, 0, 0);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 格子编号
|
/// 格子编号
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -13,31 +18,40 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 格子在地图中的x坐标
|
/// 格子在地图中的x坐标
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float X { get; } = x;
|
public int X { get; } = x;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 格子在地图中的y坐标
|
/// 格子在地图中的y坐标
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float Y { get; } = y;
|
public int Y { get; } = y;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 格子在地图中的z坐标
|
/// 格子在地图中的z坐标
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float Z { get; } = z;
|
public int Z { get; } = z;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是谁站在这格子上?
|
/// 是谁站在这格子上?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<string, Character> Characters { get; set; } = [];
|
public HashSet<Character> Characters { get; set; } = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 此格子目前受到了什么影响?或者它有什么技能…
|
/// 此格子目前受到了什么影响?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<string, Skill> Skills { get; set; } = [];
|
public HashSet<Effect> Effects { get; set; } = [];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 此格子呈现的颜色(默认为 <see cref="Color.Gray"/> )
|
/// 此格子呈现的颜色(默认为 <see cref="Color.Gray"/> )
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Color Color { get; set; } = Color.Gray;
|
public Color Color { get; set; } = Color.Gray;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 默认的字符串表示形式
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"Grid: {Id} ({X}, {Y}, {Z})";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -99,6 +99,15 @@ namespace Milimoe.FunGame.Core.Library.Common.Addon
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当 Web API 服务启动完成后触发
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public virtual void OnWebAPIStarted(params object[] objs)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 绑定事件。在<see cref="BeforeLoad"/>后触发
|
/// 绑定事件。在<see cref="BeforeLoad"/>后触发
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -77,10 +77,11 @@ namespace Milimoe.FunGame.Core.Library.Common.Architecture
|
|||||||
{
|
{
|
||||||
if (!SendingHeartBeat) _SendingHeartBeat = true;
|
if (!SendingHeartBeat) _SendingHeartBeat = true;
|
||||||
// 发送心跳包
|
// 发送心跳包
|
||||||
|
_LastHeartbeatReceived = false;
|
||||||
if (await _HTTPClient.Send(SocketMessageType.HeartBeat) == SocketResult.Success)
|
if (await _HTTPClient.Send(SocketMessageType.HeartBeat) == SocketResult.Success)
|
||||||
{
|
{
|
||||||
await Task.Delay(4 * 1000);
|
await Task.Delay(4 * 1000);
|
||||||
AddHeartBeatFaileds();
|
if (!_LastHeartbeatReceived) AddHeartBeatFaileds();
|
||||||
}
|
}
|
||||||
else AddHeartBeatFaileds();
|
else AddHeartBeatFaileds();
|
||||||
await Task.Delay(20 * 1000);
|
await Task.Delay(20 * 1000);
|
||||||
|
|||||||
@ -9,8 +9,8 @@ namespace Milimoe.FunGame.Core.Library.Common.Event
|
|||||||
public long QuestId { get; } = questId;
|
public long QuestId { get; } = questId;
|
||||||
public Activity Activity { get; } = activity;
|
public Activity Activity { get; } = activity;
|
||||||
public ActivityState ActivityState { get; } = activity.Status;
|
public ActivityState ActivityState { get; } = activity.Status;
|
||||||
public DateTime StartTime { get; } = activity.StartTime;
|
public DateTime? StartTime { get; } = activity.StartTime;
|
||||||
public DateTime EndTime { get; } = activity.EndTime;
|
public DateTime? EndTime { get; } = activity.EndTime;
|
||||||
public bool AllowAccess { get; set; } = false;
|
public bool AllowAccess { get; set; } = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
88
Library/Common/JsonConverter/ActivityConverter.cs
Normal file
88
Library/Common/JsonConverter/ActivityConverter.cs
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using Milimoe.FunGame.Core.Api.Utility;
|
||||||
|
using Milimoe.FunGame.Core.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Library.Common.Architecture;
|
||||||
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
|
||||||
|
namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
||||||
|
{
|
||||||
|
public class ActivityConverter : BaseEntityConverter<Activity>
|
||||||
|
{
|
||||||
|
public override Activity NewInstance()
|
||||||
|
{
|
||||||
|
return new Activity();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadPropertyName(ref Utf8JsonReader reader, string propertyName, JsonSerializerOptions options, ref Activity result, Dictionary<string, object> convertingContext)
|
||||||
|
{
|
||||||
|
switch (propertyName)
|
||||||
|
{
|
||||||
|
case nameof(Activity.Id):
|
||||||
|
result.Id = reader.GetInt64();
|
||||||
|
break;
|
||||||
|
case nameof(Activity.Guid):
|
||||||
|
result.Guid = NetworkUtility.JsonDeserialize<Guid>(ref reader, options);
|
||||||
|
break;
|
||||||
|
case nameof(Activity.Name):
|
||||||
|
result.Name = reader.GetString() ?? "";
|
||||||
|
break;
|
||||||
|
case nameof(Activity.Description):
|
||||||
|
result.Description = reader.GetString() ?? "";
|
||||||
|
break;
|
||||||
|
case nameof(Activity.StartTime):
|
||||||
|
string startTimeStr = reader.GetString() ?? "";
|
||||||
|
if (DateTime.TryParseExact(startTimeStr, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out DateTime startTime))
|
||||||
|
{
|
||||||
|
result.StartTime = startTime;
|
||||||
|
}
|
||||||
|
result.UpdateState();
|
||||||
|
break;
|
||||||
|
case nameof(Activity.EndTime):
|
||||||
|
string endTimeStr = reader.GetString() ?? "";
|
||||||
|
if (DateTime.TryParseExact(endTimeStr, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out DateTime endTime))
|
||||||
|
{
|
||||||
|
result.EndTime = endTime;
|
||||||
|
}
|
||||||
|
result.UpdateState();
|
||||||
|
break;
|
||||||
|
case nameof(Activity.Quests):
|
||||||
|
List<Quest> quests = NetworkUtility.JsonDeserialize<List<Quest>>(ref reader, options) ?? [];
|
||||||
|
foreach (Quest quest in quests)
|
||||||
|
{
|
||||||
|
result.Quests.Add(quest);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(Activity.Predecessor):
|
||||||
|
result.Predecessor = reader.GetInt64();
|
||||||
|
result.UpdateState();
|
||||||
|
break;
|
||||||
|
case nameof(Activity.PredecessorStatus):
|
||||||
|
result.PredecessorStatus = (ActivityState)reader.GetInt32();
|
||||||
|
result.UpdateState();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, Activity value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
writer.WriteStartObject();
|
||||||
|
|
||||||
|
writer.WriteNumber(nameof(Activity.Id), value.Id);
|
||||||
|
if (value.Guid != Guid.Empty)
|
||||||
|
{
|
||||||
|
writer.WritePropertyName(nameof(Activity.Guid));
|
||||||
|
JsonSerializer.Serialize(writer, value.Guid, options);
|
||||||
|
}
|
||||||
|
writer.WriteString(nameof(Activity.Name), value.Name);
|
||||||
|
writer.WriteString(nameof(Activity.Description), value.Description);
|
||||||
|
if (value.StartTime != null) writer.WriteString(nameof(Activity.StartTime), value.StartTime.Value.ToString(General.GeneralDateTimeFormat));
|
||||||
|
if (value.EndTime != null) writer.WriteString(nameof(Activity.EndTime), value.EndTime.Value.ToString(General.GeneralDateTimeFormat));
|
||||||
|
writer.WritePropertyName(nameof(Activity.Quests));
|
||||||
|
JsonSerializer.Serialize(writer, value.Quests, options);
|
||||||
|
writer.WriteNumber(nameof(Activity.Predecessor), value.Predecessor);
|
||||||
|
writer.WriteNumber(nameof(Activity.PredecessorStatus), (int)value.PredecessorStatus);
|
||||||
|
|
||||||
|
writer.WriteEndObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -83,6 +83,9 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
case nameof(Character.ExHPPercentage):
|
case nameof(Character.ExHPPercentage):
|
||||||
result.ExHPPercentage = reader.GetDouble();
|
result.ExHPPercentage = reader.GetDouble();
|
||||||
break;
|
break;
|
||||||
|
case nameof(Character.HasMP):
|
||||||
|
result.HasMP = reader.GetBoolean();
|
||||||
|
break;
|
||||||
case nameof(Character.InitialMP):
|
case nameof(Character.InitialMP):
|
||||||
result.InitialMP = reader.GetDouble();
|
result.InitialMP = reader.GetDouble();
|
||||||
break;
|
break;
|
||||||
@ -197,8 +200,11 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
case nameof(Character.ExCDR):
|
case nameof(Character.ExCDR):
|
||||||
result.ExCDR = reader.GetDouble();
|
result.ExCDR = reader.GetDouble();
|
||||||
break;
|
break;
|
||||||
case nameof(Character.ATR):
|
case nameof(Character.ExATR):
|
||||||
result.ATR = reader.GetDouble();
|
result.ExATR = reader.GetInt32();
|
||||||
|
break;
|
||||||
|
case nameof(Character.ExMOV):
|
||||||
|
result.ExMOV = reader.GetInt32();
|
||||||
break;
|
break;
|
||||||
case nameof(Character.ExCritRate):
|
case nameof(Character.ExCritRate):
|
||||||
result.ExCritRate = reader.GetDouble();
|
result.ExCritRate = reader.GetDouble();
|
||||||
@ -218,7 +224,10 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
case nameof(Character.NormalAttack):
|
case nameof(Character.NormalAttack):
|
||||||
NormalAttack normalAttack = NetworkUtility.JsonDeserialize<NormalAttack>(ref reader, options) ?? new NormalAttack(result);
|
NormalAttack normalAttack = NetworkUtility.JsonDeserialize<NormalAttack>(ref reader, options) ?? new NormalAttack(result);
|
||||||
result.NormalAttack.Level = normalAttack.Level;
|
result.NormalAttack.Level = normalAttack.Level;
|
||||||
result.NormalAttack.HardnessTime = normalAttack.HardnessTime;
|
result.NormalAttack.ExDamage = normalAttack.ExDamage;
|
||||||
|
result.NormalAttack.ExDamage2 = normalAttack.ExDamage2;
|
||||||
|
result.NormalAttack.ExHardnessTime = normalAttack.ExHardnessTime;
|
||||||
|
result.NormalAttack.ExHardnessTime2 = normalAttack.ExHardnessTime2;
|
||||||
result.NormalAttack.SetMagicType(normalAttack.IsMagic, normalAttack.MagicType);
|
result.NormalAttack.SetMagicType(normalAttack.IsMagic, normalAttack.MagicType);
|
||||||
break;
|
break;
|
||||||
case nameof(Character.Skills):
|
case nameof(Character.Skills):
|
||||||
@ -267,6 +276,7 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
writer.WriteNumber(nameof(Character.InitialHP), value.InitialHP);
|
writer.WriteNumber(nameof(Character.InitialHP), value.InitialHP);
|
||||||
writer.WriteNumber(nameof(Character.ExHP2), value.ExHP2);
|
writer.WriteNumber(nameof(Character.ExHP2), value.ExHP2);
|
||||||
writer.WriteNumber(nameof(Character.ExHPPercentage), value.ExHPPercentage);
|
writer.WriteNumber(nameof(Character.ExHPPercentage), value.ExHPPercentage);
|
||||||
|
writer.WriteBoolean(nameof(Character.HasMP), value.HasMP);
|
||||||
writer.WriteNumber(nameof(Character.InitialMP), value.InitialMP);
|
writer.WriteNumber(nameof(Character.InitialMP), value.InitialMP);
|
||||||
writer.WriteNumber(nameof(Character.ExMP2), value.ExMP2);
|
writer.WriteNumber(nameof(Character.ExMP2), value.ExMP2);
|
||||||
writer.WriteNumber(nameof(Character.ExMPPercentage), value.ExMPPercentage);
|
writer.WriteNumber(nameof(Character.ExMPPercentage), value.ExMPPercentage);
|
||||||
@ -305,7 +315,8 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
writer.WriteNumber(nameof(Character.ExActionCoefficient), value.ExActionCoefficient);
|
writer.WriteNumber(nameof(Character.ExActionCoefficient), value.ExActionCoefficient);
|
||||||
writer.WriteNumber(nameof(Character.ExAccelerationCoefficient), value.ExAccelerationCoefficient);
|
writer.WriteNumber(nameof(Character.ExAccelerationCoefficient), value.ExAccelerationCoefficient);
|
||||||
writer.WriteNumber(nameof(Character.ExCDR), value.ExCDR);
|
writer.WriteNumber(nameof(Character.ExCDR), value.ExCDR);
|
||||||
writer.WriteNumber(nameof(Character.ATR), value.ATR);
|
writer.WriteNumber(nameof(Character.ExATR), value.ExATR);
|
||||||
|
writer.WriteNumber(nameof(Character.ExMOV), value.ExMOV);
|
||||||
writer.WriteNumber(nameof(Character.ExCritRate), value.ExCritRate);
|
writer.WriteNumber(nameof(Character.ExCritRate), value.ExCritRate);
|
||||||
writer.WriteNumber(nameof(Character.ExCritDMG), value.ExCritDMG);
|
writer.WriteNumber(nameof(Character.ExCritDMG), value.ExCritDMG);
|
||||||
writer.WriteNumber(nameof(Character.ExEvadeRate), value.ExEvadeRate);
|
writer.WriteNumber(nameof(Character.ExEvadeRate), value.ExEvadeRate);
|
||||||
|
|||||||
@ -73,6 +73,13 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
result.Applicants[id] = new(id);
|
result.Applicants[id] = new(id);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case nameof(Club.Invitees):
|
||||||
|
List<long> invitees = NetworkUtility.JsonDeserialize<List<long>>(ref reader, options) ?? [];
|
||||||
|
foreach (long id in invitees)
|
||||||
|
{
|
||||||
|
result.Invitees[id] = new(id);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case nameof(Club.MemberJoinTime):
|
case nameof(Club.MemberJoinTime):
|
||||||
Dictionary<long, DateTime> memberJoinTime = NetworkUtility.JsonDeserialize<Dictionary<long, DateTime>>(ref reader, options) ?? [];
|
Dictionary<long, DateTime> memberJoinTime = NetworkUtility.JsonDeserialize<Dictionary<long, DateTime>>(ref reader, options) ?? [];
|
||||||
foreach (long id in memberJoinTime.Keys)
|
foreach (long id in memberJoinTime.Keys)
|
||||||
@ -87,6 +94,13 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
result.ApplicationTime[id] = applicationTime[id];
|
result.ApplicationTime[id] = applicationTime[id];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case nameof(Club.InvitedTime):
|
||||||
|
Dictionary<long, DateTime> invitedTime = NetworkUtility.JsonDeserialize<Dictionary<long, DateTime>>(ref reader, options) ?? [];
|
||||||
|
foreach (long id in invitedTime.Keys)
|
||||||
|
{
|
||||||
|
result.InvitedTime[id] = invitedTime[id];
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,10 +125,14 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
JsonSerializer.Serialize(writer, value.Members.Keys, options);
|
JsonSerializer.Serialize(writer, value.Members.Keys, options);
|
||||||
writer.WritePropertyName(nameof(Club.Applicants));
|
writer.WritePropertyName(nameof(Club.Applicants));
|
||||||
JsonSerializer.Serialize(writer, value.Applicants.Keys, options);
|
JsonSerializer.Serialize(writer, value.Applicants.Keys, options);
|
||||||
|
writer.WritePropertyName(nameof(Club.Invitees));
|
||||||
|
JsonSerializer.Serialize(writer, value.Invitees.Keys, options);
|
||||||
writer.WritePropertyName(nameof(Club.MemberJoinTime));
|
writer.WritePropertyName(nameof(Club.MemberJoinTime));
|
||||||
JsonSerializer.Serialize(writer, value.MemberJoinTime, options);
|
JsonSerializer.Serialize(writer, value.MemberJoinTime, options);
|
||||||
writer.WritePropertyName(nameof(Club.ApplicationTime));
|
writer.WritePropertyName(nameof(Club.ApplicationTime));
|
||||||
JsonSerializer.Serialize(writer, value.ApplicationTime, options);
|
JsonSerializer.Serialize(writer, value.ApplicationTime, options);
|
||||||
|
writer.WritePropertyName(nameof(Club.InvitedTime));
|
||||||
|
JsonSerializer.Serialize(writer, value.InvitedTime, options);
|
||||||
|
|
||||||
writer.WriteEndObject();
|
writer.WriteEndObject();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
using Milimoe.FunGame.Core.Api.Utility;
|
using Milimoe.FunGame.Core.Api.Utility;
|
||||||
using Milimoe.FunGame.Core.Entity;
|
using Milimoe.FunGame.Core.Entity;
|
||||||
using Milimoe.FunGame.Core.Library.Common.Architecture;
|
using Milimoe.FunGame.Core.Library.Common.Architecture;
|
||||||
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
|
||||||
namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
||||||
{
|
{
|
||||||
@ -29,6 +30,9 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
case nameof(Goods.Stock):
|
case nameof(Goods.Stock):
|
||||||
result.Stock = reader.GetInt32();
|
result.Stock = reader.GetInt32();
|
||||||
break;
|
break;
|
||||||
|
case nameof(Goods.Quota):
|
||||||
|
result.Quota = reader.GetInt32();
|
||||||
|
break;
|
||||||
case nameof(Goods.Name):
|
case nameof(Goods.Name):
|
||||||
result.Name = reader.GetString() ?? "";
|
result.Name = reader.GetString() ?? "";
|
||||||
break;
|
break;
|
||||||
@ -42,6 +46,20 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
result.Prices[needy] = prices[needy];
|
result.Prices[needy] = prices[needy];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case nameof(Goods.UsersBuyCount):
|
||||||
|
Dictionary<long, int> buyCount = NetworkUtility.JsonDeserialize<Dictionary<long, int>>(ref reader, options) ?? [];
|
||||||
|
foreach (long uid in buyCount.Keys)
|
||||||
|
{
|
||||||
|
result.UsersBuyCount[uid] = buyCount[uid];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(Store.ExpireTime):
|
||||||
|
string dateString = reader.GetString() ?? "";
|
||||||
|
if (DateTime.TryParseExact(dateString, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out DateTime time))
|
||||||
|
{
|
||||||
|
result.ExpireTime = time;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,10 +71,14 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
writer.WritePropertyName(nameof(Goods.Items));
|
writer.WritePropertyName(nameof(Goods.Items));
|
||||||
JsonSerializer.Serialize(writer, value.Items, options);
|
JsonSerializer.Serialize(writer, value.Items, options);
|
||||||
writer.WriteNumber(nameof(Goods.Stock), value.Stock);
|
writer.WriteNumber(nameof(Goods.Stock), value.Stock);
|
||||||
|
writer.WriteNumber(nameof(Goods.Quota), value.Quota);
|
||||||
writer.WriteString(nameof(Goods.Name), value.Name);
|
writer.WriteString(nameof(Goods.Name), value.Name);
|
||||||
writer.WriteString(nameof(Goods.Description), value.Description);
|
writer.WriteString(nameof(Goods.Description), value.Description);
|
||||||
writer.WritePropertyName(nameof(Goods.Prices));
|
writer.WritePropertyName(nameof(Goods.Prices));
|
||||||
JsonSerializer.Serialize(writer, value.Prices, options);
|
JsonSerializer.Serialize(writer, value.Prices, options);
|
||||||
|
writer.WritePropertyName(nameof(Goods.UsersBuyCount));
|
||||||
|
JsonSerializer.Serialize(writer, value.UsersBuyCount, options);
|
||||||
|
if (value.ExpireTime.HasValue) writer.WriteString(nameof(Goods.ExpireTime), value.ExpireTime.Value.ToString(General.GeneralDateTimeFormat));
|
||||||
|
|
||||||
writer.WriteEndObject();
|
writer.WriteEndObject();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,6 +56,9 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
case nameof(Item.IsInGameItem):
|
case nameof(Item.IsInGameItem):
|
||||||
result.IsInGameItem = reader.GetBoolean();
|
result.IsInGameItem = reader.GetBoolean();
|
||||||
break;
|
break;
|
||||||
|
case nameof(Item.IsLock):
|
||||||
|
result.IsLock = reader.GetBoolean();
|
||||||
|
break;
|
||||||
case nameof(Item.Equipable):
|
case nameof(Item.Equipable):
|
||||||
result.Equipable = reader.GetBoolean();
|
result.Equipable = reader.GetBoolean();
|
||||||
break;
|
break;
|
||||||
@ -133,6 +136,7 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
writer.WriteNumber(nameof(Item.RarityType), (int)value.RarityType);
|
writer.WriteNumber(nameof(Item.RarityType), (int)value.RarityType);
|
||||||
writer.WriteNumber(nameof(Item.RankType), (int)value.RankType);
|
writer.WriteNumber(nameof(Item.RankType), (int)value.RankType);
|
||||||
writer.WriteBoolean(nameof(Item.IsInGameItem), value.IsInGameItem);
|
writer.WriteBoolean(nameof(Item.IsInGameItem), value.IsInGameItem);
|
||||||
|
writer.WriteBoolean(nameof(Item.IsLock), value.IsLock);
|
||||||
writer.WriteBoolean(nameof(Item.Equipable), value.Equipable);
|
writer.WriteBoolean(nameof(Item.Equipable), value.Equipable);
|
||||||
writer.WriteBoolean(nameof(Item.Unequipable), value.Unequipable);
|
writer.WriteBoolean(nameof(Item.Unequipable), value.Unequipable);
|
||||||
writer.WriteNumber(nameof(Item.RemainUseTimes), value.RemainUseTimes);
|
writer.WriteNumber(nameof(Item.RemainUseTimes), value.RemainUseTimes);
|
||||||
|
|||||||
@ -36,11 +36,11 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
case nameof(MagicResistance.Element):
|
case nameof(MagicResistance.Element):
|
||||||
result.Element = reader.GetDouble();
|
result.Element = reader.GetDouble();
|
||||||
break;
|
break;
|
||||||
case nameof(MagicResistance.Fleabane):
|
case nameof(MagicResistance.Aster):
|
||||||
result.Fleabane = reader.GetDouble();
|
result.Aster = reader.GetDouble();
|
||||||
break;
|
break;
|
||||||
case nameof(MagicResistance.Particle):
|
case nameof(MagicResistance.SpatioTemporal):
|
||||||
result.Particle = reader.GetDouble();
|
result.SpatioTemporal = reader.GetDouble();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -56,8 +56,8 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
writer.WriteNumber(nameof(MagicResistance.Bright), value.Bright);
|
writer.WriteNumber(nameof(MagicResistance.Bright), value.Bright);
|
||||||
writer.WriteNumber(nameof(MagicResistance.Shadow), value.Shadow);
|
writer.WriteNumber(nameof(MagicResistance.Shadow), value.Shadow);
|
||||||
writer.WriteNumber(nameof(MagicResistance.Element), value.Element);
|
writer.WriteNumber(nameof(MagicResistance.Element), value.Element);
|
||||||
writer.WriteNumber(nameof(MagicResistance.Fleabane), value.Fleabane);
|
writer.WriteNumber(nameof(MagicResistance.Aster), value.Aster);
|
||||||
writer.WriteNumber(nameof(MagicResistance.Particle), value.Particle);
|
writer.WriteNumber(nameof(MagicResistance.SpatioTemporal), value.SpatioTemporal);
|
||||||
|
|
||||||
writer.WriteEndObject();
|
writer.WriteEndObject();
|
||||||
}
|
}
|
||||||
|
|||||||
96
Library/Common/JsonConverter/MarketConverter.cs
Normal file
96
Library/Common/JsonConverter/MarketConverter.cs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using Milimoe.FunGame.Core.Api.Utility;
|
||||||
|
using Milimoe.FunGame.Core.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Library.Common.Architecture;
|
||||||
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
|
||||||
|
namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
||||||
|
{
|
||||||
|
public class MarketConverter : BaseEntityConverter<Market>
|
||||||
|
{
|
||||||
|
public override Market NewInstance()
|
||||||
|
{
|
||||||
|
return new Market("市场");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadPropertyName(ref Utf8JsonReader reader, string propertyName, JsonSerializerOptions options, ref Market result, Dictionary<string, object> convertingContext)
|
||||||
|
{
|
||||||
|
switch (propertyName)
|
||||||
|
{
|
||||||
|
case nameof(Market.Name):
|
||||||
|
result.Name = reader.GetString() ?? "";
|
||||||
|
break;
|
||||||
|
case nameof(Market.Description):
|
||||||
|
result.Description = reader.GetString() ?? "";
|
||||||
|
break;
|
||||||
|
case nameof(Market.StartTime):
|
||||||
|
string dateString = reader.GetString() ?? "";
|
||||||
|
if (DateTime.TryParseExact(dateString, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out DateTime time))
|
||||||
|
{
|
||||||
|
result.StartTime = time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.StartTime = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(Market.EndTime):
|
||||||
|
dateString = reader.GetString() ?? "";
|
||||||
|
if (DateTime.TryParseExact(dateString, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out time))
|
||||||
|
{
|
||||||
|
result.EndTime = time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.EndTime = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(Market.StartTimeOfDay):
|
||||||
|
dateString = reader.GetString() ?? "";
|
||||||
|
if (DateTime.TryParseExact(dateString, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out time))
|
||||||
|
{
|
||||||
|
result.StartTimeOfDay = time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.StartTimeOfDay = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(Market.EndTimeOfDay):
|
||||||
|
dateString = reader.GetString() ?? "";
|
||||||
|
if (DateTime.TryParseExact(dateString, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out time))
|
||||||
|
{
|
||||||
|
result.EndTimeOfDay = time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.EndTimeOfDay = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(Market.MarketItems):
|
||||||
|
Dictionary<long, MarketItem> marketItems = NetworkUtility.JsonDeserialize<Dictionary<long, MarketItem>>(ref reader, options) ?? [];
|
||||||
|
foreach (long id in marketItems.Keys)
|
||||||
|
{
|
||||||
|
result.MarketItems[id] = marketItems[id];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, Market value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
writer.WriteStartObject();
|
||||||
|
|
||||||
|
writer.WriteString(nameof(Market.Name), value.Name);
|
||||||
|
writer.WriteString(nameof(Market.Description), value.Description);
|
||||||
|
if (value.StartTime.HasValue) writer.WriteString(nameof(Market.StartTime), value.StartTime.Value.ToString(General.GeneralDateTimeFormat));
|
||||||
|
if (value.EndTime.HasValue) writer.WriteString(nameof(Market.EndTime), value.EndTime.Value.ToString(General.GeneralDateTimeFormat));
|
||||||
|
if (value.StartTimeOfDay.HasValue) writer.WriteString(nameof(Market.StartTimeOfDay), value.StartTimeOfDay.Value.ToString(General.GeneralDateTimeFormat));
|
||||||
|
if (value.EndTimeOfDay.HasValue) writer.WriteString(nameof(Market.EndTimeOfDay), value.EndTimeOfDay.Value.ToString(General.GeneralDateTimeFormat));
|
||||||
|
writer.WritePropertyName(nameof(Market.MarketItems));
|
||||||
|
JsonSerializer.Serialize(writer, value.MarketItems, options);
|
||||||
|
|
||||||
|
writer.WriteEndObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
93
Library/Common/JsonConverter/MarketItemConverter.cs
Normal file
93
Library/Common/JsonConverter/MarketItemConverter.cs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using Milimoe.FunGame.Core.Api.Utility;
|
||||||
|
using Milimoe.FunGame.Core.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Library.Common.Architecture;
|
||||||
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
|
||||||
|
namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
||||||
|
{
|
||||||
|
public class MarketItemConverter : BaseEntityConverter<MarketItem>
|
||||||
|
{
|
||||||
|
public override MarketItem NewInstance()
|
||||||
|
{
|
||||||
|
return new MarketItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadPropertyName(ref Utf8JsonReader reader, string propertyName, JsonSerializerOptions options, ref MarketItem result, Dictionary<string, object> convertingContext)
|
||||||
|
{
|
||||||
|
switch (propertyName)
|
||||||
|
{
|
||||||
|
case nameof(MarketItem.Id):
|
||||||
|
result.Id = reader.GetInt64();
|
||||||
|
break;
|
||||||
|
case nameof(MarketItem.User):
|
||||||
|
result.User = reader.GetInt64();
|
||||||
|
break;
|
||||||
|
case nameof(MarketItem.Username):
|
||||||
|
result.Username = reader.GetString() ?? "";
|
||||||
|
break;
|
||||||
|
case nameof(MarketItem.Item):
|
||||||
|
result.Item = NetworkUtility.JsonDeserialize<Item>(ref reader, options) ?? Factory.GetItem();
|
||||||
|
break;
|
||||||
|
case nameof(MarketItem.Stock):
|
||||||
|
result.Stock = Convert.ToInt32(reader.GetInt64());
|
||||||
|
break;
|
||||||
|
case nameof(MarketItem.Name):
|
||||||
|
result.Name = reader.GetString() ?? "";
|
||||||
|
break;
|
||||||
|
case nameof(MarketItem.Price):
|
||||||
|
result.Price = reader.GetDouble();
|
||||||
|
break;
|
||||||
|
case nameof(MarketItem.CreateTime):
|
||||||
|
string dateString = reader.GetString() ?? "";
|
||||||
|
if (DateTime.TryParseExact(dateString, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out DateTime time))
|
||||||
|
{
|
||||||
|
result.CreateTime = time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.CreateTime = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(MarketItem.FinishTime):
|
||||||
|
dateString = reader.GetString() ?? "";
|
||||||
|
if (DateTime.TryParseExact(dateString, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out time))
|
||||||
|
{
|
||||||
|
result.FinishTime = time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.FinishTime = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(MarketItem.Status):
|
||||||
|
result.Status = (MarketItemState)reader.GetInt32();
|
||||||
|
break;
|
||||||
|
case nameof(MarketItem.Buyers):
|
||||||
|
result.Buyers = NetworkUtility.JsonDeserialize<HashSet<long>>(ref reader, options) ?? [];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, MarketItem value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
writer.WriteStartObject();
|
||||||
|
|
||||||
|
writer.WriteNumber(nameof(MarketItem.Id), value.Id);
|
||||||
|
writer.WriteNumber(nameof(MarketItem.User), value.User);
|
||||||
|
writer.WriteString(nameof(MarketItem.Username), value.Username);
|
||||||
|
writer.WritePropertyName(nameof(MarketItem.Item));
|
||||||
|
JsonSerializer.Serialize(writer, value.Item, options);
|
||||||
|
writer.WriteNumber(nameof(MarketItem.Stock), value.Stock);
|
||||||
|
writer.WriteString(nameof(MarketItem.Name), value.Name);
|
||||||
|
writer.WriteNumber(nameof(MarketItem.Price), value.Price);
|
||||||
|
writer.WriteString(nameof(MarketItem.CreateTime), value.CreateTime.ToString(General.GeneralDateTimeFormat));
|
||||||
|
if (value.FinishTime.HasValue) writer.WriteString(nameof(MarketItem.FinishTime), value.FinishTime.Value.ToString(General.GeneralDateTimeFormat));
|
||||||
|
writer.WriteNumber(nameof(MarketItem.Status), (int)value.Status);
|
||||||
|
writer.WritePropertyName(nameof(MarketItem.Buyers));
|
||||||
|
JsonSerializer.Serialize(writer, value.Buyers, options);
|
||||||
|
|
||||||
|
writer.WriteEndObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -20,8 +20,17 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
case nameof(NormalAttack.Level):
|
case nameof(NormalAttack.Level):
|
||||||
result.Level = reader.GetInt32();
|
result.Level = reader.GetInt32();
|
||||||
break;
|
break;
|
||||||
case nameof(NormalAttack.HardnessTime):
|
case nameof(NormalAttack.ExDamage):
|
||||||
result.HardnessTime = reader.GetDouble();
|
result.ExDamage = reader.GetDouble();
|
||||||
|
break;
|
||||||
|
case nameof(NormalAttack.ExDamage2):
|
||||||
|
result.ExDamage2 = reader.GetDouble();
|
||||||
|
break;
|
||||||
|
case nameof(NormalAttack.ExHardnessTime):
|
||||||
|
result.ExHardnessTime = reader.GetDouble();
|
||||||
|
break;
|
||||||
|
case nameof(NormalAttack.ExHardnessTime2):
|
||||||
|
result.ExHardnessTime2 = reader.GetDouble();
|
||||||
break;
|
break;
|
||||||
case nameof(NormalAttack.IsMagic):
|
case nameof(NormalAttack.IsMagic):
|
||||||
result.SetMagicType(reader.GetBoolean(), result.MagicType);
|
result.SetMagicType(reader.GetBoolean(), result.MagicType);
|
||||||
@ -40,7 +49,10 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
writer.WriteStartObject();
|
writer.WriteStartObject();
|
||||||
|
|
||||||
writer.WriteNumber(nameof(NormalAttack.Level), value.Level);
|
writer.WriteNumber(nameof(NormalAttack.Level), value.Level);
|
||||||
writer.WriteNumber(nameof(NormalAttack.HardnessTime), value.HardnessTime);
|
writer.WriteNumber(nameof(NormalAttack.ExDamage), value.ExDamage);
|
||||||
|
writer.WriteNumber(nameof(NormalAttack.ExDamage2), value.ExDamage2);
|
||||||
|
writer.WriteNumber(nameof(NormalAttack.ExHardnessTime), value.ExHardnessTime);
|
||||||
|
writer.WriteNumber(nameof(NormalAttack.ExHardnessTime2), value.ExHardnessTime2);
|
||||||
writer.WriteBoolean(nameof(NormalAttack.IsMagic), value.IsMagic);
|
writer.WriteBoolean(nameof(NormalAttack.IsMagic), value.IsMagic);
|
||||||
writer.WriteNumber(nameof(NormalAttack.MagicType), (int)value.MagicType);
|
writer.WriteNumber(nameof(NormalAttack.MagicType), (int)value.MagicType);
|
||||||
writer.WriteNumber(nameof(NormalAttack.IgnoreImmune), (int)value.IgnoreImmune);
|
writer.WriteNumber(nameof(NormalAttack.IgnoreImmune), (int)value.IgnoreImmune);
|
||||||
|
|||||||
134
Library/Common/JsonConverter/QuestConverter.cs
Normal file
134
Library/Common/JsonConverter/QuestConverter.cs
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using Milimoe.FunGame.Core.Api.Utility;
|
||||||
|
using Milimoe.FunGame.Core.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Library.Common.Architecture;
|
||||||
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
|
||||||
|
namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
||||||
|
{
|
||||||
|
public class QuestConverter : BaseEntityConverter<Quest>
|
||||||
|
{
|
||||||
|
public override Quest NewInstance()
|
||||||
|
{
|
||||||
|
return new Quest();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadPropertyName(ref Utf8JsonReader reader, string propertyName, JsonSerializerOptions options, ref Quest result, Dictionary<string, object> convertingContext)
|
||||||
|
{
|
||||||
|
switch (propertyName)
|
||||||
|
{
|
||||||
|
case nameof(Quest.Id):
|
||||||
|
result.Id = reader.GetInt64();
|
||||||
|
break;
|
||||||
|
case nameof(Quest.Guid):
|
||||||
|
result.Guid = NetworkUtility.JsonDeserialize<Guid>(ref reader, options);
|
||||||
|
break;
|
||||||
|
case nameof(Quest.Name):
|
||||||
|
result.Name = reader.GetString() ?? "";
|
||||||
|
break;
|
||||||
|
case nameof(Quest.Description):
|
||||||
|
result.Description = reader.GetString() ?? "";
|
||||||
|
break;
|
||||||
|
case nameof(Quest.Status):
|
||||||
|
result.Status = (QuestState)reader.GetInt32();
|
||||||
|
break;
|
||||||
|
case nameof(Quest.CharacterId):
|
||||||
|
result.CharacterId = reader.GetInt64();
|
||||||
|
break;
|
||||||
|
case nameof(Quest.RegionId):
|
||||||
|
result.RegionId = reader.GetInt64();
|
||||||
|
break;
|
||||||
|
case nameof(Quest.NeedyExploreCharacterName):
|
||||||
|
result.NeedyExploreCharacterName = reader.GetString() ?? "";
|
||||||
|
break;
|
||||||
|
case nameof(Quest.NeedyExploreItemName):
|
||||||
|
result.NeedyExploreItemName = reader.GetString() ?? "";
|
||||||
|
break;
|
||||||
|
case nameof(Quest.NeedyExploreEventName):
|
||||||
|
result.NeedyExploreEventName = reader.GetString() ?? "";
|
||||||
|
break;
|
||||||
|
case nameof(Quest.CreditsAward):
|
||||||
|
result.CreditsAward = reader.GetDouble();
|
||||||
|
break;
|
||||||
|
case nameof(Quest.MaterialsAward):
|
||||||
|
result.MaterialsAward = reader.GetDouble();
|
||||||
|
break;
|
||||||
|
case nameof(Quest.Awards):
|
||||||
|
List<Item> awards = NetworkUtility.JsonDeserialize<List<Item>>(ref reader, options) ?? [];
|
||||||
|
foreach (Item item in awards)
|
||||||
|
{
|
||||||
|
result.Awards.Add(item);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(Quest.AwardsCount):
|
||||||
|
Dictionary<string, int> dict = NetworkUtility.JsonDeserialize<Dictionary<string, int>>(ref reader, options) ?? [];
|
||||||
|
foreach (string key in dict.Keys)
|
||||||
|
{
|
||||||
|
result.AwardsCount[key] = dict[key];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(Quest.StartTime):
|
||||||
|
string startTimeStr = reader.GetString() ?? "";
|
||||||
|
if (DateTime.TryParseExact(startTimeStr, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out DateTime startTime))
|
||||||
|
{
|
||||||
|
result.StartTime = startTime;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(Quest.SettleTime):
|
||||||
|
string settleTimeStr = reader.GetString() ?? "";
|
||||||
|
if (DateTime.TryParseExact(settleTimeStr, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out DateTime settleTime))
|
||||||
|
{
|
||||||
|
result.SettleTime = settleTime;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(Quest.QuestType):
|
||||||
|
result.QuestType = (QuestType)reader.GetInt32();
|
||||||
|
break;
|
||||||
|
case nameof(Quest.EstimatedMinutes):
|
||||||
|
result.EstimatedMinutes = reader.GetInt32();
|
||||||
|
break;
|
||||||
|
case nameof(Quest.Progress):
|
||||||
|
result.Progress = reader.GetInt32();
|
||||||
|
break;
|
||||||
|
case nameof(Quest.MaxProgress):
|
||||||
|
result.MaxProgress = reader.GetInt32();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, Quest value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
writer.WriteStartObject();
|
||||||
|
|
||||||
|
writer.WriteNumber(nameof(Quest.Id), value.Id);
|
||||||
|
if (value.Guid != Guid.Empty)
|
||||||
|
{
|
||||||
|
writer.WritePropertyName(nameof(Quest.Guid));
|
||||||
|
JsonSerializer.Serialize(writer, value.Guid, options);
|
||||||
|
}
|
||||||
|
writer.WriteString(nameof(Quest.Name), value.Name);
|
||||||
|
writer.WriteString(nameof(Quest.Description), value.Description);
|
||||||
|
writer.WriteNumber(nameof(Quest.Status), (int)value.Status);
|
||||||
|
writer.WriteNumber(nameof(Quest.CharacterId), value.CharacterId);
|
||||||
|
writer.WriteNumber(nameof(Quest.RegionId), value.RegionId);
|
||||||
|
writer.WriteString(nameof(Quest.NeedyExploreCharacterName), value.NeedyExploreCharacterName);
|
||||||
|
writer.WriteString(nameof(Quest.NeedyExploreItemName), value.NeedyExploreItemName);
|
||||||
|
writer.WriteString(nameof(Quest.NeedyExploreEventName), value.NeedyExploreEventName);
|
||||||
|
writer.WriteNumber(nameof(Quest.CreditsAward), value.CreditsAward);
|
||||||
|
writer.WriteNumber(nameof(Quest.MaterialsAward), value.MaterialsAward);
|
||||||
|
writer.WritePropertyName(nameof(Quest.Awards));
|
||||||
|
JsonSerializer.Serialize(writer, value.Awards, options);
|
||||||
|
writer.WritePropertyName(nameof(Quest.AwardsCount));
|
||||||
|
JsonSerializer.Serialize(writer, value.AwardsCount, options);
|
||||||
|
writer.WriteString(nameof(Quest.AwardsString), value.AwardsString);
|
||||||
|
if (value.StartTime != null) writer.WriteString(nameof(Quest.StartTime), value.StartTime.Value.ToString(General.GeneralDateTimeFormat));
|
||||||
|
if (value.SettleTime != null) writer.WriteString(nameof(Quest.SettleTime), value.SettleTime.Value.ToString(General.GeneralDateTimeFormat));
|
||||||
|
writer.WriteNumber(nameof(Quest.QuestType), (int)value.QuestType);
|
||||||
|
writer.WriteNumber(nameof(Quest.EstimatedMinutes), value.EstimatedMinutes);
|
||||||
|
writer.WriteNumber(nameof(Quest.Progress), value.Progress);
|
||||||
|
writer.WriteNumber(nameof(Quest.MaxProgress), value.MaxProgress);
|
||||||
|
|
||||||
|
writer.WriteEndObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
234
Library/Common/JsonConverter/RoundRecordConverter.cs
Normal file
234
Library/Common/JsonConverter/RoundRecordConverter.cs
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using Milimoe.FunGame.Core.Api.Utility;
|
||||||
|
using Milimoe.FunGame.Core.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Library.Common.Architecture;
|
||||||
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
using Milimoe.FunGame.Core.Model;
|
||||||
|
|
||||||
|
namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
||||||
|
{
|
||||||
|
public class RoundRecordConverter : BaseEntityConverter<RoundRecord>
|
||||||
|
{
|
||||||
|
public override RoundRecord NewInstance()
|
||||||
|
{
|
||||||
|
return new RoundRecord(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ReadPropertyName(ref Utf8JsonReader reader, string propertyName, JsonSerializerOptions options, ref RoundRecord result, Dictionary<string, object> convertingContext)
|
||||||
|
{
|
||||||
|
switch (propertyName)
|
||||||
|
{
|
||||||
|
case nameof(RoundRecord.Round):
|
||||||
|
result.Round = reader.GetInt32();
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.Actor):
|
||||||
|
result.Actor = NetworkUtility.JsonDeserialize<Character>(ref reader, options) ?? Factory.GetCharacter();
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.Targets):
|
||||||
|
List<Character> targets = NetworkUtility.JsonDeserialize<List<Character>>(ref reader, options) ?? [];
|
||||||
|
result.Targets.AddRange(targets);
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.Damages):
|
||||||
|
Dictionary<Guid, double> damagesGuid = NetworkUtility.JsonDeserialize<Dictionary<Guid, double>>(ref reader, options) ?? [];
|
||||||
|
foreach (KeyValuePair<Guid, double> kvp in damagesGuid)
|
||||||
|
{
|
||||||
|
Character? character = FindCharacterByGuid(kvp.Key, result);
|
||||||
|
if (character != null)
|
||||||
|
{
|
||||||
|
result.Damages[character] = kvp.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(RoundRecord.ActionType):
|
||||||
|
result.ActionType = (CharacterActionType)reader.GetInt32();
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.Skill):
|
||||||
|
result.Skill = NetworkUtility.JsonDeserialize<Skill>(ref reader, options);
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.SkillCost):
|
||||||
|
result.SkillCost = reader.GetString() ?? "";
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.Item):
|
||||||
|
result.Item = NetworkUtility.JsonDeserialize<Item>(ref reader, options);
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.HasKill):
|
||||||
|
result.HasKill = reader.GetBoolean();
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.Assists):
|
||||||
|
List<Character> assists = NetworkUtility.JsonDeserialize<List<Character>>(ref reader, options) ?? [];
|
||||||
|
result.Assists.AddRange(assists);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(RoundRecord.IsCritical):
|
||||||
|
Dictionary<Guid, bool> isCriticalGuid = NetworkUtility.JsonDeserialize<Dictionary<Guid, bool>>(ref reader, options) ?? [];
|
||||||
|
foreach (KeyValuePair<Guid, bool> kvp in isCriticalGuid)
|
||||||
|
{
|
||||||
|
Character? character = FindCharacterByGuid(kvp.Key, result);
|
||||||
|
if (character != null)
|
||||||
|
{
|
||||||
|
result.IsCritical[character] = kvp.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.IsEvaded):
|
||||||
|
Dictionary<Guid, bool> isEvadedGuid = NetworkUtility.JsonDeserialize<Dictionary<Guid, bool>>(ref reader, options) ?? [];
|
||||||
|
foreach (KeyValuePair<Guid, bool> kvp in isEvadedGuid)
|
||||||
|
{
|
||||||
|
Character? character = FindCharacterByGuid(kvp.Key, result);
|
||||||
|
if (character != null)
|
||||||
|
{
|
||||||
|
result.IsEvaded[character] = kvp.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.IsImmune):
|
||||||
|
Dictionary<Guid, bool> isImmuneGuid = NetworkUtility.JsonDeserialize<Dictionary<Guid, bool>>(ref reader, options) ?? [];
|
||||||
|
foreach (KeyValuePair<Guid, bool> kvp in isImmuneGuid)
|
||||||
|
{
|
||||||
|
Character? character = FindCharacterByGuid(kvp.Key, result);
|
||||||
|
if (character != null)
|
||||||
|
{
|
||||||
|
result.IsImmune[character] = kvp.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.Heals):
|
||||||
|
Dictionary<Guid, double> healsGuid = NetworkUtility.JsonDeserialize<Dictionary<Guid, double>>(ref reader, options) ?? [];
|
||||||
|
foreach (KeyValuePair<Guid, double> kvp in healsGuid)
|
||||||
|
{
|
||||||
|
Character? character = FindCharacterByGuid(kvp.Key, result);
|
||||||
|
if (character != null)
|
||||||
|
{
|
||||||
|
result.Heals[character] = kvp.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.Effects):
|
||||||
|
Dictionary<Guid, Effect> effectsGuid = NetworkUtility.JsonDeserialize<Dictionary<Guid, Effect>>(ref reader, options) ?? [];
|
||||||
|
foreach (KeyValuePair<Guid, Effect> kvp in effectsGuid)
|
||||||
|
{
|
||||||
|
Character? character = FindCharacterByGuid(kvp.Key, result);
|
||||||
|
if (character != null)
|
||||||
|
{
|
||||||
|
result.Effects[character] = kvp.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.ApplyEffects):
|
||||||
|
Dictionary<Guid, List<EffectType>> applyEffectsGuid = NetworkUtility.JsonDeserialize<Dictionary<Guid, List<EffectType>>>(ref reader, options) ?? [];
|
||||||
|
result.ApplyEffects.Clear();
|
||||||
|
foreach (KeyValuePair<Guid, List<EffectType>> kvp in applyEffectsGuid)
|
||||||
|
{
|
||||||
|
Character? character = FindCharacterByGuid(kvp.Key, result);
|
||||||
|
if (character != null)
|
||||||
|
{
|
||||||
|
result.ApplyEffects[character] = kvp.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.ActorContinuousKilling):
|
||||||
|
List<string> actorCK = NetworkUtility.JsonDeserialize<List<string>>(ref reader, options) ?? [];
|
||||||
|
result.ActorContinuousKilling.AddRange(actorCK);
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.DeathContinuousKilling):
|
||||||
|
List<string> deathCK = NetworkUtility.JsonDeserialize<List<string>>(ref reader, options) ?? [];
|
||||||
|
result.DeathContinuousKilling.AddRange(deathCK);
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.CastTime):
|
||||||
|
result.CastTime = reader.GetDouble();
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.HardnessTime):
|
||||||
|
result.HardnessTime = reader.GetDouble();
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.RespawnCountdowns):
|
||||||
|
Dictionary<Guid, double> respawnCountdownGuid = NetworkUtility.JsonDeserialize<Dictionary<Guid, double>>(ref reader, options) ?? [];
|
||||||
|
foreach (KeyValuePair<Guid, double> kvp in respawnCountdownGuid)
|
||||||
|
{
|
||||||
|
Character? character = FindCharacterByGuid(kvp.Key, result);
|
||||||
|
if (character != null)
|
||||||
|
{
|
||||||
|
result.RespawnCountdowns[character] = kvp.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.Respawns):
|
||||||
|
List<Character> respawns = NetworkUtility.JsonDeserialize<List<Character>>(ref reader, options) ?? [];
|
||||||
|
result.Respawns.AddRange(respawns);
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.RoundRewards):
|
||||||
|
List<Skill> rewards = NetworkUtility.JsonDeserialize<List<Skill>>(ref reader, options) ?? [];
|
||||||
|
result.RoundRewards.AddRange(rewards);
|
||||||
|
break;
|
||||||
|
case nameof(RoundRecord.OtherMessages):
|
||||||
|
List<string> messages = NetworkUtility.JsonDeserialize<List<string>>(ref reader, options) ?? [];
|
||||||
|
result.OtherMessages.AddRange(messages);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
reader.Skip();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, RoundRecord value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
writer.WriteStartObject();
|
||||||
|
writer.WriteNumber(nameof(RoundRecord.Round), value.Round);
|
||||||
|
writer.WritePropertyName(nameof(RoundRecord.Actor));
|
||||||
|
JsonSerializer.Serialize(writer, value.Actor, options);
|
||||||
|
writer.WritePropertyName(nameof(RoundRecord.Targets));
|
||||||
|
JsonSerializer.Serialize(writer, value.Targets, options);
|
||||||
|
writer.WritePropertyName(nameof(RoundRecord.Damages));
|
||||||
|
JsonSerializer.Serialize(writer, value.Damages.ToDictionary(kv => kv.Key.Guid, kv => kv.Value), options);
|
||||||
|
writer.WriteNumber(nameof(RoundRecord.ActionType), (int)value.ActionType);
|
||||||
|
writer.WritePropertyName(nameof(RoundRecord.Skill));
|
||||||
|
JsonSerializer.Serialize(writer, value.Skill, options);
|
||||||
|
writer.WriteString(nameof(RoundRecord.SkillCost), value.SkillCost);
|
||||||
|
writer.WritePropertyName(nameof(RoundRecord.Item));
|
||||||
|
JsonSerializer.Serialize(writer, value.Item, options);
|
||||||
|
writer.WriteBoolean(nameof(RoundRecord.HasKill), value.HasKill);
|
||||||
|
writer.WritePropertyName(nameof(RoundRecord.Assists));
|
||||||
|
JsonSerializer.Serialize(writer, value.Assists, options);
|
||||||
|
writer.WritePropertyName(nameof(RoundRecord.IsCritical));
|
||||||
|
JsonSerializer.Serialize(writer, value.IsCritical.ToDictionary(kv => kv.Key.Guid, kv => kv.Value), options);
|
||||||
|
writer.WritePropertyName(nameof(RoundRecord.IsEvaded));
|
||||||
|
JsonSerializer.Serialize(writer, value.IsEvaded.ToDictionary(kv => kv.Key.Guid, kv => kv.Value), options);
|
||||||
|
writer.WritePropertyName(nameof(RoundRecord.IsImmune));
|
||||||
|
JsonSerializer.Serialize(writer, value.IsImmune.ToDictionary(kv => kv.Key.Guid, kv => kv.Value), options);
|
||||||
|
writer.WritePropertyName(nameof(RoundRecord.Heals));
|
||||||
|
JsonSerializer.Serialize(writer, value.Heals.ToDictionary(kv => kv.Key.Guid, kv => kv.Value), options);
|
||||||
|
writer.WritePropertyName(nameof(RoundRecord.Effects));
|
||||||
|
JsonSerializer.Serialize(writer, value.Effects.ToDictionary(kv => kv.Key.Guid, kv => kv.Value), options);
|
||||||
|
writer.WritePropertyName(nameof(RoundRecord.ApplyEffects));
|
||||||
|
JsonSerializer.Serialize(writer, value.ApplyEffects.ToDictionary(kv => kv.Key.Guid, kv => kv.Value), options);
|
||||||
|
writer.WritePropertyName(nameof(RoundRecord.ActorContinuousKilling));
|
||||||
|
JsonSerializer.Serialize(writer, value.ActorContinuousKilling, options);
|
||||||
|
writer.WritePropertyName(nameof(RoundRecord.DeathContinuousKilling));
|
||||||
|
JsonSerializer.Serialize(writer, value.DeathContinuousKilling, options);
|
||||||
|
writer.WriteNumber(nameof(RoundRecord.CastTime), value.CastTime);
|
||||||
|
writer.WriteNumber(nameof(RoundRecord.HardnessTime), value.HardnessTime);
|
||||||
|
writer.WritePropertyName(nameof(RoundRecord.RespawnCountdowns));
|
||||||
|
JsonSerializer.Serialize(writer, value.RespawnCountdowns.ToDictionary(kv => kv.Key.Guid, kv => kv.Value), options);
|
||||||
|
writer.WritePropertyName(nameof(RoundRecord.Respawns));
|
||||||
|
JsonSerializer.Serialize(writer, value.Respawns, options);
|
||||||
|
writer.WritePropertyName(nameof(RoundRecord.RoundRewards));
|
||||||
|
JsonSerializer.Serialize(writer, value.RoundRewards, options);
|
||||||
|
writer.WritePropertyName(nameof(RoundRecord.OtherMessages));
|
||||||
|
JsonSerializer.Serialize(writer, value.OtherMessages, options);
|
||||||
|
writer.WriteEndObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Character? FindCharacterByGuid(Guid guid, RoundRecord record)
|
||||||
|
{
|
||||||
|
Character? character = record.Targets.FirstOrDefault(c => c.Guid == guid);
|
||||||
|
if (character != null) return character;
|
||||||
|
if (record.Actor != null && record.Actor.Guid == guid) return record.Actor;
|
||||||
|
character = record.Assists.FirstOrDefault(c => c.Guid == guid);
|
||||||
|
if (character != null) return character;
|
||||||
|
character = record.Respawns.FirstOrDefault(c => c.Guid == guid);
|
||||||
|
if (character != null) return character;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -39,11 +39,14 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
case nameof(Shield.Element):
|
case nameof(Shield.Element):
|
||||||
result.Element = reader.GetDouble();
|
result.Element = reader.GetDouble();
|
||||||
break;
|
break;
|
||||||
case nameof(Shield.Fleabane):
|
case nameof(Shield.Aster):
|
||||||
result.Fleabane = reader.GetDouble();
|
result.Aster = reader.GetDouble();
|
||||||
break;
|
break;
|
||||||
case nameof(Shield.Particle):
|
case nameof(Shield.SpatioTemporal):
|
||||||
result.Particle = reader.GetDouble();
|
result.SpatioTemporal = reader.GetDouble();
|
||||||
|
break;
|
||||||
|
case nameof(Shield.Mix):
|
||||||
|
result.Mix = reader.GetDouble();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -60,8 +63,9 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
writer.WriteNumber(nameof(Shield.Bright), value.Bright);
|
writer.WriteNumber(nameof(Shield.Bright), value.Bright);
|
||||||
writer.WriteNumber(nameof(Shield.Shadow), value.Shadow);
|
writer.WriteNumber(nameof(Shield.Shadow), value.Shadow);
|
||||||
writer.WriteNumber(nameof(Shield.Element), value.Element);
|
writer.WriteNumber(nameof(Shield.Element), value.Element);
|
||||||
writer.WriteNumber(nameof(Shield.Fleabane), value.Fleabane);
|
writer.WriteNumber(nameof(Shield.Aster), value.Aster);
|
||||||
writer.WriteNumber(nameof(Shield.Particle), value.Particle);
|
writer.WriteNumber(nameof(Shield.SpatioTemporal), value.SpatioTemporal);
|
||||||
|
writer.WriteNumber(nameof(Shield.Mix), value.Mix);
|
||||||
|
|
||||||
writer.WriteEndObject();
|
writer.WriteEndObject();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,6 +41,12 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
case nameof(Skill.Level):
|
case nameof(Skill.Level):
|
||||||
result.Level = reader.GetInt32();
|
result.Level = reader.GetInt32();
|
||||||
break;
|
break;
|
||||||
|
case nameof(Skill.CastAnywhere):
|
||||||
|
result.CastAnywhere = reader.GetBoolean();
|
||||||
|
break;
|
||||||
|
case nameof(Skill.CastRange):
|
||||||
|
result.CastRange = reader.GetInt32();
|
||||||
|
break;
|
||||||
case nameof(Skill.CanSelectSelf):
|
case nameof(Skill.CanSelectSelf):
|
||||||
result.CanSelectSelf = reader.GetBoolean();
|
result.CanSelectSelf = reader.GetBoolean();
|
||||||
break;
|
break;
|
||||||
@ -86,6 +92,12 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
case nameof(Skill.HardnessTime):
|
case nameof(Skill.HardnessTime):
|
||||||
result.HardnessTime = reader.GetDouble();
|
result.HardnessTime = reader.GetDouble();
|
||||||
break;
|
break;
|
||||||
|
case nameof(Skill.ExHardnessTime):
|
||||||
|
result.ExHardnessTime = reader.GetDouble();
|
||||||
|
break;
|
||||||
|
case nameof(Skill.ExHardnessTime2):
|
||||||
|
result.ExHardnessTime2 = reader.GetDouble();
|
||||||
|
break;
|
||||||
case nameof(Skill.Effects):
|
case nameof(Skill.Effects):
|
||||||
HashSet<Effect> effects = NetworkUtility.JsonDeserialize<HashSet<Effect>>(ref reader, options) ?? [];
|
HashSet<Effect> effects = NetworkUtility.JsonDeserialize<HashSet<Effect>>(ref reader, options) ?? [];
|
||||||
foreach (Effect effect in effects)
|
foreach (Effect effect in effects)
|
||||||
@ -119,6 +131,8 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
if (value.GeneralDescription.Length > 0) writer.WriteString(nameof(Skill.GeneralDescription), value.GeneralDescription);
|
if (value.GeneralDescription.Length > 0) writer.WriteString(nameof(Skill.GeneralDescription), value.GeneralDescription);
|
||||||
if (value.Slogan.Length > 0) writer.WriteString(nameof(Skill.Slogan), value.Slogan);
|
if (value.Slogan.Length > 0) writer.WriteString(nameof(Skill.Slogan), value.Slogan);
|
||||||
if (value.Level > 0) writer.WriteNumber(nameof(Skill.Level), value.Level);
|
if (value.Level > 0) writer.WriteNumber(nameof(Skill.Level), value.Level);
|
||||||
|
writer.WriteBoolean(nameof(Skill.CastAnywhere), value.CastAnywhere);
|
||||||
|
writer.WriteNumber(nameof(Skill.CastRange), value.CastRange);
|
||||||
if (value.CanSelectSelf) writer.WriteBoolean(nameof(Skill.CanSelectSelf), value.CanSelectSelf);
|
if (value.CanSelectSelf) writer.WriteBoolean(nameof(Skill.CanSelectSelf), value.CanSelectSelf);
|
||||||
if (!value.CanSelectEnemy) writer.WriteBoolean(nameof(Skill.CanSelectEnemy), value.CanSelectEnemy);
|
if (!value.CanSelectEnemy) writer.WriteBoolean(nameof(Skill.CanSelectEnemy), value.CanSelectEnemy);
|
||||||
if (value.CanSelectTeammate) writer.WriteBoolean(nameof(Skill.CanSelectTeammate), value.CanSelectTeammate);
|
if (value.CanSelectTeammate) writer.WriteBoolean(nameof(Skill.CanSelectTeammate), value.CanSelectTeammate);
|
||||||
@ -134,6 +148,8 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
if (value.CD > 0) writer.WriteNumber(nameof(Skill.CD), value.CD);
|
if (value.CD > 0) writer.WriteNumber(nameof(Skill.CD), value.CD);
|
||||||
if (value.CurrentCD > 0) writer.WriteNumber(nameof(Skill.CurrentCD), value.CurrentCD);
|
if (value.CurrentCD > 0) writer.WriteNumber(nameof(Skill.CurrentCD), value.CurrentCD);
|
||||||
if (value.HardnessTime > 0) writer.WriteNumber(nameof(Skill.HardnessTime), value.HardnessTime);
|
if (value.HardnessTime > 0) writer.WriteNumber(nameof(Skill.HardnessTime), value.HardnessTime);
|
||||||
|
if (value.ExHardnessTime != 0) writer.WriteNumber(nameof(Skill.ExHardnessTime), value.ExHardnessTime);
|
||||||
|
if (value.ExHardnessTime2 != 0) writer.WriteNumber(nameof(Skill.ExHardnessTime2), value.ExHardnessTime2);
|
||||||
writer.WritePropertyName(nameof(Skill.Effects));
|
writer.WritePropertyName(nameof(Skill.Effects));
|
||||||
JsonSerializer.Serialize(writer, value.Effects, options);
|
JsonSerializer.Serialize(writer, value.Effects, options);
|
||||||
writer.WritePropertyName(nameof(Skill.Values));
|
writer.WritePropertyName(nameof(Skill.Values));
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
using Milimoe.FunGame.Core.Api.Utility;
|
using Milimoe.FunGame.Core.Api.Utility;
|
||||||
using Milimoe.FunGame.Core.Entity;
|
using Milimoe.FunGame.Core.Entity;
|
||||||
using Milimoe.FunGame.Core.Library.Common.Architecture;
|
using Milimoe.FunGame.Core.Library.Common.Architecture;
|
||||||
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
|
||||||
namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
||||||
{
|
{
|
||||||
@ -19,6 +20,53 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
case nameof(Store.Name):
|
case nameof(Store.Name):
|
||||||
result.Name = reader.GetString() ?? "";
|
result.Name = reader.GetString() ?? "";
|
||||||
break;
|
break;
|
||||||
|
case nameof(Store.Description):
|
||||||
|
result.Description = reader.GetString() ?? "";
|
||||||
|
break;
|
||||||
|
case nameof(Store.StartTime):
|
||||||
|
string dateString = reader.GetString() ?? "";
|
||||||
|
if (DateTime.TryParseExact(dateString, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out DateTime time))
|
||||||
|
{
|
||||||
|
result.StartTime = time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.StartTime = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(Store.EndTime):
|
||||||
|
dateString = reader.GetString() ?? "";
|
||||||
|
if (DateTime.TryParseExact(dateString, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out time))
|
||||||
|
{
|
||||||
|
result.EndTime = time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.EndTime = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(Store.StartTimeOfDay):
|
||||||
|
dateString = reader.GetString() ?? "";
|
||||||
|
if (DateTime.TryParseExact(dateString, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out time))
|
||||||
|
{
|
||||||
|
result.StartTimeOfDay = time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.StartTimeOfDay = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(Store.EndTimeOfDay):
|
||||||
|
dateString = reader.GetString() ?? "";
|
||||||
|
if (DateTime.TryParseExact(dateString, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out time))
|
||||||
|
{
|
||||||
|
result.EndTimeOfDay = time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.EndTimeOfDay = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case nameof(Store.Goods):
|
case nameof(Store.Goods):
|
||||||
Dictionary<long, Goods> goods = NetworkUtility.JsonDeserialize<Dictionary<long, Goods>>(ref reader, options) ?? [];
|
Dictionary<long, Goods> goods = NetworkUtility.JsonDeserialize<Dictionary<long, Goods>>(ref reader, options) ?? [];
|
||||||
foreach (long id in goods.Keys)
|
foreach (long id in goods.Keys)
|
||||||
@ -26,6 +74,43 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
result.Goods[id] = goods[id];
|
result.Goods[id] = goods[id];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case nameof(Store.AutoRefresh):
|
||||||
|
result.AutoRefresh = reader.GetBoolean();
|
||||||
|
break;
|
||||||
|
case nameof(Store.NextRefreshDate):
|
||||||
|
dateString = reader.GetString() ?? "";
|
||||||
|
if (DateTime.TryParseExact(dateString, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out time))
|
||||||
|
{
|
||||||
|
result.NextRefreshDate = time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.NextRefreshDate = DateTime.MinValue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(Store.NextRefreshGoods):
|
||||||
|
Dictionary<long, Goods> goods2 = NetworkUtility.JsonDeserialize<Dictionary<long, Goods>>(ref reader, options) ?? [];
|
||||||
|
foreach (long id in goods2.Keys)
|
||||||
|
{
|
||||||
|
result.NextRefreshGoods[id] = goods2[id];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case nameof(Store.RefreshInterval):
|
||||||
|
result.RefreshInterval = Convert.ToInt32(reader.GetInt64());
|
||||||
|
break;
|
||||||
|
case nameof(Store.GetNewerGoodsOnVisiting):
|
||||||
|
result.GetNewerGoodsOnVisiting = reader.GetBoolean();
|
||||||
|
break;
|
||||||
|
case nameof(Store.GlobalStock):
|
||||||
|
result.GlobalStock = reader.GetBoolean();
|
||||||
|
break;
|
||||||
|
case nameof(Store.ExpireTime):
|
||||||
|
dateString = reader.GetString() ?? "";
|
||||||
|
if (DateTime.TryParseExact(dateString, General.GeneralDateTimeFormat, null, System.Globalization.DateTimeStyles.None, out time))
|
||||||
|
{
|
||||||
|
result.ExpireTime = time;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,8 +119,21 @@ namespace Milimoe.FunGame.Core.Library.Common.JsonConverter
|
|||||||
writer.WriteStartObject();
|
writer.WriteStartObject();
|
||||||
|
|
||||||
writer.WriteString(nameof(Store.Name), value.Name);
|
writer.WriteString(nameof(Store.Name), value.Name);
|
||||||
|
writer.WriteString(nameof(Store.Description), value.Description);
|
||||||
|
if (value.StartTime.HasValue) writer.WriteString(nameof(Store.StartTime), value.StartTime.Value.ToString(General.GeneralDateTimeFormat));
|
||||||
|
if (value.EndTime.HasValue) writer.WriteString(nameof(Store.EndTime), value.EndTime.Value.ToString(General.GeneralDateTimeFormat));
|
||||||
|
if (value.StartTimeOfDay.HasValue) writer.WriteString(nameof(Store.StartTimeOfDay), value.StartTimeOfDay.Value.ToString(General.GeneralDateTimeFormat));
|
||||||
|
if (value.EndTimeOfDay.HasValue) writer.WriteString(nameof(Store.EndTimeOfDay), value.EndTimeOfDay.Value.ToString(General.GeneralDateTimeFormat));
|
||||||
writer.WritePropertyName(nameof(Store.Goods));
|
writer.WritePropertyName(nameof(Store.Goods));
|
||||||
JsonSerializer.Serialize(writer, value.Goods, options);
|
JsonSerializer.Serialize(writer, value.Goods, options);
|
||||||
|
writer.WriteBoolean(nameof(Store.AutoRefresh), value.AutoRefresh);
|
||||||
|
writer.WriteString(nameof(Store.NextRefreshDate), value.NextRefreshDate.ToString(General.GeneralDateTimeFormat));
|
||||||
|
writer.WritePropertyName(nameof(Store.NextRefreshGoods));
|
||||||
|
JsonSerializer.Serialize(writer, value.NextRefreshGoods, options);
|
||||||
|
writer.WriteNumber(nameof(Store.RefreshInterval), value.RefreshInterval);
|
||||||
|
writer.WriteBoolean(nameof(Store.GetNewerGoodsOnVisiting), value.GetNewerGoodsOnVisiting);
|
||||||
|
writer.WriteBoolean(nameof(Store.GlobalStock), value.GlobalStock);
|
||||||
|
if (value.ExpireTime.HasValue) writer.WriteString(nameof(Store.ExpireTime), value.ExpireTime.Value.ToString(General.GeneralDateTimeFormat));
|
||||||
|
|
||||||
writer.WriteEndObject();
|
writer.WriteEndObject();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
|
using Milimoe.FunGame.Core.Model;
|
||||||
using Milimoe.FunGame.Core.Model;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 此文件用于保存字符串常量(String Set)
|
* 此文件用于保存字符串常量(String Set)
|
||||||
@ -33,6 +32,46 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
_ => "未开始"
|
_ => "未开始"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetActivityStatus(ActivityState status)
|
||||||
|
{
|
||||||
|
return status switch
|
||||||
|
{
|
||||||
|
ActivityState.Future => "预告中",
|
||||||
|
ActivityState.Upcoming => "即将开始",
|
||||||
|
ActivityState.InProgress => "进行中",
|
||||||
|
_ => "已结束"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetOfferStatus(OfferState status)
|
||||||
|
{
|
||||||
|
return status switch
|
||||||
|
{
|
||||||
|
OfferState.Created => "已创建",
|
||||||
|
OfferState.Cancelled => "已取消",
|
||||||
|
OfferState.PendingOfferorConfirmation => "等待发起方确认",
|
||||||
|
OfferState.PendingOffereeConfirmation => "等待接收方确认",
|
||||||
|
OfferState.OfferorConfirmed => "发起方已确认",
|
||||||
|
OfferState.OffereeConfirmed => "接收方已确认",
|
||||||
|
OfferState.Sent => "已发送",
|
||||||
|
OfferState.Negotiating => "协商中",
|
||||||
|
OfferState.NegotiationAccepted => "协商已接受",
|
||||||
|
OfferState.Rejected => "已拒绝",
|
||||||
|
OfferState.Completed => "已完成",
|
||||||
|
_ => "已过期"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetMarketItemStatus(MarketItemState status)
|
||||||
|
{
|
||||||
|
return status switch
|
||||||
|
{
|
||||||
|
MarketItemState.Delisted => "已下架",
|
||||||
|
MarketItemState.Purchased => "已售罄",
|
||||||
|
_ => "已上架"
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -387,8 +426,8 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
MagicType.Bright => "光魔法伤害",
|
MagicType.Bright => "光魔法伤害",
|
||||||
MagicType.Shadow => "影魔法伤害",
|
MagicType.Shadow => "影魔法伤害",
|
||||||
MagicType.Element => "元素魔法伤害",
|
MagicType.Element => "元素魔法伤害",
|
||||||
MagicType.Fleabane => "紫宛魔法伤害",
|
MagicType.Aster => "紫宛魔法伤害",
|
||||||
MagicType.Particle => "时空魔法伤害",
|
MagicType.SpatioTemporal => "时空魔法伤害",
|
||||||
_ => "魔法伤害",
|
_ => "魔法伤害",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -397,14 +436,14 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
{
|
{
|
||||||
return type switch
|
return type switch
|
||||||
{
|
{
|
||||||
MagicType.Starmark => "星痕抗性",
|
MagicType.Starmark => "星痕魔法抗性",
|
||||||
MagicType.PurityNatural => "现代结晶抗性",
|
MagicType.PurityNatural => "现代结晶魔法抗性",
|
||||||
MagicType.PurityContemporary => "纯粹结晶抗性",
|
MagicType.PurityContemporary => "纯粹结晶魔法抗性",
|
||||||
MagicType.Bright => "光抗性",
|
MagicType.Bright => "光魔法抗性",
|
||||||
MagicType.Shadow => "影抗性",
|
MagicType.Shadow => "影魔法抗性",
|
||||||
MagicType.Element => "元素抗性",
|
MagicType.Element => "元素魔法抗性",
|
||||||
MagicType.Fleabane => "紫宛抗性",
|
MagicType.Aster => "紫宛魔法抗性",
|
||||||
MagicType.Particle => "时空抗性",
|
MagicType.SpatioTemporal => "时空魔法抗性",
|
||||||
_ => "魔法抗性",
|
_ => "魔法抗性",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -439,6 +478,7 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
CharacterState.ActionRestricted => "角色现在行动受限",
|
CharacterState.ActionRestricted => "角色现在行动受限",
|
||||||
CharacterState.BattleRestricted => "角色现在战斗不能",
|
CharacterState.BattleRestricted => "角色现在战斗不能",
|
||||||
CharacterState.SkillRestricted => "角色现在技能受限",
|
CharacterState.SkillRestricted => "角色现在技能受限",
|
||||||
|
CharacterState.AttackRestricted => "角色现在攻击受限",
|
||||||
_ => "角色现在完全行动不能"
|
_ => "角色现在完全行动不能"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -454,6 +494,28 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
_ => "★"
|
_ => "★"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetDamageTypeName(DamageType damageType, MagicType magicType = MagicType.None)
|
||||||
|
{
|
||||||
|
return damageType switch
|
||||||
|
{
|
||||||
|
DamageType.Magical => GetMagicDamageName(magicType),
|
||||||
|
DamageType.True => "真实伤害",
|
||||||
|
_ => "物理伤害"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetImmuneTypeName(ImmuneType type)
|
||||||
|
{
|
||||||
|
return type switch
|
||||||
|
{
|
||||||
|
ImmuneType.Physical => "物理免疫",
|
||||||
|
ImmuneType.Magical => "魔法免疫",
|
||||||
|
ImmuneType.Skilled => "技能免疫",
|
||||||
|
ImmuneType.All => "完全免疫",
|
||||||
|
_ => ""
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ItemSet
|
public class ItemSet
|
||||||
@ -682,6 +744,13 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
EffectType.SkilledImmune => "技能免疫",
|
EffectType.SkilledImmune => "技能免疫",
|
||||||
EffectType.AllImmune => "完全免疫",
|
EffectType.AllImmune => "完全免疫",
|
||||||
EffectType.EvadeBoost => "闪避提升",
|
EffectType.EvadeBoost => "闪避提升",
|
||||||
|
EffectType.Lifesteal => "生命偷取",
|
||||||
|
EffectType.GrievousWound => "重伤",
|
||||||
|
EffectType.WeakDispelling => "持续性弱驱散",
|
||||||
|
EffectType.StrongDispelling => "持续性强驱散",
|
||||||
|
EffectType.Recovery => "恢复",
|
||||||
|
EffectType.Vulnerable => "易伤",
|
||||||
|
EffectType.Delay => "迟滞",
|
||||||
_ => "未知效果"
|
_ => "未知效果"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -710,6 +779,8 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
EffectType.Petrify => DispelledType.Strong,
|
EffectType.Petrify => DispelledType.Strong,
|
||||||
EffectType.SilenceMagic => DispelledType.Strong,
|
EffectType.SilenceMagic => DispelledType.Strong,
|
||||||
EffectType.Banish => DispelledType.Strong,
|
EffectType.Banish => DispelledType.Strong,
|
||||||
|
EffectType.AllImmune => DispelledType.Strong,
|
||||||
|
EffectType.StrongDispelling => DispelledType.Strong,
|
||||||
EffectType.Mark => DispelledType.Weak,
|
EffectType.Mark => DispelledType.Weak,
|
||||||
EffectType.Slow => DispelledType.Weak,
|
EffectType.Slow => DispelledType.Weak,
|
||||||
EffectType.Weaken => DispelledType.Weak,
|
EffectType.Weaken => DispelledType.Weak,
|
||||||
@ -733,10 +804,13 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
EffectType.PhysicalImmune => DispelledType.Weak,
|
EffectType.PhysicalImmune => DispelledType.Weak,
|
||||||
EffectType.MagicalImmune => DispelledType.Weak,
|
EffectType.MagicalImmune => DispelledType.Weak,
|
||||||
EffectType.SkilledImmune => DispelledType.Weak,
|
EffectType.SkilledImmune => DispelledType.Weak,
|
||||||
EffectType.AllImmune => DispelledType.Strong,
|
|
||||||
EffectType.EvadeBoost => DispelledType.Weak,
|
EffectType.EvadeBoost => DispelledType.Weak,
|
||||||
EffectType.Lifesteal => DispelledType.Weak,
|
EffectType.Lifesteal => DispelledType.Weak,
|
||||||
EffectType.GrievousWound => DispelledType.Weak,
|
EffectType.GrievousWound => DispelledType.Weak,
|
||||||
|
EffectType.WeakDispelling => DispelledType.Weak,
|
||||||
|
EffectType.Recovery => DispelledType.Weak,
|
||||||
|
EffectType.Vulnerable => DispelledType.Weak,
|
||||||
|
EffectType.Delay => DispelledType.Weak,
|
||||||
_ => DispelledType.Weak
|
_ => DispelledType.Weak
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -791,7 +865,12 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
EffectType.AllImmune => false,
|
EffectType.AllImmune => false,
|
||||||
EffectType.EvadeBoost => false,
|
EffectType.EvadeBoost => false,
|
||||||
EffectType.Lifesteal => false,
|
EffectType.Lifesteal => false,
|
||||||
EffectType.GrievousWound => false,
|
EffectType.GrievousWound => true,
|
||||||
|
EffectType.WeakDispelling => false,
|
||||||
|
EffectType.StrongDispelling => false,
|
||||||
|
EffectType.Recovery => false,
|
||||||
|
EffectType.Vulnerable => true,
|
||||||
|
EffectType.Delay => true,
|
||||||
_ => false
|
_ => false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,14 @@
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 核心库的版本号
|
/// 核心库的版本号
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string FunGame_Version { get; } = $"{FunGame_Version_Major}.{FunGame_Version_Minor}{FunGame_VersionPatch}";
|
public static string FunGame_Version
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
string patch = FunGame_VersionPatch.StartsWith('.') ? FunGame_VersionPatch : $".{FunGame_VersionPatch}";
|
||||||
|
return $"{FunGame_Version_Major}.{FunGame_Version_Minor}{patch}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public const string FunGame_Core = "FunGame Core";
|
public const string FunGame_Core = "FunGame Core";
|
||||||
public const string FunGame_Core_Api = "FunGame Core Api";
|
public const string FunGame_Core_Api = "FunGame Core Api";
|
||||||
@ -31,9 +38,9 @@
|
|||||||
public const string FunGame_Desktop = "FunGame Desktop";
|
public const string FunGame_Desktop = "FunGame Desktop";
|
||||||
public const string FunGame_Server = "FunGame Server Console";
|
public const string FunGame_Server = "FunGame Server Console";
|
||||||
|
|
||||||
public const int FunGame_Version_Major = 1;
|
public const int FunGame_Version_Major = 2;
|
||||||
public const int FunGame_Version_Minor = 0;
|
public const int FunGame_Version_Minor = 0;
|
||||||
public const string FunGame_VersionPatch = ".0-rc.1";
|
public const string FunGame_VersionPatch = "0-dev";
|
||||||
public const string FunGame_Version_Build = "";
|
public const string FunGame_Version_Build = "";
|
||||||
|
|
||||||
public const string FunGameCoreTitle = @" _____ _ _ _ _ ____ _ __ __ _____ ____ ___ ____ _____
|
public const string FunGameCoreTitle = @" _____ _ _ _ _ ____ _ __ __ _____ ____ ___ ____ _____
|
||||||
|
|||||||
@ -57,6 +57,11 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static string GeneralDateTimeFormatChinese => "yyyy年MM月dd日 HH:mm:ss";
|
public static string GeneralDateTimeFormatChinese => "yyyy年MM月dd日 HH:mm:ss";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HH:mm:ss
|
||||||
|
/// </summary>
|
||||||
|
public static string GeneralDateTimeFormatTimeOnly => "HH:mm:ss";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 默认的时间值(1970年8月1日8点0分0秒)
|
/// 默认的时间值(1970年8月1日8点0分0秒)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -48,7 +48,7 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
Fail,
|
Fail,
|
||||||
NotFound,
|
NotFound,
|
||||||
SQLError,
|
SQLError,
|
||||||
IsExist
|
Exists
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum MailSendResult
|
public enum MailSendResult
|
||||||
@ -62,7 +62,9 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
{
|
{
|
||||||
Normal,
|
Normal,
|
||||||
Critical,
|
Critical,
|
||||||
Evaded
|
Evaded,
|
||||||
|
Shield,
|
||||||
|
Immune
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum RedeemResult
|
public enum RedeemResult
|
||||||
|
|||||||
@ -228,6 +228,11 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 注意:具有控制效果的特效,应该和技能本身的特效(一般此项为None)区分开来。此效果被赋值会改变一些判断的结果。
|
/// 注意:具有控制效果的特效,应该和技能本身的特效(一般此项为None)区分开来。此效果被赋值会改变一些判断的结果。
|
||||||
|
/// <para>关联方法:</para>
|
||||||
|
/// <para><see cref="SkillSet.GetCharacterStateByEffectType(EffectType)"/></para>
|
||||||
|
/// <para><see cref="SkillSet.GetDispelledTypeByEffectType(EffectType)"/></para>
|
||||||
|
/// <para><see cref="SkillSet.GetEffectTypeName(EffectType)"/></para>
|
||||||
|
/// <para><see cref="SkillSet.GetIsDebuffByEffectType(EffectType)"/></para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum EffectType
|
public enum EffectType
|
||||||
{
|
{
|
||||||
@ -292,7 +297,7 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
Taunt,
|
Taunt,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 减速,目标行动速度和攻击频率降低
|
/// 减速,目标行动速度或加速系数降低
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Slow,
|
Slow,
|
||||||
|
|
||||||
@ -307,12 +312,12 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
Poison,
|
Poison,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 燃烧,目标受到火焰伤害,持续一段时间
|
/// 燃烧,目标受到伤害,持续一段时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Burn,
|
Burn,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 流血,目标持续受到物理伤害
|
/// 流血,目标持续受到伤害
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Bleed,
|
Bleed,
|
||||||
|
|
||||||
@ -412,7 +417,7 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
Confusion,
|
Confusion,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 石化,目标无法行动,并大幅增加受到的伤害
|
/// 石化,目标无法行动
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Petrify,
|
Petrify,
|
||||||
|
|
||||||
@ -464,7 +469,32 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 重伤,目标受到的治疗效果降低
|
/// 重伤,目标受到的治疗效果降低
|
||||||
/// </summary>
|
/// </summary>
|
||||||
GrievousWound
|
GrievousWound,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 持续性弱驱散
|
||||||
|
/// </summary>
|
||||||
|
WeakDispelling,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 持续性强驱散
|
||||||
|
/// </summary>
|
||||||
|
StrongDispelling,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 恢复
|
||||||
|
/// </summary>
|
||||||
|
Recovery,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 易伤
|
||||||
|
/// </summary>
|
||||||
|
Vulnerable,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 迟滞,硬直时间延长
|
||||||
|
/// </summary>
|
||||||
|
Delay
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ItemType
|
public enum ItemType
|
||||||
@ -612,8 +642,8 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
Bright,
|
Bright,
|
||||||
Shadow,
|
Shadow,
|
||||||
Element,
|
Element,
|
||||||
Fleabane,
|
Aster,
|
||||||
Particle
|
SpatioTemporal
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum PrimaryAttribute
|
public enum PrimaryAttribute
|
||||||
@ -710,6 +740,7 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
public enum CharacterActionType
|
public enum CharacterActionType
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
|
Move,
|
||||||
NormalAttack,
|
NormalAttack,
|
||||||
PreCastSkill,
|
PreCastSkill,
|
||||||
CastSkill,
|
CastSkill,
|
||||||
@ -1006,13 +1037,40 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 标准实现的免疫类型
|
/// 标准实现的免疫类型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
public enum ImmuneType
|
public enum ImmuneType
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Physical = 1 << 0,
|
||||||
|
Magical = 1 << 1,
|
||||||
|
Skilled = 1 << 2,
|
||||||
|
All = 1 << 3,
|
||||||
|
Special = 1 << 4
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ShieldType
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
Physical,
|
Physical,
|
||||||
Magical,
|
Magical,
|
||||||
Skilled,
|
Mix,
|
||||||
All,
|
Effect
|
||||||
Special
|
}
|
||||||
|
|
||||||
|
public enum DamageType
|
||||||
|
{
|
||||||
|
Physical,
|
||||||
|
Magical,
|
||||||
|
True
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum SkillRangeType
|
||||||
|
{
|
||||||
|
Diamond,
|
||||||
|
Circle,
|
||||||
|
Square,
|
||||||
|
Line,
|
||||||
|
LinePass,
|
||||||
|
Sector
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,10 +10,11 @@ namespace Milimoe.FunGame.Core.Library.SQLScript.Entity
|
|||||||
public const string Column_ItemGuid = "ItemGuid";
|
public const string Column_ItemGuid = "ItemGuid";
|
||||||
public const string Column_UserId = "UserId";
|
public const string Column_UserId = "UserId";
|
||||||
public const string Column_Price = "Price";
|
public const string Column_Price = "Price";
|
||||||
|
public const string Column_Stock = "Stock";
|
||||||
public const string Column_CreateTime = "CreateTime";
|
public const string Column_CreateTime = "CreateTime";
|
||||||
public const string Column_FinishTime = "FinishTime";
|
public const string Column_FinishTime = "FinishTime";
|
||||||
public const string Column_Status = "Status";
|
public const string Column_Status = "Status";
|
||||||
public const string Column_Buyer = "Buyer";
|
public const string Column_Buyers = "Buyers";
|
||||||
|
|
||||||
public const string Select_MarketItems = $"{Command_Select} {Command_All} {Command_From} {TableName}";
|
public const string Select_MarketItems = $"{Command_Select} {Command_All} {Command_From} {TableName}";
|
||||||
|
|
||||||
@ -35,14 +36,15 @@ namespace Milimoe.FunGame.Core.Library.SQLScript.Entity
|
|||||||
return $"{Select_MarketItems} {Command_Where} {Column_Status} = @Status";
|
return $"{Select_MarketItems} {Command_Where} {Column_Status} = @Status";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string Insert_MarketItem(SQLHelper SQLHelper, Guid ItemGuid, long UserId, double Price, MarketItemState state = MarketItemState.Listed)
|
public static string Insert_MarketItem(SQLHelper SQLHelper, Guid ItemGuid, long UserId, double Price, double Stock, MarketItemState state = MarketItemState.Listed)
|
||||||
{
|
{
|
||||||
SQLHelper.Parameters["@ItemGuid"] = ItemGuid.ToString();
|
SQLHelper.Parameters["@ItemGuid"] = ItemGuid.ToString();
|
||||||
SQLHelper.Parameters["@UserId"] = UserId;
|
SQLHelper.Parameters["@UserId"] = UserId;
|
||||||
SQLHelper.Parameters["@Price"] = Price;
|
SQLHelper.Parameters["@Price"] = Price;
|
||||||
|
SQLHelper.Parameters["@Stock"] = Stock;
|
||||||
SQLHelper.Parameters["@Status"] = (int)state;
|
SQLHelper.Parameters["@Status"] = (int)state;
|
||||||
|
|
||||||
return $"{Command_Insert} {Command_Into} {TableName} ({Column_ItemGuid}, {Column_UserId}, {Column_Price}, {Column_Status}) {Command_Values} (@ItemId, @UserId, @Price, @Status)";
|
return $"{Command_Insert} {Command_Into} {TableName} ({Column_ItemGuid}, {Column_UserId}, {Column_Price}, {Column_Stock}, {Column_Status}) {Command_Values} (@ItemId, @UserId, @Price, @Stock, @Status)";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string Update_MarketItemPrice(SQLHelper SQLHelper, Guid ItemGuid, double Price)
|
public static string Update_MarketItemPrice(SQLHelper SQLHelper, Guid ItemGuid, double Price)
|
||||||
@ -52,6 +54,13 @@ namespace Milimoe.FunGame.Core.Library.SQLScript.Entity
|
|||||||
return $"{Command_Update} {TableName} {Command_Set} {Column_Price} = @Price {Command_Where} {Column_ItemGuid} = @ItemGuid";
|
return $"{Command_Update} {TableName} {Command_Set} {Column_Price} = @Price {Command_Where} {Column_ItemGuid} = @ItemGuid";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string Update_MarketItemStock(SQLHelper SQLHelper, Guid ItemGuid, double Stock)
|
||||||
|
{
|
||||||
|
SQLHelper.Parameters["@ItemGuid"] = ItemGuid.ToString();
|
||||||
|
SQLHelper.Parameters["@Stock"] = Stock;
|
||||||
|
return $"{Command_Update} {TableName} {Command_Set} {Column_Stock} = @Stock {Command_Where} {Column_ItemGuid} = @ItemGuid";
|
||||||
|
}
|
||||||
|
|
||||||
public static string Update_MarketItemState(SQLHelper SQLHelper, Guid ItemGuid, MarketItemState state)
|
public static string Update_MarketItemState(SQLHelper SQLHelper, Guid ItemGuid, MarketItemState state)
|
||||||
{
|
{
|
||||||
SQLHelper.Parameters["@ItemGuid"] = ItemGuid.ToString();
|
SQLHelper.Parameters["@ItemGuid"] = ItemGuid.ToString();
|
||||||
@ -59,12 +68,12 @@ namespace Milimoe.FunGame.Core.Library.SQLScript.Entity
|
|||||||
return $"{Command_Update} {TableName} {Command_Set} {Column_Status} = @Status {Command_Where} {Column_ItemGuid} = @ItemGuid";
|
return $"{Command_Update} {TableName} {Command_Set} {Column_Status} = @Status {Command_Where} {Column_ItemGuid} = @ItemGuid";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string Update_Buy(SQLHelper SQLHelper, Guid ItemGuid, long Buyer)
|
public static string Update_Buy(SQLHelper SQLHelper, Guid ItemGuid, string Buyers)
|
||||||
{
|
{
|
||||||
SQLHelper.Parameters["@ItemGuid"] = ItemGuid.ToString();
|
SQLHelper.Parameters["@ItemGuid"] = ItemGuid.ToString();
|
||||||
SQLHelper.Parameters["@Buyer"] = Buyer;
|
SQLHelper.Parameters["@Buyers"] = Buyers;
|
||||||
SQLHelper.Parameters["@Status"] = (int)MarketItemState.Purchased;
|
SQLHelper.Parameters["@Status"] = (int)MarketItemState.Purchased;
|
||||||
return $"{Command_Update} {TableName} {Command_Set} {Column_Buyer} = @Buyer, {Column_Status} = @Status {Command_Where} {Column_ItemGuid} = @ItemGuid";
|
return $"{Command_Update} {TableName} {Command_Set} {Column_Buyers} = @Buyers, {Column_Status} = @Status {Command_Where} {Column_ItemGuid} = @ItemGuid";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string Update_MarketItemFinishTime(SQLHelper SQLHelper, Guid ItemGuid, DateTime FinishTime)
|
public static string Update_MarketItemFinishTime(SQLHelper SQLHelper, Guid ItemGuid, DateTime FinishTime)
|
||||||
|
|||||||
@ -65,5 +65,19 @@ namespace Milimoe.FunGame.Core.Library.SQLScript.Entity
|
|||||||
SQLHelper.Parameters["@OfferId"] = OfferId;
|
SQLHelper.Parameters["@OfferId"] = OfferId;
|
||||||
return $"{Command_Delete} {Command_From} {TableName_Backup} {Command_Where} {Column_OfferId} = @OfferId";
|
return $"{Command_Delete} {Command_From} {TableName_Backup} {Command_Where} {Column_OfferId} = @OfferId";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string Delete_OfferItemsByOfferIdAndItemGuid(SQLHelper SQLHelper, long OfferId, Guid ItemGuid)
|
||||||
|
{
|
||||||
|
SQLHelper.Parameters["@OfferId"] = OfferId;
|
||||||
|
SQLHelper.Parameters["@ItemGuid"] = ItemGuid.ToString();
|
||||||
|
return $"{Command_Delete} {Command_From} {TableName} {Command_Where} {Column_OfferId} = @OfferId {Command_And} {Column_ItemGuid} = @ItemGuid";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Delete_OfferItemsBackupByOfferIdAndItemGuid(SQLHelper SQLHelper, long OfferId, Guid ItemGuid)
|
||||||
|
{
|
||||||
|
SQLHelper.Parameters["@OfferId"] = OfferId;
|
||||||
|
SQLHelper.Parameters["@ItemGuid"] = ItemGuid.ToString();
|
||||||
|
return $"{Command_Delete} {Command_From} {TableName_Backup} {Command_Where} {Column_OfferId} = @OfferId {Command_And} {Column_ItemGuid} = @ItemGuid";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,10 +39,11 @@ namespace Milimoe.FunGame.Core.Library.SQLScript.Entity
|
|||||||
SQLHelper.Parameters["@Offeror"] = Offeror;
|
SQLHelper.Parameters["@Offeror"] = Offeror;
|
||||||
SQLHelper.Parameters["@Offeree"] = Offeree;
|
SQLHelper.Parameters["@Offeree"] = Offeree;
|
||||||
SQLHelper.Parameters["@Status"] = (int)Status;
|
SQLHelper.Parameters["@Status"] = (int)Status;
|
||||||
|
SQLHelper.Parameters["@CreateTime"] = DateTime.Now;
|
||||||
SQLHelper.Parameters["@NegotiatedTimes"] = NegotiatedTimes;
|
SQLHelper.Parameters["@NegotiatedTimes"] = NegotiatedTimes;
|
||||||
|
|
||||||
return $"{Command_Insert} {Command_Into} {TableName} ({Column_Offeror}, {Column_Offeree}, {Column_Status}, {Column_NegotiatedTimes}) " +
|
return $"{Command_Insert} {Command_Into} {TableName} ({Column_Offeror}, {Column_Offeree}, {Column_Status}, {Column_CreateTime}), {Column_NegotiatedTimes}) " +
|
||||||
$"{Command_Values} (@Offeror, @Offeree, @Status, @NegotiatedTimes)";
|
$"{Command_Values} (@Offeror, @Offeree, @Status, @CreateTime, @NegotiatedTimes)";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string Update_OfferStatus(SQLHelper SQLHelper, long Id, OfferState Status)
|
public static string Update_OfferStatus(SQLHelper SQLHelper, long Id, OfferState Status)
|
||||||
|
|||||||
@ -23,7 +23,7 @@ namespace Milimoe.FunGame.Core.Library.SQLScript.Entity
|
|||||||
public const string Select_Rooms = $"{Command_Select} {TableName}.{Command_All}, {UserQuery.TableName}.{UserQuery.Column_Username} {Command_As} {Column_RoomMasterName} " +
|
public const string Select_Rooms = $"{Command_Select} {TableName}.{Command_All}, {UserQuery.TableName}.{UserQuery.Column_Username} {Command_As} {Column_RoomMasterName} " +
|
||||||
$"{Command_From} {TableName} {Command_LeftJoin} {UserQuery.TableName} {Command_On} {UserQuery.TableName}.{UserQuery.Column_Id} = {TableName}.{Column_RoomMaster}";
|
$"{Command_From} {TableName} {Command_LeftJoin} {UserQuery.TableName} {Command_On} {UserQuery.TableName}.{UserQuery.Column_Id} = {TableName}.{Column_RoomMaster}";
|
||||||
|
|
||||||
public static string Select_IsExistRoom(SQLHelper SQLHelper, string Roomid)
|
public static string Select_RoomByRoomId(SQLHelper SQLHelper, string Roomid)
|
||||||
{
|
{
|
||||||
SQLHelper.Parameters["@Roomid"] = Roomid;
|
SQLHelper.Parameters["@Roomid"] = Roomid;
|
||||||
return $"{Command_Select} {Command_All} {Command_From} {TableName} {Command_Where} {Column_Roomid} = @Roomid";
|
return $"{Command_Select} {Command_All} {Command_From} {TableName} {Command_Where} {Column_Roomid} = @Roomid";
|
||||||
|
|||||||
@ -33,13 +33,13 @@ namespace Milimoe.FunGame.Core.Library.SQLScript.Entity
|
|||||||
return $"{Select_Users} {Command_Where} {Column_Id} = @Id";
|
return $"{Select_Users} {Command_Where} {Column_Id} = @Id";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string Select_IsExistEmail(SQLHelper SQLHelper, string Email)
|
public static string Select_UserByEmail(SQLHelper SQLHelper, string Email)
|
||||||
{
|
{
|
||||||
SQLHelper.Parameters["@Email"] = Email;
|
SQLHelper.Parameters["@Email"] = Email;
|
||||||
return $"{Select_Users} {Command_Where} {Column_Email} = @Email";
|
return $"{Select_Users} {Command_Where} {Column_Email} = @Email";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string Select_IsExistUsername(SQLHelper SQLHelper, string Username)
|
public static string Select_UserByUsername(SQLHelper SQLHelper, string Username)
|
||||||
{
|
{
|
||||||
SQLHelper.Parameters["@Username"] = Username;
|
SQLHelper.Parameters["@Username"] = Username;
|
||||||
return $"{Select_Users} {Command_Where} {Column_Username} = @Username";
|
return $"{Select_Users} {Command_Where} {Column_Username} = @Username";
|
||||||
|
|||||||
1
Library/SQLScript/PatchScript/mysql/2.0.0.250728.sql
Normal file
1
Library/SQLScript/PatchScript/mysql/2.0.0.250728.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE MarketItems CHANGE COLUMN Buyer Buyers VARCHAR(255) NOT NULL DEFAULT '';
|
||||||
43
Library/SQLScript/PatchScript/sqlite/2.0.0.250728.sql
Normal file
43
Library/SQLScript/PatchScript/sqlite/2.0.0.250728.sql
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
PRAGMA foreign_keys = OFF;
|
||||||
|
|
||||||
|
BEGIN TRANSACTION;
|
||||||
|
|
||||||
|
ALTER TABLE MarketItems RENAME TO _MarketItems_old;
|
||||||
|
|
||||||
|
CREATE TABLE MarketItems (
|
||||||
|
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
ItemGuid TEXT NOT NULL DEFAULT '',
|
||||||
|
UserId INTEGER NOT NULL DEFAULT 0,
|
||||||
|
Price REAL NOT NULL DEFAULT 0,
|
||||||
|
CreateTime DATETIME NOT NULL DEFAULT (DATETIME('now')),
|
||||||
|
FinishTime DATETIME DEFAULT NULL,
|
||||||
|
Status INTEGER NOT NULL DEFAULT 0,
|
||||||
|
Buyers TEXT NOT NULL DEFAULT ''
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO MarketItems (
|
||||||
|
Id,
|
||||||
|
ItemGuid,
|
||||||
|
UserId,
|
||||||
|
Price,
|
||||||
|
CreateTime,
|
||||||
|
FinishTime,
|
||||||
|
Status,
|
||||||
|
Buyers
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
Id,
|
||||||
|
ItemGuid,
|
||||||
|
UserId,
|
||||||
|
Price,
|
||||||
|
CreateTime,
|
||||||
|
FinishTime,
|
||||||
|
Status,
|
||||||
|
CAST(Buyer AS TEXT)
|
||||||
|
FROM _MarketItems_old;
|
||||||
|
|
||||||
|
DROP TABLE _MarketItems_old;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
PRAGMA foreign_keys = ON;
|
||||||
@ -95,7 +95,7 @@ CREATE TABLE `MarketItems` (
|
|||||||
`CreateTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
`CreateTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
`FinishTime` datetime DEFAULT NULL,
|
`FinishTime` datetime DEFAULT NULL,
|
||||||
`Status` int(10) NOT NULL DEFAULT '0',
|
`Status` int(10) NOT NULL DEFAULT '0',
|
||||||
`Buyer` bigint(20) NOT NULL DEFAULT '0',
|
`Buyers` varchar(255) NOT NULL DEFAULT '',
|
||||||
PRIMARY KEY (`Id`)
|
PRIMARY KEY (`Id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
|||||||
@ -92,7 +92,7 @@ CREATE TABLE MarketItems (
|
|||||||
CreateTime DATETIME NOT NULL DEFAULT (DATETIME('now')),
|
CreateTime DATETIME NOT NULL DEFAULT (DATETIME('now')),
|
||||||
FinishTime DATETIME DEFAULT NULL,
|
FinishTime DATETIME DEFAULT NULL,
|
||||||
Status INTEGER NOT NULL DEFAULT 0,
|
Status INTEGER NOT NULL DEFAULT 0,
|
||||||
Buyer INTEGER NOT NULL DEFAULT 0
|
Buyers TEXT NOT NULL DEFAULT ''
|
||||||
);
|
);
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
|
|||||||
18
Model/AIDecision.cs
Normal file
18
Model/AIDecision.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using Milimoe.FunGame.Core.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Interface.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Library.Common.Addon;
|
||||||
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
|
||||||
|
namespace Milimoe.FunGame.Core.Model
|
||||||
|
{
|
||||||
|
public class AIDecision
|
||||||
|
{
|
||||||
|
public CharacterActionType ActionType { get; set; } = CharacterActionType.EndTurn;
|
||||||
|
public Grid? TargetMoveGrid { get; set; } = null;
|
||||||
|
public ISkill? SkillToUse { get; set; } = null;
|
||||||
|
public Item? ItemToUse { get; set; } = null;
|
||||||
|
public List<Character> Targets { get; set; } = [];
|
||||||
|
public double Score { get; set; } = 0;
|
||||||
|
public bool IsPureMove { get; set; } = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -22,8 +22,8 @@ namespace Milimoe.FunGame.Core.Model
|
|||||||
characters ??= [];
|
characters ??= [];
|
||||||
return type switch
|
return type switch
|
||||||
{
|
{
|
||||||
RoomType.Team => new TeamGamingQueue(writer),
|
RoomType.Team => new TeamGamingQueue(characters, writer),
|
||||||
_ => new MixGamingQueue(writer)
|
_ => new MixGamingQueue(characters, writer)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using Milimoe.FunGame.Core.Entity;
|
using Milimoe.FunGame.Core.Entity;
|
||||||
|
using Milimoe.FunGame.Core.Library.Constant;
|
||||||
|
|
||||||
namespace Milimoe.FunGame.Core.Model
|
namespace Milimoe.FunGame.Core.Model
|
||||||
{
|
{
|
||||||
@ -37,6 +38,14 @@ namespace Milimoe.FunGame.Core.Model
|
|||||||
{ "E", 200 },
|
{ "E", 200 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 使用的魔法类型
|
||||||
|
/// </summary>
|
||||||
|
public HashSet<MagicType> UseMagicType { get; set; } = [
|
||||||
|
MagicType.None, MagicType.Starmark, MagicType.PurityNatural, MagicType.PurityContemporary,
|
||||||
|
MagicType.Element, MagicType.Bright, MagicType.Shadow, MagicType.Aster, MagicType.SpatioTemporal
|
||||||
|
];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始生命值
|
/// 初始生命值
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -286,6 +295,251 @@ namespace Milimoe.FunGame.Core.Model
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public double TakenDamageGetEPMax { get; set; } = 15;
|
public double TakenDamageGetEPMax { get; set; } = 15;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 单手剑的基础伤害倍率
|
||||||
|
/// </summary>
|
||||||
|
public double OneHandedSwordBaseMultiplier { get; set; } = 1.0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 单手剑的基础伤害倍率成长
|
||||||
|
/// </summary>
|
||||||
|
public double OneHandedSwordLevelBonus { get; set; } = 0.05;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 双手剑的基础伤害倍率
|
||||||
|
/// </summary>
|
||||||
|
public double TwoHandedSwordBaseMultiplier { get; set; } = 1.2;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 双手剑的基础伤害倍率成长
|
||||||
|
/// </summary>
|
||||||
|
public double TwoHandedSwordLevelBonus { get; set; } = 0.06;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 弓的基础伤害倍率
|
||||||
|
/// </summary>
|
||||||
|
public double BowBaseMultiplier { get; set; } = 0.9;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 弓的基础伤害倍率成长
|
||||||
|
/// </summary>
|
||||||
|
public double BowLevelBonus { get; set; } = 0.04;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 手枪的基础伤害倍率
|
||||||
|
/// </summary>
|
||||||
|
public double PistolBaseMultiplier { get; set; } = 0.9;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 手枪的基础伤害倍率成长
|
||||||
|
/// </summary>
|
||||||
|
public double PistolLevelBonus { get; set; } = 0.03;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 步枪的基础伤害倍率
|
||||||
|
/// </summary>
|
||||||
|
public double RifleBaseMultiplier { get; set; } = 1.1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 步枪的基础伤害倍率成长
|
||||||
|
/// </summary>
|
||||||
|
public double RifleLevelBonus { get; set; } = 0.05;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 双持短刀的基础伤害倍率
|
||||||
|
/// </summary>
|
||||||
|
public double DualDaggersBaseMultiplier { get; set; } = 0.85;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 双持短刀的基础伤害倍率成长
|
||||||
|
/// </summary>
|
||||||
|
public double DualDaggersLevelBonus { get; set; } = 0.04;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 法器的基础伤害倍率
|
||||||
|
/// </summary>
|
||||||
|
public double TalismanBaseMultiplier { get; set; } = 1.0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 法器的基础伤害倍率成长
|
||||||
|
/// </summary>
|
||||||
|
public double TalismanLevelBonus { get; set; } = 0.05;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 法杖的基础伤害倍率
|
||||||
|
/// </summary>
|
||||||
|
public double StaffBaseMultiplier { get; set; } = 1.15;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 法杖的基础伤害倍率成长
|
||||||
|
/// </summary>
|
||||||
|
public double StaffLevelBonus { get; set; } = 0.04;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 长柄武器的基础伤害倍率
|
||||||
|
/// </summary>
|
||||||
|
public double PolearmBaseMultiplier { get; set; } = 0.95;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 长柄武器的基础伤害倍率成长
|
||||||
|
/// </summary>
|
||||||
|
public double PolearmLevelBonus { get; set; } = 0.05;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 拳套的基础伤害倍率
|
||||||
|
/// </summary>
|
||||||
|
public double GauntletBaseMultiplier { get; set; } = 1.05;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 拳套的基础伤害倍率成长
|
||||||
|
/// </summary>
|
||||||
|
public double GauntletLevelBonus { get; set; } = 0.05;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 暗器的基础伤害倍率
|
||||||
|
/// </summary>
|
||||||
|
public double HiddenWeaponBaseMultiplier { get; set; } = 0.9;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 暗器的基础伤害倍率成长
|
||||||
|
/// </summary>
|
||||||
|
public double HiddenWeaponLevelBonus { get; set; } = 0.05;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 单手剑的硬直时间
|
||||||
|
/// </summary>
|
||||||
|
public double OneHandedSwordHardness { get; set; } = 8;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 双手剑的硬直时间
|
||||||
|
/// </summary>
|
||||||
|
public double TwoHandedSwordHardness { get; set; } = 12;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 弓的硬直时间
|
||||||
|
/// </summary>
|
||||||
|
public double BowHardness { get; set; } = 9;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 手枪的硬直时间
|
||||||
|
/// </summary>
|
||||||
|
public double PistolHardness { get; set; } = 6;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 步枪的硬直时间
|
||||||
|
/// </summary>
|
||||||
|
public double RifleHardness { get; set; } = 11;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 双持短刀的硬直时间
|
||||||
|
/// </summary>
|
||||||
|
public double DualDaggersHardness { get; set; } = 7;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 法器的硬直时间
|
||||||
|
/// </summary>
|
||||||
|
public double TalismanHardness { get; set; } = 10;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 法杖的硬直时间
|
||||||
|
/// </summary>
|
||||||
|
public double StaffHardness { get; set; } = 12;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 长柄武器的硬直时间
|
||||||
|
/// </summary>
|
||||||
|
public double PolearmHardness { get; set; } = 10;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 拳套的硬直时间
|
||||||
|
/// </summary>
|
||||||
|
public double GauntletHardness { get; set; } = 8;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 暗器的硬直时间
|
||||||
|
/// </summary>
|
||||||
|
public double HiddenWeaponHardness { get; set; } = 7;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 单手剑的攻击距离
|
||||||
|
/// </summary>
|
||||||
|
public int OneHandedSwordAttackRange { get; set; } = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 双手剑的攻击距离
|
||||||
|
/// </summary>
|
||||||
|
public int TwoHandedSwordAttackRange { get; set; } = 2;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 弓的攻击距离
|
||||||
|
/// </summary>
|
||||||
|
public int BowAttackRange { get; set; } = 4;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 手枪的攻击距离
|
||||||
|
/// </summary>
|
||||||
|
public int PistolAttackRange { get; set; } = 3;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 步枪的攻击距离
|
||||||
|
/// </summary>
|
||||||
|
public int RifleAttackRange { get; set; } = 5;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 双持短刀的攻击距离
|
||||||
|
/// </summary>
|
||||||
|
public int DualDaggersAttackRange { get; set; } = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 法器的攻击距离
|
||||||
|
/// </summary>
|
||||||
|
public int TalismanAttackRange { get; set; } = 5;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 法杖的攻击距离
|
||||||
|
/// </summary>
|
||||||
|
public int StaffAttackRange { get; set; } = 3;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 长柄武器的攻击距离
|
||||||
|
/// </summary>
|
||||||
|
public int PolearmAttackRange { get; set; } = 2;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 拳套的攻击距离
|
||||||
|
/// </summary>
|
||||||
|
public int GauntletAttackRange { get; set; } = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 暗器的攻击距离
|
||||||
|
/// </summary>
|
||||||
|
public int HiddenWeaponAttackRange { get; set; } = 4;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 核心角色的移动距离
|
||||||
|
/// </summary>
|
||||||
|
public int RoleMOV_Core { get; set; } = 3;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 先锋角色的移动距离
|
||||||
|
/// </summary>
|
||||||
|
public int RoleMOV_Vanguard { get; set; } = 6;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 近卫角色的移动距离
|
||||||
|
/// </summary>
|
||||||
|
public int RoleMOV_Guardian { get; set; } = 5;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 支援角色的移动距离
|
||||||
|
/// </summary>
|
||||||
|
public int RoleMOV_Support { get; set; } = 4;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 治疗角色的移动距离
|
||||||
|
/// </summary>
|
||||||
|
public int RoleMOV_Medic { get; set; } = 3;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 应用此游戏平衡常数给实体
|
/// 应用此游戏平衡常数给实体
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -38,7 +38,7 @@ namespace Milimoe.FunGame.Core.Model
|
|||||||
|
|
||||||
public void AddOrUpdateEvent(string name, IEnumerable<Activity> activities)
|
public void AddOrUpdateEvent(string name, IEnumerable<Activity> activities)
|
||||||
{
|
{
|
||||||
Events[name] = new(activities);
|
Events[name] = [.. activities];
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool RemoveEvent(string name)
|
public bool RemoveEvent(string name)
|
||||||
|
|||||||
1777
Model/GamingQueue.cs
1777
Model/GamingQueue.cs
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,9 @@ using Milimoe.FunGame.Core.Library.Constant;
|
|||||||
|
|
||||||
namespace Milimoe.FunGame.Core.Model
|
namespace Milimoe.FunGame.Core.Model
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 混战游戏队列,增强版混战模式 <see cref="RoomType.Mix"/>
|
||||||
|
/// </summary>
|
||||||
public class MixGamingQueue : GamingQueue
|
public class MixGamingQueue : GamingQueue
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -108,7 +111,7 @@ namespace Milimoe.FunGame.Core.Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建一个混战游戏队列并初始化行动顺序表
|
/// 创建一个混战游戏队列并初始化角色
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="characters"></param>
|
/// <param name="characters"></param>
|
||||||
/// <param name="writer"></param>
|
/// <param name="writer"></param>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
namespace Milimoe.FunGame.Core.Model
|
namespace Milimoe.FunGame.Core.Model
|
||||||
{
|
{
|
||||||
public class RecurringTask(string name, TimeSpan interval, Action action)
|
public class RecurringTask(string name, TimeSpan interval, Action action, Action<Exception>? error = null)
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 任务名称
|
/// 任务名称
|
||||||
@ -31,5 +31,10 @@
|
|||||||
/// 最后一次运行时发生的错误
|
/// 最后一次运行时发生的错误
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Exception? Error { get; set; }
|
public Exception? Error { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 捕获异常后,触发的回调函数
|
||||||
|
/// </summary>
|
||||||
|
public Action<Exception>? ErrorHandler { get; set; } = error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -98,7 +98,7 @@ namespace Milimoe.FunGame.Core.Model
|
|||||||
|
|
||||||
public Room GetRoom(string roomid) => _List.TryGetValue(roomid, out Room? room) ? room : General.HallInstance;
|
public Room GetRoom(string roomid) => _List.TryGetValue(roomid, out Room? room) ? room : General.HallInstance;
|
||||||
|
|
||||||
public bool IsExist(string roomid) => _List.ContainsKey(roomid);
|
public bool Exists(string roomid) => _List.ContainsKey(roomid);
|
||||||
|
|
||||||
public void SetRoomMaster(string roomid, User user)
|
public void SetRoomMaster(string roomid, User user)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -14,6 +14,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
public string SkillCost { get; set; } = "";
|
public string SkillCost { get; set; } = "";
|
||||||
public Item? Item { get; set; } = null;
|
public Item? Item { get; set; } = null;
|
||||||
public bool HasKill { get; set; } = false;
|
public bool HasKill { get; set; } = false;
|
||||||
|
public List<Character> Assists { get; set; } = [];
|
||||||
public Dictionary<Character, double> Damages { get; set; } = [];
|
public Dictionary<Character, double> Damages { get; set; } = [];
|
||||||
public Dictionary<Character, bool> IsCritical { get; set; } = [];
|
public Dictionary<Character, bool> IsCritical { get; set; } = [];
|
||||||
public Dictionary<Character, bool> IsEvaded { get; set; } = [];
|
public Dictionary<Character, bool> IsEvaded { get; set; } = [];
|
||||||
@ -65,6 +66,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
builder.AppendLine(string.Join(" / ", GetTargetsState()));
|
builder.AppendLine(string.Join(" / ", GetTargetsState()));
|
||||||
if (DeathContinuousKilling.Count > 0) builder.AppendLine($"{string.Join("\r\n", DeathContinuousKilling)}");
|
if (DeathContinuousKilling.Count > 0) builder.AppendLine($"{string.Join("\r\n", DeathContinuousKilling)}");
|
||||||
if (ActorContinuousKilling.Count > 0) builder.AppendLine($"{string.Join("\r\n", ActorContinuousKilling)}");
|
if (ActorContinuousKilling.Count > 0) builder.AppendLine($"{string.Join("\r\n", ActorContinuousKilling)}");
|
||||||
|
if (Assists.Count > 0) builder.AppendLine($"本回合助攻:[ {string.Join(" ] / [ ", Assists)} ]");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ActionType == CharacterActionType.PreCastSkill && Skill != null)
|
if (ActionType == CharacterActionType.PreCastSkill && Skill != null)
|
||||||
@ -75,11 +77,17 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
builder.AppendLine($"[ {Actor} ]:{Skill.Name}({SkillCost})-> ");
|
builder.Append($"[ {Actor} ] {Skill.Name}({SkillCost})-> ");
|
||||||
builder.AppendLine(string.Join(" / ", GetTargetsState()));
|
builder.AppendLine(string.Join(" / ", GetTargetsState()));
|
||||||
builder.AppendLine($"[ {Actor} ] 回合结束,硬直时间:{HardnessTime:0.##}");
|
builder.AppendLine($"[ {Actor} ] 回合结束,硬直时间:{HardnessTime:0.##}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (ActionType == CharacterActionType.UseItem && Item != null)
|
||||||
|
{
|
||||||
|
builder.Append($"[ {Actor} ] {Item.Name}{(SkillCost != "" ? $"({SkillCost})" : " ")}-> ");
|
||||||
|
builder.AppendLine(string.Join(" / ", GetTargetsState()));
|
||||||
|
builder.AppendLine($"[ {Actor} ] 回合结束,硬直时间:{HardnessTime:0.##}");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
builder.AppendLine($"[ {Actor} ] 回合结束,硬直时间:{HardnessTime:0.##}");
|
builder.AppendLine($"[ {Actor} ] 回合结束,硬直时间:{HardnessTime:0.##}");
|
||||||
@ -106,6 +114,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
string hasDamage = "";
|
string hasDamage = "";
|
||||||
string hasHeal = "";
|
string hasHeal = "";
|
||||||
string hasEffect = "";
|
string hasEffect = "";
|
||||||
|
string hasEvaded = "";
|
||||||
if (Damages.TryGetValue(target, out double damage))
|
if (Damages.TryGetValue(target, out double damage))
|
||||||
{
|
{
|
||||||
hasDamage = $"伤害:{damage:0.##}";
|
hasDamage = $"伤害:{damage:0.##}";
|
||||||
@ -126,19 +135,21 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
{
|
{
|
||||||
if (ActionType == CharacterActionType.NormalAttack)
|
if (ActionType == CharacterActionType.NormalAttack)
|
||||||
{
|
{
|
||||||
hasDamage = "完美闪避";
|
hasEvaded = hasDamage == "" ? "完美闪避" : "闪避";
|
||||||
}
|
}
|
||||||
else if ((ActionType == CharacterActionType.PreCastSkill || ActionType == CharacterActionType.CastSkill || ActionType == CharacterActionType.CastSuperSkill))
|
else if ((ActionType == CharacterActionType.PreCastSkill || ActionType == CharacterActionType.CastSkill || ActionType == CharacterActionType.CastSuperSkill))
|
||||||
{
|
{
|
||||||
hasDamage = "技能免疫";
|
hasEvaded = "技能免疫";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (IsImmune.ContainsKey(target) && hasDamage != "" && target != Actor)
|
if (IsImmune.ContainsKey(target) && hasDamage != "" && target != Actor)
|
||||||
{
|
{
|
||||||
hasDamage = "免疫";
|
hasDamage = "免疫";
|
||||||
}
|
}
|
||||||
string[] strs = [hasDamage, hasHeal, hasEffect];
|
string[] strs = [hasDamage, hasHeal, hasEffect, hasEvaded];
|
||||||
strings.Add($"[ {target}({string.Join(" / ", strs.Where(s => s != ""))})])");
|
strs = [.. strs.Where(s => s != "")];
|
||||||
|
if (strs.Length == 0) strings.Add($"[ {target} ])");
|
||||||
|
else strings.Add($"[ {target}({string.Join(" / ", strs)})])");
|
||||||
}
|
}
|
||||||
return strings;
|
return strings;
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
namespace Milimoe.FunGame.Core.Model
|
namespace Milimoe.FunGame.Core.Model
|
||||||
{
|
{
|
||||||
public class ScheduledTask(string name, TimeSpan timeSpan, Action action)
|
public class ScheduledTask(string name, TimeSpan timeSpan, Action action, Action<Exception>? error = null)
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 任务名称
|
/// 任务名称
|
||||||
@ -31,5 +31,10 @@
|
|||||||
/// 最后一次运行时发生的错误
|
/// 最后一次运行时发生的错误
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Exception? Error { get; set; }
|
public Exception? Error { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 捕获异常后,触发的回调函数
|
||||||
|
/// </summary>
|
||||||
|
public Action<Exception>? ErrorHandler { get; set; } = error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,9 @@ using Milimoe.FunGame.Core.Library.Constant;
|
|||||||
|
|
||||||
namespace Milimoe.FunGame.Core.Model
|
namespace Milimoe.FunGame.Core.Model
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 团队游戏队列,团队模式 <see cref="RoomType.Team"/>
|
||||||
|
/// </summary>
|
||||||
public class TeamGamingQueue : GamingQueue
|
public class TeamGamingQueue : GamingQueue
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -32,7 +35,7 @@ namespace Milimoe.FunGame.Core.Model
|
|||||||
/// <param name="characters"></param>
|
/// <param name="characters"></param>
|
||||||
public void AddTeam(string teamName, IEnumerable<Character> characters)
|
public void AddTeam(string teamName, IEnumerable<Character> characters)
|
||||||
{
|
{
|
||||||
if (teamName != "" && characters.Any())
|
if (teamName != "" && characters.Any(c => c.HP > 0))
|
||||||
{
|
{
|
||||||
_teams.Add(teamName, new(teamName, characters));
|
_teams.Add(teamName, new(teamName, characters));
|
||||||
}
|
}
|
||||||
@ -111,10 +114,20 @@ namespace Milimoe.FunGame.Core.Model
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected override async Task OnDeathCalculation(Character death, Character killer)
|
protected override async Task OnDeathCalculation(Character death, Character killer)
|
||||||
{
|
{
|
||||||
|
if (killer == death)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
Team? team = GetTeam(killer);
|
Team? team = GetTeam(killer);
|
||||||
if (team != null)
|
if (team != null)
|
||||||
{
|
{
|
||||||
team.Score++;
|
Team? team2 = GetTeam(death);
|
||||||
|
if (team == team2)
|
||||||
|
{
|
||||||
|
WriteLine($"[ {team} ] 受到了击杀队友惩罚!减少死亡竞赛得分!!");
|
||||||
|
team.Score--;
|
||||||
|
}
|
||||||
|
else team.Score++;
|
||||||
}
|
}
|
||||||
else await Task.CompletedTask;
|
else await Task.CompletedTask;
|
||||||
}
|
}
|
||||||
@ -134,7 +147,7 @@ namespace Milimoe.FunGame.Core.Model
|
|||||||
{
|
{
|
||||||
string[] teamActive = [.. Teams.OrderByDescending(kv => kv.Value.Score).Select(kv =>
|
string[] teamActive = [.. Teams.OrderByDescending(kv => kv.Value.Score).Select(kv =>
|
||||||
{
|
{
|
||||||
int activeCount = kv.Value.GetActiveCharacters(this).Count;
|
int activeCount = kv.Value.GetActiveCharacters().Count;
|
||||||
if (kv.Value == killTeam)
|
if (kv.Value == killTeam)
|
||||||
{
|
{
|
||||||
activeCount += 1;
|
activeCount += 1;
|
||||||
@ -146,7 +159,7 @@ namespace Milimoe.FunGame.Core.Model
|
|||||||
|
|
||||||
if (deathTeam != null)
|
if (deathTeam != null)
|
||||||
{
|
{
|
||||||
List<Character> remain = deathTeam.GetActiveCharacters(this);
|
List<Character> remain = deathTeam.GetActiveCharacters();
|
||||||
int remainCount = remain.Count;
|
int remainCount = remain.Count;
|
||||||
if (remainCount == 0)
|
if (remainCount == 0)
|
||||||
{
|
{
|
||||||
@ -162,8 +175,7 @@ namespace Milimoe.FunGame.Core.Model
|
|||||||
|
|
||||||
if (killTeam != null)
|
if (killTeam != null)
|
||||||
{
|
{
|
||||||
List<Character> actives = killTeam.GetActiveCharacters(this);
|
List<Character> actives = killTeam.GetActiveCharacters();
|
||||||
actives.Add(killer);
|
|
||||||
int remainCount = actives.Count;
|
int remainCount = actives.Count;
|
||||||
if (remainCount > 0 && MaxRespawnTimes == 0)
|
if (remainCount > 0 && MaxRespawnTimes == 0)
|
||||||
{
|
{
|
||||||
@ -285,7 +297,7 @@ namespace Milimoe.FunGame.Core.Model
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建一个团队游戏队列并初始化行动顺序表
|
/// 创建一个团队游戏队列并初始化角色
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="characters"></param>
|
/// <param name="characters"></param>
|
||||||
/// <param name="writer"></param>
|
/// <param name="writer"></param>
|
||||||
|
|||||||
@ -36,6 +36,8 @@ git clone -b latest https://github.com/project-redbud/FunGame-Core.git
|
|||||||
我们维护了一份 API 文档,如有需要请随时查阅:[FunGame 开发文档](https://project-redbud.github.io/)。
|
我们维护了一份 API 文档,如有需要请随时查阅:[FunGame 开发文档](https://project-redbud.github.io/)。
|
||||||
文档内容会随着本项目的更改而变化,但是我们不保证能够及时更新文档。
|
文档内容会随着本项目的更改而变化,但是我们不保证能够及时更新文档。
|
||||||
|
|
||||||
|
也欢迎查阅由 `DeepWiki` 提供的 AI 生成的文档:[DeepWiki 文档](https://deepwiki.com/project-redbud/FunGame-Core),此 AI 工具从头到尾分析了整个项目的代码并组织为 Wiki 形式,方便开发者结合源代码来理解整个项目。
|
||||||
|
|
||||||
在使用本项目的过程中遇到任何问题,欢迎提交 [issues](https://github.com/project-redbud/FunGame-Core/issues),我们会积极解决你的问题。
|
在使用本项目的过程中遇到任何问题,欢迎提交 [issues](https://github.com/project-redbud/FunGame-Core/issues),我们会积极解决你的问题。
|
||||||
|
|
||||||
## 许可证
|
## 许可证
|
||||||
|
|||||||
@ -22,7 +22,8 @@ namespace Milimoe.FunGame.Core.Service
|
|||||||
Converters = { new DateTimeConverter(), new DataTableConverter(), new DataSetConverter(), new UserConverter(), new RoomConverter(),
|
Converters = { new DateTimeConverter(), new DataTableConverter(), new DataSetConverter(), new UserConverter(), new RoomConverter(),
|
||||||
new CharacterConverter(), new MagicResistanceConverter(), new EquipSlotConverter(), new SkillConverter(), new EffectConverter(), new ItemConverter(),
|
new CharacterConverter(), new MagicResistanceConverter(), new EquipSlotConverter(), new SkillConverter(), new EffectConverter(), new ItemConverter(),
|
||||||
new InventoryConverter(), new NormalAttackConverter(), new ClubConverter(), new GoodsConverter(), new StoreConverter(),
|
new InventoryConverter(), new NormalAttackConverter(), new ClubConverter(), new GoodsConverter(), new StoreConverter(),
|
||||||
new NovelOptionConverter(), new NovelNodeConverter(), new ShieldConverter()
|
new NovelOptionConverter(), new NovelNodeConverter(), new ShieldConverter(), new RoundRecordConverter(), new ActivityConverter(), new QuestConverter(),
|
||||||
|
new MarketConverter(), new MarketItemConverter()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user