| @@ -9,6 +9,7 @@ | |||
| #### 移动 | |||
| - `std::future<bool> Move(int64_t timeInMilliseconds, double angleInRadian)`:移动,`timeInMilliseconds` 为移动时间,单位毫秒;`angleInRadian` 表示移动方向,单位弧度,使用极坐标,**竖直向下方向为 x 轴,水平向右方向为 y 轴**。因为移动过程中你会受到多种干扰使得移动结果不符合你的预期;因此建议小步移动,边移动边考虑之后的行为。 | |||
| - 5ms 以内的移动指令会被禁止,你不应当使用过小的移动指令 | |||
| - `std::future<bool> MoveRight(uint32_t timeInMilliseconds)`即向右移动,`MoveLeft`、`MoveDown`、`MoveUp` 同理 | |||
| #### 使用技能 | |||
| @@ -305,6 +305,7 @@ $$ | |||
| - 不可救人 | |||
| - 无牵制得分 | |||
| - 不可使用道具(可以捡起和扔道具) | |||
| - 不沉迷,击中直接摧毁 | |||
| #### 技术宅TechOtaku | |||
| - 特性 | |||
| @@ -65,4 +65,10 @@ | |||
| # 5月21日更新 | |||
| - docs:更新了 游戏机制与平衡性调整更新(基本不变版).pdf | |||
| - Klee小炸弹的攻击范围与放射方向调整 | |||
| - Klee小炸弹的攻击范围与放射方向调整 | |||
| # 5月22日11:00更新 | |||
| - fix:修复了开校门的bug | |||
| # 5月25日更新 | |||
| - fix:修复了Semaphore设置错误的问题 | |||
| @@ -1,6 +1,7 @@ | |||
| using Preparation.Utility; | |||
| using Preparation.Interface; | |||
| using System; | |||
| using System.Threading; | |||
| namespace GameClass.GameObj | |||
| { | |||
| @@ -108,16 +109,15 @@ namespace GameClass.GameObj | |||
| private int timeOfRescue = 0; | |||
| public int TimeOfRescue | |||
| { | |||
| get => timeOfRescue; | |||
| set | |||
| { | |||
| if (value > 0) | |||
| lock (gameObjLock) | |||
| timeOfRescue = (value < GameData.basicTimeOfRescue) ? value : GameData.basicTimeOfRescue; | |||
| else | |||
| lock (gameObjLock) | |||
| timeOfRescue = 0; | |||
| } | |||
| get => Interlocked.CompareExchange(ref timeOfRescue, -1, -1); | |||
| } | |||
| public bool AddTimeOfRescue(int value) | |||
| { | |||
| return Interlocked.Add(ref timeOfRescue, value) >= GameData.basicTimeOfRescue; | |||
| } | |||
| public void SetTimeOfRescue(int value) | |||
| { | |||
| Interlocked.Exchange(ref timeOfRescue, value); | |||
| } | |||
| public Student(XY initPos, int initRadius, CharacterType characterType) : base(initPos, initRadius, characterType) | |||
| @@ -418,34 +418,64 @@ namespace GameClass.GameObj | |||
| || playerState == PlayerStateType.Null || playerState == PlayerStateType.Moving); | |||
| } | |||
| private GameObj? whatInteractingWith = null; | |||
| public GameObj? WhatInteractingWith => whatInteractingWith; | |||
| public GameObj? WhatInteractingWith | |||
| { | |||
| get | |||
| { | |||
| lock (actionLock) | |||
| { | |||
| return whatInteractingWith; | |||
| } | |||
| } | |||
| } | |||
| public bool StartThread(long stateNum, RunningStateType runningState) | |||
| { | |||
| lock (ActionLock) | |||
| { | |||
| if (this.StateNum == stateNum) | |||
| { | |||
| this.runningState = runningState; | |||
| return true; | |||
| } | |||
| } | |||
| return false; | |||
| } | |||
| private long ChangePlayerState(PlayerStateType value = PlayerStateType.Null, GameObj? gameObj = null) | |||
| private long ChangePlayerState(RunningStateType running, PlayerStateType value = PlayerStateType.Null, GameObj? gameObj = null) | |||
| { | |||
| //只能被SetPlayerState引用 | |||
| if (runningState == RunningStateType.RunningSleepily) | |||
| { | |||
| ThreadNum.Release(); | |||
| } | |||
| runningState = running; | |||
| whatInteractingWith = gameObj; | |||
| playerState = value; | |||
| //Debugger.Output(this,playerState.ToString()+" "+IsMoving.ToString()); | |||
| return ++stateNum; | |||
| } | |||
| private long ChangePlayerStateInOneThread(PlayerStateType value = PlayerStateType.Null, GameObj? gameObj = null) | |||
| private long ChangePlayerStateInOneThread(RunningStateType running, PlayerStateType value = PlayerStateType.Null, GameObj? gameObj = null) | |||
| { | |||
| if (runningState == RunningStateType.RunningSleepily) | |||
| { | |||
| ThreadNum.Release(); | |||
| } | |||
| runningState = running; | |||
| //只能被SetPlayerState引用 | |||
| whatInteractingWith = gameObj; | |||
| playerState = value; | |||
| //Debugger.Output(this,playerState.ToString()+" "+IsMoving.ToString()); | |||
| return stateNum; | |||
| } | |||
| public long SetPlayerState(PlayerStateType value = PlayerStateType.Null, IGameObj? obj = null) | |||
| public long SetPlayerState(RunningStateType runningState, PlayerStateType value = PlayerStateType.Null, IGameObj? obj = null) | |||
| { | |||
| GameObj? gameObj = (GameObj?)obj; | |||
| lock (actionLock) | |||
| { | |||
| PlayerStateType nowPlayerState = PlayerState; | |||
| if (nowPlayerState == value && value != PlayerStateType.UsingSkill) return -1; | |||
| GameObj? lastObj = whatInteractingWith; | |||
| switch (nowPlayerState) | |||
| { | |||
| case PlayerStateType.Escaped: | |||
| @@ -454,119 +484,85 @@ namespace GameClass.GameObj | |||
| case PlayerStateType.Addicted: | |||
| if (value == PlayerStateType.Rescued) | |||
| return ChangePlayerStateInOneThread(value, gameObj); | |||
| return ChangePlayerStateInOneThread(runningState, value, gameObj); | |||
| else if (value == PlayerStateType.Null || value == PlayerStateType.Deceased) | |||
| return ChangePlayerState(value, gameObj); | |||
| return ChangePlayerState(runningState, value, gameObj); | |||
| else return -1; | |||
| case PlayerStateType.Rescued: | |||
| if (value == PlayerStateType.Addicted) | |||
| return ChangePlayerStateInOneThread(value, gameObj); | |||
| return ChangePlayerStateInOneThread(runningState, value, gameObj); | |||
| else if (value == PlayerStateType.Null || value == PlayerStateType.Deceased) | |||
| return ChangePlayerState(value, gameObj); | |||
| return ChangePlayerState(runningState, value, gameObj); | |||
| else return -1; | |||
| case PlayerStateType.TryingToAttack: | |||
| if (value == PlayerStateType.Addicted || value == PlayerStateType.Swinging | |||
| || value == PlayerStateType.Deceased || value == PlayerStateType.Stunned | |||
| || value == PlayerStateType.Charmed || value == PlayerStateType.Null) | |||
| return ChangePlayerState(value, gameObj); | |||
| return ChangePlayerState(runningState, value, gameObj); | |||
| else return -1; | |||
| case PlayerStateType.Stunned: | |||
| case PlayerStateType.Charmed: | |||
| if (value == PlayerStateType.Addicted || value == PlayerStateType.Deceased | |||
| || value == PlayerStateType.Null) | |||
| return ChangePlayerState(value, gameObj); | |||
| return ChangePlayerState(runningState, value, gameObj); | |||
| else return -1; | |||
| case PlayerStateType.Swinging: | |||
| if (value == PlayerStateType.Addicted | |||
| || value == PlayerStateType.Deceased || value == PlayerStateType.Stunned | |||
| || value == PlayerStateType.Charmed || value == PlayerStateType.Null) | |||
| { | |||
| try | |||
| { | |||
| return ChangePlayerState(value, gameObj); | |||
| } | |||
| finally | |||
| { | |||
| ThreadNum.Release(); | |||
| } | |||
| } | |||
| return ChangePlayerState(runningState, value, gameObj); | |||
| else return -1; | |||
| case PlayerStateType.ClimbingThroughWindows: | |||
| if (value == PlayerStateType.Addicted | |||
| || value == PlayerStateType.Deceased || value == PlayerStateType.Stunned | |||
| || value == PlayerStateType.Charmed || value == PlayerStateType.Null) | |||
| { | |||
| Window window = (Window)WhatInteractingWith!; | |||
| try | |||
| { | |||
| window.FinishClimbing(); | |||
| return ChangePlayerState(value, gameObj); | |||
| } | |||
| finally | |||
| { | |||
| if (window.Stage.x == 0) | |||
| ThreadNum.Release(); | |||
| else ReSetPos(window.Stage); | |||
| } | |||
| Window window = (Window)lastObj!; | |||
| if (window.Stage.x != 0) ReSetPos(window.Stage); | |||
| window.FinishClimbing(); | |||
| return ChangePlayerState(runningState, value, gameObj); | |||
| } | |||
| else return -1; | |||
| case PlayerStateType.OpeningTheChest: | |||
| ((Chest)whatInteractingWith!).StopOpen(); | |||
| return ChangePlayerState(value, gameObj); | |||
| if (value == PlayerStateType.Rescued) return -1; | |||
| ((Chest)lastObj!).StopOpen(); | |||
| return ChangePlayerState(runningState, value, gameObj); | |||
| case PlayerStateType.OpeningTheDoorway: | |||
| try | |||
| { | |||
| Doorway doorway = (Doorway)whatInteractingWith!; | |||
| doorway.StopOpenning(); | |||
| return ChangePlayerState(value, gameObj); | |||
| } | |||
| finally | |||
| { | |||
| ThreadNum.Release(); | |||
| } | |||
| if (value == PlayerStateType.Rescued) return -1; | |||
| Doorway doorway = (Doorway)lastObj!; | |||
| doorway.StopOpenning(); | |||
| return ChangePlayerState(runningState, value, gameObj); | |||
| case PlayerStateType.OpeningTheDoor: | |||
| Door door = (Door)whatInteractingWith!; | |||
| try | |||
| if (value == PlayerStateType.Rescued) return -1; | |||
| Door door = (Door)lastObj!; | |||
| door.StopOpen(); | |||
| ReleaseTool(door.DoorNum switch | |||
| { | |||
| door.StopOpen(); | |||
| ReleaseTool(door.DoorNum switch | |||
| { | |||
| 3 => PropType.Key3, | |||
| 5 => PropType.Key5, | |||
| _ => PropType.Key6, | |||
| } | |||
| ); | |||
| return ChangePlayerState(value, gameObj); | |||
| } | |||
| finally | |||
| { | |||
| ThreadNum.Release(); | |||
| 3 => PropType.Key3, | |||
| 5 => PropType.Key5, | |||
| _ => PropType.Key6, | |||
| } | |||
| ); | |||
| return ChangePlayerState(runningState, value, gameObj); | |||
| case PlayerStateType.UsingSkill: | |||
| { | |||
| if (value == PlayerStateType.Rescued) return -1; | |||
| switch (CharacterType) | |||
| { | |||
| case CharacterType.TechOtaku: | |||
| { | |||
| if (typeof(CraftingBench).IsInstanceOfType(whatInteractingWith)) | |||
| if (typeof(CraftingBench).IsInstanceOfType(lastObj)) | |||
| { | |||
| try | |||
| { | |||
| ((CraftingBench)whatInteractingWith!).StopSkill(); | |||
| return ChangePlayerState(value, gameObj); | |||
| } | |||
| finally | |||
| { | |||
| ThreadNum.Release(); | |||
| } | |||
| ((CraftingBench)lastObj!).StopSkill(); | |||
| return ChangePlayerState(runningState, value, gameObj); | |||
| } | |||
| else | |||
| { | |||
| if (value != PlayerStateType.UsingSkill) | |||
| ((UseRobot)FindActiveSkill(ActiveSkillType.UseRobot)).NowPlayerID = (int)playerID; | |||
| return ChangePlayerState(value, gameObj); | |||
| return ChangePlayerState(runningState, value, gameObj); | |||
| } | |||
| } | |||
| case CharacterType.Assassin: | |||
| @@ -574,14 +570,15 @@ namespace GameClass.GameObj | |||
| else | |||
| { | |||
| TryDeleteInvisible(); | |||
| return ChangePlayerState(value, gameObj); | |||
| return ChangePlayerState(runningState, value, gameObj); | |||
| } | |||
| default: | |||
| return ChangePlayerState(value, gameObj); | |||
| return ChangePlayerState(runningState, value, gameObj); | |||
| } | |||
| } | |||
| default: | |||
| return ChangePlayerState(value, gameObj); | |||
| if (value == PlayerStateType.Rescued) return -1; | |||
| return ChangePlayerState(runningState, value, gameObj); | |||
| } | |||
| } | |||
| } | |||
| @@ -590,19 +587,33 @@ namespace GameClass.GameObj | |||
| { | |||
| lock (actionLock) | |||
| { | |||
| runningState = RunningStateType.Null; | |||
| whatInteractingWith = null; | |||
| playerState = PlayerStateType.Null; | |||
| return ++stateNum; | |||
| } | |||
| } | |||
| public bool ResetPlayerState(long state, RunningStateType running = RunningStateType.Null, PlayerStateType value = PlayerStateType.Null, IGameObj? obj = null) | |||
| { | |||
| lock (actionLock) | |||
| { | |||
| if (state != stateNum) return false; | |||
| this.runningState = running; | |||
| whatInteractingWith = (GameObj?)obj; | |||
| playerState = value; | |||
| ++stateNum; | |||
| return true; | |||
| } | |||
| } | |||
| public bool TryToRemoveFromGame(PlayerStateType playerStateType) | |||
| { | |||
| lock (actionLock) | |||
| { | |||
| if (!TryToRemove()) return false; | |||
| if (SetPlayerState(RunningStateType.RunningForcibly, playerStateType) == -1) return false; | |||
| TryToRemove(); | |||
| ReSetCanMove(false); | |||
| SetPlayerState(playerStateType); | |||
| position = GameData.PosWhoDie; | |||
| } | |||
| return true; | |||
| @@ -1,5 +1,6 @@ | |||
| using Preparation.Interface; | |||
| using Preparation.Utility; | |||
| using System; | |||
| namespace GameClass.GameObj | |||
| { | |||
| @@ -22,19 +23,20 @@ namespace GameClass.GameObj | |||
| public int OpenStartTime => openStartTime; | |||
| private Character? whoOpen = null; | |||
| public Character? WhoOpen => whoOpen; | |||
| public void Open(int startTime, Character character) | |||
| public bool Open(Character character) | |||
| { | |||
| lock (GameObjReaderWriterLock) | |||
| { | |||
| openStartTime = startTime; | |||
| if (whoOpen != null) return false; | |||
| openStartTime = Environment.TickCount; | |||
| whoOpen = character; | |||
| } | |||
| return true; | |||
| } | |||
| public void StopOpen() | |||
| { | |||
| lock (GameObjReaderWriterLock) | |||
| { | |||
| openStartTime = 0; | |||
| whoOpen = null; | |||
| } | |||
| } | |||
| @@ -70,8 +70,8 @@ namespace GameClass.GameObj | |||
| } | |||
| } | |||
| private long openStartTime = 0; | |||
| public long OpenStartTime | |||
| private int openStartTime = 0; | |||
| public int OpenStartTime | |||
| { | |||
| get | |||
| { | |||
| @@ -86,7 +86,7 @@ namespace GameClass.GameObj | |||
| { | |||
| if (isOpen) return false; | |||
| if (whoLockOrOpen != null) return false; | |||
| openStartTime = Environment.TickCount64; | |||
| openStartTime = Environment.TickCount; | |||
| whoLockOrOpen = character; | |||
| return true; | |||
| } | |||
| @@ -97,7 +97,7 @@ namespace GameClass.GameObj | |||
| { | |||
| if (whoLockOrOpen != null) | |||
| { | |||
| if ((Environment.TickCount64 - openStartTime) >= GameData.degreeOfLockingOrOpeningTheDoor / whoLockOrOpen.SpeedOfOpeningOrLocking) | |||
| if ((Environment.TickCount - openStartTime) >= GameData.degreeOfLockingOrOpeningTheDoor / whoLockOrOpen.SpeedOfOpeningOrLocking) | |||
| isOpen = true; | |||
| whoLockOrOpen = null; | |||
| } | |||
| @@ -153,9 +153,23 @@ namespace GameClass.GameObj | |||
| if (character != null) | |||
| { | |||
| lock (character.ActionLock) | |||
| { | |||
| if (character.PlayerState == PlayerStateType.OpeningTheDoor) | |||
| character.SetPlayerState(); | |||
| { | |||
| character.ReleaseTool(DoorNum switch | |||
| { | |||
| 3 => PropType.Key3, | |||
| 5 => PropType.Key5, | |||
| _ => PropType.Key6, | |||
| }); | |||
| character.SetPlayerStateNaturally(); | |||
| } | |||
| else if (character.PlayerState == PlayerStateType.LockingTheDoor) | |||
| { | |||
| character.SetPlayerStateNaturally(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -75,6 +75,7 @@ namespace GameClass.GameObj | |||
| { | |||
| if (Interlocked.Increment(ref numOfNoHpStudent) == GameData.numOfStudent) | |||
| { | |||
| AddScoreFromAddict(); | |||
| Timer.IsGaming = false; | |||
| return; | |||
| } | |||
| @@ -120,6 +121,10 @@ namespace GameClass.GameObj | |||
| GameObjLockDict[GameObjType.EmergencyExit].ExitReadLock(); | |||
| } | |||
| } | |||
| private void AddScoreFromAddict() | |||
| { | |||
| } | |||
| private Dictionary<GameObjType, IList<IGameObj>> gameObjDict; | |||
| @@ -182,6 +187,26 @@ namespace GameClass.GameObj | |||
| } | |||
| return player; | |||
| } | |||
| public Character FindGhost() | |||
| { | |||
| gameObjLockDict[GameObjType.Character].EnterReadLock(); | |||
| try | |||
| { | |||
| int i; | |||
| for (i = 0; i < (gameObjDict[GameObjType.Character]).Count - 1; ++i) | |||
| { | |||
| if (((Character)gameObjDict[GameObjType.Character][i]).IsGhost()) | |||
| { | |||
| return ((Character)gameObjDict[GameObjType.Character][i]); | |||
| } | |||
| } | |||
| return ((Character)gameObjDict[GameObjType.Character][i]); | |||
| } | |||
| finally | |||
| { | |||
| gameObjLockDict[GameObjType.Character].ExitReadLock(); | |||
| } | |||
| } | |||
| public Character? FindPlayerToAction(long playerID) | |||
| { | |||
| Character? player = null; | |||
| @@ -215,61 +240,7 @@ namespace GameClass.GameObj | |||
| } | |||
| return player; | |||
| } | |||
| public bool Remove(GameObj gameObj) | |||
| { | |||
| GameObj? ToDel = null; | |||
| GameObjLockDict[gameObj.Type].EnterWriteLock(); | |||
| try | |||
| { | |||
| 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(); | |||
| } | |||
| return ToDel != null; | |||
| } | |||
| public bool RemoveJustFromMap(GameObj gameObj) | |||
| { | |||
| GameObjLockDict[gameObj.Type].EnterWriteLock(); | |||
| try | |||
| { | |||
| if (GameObjDict[gameObj.Type].Remove(gameObj)) | |||
| { | |||
| gameObj.TryToRemove(); | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| finally | |||
| { | |||
| GameObjLockDict[gameObj.Type].ExitWriteLock(); | |||
| } | |||
| } | |||
| public void Add(GameObj gameObj) | |||
| { | |||
| GameObjLockDict[gameObj.Type].EnterWriteLock(); | |||
| try | |||
| { | |||
| GameObjDict[gameObj.Type].Add(gameObj); | |||
| } | |||
| finally | |||
| { | |||
| GameObjLockDict[gameObj.Type].ExitWriteLock(); | |||
| } | |||
| } | |||
| public GameObj? OneForInteract(XY Pos, GameObjType gameObjType) | |||
| { | |||
| GameObj? GameObjForInteract = null; | |||
| @@ -375,6 +346,7 @@ namespace GameClass.GameObj | |||
| } | |||
| return GameObjForInteract; | |||
| } | |||
| public bool CanSee(Character player, GameObj gameObj) | |||
| { | |||
| if ((gameObj.Type == GameObjType.Character) && ((Character)gameObj).HasInvisible) return false; | |||
| @@ -422,6 +394,63 @@ namespace GameClass.GameObj | |||
| } | |||
| return true; | |||
| } | |||
| public bool Remove(GameObj gameObj) | |||
| { | |||
| GameObj? ToDel = null; | |||
| GameObjLockDict[gameObj.Type].EnterWriteLock(); | |||
| try | |||
| { | |||
| 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(); | |||
| } | |||
| return ToDel != null; | |||
| } | |||
| public bool RemoveJustFromMap(GameObj gameObj) | |||
| { | |||
| GameObjLockDict[gameObj.Type].EnterWriteLock(); | |||
| try | |||
| { | |||
| if (GameObjDict[gameObj.Type].Remove(gameObj)) | |||
| { | |||
| gameObj.TryToRemove(); | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| finally | |||
| { | |||
| GameObjLockDict[gameObj.Type].ExitWriteLock(); | |||
| } | |||
| } | |||
| public void Add(GameObj gameObj) | |||
| { | |||
| GameObjLockDict[gameObj.Type].EnterWriteLock(); | |||
| try | |||
| { | |||
| GameObjDict[gameObj.Type].Add(gameObj); | |||
| } | |||
| finally | |||
| { | |||
| GameObjLockDict[gameObj.Type].ExitWriteLock(); | |||
| } | |||
| } | |||
| public Map(uint[,] mapResource) | |||
| { | |||
| gameObjDict = new Dictionary<GameObjType, IList<IGameObj>>(); | |||
| @@ -29,6 +29,20 @@ namespace GameClass.GameObj | |||
| } | |||
| } | |||
| protected RunningStateType runningState = RunningStateType.Null; | |||
| public RunningStateType RunningState | |||
| { | |||
| get | |||
| { | |||
| lock (actionLock) return runningState; | |||
| } | |||
| set | |||
| { | |||
| lock (actionLock) | |||
| runningState = value; | |||
| } | |||
| } | |||
| public override XY Position | |||
| { | |||
| get | |||
| @@ -52,13 +52,7 @@ namespace GameClass.GameObj | |||
| } | |||
| public void TryStopSkill() | |||
| { | |||
| lock (Parent!.ActionLock) | |||
| { | |||
| if (Parent!.StateNum == parentStateNum) | |||
| { | |||
| Parent!.SetPlayerState(); | |||
| } | |||
| } | |||
| Parent!.ResetPlayerState(parentStateNum); | |||
| } | |||
| public override PropType GetPropType() => PropType.CraftingBench; | |||
| } | |||
| @@ -1,9 +1,7 @@ | |||
| using System; | |||
| using System.Numerics; | |||
| using System.Threading; | |||
| using GameClass.GameObj; | |||
| using GameEngine; | |||
| using Preparation.Interface; | |||
| using Preparation.Utility; | |||
| using Timothy.FrameRateTask; | |||
| @@ -17,17 +15,19 @@ namespace Gaming | |||
| public bool MovePlayer(Character playerToMove, int moveTimeInMilliseconds, double moveDirection) | |||
| { | |||
| if (moveTimeInMilliseconds < 5) return false; | |||
| long stateNum = playerToMove.SetPlayerState(PlayerStateType.Moving); | |||
| long stateNum = playerToMove.SetPlayerState(RunningStateType.Waiting, PlayerStateType.Moving); | |||
| if (stateNum == -1) return false; | |||
| new Thread | |||
| ( | |||
| () => | |||
| { | |||
| playerToMove.ThreadNum.WaitOne(); | |||
| if (stateNum != playerToMove.StateNum) | |||
| if (!playerToMove.StartThread(stateNum, RunningStateType.RunningActively)) | |||
| { | |||
| playerToMove.ThreadNum.Release(); | |||
| else | |||
| moveEngine.MoveObj(playerToMove, moveTimeInMilliseconds, moveDirection, stateNum); | |||
| return; | |||
| } | |||
| moveEngine.MoveObj(playerToMove, moveTimeInMilliseconds, moveDirection, stateNum); | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| @@ -37,22 +37,28 @@ namespace Gaming | |||
| public bool MovePlayerWhenStunned(Character playerToMove, int moveTimeInMilliseconds, double moveDirection) | |||
| { | |||
| if (playerToMove.CharacterType == CharacterType.Robot) return false; | |||
| long stateNum = playerToMove.SetPlayerState(PlayerStateType.Charmed); | |||
| long stateNum = playerToMove.SetPlayerState(RunningStateType.Waiting, PlayerStateType.Charmed); | |||
| if (stateNum == -1) return false; | |||
| new Thread | |||
| (() => | |||
| { | |||
| playerToMove.ThreadNum.WaitOne(); | |||
| if (stateNum != playerToMove.StateNum) | |||
| if (!playerToMove.StartThread(stateNum, RunningStateType.RunningActively)) | |||
| { | |||
| playerToMove.ThreadNum.Release(); | |||
| return; | |||
| } | |||
| else | |||
| { | |||
| moveEngine.MoveObj(playerToMove, moveTimeInMilliseconds, moveDirection, playerToMove.StateNum); | |||
| Thread.Sleep(moveTimeInMilliseconds); | |||
| lock (playerToMove.ActionLock) | |||
| { | |||
| if (stateNum == playerToMove.StateNum) | |||
| playerToMove.SetPlayerStateNaturally(); | |||
| lock (playerToMove.ActionLock) | |||
| { | |||
| if (stateNum == playerToMove.StateNum) | |||
| playerToMove.SetPlayerStateNaturally(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -67,7 +73,7 @@ namespace Gaming | |||
| { | |||
| if (player.Commandable()) | |||
| { | |||
| player.SetPlayerState(); | |||
| player.SetPlayerState(RunningStateType.Null); | |||
| return true; | |||
| } | |||
| } | |||
| @@ -79,21 +85,27 @@ namespace Gaming | |||
| Generator? generatorForFix = (Generator?)gameMap.OneForInteract(player.Position, GameObjType.Generator); | |||
| if (generatorForFix == null) return false; | |||
| long stateNum = player.SetPlayerState(PlayerStateType.Fixing); | |||
| long stateNum = player.SetPlayerState(RunningStateType.Waiting, PlayerStateType.Fixing); | |||
| if (stateNum == -1) return false; | |||
| player.ThreadNum.WaitOne(); | |||
| if (generatorForFix.DegreeOfRepair == GameData.degreeOfFixedGenerator) | |||
| { | |||
| player.ThreadNum.Release(); | |||
| return false; | |||
| } | |||
| generatorForFix.AddNumOfFixing(); | |||
| new Thread | |||
| ( | |||
| () => | |||
| { | |||
| player.ThreadNum.WaitOne(); | |||
| if (generatorForFix.DegreeOfRepair == GameData.degreeOfFixedGenerator) | |||
| { | |||
| player.ThreadNum.Release(); | |||
| return; | |||
| } | |||
| if (!player.StartThread(stateNum, RunningStateType.RunningActively)) | |||
| { | |||
| player.ThreadNum.Release(); | |||
| return; | |||
| } | |||
| generatorForFix.AddNumOfFixing(); | |||
| Thread.Sleep(GameData.checkInterval); | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => stateNum == player.StateNum && gameMap.Timer.IsGaming, | |||
| @@ -106,9 +118,11 @@ namespace Gaming | |||
| lock (player.ActionLock) | |||
| { | |||
| if (stateNum == player.StateNum) | |||
| player.SetPlayerState(); | |||
| player.SetPlayerState(RunningStateType.Null); | |||
| } | |||
| return false; | |||
| } | |||
| return true; | |||
| }, | |||
| timeInterval: GameData.checkInterval, | |||
| finallyReturn: () => 0 | |||
| @@ -129,34 +143,27 @@ namespace Gaming | |||
| Doorway? doorwayToOpen = (Doorway?)gameMap.OneForInteract(player.Position, GameObjType.Doorway); | |||
| if (doorwayToOpen == null) return false; | |||
| long stateNum = player.SetPlayerState(PlayerStateType.OpeningTheDoorway, doorwayToOpen); | |||
| long stateNum = player.SetPlayerState(RunningStateType.Waiting, PlayerStateType.OpeningTheDoorway, doorwayToOpen); | |||
| if (stateNum == -1) return false; | |||
| new Thread | |||
| ( | |||
| () => | |||
| { | |||
| player.ThreadNum.WaitOne(); | |||
| lock (player.ActionLock) | |||
| if (!player.StartThread(stateNum, RunningStateType.RunningSleepily)) | |||
| { | |||
| if (stateNum != player.StateNum) | |||
| { | |||
| player.ThreadNum.Release(); | |||
| return; | |||
| } | |||
| player.ThreadNum.Release(); | |||
| return; | |||
| } | |||
| doorwayToOpen.TryToOpen(); | |||
| Thread.Sleep(GameData.degreeOfOpenedDoorway - doorwayToOpen.OpenDegree); | |||
| lock (player.ActionLock) | |||
| if (player.ResetPlayerState(stateNum)) | |||
| { | |||
| if (stateNum == player.StateNum) | |||
| { | |||
| player.SetPlayerStateNaturally(); | |||
| doorwayToOpen.FinishOpenning(); | |||
| player.ThreadNum.Release(); | |||
| } | |||
| doorwayToOpen.FinishOpenning(); | |||
| player.ThreadNum.Release(); | |||
| } | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| @@ -165,14 +172,15 @@ namespace Gaming | |||
| public bool Escape(Student player) | |||
| { | |||
| if (!(player.Commandable()) || player.CharacterType == CharacterType.Robot || player.CharacterType == CharacterType.Teacher) | |||
| if (player.CharacterType == CharacterType.Robot || player.CharacterType == CharacterType.Teacher) | |||
| return false; | |||
| Doorway? doorwayForEscape = (Doorway?)gameMap.OneForInteract(player.Position, GameObjType.Doorway); | |||
| if (doorwayForEscape != null && doorwayForEscape.IsOpen()) | |||
| { | |||
| if (!player.TryToRemoveFromGame(PlayerStateType.Escaped)) return false; | |||
| player.AddScore(GameData.StudentScoreEscape); | |||
| gameMap.MapEscapeStudent(); | |||
| player.TryToRemoveFromGame(PlayerStateType.Escaped); | |||
| return true; | |||
| } | |||
| else | |||
| @@ -180,9 +188,9 @@ namespace Gaming | |||
| EmergencyExit? emergencyExit = (EmergencyExit?)gameMap.OneForInteract(player.Position, GameObjType.EmergencyExit); | |||
| if (emergencyExit != null && emergencyExit.IsOpen) | |||
| { | |||
| if (!player.TryToRemoveFromGame(PlayerStateType.Escaped)) return false; | |||
| player.AddScore(GameData.StudentScoreEscape); | |||
| gameMap.MapEscapeStudent(); | |||
| player.TryToRemoveFromGame(PlayerStateType.Escaped); | |||
| return true; | |||
| } | |||
| return false; | |||
| @@ -197,38 +205,88 @@ namespace Gaming | |||
| playerTreated = gameMap.StudentForInteract(player.Position); | |||
| if (playerTreated == null) return false; | |||
| } | |||
| if (player == playerTreated || (!player.Commandable()) || playerTreated.PlayerState == PlayerStateType.Treated || | |||
| (!playerTreated.Commandable()) || | |||
| playerTreated.HP == playerTreated.MaxHp || !GameData.ApproachToInteract(playerTreated.Position, player.Position)) | |||
| else if (!GameData.ApproachToInteract(playerTreated.Position, player.Position)) return false; | |||
| if (playerTreated.HP == playerTreated.MaxHp) return false; | |||
| long stateNumTreated = playerTreated.SetPlayerState(RunningStateType.Waiting, PlayerStateType.Treated); | |||
| if (stateNumTreated == -1) return false; | |||
| long stateNum = player.SetPlayerState(RunningStateType.Waiting, PlayerStateType.Treating); | |||
| if (stateNum == -1) | |||
| { | |||
| lock (playerTreated.ActionLock) | |||
| { | |||
| if (playerTreated.StateNum == stateNumTreated) | |||
| player.SetPlayerStateNaturally(); | |||
| } | |||
| return false; | |||
| } | |||
| new Thread | |||
| ( | |||
| () => | |||
| { | |||
| playerTreated.SetPlayerState(PlayerStateType.Treated); | |||
| player.SetPlayerState(PlayerStateType.Treating); | |||
| long threadNum = player.StateNum; | |||
| player.ThreadNum.WaitOne(); | |||
| if (!player.StartThread(stateNum, RunningStateType.RunningActively)) | |||
| { | |||
| player.ThreadNum.Release(); | |||
| lock (playerTreated.ActionLock) | |||
| { | |||
| if (playerTreated.StateNum == stateNumTreated) | |||
| playerTreated.SetPlayerStateNaturally(); | |||
| } | |||
| return; | |||
| } | |||
| playerTreated.ThreadNum.WaitOne(); | |||
| if (!playerTreated.StartThread(stateNum, RunningStateType.RunningActively)) | |||
| { | |||
| playerTreated.ThreadNum.Release(); | |||
| lock (player.ActionLock) | |||
| { | |||
| if (player.StateNum == stateNum) | |||
| player.SetPlayerStateNaturally(); | |||
| } | |||
| player.ThreadNum.Release(); | |||
| return; | |||
| } | |||
| Thread.Sleep(GameData.checkInterval); | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => playerTreated.PlayerState == PlayerStateType.Treated && threadNum == player.StateNum && gameMap.Timer.IsGaming, | |||
| loopCondition: () => stateNum == player.StateNum && gameMap.Timer.IsGaming, | |||
| loopToDo: () => | |||
| { | |||
| if (playerTreated.AddDegreeOfTreatment(GameData.frameDuration * player.TreatSpeed, player)) | |||
| playerTreated.SetPlayerState();// | |||
| lock (playerTreated.ActionLock) | |||
| { | |||
| if (playerTreated.StateNum == stateNumTreated) | |||
| { | |||
| if (playerTreated.AddDegreeOfTreatment(GameData.checkInterval * player.TreatSpeed, player)) | |||
| { | |||
| playerTreated.SetPlayerStateNaturally(); | |||
| return false; | |||
| } | |||
| } | |||
| else return false; | |||
| } | |||
| return true; | |||
| }, | |||
| timeInterval: GameData.frameDuration, | |||
| timeInterval: GameData.checkInterval, | |||
| finallyReturn: () => 0 | |||
| ) | |||
| .Start(); | |||
| player.ThreadNum.Release(); | |||
| playerTreated.ThreadNum.Release(); | |||
| if (player.ResetPlayerState(stateNum)) | |||
| return; | |||
| if (threadNum == player.StateNum) player.SetPlayerState(); | |||
| else if (playerTreated.PlayerState == PlayerStateType.Treated) playerTreated.SetPlayerState(); | |||
| playerTreated.ResetPlayerState(stateNumTreated); | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| return true; | |||
| } | |||
| public bool Rescue(Student player, Student? playerRescued = null) | |||
| { | |||
| if (player.CharacterType == CharacterType.Robot) return false; | |||
| @@ -238,69 +296,114 @@ namespace Gaming | |||
| playerRescued = gameMap.StudentForInteract(player.Position); | |||
| if (playerRescued == null) return false; | |||
| } | |||
| // else//no need | |||
| // if (!GameData.ApproachToInteract(playerRescued.Position, player.Position)) return false; | |||
| long stateNumRescued = playerRescued.SetPlayerState(RunningStateType.Waiting, PlayerStateType.Rescued); | |||
| if (stateNumRescued == -1) return false; | |||
| if ((!player.Commandable()) || playerRescued.PlayerState != PlayerStateType.Addicted || !GameData.ApproachToInteract(playerRescued.Position, player.Position)) | |||
| long stateNum = player.SetPlayerState(RunningStateType.Waiting, PlayerStateType.Rescuing); | |||
| if (stateNum == -1) | |||
| { | |||
| playerRescued.ResetPlayerState(stateNumRescued, RunningStateType.RunningForcibly, PlayerStateType.Addicted); | |||
| return false; | |||
| player.SetPlayerState(PlayerStateType.Rescuing); | |||
| playerRescued.SetPlayerState(PlayerStateType.Rescued); | |||
| long threadNum = player.StateNum; | |||
| } | |||
| new Thread | |||
| ( | |||
| () => | |||
| { | |||
| player.ThreadNum.WaitOne(); | |||
| if (!player.StartThread(stateNum, RunningStateType.RunningSleepily)) | |||
| { | |||
| player.ThreadNum.Release(); | |||
| playerRescued.ResetPlayerState(stateNumRescued, RunningStateType.RunningForcibly, PlayerStateType.Addicted); | |||
| return; | |||
| } | |||
| playerRescued.ThreadNum.WaitOne(); | |||
| if (!GameData.ApproachToInteract(playerRescued.Position, player.Position)) return; | |||
| if (!playerRescued.StartThread(stateNumRescued, RunningStateType.RunningSleepily)) | |||
| { | |||
| playerRescued.ThreadNum.Release(); | |||
| if (!player.ResetPlayerState(stateNum)) | |||
| player.ThreadNum.Release(); | |||
| return; | |||
| } | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => playerRescued.PlayerState == PlayerStateType.Rescued && threadNum == player.StateNum && gameMap.Timer.IsGaming, | |||
| loopCondition: () => stateNum == player.StateNum && gameMap.Timer.IsGaming, | |||
| loopToDo: () => | |||
| { | |||
| playerRescued.TimeOfRescue += GameData.frameDuration; | |||
| lock (playerRescued.ActionLock) | |||
| { | |||
| if (playerRescued.StateNum == stateNumRescued) | |||
| { | |||
| if (playerRescued.AddTimeOfRescue(GameData.checkInterval)) | |||
| { | |||
| playerRescued.SetPlayerStateNaturally(); | |||
| playerRescued.HP = playerRescued.MaxHp / 2; | |||
| player.AddScore(GameData.StudentScoreRescue); | |||
| return false; | |||
| } | |||
| } | |||
| else return false; | |||
| } | |||
| return true; | |||
| }, | |||
| timeInterval: GameData.frameDuration, | |||
| finallyReturn: () => 0, | |||
| maxTotalDuration: GameData.basicTimeOfRescue | |||
| timeInterval: GameData.checkInterval, | |||
| finallyReturn: () => 0 | |||
| ) | |||
| .Start(); | |||
| playerRescued.SetTimeOfRescue(0); | |||
| if (playerRescued.PlayerState == PlayerStateType.Rescued) | |||
| { | |||
| if (playerRescued.TimeOfRescue >= GameData.basicTimeOfRescue) | |||
| { | |||
| playerRescued.SetPlayerState(); | |||
| playerRescued.HP = playerRescued.MaxHp / 2; | |||
| player.AddScore(GameData.StudentScoreRescue); | |||
| } | |||
| else | |||
| playerRescued.SetPlayerState(PlayerStateType.Addicted); | |||
| } | |||
| if (threadNum == player.StateNum) player.SetPlayerState(); | |||
| playerRescued.TimeOfRescue = 0; | |||
| player.ThreadNum.Release(); | |||
| playerRescued.ThreadNum.Release(); | |||
| if (player.ResetPlayerState(stateNum)) return; | |||
| playerRescued.ResetPlayerState(stateNumRescued, RunningStateType.RunningForcibly, PlayerStateType.Addicted); | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| return true; | |||
| } | |||
| public bool OpenChest(Character player) | |||
| { | |||
| if ((!player.Commandable()) || player.PlayerState == PlayerStateType.OpeningTheChest) | |||
| return false; | |||
| Chest? chestToOpen = (Chest?)gameMap.OneForInteract(player.Position, GameObjType.Chest); | |||
| if (chestToOpen == null) return false; | |||
| if (chestToOpen == null || chestToOpen.OpenStartTime > 0) | |||
| return false; | |||
| long stateNum = player.SetPlayerState(RunningStateType.Waiting, PlayerStateType.OpeningTheChest, chestToOpen); | |||
| if (stateNum == -1) return false; | |||
| player.SetPlayerState(PlayerStateType.OpeningTheChest, chestToOpen); | |||
| int startTime = gameMap.Timer.nowTime(); | |||
| chestToOpen.Open(startTime, player); | |||
| new Thread | |||
| ( | |||
| () => | |||
| { | |||
| player.ThreadNum.WaitOne(); | |||
| lock (player.ActionLock) | |||
| { | |||
| if (!player.StartThread(stateNum, RunningStateType.RunningSleepily)) | |||
| { | |||
| player.ThreadNum.Release(); | |||
| return; | |||
| } | |||
| else | |||
| if (!chestToOpen.Open(player)) | |||
| { | |||
| player.ThreadNum.Release(); | |||
| player.SetPlayerStateNaturally(); | |||
| return; | |||
| } | |||
| } | |||
| Thread.Sleep(GameData.degreeOfOpenedChest / player.SpeedOfOpenChest); | |||
| if (chestToOpen.OpenStartTime == startTime) | |||
| if (player.ResetPlayerState(stateNum)) | |||
| { | |||
| player.SetPlayerStateNaturally(); | |||
| player.ThreadNum.Release(); | |||
| for (int i = 0; i < GameData.maxNumOfPropInChest; ++i) | |||
| { | |||
| Gadget prop = chestToOpen.PropInChest[i]; | |||
| @@ -316,12 +419,13 @@ namespace Gaming | |||
| return true; | |||
| } | |||
| public bool ClimbingThroughWindow(Character player) | |||
| { | |||
| Window? windowForClimb = (Window?)gameMap.OneForInteractInACross(player.Position, GameObjType.Window); | |||
| if (windowForClimb == null) return false; | |||
| long stateNum = player.SetPlayerState(PlayerStateType.ClimbingThroughWindows, windowForClimb); | |||
| long stateNum = player.SetPlayerState(RunningStateType.Waiting, PlayerStateType.ClimbingThroughWindows, windowForClimb); | |||
| if (stateNum == -1) return false; | |||
| XY windowToPlayer = new( | |||
| @@ -344,43 +448,43 @@ namespace Gaming | |||
| () => | |||
| { | |||
| player.ThreadNum.WaitOne(); | |||
| if (stateNum != player.StateNum) | |||
| { | |||
| player.ThreadNum.Release(); | |||
| } | |||
| else | |||
| lock (player.ActionLock) | |||
| { | |||
| if (!windowForClimb.TryToClimb(player)) | |||
| if (!player.StartThread(stateNum, RunningStateType.RunningSleepily)) | |||
| { | |||
| player.ThreadNum.Release(); | |||
| player.SetPlayerStateNaturally(); | |||
| return; | |||
| } | |||
| else | |||
| if (!windowForClimb.TryToClimb(player)) | |||
| { | |||
| Thread.Sleep((int)((windowToPlayer + windowForClimb.Position - player.Position).Length() * 1000 / player.MoveSpeed)); | |||
| player.SetPlayerStateNaturally(); | |||
| player.ThreadNum.Release(); | |||
| return; | |||
| } | |||
| } | |||
| lock (player.ActionLock) | |||
| { | |||
| if (player.StateNum != stateNum) return; | |||
| player.ReSetPos(windowToPlayer + windowForClimb.Position); | |||
| windowForClimb.Enter2Stage(windowForClimb.Position - 2 * windowToPlayer); | |||
| } | |||
| Thread.Sleep((int)((windowToPlayer + windowForClimb.Position - player.Position).Length() * 1000 / player.MoveSpeed)); | |||
| lock (player.ActionLock) | |||
| { | |||
| if (!player.StartThread(stateNum, RunningStateType.RunningActively)) return; | |||
| player.ReSetPos(windowToPlayer + windowForClimb.Position); | |||
| windowForClimb.Enter2Stage(windowForClimb.Position - 2 * windowToPlayer); | |||
| } | |||
| player.MoveSpeed = player.SpeedOfClimbingThroughWindows; | |||
| moveEngine.MoveObj(player, (int)(GameData.numOfPosGridPerCell * 3 * 1000 / player.MoveSpeed / 2), (-1 * windowToPlayer).Angle(), stateNum); | |||
| player.MoveSpeed = player.SpeedOfClimbingThroughWindows; | |||
| moveEngine.MoveObj(player, (int)(GameData.numOfPosGridPerCell * 3 * 1000 / player.MoveSpeed / 2), (-1 * windowToPlayer).Angle(), stateNum); | |||
| Thread.Sleep((int)(GameData.numOfPosGridPerCell * 3 * 1000 / player.MoveSpeed / 2)); | |||
| Thread.Sleep((int)(GameData.numOfPosGridPerCell * 3 * 1000 / player.MoveSpeed / 2)); | |||
| player.MoveSpeed = player.ReCalculateBuff(BuffType.AddSpeed, player.OrgMoveSpeed, GameData.MaxSpeed, GameData.MinSpeed); | |||
| player.MoveSpeed = player.ReCalculateBuff(BuffType.AddSpeed, player.OrgMoveSpeed, GameData.MaxSpeed, GameData.MinSpeed); | |||
| lock (player.ActionLock) | |||
| { | |||
| if (stateNum == player.StateNum) | |||
| { | |||
| player.SetPlayerState(); | |||
| windowForClimb.FinishClimbing(); | |||
| } | |||
| } | |||
| lock (player.ActionLock) | |||
| { | |||
| if (stateNum == player.StateNum) | |||
| { | |||
| player.SetPlayerStateNaturally(); | |||
| windowForClimb.FinishClimbing(); | |||
| } | |||
| } | |||
| } | |||
| @@ -389,6 +493,7 @@ namespace Gaming | |||
| return true; | |||
| } | |||
| public bool LockDoor(Character player) | |||
| { | |||
| if (player.CharacterType == CharacterType.Robot) return false; | |||
| @@ -404,7 +509,7 @@ namespace Gaming | |||
| if (!player.UseTool(propType)) return false; | |||
| long stateNum = player.SetPlayerState(PlayerStateType.LockingTheDoor, doorToLock); | |||
| long stateNum = player.SetPlayerState(RunningStateType.Waiting, PlayerStateType.LockingTheDoor, doorToLock); | |||
| if (stateNum == -1) | |||
| { | |||
| player.ReleaseTool(propType); | |||
| @@ -416,47 +521,37 @@ namespace Gaming | |||
| () => | |||
| { | |||
| player.ThreadNum.WaitOne(); | |||
| if (stateNum != player.StateNum) | |||
| if (!player.StartThread(stateNum, RunningStateType.RunningActively)) | |||
| { | |||
| player.ReleaseTool(propType); | |||
| player.ThreadNum.Release(); | |||
| return; | |||
| } | |||
| else | |||
| if (!doorToLock.TryLock(player)) | |||
| { | |||
| if (!doorToLock.TryLock(player)) | |||
| { | |||
| player.ReleaseTool(propType); | |||
| lock (player.ActionLock) | |||
| { | |||
| if (stateNum == player.StateNum) player.SetPlayerState(); | |||
| } | |||
| player.ThreadNum.Release(); | |||
| } | |||
| else | |||
| { | |||
| Thread.Sleep(GameData.checkInterval); | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => stateNum == player.StateNum && gameMap.Timer.IsGaming && doorToLock.LockDegree < GameData.degreeOfLockingOrOpeningTheDoor, | |||
| loopToDo: () => | |||
| { | |||
| if ((gameMap.PartInTheSameCell(doorToLock.Position, GameObjType.Character)) != null) | |||
| return false; | |||
| doorToLock.LockDegree += GameData.checkInterval * player.SpeedOfOpeningOrLocking; | |||
| return true; | |||
| }, | |||
| timeInterval: GameData.checkInterval, | |||
| finallyReturn: () => 0 | |||
| ) | |||
| .Start(); | |||
| doorToLock.StopLock(); | |||
| player.ReleaseTool(propType); | |||
| lock (player.ActionLock) | |||
| { | |||
| if (stateNum == player.StateNum) player.SetPlayerStateNaturally(); | |||
| } | |||
| player.ThreadNum.Release(); | |||
| } | |||
| player.ReleaseTool(propType); | |||
| player.ResetPlayerState(stateNum); | |||
| player.ThreadNum.Release(); | |||
| return; | |||
| } | |||
| Thread.Sleep(GameData.checkInterval); | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => stateNum == player.StateNum && gameMap.Timer.IsGaming && doorToLock.LockDegree < GameData.degreeOfLockingOrOpeningTheDoor, | |||
| loopToDo: () => | |||
| { | |||
| if ((gameMap.PartInTheSameCell(doorToLock.Position, GameObjType.Character)) != null) | |||
| return false; | |||
| doorToLock.LockDegree += GameData.checkInterval * player.SpeedOfOpeningOrLocking; | |||
| return true; | |||
| }, | |||
| timeInterval: GameData.checkInterval, | |||
| finallyReturn: () => 0 | |||
| ) | |||
| .Start(); | |||
| doorToLock.StopLock(); | |||
| player.ReleaseTool(propType); | |||
| player.ThreadNum.Release(); | |||
| player.ResetPlayerState(stateNum); | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| @@ -479,7 +574,7 @@ namespace Gaming | |||
| if (!player.UseTool(propType)) return false; | |||
| long stateNum = player.SetPlayerState(PlayerStateType.OpeningTheDoor, doorToLock); | |||
| long stateNum = player.SetPlayerState(RunningStateType.Waiting, PlayerStateType.OpeningTheDoor, doorToLock); | |||
| if (stateNum == -1) | |||
| { | |||
| player.ReleaseTool(propType); | |||
| @@ -491,42 +586,29 @@ namespace Gaming | |||
| () => | |||
| { | |||
| player.ThreadNum.WaitOne(); | |||
| if (stateNum != player.StateNum) | |||
| if (!player.StartThread(stateNum, RunningStateType.RunningSleepily)) | |||
| { | |||
| player.ReleaseTool(propType); | |||
| player.ThreadNum.Release(); | |||
| return; | |||
| } | |||
| else | |||
| if (!doorToLock.TryOpen(player)) | |||
| { | |||
| if (!doorToLock.TryOpen(player)) | |||
| { | |||
| player.ReleaseTool(propType); | |||
| lock (player.ActionLock) | |||
| { | |||
| if (stateNum == player.StateNum) | |||
| { | |||
| player.SetPlayerStateNaturally(); | |||
| player.ThreadNum.Release(); | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| Thread.Sleep(GameData.degreeOfLockingOrOpeningTheDoor / player.SpeedOfOpeningOrLocking); | |||
| player.ReleaseTool(propType); | |||
| if (player.ResetPlayerState(stateNum)) | |||
| player.ThreadNum.Release(); | |||
| return; | |||
| } | |||
| Thread.Sleep(GameData.degreeOfLockingOrOpeningTheDoor / player.SpeedOfOpeningOrLocking); | |||
| lock (player.ActionLock) | |||
| { | |||
| if (stateNum == player.StateNum) | |||
| { | |||
| player.SetPlayerStateNaturally(); | |||
| doorToLock.StopOpen(); | |||
| player.ReleaseTool(propType); | |||
| player.ThreadNum.Release(); | |||
| } | |||
| } | |||
| } | |||
| if (player.ResetPlayerState(stateNum)) | |||
| { | |||
| doorToLock.StopOpen(); | |||
| player.ReleaseTool(propType); | |||
| player.ThreadNum.Release(); | |||
| } | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| @@ -30,7 +30,7 @@ namespace Gaming | |||
| }, | |||
| EndMove: obj => | |||
| { | |||
| Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64); | |||
| Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount); | |||
| if (obj.CanMove && ((Bullet)obj).TypeOfBullet != BulletType.JumpyDumpty) | |||
| BulletBomb((Bullet)obj, null); | |||
| obj.ReSetCanMove(false); | |||
| @@ -201,6 +201,8 @@ namespace Gaming | |||
| public bool Attack(Character player, double angle) | |||
| { // 子弹如果没有和其他物体碰撞,将会一直向前直到超出人物的attackRange | |||
| if (!player.Commandable()) return false; | |||
| Bullet? bullet = player.Attack(angle, gameMap.Timer.nowTime()); | |||
| if (bullet != null) | |||
| @@ -212,14 +214,25 @@ namespace Gaming | |||
| if (bullet.CastTime > 0) | |||
| { | |||
| player.SetPlayerState(PlayerStateType.TryingToAttack); | |||
| long threadNum = player.StateNum; | |||
| long stateNum = player.SetPlayerState(RunningStateType.Waiting, PlayerStateType.TryingToAttack); | |||
| if (stateNum == -1) | |||
| { | |||
| TryRemoveBullet(bullet); | |||
| return false; | |||
| } | |||
| new Thread | |||
| (() => | |||
| { | |||
| player.ThreadNum.WaitOne(); | |||
| if (!player.StartThread(stateNum, RunningStateType.RunningActively)) | |||
| { | |||
| TryRemoveBullet(bullet); | |||
| player.ThreadNum.Release(); | |||
| return; | |||
| } | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => threadNum == player.StateNum && gameMap.Timer.IsGaming, | |||
| loopCondition: () => stateNum == player.StateNum && gameMap.Timer.IsGaming, | |||
| loopToDo: () => | |||
| { | |||
| }, | |||
| @@ -229,13 +242,11 @@ namespace Gaming | |||
| ) | |||
| .Start(); | |||
| player.ThreadNum.Release(); | |||
| if (gameMap.Timer.IsGaming) | |||
| { | |||
| if (threadNum == player.StateNum) | |||
| { | |||
| player.SetPlayerState(); | |||
| } | |||
| else TryRemoveBullet(bullet); | |||
| if (!player.ResetPlayerState(stateNum)) | |||
| TryRemoveBullet(bullet); | |||
| } | |||
| } | |||
| ) | |||
| @@ -218,11 +218,8 @@ namespace Gaming | |||
| public void BeAddictedToGame(Student player, Ghost ghost) | |||
| { | |||
| long stateNum = player.SetPlayerState(PlayerStateType.Addicted); | |||
| if (stateNum == -1) | |||
| { | |||
| return; | |||
| } | |||
| long stateNum = player.SetPlayerState(RunningStateType.Waiting, PlayerStateType.Addicted); | |||
| if (stateNum == -1) return; | |||
| if (player.CharacterType == CharacterType.Robot) | |||
| { | |||
| @@ -278,19 +275,18 @@ namespace Gaming | |||
| public static long BeStunned(Character player, int time) | |||
| { | |||
| if (player.CharacterType == CharacterType.Robot) return -1; | |||
| long threadNum = player.SetPlayerState(PlayerStateType.Stunned); | |||
| if (threadNum == -1) return -1; | |||
| long stateNum = player.SetPlayerState(RunningStateType.RunningForcibly, PlayerStateType.Stunned); | |||
| if (stateNum == -1) return -1; | |||
| new Thread | |||
| (() => | |||
| { | |||
| Debugger.Output(player, " is stunned for " + time.ToString()); | |||
| Thread.Sleep(time); | |||
| if (threadNum == player.StateNum) | |||
| player.SetPlayerState(); | |||
| player.ResetPlayerState(stateNum); | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| return threadNum; | |||
| return stateNum; | |||
| } | |||
| public bool TryBeAwed(Student character, Bullet bullet) | |||
| @@ -378,23 +374,14 @@ namespace Gaming | |||
| public bool BackSwing(Character player, int time) | |||
| { | |||
| if (time <= 0) return false; | |||
| long stateNum = player.SetPlayerState(PlayerStateType.Swinging); | |||
| long stateNum = player.SetPlayerState(RunningStateType.RunningForcibly, PlayerStateType.Swinging); | |||
| if (stateNum == -1) return false; | |||
| new Thread | |||
| (() => | |||
| { | |||
| player.ThreadNum.WaitOne(); | |||
| Thread.Sleep(time); | |||
| lock (player.ActionLock) | |||
| { | |||
| if (stateNum == player.StateNum) | |||
| { | |||
| player.ThreadNum.Release(); | |||
| player.SetPlayerStateNaturally(); | |||
| } | |||
| } | |||
| player.ResetPlayerState(stateNum); | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| @@ -428,7 +415,7 @@ namespace Gaming | |||
| lock (parent.ActionLock) | |||
| { | |||
| if (parent.PlayerState == PlayerStateType.UsingSkill) | |||
| parent.SetPlayerState(); | |||
| parent.SetPlayerStateNaturally(); | |||
| } | |||
| } | |||
| } | |||
| @@ -225,7 +225,7 @@ namespace Gaming | |||
| if (!gameMap.Timer.IsGaming) | |||
| return false; | |||
| Character? player = gameMap.FindPlayerToAction(playerID); | |||
| if (player != null && player.Commandable()) | |||
| if (player != null) | |||
| { | |||
| return attackManager.Attack(player, angle); | |||
| } | |||
| @@ -93,7 +93,7 @@ namespace Gaming | |||
| public static bool BecomeInvisible(Character player) | |||
| { | |||
| ActiveSkill activeSkill = player.FindActiveSkill(ActiveSkillType.BecomeInvisible); | |||
| long stateNum = player.SetPlayerState(PlayerStateType.UsingSkill); | |||
| long stateNum = player.SetPlayerState(RunningStateType.RunningForcibly, PlayerStateType.UsingSkill); | |||
| if (stateNum == -1) | |||
| { | |||
| return false; | |||
| @@ -106,15 +106,9 @@ namespace Gaming | |||
| }, | |||
| () => | |||
| { | |||
| lock (player.ActionLock) | |||
| { | |||
| if (stateNum == player.StateNum) | |||
| { | |||
| player.SetPlayerStateNaturally(); | |||
| } | |||
| } | |||
| player.ResetPlayerState(stateNum); | |||
| } | |||
| ); | |||
| ); | |||
| } | |||
| public static bool UseRobot(Character player, int robotID) | |||
| @@ -141,7 +135,7 @@ namespace Gaming | |||
| activeSkill.NowPlayerID = robotID; | |||
| } | |||
| else return false; | |||
| long stateNum = player.SetPlayerState(PlayerStateType.UsingSkill); | |||
| long stateNum = player.SetPlayerState(RunningStateType.RunningForcibly, PlayerStateType.UsingSkill); | |||
| if (stateNum == -1) | |||
| { | |||
| activeSkill.NowPlayerID = (int)player.PlayerID; | |||
| @@ -250,48 +244,48 @@ namespace Gaming | |||
| { | |||
| CraftingBench craftingBench = new(res, player, num); | |||
| long stateNum = player.SetPlayerState(PlayerStateType.UsingSkill, craftingBench); | |||
| long stateNum = player.SetPlayerState(RunningStateType.Waiting, PlayerStateType.UsingSkill, craftingBench); | |||
| if (stateNum == -1) | |||
| { | |||
| ((SummonGolem)activeSkill).DeleteGolem(num); | |||
| return false; | |||
| } | |||
| player.ThreadNum.WaitOne(); | |||
| if (stateNum != player.StateNum) | |||
| { | |||
| ((SummonGolem)activeSkill).DeleteGolem(num); | |||
| player.ThreadNum.Release(); | |||
| return false; | |||
| } | |||
| if (actionManager.moveEngine.CheckCollision(craftingBench, res) != null) | |||
| { | |||
| ((SummonGolem)activeSkill).DeleteGolem(num); | |||
| player.ThreadNum.Release(); | |||
| return false; | |||
| } | |||
| craftingBench.ParentStateNum = stateNum; | |||
| gameMap.Add(craftingBench); | |||
| return ActiveSkillEffect(activeSkill, player, () => | |||
| { | |||
| player.ThreadNum.WaitOne(); | |||
| if (!player.StartThread(stateNum, RunningStateType.RunningSleepily)) | |||
| { | |||
| ((SummonGolem)activeSkill).DeleteGolem(num); | |||
| player.ThreadNum.Release(); | |||
| } | |||
| else | |||
| { | |||
| if (actionManager.moveEngine.CheckCollision(craftingBench, res) != null) | |||
| { | |||
| ((SummonGolem)activeSkill).DeleteGolem(num); | |||
| if (player.ResetPlayerState(stateNum)) | |||
| player.ThreadNum.Release(); | |||
| } | |||
| else | |||
| { | |||
| craftingBench.ParentStateNum = stateNum; | |||
| gameMap.Add(craftingBench); | |||
| } | |||
| } | |||
| }, | |||
| () => | |||
| { | |||
| lock (player.ActionLock) | |||
| if (player.ResetPlayerState(stateNum)) | |||
| { | |||
| if (stateNum == player.StateNum) | |||
| gameMap.RemoveJustFromMap(craftingBench); | |||
| Golem? golem = (Golem?)characterManager.AddPlayer(res, player.TeamID, (num + 1) * GameData.numOfPeople + player.PlayerID, CharacterType.Robot, player); | |||
| if (golem == null) | |||
| { | |||
| gameMap.RemoveJustFromMap(craftingBench); | |||
| Golem? golem = (Golem?)characterManager.AddPlayer(res, player.TeamID, (num + 1) * GameData.numOfPeople + player.PlayerID, CharacterType.Robot, player); | |||
| if (golem == null) | |||
| { | |||
| ((SummonGolem)activeSkill).AddGolem(num); | |||
| } | |||
| player.SetPlayerStateNaturally(); | |||
| player.ThreadNum.Release(); | |||
| ((SummonGolem)activeSkill).AddGolem(num); | |||
| } | |||
| player.ThreadNum.Release(); | |||
| } | |||
| } | |||
| ); | |||
| @@ -373,34 +367,36 @@ namespace Gaming | |||
| public bool HaveTea(Character player, int angle1000) | |||
| { | |||
| long stateNum = player.SetPlayerState(PlayerStateType.UsingSkill); | |||
| long stateNum = player.SetPlayerState(RunningStateType.Waiting, PlayerStateType.UsingSkill); | |||
| if (stateNum == -1) | |||
| { | |||
| return false; | |||
| } | |||
| player.ThreadNum.WaitOne(); | |||
| XY res = player.Position + new XY(angle1000 / 1000.0, GameData.distanceOfHaveTea); | |||
| Debugger.Output(res.ToString()); | |||
| if (actionManager.moveEngine.CheckCollision(player, res) != null) | |||
| { | |||
| player.ThreadNum.Release(); | |||
| return false; | |||
| } | |||
| Debugger.Output("NO Collision!"); | |||
| player.ReSetPos(res); | |||
| lock (player.ActionLock) | |||
| return ActiveSkillEffect(player.FindActiveSkill(ActiveSkillType.HaveTea), player, () => | |||
| { | |||
| if (player.StateNum == stateNum) | |||
| player.ThreadNum.WaitOne(); | |||
| XY res = player.Position + new XY(angle1000 / 1000.0, GameData.distanceOfHaveTea); | |||
| if (!player.StartThread(stateNum, RunningStateType.RunningActively)) | |||
| { | |||
| player.SetPlayerStateNaturally(); | |||
| player.ThreadNum.Release(); | |||
| } | |||
| else | |||
| { | |||
| if (actionManager.moveEngine.CheckCollision(player, res) != null) | |||
| { | |||
| player.ThreadNum.Release(); | |||
| } | |||
| else | |||
| { | |||
| Debugger.Output("NO Collision!"); | |||
| player.ReSetPos(res); | |||
| player.ThreadNum.Release(); | |||
| player.ResetPlayerState(stateNum); | |||
| Debugger.Output(player, "have tea!"); | |||
| } | |||
| } | |||
| } | |||
| player.ThreadNum.Release(); | |||
| return ActiveSkillEffect(player.FindActiveSkill(ActiveSkillType.HaveTea), player, () => | |||
| { | |||
| Debugger.Output(player, "have tea!"); | |||
| }, | |||
| () => | |||
| { }); | |||
| @@ -416,13 +412,16 @@ namespace Gaming | |||
| { | |||
| foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) | |||
| { | |||
| if ((character.PlayerState == PlayerStateType.Addicted) && gameMap.CanSee(player, character)) | |||
| lock (character.ActionLock) | |||
| { | |||
| character.SetPlayerState(); | |||
| character.HP = GameData.RemainHpWhenAddLife; | |||
| ((Student)character).TimeOfRescue = 0; | |||
| player.AddScore(GameData.StudentScoreRescue); | |||
| break; | |||
| if ((character.PlayerState == PlayerStateType.Addicted) && gameMap.CanSee(player, character)) | |||
| { | |||
| character.SetPlayerStateNaturally(); | |||
| character.HP = GameData.RemainHpWhenAddLife; | |||
| ((Student)character).SetTimeOfRescue(0); | |||
| player.AddScore(GameData.StudentScoreRescue); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -15,7 +15,8 @@ namespace Preparation.Interface | |||
| public CharacterType CharacterType { get; } | |||
| public ActiveSkill FindActiveSkill(ActiveSkillType activeSkillType); | |||
| public int UpdateBulletNum(int time); | |||
| public long SetPlayerState(PlayerStateType value = PlayerStateType.Null, IGameObj? obj = null); | |||
| public long SetPlayerState(RunningStateType running, PlayerStateType value = PlayerStateType.Null, IGameObj? obj = null); | |||
| public bool ResetPlayerState(long state, RunningStateType running = RunningStateType.Null, PlayerStateType value = PlayerStateType.Null, IGameObj? obj = null); | |||
| public bool IsGhost(); | |||
| } | |||
| @@ -27,6 +27,14 @@ namespace Preparation.Utility | |||
| Charmed = 18, | |||
| OpeningTheDoor = 19, | |||
| } | |||
| public enum RunningStateType | |||
| { | |||
| Null = 0, | |||
| Waiting = 1, | |||
| RunningActively = 2, | |||
| RunningSleepily = 3, | |||
| RunningForcibly = 4, | |||
| } | |||
| public enum GameObjType | |||
| { | |||
| Null = 0, | |||
| @@ -105,7 +105,7 @@ namespace Preparation.Utility | |||
| public const int basicTimeOfRescue = 1000; | |||
| #if DEBUG | |||
| public const int basicStudentMoveSpeed = 3000;// 基本移动速度,单位:s-1 | |||
| public const int basicStudentMoveSpeed = 9000;// 基本移动速度,单位:s-1 | |||
| #else | |||
| public const int basicStudentMoveSpeed = 3000; | |||
| #endif | |||
| @@ -133,7 +133,7 @@ namespace Server | |||
| currentGameInfo.ObjMessage.Add(currentMapMsg); | |||
| IsSpectatorJoin = false; | |||
| } | |||
| int time = game.GameMap.Timer.nowTime(); | |||
| int time = Environment.TickCount; | |||
| foreach (GameObj gameObj in gameObjList) | |||
| { | |||
| MessageOfObj? msg = CopyInfo.Auto(gameObj, time); | |||
| @@ -149,7 +149,7 @@ namespace Server | |||
| currentNews.Clear(); | |||
| } | |||
| currentGameInfo.GameState = gameState; | |||
| currentGameInfo.AllMessage = GetMessageOfAll(time); | |||
| currentGameInfo.AllMessage = GetMessageOfAll(game.GameMap.Timer.nowTime()); | |||
| mwr?.WriteOne(currentGameInfo); | |||
| break; | |||
| default: | |||