using System; using System.Threading; using System.Collections.Generic; using GameClass.GameObj; using Preparation.Utility; using GameEngine; using Preparation.Interface; using Timothy.FrameRateTask; using System.Numerics; namespace Gaming { public partial class Game { private readonly CharacterManager characterManager; private class CharacterManager { readonly Map gameMap; public CharacterManager(Map gameMap) { this.gameMap = gameMap; } public Character? AddPlayer(XY pos, int teamID, int playerID, CharacterType characterType, Character? parent = null) { Character newPlayer; if (characterType == CharacterType.Robot) { newPlayer = new Golem(pos, GameData.characterRadius, parent); } else newPlayer = (GameData.IsGhost(characterType)) ? new Ghost(pos, GameData.characterRadius, characterType) : new Student(pos, GameData.characterRadius, characterType); gameMap.Add(newPlayer); newPlayer.TeamID = teamID; newPlayer.PlayerID = playerID; #region 人物装弹 new Thread ( () => { while (!gameMap.Timer.IsGaming) Thread.Sleep(Math.Max(newPlayer.CD, GameData.checkInterval)); long lastTime = Environment.TickCount64; new FrameRateTaskExecutor( loopCondition: () => gameMap.Timer.IsGaming && !newPlayer.IsResetting, loopToDo: () => { long nowTime = Environment.TickCount64; if (newPlayer.BulletNum == newPlayer.MaxBulletNum) lastTime = nowTime; else if (nowTime - lastTime >= newPlayer.CD) { _ = newPlayer.TryAddBulletNum(); lastTime = nowTime; } }, timeInterval: GameData.checkInterval, finallyReturn: () => 0 ) { AllowTimeExceed = true/*, MaxTolerantTimeExceedCount = 5, TimeExceedAction = exceedTooMuch => { if (exceedTooMuch) Console.WriteLine("The computer runs too slow that it cannot check the color below the player in time!"); }*/ } .Start(); } ) { IsBackground = true }.Start(); #endregion #region BGM,牵制得分更新 new Thread ( () => { while (!gameMap.Timer.IsGaming) Thread.Sleep(GameData.checkInterval); int TimePinningDown = 0, ScoreAdded = 0; bool noise = false; if (!newPlayer.IsGhost()) { gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); try { foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) { if (person.IsGhost()) { if (person.CharacterType == CharacterType.ANoisyPerson) { noise = true; newPlayer.AddBgm(BgmType.GhostIsComing, 1411180); newPlayer.AddBgm(BgmType.GeneratorIsBeingFixed, 154991); } } } } finally { gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); } } new FrameRateTaskExecutor( loopCondition: () => gameMap.Timer.IsGaming && !newPlayer.IsResetting, loopToDo: () => { gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); try { if (newPlayer.IsGhost()) { double bgmVolume = 0; foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) { if (!person.IsGhost() && XY.Distance(newPlayer.Position, person.Position) <= (newPlayer.AlertnessRadius / person.Concealment)) { if ((double)newPlayer.AlertnessRadius / XY.Distance(newPlayer.Position, person.Position) > bgmVolume) bgmVolume = newPlayer.AlertnessRadius / XY.Distance(newPlayer.Position, person.Position); } } if (bgmVolume > 0) newPlayer.AddBgm(BgmType.StudentIsApproaching, bgmVolume); } else { foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) { if (person.IsGhost()) { if (!noise && XY.Distance(newPlayer.Position, person.Position) <= (newPlayer.AlertnessRadius / person.Concealment)) newPlayer.AddBgm(BgmType.GhostIsComing, (double)newPlayer.AlertnessRadius / XY.Distance(newPlayer.Position, person.Position)); if (XY.Distance(newPlayer.Position, person.Position) <= GameData.basicViewRange) { TimePinningDown += GameData.checkInterval; newPlayer.AddScore(GameData.StudentScorePinDown(TimePinningDown) - ScoreAdded); ScoreAdded = GameData.StudentScorePinDown(TimePinningDown); } else TimePinningDown = ScoreAdded = 0; break; } } } } finally { gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); } if (!noise) { gameMap.GameObjLockDict[GameObjType.Generator].EnterReadLock(); try { double bgmVolume = 0; foreach (Generator generator in gameMap.GameObjDict[GameObjType.Generator]) { if (XY.Distance(newPlayer.Position, generator.Position) <= newPlayer.AlertnessRadius) { if ((double)newPlayer.AlertnessRadius * generator.DegreeOfRepair / GameData.degreeOfFixedGenerator / XY.Distance(newPlayer.Position, generator.Position) > bgmVolume) bgmVolume = (double)newPlayer.AlertnessRadius * generator.DegreeOfRepair / GameData.degreeOfFixedGenerator / XY.Distance(newPlayer.Position, generator.Position); } } if (bgmVolume > 0) newPlayer.AddBgm(BgmType.GeneratorIsBeingFixed, bgmVolume); } finally { gameMap.GameObjLockDict[GameObjType.Generator].ExitReadLock(); } } }, timeInterval: GameData.checkInterval, finallyReturn: () => 0 ) { AllowTimeExceed = true/*, MaxTolerantTimeExceedCount = 5, TimeExceedAction = exceedTooMuch => { if (exceedTooMuch) Console.WriteLine("The computer runs too slow that it cannot check the color below the player in time!"); }*/ } .Start(); } ) { IsBackground = true }.Start(); #endregion return newPlayer; } public void BeAddictedToGame(Student player, Ghost ghost) { if (player.CharacterType == CharacterType.Robot) { ghost.AddScore(GameData.TrickerScoreDestroyRobot); Die(player); return; } ghost.AddScore(GameData.TrickerScoreStudentBeAddicted); new Thread (() => { if (player.GamingAddiction > GameData.BeginGamingAddiction && player.GamingAddiction < GameData.MidGamingAddiction) player.GamingAddiction = GameData.MidGamingAddiction; player.PlayerState = PlayerStateType.Addicted; #if DEBUG Debugger.Output(player, " is addicted "); #endif new FrameRateTaskExecutor( () => (player.PlayerState == PlayerStateType.Addicted || player.PlayerState == PlayerStateType.Rescued) && player.GamingAddiction < player.MaxGamingAddiction && gameMap.Timer.IsGaming, () => { player.GamingAddiction += (player.PlayerState == PlayerStateType.Addicted) ? GameData.frameDuration : 0; }, timeInterval: GameData.frameDuration, () => { if (player.GamingAddiction == player.MaxGamingAddiction && gameMap.Timer.IsGaming) { ghost.AddScore(GameData.TrickerScoreStudentDie); Die(player); } return 0; } ) .Start(); } ) { IsBackground = true }.Start(); } public static bool BeStunned(Character player, int time) { if (player.PlayerState == PlayerStateType.Stunned || player.NoHp() || player.CharacterType == CharacterType.Robot) return false; new Thread (() => { player.PlayerState = PlayerStateType.Stunned; Thread.Sleep(time); if (player.PlayerState == PlayerStateType.Stunned) player.PlayerState = PlayerStateType.Null; } ) { IsBackground = true }.Start(); return true; } public static bool BackSwing(Character? player, int time) { if (player == null || time <= 0) return false; if (player.PlayerState == PlayerStateType.Swinging || (!player.Commandable() && player.PlayerState != PlayerStateType.TryingToAttack)) return false; player.PlayerState = PlayerStateType.Swinging; new Thread (() => { Thread.Sleep(time); if (player.PlayerState == PlayerStateType.Swinging) { player.PlayerState = PlayerStateType.Null; } } ) { IsBackground = true }.Start(); return true; } private void Die(Character player) { #if DEBUG Debugger.Output(player, "die."); #endif player.Die(PlayerStateType.Deceased); for (int i = 0; i < GameData.maxNumOfPropInPropInventory; i++) { Prop? prop = player.UseProp(i); if (prop != null) { prop.ReSetPos(player.Position, gameMap.GetPlaceType(player.Position)); gameMap.Add(prop); } } if (player.CharacterType == CharacterType.Robot) return; ++gameMap.NumOfDeceasedStudent; if (GameData.numOfStudent - gameMap.NumOfDeceasedStudent - gameMap.NumOfEscapedStudent == 1) { gameMap.GameObjLockDict[GameObjType.EmergencyExit].EnterReadLock(); try { foreach (EmergencyExit emergencyExit in gameMap.GameObjDict[GameObjType.EmergencyExit]) if (emergencyExit.CanOpen) { emergencyExit.IsOpen = true; break; } } finally { gameMap.GameObjLockDict[GameObjType.EmergencyExit].ExitReadLock(); } } } } } }