| @@ -3,6 +3,7 @@ using System.Threading; | |||
| using Preparation.Interface; | |||
| using Preparation.Utility; | |||
| using System; | |||
| using System.Collections.Concurrent; | |||
| namespace GameClass.GameObj | |||
| { | |||
| @@ -21,32 +22,18 @@ namespace GameClass.GameObj | |||
| uint value = Interlocked.Increment(ref numOfRepairedGenerators); | |||
| if (value == GameData.numOfGeneratorRequiredForEmergencyExit) | |||
| { | |||
| GameObjLockDict[GameObjType.EmergencyExit].EnterReadLock(); | |||
| try | |||
| { | |||
| Random r = new(Environment.TickCount); | |||
| EmergencyExit emergencyExit = (EmergencyExit)(GameObjDict[GameObjType.EmergencyExit][r.Next(0, GameObjDict[GameObjType.EmergencyExit].Count)]); | |||
| emergencyExit.CanOpen.SetReturnOri(true); | |||
| Preparation.Utility.Debugger.Output(emergencyExit, emergencyExit.Position.ToString()); | |||
| } | |||
| finally | |||
| { | |||
| GameObjLockDict[GameObjType.EmergencyExit].ExitReadLock(); | |||
| } | |||
| Random r = new(Environment.TickCount); | |||
| EmergencyExit emergencyExit = (EmergencyExit)(GameObjDict[GameObjType.EmergencyExit][r.Next(0, GameObjDict[GameObjType.EmergencyExit].Count)]); | |||
| emergencyExit.CanOpen.SetReturnOri(true); | |||
| Preparation.Utility.Debugger.Output(emergencyExit, emergencyExit.Position.ToString()); | |||
| } | |||
| else | |||
| if (value == GameData.numOfGeneratorRequiredForRepair) | |||
| { | |||
| GameObjLockDict[GameObjType.Doorway].EnterReadLock(); | |||
| try | |||
| GameObjDict[GameObjType.Doorway].ForEach(delegate (IGameObj doorway) | |||
| { | |||
| foreach (Doorway doorway in GameObjDict[GameObjType.Doorway]) | |||
| doorway.PowerSupply.SetReturnOri(true); | |||
| } | |||
| finally | |||
| { | |||
| GameObjLockDict[GameObjType.Doorway].ExitReadLock(); | |||
| } | |||
| ((Doorway)doorway).PowerSupply.SetReturnOri(true); | |||
| }); | |||
| } | |||
| } | |||
| @@ -113,20 +100,10 @@ namespace GameClass.GameObj | |||
| 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(); | |||
| } | |||
| EmergencyExit? emergencyExit = | |||
| (EmergencyExit?)GameObjDict[GameObjType.EmergencyExit].Find(gameObj => ((EmergencyExit)gameObj).CanOpen); | |||
| if (emergencyExit != null) | |||
| emergencyExit.IsOpen = true; | |||
| } | |||
| private void AddScoreFromAddict() | |||
| { | |||
| @@ -134,10 +111,8 @@ namespace GameClass.GameObj | |||
| } | |||
| private Dictionary<GameObjType, IList<IGameObj>> gameObjDict; | |||
| public Dictionary<GameObjType, IList<IGameObj>> GameObjDict => gameObjDict; | |||
| private Dictionary<GameObjType, ReaderWriterLockSlim> gameObjLockDict; | |||
| public Dictionary<GameObjType, ReaderWriterLockSlim> GameObjLockDict => gameObjLockDict; | |||
| private Dictionary<GameObjType, LockedClassList<IGameObj>> gameObjDict; | |||
| public Dictionary<GameObjType, LockedClassList<IGameObj>> GameObjDict => gameObjDict; | |||
| public readonly uint[,] protoGameMap; | |||
| public uint[,] ProtoGameMap => protoGameMap; | |||
| @@ -175,182 +150,55 @@ namespace GameClass.GameObj | |||
| public Character? FindPlayerInID(long playerID) | |||
| { | |||
| Character? player = null; | |||
| gameObjLockDict[GameObjType.Character].EnterReadLock(); | |||
| try | |||
| { | |||
| foreach (Character person in gameObjDict[GameObjType.Character]) | |||
| { | |||
| if (playerID == person.ID) | |||
| { | |||
| player = person; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameObjLockDict[GameObjType.Character].ExitReadLock(); | |||
| } | |||
| return player; | |||
| return (Character?)GameObjDict[GameObjType.Character].Find(gameObj => (playerID == ((Character)gameObj).ID)); | |||
| } | |||
| public Character? FindPlayerInPlayerID(long playerID) | |||
| { | |||
| Character? player = null; | |||
| gameObjLockDict[GameObjType.Character].EnterReadLock(); | |||
| try | |||
| { | |||
| foreach (Character person in gameObjDict[GameObjType.Character]) | |||
| { | |||
| if (playerID == person.PlayerID) | |||
| { | |||
| player = person; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameObjLockDict[GameObjType.Character].ExitReadLock(); | |||
| } | |||
| return player; | |||
| return (Character?)GameObjDict[GameObjType.Character].Find(gameObj => (playerID == ((Character)gameObj).PlayerID)); | |||
| } | |||
| public Ghost? ghost = null; | |||
| public Character? FindPlayerToAction(long playerID) | |||
| { | |||
| Character? player = null; | |||
| gameObjLockDict[GameObjType.Character].EnterReadLock(); | |||
| try | |||
| { | |||
| foreach (Character person in gameObjDict[GameObjType.Character]) | |||
| { | |||
| if (playerID == person.ID) | |||
| { | |||
| if (person.CharacterType == CharacterType.TechOtaku) | |||
| { | |||
| foreach (Character character in gameObjDict[GameObjType.Character]) | |||
| { | |||
| if (((UseRobot)person.FindActiveSkill(ActiveSkillType.UseRobot)).NowPlayerID == character.PlayerID) | |||
| { | |||
| player = character; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| else player = person; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameObjLockDict[GameObjType.Character].ExitReadLock(); | |||
| } | |||
| Character? player = (Character?)GameObjDict[GameObjType.Character].Find(gameObj => (playerID == ((Character)gameObj).ID)); | |||
| if (player == null) return null; | |||
| if (player.CharacterType == CharacterType.TechOtaku) | |||
| player = (Character?)GameObjDict[GameObjType.Character].Find( | |||
| gameObj => ( | |||
| ((UseRobot)player.FindActiveSkill(ActiveSkillType.UseRobot)).NowPlayerID == ((Character)gameObj).PlayerID | |||
| ) | |||
| ); | |||
| return player; | |||
| } | |||
| public GameObj? OneForInteract(XY Pos, GameObjType gameObjType) | |||
| { | |||
| GameObj? GameObjForInteract = null; | |||
| GameObjLockDict[gameObjType].EnterReadLock(); | |||
| try | |||
| { | |||
| foreach (GameObj gameObj in GameObjDict[gameObjType]) | |||
| { | |||
| if (GameData.ApproachToInteract(gameObj.Position, Pos)) | |||
| { | |||
| GameObjForInteract = gameObj; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| GameObjLockDict[gameObjType].ExitReadLock(); | |||
| } | |||
| return GameObjForInteract; | |||
| return (GameObj?)GameObjDict[gameObjType].Find(gameObj => GameData.ApproachToInteract(gameObj.Position, Pos)); | |||
| } | |||
| public Student? StudentForInteract(Student AStudent) | |||
| { | |||
| GameObjLockDict[GameObjType.Character].EnterReadLock(); | |||
| try | |||
| { | |||
| foreach (Character character in GameObjDict[GameObjType.Character]) | |||
| { | |||
| if (!character.IsGhost() && character != AStudent && GameData.ApproachToInteract(character.Position, AStudent.Position)) | |||
| { | |||
| return (Student)character; | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| return (Student?)GameObjDict[GameObjType.Character].Find(gameObj => | |||
| { | |||
| GameObjLockDict[GameObjType.Character].ExitReadLock(); | |||
| } | |||
| return null; | |||
| Character character = (Character)gameObj; | |||
| return !character.IsGhost() && character != AStudent && GameData.ApproachToInteract(character.Position, AStudent.Position); | |||
| }); | |||
| } | |||
| public GameObj? OneInTheSameCell(XY Pos, GameObjType gameObjType) | |||
| { | |||
| GameObj? GameObjForInteract = null; | |||
| GameObjLockDict[gameObjType].EnterReadLock(); | |||
| try | |||
| { | |||
| foreach (GameObj gameObj in GameObjDict[gameObjType]) | |||
| { | |||
| if (GameData.IsInTheSameCell(gameObj.Position, Pos)) | |||
| { | |||
| GameObjForInteract = gameObj; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| GameObjLockDict[gameObjType].ExitReadLock(); | |||
| } | |||
| return GameObjForInteract; | |||
| return (GameObj?)GameObjDict[gameObjType].Find(gameObj => | |||
| GameData.IsInTheSameCell(gameObj.Position, Pos) | |||
| ); | |||
| } | |||
| public GameObj? PartInTheSameCell(XY Pos, GameObjType gameObjType) | |||
| { | |||
| GameObj? GameObjForInteract = null; | |||
| GameObjLockDict[gameObjType].EnterReadLock(); | |||
| try | |||
| { | |||
| foreach (GameObj gameObj in GameObjDict[gameObjType]) | |||
| { | |||
| if (GameData.PartInTheSameCell(gameObj.Position, Pos)) | |||
| { | |||
| GameObjForInteract = gameObj; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| GameObjLockDict[gameObjType].ExitReadLock(); | |||
| } | |||
| return GameObjForInteract; | |||
| return (GameObj?)GameObjDict[gameObjType].Find(gameObj => | |||
| GameData.PartInTheSameCell(gameObj.Position, Pos) | |||
| ); | |||
| } | |||
| public GameObj? OneForInteractInACross(XY Pos, GameObjType gameObjType) | |||
| { | |||
| GameObj? GameObjForInteract = null; | |||
| GameObjLockDict[gameObjType].EnterReadLock(); | |||
| try | |||
| { | |||
| foreach (GameObj gameObj in GameObjDict[gameObjType]) | |||
| { | |||
| if (GameData.ApproachToInteractInACross(gameObj.Position, Pos)) | |||
| { | |||
| GameObjForInteract = gameObj; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| GameObjLockDict[gameObjType].ExitReadLock(); | |||
| } | |||
| return GameObjForInteract; | |||
| return (GameObj?)GameObjDict[gameObjType].Find(gameObj => | |||
| GameData.ApproachToInteractInACross(gameObj.Position, Pos)); | |||
| } | |||
| public bool CanSee(Character player, GameObj gameObj) | |||
| @@ -403,70 +251,35 @@ namespace GameClass.GameObj | |||
| public bool Remove(GameObj gameObj) | |||
| { | |||
| GameObj? ToDel = null; | |||
| GameObjLockDict[gameObj.Type].EnterWriteLock(); | |||
| try | |||
| if (GameObjDict[gameObj.Type].RemoveOne(obj => gameObj.ID == obj.ID)) | |||
| { | |||
| foreach (GameObj obj in GameObjDict[gameObj.Type]) | |||
| { | |||
| if (gameObj.ID == obj.ID) | |||
| { | |||
| ToDel = obj; | |||
| break; | |||
| } | |||
| } | |||
| if (ToDel != null) | |||
| { | |||
| GameObjDict[gameObj.Type].Remove(ToDel); | |||
| ToDel.TryToRemove(); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| GameObjLockDict[gameObj.Type].ExitWriteLock(); | |||
| gameObj.TryToRemove(); | |||
| return true; | |||
| } | |||
| return ToDel != null; | |||
| return false; | |||
| } | |||
| public bool RemoveJustFromMap(GameObj gameObj) | |||
| { | |||
| GameObjLockDict[gameObj.Type].EnterWriteLock(); | |||
| try | |||
| if (GameObjDict[gameObj.Type].Remove(gameObj)) | |||
| { | |||
| if (GameObjDict[gameObj.Type].Remove(gameObj)) | |||
| { | |||
| gameObj.TryToRemove(); | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| finally | |||
| { | |||
| GameObjLockDict[gameObj.Type].ExitWriteLock(); | |||
| gameObj.TryToRemove(); | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| public void Add(GameObj gameObj) | |||
| { | |||
| GameObjLockDict[gameObj.Type].EnterWriteLock(); | |||
| try | |||
| { | |||
| GameObjDict[gameObj.Type].Add(gameObj); | |||
| } | |||
| finally | |||
| { | |||
| GameObjLockDict[gameObj.Type].ExitWriteLock(); | |||
| } | |||
| GameObjDict[gameObj.Type].Add(gameObj); | |||
| } | |||
| public Map(uint[,] mapResource) | |||
| { | |||
| gameObjDict = new Dictionary<GameObjType, IList<IGameObj>>(); | |||
| gameObjLockDict = new Dictionary<GameObjType, ReaderWriterLockSlim>(); | |||
| gameObjDict = new Dictionary<GameObjType, LockedClassList<IGameObj>>(); | |||
| foreach (GameObjType idx in Enum.GetValues(typeof(GameObjType))) | |||
| { | |||
| if (idx != GameObjType.Null) | |||
| { | |||
| gameObjDict.Add(idx, new List<IGameObj>()); | |||
| gameObjLockDict.Add(idx, new ReaderWriterLockSlim()); | |||
| gameObjDict.TryAdd(idx, new LockedClassList<IGameObj>()); | |||
| } | |||
| } | |||
| @@ -1,5 +1,6 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Threading; | |||
| using Preparation.Interface; | |||
| using Preparation.Utility; | |||
| @@ -10,33 +11,25 @@ namespace GameEngine | |||
| public IGameObj? CheckCollision(IMoveable obj, XY Pos) | |||
| { | |||
| // 在列表中检查碰撞 | |||
| Func<IEnumerable<IGameObj>, ReaderWriterLockSlim, IGameObj?> CheckCollisionInList = | |||
| (IEnumerable<IGameObj> lst, ReaderWriterLockSlim listLock) => | |||
| Func<LockedClassList<IGameObj>, IGameObj?> CheckCollisionInList = | |||
| (LockedClassList<IGameObj> lst) => | |||
| { | |||
| IGameObj? collisionObj = null; | |||
| listLock.EnterReadLock(); | |||
| try | |||
| foreach (IGameObj listObj in lst) | |||
| { | |||
| foreach (var listObj in lst) | |||
| if (obj.WillCollideWith(listObj, Pos)) | |||
| { | |||
| if (obj.WillCollideWith(listObj, Pos)) | |||
| { | |||
| collisionObj = listObj; | |||
| break; | |||
| } | |||
| collisionObj = listObj; | |||
| break; | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| listLock.ExitReadLock(); | |||
| } | |||
| return collisionObj; | |||
| }; | |||
| IGameObj? collisionObj; | |||
| foreach (var list in lists) | |||
| { | |||
| if ((collisionObj = CheckCollisionInList(list.Item1, list.Item2)) != null) | |||
| if ((collisionObj = CheckCollisionInList(list)) != null) | |||
| { | |||
| return collisionObj; | |||
| } | |||
| @@ -127,100 +120,86 @@ namespace GameEngine | |||
| double maxDistance = uint.MaxValue; | |||
| foreach (var listWithLock in lists) | |||
| { | |||
| var lst = listWithLock.Item1; | |||
| var listLock = listWithLock.Item2; | |||
| listLock.EnterReadLock(); | |||
| try | |||
| var lst = listWithLock; | |||
| foreach (IGameObj listObj in lst) | |||
| { | |||
| foreach (IGameObj listObj in lst) | |||
| // 如果再走一步发生碰撞 | |||
| if (obj.WillCollideWith(listObj, nextPos)) | |||
| { | |||
| // 如果再走一步发生碰撞 | |||
| if (obj.WillCollideWith(listObj, nextPos)) | |||
| { | |||
| switch (listObj.Shape) // 默认obj为圆形 | |||
| { | |||
| switch (listObj.Shape) // 默认obj为圆形 | |||
| { | |||
| case ShapeType.Circle: | |||
| { | |||
| // 计算两者之间的距离 | |||
| double mod = XY.DistanceFloor3(listObj.Position, obj.Position); | |||
| int orgDeltaX = listObj.Position.x - obj.Position.x; | |||
| int orgDeltaY = listObj.Position.y - obj.Position.y; | |||
| case ShapeType.Circle: | |||
| { | |||
| // 计算两者之间的距离 | |||
| double mod = XY.DistanceFloor3(listObj.Position, obj.Position); | |||
| int orgDeltaX = listObj.Position.x - obj.Position.x; | |||
| int orgDeltaY = listObj.Position.y - obj.Position.y; | |||
| if (mod < listObj.Radius + obj.Radius) // 如果两者已经重叠 | |||
| if (mod < listObj.Radius + obj.Radius) // 如果两者已经重叠 | |||
| { | |||
| tmpMax = 0; | |||
| } | |||
| else | |||
| { | |||
| double tmp = mod - obj.Radius - listObj.Radius; | |||
| // 计算能走的最长距离,好像这么算有一点误差? | |||
| tmp = ((int)(tmp * 1000 / Math.Cos(Math.Atan2(orgDeltaY, orgDeltaX) - moveVec.Angle()))); | |||
| if (tmp < 0 || tmp > uint.MaxValue || double.IsNaN(tmp)) | |||
| { | |||
| tmpMax = 0; | |||
| tmpMax = uint.MaxValue; | |||
| } | |||
| else | |||
| { | |||
| double tmp = mod - obj.Radius - listObj.Radius; | |||
| // 计算能走的最长距离,好像这么算有一点误差? | |||
| tmp = ((int)(tmp * 1000 / Math.Cos(Math.Atan2(orgDeltaY, orgDeltaX) - moveVec.Angle()))); | |||
| if (tmp < 0 || tmp > uint.MaxValue || double.IsNaN(tmp)) | |||
| { | |||
| tmpMax = uint.MaxValue; | |||
| } | |||
| else | |||
| tmpMax = tmp / 1000.0; | |||
| } | |||
| break; | |||
| tmpMax = tmp / 1000.0; | |||
| } | |||
| case ShapeType.Square: | |||
| break; | |||
| } | |||
| case ShapeType.Square: | |||
| { | |||
| // if (obj.WillCollideWith(listObj, obj.Position)) | |||
| // tmpMax = 0; | |||
| // else tmpMax = MaxMoveToSquare(obj, listObj); | |||
| // break; | |||
| if (obj.WillCollideWith(listObj, obj.Position)) | |||
| tmpMax = 0; | |||
| else | |||
| { | |||
| // if (obj.WillCollideWith(listObj, obj.Position)) | |||
| // tmpMax = 0; | |||
| // else tmpMax = MaxMoveToSquare(obj, listObj); | |||
| // break; | |||
| if (obj.WillCollideWith(listObj, obj.Position)) | |||
| tmpMax = 0; | |||
| else | |||
| // 二分查找最大可能移动距离 | |||
| int left = 0, right = (int)moveVec.Length(); | |||
| while (left < right - 1) | |||
| { | |||
| // 二分查找最大可能移动距离 | |||
| int left = 0, right = (int)moveVec.Length(); | |||
| while (left < right - 1) | |||
| int mid = (right - left) / 2 + left; | |||
| if (obj.WillCollideWith(listObj, obj.Position + new XY(moveVec, mid))) | |||
| { | |||
| int mid = (right - left) / 2 + left; | |||
| if (obj.WillCollideWith(listObj, obj.Position + new XY(moveVec, mid))) | |||
| { | |||
| right = mid; | |||
| } | |||
| else | |||
| left = mid; | |||
| right = mid; | |||
| } | |||
| tmpMax = (uint)left; | |||
| else | |||
| left = mid; | |||
| } | |||
| break; | |||
| tmpMax = (uint)left; | |||
| } | |||
| default: | |||
| tmpMax = uint.MaxValue; | |||
| break; | |||
| } | |||
| if (tmpMax < maxDistance) | |||
| maxDistance = tmpMax; | |||
| } | |||
| default: | |||
| tmpMax = uint.MaxValue; | |||
| break; | |||
| } | |||
| if (tmpMax < maxDistance) | |||
| maxDistance = tmpMax; | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| listLock.ExitReadLock(); | |||
| } | |||
| } | |||
| return maxDistance; | |||
| } | |||
| readonly IMap gameMap; | |||
| private readonly Tuple<IEnumerable<IGameObj>, ReaderWriterLockSlim>[] lists; | |||
| private readonly LockedClassList<IGameObj>[] lists; | |||
| public CollisionChecker(IMap gameMap) | |||
| { | |||
| this.gameMap = gameMap; | |||
| lists = new Tuple<IEnumerable<IGameObj>, ReaderWriterLockSlim>[gameMap.GameObjDict.Count]; | |||
| int i = 0; | |||
| foreach (var keyValuePair in gameMap.GameObjDict) | |||
| { | |||
| lists[i++] = new Tuple<IEnumerable<IGameObj>, ReaderWriterLockSlim>(keyValuePair.Value as IList<IGameObj>, gameMap.GameObjLockDict[keyValuePair.Key]); | |||
| } | |||
| lists = gameMap.GameObjDict.Values.ToArray(); | |||
| } | |||
| } | |||
| } | |||
| @@ -168,20 +168,11 @@ namespace Gaming | |||
| { | |||
| if (bullet.CanBeBombed(kvp.Key)) | |||
| { | |||
| gameMap.GameObjLockDict[kvp.Key].EnterReadLock(); | |||
| try | |||
| { | |||
| foreach (var item in gameMap.GameObjDict[kvp.Key]) | |||
| if (bullet.CanAttack((GameObj)item)) | |||
| { | |||
| beAttackedList.Add(item); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[kvp.Key].ExitReadLock(); | |||
| } | |||
| foreach (var item in gameMap.GameObjDict[kvp.Key]) | |||
| if (bullet.CanAttack((GameObj)item)) | |||
| { | |||
| beAttackedList.Add((IGameObj)item); | |||
| } | |||
| } | |||
| } | |||
| @@ -71,96 +71,72 @@ namespace Gaming | |||
| bool noise = false; | |||
| if (!newPlayer.IsGhost()) | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); | |||
| try | |||
| foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) | |||
| { | |||
| foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) | |||
| if (person.IsGhost()) | |||
| { | |||
| if (person.IsGhost()) | |||
| if (person.CharacterType == CharacterType.ANoisyPerson) | |||
| { | |||
| if (person.CharacterType == CharacterType.ANoisyPerson) | |||
| { | |||
| noise = true; | |||
| newPlayer.AddBgm(BgmType.GhostIsComing, 1411180); | |||
| newPlayer.AddBgm(BgmType.GeneratorIsBeingFixed, 154991); | |||
| } | |||
| noise = true; | |||
| newPlayer.AddBgm(BgmType.GhostIsComing, 1411180); | |||
| newPlayer.AddBgm(BgmType.GeneratorIsBeingFixed, 154991); | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); | |||
| } | |||
| } | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => gameMap.Timer.IsGaming && !newPlayer.IsRemoved, | |||
| loopToDo: () => | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); | |||
| try | |||
| if (newPlayer.IsGhost()) | |||
| { | |||
| if (newPlayer.IsGhost()) | |||
| double bgmVolume = 0; | |||
| foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) | |||
| { | |||
| double bgmVolume = 0; | |||
| foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) | |||
| if (!person.IsGhost() && XY.DistanceFloor3(newPlayer.Position, person.Position) <= (newPlayer.AlertnessRadius / person.Concealment)) | |||
| { | |||
| if (!person.IsGhost() && XY.DistanceFloor3(newPlayer.Position, person.Position) <= (newPlayer.AlertnessRadius / person.Concealment)) | |||
| { | |||
| if ((double)newPlayer.AlertnessRadius / XY.DistanceFloor3(newPlayer.Position, person.Position) > bgmVolume) | |||
| bgmVolume = newPlayer.AlertnessRadius / XY.DistanceFloor3(newPlayer.Position, person.Position); | |||
| } | |||
| if ((double)newPlayer.AlertnessRadius / XY.DistanceFloor3(newPlayer.Position, person.Position) > bgmVolume) | |||
| bgmVolume = newPlayer.AlertnessRadius / XY.DistanceFloor3(newPlayer.Position, person.Position); | |||
| } | |||
| newPlayer.AddBgm(BgmType.StudentIsApproaching, bgmVolume); | |||
| } | |||
| else | |||
| newPlayer.AddBgm(BgmType.StudentIsApproaching, bgmVolume); | |||
| } | |||
| else | |||
| { | |||
| foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) | |||
| { | |||
| foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) | |||
| if (person.IsGhost()) | |||
| { | |||
| if (person.IsGhost()) | |||
| if (!noise) | |||
| { | |||
| if (!noise) | |||
| { | |||
| if (XY.DistanceFloor3(newPlayer.Position, person.Position) <= (newPlayer.AlertnessRadius / person.Concealment)) | |||
| newPlayer.AddBgm(BgmType.GhostIsComing, (double)newPlayer.AlertnessRadius / XY.DistanceFloor3(newPlayer.Position, person.Position)); | |||
| else newPlayer.AddBgm(BgmType.GhostIsComing, 0); | |||
| } | |||
| if (newPlayer.CharacterType != CharacterType.Teacher && newPlayer.CharacterType != CharacterType.Robot && newPlayer.CanPinDown() && XY.DistanceFloor3(newPlayer.Position, person.Position) <= GameData.PinningDownRange) | |||
| { | |||
| TimePinningDown += GameData.checkInterval; | |||
| newPlayer.AddScore(GameData.StudentScorePinDown(TimePinningDown) - ScoreAdded); | |||
| ScoreAdded = GameData.StudentScorePinDown(TimePinningDown); | |||
| } | |||
| else TimePinningDown = ScoreAdded = 0; | |||
| break; | |||
| if (XY.DistanceFloor3(newPlayer.Position, person.Position) <= (newPlayer.AlertnessRadius / person.Concealment)) | |||
| newPlayer.AddBgm(BgmType.GhostIsComing, (double)newPlayer.AlertnessRadius / XY.DistanceFloor3(newPlayer.Position, person.Position)); | |||
| else newPlayer.AddBgm(BgmType.GhostIsComing, 0); | |||
| } | |||
| if (newPlayer.CharacterType != CharacterType.Teacher && newPlayer.CharacterType != CharacterType.Robot && newPlayer.CanPinDown() && XY.DistanceFloor3(newPlayer.Position, person.Position) <= GameData.PinningDownRange) | |||
| { | |||
| 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]) | |||
| { | |||
| double bgmVolume = 0; | |||
| foreach (Generator generator in gameMap.GameObjDict[GameObjType.Generator]) | |||
| if (XY.DistanceFloor3(newPlayer.Position, generator.Position) <= newPlayer.AlertnessRadius) | |||
| { | |||
| if (XY.DistanceFloor3(newPlayer.Position, generator.Position) <= newPlayer.AlertnessRadius) | |||
| { | |||
| if (generator.NumOfFixing > 0 && (double)newPlayer.AlertnessRadius * generator.DegreeOfRepair / GameData.degreeOfFixedGenerator / XY.DistanceFloor3(newPlayer.Position, generator.Position) > bgmVolume) | |||
| bgmVolume = (double)newPlayer.AlertnessRadius * generator.DegreeOfRepair / GameData.degreeOfFixedGenerator / XY.DistanceFloor3(newPlayer.Position, generator.Position); | |||
| } | |||
| if (generator.NumOfFixing > 0 && (double)newPlayer.AlertnessRadius * generator.DegreeOfRepair / GameData.degreeOfFixedGenerator / XY.DistanceFloor3(newPlayer.Position, generator.Position) > bgmVolume) | |||
| bgmVolume = (double)newPlayer.AlertnessRadius * generator.DegreeOfRepair / GameData.degreeOfFixedGenerator / XY.DistanceFloor3(newPlayer.Position, generator.Position); | |||
| } | |||
| newPlayer.AddBgm(BgmType.GeneratorIsBeingFixed, bgmVolume); | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Generator].ExitReadLock(); | |||
| } | |||
| newPlayer.AddBgm(BgmType.GeneratorIsBeingFixed, bgmVolume); | |||
| } | |||
| }, | |||
| timeInterval: GameData.checkInterval, | |||
| @@ -281,17 +281,9 @@ namespace Gaming | |||
| { | |||
| if (!gameMap.Timer.IsGaming) | |||
| return; | |||
| gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); | |||
| try | |||
| foreach (Character player in gameMap.GameObjDict[GameObjType.Character]) | |||
| { | |||
| foreach (Character player in gameMap.GameObjDict[GameObjType.Character]) | |||
| { | |||
| skillManager.UseAllPassiveSkill(player); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); | |||
| skillManager.UseAllPassiveSkill(player); | |||
| } | |||
| } | |||
| @@ -319,22 +311,14 @@ namespace Gaming | |||
| { | |||
| if (!GameData.NeedCopy(keyValuePair.Key)) | |||
| { | |||
| gameMap.GameObjLockDict[keyValuePair.Key].EnterWriteLock(); | |||
| try | |||
| if (keyValuePair.Key == GameObjType.Character) | |||
| { | |||
| if (keyValuePair.Key == GameObjType.Character) | |||
| foreach (Character player in gameMap.GameObjDict[GameObjType.Character]) | |||
| { | |||
| foreach (Character player in gameMap.GameObjDict[GameObjType.Character]) | |||
| { | |||
| player.CanMove.SetReturnOri(false); | |||
| } | |||
| player.CanMove.SetReturnOri(false); | |||
| } | |||
| gameMap.GameObjDict[keyValuePair.Key].Clear(); | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[keyValuePair.Key].ExitWriteLock(); | |||
| } | |||
| gameMap.GameObjDict[keyValuePair.Key].Clear(); | |||
| } | |||
| } | |||
| } | |||
| @@ -350,15 +334,7 @@ namespace Gaming | |||
| { | |||
| if (GameData.NeedCopy(keyValuePair.Key)) | |||
| { | |||
| gameMap.GameObjLockDict[keyValuePair.Key].EnterReadLock(); | |||
| try | |||
| { | |||
| gameObjList.AddRange(gameMap.GameObjDict[keyValuePair.Key]); | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[keyValuePair.Key].ExitReadLock(); | |||
| } | |||
| gameObjList.AddRange(gameMap.GameObjDict[keyValuePair.Key].ToNewList()); | |||
| } | |||
| } | |||
| return gameObjList; | |||
| @@ -83,24 +83,16 @@ namespace Gaming | |||
| } | |||
| else | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Gadget].EnterReadLock(); | |||
| try | |||
| foreach (Gadget prop in gameMap.GameObjDict[GameObjType.Gadget]) | |||
| { | |||
| foreach (Gadget prop in gameMap.GameObjDict[GameObjType.Gadget]) | |||
| if (prop.GetPropType() == propType) | |||
| { | |||
| if (prop.GetPropType() == propType) | |||
| if (GameData.IsInTheSameCell(prop.Position, player.Position) && prop.CanMove == false) | |||
| { | |||
| if (GameData.IsInTheSameCell(prop.Position, player.Position) && prop.CanMove == false) | |||
| { | |||
| pickProp = player.PropInventory[indexing] = prop; | |||
| } | |||
| pickProp = player.PropInventory[indexing] = prop; | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Gadget].ExitReadLock(); | |||
| } | |||
| } | |||
| if (pickProp.GetPropType() != PropType.Null) | |||
| @@ -142,47 +134,39 @@ namespace Gaming | |||
| int len = availableCellForGenerateProp.Count; | |||
| Random r = new Random(Environment.TickCount); | |||
| gameMap.GameObjLockDict[GameObjType.Chest].EnterReadLock(); | |||
| try | |||
| int cou = 0; | |||
| while (cou < GameData.numOfKeyEachArea) | |||
| { | |||
| int cou = 0; | |||
| while (cou < GameData.numOfKeyEachArea) | |||
| { | |||
| ++cou; | |||
| Chest chest = GetChest(r); | |||
| chest.PropInChest[1] = new Key3(chest.Position); | |||
| chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); | |||
| } | |||
| cou = 0; | |||
| while (cou < GameData.numOfKeyEachArea) | |||
| { | |||
| ++cou; | |||
| Chest chest = GetChest(r); | |||
| chest.PropInChest[1] = new Key5(chest.Position); | |||
| chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); | |||
| } | |||
| cou = 0; | |||
| while (cou < GameData.numOfKeyEachArea) | |||
| { | |||
| ++cou; | |||
| Chest chest = GetChest(r); | |||
| chest.PropInChest[1] = new Key6(chest.Position); | |||
| chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); | |||
| } | |||
| ++cou; | |||
| Chest chest = GetChest(r); | |||
| chest.PropInChest[1] = new Key3(chest.Position); | |||
| chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); | |||
| } | |||
| cou = 0; | |||
| while (cou < GameData.numOfKeyEachArea) | |||
| { | |||
| ++cou; | |||
| Chest chest = GetChest(r); | |||
| chest.PropInChest[1] = new Key5(chest.Position); | |||
| chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); | |||
| } | |||
| cou = 0; | |||
| while (cou < GameData.numOfKeyEachArea) | |||
| { | |||
| ++cou; | |||
| Chest chest = GetChest(r); | |||
| chest.PropInChest[1] = new Key6(chest.Position); | |||
| chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); | |||
| } | |||
| foreach (Chest chest in gameMap.GameObjDict[GameObjType.Chest]) | |||
| foreach (Chest chest in gameMap.GameObjDict[GameObjType.Chest]) | |||
| { | |||
| if (chest.PropInChest[0].GetPropType() == PropType.Null) | |||
| { | |||
| if (chest.PropInChest[0].GetPropType() == PropType.Null) | |||
| { | |||
| chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); | |||
| chest.PropInChest[1] = ProduceOnePropNotKey(r, chest.Position); | |||
| } | |||
| chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); | |||
| chest.PropInChest[1] = ProduceOnePropNotKey(r, chest.Position); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Chest].ExitReadLock(); | |||
| } | |||
| /* | |||
| new Thread | |||
| ( | |||
| @@ -43,35 +43,27 @@ namespace Gaming | |||
| loopCondition: () => player.Commandable() && gameMap.Timer.IsGaming, | |||
| loopToDo: () => | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); | |||
| try | |||
| foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) | |||
| { | |||
| foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) | |||
| if (!person.IsGhost() && person.CharacterType != CharacterType.Robot && !person.NoHp()) | |||
| { | |||
| if (!person.IsGhost() && person.CharacterType != CharacterType.Robot && !person.NoHp()) | |||
| double dis = XY.DistanceFloor3(person.Position, player.Position); | |||
| if (dis >= player.AlertnessRadius) | |||
| { | |||
| double dis = XY.DistanceFloor3(person.Position, player.Position); | |||
| if (dis >= player.AlertnessRadius) | |||
| { | |||
| person.AddMoveSpeed(GameData.checkIntervalWhenShowTime, dis / player.AlertnessRadius); | |||
| actionManager.MovePlayerWhenStunned(person, GameData.checkIntervalWhenShowTime, (player.Position - person.Position).Angle()); | |||
| } | |||
| else if (dis >= player.ViewRange) | |||
| person.AddMoveSpeed(GameData.checkIntervalWhenShowTime, dis / player.AlertnessRadius); | |||
| actionManager.MovePlayerWhenStunned(person, GameData.checkIntervalWhenShowTime, (player.Position - person.Position).Angle()); | |||
| } | |||
| else if (dis >= player.ViewRange) | |||
| { | |||
| Student student = (Student)person; | |||
| student.GamingAddiction.AddPositiveV(GameData.checkIntervalWhenShowTime); | |||
| if (student.GamingAddiction.IsMaxV()) | |||
| { | |||
| Student student = (Student)person; | |||
| student.GamingAddiction.AddPositiveV(GameData.checkIntervalWhenShowTime); | |||
| if (student.GamingAddiction.IsMaxV()) | |||
| { | |||
| characterManager.Die(student); | |||
| } | |||
| characterManager.Die(student); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); | |||
| } | |||
| }, | |||
| timeInterval: GameData.checkIntervalWhenShowTime, | |||
| maxTotalDuration: skill.DurationTime, | |||
| @@ -178,22 +170,15 @@ namespace Gaming | |||
| loopToDo: () => | |||
| { | |||
| dis = ((homingMissile == null || homingMissile.IsRemoved) ? double.MaxValue : XY.DistanceFloor3(homingMissile.Position, whoAttacked.Position)); | |||
| gameMap.GameObjLockDict[GameObjType.Bullet].EnterReadLock(); | |||
| try | |||
| foreach (Bullet bullet in gameMap.GameObjDict[GameObjType.Bullet]) | |||
| { | |||
| foreach (Bullet bullet in gameMap.GameObjDict[GameObjType.Bullet]) | |||
| if (!bullet.CanMove && XY.DistanceFloor3(bullet.Position, whoAttacked.Position) < dis && bullet.TypeOfBullet == BulletType.JumpyDumpty) | |||
| { | |||
| if (!bullet.CanMove && XY.DistanceFloor3(bullet.Position, whoAttacked.Position) < dis && bullet.TypeOfBullet == BulletType.JumpyDumpty) | |||
| { | |||
| homingMissile = bullet; | |||
| dis = XY.DistanceFloor3(bullet.Position, whoAttacked.Position); | |||
| } | |||
| homingMissile = bullet; | |||
| dis = XY.DistanceFloor3(bullet.Position, whoAttacked.Position); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Bullet].ExitReadLock(); | |||
| } | |||
| if (homingMissile != null) | |||
| { | |||
| homingMissile.CanMove.SetReturnOri(true); | |||
| @@ -309,22 +294,14 @@ namespace Gaming | |||
| if ((!player.Commandable())) return false; | |||
| return ActiveSkillEffect(player.FindActiveSkill(ActiveSkillType.Howl), player, () => | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); | |||
| try | |||
| foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) | |||
| { | |||
| foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) | |||
| if (!character.IsGhost() && !character.NoHp() && XY.DistanceFloor3(character.Position, player.Position) <= player.ViewRange) | |||
| { | |||
| if (!character.IsGhost() && !character.NoHp() && XY.DistanceFloor3(character.Position, player.Position) <= player.ViewRange) | |||
| { | |||
| if (CharacterManager.BeStunned(character, GameData.timeOfStudentStunnedWhenHowl) > 0) | |||
| player.AddScore(GameData.TrickerScoreStudentBeStunned(GameData.timeOfStudentStunnedWhenHowl)); | |||
| } | |||
| if (CharacterManager.BeStunned(character, GameData.timeOfStudentStunnedWhenHowl) > 0) | |||
| player.AddScore(GameData.TrickerScoreStudentBeStunned(GameData.timeOfStudentStunnedWhenHowl)); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); | |||
| } | |||
| characterManager.BackSwing(player, GameData.timeOfGhostSwingingAfterHowl); | |||
| Debugger.Output(player, "howled!"); | |||
| }, | |||
| @@ -337,29 +314,21 @@ namespace Gaming | |||
| if ((!player.Commandable())) return false; | |||
| return ActiveSkillEffect(player.FindActiveSkill(ActiveSkillType.Punish), player, () => | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); | |||
| try | |||
| foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) | |||
| { | |||
| foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) | |||
| if (character.IsGhost() && | |||
| (character.PlayerState == PlayerStateType.TryingToAttack || character.PlayerState == PlayerStateType.Swinging | |||
| || character.PlayerState == PlayerStateType.UsingSkill | |||
| || character.PlayerState == PlayerStateType.LockingTheDoor || character.PlayerState == PlayerStateType.OpeningTheDoor | |||
| || character.PlayerState == PlayerStateType.ClimbingThroughWindows) | |||
| && XY.DistanceFloor3(character.Position, player.Position) <= player.ViewRange / 3) | |||
| { | |||
| if (character.IsGhost() && | |||
| (character.PlayerState == PlayerStateType.TryingToAttack || character.PlayerState == PlayerStateType.Swinging | |||
| || character.PlayerState == PlayerStateType.UsingSkill | |||
| || character.PlayerState == PlayerStateType.LockingTheDoor || character.PlayerState == PlayerStateType.OpeningTheDoor | |||
| || character.PlayerState == PlayerStateType.ClimbingThroughWindows) | |||
| && XY.DistanceFloor3(character.Position, player.Position) <= player.ViewRange / 3) | |||
| { | |||
| int stunTime = (GameData.timeOfGhostStunnedWhenPunish + (int)((GameData.factorOfTimeStunnedWhenPunish * (player.HP.GetMaxV() - player.HP) / GameData.basicApOfGhost))) / characterManager.FactorTeacher; | |||
| if (CharacterManager.BeStunned(character, stunTime) > 0) | |||
| player.AddScore(GameData.StudentScoreTrickerBeStunned(stunTime) / characterManager.FactorTeacher); | |||
| break; | |||
| } | |||
| int stunTime = (GameData.timeOfGhostStunnedWhenPunish + (int)((GameData.factorOfTimeStunnedWhenPunish * (player.HP.GetMaxV() - player.HP) / GameData.basicApOfGhost))) / characterManager.FactorTeacher; | |||
| if (CharacterManager.BeStunned(character, stunTime) > 0) | |||
| player.AddScore(GameData.StudentScoreTrickerBeStunned(stunTime) / characterManager.FactorTeacher); | |||
| break; | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); | |||
| } | |||
| Debugger.Output(player, "uses punishing!"); | |||
| }, | |||
| () => | |||
| @@ -411,28 +380,20 @@ namespace Gaming | |||
| if ((!player.Commandable())) return false; | |||
| return ActiveSkillEffect(player.FindActiveSkill(ActiveSkillType.Rouse), player, () => | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); | |||
| try | |||
| foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) | |||
| { | |||
| foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) | |||
| lock (character.ActionLock) | |||
| { | |||
| lock (character.ActionLock) | |||
| if ((character.PlayerState == PlayerStateType.Addicted) && gameMap.CanSee(player, character)) | |||
| { | |||
| if ((character.PlayerState == PlayerStateType.Addicted) && gameMap.CanSee(player, character)) | |||
| { | |||
| character.SetPlayerStateNaturally(); | |||
| character.HP.SetPositiveV(GameData.RemainHpWhenAddLife); | |||
| ((Student)character).TimeOfRescue.SetReturnOri(0); | |||
| player.AddScore(GameData.StudentScoreRescue); | |||
| break; | |||
| } | |||
| character.SetPlayerStateNaturally(); | |||
| character.HP.SetPositiveV(GameData.RemainHpWhenAddLife); | |||
| ((Student)character).TimeOfRescue.SetReturnOri(0); | |||
| player.AddScore(GameData.StudentScoreRescue); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); | |||
| } | |||
| Debugger.Output(player, "rouse someone!"); | |||
| }, | |||
| () => | |||
| @@ -444,24 +405,16 @@ namespace Gaming | |||
| if ((!player.Commandable())) return false; | |||
| return ActiveSkillEffect(player.FindActiveSkill(ActiveSkillType.Encourage), player, () => | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); | |||
| try | |||
| foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) | |||
| { | |||
| foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) | |||
| if ((character.HP < character.HP.GetMaxV()) && gameMap.CanSee(player, character)) | |||
| { | |||
| if ((character.HP < character.HP.GetMaxV()) && gameMap.CanSee(player, character)) | |||
| { | |||
| player.AddScore(GameData.StudentScoreTreat(GameData.addHpWhenEncourage)); | |||
| character.HP.AddPositiveV(GameData.addHpWhenEncourage); | |||
| ((Student)character).SetDegreeOfTreatment0(); | |||
| break; | |||
| } | |||
| player.AddScore(GameData.StudentScoreTreat(GameData.addHpWhenEncourage)); | |||
| character.HP.AddPositiveV(GameData.addHpWhenEncourage); | |||
| ((Student)character).SetDegreeOfTreatment0(); | |||
| break; | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); | |||
| } | |||
| Debugger.Output(player, "encourage someone!"); | |||
| }, | |||
| () => | |||
| @@ -473,22 +426,14 @@ namespace Gaming | |||
| if ((!player.Commandable())) return false; | |||
| return ActiveSkillEffect(player.FindActiveSkill(ActiveSkillType.Inspire), player, () => | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); | |||
| try | |||
| foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) | |||
| { | |||
| foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) | |||
| if (gameMap.CanSee(player, character) && !character.IsGhost()) | |||
| { | |||
| if (gameMap.CanSee(player, character) && !character.IsGhost()) | |||
| { | |||
| player.AddScore(GameData.ScoreInspire); | |||
| character.AddMoveSpeed(GameData.timeOfAddingSpeedWhenInspire, GameData.addedTimeOfSpeedWhenInspire); | |||
| } | |||
| player.AddScore(GameData.ScoreInspire); | |||
| character.AddMoveSpeed(GameData.timeOfAddingSpeedWhenInspire, GameData.addedTimeOfSpeedWhenInspire); | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); | |||
| } | |||
| Debugger.Output(player, "inspires!"); | |||
| }, | |||
| () => | |||
| @@ -1,4 +1,5 @@ | |||
| using System.Collections.Generic; | |||
| using System.Collections.Concurrent; | |||
| using System.Collections.Generic; | |||
| using System.Threading; | |||
| using Preparation.Utility; | |||
| @@ -9,8 +10,7 @@ namespace Preparation.Interface | |||
| ITimer Timer { get; } | |||
| // the two dicts must have same keys | |||
| Dictionary<GameObjType, IList<IGameObj>> GameObjDict { get; } | |||
| Dictionary<GameObjType, ReaderWriterLockSlim> GameObjLockDict { get; } | |||
| Dictionary<GameObjType, LockedClassList<IGameObj>> GameObjDict { get; } | |||
| public uint[,] ProtoGameMap { get; } | |||
| public PlaceType GetPlaceType(IGameObj obj); | |||
| @@ -1,24 +1,26 @@ | |||
| using System; | |||
| using System.Collections; | |||
| using System.Collections.Generic; | |||
| using System.Threading; | |||
| namespace Preparation.Utility | |||
| { | |||
| public class LockedClassList<T> where T : class | |||
| public class LockedClassList<T> : IEnumerable | |||
| where T : class | |||
| { | |||
| private readonly ReaderWriterLockSlim listLock = new(); | |||
| private List<T> list; | |||
| #region 构造 | |||
| public LockedList() | |||
| public LockedClassList() | |||
| { | |||
| list = new List<T>(); | |||
| } | |||
| public LockedList(int capacity) | |||
| public LockedClassList(int capacity) | |||
| { | |||
| list = new List<T>(capacity); | |||
| } | |||
| public LockedList(IEnumerable<T> collection) | |||
| public LockedClassList(IEnumerable<T> collection) | |||
| { | |||
| list = new List<T>(collection); | |||
| } | |||
| @@ -141,6 +143,17 @@ namespace Preparation.Utility | |||
| return ReadLock(() => { return list.IndexOf(item); }); | |||
| } | |||
| public Array ToArray() | |||
| { | |||
| return ReadLock(() => { return list.ToArray(); }); | |||
| } | |||
| public List<T> ToNewList() | |||
| { | |||
| List<T> lt = new(); | |||
| return ReadLock(() => { lt.AddRange(list); return lt; }); | |||
| } | |||
| public bool Contains(T item) | |||
| { | |||
| return ReadLock(() => { return list.Contains(item); }); | |||
| @@ -159,6 +172,11 @@ namespace Preparation.Utility | |||
| public int FindIndex(Predicate<T> match) => ReadLock(() => { return list.FindIndex(match); }); | |||
| public void ForEach(Action<T> action) => ReadLock(() => { list.ForEach(action); }); | |||
| public IEnumerator GetEnumerator() | |||
| { | |||
| return ReadLock(() => { return list.GetEnumerator(); }); | |||
| } | |||
| #endregion | |||
| } | |||
| } | |||
| @@ -173,17 +173,9 @@ namespace Server | |||
| } | |||
| private bool playerDeceased(int playerID) | |||
| { | |||
| game.GameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); | |||
| try | |||
| foreach (Character character in game.GameMap.GameObjDict[GameObjType.Character]) | |||
| { | |||
| foreach (Character character in game.GameMap.GameObjDict[GameObjType.Character]) | |||
| { | |||
| if (character.PlayerID == playerID && character.PlayerState == PlayerStateType.Deceased) return true; | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| game.GameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); | |||
| if (character.PlayerID == playerID && character.PlayerState == PlayerStateType.Deceased) return true; | |||
| } | |||
| return false; | |||
| } | |||
| @@ -191,19 +183,10 @@ namespace Server | |||
| public override int[] GetScore() | |||
| { | |||
| int[] score = new int[2]; // 0代表Student,1代表Tricker | |||
| game.GameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); | |||
| try | |||
| { | |||
| foreach (Character character in game.GameMap.GameObjDict[GameObjType.Character]) | |||
| { | |||
| if (!character.IsGhost()) score[0] += (int)character.Score; | |||
| else score[1] += (int)character.Score; | |||
| } | |||
| } | |||
| finally | |||
| foreach (Character character in game.GameMap.GameObjDict[GameObjType.Character]) | |||
| { | |||
| game.GameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); | |||
| if (!character.IsGhost()) score[0] += (int)character.Score; | |||
| else score[1] += (int)character.Score; | |||
| } | |||
| return score; | |||
| } | |||