fix: 🐛 fix the bug about numOfNoHpStudent
tags/v0.1.0
| @@ -52,6 +52,12 @@ | |||||
| - docs:更新了 游戏机制与平衡性调整更新草案.pdf | - docs:更新了 游戏机制与平衡性调整更新草案.pdf | ||||
| - feat:游戏机制与平衡性调整已完成 | - feat:游戏机制与平衡性调整已完成 | ||||
| # 5月20日更新 | |||||
| # 5月20日18:00更新 | |||||
| - docs:更新了 游戏机制与平衡性调整更新(基本不变版).pdf | - docs:更新了 游戏机制与平衡性调整更新(基本不变版).pdf | ||||
| - fix:修复了Pubnish技能眩晕时长的错误 | |||||
| - fix:修复了Pubnish技能眩晕时长的错误 | |||||
| # 5月20日23:30更新 | |||||
| - fix:修复了学习已经完成的作业会卡死的问题 | |||||
| # 5月21日更新 | |||||
| - fix:修复了游戏结束判定的bug | |||||
| @@ -455,13 +455,13 @@ namespace GameClass.GameObj | |||||
| case PlayerStateType.Addicted: | case PlayerStateType.Addicted: | ||||
| if (value == PlayerStateType.Rescued) | if (value == PlayerStateType.Rescued) | ||||
| return ChangePlayerStateInOneThread(value, gameObj); | return ChangePlayerStateInOneThread(value, gameObj); | ||||
| else if (value == PlayerStateType.Null) | |||||
| else if (value == PlayerStateType.Null || value == PlayerStateType.Deceased) | |||||
| return ChangePlayerState(value, gameObj); | return ChangePlayerState(value, gameObj); | ||||
| else return -1; | else return -1; | ||||
| case PlayerStateType.Rescued: | case PlayerStateType.Rescued: | ||||
| if (value == PlayerStateType.Addicted) | if (value == PlayerStateType.Addicted) | ||||
| return ChangePlayerStateInOneThread(value, gameObj); | return ChangePlayerStateInOneThread(value, gameObj); | ||||
| else if (value == PlayerStateType.Null) | |||||
| else if (value == PlayerStateType.Null || value == PlayerStateType.Deceased) | |||||
| return ChangePlayerState(value, gameObj); | return ChangePlayerState(value, gameObj); | ||||
| else return -1; | else return -1; | ||||
| @@ -590,15 +590,17 @@ namespace GameClass.GameObj | |||||
| } | } | ||||
| } | } | ||||
| public void RemoveFromGame(PlayerStateType playerStateType) | |||||
| public bool TryToRemoveFromGame(PlayerStateType playerStateType) | |||||
| { | { | ||||
| lock (actionLock) | lock (actionLock) | ||||
| { | { | ||||
| TryToRemove(); | |||||
| if (!TryToRemove()) return false; | |||||
| Debugger.Output(this, "TryToRemove"); | |||||
| ReSetCanMove(false); | ReSetCanMove(false); | ||||
| SetPlayerState(playerStateType); | SetPlayerState(playerStateType); | ||||
| position = GameData.PosWhoDie; | position = GameData.PosWhoDie; | ||||
| } | } | ||||
| return true; | |||||
| } | } | ||||
| #endregion | #endregion | ||||
| @@ -43,9 +43,9 @@ namespace GameClass.GameObj | |||||
| return (Interlocked.CompareExchange(ref isRemoved, 0, 0) == 1); | return (Interlocked.CompareExchange(ref isRemoved, 0, 0) == 1); | ||||
| } | } | ||||
| } | } | ||||
| public virtual void TryToRemove() | |||||
| public virtual bool TryToRemove() | |||||
| { | { | ||||
| Interlocked.Exchange(ref isRemoved, 1); | |||||
| return Interlocked.Exchange(ref isRemoved, 1) == 0; | |||||
| } | } | ||||
| public int Radius { get; } | public int Radius { get; } | ||||
| @@ -11,58 +11,14 @@ namespace GameClass.GameObj | |||||
| private readonly Dictionary<uint, XY> birthPointList; // 出生点列表 | private readonly Dictionary<uint, XY> birthPointList; // 出生点列表 | ||||
| public Dictionary<uint, XY> BirthPointList => birthPointList; | public Dictionary<uint, XY> BirthPointList => birthPointList; | ||||
| private readonly object lockForNum = new(); | |||||
| private void WhenStudentNumChange() | |||||
| { | |||||
| if (numOfDeceasedStudent + numOfEscapedStudent == GameData.numOfStudent) | |||||
| { | |||||
| Timer.IsGaming = false; | |||||
| return; | |||||
| } | |||||
| if (GameData.numOfStudent - numOfDeceasedStudent - numOfEscapedStudent == 1) | |||||
| { | |||||
| GameObjLockDict[GameObjType.Character].EnterReadLock(); | |||||
| try | |||||
| { | |||||
| foreach (Character player in GameObjDict[GameObjType.Character]) | |||||
| if (player.PlayerState == PlayerStateType.Addicted) | |||||
| { | |||||
| Timer.IsGaming = false; | |||||
| break; | |||||
| } | |||||
| } | |||||
| finally | |||||
| { | |||||
| GameObjLockDict[GameObjType.Character].ExitReadLock(); | |||||
| } | |||||
| if (Timer.IsGaming) | |||||
| { | |||||
| GameObjLockDict[GameObjType.EmergencyExit].EnterWriteLock(); | |||||
| try | |||||
| { | |||||
| foreach (EmergencyExit emergencyExit in GameObjDict[GameObjType.EmergencyExit]) | |||||
| if (emergencyExit.CanOpen) | |||||
| { | |||||
| emergencyExit.IsOpen = true; | |||||
| break; | |||||
| } | |||||
| } | |||||
| finally | |||||
| { | |||||
| GameObjLockDict[GameObjType.EmergencyExit].ExitWriteLock(); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| private uint numOfRepairedGenerators = 0; | private uint numOfRepairedGenerators = 0; | ||||
| public uint NumOfRepairedGenerators | public uint NumOfRepairedGenerators | ||||
| { | { | ||||
| get => Interlocked.CompareExchange(ref numOfDeceasedStudent, 0, 0); | |||||
| get => Interlocked.CompareExchange(ref numOfRepairedGenerators, 0, 0); | |||||
| } | } | ||||
| public void AddNumOfRepairedGenerators() | public void AddNumOfRepairedGenerators() | ||||
| { | { | ||||
| uint value = Interlocked.Increment(ref numOfDeceasedStudent); | |||||
| uint value = Interlocked.Increment(ref numOfRepairedGenerators); | |||||
| if (value == GameData.numOfGeneratorRequiredForEmergencyExit) | if (value == GameData.numOfGeneratorRequiredForEmergencyExit) | ||||
| { | { | ||||
| GameObjLockDict[GameObjType.EmergencyExit].EnterWriteLock(); | GameObjLockDict[GameObjType.EmergencyExit].EnterWriteLock(); | ||||
| @@ -93,33 +49,79 @@ namespace GameClass.GameObj | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| private uint numOfDeceasedStudent = 0; | private uint numOfDeceasedStudent = 0; | ||||
| public uint NumOfDeceasedStudent | public uint NumOfDeceasedStudent | ||||
| { | { | ||||
| get => numOfDeceasedStudent; | |||||
| set | |||||
| { | |||||
| lock (lockForNum) | |||||
| { | |||||
| numOfDeceasedStudent = value; | |||||
| WhenStudentNumChange(); | |||||
| } | |||||
| } | |||||
| get => Interlocked.CompareExchange(ref numOfDeceasedStudent, 0, 0); | |||||
| } | } | ||||
| private uint numOfEscapedStudent = 0; | private uint numOfEscapedStudent = 0; | ||||
| public uint NumOfEscapedStudent | public uint NumOfEscapedStudent | ||||
| { | { | ||||
| get => numOfEscapedStudent; | |||||
| set | |||||
| get => Interlocked.CompareExchange(ref numOfEscapedStudent, 0, 0); | |||||
| } | |||||
| private uint numOfNoHpStudent = 0; | |||||
| public uint NumOfNoHpStudent | |||||
| { | |||||
| get => Interlocked.CompareExchange(ref numOfNoHpStudent, 0, 0); | |||||
| } | |||||
| private uint numOfRemovedStudent = 0; | |||||
| public uint NumOfRemovedStudent | |||||
| { | |||||
| get => Interlocked.CompareExchange(ref numOfRemovedStudent, 0, 0); | |||||
| } | |||||
| public void MapEscapeStudent() | |||||
| { | |||||
| if (Interlocked.Increment(ref numOfNoHpStudent) == GameData.numOfStudent) | |||||
| { | { | ||||
| lock (lockForNum) | |||||
| { | |||||
| numOfEscapedStudent = value; | |||||
| WhenStudentNumChange(); | |||||
| } | |||||
| Timer.IsGaming = false; | |||||
| return; | |||||
| } | |||||
| Interlocked.Increment(ref numOfEscapedStudent); | |||||
| if (Interlocked.Increment(ref numOfRemovedStudent) == GameData.numOfStudent - 1) | |||||
| OpenEmergencyExit(); | |||||
| } | |||||
| public void MapDieStudent() | |||||
| { | |||||
| if (Interlocked.Increment(ref numOfNoHpStudent) == GameData.numOfStudent) | |||||
| { | |||||
| Timer.IsGaming = false; | |||||
| return; | |||||
| } | |||||
| Interlocked.Increment(ref numOfDeceasedStudent); | |||||
| if (Interlocked.Increment(ref numOfRemovedStudent) == GameData.numOfStudent - 1) | |||||
| OpenEmergencyExit(); | |||||
| } | |||||
| public void MapAddictStudent() | |||||
| { | |||||
| if (Interlocked.Increment(ref numOfNoHpStudent) == GameData.numOfStudent) | |||||
| Timer.IsGaming = false; | |||||
| } | |||||
| public void MapRescueStudent() | |||||
| { | |||||
| Interlocked.Decrement(ref numOfNoHpStudent); | |||||
| } | |||||
| private void OpenEmergencyExit() | |||||
| { | |||||
| GameObjLockDict[GameObjType.EmergencyExit].EnterReadLock(); | |||||
| try | |||||
| { | |||||
| foreach (EmergencyExit emergencyExit in GameObjDict[GameObjType.EmergencyExit]) | |||||
| if (emergencyExit.CanOpen) | |||||
| { | |||||
| emergencyExit.IsOpen = true; | |||||
| break; | |||||
| } | |||||
| } | |||||
| finally | |||||
| { | |||||
| GameObjLockDict[GameObjType.EmergencyExit].ExitReadLock(); | |||||
| } | } | ||||
| } | } | ||||
| private Dictionary<GameObjType, IList<IGameObj>> gameObjDict; | private Dictionary<GameObjType, IList<IGameObj>> gameObjDict; | ||||
| public Dictionary<GameObjType, IList<IGameObj>> GameObjDict => gameObjDict; | public Dictionary<GameObjType, IList<IGameObj>> GameObjDict => gameObjDict; | ||||
| private Dictionary<GameObjType, ReaderWriterLockSlim> gameObjLockDict; | private Dictionary<GameObjType, ReaderWriterLockSlim> gameObjLockDict; | ||||
| @@ -163,8 +163,8 @@ namespace Gaming | |||||
| if (doorwayForEscape != null && doorwayForEscape.IsOpen()) | if (doorwayForEscape != null && doorwayForEscape.IsOpen()) | ||||
| { | { | ||||
| player.AddScore(GameData.StudentScoreEscape); | player.AddScore(GameData.StudentScoreEscape); | ||||
| ++gameMap.NumOfEscapedStudent; | |||||
| player.RemoveFromGame(PlayerStateType.Escaped); | |||||
| gameMap.MapEscapeStudent(); | |||||
| player.TryToRemoveFromGame(PlayerStateType.Escaped); | |||||
| return true; | return true; | ||||
| } | } | ||||
| else | else | ||||
| @@ -173,8 +173,8 @@ namespace Gaming | |||||
| if (emergencyExit != null && emergencyExit.IsOpen) | if (emergencyExit != null && emergencyExit.IsOpen) | ||||
| { | { | ||||
| player.AddScore(GameData.StudentScoreEscape); | player.AddScore(GameData.StudentScoreEscape); | ||||
| ++gameMap.NumOfEscapedStudent; | |||||
| player.RemoveFromGame(PlayerStateType.Escaped); | |||||
| gameMap.MapEscapeStudent(); | |||||
| player.TryToRemoveFromGame(PlayerStateType.Escaped); | |||||
| return true; | return true; | ||||
| } | } | ||||
| return false; | return false; | ||||
| @@ -218,13 +218,18 @@ namespace Gaming | |||||
| public void BeAddictedToGame(Student player, Ghost ghost) | public void BeAddictedToGame(Student player, Ghost ghost) | ||||
| { | { | ||||
| long stateNum = player.SetPlayerState(PlayerStateType.Addicted); | |||||
| if (stateNum == -1) | |||||
| { | |||||
| return; | |||||
| } | |||||
| if (player.CharacterType == CharacterType.Robot) | if (player.CharacterType == CharacterType.Robot) | ||||
| { | { | ||||
| ghost.AddScore(GameData.TrickerScoreDestroyRobot); | ghost.AddScore(GameData.TrickerScoreDestroyRobot); | ||||
| Die(player); | Die(player); | ||||
| return; | return; | ||||
| } | } | ||||
| ghost.AddScore(GameData.TrickerScoreStudentBeAddicted); | |||||
| if (player.GamingAddiction > 0) | if (player.GamingAddiction > 0) | ||||
| { | { | ||||
| if (player.GamingAddiction < GameData.BeginGamingAddiction) | if (player.GamingAddiction < GameData.BeginGamingAddiction) | ||||
| @@ -238,16 +243,16 @@ namespace Gaming | |||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| player.SetPlayerState(PlayerStateType.Addicted); | |||||
| long threadNum = player.StateNum; | |||||
| ghost.AddScore(GameData.TrickerScoreStudentBeAddicted); | |||||
| gameMap.MapAddictStudent(); | |||||
| new Thread | new Thread | ||||
| (() => | (() => | ||||
| { | { | ||||
| #if DEBUG | |||||
| Debugger.Output(player, " is addicted "); | Debugger.Output(player, " is addicted "); | ||||
| #endif | |||||
| new FrameRateTaskExecutor<int>( | new FrameRateTaskExecutor<int>( | ||||
| () => threadNum == player.StateNum && player.GamingAddiction < player.MaxGamingAddiction && gameMap.Timer.IsGaming, | |||||
| () => stateNum == player.StateNum && player.GamingAddiction < player.MaxGamingAddiction && gameMap.Timer.IsGaming, | |||||
| () => | () => | ||||
| { | { | ||||
| player.GamingAddiction += (player.PlayerState == PlayerStateType.Addicted) ? GameData.frameDuration : 0; | player.GamingAddiction += (player.PlayerState == PlayerStateType.Addicted) ? GameData.frameDuration : 0; | ||||
| @@ -255,6 +260,7 @@ namespace Gaming | |||||
| timeInterval: GameData.frameDuration, | timeInterval: GameData.frameDuration, | ||||
| () => | () => | ||||
| { | { | ||||
| gameMap.MapRescueStudent(); | |||||
| if (player.GamingAddiction == player.MaxGamingAddiction && gameMap.Timer.IsGaming) | if (player.GamingAddiction == player.MaxGamingAddiction && gameMap.Timer.IsGaming) | ||||
| { | { | ||||
| ghost.AddScore(GameData.TrickerScoreStudentDie); | ghost.AddScore(GameData.TrickerScoreStudentDie); | ||||
| @@ -397,11 +403,9 @@ namespace Gaming | |||||
| public void Die(Student player) | public void Die(Student player) | ||||
| { | { | ||||
| #if DEBUG | |||||
| Debugger.Output(player, "die."); | Debugger.Output(player, "die."); | ||||
| #endif | |||||
| if (player.PlayerState == PlayerStateType.Deceased) return; | |||||
| player.RemoveFromGame(PlayerStateType.Deceased); | |||||
| if (!player.TryToRemoveFromGame(PlayerStateType.Deceased)) return; | |||||
| for (int i = 0; i < GameData.maxNumOfPropInPropInventory; i++) | for (int i = 0; i < GameData.maxNumOfPropInPropInventory; i++) | ||||
| { | { | ||||
| @@ -430,9 +434,8 @@ namespace Gaming | |||||
| } | } | ||||
| return; | return; | ||||
| } | } | ||||
| ++gameMap.NumOfDeceasedStudent; | |||||
| gameMap.MapDieStudent(); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||