diff --git a/dependency/proto/MessageType.proto b/dependency/proto/MessageType.proto index 8f8184c..7e97811 100755 --- a/dependency/proto/MessageType.proto +++ b/dependency/proto/MessageType.proto @@ -109,7 +109,8 @@ enum StudentType ATHLETE = 1; STUDENTTYPE2 = 2;//Teacher STUDENTTYPE3 = 3;//StraightAStudent - STUDENTTYPE4 = 4; + STUDENTTYPE4 = 4;//Robot + TECH_OTAKU =5; } enum TrickerType diff --git a/logic/GameClass/GameObj/Character/Character.Skill.cs b/logic/GameClass/GameObj/Character/Character.Skill.cs index 4fb1cae..026076e 100644 --- a/logic/GameClass/GameObj/Character/Character.Skill.cs +++ b/logic/GameClass/GameObj/Character/Character.Skill.cs @@ -66,6 +66,9 @@ namespace GameClass.GameObj case CharacterType.Assassin: this.occupation = new Assassin(); break; + case CharacterType.Robot: + this.occupation = new Robot(); + break; case CharacterType.Teacher: this.occupation = new Teacher(); break; @@ -78,6 +81,9 @@ namespace GameClass.GameObj case CharacterType.ANoisyPerson: this.occupation = new ANoisyPerson(); break; + case CharacterType.TechOtaku: + this.occupation = new TechOtaku(); + break; case CharacterType.Athlete: default: this.occupation = new Athlete(); diff --git a/logic/GameClass/GameObj/Character/Character.Student.cs b/logic/GameClass/GameObj/Character/Character.Student.cs index e20ab44..c52a98e 100644 --- a/logic/GameClass/GameObj/Character/Character.Student.cs +++ b/logic/GameClass/GameObj/Character/Character.Student.cs @@ -167,4 +167,23 @@ namespace GameClass.GameObj this.MaxGamingAddiction = ((IStudent)Occupation).MaxGamingAddiction; } } + public class Golem : Student + { + private Character? parent; // 主人 + public Character? Parent + { + get => parent; + set + { + lock (gameObjLock) + { + parent = value; + } + } + } + public Golem(XY initPos, int initRadius, Character? parent) : base(initPos, initRadius, CharacterType.Robot) + { + this.parent = parent; + } + } } \ No newline at end of file diff --git a/logic/GameClass/GameObj/Character/Skill.cs b/logic/GameClass/GameObj/Character/Skill.cs index 74c8729..e83d9c1 100644 --- a/logic/GameClass/GameObj/Character/Skill.cs +++ b/logic/GameClass/GameObj/Character/Skill.cs @@ -3,20 +3,6 @@ using Preparation.Utility; namespace GameClass.GameObj { - public class BecomeVampire : IActiveSkill // 化身吸血鬼 - { - public int SkillCD => GameData.commonSkillCD * 4 / 3; - public int DurationTime => GameData.commonSkillTime; - - private readonly object commonSkillLock = new object(); - public object ActiveSkillLock => commonSkillLock; - - public bool isBeingUsed = false; - public bool IsBeingUsed - { - get => isBeingUsed; set => isBeingUsed = value; - } - } public class CanBeginToCharge : IActiveSkill { public int SkillCD => GameData.commonSkillCD / 5; @@ -79,7 +65,7 @@ namespace GameClass.GameObj public class JumpyBomb : IActiveSkill { - public int SkillCD => GameData.commonSkillCD / 30 * 5; + public int SkillCD => GameData.commonSkillCD / 25 * 5; public int DurationTime => GameData.commonSkillTime / 2; private readonly object commonSkillLock = new object(); public object ActiveSkillLock => commonSkillLock; @@ -105,20 +91,6 @@ namespace GameClass.GameObj } } - public class SuperFast : IActiveSkill // 3倍速 - { - public int SkillCD => GameData.commonSkillCD; - public int DurationTime => GameData.commonSkillTime * 4 / 10; - private readonly object commonSkillLock = new object(); - public object ActiveSkillLock => commonSkillLock; - - public bool isBeingUsed = false; - public bool IsBeingUsed - { - get => isBeingUsed; set => isBeingUsed = value; - } - } - public class WriteAnswers : IActiveSkill { public int SkillCD => GameData.commonSkillCD; diff --git a/logic/Gaming/ActionManager.cs b/logic/Gaming/ActionManager.cs index 3b283f3..ab8eab3 100644 --- a/logic/Gaming/ActionManager.cs +++ b/logic/Gaming/ActionManager.cs @@ -23,16 +23,16 @@ namespace Gaming { if (((Bullet)collisionObj).Parent != player && ((Bullet)collisionObj).TypeOfBullet == BulletType.JumpyDumpty) { - if (AttackManager.BeStunned((Character)player, ((Bullet)collisionObj).AP / GameData.timeFactorOfGhostFainting)) + if (CharacterManager.BeStunned((Character)player, ((Bullet)collisionObj).AP / GameData.timeFactorOfGhostFainting)) player.AddScore(GameData.TrickerScoreStudentBeStunned(((Bullet)collisionObj).AP / GameData.timeFactorOfGhostFainting)); gameMap.Remove((GameObj)collisionObj); } } if (player.FindIActiveSkill(ActiveSkillType.CanBeginToCharge).IsBeingUsed && collisionObj.Type == GameObjType.Character && ((Character)collisionObj).IsGhost()) { - if (AttackManager.BeStunned((Character)collisionObj, GameData.TimeOfGhostFaintingWhenCharge)) + if (CharacterManager.BeStunned((Character)collisionObj, GameData.TimeOfGhostFaintingWhenCharge)) player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.TimeOfGhostFaintingWhenCharge)); - AttackManager.BeStunned(player, GameData.TimeOfStudentFaintingWhenCharge); + CharacterManager.BeStunned(player, GameData.TimeOfStudentFaintingWhenCharge); } } public bool MovePlayer(Character playerToMove, int moveTimeInMilliseconds, double moveDirection) diff --git a/logic/Gaming/AttackManager.cs b/logic/Gaming/AttackManager.cs index 60c5530..ac44688 100644 --- a/logic/Gaming/AttackManager.cs +++ b/logic/Gaming/AttackManager.cs @@ -17,7 +17,9 @@ namespace Gaming { readonly Map gameMap; readonly MoveEngine moveEngine; - public AttackManager(Map gameMap) + readonly CharacterManager characterManager; + + public AttackManager(Map gameMap, CharacterManager characterManager) { this.gameMap = gameMap; this.moveEngine = new MoveEngine( @@ -29,121 +31,12 @@ namespace Gaming }, EndMove: obj => { -#if DEBUG Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64); - -#endif if (obj.CanMove && ((Bullet)obj).TypeOfBullet != BulletType.JumpyDumpty) BulletBomb((Bullet)obj, null); } ); - } - - private void BeAddictedToGame(Student player, Ghost ghost) - { - 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()) 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); - } - } - ++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(); - } - } + this.characterManager = characterManager; } private void BombObj(Bullet bullet, GameObj objBeingShot) @@ -164,11 +57,11 @@ namespace Gaming } if (whoBeAttacked.BeAttacked(bullet)) { - BeAddictedToGame(whoBeAttacked, (Ghost)bullet.Parent); + characterManager.BeAddictedToGame(whoBeAttacked, (Ghost)bullet.Parent); } if (whoBeAttacked.CanBeAwed()) { - if (BeStunned(whoBeAttacked, GameData.basicStunnedTimeOfStudent)) + if (CharacterManager.BeStunned(whoBeAttacked, GameData.basicStunnedTimeOfStudent)) bullet.Parent.AddScore(GameData.TrickerScoreStudentBeStunned(GameData.basicStunnedTimeOfStudent)); } } @@ -201,14 +94,14 @@ namespace Gaming { if (objBeingShot == null) { - BackSwing((Character?)bullet.Parent, bullet.Backswing); + CharacterManager.BackSwing((Character?)bullet.Parent, bullet.Backswing); return; } Debugger.Output(bullet, bullet.TypeOfBullet.ToString()); BombObj(bullet, objBeingShot); - BackSwing((Character?)bullet.Parent, bullet.RecoveryFromHit); + CharacterManager.BackSwing((Character?)bullet.Parent, bullet.RecoveryFromHit); return; } @@ -259,48 +152,14 @@ namespace Gaming { BombObj(bullet, beAttackedObj); } + beAttackedList.Clear(); + if (objBeingShot == null) { - if (bullet.Backswing > 0) - { - bullet.Parent.PlayerState = PlayerStateType.Swinging; - - new Thread - (() => - { - Thread.Sleep(bullet.Backswing); - - if (gameMap.Timer.IsGaming && bullet.Parent.PlayerState == PlayerStateType.Swinging) - { - bullet.Parent.PlayerState = PlayerStateType.Null; - } - } - ) - { IsBackground = true }.Start(); - } + CharacterManager.BackSwing((Character?)bullet.Parent, bullet.Backswing); } else - { - if (bullet.RecoveryFromHit > 0) - { - bullet.Parent.PlayerState = PlayerStateType.Swinging; - - new Thread - (() => - { - - Thread.Sleep(bullet.RecoveryFromHit); - - if (gameMap.Timer.IsGaming && bullet.Parent.PlayerState == PlayerStateType.Swinging) - { - bullet.Parent.PlayerState = PlayerStateType.Null; - } - } - ) - { IsBackground = true }.Start(); - } - } - beAttackedList.Clear(); + CharacterManager.BackSwing((Character?)bullet.Parent, bullet.RecoveryFromHit); } public bool Attack(Character? player, double angle) diff --git a/logic/Gaming/CharacterManager .cs b/logic/Gaming/CharacterManager .cs new file mode 100644 index 0000000..bf70b07 --- /dev/null +++ b/logic/Gaming/CharacterManager .cs @@ -0,0 +1,306 @@ +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) + { + 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()) 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); + } + } + ++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(); + } + } + } + + } + } +} \ No newline at end of file diff --git a/logic/Gaming/Game.cs b/logic/Gaming/Game.cs index c5c0855..8db79ed 100644 --- a/logic/Gaming/Game.cs +++ b/logic/Gaming/Game.cs @@ -14,10 +14,10 @@ namespace Gaming public struct PlayerInitInfo { public uint birthPointIndex; - public long teamID; - public long playerID; + public int teamID; + public int playerID; public CharacterType characterType; - public PlayerInitInfo(uint birthPointIndex, long teamID, long playerID, CharacterType characterType) + public PlayerInitInfo(uint birthPointIndex, int teamID, int playerID, CharacterType characterType) { this.birthPointIndex = birthPointIndex; this.teamID = teamID; @@ -39,171 +39,12 @@ namespace Gaming return GameObj.invalidID; XY pos = gameMap.BirthPointList[playerInitInfo.birthPointIndex]; + Character? newPlayer = characterManager.AddPlayer(pos, playerInitInfo.teamID, playerInitInfo.playerID, playerInitInfo.characterType); + if (newPlayer == null) return GameObj.invalidID; // Console.WriteLine($"x,y: {pos.x},{pos.y}"); - Character newPlayer = (GameData.IsGhost(playerInitInfo.characterType)) ? new Ghost(pos, GameData.characterRadius, playerInitInfo.characterType) : new Student(pos, GameData.characterRadius, playerInitInfo.characterType); - gameMap.Add(newPlayer); - // Console.WriteLine($"GameObjDict[GameObjType.Character] length:{gameMap.GameObjDict[GameObjType.Character].Count}"); teamList[(int)playerInitInfo.teamID].AddPlayer(newPlayer); - newPlayer.TeamID = playerInitInfo.teamID; - newPlayer.PlayerID = playerInitInfo.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.ID; } public bool StartGame(int milliSeconds) @@ -529,10 +370,11 @@ namespace Gaming teamList.Add(new Team()); } - attackManager = new AttackManager(gameMap); + characterManager = new CharacterManager(gameMap); + attackManager = new AttackManager(gameMap, characterManager); actionManager = new ActionManager(gameMap); propManager = new PropManager(gameMap); - skillManager = new SkillManager(gameMap, actionManager, attackManager, propManager); + skillManager = new SkillManager(gameMap, actionManager, attackManager, propManager, characterManager); } } } diff --git a/logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs b/logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs index 5cff149..e03d4c5 100644 --- a/logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs +++ b/logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs @@ -106,7 +106,7 @@ namespace Gaming { if (!character.IsGhost() && XY.Distance(character.Position, player.Position) <= player.ViewRange) { - if (AttackManager.BeStunned(character, GameData.TimeOfStudentFaintingWhenHowl)) + if (CharacterManager.BeStunned(character, GameData.TimeOfStudentFaintingWhenHowl)) player.AddScore(GameData.TrickerScoreStudentBeStunned(GameData.TimeOfStudentFaintingWhenHowl)); break; } @@ -116,7 +116,7 @@ namespace Gaming { gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); } - AttackManager.BackSwing(player, GameData.TimeOfGhostSwingingAfterHowl); + CharacterManager.BackSwing(player, GameData.TimeOfGhostSwingingAfterHowl); Debugger.Output(player, "howled!"); }, () => @@ -137,7 +137,7 @@ namespace Gaming || character.PlayerState == PlayerStateType.UsingSkill || character.PlayerState == PlayerStateType.LockingOrOpeningTheDoor || character.PlayerState == PlayerStateType.OpeningTheChest) && gameMap.CanSee(player, character)) { - if (AttackManager.BeStunned(character, GameData.TimeOfGhostFaintingWhenPunish + (player.MaxHp - player.HP) / GameData.timeFactorOfGhostFainting)) + if (CharacterManager.BeStunned(character, GameData.TimeOfGhostFaintingWhenPunish + (player.MaxHp - player.HP) / GameData.timeFactorOfGhostFainting)) player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.TimeOfGhostFaintingWhenPunish + (player.MaxHp - player.HP) / GameData.timeFactorOfGhostFainting)); break; } diff --git a/logic/Gaming/SkillManager/SkillManager.cs b/logic/Gaming/SkillManager/SkillManager.cs index 3edabcf..b676d16 100644 --- a/logic/Gaming/SkillManager/SkillManager.cs +++ b/logic/Gaming/SkillManager/SkillManager.cs @@ -69,15 +69,17 @@ namespace Gaming } private readonly Map gameMap; + private readonly CharacterManager characterManager; private readonly ActionManager actionManager; private readonly AttackManager attackManager; private readonly PropManager propManager; - public SkillManager(Map gameMap, ActionManager action, AttackManager attack, PropManager prop) + public SkillManager(Map gameMap, ActionManager action, AttackManager attack, PropManager prop, CharacterManager characterManager) { this.gameMap = gameMap; this.actionManager = action; this.propManager = prop; this.attackManager = attack; + this.characterManager = characterManager; } } } diff --git a/logic/Preparation/Interface/IOccupation.cs b/logic/Preparation/Interface/IOccupation.cs index 4bd0cff..47d1d1e 100644 --- a/logic/Preparation/Interface/IOccupation.cs +++ b/logic/Preparation/Interface/IOccupation.cs @@ -98,7 +98,6 @@ namespace Preparation.Interface public int speedOfOpenChest = (int)(GameData.basicSpeedOfOpenChest * 1.1); public int SpeedOfOpenChest => speedOfOpenChest; } - public class ANoisyPerson : IGhost { private const int moveSpeed = (int)(GameData.basicMoveSpeed * 1.1); @@ -250,7 +249,7 @@ namespace Preparation.Interface public const int alertnessRadius = (int)(GameData.basicAlertnessRadius * 0.9); public int AlertnessRadius => alertnessRadius; - public int viewRange = GameData.basicViewRange; + public int viewRange = (int)(GameData.basicViewRange * 0.9); public int ViewRange => viewRange; public int timeOfOpeningOrLocking = GameData.basicSpeedOfOpeningOrLocking; @@ -262,4 +261,90 @@ namespace Preparation.Interface public int speedOfOpenChest = GameData.basicSpeedOfOpenChest; public int SpeedOfOpenChest => speedOfOpenChest; } -} + public class Robot : IStudent + { + private const int moveSpeed = (int)(GameData.basicMoveSpeed); + public int MoveSpeed => moveSpeed; + + private const int maxHp = (int)(GameData.basicHp / 2.5); + public int MaxHp => maxHp; + + private const int maxGamingAddiction = 0; + public int MaxGamingAddiction => maxGamingAddiction; + + public const int maxBulletNum = 0; + public int MaxBulletNum => maxBulletNum; + + public BulletType InitBullet => BulletType.Null; + + public List ListOfIActiveSkill => new(new ActiveSkillType[] { }); + public List ListOfIPassiveSkill => new(new PassiveSkillType[] { }); + + public const int fixSpeed = GameData.basicFixSpeed; + public int FixSpeed => fixSpeed; + + public const int treatSpeed = GameData.basicTreatSpeed * 8 / 10; + public int TreatSpeed => treatSpeed; + + public const double concealment = GameData.basicConcealment; + public double Concealment => concealment; + + public const int alertnessRadius = (int)(GameData.basicAlertnessRadius); + public int AlertnessRadius => alertnessRadius; + + public int viewRange = GameData.basicViewRange; + public int ViewRange => viewRange; + + public int timeOfOpeningOrLocking = GameData.basicSpeedOfOpeningOrLocking; + public int TimeOfOpeningOrLocking => timeOfOpeningOrLocking; + + public int speedOfClimbingThroughWindows = 1; + public int SpeedOfClimbingThroughWindows => speedOfClimbingThroughWindows; + + public int speedOfOpenChest = GameData.basicSpeedOfOpenChest; + public int SpeedOfOpenChest => speedOfOpenChest; + } + public class TechOtaku : IStudent + { + private const int moveSpeed = (int)(GameData.basicMoveSpeed * 0.75); + public int MoveSpeed => moveSpeed; + + private const int maxHp = (int)(GameData.basicHp * 0.9); + public int MaxHp => maxHp; + + private const int maxGamingAddiction = (int)(GameData.basicMaxGamingAddiction * 1.1); + public int MaxGamingAddiction => maxGamingAddiction; + + public const int maxBulletNum = 0; + public int MaxBulletNum => maxBulletNum; + + public BulletType InitBullet => BulletType.Null; + + public List ListOfIActiveSkill => new(new ActiveSkillType[] { }); + public List ListOfIPassiveSkill => new(new PassiveSkillType[] { }); + + public const int fixSpeed = (int)(GameData.basicFixSpeed * 1.1); + public int FixSpeed => fixSpeed; + + public const int treatSpeed = GameData.basicTreatSpeed * 9 / 10; + public int TreatSpeed => treatSpeed; + + public const double concealment = GameData.basicConcealment; + public double Concealment => concealment; + + public const int alertnessRadius = (int)(GameData.basicAlertnessRadius); + public int AlertnessRadius => alertnessRadius; + + public int viewRange = (int)(GameData.basicViewRange * 0.9); + public int ViewRange => viewRange; + + public int timeOfOpeningOrLocking = GameData.basicSpeedOfOpeningOrLocking; + public int TimeOfOpeningOrLocking => timeOfOpeningOrLocking; + + public int speedOfClimbingThroughWindows = (int)(GameData.basicStudentSpeedOfClimbingThroughWindows * 3 / 4); + public int SpeedOfClimbingThroughWindows => speedOfClimbingThroughWindows; + + public int speedOfOpenChest = GameData.basicSpeedOfOpenChest; + public int SpeedOfOpenChest => speedOfOpenChest; + } +} \ No newline at end of file diff --git a/logic/Preparation/Utility/EnumType.cs b/logic/Preparation/Utility/EnumType.cs index 6bb803e..8defceb 100644 --- a/logic/Preparation/Utility/EnumType.cs +++ b/logic/Preparation/Utility/EnumType.cs @@ -77,10 +77,11 @@ namespace Preparation.Utility Assassin = 1, Athlete = 2, Klee = 3, - SpeedUpWhenLeavingGrass = 4, + TechOtaku = 4, Teacher = 5, StraightAStudent = 6, ANoisyPerson = 7, + Robot = 8, } public enum ActiveSkillType // 主动技能 { diff --git a/logic/Server/CopyInfo.cs b/logic/Server/CopyInfo.cs index 4250556..4bec6b3 100644 --- a/logic/Server/CopyInfo.cs +++ b/logic/Server/CopyInfo.cs @@ -182,6 +182,10 @@ namespace Server return StudentType._2; case CharacterType.StraightAStudent: return StudentType._3; + case CharacterType.Robot: + return StudentType._4; + case CharacterType.TechOtaku: + return StudentType.TechOtaku; default: return Protobuf.StudentType.NullStudentType; } @@ -197,6 +201,10 @@ namespace Server return Preparation.Utility.CharacterType.Teacher; case StudentType._3: return CharacterType.StraightAStudent; + case StudentType._4: + return CharacterType.Robot; + case StudentType.TechOtaku: + return CharacterType.TechOtaku; default: return Preparation.Utility.CharacterType.Null; } diff --git a/logic/Server/GameServer.cs b/logic/Server/GameServer.cs index 2850612..7182f61 100644 --- a/logic/Server/GameServer.cs +++ b/logic/Server/GameServer.cs @@ -312,7 +312,7 @@ namespace Server lock (addPlayerLock) { - Game.PlayerInitInfo playerInitInfo = new(GetBirthPointIdx(request.PlayerId), PlayerTypeToTeamID(request.PlayerType), request.PlayerId, characterType); + Game.PlayerInitInfo playerInitInfo = new(GetBirthPointIdx(request.PlayerId), PlayerTypeToTeamID(request.PlayerType), (int)request.PlayerId, characterType); long newPlayerID = game.AddPlayer(playerInitInfo); if (newPlayerID == GameObj.invalidID) return;