mirror of
https://github.com/project-redbud/FunGame-Core.git
synced 2025-12-05 08:09:02 +00:00
Compare commits
62 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 |
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)
|
||||||
{
|
{
|
||||||
|
case JsonValueKind.Number when arrayElement.TryGetInt64(out long longValue):
|
||||||
longList.Add(longValue);
|
longList.Add(longValue);
|
||||||
|
resultList.Add(longValue);
|
||||||
|
firstValueKind ??= JsonValueKind.Number;
|
||||||
|
if (firstValueKind != JsonValueKind.Number) isMixed = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JsonValueKind.Number when arrayElement.TryGetDouble(out double doubleValue):
|
||||||
|
douList.Add(doubleValue);
|
||||||
|
resultList.Add(doubleValue);
|
||||||
|
firstValueKind ??= JsonValueKind.Number;
|
||||||
|
if (firstValueKind != JsonValueKind.Number) isMixed = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JsonValueKind.Number when arrayElement.TryGetDecimal(out decimal decimalValue):
|
||||||
|
decList.Add(decimalValue);
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
else if (array_e.ValueKind == JsonValueKind.Number && array_e.TryGetDouble(out double douValue))
|
}
|
||||||
|
|
||||||
|
// 根据类型一致性选择存储的列表
|
||||||
|
if (resultList.Count > 0)
|
||||||
{
|
{
|
||||||
douList.Add(douValue);
|
if (!isMixed)
|
||||||
}
|
|
||||||
else if (array_e.ValueKind == JsonValueKind.Number && array_e.TryGetDecimal(out decimal decValue))
|
|
||||||
{
|
{
|
||||||
decList.Add(decValue);
|
// 所有元素类型一致,存储到对应的特定类型列表
|
||||||
}
|
switch (firstValueKind)
|
||||||
else if (array_e.ValueKind == JsonValueKind.String)
|
|
||||||
{
|
{
|
||||||
strList.Add(array_e.GetString() ?? "");
|
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 if (array_e.ValueKind == JsonValueKind.True || array_e.ValueKind == JsonValueKind.False)
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
bolList.Add(array_e.GetBoolean());
|
// 混合类型或包含对象/数组,存储为 List<object>
|
||||||
}
|
base.Add(key, resultList);
|
||||||
}
|
}
|
||||||
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 (strList.Count > 0) base.Add(key, strList);
|
/// <summary>
|
||||||
if (bolList.Count > 0) base.Add(key, bolList);
|
/// 递归解析 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,18 +35,17 @@ 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);
|
||||||
ScheduledTask task = new(name, timeOfDay, action);
|
|
||||||
if (DateTime.Now > DateTime.Today.Add(timeOfDay))
|
if (DateTime.Now > DateTime.Today.Add(timeOfDay))
|
||||||
{
|
{
|
||||||
task.LastRun = DateTime.Today.Add(timeOfDay);
|
task.LastRun = DateTime.Today.Add(timeOfDay);
|
||||||
}
|
}
|
||||||
_tasks.Add(task);
|
_tasks.Add(task);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 添加一个循环任务
|
/// 添加一个循环任务
|
||||||
@ -55,20 +54,19 @@ 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;
|
DateTime now = DateTime.Now;
|
||||||
now = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0);
|
now = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second, 0);
|
||||||
DateTime nextRun = startNow ? now : now.Add(interval);
|
DateTime nextRun = startNow ? now : now.Add(interval);
|
||||||
RecurringTask recurringTask = new(name, interval, action)
|
RecurringTask recurringTask = new(name, interval, action, error)
|
||||||
{
|
{
|
||||||
NextRun = nextRun
|
NextRun = nextRun
|
||||||
};
|
};
|
||||||
_recurringTasks.Add(recurringTask);
|
_recurringTasks.Add(recurringTask);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 移除任务计划
|
/// 移除任务计划
|
||||||
@ -76,12 +74,10 @@ 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,8 +161,7 @@ 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;
|
DateTime now = DateTime.Now;
|
||||||
|
|
||||||
foreach (ScheduledTask task in _tasks)
|
foreach (ScheduledTask task in _tasks)
|
||||||
@ -185,6 +180,8 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
task.Error = ex;
|
task.Error = ex;
|
||||||
|
TXTHelper.AppendErrorLog(ex.ToString());
|
||||||
|
task.ErrorHandler?.Invoke(ex);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -206,6 +203,8 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
recurringTask.Error = ex;
|
recurringTask.Error = ex;
|
||||||
|
TXTHelper.AppendErrorLog(ex.ToString());
|
||||||
|
recurringTask.ErrorHandler?.Invoke(ex);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -213,4 +212,3 @@ namespace Milimoe.FunGame.Core.Api.Utility
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@ -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,11 +129,15 @@ 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);
|
||||||
|
if (past != _Level)
|
||||||
|
{
|
||||||
OnAttributeChanged();
|
OnAttributeChanged();
|
||||||
Recovery();
|
Recovery();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 经验值
|
/// 经验值
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -914,12 +985,18 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <param name="pastMaxHP"></param>
|
/// <param name="pastMaxHP"></param>
|
||||||
/// <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)
|
||||||
|
{
|
||||||
|
if (pastHP > 0 && pastMaxHP > 0)
|
||||||
{
|
{
|
||||||
double pHP = pastHP / pastMaxHP;
|
double pHP = pastHP / pastMaxHP;
|
||||||
double pMP = pastMP / pastMaxMP;
|
|
||||||
HP = MaxHP * pHP;
|
HP = MaxHP * pHP;
|
||||||
|
}
|
||||||
|
if (pastMP > 0 && pastMaxMP > 0)
|
||||||
|
{
|
||||||
|
double pMP = pastMP / pastMaxMP;
|
||||||
MP = MaxMP * pMP;
|
MP = MaxMP * pMP;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 为角色装备物品(必须使用此方法而不是自己去给EquipSlot里的物品赋值)<para/>
|
/// 为角色装备物品(必须使用此方法而不是自己去给EquipSlot里的物品赋值)<para/>
|
||||||
@ -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,8 +1801,71 @@ 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(GetEquipSlotInfo().Trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Items.Count > 0)
|
||||||
|
{
|
||||||
|
builder.AppendLine(GetBackpackItemsInfo().Trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
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("== 装备栏 ==");
|
builder.AppendLine("== 装备栏 ==");
|
||||||
if (EquipSlot.MagicCardPack != null)
|
if (EquipSlot.MagicCardPack != null)
|
||||||
{
|
{
|
||||||
@ -1789,20 +1897,59 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Accessory2.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Accessory2) + ":" + EquipSlot.Accessory2.Name);
|
builder.AppendLine($"[{ItemSet.GetQualityTypeName(EquipSlot.Accessory2.QualityType)}]" + ItemSet.GetEquipSlotTypeName(EquipSlotType.Accessory2) + ":" + EquipSlot.Accessory2.Name);
|
||||||
builder.AppendLine(EquipSlot.Accessory2.Description);
|
builder.AppendLine(EquipSlot.Accessory2.Description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Items.Count > 0)
|
/// <summary>
|
||||||
|
/// 获取角色背包信息
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public string GetBackpackItemsInfo()
|
||||||
{
|
{
|
||||||
|
StringBuilder builder = new();
|
||||||
|
|
||||||
builder.AppendLine("== 角色背包 ==");
|
builder.AppendLine("== 角色背包 ==");
|
||||||
foreach (Item item in Items)
|
foreach (Item item in Items)
|
||||||
{
|
{
|
||||||
builder.Append(item.ToString());
|
builder.AppendLine($"[{ItemSet.GetQualityTypeName(item.QualityType)}]" + ItemSet.GetItemTypeName(item.ItemType) + ":" + item.Name);
|
||||||
|
builder.AppendLine(item.Description);
|
||||||
|
if (item.Skills.Active != null)
|
||||||
|
{
|
||||||
|
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,19 +2093,34 @@ 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)
|
||||||
|
{
|
||||||
|
if (skill.SkillType != SkillType.Magic || copyMagic)
|
||||||
{
|
{
|
||||||
Skill newskill = skill.Copy();
|
Skill newskill = skill.Copy();
|
||||||
newskill.Character = c;
|
newskill.Character = c;
|
||||||
c.Skills.Add(newskill);
|
c.Skills.Add(newskill);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (copyItem)
|
||||||
|
{
|
||||||
foreach (Item item in Items)
|
foreach (Item item in Items)
|
||||||
{
|
{
|
||||||
Item newitem = item.Copy();
|
Item newitem = item.Copy();
|
||||||
newitem.Character = c;
|
newitem.Character = c;
|
||||||
c.Items.Add(newitem);
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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,13 +346,14 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReduceTimesAndRemove()
|
/// <summary>
|
||||||
{
|
/// 使用后减少使用次数或删除物品
|
||||||
if (User != null)
|
/// </summary>
|
||||||
|
public void ReduceTimesAndRemove(int times = 1)
|
||||||
{
|
{
|
||||||
if (IsReduceTimesAfterUse)
|
if (IsReduceTimesAfterUse)
|
||||||
{
|
{
|
||||||
RemainUseTimes--;
|
RemainUseTimes -= times;
|
||||||
}
|
}
|
||||||
if (RemainUseTimes < 0) RemainUseTimes = 0;
|
if (RemainUseTimes < 0) RemainUseTimes = 0;
|
||||||
if (IsRemoveAfterUse && RemainUseTimes == 0)
|
if (IsRemoveAfterUse && RemainUseTimes == 0)
|
||||||
@ -361,7 +361,6 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
EntityState = EntityState.Deleted;
|
EntityState = EntityState.Deleted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当物品被角色使用时
|
/// 当物品被角色使用时
|
||||||
@ -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,7 +480,15 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
List<string> sellandtrade = [];
|
List<string> sellandtrade = [];
|
||||||
|
bool useRN = false;
|
||||||
|
|
||||||
|
if (IsLock)
|
||||||
|
{
|
||||||
|
sellandtrade.Add("不可出售");
|
||||||
|
sellandtrade.Add("不可交易");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (IsSellable)
|
if (IsSellable)
|
||||||
{
|
{
|
||||||
sellandtrade.Add("可出售");
|
sellandtrade.Add("可出售");
|
||||||
@ -479,6 +496,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
|
|
||||||
if (!IsSellable && NextSellableTime != DateTime.MinValue)
|
if (!IsSellable && NextSellableTime != DateTime.MinValue)
|
||||||
{
|
{
|
||||||
|
useRN = true;
|
||||||
sellandtrade.Add($"此物品将在 {NextSellableTime.ToString(General.GeneralDateTimeFormatChinese)} 后可出售");
|
sellandtrade.Add($"此物品将在 {NextSellableTime.ToString(General.GeneralDateTimeFormatChinese)} 后可出售");
|
||||||
}
|
}
|
||||||
else if (!IsSellable)
|
else if (!IsSellable)
|
||||||
@ -493,14 +511,16 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
|
|
||||||
if (!IsTradable && NextTradableTime != DateTime.MinValue)
|
if (!IsTradable && NextTradableTime != DateTime.MinValue)
|
||||||
{
|
{
|
||||||
|
useRN = true;
|
||||||
sellandtrade.Add($"此物品将在 {NextTradableTime.ToString(General.GeneralDateTimeFormatChinese)} 后可交易");
|
sellandtrade.Add($"此物品将在 {NextTradableTime.ToString(General.GeneralDateTimeFormatChinese)} 后可交易");
|
||||||
}
|
}
|
||||||
else if (!IsTradable)
|
else if (!IsTradable)
|
||||||
{
|
{
|
||||||
sellandtrade.Add("不可交易");
|
sellandtrade.Add("不可交易");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sellandtrade.Count > 0) builder.AppendLine(string.Join(" ", sellandtrade).Trim());
|
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
|
||||||
@ -73,7 +74,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否显示在状态栏
|
/// 是否显示在状态栏
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ShowInStatusBar => !ForceHideInStatusBar && !IsSubsidiary && (Skill.Item is null || (Durative && Duration > 0) || DurationTurn > 0 || DurativeWithoutDuration);
|
public bool ShowInStatusBar => !ForceHideInStatusBar && (Skill.Item is null || (Durative && Duration > 0) || DurationTurn > 0 || DurativeWithoutDuration);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 特效是否生效
|
/// 特效是否生效
|
||||||
@ -218,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)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -232,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;
|
||||||
}
|
}
|
||||||
@ -248,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>
|
||||||
@ -335,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)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -354,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)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -508,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"/>
|
||||||
@ -531,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;
|
||||||
}
|
}
|
||||||
@ -574,6 +633,8 @@ 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 (isEnemy != effect.IsDebuff)
|
||||||
|
{
|
||||||
if (target.CharacterEffectTypes.TryGetValue(effect, out List<EffectType>? types) && types != null)
|
if (target.CharacterEffectTypes.TryGetValue(effect, out List<EffectType>? types) && types != null)
|
||||||
{
|
{
|
||||||
RemoveEffectTypesByDispel(types, isEnemy);
|
RemoveEffectTypesByDispel(types, isEnemy);
|
||||||
@ -587,6 +648,7 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
{
|
{
|
||||||
removeEffectTypes = true;
|
removeEffectTypes = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// 友方移除控制状态
|
// 友方移除控制状态
|
||||||
if (!isEnemy && effect.IsDebuff)
|
if (!isEnemy && effect.IsDebuff)
|
||||||
{
|
{
|
||||||
@ -654,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;
|
||||||
}
|
}
|
||||||
@ -684,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;
|
||||||
}
|
}
|
||||||
@ -700,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;
|
||||||
}
|
}
|
||||||
@ -714,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -955,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>
|
||||||
@ -965,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>
|
||||||
@ -991,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,22 +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>
|
||||||
/// 普通攻击的通用说明
|
/// 普通攻击的通用说明
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string GeneralDescription => $"对目标敌人造成基于 100(+5/Lv)% 攻击力的{(IsMagic ? CharacterSet.GetMagicDamageName(MagicType) : "物理伤害")}。";
|
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>
|
||||||
/// 普通攻击等级
|
/// 普通攻击等级
|
||||||
@ -74,9 +129,44 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
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>
|
||||||
/// 实际硬直时间
|
/// 实际硬直时间
|
||||||
@ -98,15 +188,25 @@ 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>
|
||||||
/// 普通攻击没有魔法消耗
|
/// 普通攻击没有魔法消耗
|
||||||
@ -133,34 +233,104 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public double CurrentCD => 0;
|
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);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Character character in teammates)
|
||||||
|
{
|
||||||
if (CanSelectTeammate)
|
if (CanSelectTeammate)
|
||||||
{
|
{
|
||||||
selectable.AddRange(teammates);
|
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>
|
||||||
@ -177,24 +347,91 @@ namespace Milimoe.FunGame.Core.Entity
|
|||||||
{
|
{
|
||||||
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>
|
||||||
@ -218,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();
|
||||||
@ -235,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (Character character in enemys)
|
||||||
|
{
|
||||||
|
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)
|
if (CanSelectTeammate)
|
||||||
{
|
{
|
||||||
selectable.AddRange(teammates);
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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; }
|
||||||
|
|||||||
@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
<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>
|
||||||
@ -18,29 +18,19 @@
|
|||||||
<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-0428)
|
See github releases for details on the latest changes.
|
||||||
- Abstract ActionQueue as GamingQueue, and separate the original Mix / Team modes into two queue types: MixGamingQueue and TeamGamingQueue. (1.0.0-rc.1-0502)
|
|
||||||
- In the Effect class, added ParentEffect and ForceHideInStatusBar properties for more precise control of the status bar display. (1.0.0-rc.1-0509)
|
|
||||||
- Added helper methods IsTeammate and GetIsTeammateDictionary to GamingQueue for determining if someone is a teammate, IGamingQueue also. This facilitates the skill effects to determine whether the target is a teammate. (1.0.0-rc.1-0509)
|
|
||||||
- Added more properties (such as Name, RealCD) to the ISkill interface. Both NormalAttack and Skill inherit from ISkill, thus implementing these properties, although some properties are not meaningful for NormalAttack. (1.0.0-rc.1-0509)
|
|
||||||
- Added corresponding text for EffectTypes Lifesteal and GrievousWound. (1.0.0-rc.1-0509)
|
|
||||||
- Added EffectTypes: WeakDispelling and StrongDispelling, representing DurativeWeak and DurativeStrong of DispelType. (1.0.0-rc.1-0509)
|
|
||||||
- Added underlying processing support for continuous dispelling in the TimeLapse method. (1.0.0-rc.1-0509)
|
|
||||||
- Fixed an issue where the effect's shield hook provided incorrect parameters. (1.0.0-rc.1-0509)
|
|
||||||
- Fixed an issue where the result of pre-hooks for evade and critical hit checks always deferred to the result of the last effect. It should be that if any effect prevents the check, it is skipped. (1.0.0-rc.1-0509)
|
|
||||||
- Added comments for some code. (1.0.0-rc.1-0509)
|
|
||||||
</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>
|
||||||
|
|
||||||
|
|||||||
@ -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,9 @@ 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>
|
||||||
/// 判断目标对于某个角色是否是队友
|
/// 判断目标对于某个角色是否是队友
|
||||||
@ -184,6 +219,12 @@ namespace Milimoe.FunGame.Core.Interface.Base
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Dictionary<Character, bool> GetIsTeammateDictionary(Character character, IEnumerable<Character> targets);
|
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 控制状态
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -198,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
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
|
||||||
{
|
{
|
||||||
@ -7,6 +8,11 @@ namespace Milimoe.FunGame.Core.Interface.Entity
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface ISkill : IBaseEntity
|
public interface ISkill : IBaseEntity
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 所属的行动顺序表实例
|
||||||
|
/// </summary>
|
||||||
|
public IGamingQueue? GamingQueue { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 此技能所属的角色
|
/// 此技能所属的角色
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -51,15 +57,26 @@ 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>
|
||||||
/// 实际魔法消耗 [ 魔法 ]
|
/// 实际魔法消耗 [ 魔法 ]
|
||||||
@ -99,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
|
||||||
@ -686,6 +748,9 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
EffectType.GrievousWound => "重伤",
|
EffectType.GrievousWound => "重伤",
|
||||||
EffectType.WeakDispelling => "持续性弱驱散",
|
EffectType.WeakDispelling => "持续性弱驱散",
|
||||||
EffectType.StrongDispelling => "持续性强驱散",
|
EffectType.StrongDispelling => "持续性强驱散",
|
||||||
|
EffectType.Recovery => "恢复",
|
||||||
|
EffectType.Vulnerable => "易伤",
|
||||||
|
EffectType.Delay => "迟滞",
|
||||||
_ => "未知效果"
|
_ => "未知效果"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -743,6 +808,9 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
EffectType.Lifesteal => DispelledType.Weak,
|
EffectType.Lifesteal => DispelledType.Weak,
|
||||||
EffectType.GrievousWound => DispelledType.Weak,
|
EffectType.GrievousWound => DispelledType.Weak,
|
||||||
EffectType.WeakDispelling => DispelledType.Weak,
|
EffectType.WeakDispelling => DispelledType.Weak,
|
||||||
|
EffectType.Recovery => DispelledType.Weak,
|
||||||
|
EffectType.Vulnerable => DispelledType.Weak,
|
||||||
|
EffectType.Delay => DispelledType.Weak,
|
||||||
_ => DispelledType.Weak
|
_ => DispelledType.Weak
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -797,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
|
||||||
|
|||||||
@ -297,7 +297,7 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
Taunt,
|
Taunt,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 减速,目标行动速度和攻击频率降低
|
/// 减速,目标行动速度或加速系数降低
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Slow,
|
Slow,
|
||||||
|
|
||||||
@ -312,12 +312,12 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
Poison,
|
Poison,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 燃烧,目标受到火焰伤害,持续一段时间
|
/// 燃烧,目标受到伤害,持续一段时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Burn,
|
Burn,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 流血,目标持续受到物理伤害
|
/// 流血,目标持续受到伤害
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Bleed,
|
Bleed,
|
||||||
|
|
||||||
@ -417,7 +417,7 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
Confusion,
|
Confusion,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 石化,目标无法行动,并大幅增加受到的伤害
|
/// 石化,目标无法行动
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Petrify,
|
Petrify,
|
||||||
|
|
||||||
@ -479,7 +479,22 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 持续性强驱散
|
/// 持续性强驱散
|
||||||
/// </summary>
|
/// </summary>
|
||||||
StrongDispelling
|
StrongDispelling,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 恢复
|
||||||
|
/// </summary>
|
||||||
|
Recovery,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 易伤
|
||||||
|
/// </summary>
|
||||||
|
Vulnerable,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 迟滞,硬直时间延长
|
||||||
|
/// </summary>
|
||||||
|
Delay
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ItemType
|
public enum ItemType
|
||||||
@ -627,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
|
||||||
@ -725,6 +740,7 @@ namespace Milimoe.FunGame.Core.Library.Constant
|
|||||||
public enum CharacterActionType
|
public enum CharacterActionType
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
|
Move,
|
||||||
NormalAttack,
|
NormalAttack,
|
||||||
PreCastSkill,
|
PreCastSkill,
|
||||||
CastSkill,
|
CastSkill,
|
||||||
@ -1021,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)
|
||||||
|
|||||||
1498
Model/GamingQueue.cs
1498
Model/GamingQueue.cs
File diff suppressed because it is too large
Load Diff
@ -111,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,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));
|
||||||
}
|
}
|
||||||
@ -114,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;
|
||||||
}
|
}
|
||||||
@ -137,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;
|
||||||
@ -149,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)
|
||||||
{
|
{
|
||||||
@ -165,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)
|
||||||
{
|
{
|
||||||
@ -288,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>
|
||||||
|
|||||||
@ -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