using FL.Battle;
using FL.Data;
using FL.FGUI;
using FL.Map;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using XGame;
using XGame.Database;
using XGame.Framework;
using XGame.Framework.Map;
using XGame.Framework.Nodes;
using XGame.Framework.Time;
namespace FL.Nodes.GameMain
{
public class MapComponent : NodeComponent
{
private int _chapterId;
private EMapSchedule _schedule;
private ITimer _monsterTimer;
///
/// boss战斗倒计时
///
private ITimer _bossTimer;
///
/// 是否挑战boss失败
/// 失败后战斗进入该关卡的小怪节点循环
/// UI显示挑战boss按钮
///
private bool _isBossFailed;
///
/// 是否在挑战boss
///
private bool _isBossChallenge;
private PlayerEntity _player;
/////
///// 怪物坐标相对出生点的偏移值
///// 怪物最多13个,分两排排列,索引如下
///// 二排 9 5 1 2 6 10
///// 一排 11 7 3 0 4 8 12
///// 0的左边偏移值为负数
/////
//private Vector3 _monsterOffset = new Vector3(0.8f, 1.5f, 0);
/////
///// 空闲的怪物位置索引
/////
//private List _unusedIndexs;
///
/// 怪物的实例对象
///
private Dictionary _monsterMap;
///
/// 伙伴的实例对象
///
private Dictionary _partnerMap;
private MapKey _currentMap;
public override void OnEnable(object intent)
{
EventSingle.Instance.AddListener(EventDefine.GameMainMapRemoveEntity, OnRemoveEntity);
EventSingle.Instance.AddListener(EventDefine.GameMainMapEndMask, OnMapEndMask);
EventSingle.Instance.AddListener(EventDefine.PartnerDown, OnPartnerDown);
EventSingle.Instance.AddListener(EventDefine.PartnerUp, OnPartnerUp);
EventSingle.Instance.AddListener(EventDefine.PartnerPlanChange, OnPartnersChanged);
EventSingle.Instance.AddListener(EventDefine.PartnerWearAll, OnPartnersChanged);
EventSingle.Instance.AddListener(EventDefine.GameMainMapChallengeBoss, OnChallengeBoss);
//InitMonsters();
StartMap(PlayerData.Instance.chapterId);
}
public override void OnDisable()
{
EventSingle.Instance.RemoveListener(EventDefine.GameMainMapRemoveEntity, OnRemoveEntity);
EventSingle.Instance.RemoveListener(EventDefine.GameMainMapEndMask, OnMapEndMask);
EventSingle.Instance.RemoveListener(EventDefine.PartnerDown, OnPartnerDown);
EventSingle.Instance.RemoveListener(EventDefine.PartnerUp, OnPartnerUp);
EventSingle.Instance.RemoveListener(EventDefine.PartnerPlanChange, OnPartnersChanged);
EventSingle.Instance.RemoveListener(EventDefine.PartnerWearAll, OnPartnersChanged);
EventSingle.Instance.RemoveListener(EventDefine.GameMainMapChallengeBoss, OnChallengeBoss);
_player = null;
_partnerMap?.Clear();
_monsterTimer?.Cancel();
_monsterTimer = null;
_bossTimer?.Cancel();
_bossTimer = null;
_isBossFailed = false;
_isBossChallenge = false;
_monsterMap?.Clear();
//_unusedIndexs?.Clear();
Context.Map.Close(_currentMap);
_currentMap = null;
}
//private void InitMonsters()
//{
// if (_unusedIndexs == null)
// _unusedIndexs = new List();
// else
// _unusedIndexs.Clear();
// for (var i = 0; i < 13; i++)
// {
// _unusedIndexs.Add(i);
// }
//}
private void StartMap(int chapterId)
{
_chapterId = chapterId;
_schedule = EMapSchedule.LoadingMap;
var chapter = ChapterTableRepo.Get(_chapterId);
var map = MapTableRepo.Get(chapter.Map);
var mapKey = MapKeys.NameToKey(map.AssetName);
if (mapKey == _currentMap)
{ // 是同一个地图
StartChapter(true, false);
}
else
{
// 关闭当前地图
Context.Map.Close(_currentMap);
_currentMap = mapKey;
// 加载新地图
var mapAsync = Context.Map.RunAsync(mapKey);
mapAsync.On(_ =>
{
StartChapter(true, true);
});
}
}
private void StartChapter(bool isChapterChanged, bool isMapChanged)
{
_schedule = EMapSchedule.Monster1;
var chapter = ChapterTableRepo.Get(_chapterId);
var map = MapTableRepo.Get(chapter.Map);
var dto = new LoadEntitiesDto();
dto.chapterId = _chapterId;
dto.isChapterChanged = isChapterChanged;
dto.isBossPart = chapter.Part_type == 1;
dto.isPlayerMove = true;// isChapterChanged || !_isBossFailed;
//战斗位置
dto.battlePosition = GetBattlePosition(map, chapter.Part);// map.BattlePositions[chapter.Part - 1].ToVector3();
var isGenPlayer = _player == null;
if (isGenPlayer)
{
_player = GenPlayer(map.PlayerBirth.ToVector3());
//玩家
dto.player = _player;
//伙伴
var partners = GenPartners(_player.BirthPosition);
AddPartners(partners);
dto.partners = partners;
}
else if (isMapChanged)
{
//玩家
dto.player = _player;
//伙伴
dto.partners = _partnerMap.Values.ToArray();
}
if (isChapterChanged || dto.isBossPart)
{
// 重置玩家血量
_player.Attr.Dynamic.Clear();
_player.Attr.ResetHp();
}
if (isChapterChanged)
{
// 随从可能有替换过,重置随从的出生点
var birthPosition = _player.BirthPosition;
foreach (var partner in _partnerMap.Values)
{
partner.BirthPosition = birthPosition + PartnersData.Instance.GetPartnerOffset(partner.Attr.UID);
}
}
//怪物数据
var monsters = GenMonsters();
AddMonsters(monsters);
dto.monsters = monsters;
dto.monsterMoveDistance = map.MonsterBirth.Y - map.BattleFirst.Y;// map.MonsterPositions[chapter.Part - 1].ToVector3().y - dto.battlePosition.y;
//定时器
if (!dto.isBossPart)
{ // 普通节点,增加定时器
//dto.monsterMoveDelay = 0;
if (_monsterTimer != null)
{ // 理论上不会出现这个错误
_monsterTimer.Cancel();
Log.Error($"StartChapter _monsterTimer error. chapterId:{_chapterId}");
}
_monsterTimer = Context.Time.AddDelayLooperTimer(chapter.Interval * 20, chapter.Interval * 20, OnLoopGenMonsters);
}
else
{ // boss关卡,直接到最后
//dto.monsterMoveDelay = 1000;
_schedule = EMapSchedule.Monster5;
Context.UI.OpenAsync(UIKeys.MainBossLaiXi);
Context.Time.AddDelayTimer(1000, () =>
{ //1秒后自动关闭
Context.UI.Close(UIKeys.MainBossLaiXi);
if (chapter.Time > 0)
{// boss战斗倒计时
_bossTimer = Context.Time.AddDelayTimer(chapter.Time, () =>
{
CombatFailed();
});
EventSingle.Instance.Notify(EventDefine.GameMainMapBossStart, chapter.Id);
}
});
}
EventSingle.Instance.Notify(EventDefine.GameMainMapLoadEntities, dto);
}
private void OnLoopGenMonsters(int times)
{
_schedule += 1;
if (_schedule == EMapSchedule.Monster5)
{
_monsterTimer.Cancel();
_monsterTimer = null;
}
var chapter = ChapterTableRepo.Get(_chapterId);
var map = MapTableRepo.Get(chapter.Map);
var dto = new LoadEntitiesDto();
dto.chapterId = _chapterId;
//战斗位置
dto.battlePosition = GetBattlePosition(map, chapter.Part);// map.BattlePositions[chapter.Part - 1].ToVector3();
//怪物数据
var monsters = GenMonsters();
AddMonsters(monsters);
dto.monsters = monsters;
dto.monsterMoveDistance = map.MonsterBirth.Y - map.BattleFirst.Y;// map.MonsterPositions[chapter.Part - 1].ToVector3().y - dto.battlePosition.y;
EventSingle.Instance.Notify(EventDefine.GameMainMapLoadEntities, dto);
}
private PlayerEntity GenPlayer(Vector3 birth)
{
var playerData = PlayerData.Instance;
var player = new PlayerEntity()
{
BirthPosition = birth//玩家出生点
};
var entityAttr = new EntityAttributes(0, playerData.UID)
{
Name = playerData.Name,
Radius = 1,
AttackCD = 2000,
};
entityAttr.CopyFrom(playerData.Attr);
player.Init(UIDDefine.New(), entityAttr, playerData.skillIds);
return player;
}
private PartnerEntity[] GenPartners(Vector3 targetPosition)
{
var goneUpMap = PartnersData.Instance.UpPartnerUIDMap;
var count = goneUpMap.Count;
var partners = new PartnerEntity[count];
var index = 0;
foreach (var partnerUID in goneUpMap.Keys)
{
partners[index++] = GenPartner(targetPosition, partnerUID);
}
return partners;
}
private PartnerEntity GenPartner(Vector3 targetPosition, long partnerId)
{
var partner = PartnersData.Instance.GetPartnerAttrByUID(partnerId);
var entity = new PartnerEntity()
{
BirthPosition = targetPosition + PartnersData.Instance.GetPartnerOffset(partner.UID),
EpigraphId = 20300,
};
var entityAttr = new EntityAttributes(partner.TableId, partner.UID)
{
Name = partner.Name,
Radius = partner.Radius,
AttackCD = 6000,
};
entityAttr.CopyFrom(partner.Attr);
var table = PartnerTableRepo.Get(partner.TableId);
entity.Init(UIDDefine.New(), entityAttr, new int[] { partner.SkillId });
return entity;
}
private void AddPartners(PartnerEntity[] partners)
{
if (_partnerMap == null)
{
_partnerMap = new Dictionary();
}
if (partners == null || partners.Length == 0) return;
foreach (var partner in partners)
{
_partnerMap.Add(partner.EntityId, partner);
}
}
private Vector3 GetMonsterBirth(Vector3 position, int index, int cols, out int row)
{
row = 0;
if (cols < 2)
return position;
var offset = 3;
if (cols == 2)
{
position.x -= offset;
offset *= 2;
}
else if (cols == 3)
{
position.x -= offset;
}
else
{
// 最多支持4列
cols = 4;
// -4.5, -1.5, 1.5, 4.5
position.x -= (offset * 1.5f);
}
row = index / cols;
position.x += (index % cols) * offset;
return position;
}
/////
///// 获取怪物的出生坐标和索引
/////
/////
/////
/////
//private Vector3 GetMonsterBirth(Vector3 position, out int positionIdx)
//{
// if (_unusedIndexs.Count > 0)
// {
// positionIdx = _unusedIndexs[0];
// _unusedIndexs.RemoveAt(0);
// }
// else
// {
// positionIdx = 0;
// }
// if (positionIdx == 0)
// {
// return position;
// }
// var offset = Vector3.zero;
// var xMultiple = (positionIdx + 1) / 2;
// offset.x = _monsterOffset.x * xMultiple;
// if (positionIdx % 2 != 0)
// { // 索引为奇数的在左边
// offset.x = -offset.x;
// }
// if (xMultiple % 2 != 0)
// { // 倍数为奇数的在上面
// offset.y = _monsterOffset.y;
// }
// var target = position + offset;
// // 随机偏移xy(-0.2, 0.2)
// target.x += Random.Range(-0.25f, 0.25f);
// target.y += Random.Range(-0.25f, 0.25f);
// return target;
//}
//private void PushMonstPositionIdx(int positionIdx)
//{
// if (_unusedIndexs.Contains(positionIdx))
// return; // 避免重复记录
// for (var i = 0; i < _unusedIndexs.Count; i++)
// {
// if (positionIdx < _unusedIndexs[i] && (i == 0 || positionIdx > _unusedIndexs[i - 1]))
// { // 小于当前索引的值 且 大于(i - 1 )的值
// _unusedIndexs.Insert(i, positionIdx);
// return;
// }
// }
// _unusedIndexs.Add(positionIdx);
//}
private MonsterEntity[] GenMonsters()
{
var chapter = ChapterTableRepo.Get(_chapterId);
var map = MapTableRepo.Get(chapter.Map);
Vector3 birthPosition = GetMonsterBirth(map, chapter.Part);// map.MonsterPositions[chapter.Part - 1].ToVector3();
int[] monsterRefresh = null;
switch (_schedule)
{
case EMapSchedule.Monster1:
monsterRefresh = chapter.Monster_refresh1;
break;
case EMapSchedule.Monster2:
monsterRefresh = chapter.Monster_refresh2;
break;
case EMapSchedule.Monster3:
monsterRefresh = chapter.Monster_refresh3;
break;
case EMapSchedule.Monster4:
monsterRefresh = chapter.Monster_refresh4;
break;
case EMapSchedule.Monster5:
monsterRefresh = chapter.Monster_refresh5;
break;
default:
break;
}
var monsterCount = (monsterRefresh != null && monsterRefresh.Length > 0) ? monsterRefresh[1] : 0;
if (monsterCount > 0)
{ // 数量0-3
var monsters = new MonsterEntity[monsterCount];
var cols = monsterRefresh[2]; // 敌人列数
var curve = monsterRefresh[3]; //移动轨迹
var isBossPart = chapter.Part_type == 1;
for (var i = 0; i < monsterCount; i++)
{
var position = GetMonsterBirth(birthPosition, i, cols, out var row);
var monsterTab = MonsterTableRepo.Get(monsterRefresh[0]);
var entityAttr = new EntityAttributes(monsterTab.Id, UIDDefine.New())
{
Name = monsterTab.Name,
Radius = monsterTab.ModelSize * 0.5f,
AttackCD = 3000,
};
entityAttr.Static.Hp = monsterTab.Hp;
entityAttr.Static.HpLimit = monsterTab.Hp;
entityAttr.Static.MoveSpeed = Mathf.RoundToInt(monsterTab.Speed);
entityAttr.Static.Attack = monsterTab.Atk;
entityAttr.CurrentHp = monsterTab.Hp;
var entity = new MonsterEntity();
entity.Init(UIDDefine.New(), entityAttr, monsterTab.Skills);
entity.BirthPosition = position;
entity.BirthDelay = row * chapter.Interval + (isBossPart ? 1000 : 0); // boss额外加1000毫秒延迟
entity.BirthCurve = curve;
entity.IsBoss = monsterTab.Type == 2;
monsters[i] = entity;
}
return monsters;
}
return null;
}
private void AddMonsters(MonsterEntity[] monsters)
{
if (monsters == null || monsters.Length == 0) return;
if (_monsterMap == null)
{
_monsterMap = new Dictionary();
}
foreach (var monsterInfo in monsters)
{
_monsterMap.Add(monsterInfo.EntityId, monsterInfo);
}
}
#region 事件监听
private void OnRemoveEntity(int eventId, object args)
{
var entityId = (long)args;
if (_monsterMap.TryGetValue(entityId, out var entity))
{
_monsterMap.Remove(entityId);
//PushMonstPositionIdx(entity.PositionIdx);
CheckMonsterAllDead();
return;
}
if (_partnerMap.TryGetValue(entityId, out var partner))
{
_partnerMap.Remove(entityId);
return;
}
if (entityId == _player.EntityId)
{
//TODO 失败结算
CombatFailed();
}
}
private void OnPartnerDown(int eventId, object args)
{
var partnerUID = (long)args;
var entityId = GetPartnerEntityIdByUID(partnerUID);
if (entityId == 0)
return;
EventSingle.Instance.Notify(EventDefine.GameMainMapRemoveEntity, entityId);
}
private void OnPartnerUp(int eventId, object args)
{
var partnerUID = (long)args;
var entityId = GetPartnerEntityIdByUID(partnerUID);
if (entityId != 0)
return; // 已经有实例对象了
var chapter = ChapterTableRepo.Get(_chapterId);
var map = MapTableRepo.Get(chapter.Map);
var dto = new LoadEntitiesDto();
dto.chapterId = _chapterId;
//战斗位置
dto.battlePosition = GetBattlePosition(map, chapter.Part);// map.BattlePositions[chapter.Part - 1].ToVector3();
var partner = GenPartner(dto.battlePosition, partnerUID);
var partners = new PartnerEntity[] { partner };
AddPartners(partners);
dto.partners = partners;
EventSingle.Instance.Notify(EventDefine.GameMainMapLoadEntities, dto);
}
private void OnPartnersChanged(int eventId, object args)
{
//TODO 临时代码
if (_partnerMap == null) return;
var partnerIds = _partnerMap.Keys.ToList();
_partnerMap.Clear();
foreach (var partnerId in partnerIds)
{
EventSingle.Instance.Notify(EventDefine.GameMainMapRemoveEntity, partnerId);
}
var chapter = ChapterTableRepo.Get(_chapterId);
var map = MapTableRepo.Get(chapter.Map);
var dto = new LoadEntitiesDto();
dto.chapterId = _chapterId;
//战斗位置
dto.battlePosition = GetBattlePosition(map, chapter.Part);// map.BattlePositions[chapter.Part - 1].ToVector3();
var partners = GenPartners(dto.battlePosition);
AddPartners(partners);
dto.partners = partners;
EventSingle.Instance.Notify(EventDefine.GameMainMapLoadEntities, dto);
}
private void OnChallengeBoss(int eventId, object args)
{
CombatFailed(true);
}
//private void OnExchangePartner(int eventId, object args)
//{
// var addPartners = (List)args;
// var activePartnerIds = PartnersData.Instance.ActiveUIDs;
// var count = addPartners.Count;
// // 从后往前移除
// for (var i = 0; i < count; i++)
// {
// var partnerId = activePartnerIds[activePartnerIds.Count - 1];
// activePartnerIds.RemoveAt(activePartnerIds.Count - 1);
// var EntityId = GetPartnerUIDByTableId(partnerId);
// if (EntityId == 0)
// continue;
// EventSingle.Instance.Notify(EventDefine.GameMainMapRemoveEntity, EntityId);
// }
// activePartnerIds.AddRange(addPartners);
// var chapter = ChapterTableRepo.Get(_chapterId);
// var map = MapTableRepo.Get(chapter.Map);
// var dto = new LoadEntitiesDto();
// dto.chapterId = _chapterId;
// //战斗位置
// dto.battlePosition = map.BattlePositions[chapter.Part - 1].ToVector3();
// var partners = GenPartners(dto.battlePosition, addPartners);
// AddPartners(partners);
// dto.partners = partners;
// EventSingle.Instance.Notify(EventDefine.GameMainMapLoadEntities, dto);
//}
private void OnMapEndMask(int eventId, object args)
{
var sign = (EMapCombatSign)args;
var chapter = ChapterTableRepo.Get(_chapterId);
int chapterId;
if (sign is EMapCombatSign.Success)
{
var nextChapter = ChapterTableRepo.Next(_chapterId);
//没找到新关卡,重新开始
if (nextChapter == null || nextChapter.Chapter != chapter.Chapter)
{ // 没有新关卡 || 章节id变化
//TODO 章节切换
}
chapterId = nextChapter?.Id ?? PlayerData.Instance.chapterId;
_isBossChallenge = false;
}
else if (sign is EMapCombatSign.Break)
{
var bossChapter = ChapterTableRepo.FindNearestBoss(_chapterId);
Assert.IsNotNull(bossChapter, $"找不到该关卡的boss节点. Id:{_chapterId}");
chapterId = bossChapter.Id;
_isBossFailed = false;
_isBossChallenge = true;
}
else
{ // 失败,重置到本关卡第一个节点
if (chapter.Part_type == 1)
{ // boss节点失败,进入本关卡小怪节点循环
_isBossFailed = true;
}
chapterId = _chapterId / 10 * 10 + 1;
_isBossChallenge = false;
}
StartMap(chapterId);
}
#endregion
private void CheckMonsterAllDead()
{
if (_monsterMap.Count > 0 || (_player != null && _player.IsDead)) return;
// 怪物全部死亡
var chapter = ChapterTableRepo.Get(_chapterId);
if (chapter.Part_type == 1)
{ //boss关卡
_isBossFailed = false;
//TODO 结算
_bossTimer?.Cancel();
_bossTimer = null;
Context.UI.OpenAsync(UIKeys.MainBattleOverVictory);
Context.Time.AddDelayTimer(2000, () =>
{ //2秒后自动关闭
Context.UI.Close(UIKeys.MainBattleOverVictory);
EventSingle.Instance.Notify(EventDefine.GameMainMapStartMask, EMapCombatSign.Success);
});
}
else if (_schedule == EMapSchedule.Monster5)
{
var nextId = _chapterId + 1;
if (_isBossFailed)
{ // boss节点失败,进入本关卡小怪节点循环
var nextChapter = ChapterTableRepo.Get(nextId);
if (nextChapter == null || nextChapter.Part_type == 1)
{
nextId = _chapterId / 10 * 10 + 1;
}
}
_chapterId = nextId;
StartChapter(false, false);
}
}
///
/// 战斗失败
///
private void CombatFailed(bool isBreak = false)
{
_monsterTimer?.Cancel();
_monsterTimer = null;
if (!isBreak)
Context.UI.OpenAsync(UIKeys.MainBattleOverFail);
var chapter = ChapterTableRepo.Get(_chapterId);
// 清空怪物数据
//foreach (var item in _monsterMap)
//{
// PushMonstPositionIdx(item.Value.PositionIdx);
//}
_monsterMap.Clear();
EventSingle.Instance.Notify(EventDefine.GameMainMapStartMask, isBreak ? EMapCombatSign.Break : (EMapCombatSign)(chapter.Part_type + 1));
}
private long GetPartnerEntityIdByUID(long uid)
{
foreach (var item in _partnerMap)
{
if (item.Value.Attr.UID == uid)
return item.Key;
}
return 0;
}
private Vector3 GetBattlePosition(MapTable map, int mapPart)
{
if (_isBossFailed || _isBossChallenge)
mapPart = 1; // boss失败后战斗位置不再前移
return map.BattleFirst.ToVector3() + map.PartMove.ToVector3() * (mapPart - 1);
}
private Vector3 GetMonsterBirth(MapTable map, int mapPart)
{
if (_isBossFailed || _isBossChallenge)
mapPart = 1; // boss失败后战斗位置不再前移
return map.MonsterBirth.ToVector3() + map.PartMove.ToVector3() * (mapPart - 1);
}
}
}