488 lines
19 KiB
C#
488 lines
19 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Godot;
|
|
using Milimoe.FunGame.Core.Api.Utility;
|
|
using Milimoe.FunGame.Core.Entity;
|
|
using Milimoe.FunGame.Core.Library.Common.Addon;
|
|
using Milimoe.FunGame.Core.Library.Constant;
|
|
using Milimoe.FunGame.Core.Model;
|
|
using Oshima.Core.Constant;
|
|
using Oshima.FunGame.OshimaModules.Effects.OpenEffects;
|
|
using Oshima.FunGame.OshimaModules.Models;
|
|
using Oshima.FunGame.OshimaServers.Service;
|
|
|
|
namespace Milimoe.GodotGame;
|
|
|
|
public partial class Fighting : Control
|
|
{
|
|
[Export]
|
|
public TileMapLayer TileMapLayer { get; set; }
|
|
|
|
[Export]
|
|
public Camera2D CameraFight { get; set; }
|
|
|
|
public Character Character { get; set; }
|
|
public Node ParentUI { get; set; }
|
|
public Node NovelUI { get; set; }
|
|
public RichTextLabel FightLog { get; set; }
|
|
public Vector2I StartCell { get; set; }
|
|
public EnemyBody Enemy { get; set; }
|
|
|
|
public GamingQueue GamingQueue => _gamingQueue;
|
|
public Dictionary<Character, CharacterStatistics> CharacterStatistics { get; } = [];
|
|
public static Dictionary<Character, CharacterStatistics> TeamCharacterStatistics { get; } = [];
|
|
public PluginConfig StatsConfig { get; } = new(nameof(Fighting), nameof(CharacterStatistics));
|
|
public PluginConfig TeamStatsConfig { get; } = new(nameof(Fighting), nameof(TeamCharacterStatistics));
|
|
public bool IsWeb { get; set; } = false;
|
|
public bool TeamMode { get; set; } = false;
|
|
public string Msg { get; set; } = "";
|
|
|
|
private GamingQueue _gamingQueue = null;
|
|
private bool _fastMode = false;
|
|
|
|
public override void _Ready()
|
|
{
|
|
InitCharacter();
|
|
}
|
|
|
|
public async Task<List<string>> StartGame(bool isWeb = false, bool isTeam = false)
|
|
{
|
|
IsWeb = isWeb;
|
|
TeamMode = isTeam;
|
|
try
|
|
{
|
|
List<string> result = [];
|
|
Msg = "";
|
|
List<Character> allCharactersInGame = [.. FunGameConstant.Characters.OrderBy(o => Random.Shared.Next()).Take(3)];
|
|
TeamGamingQueue tgq = null;
|
|
MixGamingQueue mgq = null;
|
|
|
|
int clevel = 60;
|
|
int slevel = 6;
|
|
int mlevel = 8;
|
|
|
|
// 升级和赋能
|
|
List<Character> characters = [];
|
|
for (int index = 0; index < allCharactersInGame.Count; index++)
|
|
{
|
|
Character c = allCharactersInGame[index];
|
|
c.Level = clevel;
|
|
c.NormalAttack.Level = mlevel;
|
|
FunGameService.AddCharacterSkills(c, 1, slevel, slevel);
|
|
foreach (Skill skillLoop in FunGameConstant.Skills)
|
|
{
|
|
Skill skill = skillLoop.Copy();
|
|
skill.Character = c;
|
|
skill.Level = slevel;
|
|
c.Skills.Add(skill);
|
|
}
|
|
foreach (Skill skillLoop in FunGameConstant.CommonPassiveSkills)
|
|
{
|
|
Skill passive = skillLoop.Copy();
|
|
passive.Character = c;
|
|
passive.Level = 1;
|
|
c.Skills.Add(passive);
|
|
}
|
|
c.EP = 100;
|
|
characters.Add(c);
|
|
}
|
|
Character.NormalAttack.Level = mlevel;
|
|
foreach (Skill skillLoop in FunGameConstant.Skills)
|
|
{
|
|
Skill skill = skillLoop.Copy();
|
|
skill.Character = Character;
|
|
skill.Level = slevel;
|
|
Character.Skills.Add(skill);
|
|
}
|
|
foreach (Skill skillLoop in FunGameConstant.CommonPassiveSkills)
|
|
{
|
|
Skill passive = skillLoop.Copy();
|
|
passive.Character = Character;
|
|
passive.Level = 1;
|
|
Character.Skills.Add(passive);
|
|
}
|
|
Character.EP = 100;
|
|
characters.Add(Character);
|
|
|
|
// 询问玩家需要选择哪个角色 (通过UI界面选择)
|
|
Character player = Character ?? throw new Exception("没有选择角色,游戏结束。");
|
|
|
|
// 创建顺序表并排序
|
|
Team team1 = null, team2 = null;
|
|
if (isTeam)
|
|
{
|
|
tgq = new(WriteLine)
|
|
{
|
|
GameplayEquilibriumConstant = OshimaGameModuleConstant.GameplayEquilibriumConstant
|
|
};
|
|
_gamingQueue = tgq;
|
|
WriteLine("=== 团队模式随机分组 ===");
|
|
|
|
// 打乱角色列表
|
|
List<Character> shuffledCharacters = [.. characters.OrderBy(c => Random.Shared.Next())];
|
|
|
|
// 创建两个团队
|
|
List<Character> group1 = [];
|
|
List<Character> group2 = [];
|
|
|
|
// 将角色交替分配到两个团队中
|
|
for (int cid = 0; cid < shuffledCharacters.Count; cid++)
|
|
{
|
|
Character thisCharacter = shuffledCharacters[cid];
|
|
if (cid % 2 == 0)
|
|
{
|
|
group1.Add(thisCharacter);
|
|
}
|
|
else
|
|
{
|
|
group2.Add(thisCharacter);
|
|
}
|
|
}
|
|
|
|
// 添加到团队字典,第一个为队长
|
|
tgq.AddTeam($"{group1.First().NickName}的小队", group1);
|
|
tgq.AddTeam($"{group2.First().NickName}的小队", group2);
|
|
|
|
foreach (Team team in tgq.Teams.Values)
|
|
{
|
|
WriteLine($"团队【{team.Name}】的成员:\r\n{string.Join("\r\n", team.Members)}\r\n");
|
|
if (team.IsOnThisTeam(player))
|
|
{
|
|
foreach (Character c in team.Members.Except([player]))
|
|
{
|
|
c.Promotion = 300;
|
|
}
|
|
team1 = team;
|
|
}
|
|
else
|
|
{
|
|
team.Members.ForEach(c => c.Promotion = 400);
|
|
team2 = team;
|
|
}
|
|
}
|
|
|
|
// 初始化角色
|
|
_gamingQueue.InitCharacters(characters);
|
|
}
|
|
else
|
|
{
|
|
mgq = new MixGamingQueue(characters, WriteLine)
|
|
{
|
|
GameplayEquilibriumConstant = OshimaGameModuleConstant.GameplayEquilibriumConstant
|
|
};
|
|
_gamingQueue = mgq;
|
|
}
|
|
|
|
// 启用调试模式
|
|
//_gamingQueue.IsDebug = true;
|
|
|
|
// 加载地图和绑定事件
|
|
_gamingQueue.LoadGameMap(new GodotMap(TileMapLayer));
|
|
_gamingQueue.UseQueueProtected = false;
|
|
if (_gamingQueue.Map != null)
|
|
{
|
|
GodotMap map = (GodotMap)_gamingQueue.Map;
|
|
HashSet<Grid> allocated = [];
|
|
List<Grid> allGrids = [.. map.Grids.Values];
|
|
if (isTeam && tgq != null && team1 != null && team2 != null)
|
|
{
|
|
// 团队模式放置角色
|
|
Grid currentGrid = map.GetGridByVector2I(StartCell);
|
|
List<Grid> grids = map.GetGridsByRange(currentGrid, 10);
|
|
foreach (Character character in characters)
|
|
{
|
|
Grid grid = grids.OrderBy(o => Random.Shared.Next()).FirstOrDefault(g => g.Characters.Count == 0);
|
|
map.SetCharacterCurrentGrid(character, grid);
|
|
}
|
|
map.SetCharacterCurrentGrid(Character, currentGrid);
|
|
}
|
|
else
|
|
{
|
|
// 非团队模式,随机放置角色
|
|
foreach (Character character in characters)
|
|
{
|
|
character.NormalAttack.GamingQueue = _gamingQueue;
|
|
Grid grid = Grid.Empty;
|
|
do
|
|
{
|
|
grid = allGrids[Random.Shared.Next(allGrids.Count)];
|
|
}
|
|
while (allocated.Contains(grid));
|
|
allocated.Add(grid);
|
|
map.SetCharacterCurrentGrid(character, grid);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 绑定事件
|
|
//await Controller.SetQueue(_gamingQueue.HardnessTime);
|
|
//await Controller.SetCharacterStatistics(_gamingQueue.CharacterStatistics);
|
|
//_gamingQueue.TurnStartEvent += GamingQueue_TurnStart;
|
|
//_gamingQueue.DecideActionEvent += GamingQueue_DecideAction;
|
|
//_gamingQueue.SelectNormalAttackTargetsEvent += GamingQueue_SelectNormalAttackTargets;
|
|
//_gamingQueue.SelectSkillEvent += GamingQueue_SelectSkill;
|
|
//_gamingQueue.SelectSkillTargetsEvent += GamingQueue_SelectSkillTargets;
|
|
//_gamingQueue.SelectNonDirectionalSkillTargetsEvent += GamingQueue_SelectNonDirectionalSkillTargets;
|
|
//_gamingQueue.SelectItemEvent += GamingQueue_SelectItem;
|
|
//_gamingQueue.QueueUpdatedEvent += GamingQueue_QueueUpdated;
|
|
//_gamingQueue.TurnEndEvent += GamingQueue_TurnEnd;
|
|
//_gamingQueue.CharacterInquiryEvent += GamingQueue_CharacterInquiryEvent;
|
|
//_gamingQueue.CharacterActionTakenEvent += GamingQueue_CharacterActionTakenEvent
|
|
//_gamingQueue.SelectTargetGridEvent += GamingQueue_SelectTargetGrid;
|
|
//_gamingQueue.CharacterMoveEvent += GamingQueue_CharacterMove;
|
|
|
|
// 总游戏时长
|
|
double totalTime = 0;
|
|
|
|
// 开始空投
|
|
Msg = "";
|
|
int qMagicCardPack = 5;
|
|
int qWeapon = 5;
|
|
int qArmor = 5;
|
|
int qShoes = 5;
|
|
int qAccessory = 5;
|
|
DropItems(_gamingQueue, qMagicCardPack, qWeapon, qArmor, qShoes, qAccessory);
|
|
double nextDropItemTime = 40;
|
|
if (qMagicCardPack < 5) qMagicCardPack++;
|
|
if (qWeapon < 5) qWeapon++;
|
|
if (qArmor < 5) qArmor++;
|
|
if (qShoes < 5) qShoes++;
|
|
if (qAccessory < 5) qAccessory++;
|
|
|
|
// 初始化队列,准备开始游戏
|
|
_gamingQueue.InitActionQueue();
|
|
_gamingQueue.SetCharactersToAIControl(false, characters);
|
|
_gamingQueue.SetCharactersToAIControl(false, player);
|
|
_gamingQueue.CustomData.Add("player", player);
|
|
|
|
// 显示初始顺序表
|
|
_gamingQueue.DisplayQueue();
|
|
|
|
WriteLine($"你的角色是 [ {player} ],详细信息:{player.GetInfo()}");
|
|
|
|
// 总回合数
|
|
int maxRound = isTeam ? 9999 : 999;
|
|
|
|
// 随机回合奖励
|
|
Dictionary<long, bool> effects = [];
|
|
foreach (EffectID id in FunGameConstant.RoundRewards.Keys)
|
|
{
|
|
long effectID = (long)id;
|
|
bool isActive = false;
|
|
if (effectID > (long)EffectID.Active_Start)
|
|
{
|
|
isActive = true;
|
|
}
|
|
effects.Add(effectID, isActive);
|
|
}
|
|
_gamingQueue.InitRoundRewards(maxRound, 1, effects, id => FunGameConstant.RoundRewards[(EffectID)id]);
|
|
|
|
int i = 1;
|
|
while (i < maxRound)
|
|
{
|
|
Msg = "";
|
|
if (i == maxRound - 1)
|
|
{
|
|
if (isTeam)
|
|
{
|
|
WriteLine("两队打到天昏地暗,流局了!!");
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
WriteLine($"=== 终局审判 ===");
|
|
Dictionary<Character, double> hpPercentage = [];
|
|
foreach (Character c in characters)
|
|
{
|
|
hpPercentage.TryAdd(c, c.HP / c.MaxHP);
|
|
}
|
|
double max = hpPercentage.Values.Max();
|
|
Character winner = hpPercentage.Keys.Where(c => hpPercentage[c] == max).First();
|
|
WriteLine("[ " + winner + " ] 成为了天选之人!!");
|
|
foreach (Character c in characters.Where(c => c != winner && c.HP > 0))
|
|
{
|
|
WriteLine("[ " + winner + " ] 对 [ " + c + " ] 造成了 99999999999 点真实伤害。");
|
|
_gamingQueue.DeathCalculation(winner, c);
|
|
}
|
|
mgq?.EndGameInfo(winner);
|
|
}
|
|
result.Add(Msg);
|
|
break;
|
|
}
|
|
|
|
// 检查是否有角色可以行动
|
|
Character characterToAct = _gamingQueue.NextCharacter();
|
|
|
|
// 处理回合
|
|
if (characterToAct != null)
|
|
{
|
|
// 获取该角色当前位置
|
|
if (_gamingQueue.Map != null)
|
|
{
|
|
Grid currentGrid = _gamingQueue.Map.GetCharacterCurrentGrid(characterToAct);
|
|
if (currentGrid != null) _gamingQueue.CustomData["currentGrid"] = currentGrid;
|
|
}
|
|
|
|
bool isGameEnd = false;
|
|
|
|
try
|
|
{
|
|
isGameEnd = _gamingQueue.ProcessTurn(characterToAct);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
WriteLine(e.ToString());
|
|
}
|
|
|
|
if (isGameEnd)
|
|
{
|
|
result.Add(Msg);
|
|
break;
|
|
}
|
|
|
|
if (isWeb) _gamingQueue.DisplayQueue();
|
|
}
|
|
|
|
string roundMsg = "";
|
|
if (_gamingQueue.LastRound.HasKill)
|
|
{
|
|
roundMsg = Msg;
|
|
Msg = "";
|
|
}
|
|
|
|
// 模拟时间流逝
|
|
double timeLapse = _gamingQueue.TimeLapse();
|
|
totalTime += timeLapse;
|
|
nextDropItemTime -= timeLapse;
|
|
|
|
if (roundMsg != "")
|
|
{
|
|
if (isWeb)
|
|
{
|
|
roundMsg += "\r\n" + Msg;
|
|
}
|
|
result.Add(roundMsg);
|
|
}
|
|
|
|
if (nextDropItemTime <= 0)
|
|
{
|
|
// 空投
|
|
Msg = "";
|
|
DropItems(_gamingQueue, qMagicCardPack, qWeapon, qArmor, qShoes, qAccessory);
|
|
WriteLine("");
|
|
nextDropItemTime = 40;
|
|
if (qMagicCardPack < 5) qMagicCardPack++;
|
|
if (qWeapon < 5) qWeapon++;
|
|
if (qArmor < 5) qArmor++;
|
|
if (qShoes < 5) qShoes++;
|
|
if (qAccessory < 5) qAccessory++;
|
|
}
|
|
|
|
await Task.Delay(1);
|
|
}
|
|
|
|
WriteLine("--- 游戏结束 ---");
|
|
WriteLine($"总游戏时长:{totalTime:0.##} {_gamingQueue.GameplayEquilibriumConstant.InGameTime}");
|
|
|
|
// 赛后统计
|
|
FunGameService.GetCharacterRating(_gamingQueue.CharacterStatistics, isTeam, tgq != null ? tgq.EliminatedTeams : []);
|
|
|
|
if ((isTeam && tgq != null && tgq.EliminatedTeams.Any(t => t.IsOnThisTeam(Character) && t.IsWinner)) || _gamingQueue.Eliminated.Last() == Character)
|
|
{
|
|
Enemy.Dead = true;
|
|
}
|
|
|
|
result.Add(Msg);
|
|
return result;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
WriteLine(ex.ToString());
|
|
return [ex.ToString()];
|
|
}
|
|
}
|
|
|
|
public void WriteLine(string str = "")
|
|
{
|
|
Msg += str + "\r\n";
|
|
FightLog.AppendText(str.Trim() + "\r\n");
|
|
FightLog.ScrollToLine(FightLog.GetLineCount());
|
|
}
|
|
|
|
public void InitCharacter()
|
|
{
|
|
foreach (Character c in FunGameConstant.Characters)
|
|
{
|
|
CharacterStatistics.Add(c, new());
|
|
TeamCharacterStatistics.Add(c, new());
|
|
}
|
|
|
|
StatsConfig.LoadConfig();
|
|
TeamStatsConfig.LoadConfig();
|
|
foreach (Character character in CharacterStatistics.Keys)
|
|
{
|
|
if (StatsConfig.ContainsKey(character.ToStringWithOutUser()))
|
|
{
|
|
CharacterStatistics[character] = StatsConfig.Get<CharacterStatistics>(character.ToStringWithOutUser()) ?? CharacterStatistics[character];
|
|
}
|
|
}
|
|
foreach (Character character in TeamCharacterStatistics.Keys)
|
|
{
|
|
if (TeamStatsConfig.ContainsKey(character.ToStringWithOutUser()))
|
|
{
|
|
TeamCharacterStatistics[character] = TeamStatsConfig.Get<CharacterStatistics>(character.ToStringWithOutUser()) ?? TeamCharacterStatistics[character];
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void DropItems(GamingQueue queue, int mQuality, int wQuality, int aQuality, int sQuality, int acQuality)
|
|
{
|
|
Item[] weapons = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("11") && (int)i.QualityType == wQuality)];
|
|
Item[] armors = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("12") && (int)i.QualityType == aQuality)];
|
|
Item[] shoes = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("13") && (int)i.QualityType == sQuality)];
|
|
Item[] accessorys = [.. FunGameConstant.Equipment.Where(i => i.Id.ToString().StartsWith("14") && (int)i.QualityType == acQuality)];
|
|
Item[] consumables = [.. FunGameConstant.AllItems.Where(i => i.ItemType == ItemType.Consumable && i.IsInGameItem)];
|
|
foreach (Character character in queue.AllCharacters)
|
|
{
|
|
Item a = null, b = null, c = null, d = null;
|
|
if (weapons.Length > 0) a = weapons[Random.Shared.Next(weapons.Length)];
|
|
if (armors.Length > 0) b = armors[Random.Shared.Next(armors.Length)];
|
|
if (shoes.Length > 0) c = shoes[Random.Shared.Next(shoes.Length)];
|
|
if (accessorys.Length > 0) d = accessorys[Random.Shared.Next(accessorys.Length)];
|
|
List<Item> drops = [];
|
|
if (a != null) drops.Add(a);
|
|
if (b != null) drops.Add(b);
|
|
if (c != null) drops.Add(c);
|
|
if (d != null) drops.Add(d);
|
|
mQuality = 2;
|
|
Item magicCardPack = FunGameService.GenerateMagicCardPack(8, (QualityType)mQuality);
|
|
if (magicCardPack != null)
|
|
{
|
|
foreach (Skill magic in magicCardPack.Skills.Magics)
|
|
{
|
|
magic.Level = 8;
|
|
}
|
|
magicCardPack.SetGamingQueue(queue);
|
|
queue.Equip(character, magicCardPack);
|
|
}
|
|
foreach (Item item in drops)
|
|
{
|
|
Item realItem = item.Copy();
|
|
realItem.SetGamingQueue(queue);
|
|
queue.Equip(character, realItem);
|
|
}
|
|
if (consumables.Length > 0 && character.Items.Count < 5)
|
|
{
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
Item consumable = consumables[Random.Shared.Next(consumables.Length)].Copy();
|
|
consumable.Character = character;
|
|
character.Items.Add(consumable);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|