diff --git a/docs/GameRules.md b/docs/GameRules.md index b2fe500..2108843 100644 --- a/docs/GameRules.md +++ b/docs/GameRules.md @@ -316,6 +316,7 @@ $$ ### 道具 - 使用钥匙相当于销毁 + - 可接受指令状态下能捡起或扔道具,在场上即可使用道具 ### 交互 - 被唤醒或被勉励不属于交互状态,翻窗属于交互状态 diff --git a/logic/GameClass/GameObj/Character/Character.cs b/logic/GameClass/GameObj/Character/Character.cs index 1d6ab0e..10e9523 100644 --- a/logic/GameClass/GameObj/Character/Character.cs +++ b/logic/GameClass/GameObj/Character/Character.cs @@ -341,12 +341,14 @@ namespace GameClass.GameObj set { lock (vampireLock) + { if (value > 1) vampire = 1; else if (value < 0) vampire = 0; else vampire = value; + } } } public double OriVampire { get; protected set; } @@ -394,7 +396,8 @@ namespace GameClass.GameObj { lock (actionLock) { - return (playerState == PlayerStateType.LockingOrOpeningTheDoor || playerState == PlayerStateType.Fixing || playerState == PlayerStateType.OpeningTheChest); + return (playerState == PlayerStateType.LockingTheDoor || playerState == PlayerStateType.OpeningTheDoor + || playerState == PlayerStateType.Fixing || playerState == PlayerStateType.OpeningTheChest); } } public bool NullOrMoving() @@ -465,41 +468,75 @@ namespace GameClass.GameObj else return -1; case PlayerStateType.TryingToAttack: - if (value != PlayerStateType.Moving && value != PlayerStateType.ClimbingThroughWindows) + if (value != PlayerStateType.Moving && value != PlayerStateType.ClimbingThroughWindows + && value != PlayerStateType.LockingTheDoor && value != PlayerStateType.OpeningTheDoor) return ChangePlayerState(value, gameObj); else return -1; case PlayerStateType.Stunned: case PlayerStateType.Charmed: - if (value != PlayerStateType.Moving && value != PlayerStateType.ClimbingThroughWindows && value != PlayerStateType.Swinging) + if (value != PlayerStateType.Moving && value != PlayerStateType.ClimbingThroughWindows + && value != PlayerStateType.LockingTheDoor && value != PlayerStateType.OpeningTheDoor + && value != PlayerStateType.Swinging) return ChangePlayerState(value, gameObj); else return -1; case PlayerStateType.Swinging: - if (value != PlayerStateType.Moving && value != PlayerStateType.ClimbingThroughWindows) + if (value != PlayerStateType.Moving && value != PlayerStateType.ClimbingThroughWindows + && value != PlayerStateType.LockingTheDoor && value != PlayerStateType.OpeningTheDoor) { - ThreadNum.Release(); - return ChangePlayerState(value, gameObj); + try + { + return ChangePlayerState(value, gameObj); + } + finally + { + ThreadNum.Release(); + } } else return -1; case PlayerStateType.ClimbingThroughWindows: - if (value != PlayerStateType.Moving) + if (value != PlayerStateType.Moving && value != PlayerStateType.LockingTheDoor && value != PlayerStateType.OpeningTheDoor) { Window window = (Window)WhatInteractingWith!; - window.FinishClimbing(); - if (window.Stage.x == 0) - ThreadNum.Release(); - else ReSetPos(window.Stage); - return ChangePlayerState(value, gameObj); + try + { + window.FinishClimbing(); + return ChangePlayerState(value, gameObj); + } + finally + { + if (window.Stage.x == 0) + ThreadNum.Release(); + else ReSetPos(window.Stage); + } } else return -1; case PlayerStateType.OpeningTheChest: - ((Chest)WhatInteractingWith!).StopOpen(); + ((Chest)whatInteractingWith!).StopOpen(); return ChangePlayerState(value, gameObj); case PlayerStateType.OpeningTheDoorway: - Doorway doorway = (Doorway)WhatInteractingWith!; + Doorway doorway = (Doorway)whatInteractingWith!; doorway.StopOpenning(); return ChangePlayerState(value, gameObj); + case PlayerStateType.OpeningTheDoor: + Door door = (Door)whatInteractingWith!; + try + { + door.StopOpen(); + ReleaseTool(door.DoorNum switch + { + 3 => PropType.Key3, + 5 => PropType.Key5, + _ => PropType.Key6, + } + ); + return ChangePlayerState(value, gameObj); + } + finally + { + ThreadNum.Release(); + } default: return ChangePlayerState(value, gameObj); } @@ -638,6 +675,36 @@ namespace GameClass.GameObj return new NullProp(); } + public bool UseTool(PropType propType) + { + lock (inventoryLock) + { + for (int indexing = 0; indexing < GameData.maxNumOfPropInPropInventory; ++indexing) + { + if (PropInventory[indexing].GetPropType() == propType && PropInventory[indexing].IsUsable()) + { + return ((Tool)PropInventory[indexing]).IsUsed = true; + } + } + } + return false; + } + + public void ReleaseTool(PropType propType) + { + lock (inventoryLock) + { + for (int indexing = 0; indexing < GameData.maxNumOfPropInPropInventory; ++indexing) + { + if (PropInventory[indexing].GetPropType() == propType && ((Tool)PropInventory[indexing]).IsUsed) + { + ((Tool)PropInventory[indexing]).IsUsed = false; + break; + } + } + } + } + /// /// 如果indexing==GameData.maxNumOfPropInPropInventory表明道具栏为满 /// diff --git a/logic/GameClass/GameObj/Map/Door.cs b/logic/GameClass/GameObj/Map/Door.cs index 2410421..5955a57 100644 --- a/logic/GameClass/GameObj/Map/Door.cs +++ b/logic/GameClass/GameObj/Map/Door.cs @@ -1,5 +1,7 @@ using Preparation.Interface; using Preparation.Utility; +using System; +using System.Threading; namespace GameClass.GameObj { @@ -32,30 +34,123 @@ namespace GameClass.GameObj public override bool IsRigid => !isOpen; public override ShapeType Shape => ShapeType.Square; + private Character? whoLockOrOpen = null; + public Character? WhoLockOrOpen + { + get + { + lock (gameObjLock) + return whoLockOrOpen; + } + } + private bool isOpen = true; public bool IsOpen { - get => isOpen; - set + get { lock (gameObjLock) - isOpen = value; + return isOpen; } } - private int openOrLockDegree = 0; - public int OpenOrLockDegree + private int lockDegree = 0; + public int LockDegree { - get => openOrLockDegree; + get + { + lock (gameObjLock) + return lockDegree; + } set { - if (value > 0) - lock (gameObjLock) - openOrLockDegree = (value > GameData.degreeOfLockingOrOpeningTheDoor) ? GameData.degreeOfLockingOrOpeningTheDoor : value; - else - lock (gameObjLock) - openOrLockDegree = 0; + value = (value > GameData.degreeOfLockingOrOpeningTheDoor) ? GameData.degreeOfLockingOrOpeningTheDoor : value; + lock (gameObjLock) + lockDegree = value; + } + } + + private long openStartTime = 0; + public long OpenStartTime + { + get + { + lock (gameObjLock) + return openStartTime; + } + } + + public bool TryOpen(Character character) + { + lock (gameObjLock) + { + if (isOpen) return false; + if (whoLockOrOpen != null) return false; + openStartTime = Environment.TickCount64; + whoLockOrOpen = character; + return true; + } + } + public void StopOpen() + { + lock (gameObjLock) + { + if (whoLockOrOpen != null) + { + if (Environment.TickCount64 - openStartTime >= GameData.degreeOfLockingOrOpeningTheDoor) + isOpen = true; + whoLockOrOpen = null; + } + } + } + public void FinishOpen() + { + lock (gameObjLock) + { + isOpen = true; + whoLockOrOpen = null; + } + } + + public bool TryLock(Character character) + { + lock (gameObjLock) + { + if (!isOpen) return false; + if (whoLockOrOpen != null) return false; + lockDegree = 0; + whoLockOrOpen = character; + return true; + } + } + public void StopLock() + { + lock (gameObjLock) + { + if (lockDegree >= GameData.degreeOfLockingOrOpeningTheDoor) + isOpen = true; + whoLockOrOpen = null; + } + } + public void FinishLock() + { + lock (gameObjLock) + { + isOpen = false; + whoLockOrOpen = null; + } + } + + public void ForceToOpen() + { + Character? character; + lock (gameObjLock) + { + character = whoLockOrOpen; + whoLockOrOpen = null; + isOpen = true; } + if (character != null) character.SetPlayerState(); } } } diff --git a/logic/Gaming/ActionManager.cs b/logic/Gaming/ActionManager.cs index 278e04d..faec44b 100644 --- a/logic/Gaming/ActionManager.cs +++ b/logic/Gaming/ActionManager.cs @@ -389,67 +389,133 @@ namespace Gaming return true; } - public bool LockOrOpenDoor(Character player) + public bool LockDoor(Character player) { if (player.CharacterType == CharacterType.Robot) return false; Door? doorToLock = (Door?)gameMap.OneForInteract(player.Position, GameObjType.Door); if (doorToLock == null) return false; - bool flag = false; - foreach (Gadget prop in player.PropInventory) + + PropType propType = doorToLock.DoorNum switch + { + 3 => PropType.Key3, + 5 => PropType.Key5, + _ => PropType.Key6, + }; + + if (!player.UseTool(propType)) return false; + + long stateNum = player.SetPlayerState(PlayerStateType.LockingTheDoor, doorToLock); + if (stateNum == -1) { - switch (prop.GetPropType()) + player.ReleaseTool(propType); + return false; + } + + new Thread + ( + () => { - case PropType.Key3: - if (doorToLock.DoorNum == 3) - flag = true; - break; - case PropType.Key5: - if (doorToLock.DoorNum == 5) - flag = true; - break; - case PropType.Key6: - if (doorToLock.DoorNum == 6) - flag = true; - break; - default: - break; + player.ThreadNum.WaitOne(); + if (stateNum != player.StateNum) + { + player.ReleaseTool(propType); + player.ThreadNum.Release(); + } + else + { + if (!doorToLock.TryLock(player)) + { + player.ReleaseTool(propType); + player.SetPlayerState(); + player.ThreadNum.Release(); + } + else + { + Thread.Sleep(GameData.checkInterval); + new FrameRateTaskExecutor( + 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(); + if (stateNum == player.StateNum) player.SetPlayerState(); + player.ReleaseTool(propType); + player.ThreadNum.Release(); + } + } } - if (flag) break; - } - if (!flag) return false; + ) + { IsBackground = true }.Start(); - if (doorToLock.OpenOrLockDegree > 0 || gameMap.PartInTheSameCell(doorToLock.Position, GameObjType.Character) != null) - return false; - if (!(player.Commandable()) || player.PlayerState == PlayerStateType.LockingOrOpeningTheDoor) + return true; + } + + public bool OpenDoor(Character player) + { + if (player.CharacterType == CharacterType.Robot) return false; + Door? doorToLock = (Door?)gameMap.OneForInteract(player.Position, GameObjType.Door); + if (doorToLock == null) return false; + + PropType propType = doorToLock.DoorNum switch + { + 3 => PropType.Key3, + 5 => PropType.Key5, + _ => PropType.Key6, + }; + + if (!player.UseTool(propType)) return false; + + long stateNum = player.SetPlayerState(PlayerStateType.OpeningTheDoor, doorToLock); + if (stateNum == -1) + { + player.ReleaseTool(propType); return false; + } - player.SetPlayerState(PlayerStateType.LockingOrOpeningTheDoor); - long threadNum = player.StateNum; new Thread - ( - () => - { - new FrameRateTaskExecutor( - loopCondition: () => flag && threadNum == player.StateNum && gameMap.Timer.IsGaming && doorToLock.OpenOrLockDegree < GameData.degreeOfLockingOrOpeningTheDoor, - loopToDo: () => - { - flag = ((gameMap.PartInTheSameCell(doorToLock.Position, GameObjType.Character)) == null); - doorToLock.OpenOrLockDegree += GameData.frameDuration * player.SpeedOfOpeningOrLocking; - }, - timeInterval: GameData.frameDuration, - finallyReturn: () => 0 - ) - .Start(); - if (doorToLock.OpenOrLockDegree >= GameData.degreeOfLockingOrOpeningTheDoor) - { - doorToLock.IsOpen = (!doorToLock.IsOpen); - } - if (threadNum == player.StateNum) - player.SetPlayerState(); - doorToLock.OpenOrLockDegree = 0; - } + ( + () => + { + player.ThreadNum.WaitOne(); + if (stateNum != player.StateNum) + { + player.ReleaseTool(propType); + player.ThreadNum.Release(); + } + else + { + if (!doorToLock.TryOpen(player)) + { + player.ReleaseTool(propType); + player.SetPlayerState(); + player.ThreadNum.Release(); + } + else + { + Thread.Sleep(GameData.degreeOfLockingOrOpeningTheDoor / player.SpeedOfOpeningOrLocking); - ) + lock (player.ActionLock) + { + if (stateNum == player.StateNum) + { + player.SetPlayerState(); + doorToLock.StopOpen(); + player.ReleaseTool(propType); + player.ThreadNum.Release(); + } + } + } + } + } + ) { IsBackground = true }.Start(); return true; diff --git a/logic/Gaming/Game.cs b/logic/Gaming/Game.cs index 84074e2..8a973c9 100644 --- a/logic/Gaming/Game.cs +++ b/logic/Gaming/Game.cs @@ -197,14 +197,25 @@ namespace Gaming } return false; } - public bool LockOrOpenDoor(long playerID) + public bool LockDoor(long playerID) { if (!gameMap.Timer.IsGaming) return false; Character? player = gameMap.FindPlayerToAction(playerID); if (player != null) { - return actionManager.LockOrOpenDoor(player); + return actionManager.LockDoor(player); + } + return false; + } + public bool OpenDoor(long playerID) + { + if (!gameMap.Timer.IsGaming) + return false; + Character? player = gameMap.FindPlayerToAction(playerID); + if (player != null) + { + return actionManager.OpenDoor(player); } return false; } diff --git a/logic/Gaming/PropManager.cs b/logic/Gaming/PropManager.cs index abb5866..3481cd0 100644 --- a/logic/Gaming/PropManager.cs +++ b/logic/Gaming/PropManager.cs @@ -21,7 +21,7 @@ namespace Gaming public void UseProp(Character player, PropType propType) { - if (player.IsRemoved || player.CharacterType == CharacterType.Robot) + if (player.CharacterType == CharacterType.Robot || player.IsRemoved) return; Gadget prop = player.UseProp(propType); switch (prop.GetPropType()) diff --git a/logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs b/logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs index b9b5d7a..fccac32 100644 --- a/logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs +++ b/logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs @@ -216,7 +216,9 @@ namespace Gaming { if (character.IsGhost() && (character.PlayerState == PlayerStateType.TryingToAttack || character.PlayerState == PlayerStateType.Swinging - || character.PlayerState == PlayerStateType.UsingSkill || character.PlayerState == PlayerStateType.LockingOrOpeningTheDoor || character.PlayerState == PlayerStateType.ClimbingThroughWindows) + || character.PlayerState == PlayerStateType.UsingSkill + || character.PlayerState == PlayerStateType.LockingTheDoor || character.PlayerState == PlayerStateType.OpeningTheDoor + || character.PlayerState == PlayerStateType.ClimbingThroughWindows) && gameMap.CanSee(player, character)) { if (characterManager.BeStunned(character, GameData.timeOfGhostStunnedWhenPunish + GameData.factorOfTimeStunnedWhenPunish * (player.MaxHp - player.HP)) > 0) diff --git a/logic/Preparation/Utility/EnumType.cs b/logic/Preparation/Utility/EnumType.cs index 5809d85..0608e60 100644 --- a/logic/Preparation/Utility/EnumType.cs +++ b/logic/Preparation/Utility/EnumType.cs @@ -19,12 +19,13 @@ namespace Preparation.Utility Rescued = 10, Stunned = 11, TryingToAttack = 12,//指前摇 - LockingOrOpeningTheDoor = 13, + LockingTheDoor = 13, OpeningTheChest = 14, ClimbingThroughWindows = 15, UsingSkill = 16, OpeningTheDoorway = 17, Charmed = 18, + OpeningTheDoor = 19, } public enum GameObjType { diff --git a/logic/Preparation/Utility/Transformation.cs b/logic/Preparation/Utility/Transformation.cs index 0a997be..e5ad6fd 100644 --- a/logic/Preparation/Utility/Transformation.cs +++ b/logic/Preparation/Utility/Transformation.cs @@ -107,7 +107,8 @@ namespace Preparation.Utility return PlayerState.Graduated; case Preparation.Utility.PlayerStateType.Fixing: return PlayerState.Learning; - case Preparation.Utility.PlayerStateType.LockingOrOpeningTheDoor: + case Preparation.Utility.PlayerStateType.LockingTheDoor: + case PlayerStateType.OpeningTheDoor: return PlayerState.Locking; case Preparation.Utility.PlayerStateType.OpeningTheChest: return PlayerState.OpeningAChest; diff --git a/logic/Server/CopyInfo.cs b/logic/Server/CopyInfo.cs index 470b479..a4b9030 100644 --- a/logic/Server/CopyInfo.cs +++ b/logic/Server/CopyInfo.cs @@ -256,7 +256,7 @@ namespace Server { X = door.Position.x, Y = door.Position.y, - Progress = door.OpenOrLockDegree, + Progress = door.LockDegree, IsOpen = door.IsOpen } }; diff --git a/logic/Server/RpcServices.cs b/logic/Server/RpcServices.cs index 31ea12b..f624250 100644 --- a/logic/Server/RpcServices.cs +++ b/logic/Server/RpcServices.cs @@ -471,7 +471,7 @@ namespace Server return Task.FromResult(boolRes); } var gameID = communicationToGameID[request.PlayerId]; - boolRes.ActSuccess = game.LockOrOpenDoor(gameID); + boolRes.ActSuccess = game.OpenDoor(gameID); return Task.FromResult(boolRes); } @@ -487,7 +487,7 @@ namespace Server return Task.FromResult(boolRes); } var gameID = communicationToGameID[request.PlayerId]; - boolRes.ActSuccess = game.LockOrOpenDoor(gameID); + boolRes.ActSuccess = game.LockDoor(gameID); return Task.FromResult(boolRes); }