using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Interface.Addons;
using Milimoe.FunGame.Core.Interface.Base;
namespace Milimoe.FunGame.Core.Library.Common.Addon
{
public abstract class GameMap : IGameMap
{
///
/// 地图名称
///
public abstract string Name { get; }
///
/// 地图描述
///
public abstract string Description { get; }
///
/// 地图版本
///
public abstract string Version { get; }
///
/// 地图作者
///
public abstract string Author { get; }
///
/// 长度
///
public abstract int Length { get; }
///
/// 宽度
///
public abstract int Width { get; }
///
/// 高度
///
public abstract int Height { get; }
///
/// 格子大小
///
public abstract float Size { get; }
///
/// 格子集
///
public Dictionary Grids { get; } = [];
///
/// 格子集(基于坐标)
///
public Dictionary<(int x, int y, int z), Grid> GridsByCoordinate { get; } = [];
///
/// 角色集
///
public Dictionary Characters { get; } = [];
///
/// 使用坐标获取格子,0号格子的坐标是(0, 0),如果你还有高度的话,则是(0, 0, 0)
///
///
///
///
///
public Grid? this[int x, int y, int z = 0]
{
get
{
if (GridsByCoordinate.TryGetValue((x, y, z), out Grid? grid))
{
return grid;
}
return null;
}
}
///
/// 使用编号获取格子,从0号开始
///
///
///
public Grid? this[long id]
{
get
{
if (Grids.TryGetValue(id, out Grid? grid))
{
return grid;
}
return null;
}
}
///
/// 加载标记
///
private bool IsLoaded = false;
///
/// 加载地图
///
///
///
public bool Load(params object[] objs)
{
if (IsLoaded)
{
return false;
}
// BeforeLoad可以阻止加载此地图
if (BeforeLoad())
{
// 地图加载后,不允许再次加载此地图
IsLoaded = true;
// 生成格子
for (int x = 0; x < Length; x++)
{
for (int y = 0; y < Width; y++)
{
for (int z = 0; z < Height; z++)
{
Grid grid = new(Grids.Count, x, y, z);
Grids.Add(Grids.Count, grid);
GridsByCoordinate.Add((x, y, z), grid);
}
}
}
}
return IsLoaded;
}
///
/// 地图完全加载后需要做的事
///
public virtual void AfterLoad(GameModuleLoader loader, params object[] args)
{
// override
}
///
/// 允许返回false来阻止加载此地图
///
///
protected virtual bool BeforeLoad()
{
return true;
}
///
/// 获取角色当前所在的格子
///
///
///
public Grid? GetCharacterCurrentGrid(Character character)
{
if (Characters.TryGetValue(character, out Grid? current))
{
return current;
}
return null;
}
///
/// 强制设置角色当前所在的格子
///
///
///
///
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;
}
///
/// 将角色从地图中移除
///
///
///
public void RemoveCharacter(Character character)
{
Grid? current = GetCharacterCurrentGrid(character);
current?.Characters.Remove(character);
Characters[character] = Grid.Empty;
}
///
/// 获取以某个格子为中心,一定范围内的格子(曼哈顿距离),只考虑同一平面的格子,不包含中心格子。
///
///
///
///
public virtual List GetGridsByRange(Grid grid, int range)
{
List 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;
int y = grid.Y;
int z = grid.Z;
if (GridsByCoordinate.TryGetValue((x, y, z), out Grid? select) && select != null)
{
grids.Add(select);
}
}
}
}
grids.RemoveAll(g => g.Id == grid.Id);
return grids;
}
///
/// 设置角色移动
///
///
///
///
/// 移动的步数,只算平面移动步数
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);
if (current.Id == target.Id)
{
return 0;
}
// 记录走到某个格子时的步数
Queue<(Grid grid, int steps)> queue = new();
// 记录已访问的格子
HashSet visited = [];
// 将起始格子加入队列,步数为0,并标记为已访问
queue.Enqueue((current, 0));
visited.Add(current.Id);
while (queue.Count > 0)
{
var (currentGrid, currentSteps) = queue.Dequeue();
// 如果当前格子就是目标格子,则找到了最短路径
if (currentGrid.Id == target.Id)
{
realGrid?.Characters.Remove(character);
current.Characters.Remove(character);
target.Characters.Add(character);
Characters[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;
}
///
/// 初始化游戏队列
///
///
public virtual GameMap InitGamingQueue(IGamingQueue queue)
{
return this;
}
///
/// 在事件流逝前处理
///
///
protected virtual void BeforeTimeElapsed(ref double timeToReduce)
{
}
///
/// 在事件流逝后处理
///
///
protected virtual void AfterTimeElapsed(ref double timeToReduce)
{
}
///
/// 时间流逝时,处理格子上的特效
///
///
public void OnTimeElapsed(double timeToReduce)
{
BeforeTimeElapsed(ref timeToReduce);
foreach (Grid grid in Grids.Values)
{
List 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);
}
}
}