perf: 🔒 add a limit of call the Stop or Move fuction
tags/0.1.0
| @@ -118,7 +118,7 @@ enum TrickerType | |||||
| ASSASSIN = 1; | ASSASSIN = 1; | ||||
| KLEE = 2; | KLEE = 2; | ||||
| A_NOISY_PERSON = 3; | A_NOISY_PERSON = 3; | ||||
| TRICKERTYPE4 = 4; | |||||
| IDOL = 4; | |||||
| } | } | ||||
| // 游戏进行状态 | // 游戏进行状态 | ||||
| @@ -241,7 +241,7 @@ namespace Client | |||||
| playerMsg.TrickerType = TrickerType.ANoisyPerson; | playerMsg.TrickerType = TrickerType.ANoisyPerson; | ||||
| break; | break; | ||||
| case 4: | case 4: | ||||
| playerMsg.TrickerType = TrickerType._4; | |||||
| playerMsg.TrickerType = TrickerType.Idol; | |||||
| break; | break; | ||||
| case 0: | case 0: | ||||
| default: | default: | ||||
| @@ -49,8 +49,8 @@ namespace Client | |||||
| case TrickerType.ANoisyPerson: | case TrickerType.ANoisyPerson: | ||||
| serial.Text = "👥" + Convert.ToString(1) + "👻" + Convert.ToString(obj.PlayerId) + "\nANoisyPerson"; | serial.Text = "👥" + Convert.ToString(1) + "👻" + Convert.ToString(obj.PlayerId) + "\nANoisyPerson"; | ||||
| break; | break; | ||||
| case TrickerType._4: | |||||
| serial.Text = "👥" + Convert.ToString(1) + "👻" + Convert.ToString(obj.PlayerId) + "\nTrickerType4"; | |||||
| case TrickerType.Idol: | |||||
| serial.Text = "👥" + Convert.ToString(1) + "👻" + Convert.ToString(obj.PlayerId) + "\nIdol"; | |||||
| break; | break; | ||||
| case TrickerType.NullTrickerType: | case TrickerType.NullTrickerType: | ||||
| serial.Text = "👥" + Convert.ToString(1) + "👻" + Convert.ToString(obj.PlayerId) + "\nNullTrickerType"; | serial.Text = "👥" + Convert.ToString(1) + "👻" + Convert.ToString(obj.PlayerId) + "\nNullTrickerType"; | ||||
| @@ -318,18 +318,10 @@ namespace GameClass.GameObj | |||||
| private GameObj? whatInteractingWith = null; | private GameObj? whatInteractingWith = null; | ||||
| public GameObj? WhatInteractingWith => whatInteractingWith; | public GameObj? WhatInteractingWith => whatInteractingWith; | ||||
| public void SetPlayerState(PlayerStateType value = PlayerStateType.Null, GameObj? gameObj = null) | |||||
| public void ChangePlayerState(PlayerStateType value = PlayerStateType.Null, GameObj? gameObj = null) | |||||
| { | { | ||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| { | { | ||||
| switch (playerState) | |||||
| { | |||||
| case PlayerStateType.OpeningTheChest: | |||||
| ((Chest)whatInteractingWith).StopOpen(); | |||||
| break; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| whatInteractingWith = gameObj; | whatInteractingWith = gameObj; | ||||
| if (value != PlayerStateType.Moving) | if (value != PlayerStateType.Moving) | ||||
| IsMoving = false; | IsMoving = false; | ||||
| @@ -35,14 +35,14 @@ namespace GameClass.GameObj | |||||
| } | } | ||||
| } | } | ||||
| private bool isOpening = false; | |||||
| public bool IsOpening | |||||
| private int openStartTime = 0; | |||||
| public int OpenStartTime | |||||
| { | { | ||||
| get => isOpening; | |||||
| get => openStartTime; | |||||
| set | set | ||||
| { | { | ||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| isOpening = value; | |||||
| openStartTime = value; | |||||
| } | } | ||||
| } | } | ||||
| @@ -61,6 +61,6 @@ namespace GameClass.GameObj | |||||
| } | } | ||||
| } | } | ||||
| public bool IsOpen() => (OpenDegree == GameData.degreeOfOpenedDoorway); | |||||
| public bool IsOpen() => (openDegree == GameData.degreeOfOpenedDoorway); | |||||
| } | } | ||||
| } | } | ||||
| @@ -23,31 +23,31 @@ namespace Gaming | |||||
| { | { | ||||
| if (((Bullet)collisionObj).Parent != player && ((Bullet)collisionObj).TypeOfBullet == BulletType.JumpyDumpty) | if (((Bullet)collisionObj).Parent != player && ((Bullet)collisionObj).TypeOfBullet == BulletType.JumpyDumpty) | ||||
| { | { | ||||
| if (CharacterManager.BeStunned((Character)player, GameData.TimeOfStunnedWhenJumpyDumpty)) | |||||
| if (characterManager.BeStunned((Character)player, GameData.TimeOfStunnedWhenJumpyDumpty)) | |||||
| player.AddScore(GameData.TrickerScoreStudentBeStunned(GameData.TimeOfStunnedWhenJumpyDumpty)); | player.AddScore(GameData.TrickerScoreStudentBeStunned(GameData.TimeOfStunnedWhenJumpyDumpty)); | ||||
| gameMap.Remove((GameObj)collisionObj); | gameMap.Remove((GameObj)collisionObj); | ||||
| } | } | ||||
| } | } | ||||
| if (player.FindIActiveSkill(ActiveSkillType.CanBeginToCharge).IsBeingUsed && collisionObj.Type == GameObjType.Character && ((Character)collisionObj).IsGhost()) | if (player.FindIActiveSkill(ActiveSkillType.CanBeginToCharge).IsBeingUsed && collisionObj.Type == GameObjType.Character && ((Character)collisionObj).IsGhost()) | ||||
| { | { | ||||
| if (CharacterManager.BeStunned((Character)collisionObj, GameData.TimeOfGhostFaintingWhenCharge)) | |||||
| if (characterManager.BeStunned((Character)collisionObj, GameData.TimeOfGhostFaintingWhenCharge)) | |||||
| player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.TimeOfGhostFaintingWhenCharge)); | player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.TimeOfGhostFaintingWhenCharge)); | ||||
| CharacterManager.BeStunned(player, GameData.TimeOfStudentFaintingWhenCharge); | |||||
| characterManager.BeStunned(player, GameData.TimeOfStudentFaintingWhenCharge); | |||||
| } | } | ||||
| } | } | ||||
| public bool MovePlayer(Character playerToMove, int moveTimeInMilliseconds, double moveDirection) | public bool MovePlayer(Character playerToMove, int moveTimeInMilliseconds, double moveDirection) | ||||
| { | { | ||||
| if (!playerToMove.Commandable()) return false; | |||||
| playerToMove.SetPlayerState(PlayerStateType.Moving); | |||||
| if (!playerToMove.Commandable() || !TryToStop()) return false; | |||||
| characterManager.SetPlayerState(playerToMove, PlayerStateType.Moving); | |||||
| moveEngine.MoveObj(playerToMove, moveTimeInMilliseconds, moveDirection); | moveEngine.MoveObj(playerToMove, moveTimeInMilliseconds, moveDirection); | ||||
| return true; | return true; | ||||
| } | } | ||||
| public static bool Stop(Character player) | |||||
| public bool Stop(Character player) | |||||
| { | { | ||||
| if (player.Commandable()) | |||||
| if (player.Commandable() || !TryToStop()) | |||||
| { | { | ||||
| player.SetPlayerState(); | |||||
| characterManager.SetPlayerState(player); | |||||
| return true; | return true; | ||||
| } | } | ||||
| return false; | return false; | ||||
| @@ -63,7 +63,7 @@ namespace Gaming | |||||
| return false; | return false; | ||||
| ++generatorForFix.NumOfFixing; | ++generatorForFix.NumOfFixing; | ||||
| player.SetPlayerState(PlayerStateType.Fixing); | |||||
| characterManager.SetPlayerState(player, PlayerStateType.Fixing); | |||||
| new Thread | new Thread | ||||
| ( | ( | ||||
| () => | () => | ||||
| @@ -74,7 +74,7 @@ namespace Gaming | |||||
| { | { | ||||
| if (generatorForFix.Repair(player.FixSpeed * GameData.frameDuration, player)) | if (generatorForFix.Repair(player.FixSpeed * GameData.frameDuration, player)) | ||||
| { | { | ||||
| player.SetPlayerState(); | |||||
| characterManager.SetPlayerState(player); | |||||
| gameMap.NumOfRepairedGenerators++; | gameMap.NumOfRepairedGenerators++; | ||||
| } | } | ||||
| }, | }, | ||||
| @@ -96,31 +96,21 @@ namespace Gaming | |||||
| if (!(player.Commandable()) || player.PlayerState == PlayerStateType.OpeningTheDoorway) | if (!(player.Commandable()) || player.PlayerState == PlayerStateType.OpeningTheDoorway) | ||||
| return false; | return false; | ||||
| Doorway? doorwayToOpen = (Doorway?)gameMap.OneForInteract(player.Position, GameObjType.Doorway); | Doorway? doorwayToOpen = (Doorway?)gameMap.OneForInteract(player.Position, GameObjType.Doorway); | ||||
| if (doorwayToOpen == null || doorwayToOpen.IsOpening || !doorwayToOpen.PowerSupply) | |||||
| if (doorwayToOpen == null || doorwayToOpen.OpenStartTime > 0 || !doorwayToOpen.PowerSupply) | |||||
| return false; | return false; | ||||
| player.SetPlayerState(PlayerStateType.OpeningTheDoorway); | |||||
| doorwayToOpen.IsOpening = true; | |||||
| characterManager.SetPlayerState(player, PlayerStateType.OpeningTheDoorway, doorwayToOpen); | |||||
| int startTime = doorwayToOpen.OpenStartTime = gameMap.Timer.nowTime(); | |||||
| new Thread | new Thread | ||||
| ( | ( | ||||
| () => | () => | ||||
| { | { | ||||
| new FrameRateTaskExecutor<int>( | |||||
| loopCondition: () => player.PlayerState == PlayerStateType.OpeningTheDoorway && gameMap.Timer.IsGaming && doorwayToOpen.OpenDegree < GameData.degreeOfOpenedDoorway, | |||||
| loopToDo: () => | |||||
| { | |||||
| doorwayToOpen.OpenDegree += GameData.frameDuration; | |||||
| }, | |||||
| timeInterval: GameData.frameDuration, | |||||
| finallyReturn: () => 0 | |||||
| ) | |||||
| Thread.Sleep(GameData.degreeOfOpenedDoorway - doorwayToOpen.OpenDegree); | |||||
| .Start(); | |||||
| doorwayToOpen.IsOpening = false; | |||||
| if (doorwayToOpen.OpenDegree >= GameData.degreeOfOpenedDoorway) | |||||
| if (doorwayToOpen.OpenStartTime == startTime) | |||||
| { | { | ||||
| if (player.PlayerState == PlayerStateType.OpeningTheDoorway) | |||||
| player.SetPlayerState(); | |||||
| doorwayToOpen.OpenDegree = GameData.degreeOfOpenedDoorway; | |||||
| player.SetPlayerStateNaturally(); | |||||
| } | } | ||||
| } | } | ||||
| @@ -172,22 +162,22 @@ namespace Gaming | |||||
| ( | ( | ||||
| () => | () => | ||||
| { | { | ||||
| playerTreated.SetPlayerState(PlayerStateType.Treated); | |||||
| player.SetPlayerState(PlayerStateType.Treating); | |||||
| characterManager.SetPlayerState(playerTreated, PlayerStateType.Treated); | |||||
| characterManager.SetPlayerState(player, PlayerStateType.Treating); | |||||
| new FrameRateTaskExecutor<int>( | new FrameRateTaskExecutor<int>( | ||||
| loopCondition: () => playerTreated.PlayerState == PlayerStateType.Treated && player.PlayerState == PlayerStateType.Treating && gameMap.Timer.IsGaming, | loopCondition: () => playerTreated.PlayerState == PlayerStateType.Treated && player.PlayerState == PlayerStateType.Treating && gameMap.Timer.IsGaming, | ||||
| loopToDo: () => | loopToDo: () => | ||||
| { | { | ||||
| if (playerTreated.AddDegreeOfTreatment(GameData.frameDuration * player.TreatSpeed, player)) | if (playerTreated.AddDegreeOfTreatment(GameData.frameDuration * player.TreatSpeed, player)) | ||||
| playerTreated.SetPlayerState(); | |||||
| characterManager.SetPlayerState(playerTreated); | |||||
| }, | }, | ||||
| timeInterval: GameData.frameDuration, | timeInterval: GameData.frameDuration, | ||||
| finallyReturn: () => 0 | finallyReturn: () => 0 | ||||
| ) | ) | ||||
| .Start(); | .Start(); | ||||
| if (player.PlayerState == PlayerStateType.Treating) player.SetPlayerState(); | |||||
| else if (playerTreated.PlayerState == PlayerStateType.Treated) playerTreated.SetPlayerState(); | |||||
| if (player.PlayerState == PlayerStateType.Treating) characterManager.SetPlayerState(player); | |||||
| else if (playerTreated.PlayerState == PlayerStateType.Treated) characterManager.SetPlayerState(playerTreated); | |||||
| } | } | ||||
| ) | ) | ||||
| { IsBackground = true }.Start(); | { IsBackground = true }.Start(); | ||||
| @@ -202,8 +192,8 @@ namespace Gaming | |||||
| } | } | ||||
| if ((!player.Commandable()) || playerRescued.PlayerState != PlayerStateType.Addicted || !GameData.ApproachToInteract(playerRescued.Position, player.Position)) | if ((!player.Commandable()) || playerRescued.PlayerState != PlayerStateType.Addicted || !GameData.ApproachToInteract(playerRescued.Position, player.Position)) | ||||
| return false; | return false; | ||||
| player.SetPlayerState(PlayerStateType.Rescuing); | |||||
| playerRescued.SetPlayerState(PlayerStateType.Rescued); | |||||
| characterManager.SetPlayerState(player, PlayerStateType.Rescuing); | |||||
| characterManager.SetPlayerState(playerRescued, PlayerStateType.Rescued); | |||||
| new Thread | new Thread | ||||
| ( | ( | ||||
| @@ -225,14 +215,14 @@ namespace Gaming | |||||
| { | { | ||||
| if (playerRescued.TimeOfRescue >= GameData.basicTimeOfRescue) | if (playerRescued.TimeOfRescue >= GameData.basicTimeOfRescue) | ||||
| { | { | ||||
| playerRescued.SetPlayerState(); | |||||
| characterManager.SetPlayerState(playerRescued); | |||||
| playerRescued.HP = playerRescued.MaxHp / 2; | playerRescued.HP = playerRescued.MaxHp / 2; | ||||
| player.AddScore(GameData.StudentScoreRescue); | player.AddScore(GameData.StudentScoreRescue); | ||||
| } | } | ||||
| else | else | ||||
| playerRescued.SetPlayerState(PlayerStateType.Addicted); | |||||
| characterManager.SetPlayerState(playerRescued, PlayerStateType.Addicted); | |||||
| } | } | ||||
| if (player.PlayerState == PlayerStateType.Rescuing) player.SetPlayerState(); | |||||
| if (player.PlayerState == PlayerStateType.Rescuing) characterManager.SetPlayerState(player); | |||||
| playerRescued.TimeOfRescue = 0; | playerRescued.TimeOfRescue = 0; | ||||
| } | } | ||||
| ) | ) | ||||
| @@ -249,7 +239,7 @@ namespace Gaming | |||||
| if (chestToOpen == null || chestToOpen.OpenStartTime > 0) | if (chestToOpen == null || chestToOpen.OpenStartTime > 0) | ||||
| return false; | return false; | ||||
| player.SetPlayerState(PlayerStateType.OpeningTheChest, chestToOpen); | |||||
| characterManager.SetPlayerState(player, PlayerStateType.OpeningTheChest, chestToOpen); | |||||
| int startTime = gameMap.Timer.nowTime(); | int startTime = gameMap.Timer.nowTime(); | ||||
| chestToOpen.Open(startTime, player); | chestToOpen.Open(startTime, player); | ||||
| new Thread | new Thread | ||||
| @@ -300,7 +290,7 @@ namespace Gaming | |||||
| //Wall addWall = new Wall(windowForClimb.Position - 2 * windowToPlayer); | //Wall addWall = new Wall(windowForClimb.Position - 2 * windowToPlayer); | ||||
| // gameMap.Add(addWall); | // gameMap.Add(addWall); | ||||
| player.SetPlayerState(PlayerStateType.ClimbingThroughWindows); | |||||
| characterManager.SetPlayerState(player, PlayerStateType.ClimbingThroughWindows); | |||||
| windowForClimb.WhoIsClimbing = player; | windowForClimb.WhoIsClimbing = player; | ||||
| new Thread | new Thread | ||||
| ( | ( | ||||
| @@ -342,7 +332,7 @@ namespace Gaming | |||||
| // gameMap.Remove(addWall); | // gameMap.Remove(addWall); | ||||
| if (player.PlayerState == PlayerStateType.ClimbingThroughWindows) | if (player.PlayerState == PlayerStateType.ClimbingThroughWindows) | ||||
| { | { | ||||
| player.SetPlayerState(); | |||||
| characterManager.SetPlayerState(player); | |||||
| } | } | ||||
| } | } | ||||
| @@ -382,7 +372,7 @@ namespace Gaming | |||||
| } | } | ||||
| if (!flag) return false; | if (!flag) return false; | ||||
| player.SetPlayerState(PlayerStateType.LockingOrOpeningTheDoor); | |||||
| characterManager.SetPlayerState(player, PlayerStateType.LockingOrOpeningTheDoor); | |||||
| new Thread | new Thread | ||||
| ( | ( | ||||
| () => | () => | ||||
| @@ -405,7 +395,7 @@ namespace Gaming | |||||
| doorToLock.IsOpen = (!doorToLock.IsOpen); | doorToLock.IsOpen = (!doorToLock.IsOpen); | ||||
| } | } | ||||
| if (player.PlayerState == PlayerStateType.LockingOrOpeningTheDoor) | if (player.PlayerState == PlayerStateType.LockingOrOpeningTheDoor) | ||||
| player.SetPlayerState(); | |||||
| characterManager.SetPlayerState(player); | |||||
| doorToLock.OpenOrLockDegree = 0; | doorToLock.OpenOrLockDegree = 0; | ||||
| } | } | ||||
| @@ -437,6 +427,33 @@ namespace Gaming | |||||
| } | } | ||||
| } | } | ||||
| */ | */ | ||||
| private object numLock = new object(); | |||||
| private int lastTime = 0; | |||||
| private int numStop = 0; | |||||
| private int NumStop => numStop; | |||||
| private bool TryToStop() | |||||
| { | |||||
| lock (numLock) | |||||
| { | |||||
| int time = gameMap.Timer.nowTime(); | |||||
| if (time / GameData.frameDuration > lastTime) | |||||
| { | |||||
| lastTime = time / GameData.frameDuration; | |||||
| numStop = 1; | |||||
| return true; | |||||
| } | |||||
| else | |||||
| { | |||||
| if (numStop == GameData.LimitOfStopAndMove) | |||||
| return false; | |||||
| else | |||||
| { | |||||
| ++numStop; | |||||
| return true; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| private readonly Map gameMap; | private readonly Map gameMap; | ||||
| private readonly CharacterManager characterManager; | private readonly CharacterManager characterManager; | ||||
| @@ -81,14 +81,14 @@ namespace Gaming | |||||
| { | { | ||||
| if (objBeingShot == null) | if (objBeingShot == null) | ||||
| { | { | ||||
| CharacterManager.BackSwing((Character?)bullet.Parent, bullet.Backswing); | |||||
| characterManager.BackSwing((Character?)bullet.Parent, bullet.Backswing); | |||||
| return; | return; | ||||
| } | } | ||||
| Debugger.Output(bullet, bullet.TypeOfBullet.ToString()); | Debugger.Output(bullet, bullet.TypeOfBullet.ToString()); | ||||
| BombObj(bullet, objBeingShot); | BombObj(bullet, objBeingShot); | ||||
| CharacterManager.BackSwing((Character?)bullet.Parent, bullet.RecoveryFromHit); | |||||
| characterManager.BackSwing((Character?)bullet.Parent, bullet.RecoveryFromHit); | |||||
| return; | return; | ||||
| } | } | ||||
| @@ -140,10 +140,10 @@ namespace Gaming | |||||
| if (objBeingShot == null) | if (objBeingShot == null) | ||||
| { | { | ||||
| CharacterManager.BackSwing((Character?)bullet.Parent, bullet.Backswing); | |||||
| characterManager.BackSwing((Character?)bullet.Parent, bullet.Backswing); | |||||
| } | } | ||||
| else | else | ||||
| CharacterManager.BackSwing((Character?)bullet.Parent, bullet.RecoveryFromHit); | |||||
| characterManager.BackSwing((Character?)bullet.Parent, bullet.RecoveryFromHit); | |||||
| } | } | ||||
| public bool Attack(Character? player, double angle) | public bool Attack(Character? player, double angle) | ||||
| @@ -174,7 +174,7 @@ namespace Gaming | |||||
| if (bullet.CastTime > 0) | if (bullet.CastTime > 0) | ||||
| { | { | ||||
| player.SetPlayerState(PlayerStateType.TryingToAttack); | |||||
| characterManager.SetPlayerState(player, PlayerStateType.TryingToAttack); | |||||
| new Thread | new Thread | ||||
| (() => | (() => | ||||
| @@ -195,7 +195,7 @@ namespace Gaming | |||||
| { | { | ||||
| if (player.PlayerState == PlayerStateType.TryingToAttack) | if (player.PlayerState == PlayerStateType.TryingToAttack) | ||||
| { | { | ||||
| player.SetPlayerState(); | |||||
| characterManager.SetPlayerState(player); | |||||
| } | } | ||||
| else | else | ||||
| bullet.IsMoving = false; | bullet.IsMoving = false; | ||||
| @@ -7,6 +7,7 @@ using GameEngine; | |||||
| using Preparation.Interface; | using Preparation.Interface; | ||||
| using Timothy.FrameRateTask; | using Timothy.FrameRateTask; | ||||
| using System.Numerics; | using System.Numerics; | ||||
| using System.Timers; | |||||
| namespace Gaming | namespace Gaming | ||||
| { | { | ||||
| @@ -21,6 +22,23 @@ namespace Gaming | |||||
| this.gameMap = gameMap; | this.gameMap = gameMap; | ||||
| } | } | ||||
| public void SetPlayerState(Character player, PlayerStateType value = PlayerStateType.Null, GameObj? gameObj = null) | |||||
| { | |||||
| switch (player.PlayerState) | |||||
| { | |||||
| case PlayerStateType.OpeningTheChest: | |||||
| ((Chest)player.WhatInteractingWith).StopOpen(); | |||||
| break; | |||||
| case PlayerStateType.OpeningTheDoorway: | |||||
| Doorway doorway = (Doorway)player.WhatInteractingWith; | |||||
| doorway.OpenDegree += gameMap.Timer.nowTime() - doorway.OpenStartTime; | |||||
| doorway.OpenStartTime = 0; | |||||
| break; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| player.ChangePlayerState(value, gameObj); | |||||
| } | |||||
| public Character? AddPlayer(XY pos, int teamID, int playerID, CharacterType characterType, Character? parent = null) | public Character? AddPlayer(XY pos, int teamID, int playerID, CharacterType characterType, Character? parent = null) | ||||
| { | { | ||||
| @@ -216,7 +234,7 @@ namespace Gaming | |||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| player.SetPlayerState(PlayerStateType.Addicted); | |||||
| SetPlayerState(player, PlayerStateType.Addicted); | |||||
| new Thread | new Thread | ||||
| (() => | (() => | ||||
| { | { | ||||
| @@ -246,23 +264,23 @@ namespace Gaming | |||||
| { IsBackground = true }.Start(); | { IsBackground = true }.Start(); | ||||
| } | } | ||||
| public static bool BeStunned(Character player, int time) | |||||
| public bool BeStunned(Character player, int time) | |||||
| { | { | ||||
| if (player.PlayerState == PlayerStateType.Stunned || player.NoHp() || player.CharacterType == CharacterType.Robot) return false; | if (player.PlayerState == PlayerStateType.Stunned || player.NoHp() || player.CharacterType == CharacterType.Robot) return false; | ||||
| new Thread | new Thread | ||||
| (() => | (() => | ||||
| { | { | ||||
| player.SetPlayerState(PlayerStateType.Stunned); | |||||
| SetPlayerState(player, PlayerStateType.Stunned); | |||||
| Thread.Sleep(time); | Thread.Sleep(time); | ||||
| if (player.PlayerState == PlayerStateType.Stunned) | if (player.PlayerState == PlayerStateType.Stunned) | ||||
| player.SetPlayerState(); | |||||
| SetPlayerState(player); | |||||
| } | } | ||||
| ) | ) | ||||
| { IsBackground = true }.Start(); | { IsBackground = true }.Start(); | ||||
| return true; | return true; | ||||
| } | } | ||||
| public static bool TryBeAwed(Student character, Bullet bullet) | |||||
| public bool TryBeAwed(Student character, Bullet bullet) | |||||
| { | { | ||||
| if (character.CanBeAwed()) | if (character.CanBeAwed()) | ||||
| { | { | ||||
| @@ -337,11 +355,11 @@ namespace Gaming | |||||
| else TryBeAwed(student, bullet); | else TryBeAwed(student, bullet); | ||||
| } | } | ||||
| public static bool BackSwing(Character? player, int time) | |||||
| public bool BackSwing(Character? player, int time) | |||||
| { | { | ||||
| if (player == null || time <= 0) return false; | if (player == null || time <= 0) return false; | ||||
| if (player.PlayerState == PlayerStateType.Swinging || (!player.Commandable() && player.PlayerState != PlayerStateType.TryingToAttack)) return false; | if (player.PlayerState == PlayerStateType.Swinging || (!player.Commandable() && player.PlayerState != PlayerStateType.TryingToAttack)) return false; | ||||
| player.SetPlayerState(PlayerStateType.Swinging); | |||||
| SetPlayerState(player, PlayerStateType.Swinging); | |||||
| new Thread | new Thread | ||||
| (() => | (() => | ||||
| @@ -350,7 +368,7 @@ namespace Gaming | |||||
| if (player.PlayerState == PlayerStateType.Swinging) | if (player.PlayerState == PlayerStateType.Swinging) | ||||
| { | { | ||||
| player.SetPlayerState(); | |||||
| SetPlayerState(player); | |||||
| } | } | ||||
| } | } | ||||
| ) | ) | ||||
| @@ -167,7 +167,7 @@ namespace Gaming | |||||
| Character? player = gameMap.FindPlayerToAction(playerID); | Character? player = gameMap.FindPlayerToAction(playerID); | ||||
| if (player != null) | if (player != null) | ||||
| { | { | ||||
| return ActionManager.Stop(player); | |||||
| return actionManager.Stop(player); | |||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| @@ -233,7 +233,7 @@ namespace Gaming | |||||
| Character? player = gameMap.FindPlayerToAction(playerID); | Character? player = gameMap.FindPlayerToAction(playerID); | ||||
| if (player != null) | if (player != null) | ||||
| { | { | ||||
| PropManager.UseProp(player, propType); | |||||
| propManager.UseProp(player, propType); | |||||
| } | } | ||||
| } | } | ||||
| public void ThrowProp(long playerID, PropType propType = PropType.Null) | public void ThrowProp(long playerID, PropType propType = PropType.Null) | ||||
| @@ -375,7 +375,7 @@ namespace Gaming | |||||
| characterManager = new CharacterManager(gameMap); | characterManager = new CharacterManager(gameMap); | ||||
| attackManager = new AttackManager(gameMap, characterManager); | attackManager = new AttackManager(gameMap, characterManager); | ||||
| actionManager = new ActionManager(gameMap, characterManager); | actionManager = new ActionManager(gameMap, characterManager); | ||||
| propManager = new PropManager(gameMap); | |||||
| propManager = new PropManager(gameMap, characterManager); | |||||
| skillManager = new SkillManager(gameMap, actionManager, attackManager, propManager, characterManager); | skillManager = new SkillManager(gameMap, actionManager, attackManager, propManager, characterManager); | ||||
| } | } | ||||
| } | } | ||||
| @@ -16,10 +16,10 @@ namespace Gaming | |||||
| private class PropManager | private class PropManager | ||||
| { | { | ||||
| private readonly Map gameMap; | private readonly Map gameMap; | ||||
| private readonly CharacterManager characterManager; | |||||
| private readonly List<XY> availableCellForGenerateProp; | private readonly List<XY> availableCellForGenerateProp; | ||||
| public static void UseProp(Character player, PropType propType) | |||||
| public void UseProp(Character player, PropType propType) | |||||
| { | { | ||||
| if (player.IsResetting || player.CharacterType == CharacterType.Robot) | if (player.IsResetting || player.CharacterType == CharacterType.Robot) | ||||
| return; | return; | ||||
| @@ -57,7 +57,7 @@ namespace Gaming | |||||
| if (player.PlayerState == PlayerStateType.Stunned) | if (player.PlayerState == PlayerStateType.Stunned) | ||||
| { | { | ||||
| player.AddScore(GameData.ScorePropRecoverFromDizziness); | player.AddScore(GameData.ScorePropRecoverFromDizziness); | ||||
| player.SetPlayerState(); | |||||
| player.SetPlayerStateNaturally(); | |||||
| } | } | ||||
| break; | break; | ||||
| default: | default: | ||||
| @@ -210,8 +210,9 @@ namespace Gaming | |||||
| { IsBackground = true }.Start(); | { IsBackground = true }.Start(); | ||||
| */ | */ | ||||
| } | } | ||||
| public PropManager(Map gameMap) // 道具不能扔过墙 | |||||
| public PropManager(Map gameMap, CharacterManager characterManager) // 道具不能扔过墙 | |||||
| { | { | ||||
| this.characterManager = characterManager; | |||||
| this.gameMap = gameMap; | this.gameMap = gameMap; | ||||
| /* this.moveEngine = new MoveEngine( | /* this.moveEngine = new MoveEngine( | ||||
| gameMap: gameMap, | gameMap: gameMap, | ||||
| @@ -4,6 +4,7 @@ using Preparation.Interface; | |||||
| using Preparation.Utility; | using Preparation.Utility; | ||||
| using System; | using System; | ||||
| using Timothy.FrameRateTask; | using Timothy.FrameRateTask; | ||||
| using Google.Protobuf.Compiler; | |||||
| namespace Gaming | namespace Gaming | ||||
| { | { | ||||
| @@ -28,29 +29,51 @@ namespace Gaming | |||||
| { }); | { }); | ||||
| } | } | ||||
| public static bool ShowTime(Character player) | |||||
| public bool ShowTime(Character player) | |||||
| { | { | ||||
| if ((!player.Commandable())) return false; | if ((!player.Commandable())) return false; | ||||
| IActiveSkill skill = player.FindIActiveSkill(ActiveSkillType.ShowTime); | IActiveSkill skill = player.FindIActiveSkill(ActiveSkillType.ShowTime); | ||||
| Debugger.Output(player, ": It's show time!"); | |||||
| characterManager.SetPlayerState(player, PlayerStateType.UsingSkill); | |||||
| return ActiveSkillEffect(skill, player, () => | return ActiveSkillEffect(skill, player, () => | ||||
| { | { | ||||
| /* Thread | |||||
| * new FrameRateTaskExecutor<int>( | |||||
| loopCondition: () => player.PlayerState == PlayerStateType.OpeningTheChest && gameMap.Timer.IsGaming && (!chestToOpen.IsOpen()), | |||||
| loopToDo: () => | |||||
| { | |||||
| chestToOpen.OpenStartTime += GameData.frameDuration * player.SpeedOfOpenChest; | |||||
| }, | |||||
| timeInterval: GameData.frameDuration, | |||||
| finallyReturn: () => 0 | |||||
| ) | |||||
| new Thread | |||||
| ( | |||||
| () => | |||||
| { | |||||
| new FrameRateTaskExecutor<int>( | |||||
| loopCondition: () => player.PlayerState == PlayerStateType.UsingSkill && gameMap.Timer.IsGaming, | |||||
| loopToDo: () => | |||||
| { | |||||
| gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); | |||||
| try | |||||
| { | |||||
| foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) | |||||
| { | |||||
| if (!person.IsGhost()) | |||||
| actionManager.MovePlayer(person, GameData.frameDuration, (player.Position - person.Position).Angle()); | |||||
| } | |||||
| } | |||||
| finally | |||||
| { | |||||
| gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); | |||||
| } | |||||
| }, | |||||
| timeInterval: GameData.frameDuration, | |||||
| finallyReturn: () => 0 | |||||
| ) | |||||
| .Start();*/ | |||||
| .Start(); | |||||
| } | |||||
| ) | |||||
| { IsBackground = true }.Start(); | |||||
| }, | }, | ||||
| () => | () => | ||||
| { }); | |||||
| { | |||||
| if (player.PlayerState == PlayerStateType.UsingSkill) | |||||
| player.SetPlayerStateNaturally(); | |||||
| } | |||||
| ); | |||||
| } | } | ||||
| public static bool BecomeInvisible(Character player) | public static bool BecomeInvisible(Character player) | ||||
| @@ -145,7 +168,7 @@ namespace Gaming | |||||
| { | { | ||||
| if (!character.IsGhost() && XY.Distance(character.Position, player.Position) <= player.ViewRange) | if (!character.IsGhost() && XY.Distance(character.Position, player.Position) <= player.ViewRange) | ||||
| { | { | ||||
| if (CharacterManager.BeStunned(character, GameData.TimeOfStudentFaintingWhenHowl)) | |||||
| if (characterManager.BeStunned(character, GameData.TimeOfStudentFaintingWhenHowl)) | |||||
| player.AddScore(GameData.TrickerScoreStudentBeStunned(GameData.TimeOfStudentFaintingWhenHowl)); | player.AddScore(GameData.TrickerScoreStudentBeStunned(GameData.TimeOfStudentFaintingWhenHowl)); | ||||
| break; | break; | ||||
| } | } | ||||
| @@ -155,7 +178,7 @@ namespace Gaming | |||||
| { | { | ||||
| gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); | gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); | ||||
| } | } | ||||
| CharacterManager.BackSwing(player, GameData.TimeOfGhostSwingingAfterHowl); | |||||
| characterManager.BackSwing(player, GameData.TimeOfGhostSwingingAfterHowl); | |||||
| Debugger.Output(player, "howled!"); | Debugger.Output(player, "howled!"); | ||||
| }, | }, | ||||
| () => | () => | ||||
| @@ -177,7 +200,7 @@ namespace Gaming | |||||
| || character.PlayerState == PlayerStateType.UsingSkill) | || character.PlayerState == PlayerStateType.UsingSkill) | ||||
| && gameMap.CanSee(player, character)) | && gameMap.CanSee(player, character)) | ||||
| { | { | ||||
| if (CharacterManager.BeStunned(character, GameData.TimeOfGhostFaintingWhenPunish)) | |||||
| if (characterManager.BeStunned(character, GameData.TimeOfGhostFaintingWhenPunish)) | |||||
| player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.TimeOfGhostFaintingWhenPunish)); | player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.TimeOfGhostFaintingWhenPunish)); | ||||
| break; | break; | ||||
| } | } | ||||
| @@ -205,7 +228,7 @@ namespace Gaming | |||||
| { | { | ||||
| if ((character.PlayerState == PlayerStateType.Addicted) && gameMap.CanSee(player, character)) | if ((character.PlayerState == PlayerStateType.Addicted) && gameMap.CanSee(player, character)) | ||||
| { | { | ||||
| character.SetPlayerState(); | |||||
| characterManager.SetPlayerState(character); | |||||
| character.HP = GameData.RemainHpWhenAddLife; | character.HP = GameData.RemainHpWhenAddLife; | ||||
| ((Student)character).TimeOfRescue = 0; | ((Student)character).TimeOfRescue = 0; | ||||
| player.AddScore(GameData.StudentScoreRescue); | player.AddScore(GameData.StudentScoreRescue); | ||||
| @@ -52,6 +52,9 @@ namespace Gaming | |||||
| case ActiveSkillType.Rouse: | case ActiveSkillType.Rouse: | ||||
| Rouse(character); | Rouse(character); | ||||
| break; | break; | ||||
| case ActiveSkillType.ShowTime: | |||||
| ShowTime(character); | |||||
| break; | |||||
| default: | default: | ||||
| return false; | return false; | ||||
| } | } | ||||
| @@ -101,10 +101,10 @@ namespace Preparation.Interface | |||||
| public BulletType InitBullet => BulletType.CommonAttackOfGhost; | public BulletType InitBullet => BulletType.CommonAttackOfGhost; | ||||
| public List<ActiveSkillType> ListOfIActiveSkill => new(new ActiveSkillType[] { }); | |||||
| public List<ActiveSkillType> ListOfIActiveSkill => new(new ActiveSkillType[] { ActiveSkillType.ShowTime }); | |||||
| public List<PassiveSkillType> ListOfIPassiveSkill => new(new PassiveSkillType[] { }); | public List<PassiveSkillType> ListOfIPassiveSkill => new(new PassiveSkillType[] { }); | ||||
| public double concealment = GameData.basicConcealment; | |||||
| public double concealment = GameData.basicConcealment * 3 / 4; | |||||
| public double Concealment => concealment; | public double Concealment => concealment; | ||||
| public int alertnessRadius = GameData.basicGhostAlertnessRadius; | public int alertnessRadius = GameData.basicGhostAlertnessRadius; | ||||
| @@ -414,6 +414,8 @@ namespace Preparation.Interface | |||||
| return new ANoisyPerson(); | return new ANoisyPerson(); | ||||
| case CharacterType.TechOtaku: | case CharacterType.TechOtaku: | ||||
| return new TechOtaku(); | return new TechOtaku(); | ||||
| case CharacterType.Idol: | |||||
| return new Idol(); | |||||
| case CharacterType.Athlete: | case CharacterType.Athlete: | ||||
| default: | default: | ||||
| return new Athlete(); | return new Athlete(); | ||||
| @@ -126,7 +126,7 @@ namespace Preparation.Interface | |||||
| public int SkillCD => GameData.commonSkillCD * 3; | public int SkillCD => GameData.commonSkillCD * 3; | ||||
| public int DurationTime => GameData.commonSkillTime; | public int DurationTime => GameData.commonSkillTime; | ||||
| private readonly object commonSkillLock = new object(); | |||||
| private readonly object commonSkillLock = new(); | |||||
| public object ActiveSkillLock => commonSkillLock; | public object ActiveSkillLock => commonSkillLock; | ||||
| public bool isBeingUsed = false; | public bool isBeingUsed = false; | ||||
| @@ -275,6 +275,8 @@ namespace Preparation.Interface | |||||
| return new Rouse(); | return new Rouse(); | ||||
| case ActiveSkillType.Inspire: | case ActiveSkillType.Inspire: | ||||
| return new Inspire(); | return new Inspire(); | ||||
| case ActiveSkillType.ShowTime: | |||||
| return new ShowTime(); | |||||
| default: | default: | ||||
| return new NullSkill(); | return new NullSkill(); | ||||
| } | } | ||||
| @@ -308,6 +310,8 @@ namespace Preparation.Interface | |||||
| return ActiveSkillType.UseRobot; | return ActiveSkillType.UseRobot; | ||||
| case Rouse: | case Rouse: | ||||
| return ActiveSkillType.Rouse; | return ActiveSkillType.Rouse; | ||||
| case ShowTime: | |||||
| return ActiveSkillType.ShowTime; | |||||
| default: | default: | ||||
| return ActiveSkillType.Null; | return ActiveSkillType.Null; | ||||
| } | } | ||||
| @@ -83,6 +83,7 @@ namespace Preparation.Utility | |||||
| ANoisyPerson = 7, | ANoisyPerson = 7, | ||||
| Robot = 8, | Robot = 8, | ||||
| Sunshine = 9, | Sunshine = 9, | ||||
| Idol = 10, | |||||
| } | } | ||||
| public enum ActiveSkillType // 主动技能 | public enum ActiveSkillType // 主动技能 | ||||
| { | { | ||||
| @@ -15,6 +15,8 @@ namespace Preparation.Utility | |||||
| public const int checkInterval = 50; // 检查位置标志、补充子弹的帧时长 | public const int checkInterval = 50; // 检查位置标志、补充子弹的帧时长 | ||||
| public const long gameDuration = 600000; // 游戏时长600000ms = 10min | public const long gameDuration = 600000; // 游戏时长600000ms = 10min | ||||
| public const int LimitOfStopAndMove = 15; | |||||
| public const int MinSpeed = 1; // 最小速度 | public const int MinSpeed = 1; // 最小速度 | ||||
| public const int MaxSpeed = int.MaxValue; // 最大速度 | public const int MaxSpeed = int.MaxValue; // 最大速度 | ||||
| @@ -127,6 +129,7 @@ namespace Preparation.Utility | |||||
| CharacterType.Assassin => true, | CharacterType.Assassin => true, | ||||
| CharacterType.Klee => true, | CharacterType.Klee => true, | ||||
| CharacterType.ANoisyPerson => true, | CharacterType.ANoisyPerson => true, | ||||
| CharacterType.Idol => true, | |||||
| _ => false, | _ => false, | ||||
| }; | }; | ||||
| } | } | ||||
| @@ -233,6 +233,8 @@ namespace Preparation.Utility | |||||
| return Protobuf.TrickerType.Klee; | return Protobuf.TrickerType.Klee; | ||||
| case Preparation.Utility.CharacterType.ANoisyPerson: | case Preparation.Utility.CharacterType.ANoisyPerson: | ||||
| return Protobuf.TrickerType.ANoisyPerson; | return Protobuf.TrickerType.ANoisyPerson; | ||||
| case CharacterType.Idol: | |||||
| return TrickerType.Idol; | |||||
| default: | default: | ||||
| return Protobuf.TrickerType.NullTrickerType; | return Protobuf.TrickerType.NullTrickerType; | ||||
| } | } | ||||
| @@ -247,6 +249,8 @@ namespace Preparation.Utility | |||||
| return Preparation.Utility.CharacterType.Klee; | return Preparation.Utility.CharacterType.Klee; | ||||
| case Protobuf.TrickerType.ANoisyPerson: | case Protobuf.TrickerType.ANoisyPerson: | ||||
| return Preparation.Utility.CharacterType.ANoisyPerson; | return Preparation.Utility.CharacterType.ANoisyPerson; | ||||
| case TrickerType.Idol: | |||||
| return CharacterType.Idol; | |||||
| default: | default: | ||||
| return Preparation.Utility.CharacterType.Null; | return Preparation.Utility.CharacterType.Null; | ||||
| } | } | ||||
| @@ -75,10 +75,7 @@ namespace Preparation.Utility | |||||
| return Math.Atan2(y, x); | return Math.Atan2(y, x); | ||||
| } | } | ||||
| public override bool Equals(object obj) | |||||
| { | |||||
| throw new NotImplementedException(); | |||||
| } | |||||
| public override bool Equals(object obj) => throw new NotImplementedException(); | |||||
| public override int GetHashCode() | public override int GetHashCode() | ||||
| { | { | ||||
| @@ -32,7 +32,7 @@ namespace Server | |||||
| case Preparation.Utility.GameObjType.Chest: | case Preparation.Utility.GameObjType.Chest: | ||||
| return Chest((Chest)gameObj, time); | return Chest((Chest)gameObj, time); | ||||
| case Preparation.Utility.GameObjType.Doorway: | case Preparation.Utility.GameObjType.Doorway: | ||||
| return Gate((Doorway)gameObj); | |||||
| return Gate((Doorway)gameObj, time); | |||||
| case Preparation.Utility.GameObjType.EmergencyExit: | case Preparation.Utility.GameObjType.EmergencyExit: | ||||
| if (((EmergencyExit)gameObj).CanOpen) | if (((EmergencyExit)gameObj).CanOpen) | ||||
| return HiddenGate((EmergencyExit)gameObj); | return HiddenGate((EmergencyExit)gameObj); | ||||
| @@ -44,133 +44,153 @@ namespace Server | |||||
| } | } | ||||
| public static MessageOfObj? Auto(MessageOfNews news) | public static MessageOfObj? Auto(MessageOfNews news) | ||||
| { | { | ||||
| MessageOfObj objMsg = new(); | |||||
| objMsg.NewsMessage = news; | |||||
| MessageOfObj objMsg = new() | |||||
| { | |||||
| NewsMessage = news | |||||
| }; | |||||
| return objMsg; | return objMsg; | ||||
| } | } | ||||
| private static MessageOfObj? Student(Student player) | private static MessageOfObj? Student(Student player) | ||||
| { | { | ||||
| MessageOfObj msg = new MessageOfObj(); | |||||
| if (player.IsGhost()) return null; | if (player.IsGhost()) return null; | ||||
| msg.StudentMessage = new(); | |||||
| MessageOfObj msg = new() | |||||
| { | |||||
| StudentMessage = new() | |||||
| { | |||||
| X = player.Position.x, | |||||
| Y = player.Position.y, | |||||
| Speed = player.MoveSpeed, | |||||
| Determination = player.HP, | |||||
| Addiction = player.GamingAddiction, | |||||
| Place = Transformation.ToPlaceType((Preparation.Utility.PlaceType)player.Place), | |||||
| Guid = player.ID, | |||||
| PlayerState = Transformation.ToPlayerState((PlayerStateType)player.PlayerState), | |||||
| PlayerId = player.PlayerID, | |||||
| ViewRange = player.ViewRange, | |||||
| Radius = player.Radius, | |||||
| DangerAlert = (player.BgmDictionary.ContainsKey(BgmType.GhostIsComing)) ? player.BgmDictionary[BgmType.GhostIsComing] : 0, | |||||
| Score = player.Score, | |||||
| TreatProgress = player.DegreeOfTreatment, | |||||
| RescueProgress = player.TimeOfRescue, | |||||
| msg.StudentMessage.X = player.Position.x; | |||||
| msg.StudentMessage.Y = player.Position.y; | |||||
| msg.StudentMessage.Speed = player.MoveSpeed; | |||||
| msg.StudentMessage.Determination = player.HP; | |||||
| msg.StudentMessage.Addiction = player.GamingAddiction; | |||||
| BulletType = Transformation.ToBulletType((Preparation.Utility.BulletType)player.BulletOfPlayer), | |||||
| LearningSpeed = player.FixSpeed, | |||||
| TreatSpeed = player.TreatSpeed, | |||||
| FacingDirection = player.FacingDirection.Angle(), | |||||
| StudentType = Transformation.ToStudentType(player.CharacterType) | |||||
| } | |||||
| }; | |||||
| foreach (var keyValue in player.TimeUntilActiveSkillAvailable) | foreach (var keyValue in player.TimeUntilActiveSkillAvailable) | ||||
| msg.StudentMessage.TimeUntilSkillAvailable.Add(keyValue.Value); | msg.StudentMessage.TimeUntilSkillAvailable.Add(keyValue.Value); | ||||
| for (int i = 0; i < GameData.maxNumOfSkill - player.TimeUntilActiveSkillAvailable.Count(); ++i) | |||||
| for (int i = 0; i < GameData.maxNumOfSkill - player.TimeUntilActiveSkillAvailable.Count; ++i) | |||||
| msg.StudentMessage.TimeUntilSkillAvailable.Add(-1); | msg.StudentMessage.TimeUntilSkillAvailable.Add(-1); | ||||
| foreach (var value in player.PropInventory) | foreach (var value in player.PropInventory) | ||||
| msg.StudentMessage.Prop.Add(Transformation.ToPropType(value.GetPropType())); | msg.StudentMessage.Prop.Add(Transformation.ToPropType(value.GetPropType())); | ||||
| msg.StudentMessage.Place = Transformation.ToPlaceType((Preparation.Utility.PlaceType)player.Place); | |||||
| msg.StudentMessage.Guid = player.ID; | |||||
| msg.StudentMessage.PlayerState = Transformation.ToPlayerState((PlayerStateType)player.PlayerState); | |||||
| msg.StudentMessage.PlayerId = player.PlayerID; | |||||
| msg.StudentMessage.ViewRange = player.ViewRange; | |||||
| msg.StudentMessage.Radius = player.Radius; | |||||
| msg.StudentMessage.DangerAlert = (player.BgmDictionary.ContainsKey(BgmType.GhostIsComing)) ? player.BgmDictionary[BgmType.GhostIsComing] : 0; | |||||
| msg.StudentMessage.Score = player.Score; | |||||
| msg.StudentMessage.TreatProgress = player.DegreeOfTreatment; | |||||
| msg.StudentMessage.RescueProgress = player.TimeOfRescue; | |||||
| foreach (KeyValuePair<Preparation.Utility.BuffType, bool> kvp in player.Buff) | foreach (KeyValuePair<Preparation.Utility.BuffType, bool> kvp in player.Buff) | ||||
| { | { | ||||
| if (kvp.Value) | if (kvp.Value) | ||||
| msg.StudentMessage.Buff.Add(Transformation.ToStudentBuffType(kvp.Key)); | msg.StudentMessage.Buff.Add(Transformation.ToStudentBuffType(kvp.Key)); | ||||
| } | } | ||||
| msg.StudentMessage.BulletType = Transformation.ToBulletType((Preparation.Utility.BulletType)player.BulletOfPlayer); | |||||
| msg.StudentMessage.LearningSpeed = player.FixSpeed; | |||||
| msg.StudentMessage.TreatSpeed = player.TreatSpeed; | |||||
| msg.StudentMessage.FacingDirection = player.FacingDirection.Angle(); | |||||
| msg.StudentMessage.StudentType = Transformation.ToStudentType(player.CharacterType); | |||||
| return msg; | return msg; | ||||
| } | } | ||||
| private static MessageOfObj? Tricker(Character player) | private static MessageOfObj? Tricker(Character player) | ||||
| { | { | ||||
| MessageOfObj msg = new MessageOfObj(); | |||||
| if (!player.IsGhost()) return null; | if (!player.IsGhost()) return null; | ||||
| msg.TrickerMessage = new(); | |||||
| MessageOfObj msg = new() | |||||
| { | |||||
| TrickerMessage = new() | |||||
| { | |||||
| X = player.Position.x, | |||||
| Y = player.Position.y, | |||||
| Speed = player.MoveSpeed, | |||||
| Place = Transformation.ToPlaceType((Preparation.Utility.PlaceType)player.Place), | |||||
| TrickerType = Transformation.ToTrickerType(player.CharacterType), | |||||
| Guid = player.ID, | |||||
| Score = player.Score, | |||||
| PlayerId = player.PlayerID, | |||||
| ViewRange = player.ViewRange, | |||||
| Radius = player.Radius, | |||||
| PlayerState = Transformation.ToPlayerState((PlayerStateType)player.PlayerState), | |||||
| TrickDesire = (player.BgmDictionary.ContainsKey(BgmType.StudentIsApproaching)) ? player.BgmDictionary[BgmType.StudentIsApproaching] : 0, | |||||
| ClassVolume = (player.BgmDictionary.ContainsKey(BgmType.GeneratorIsBeingFixed)) ? player.BgmDictionary[BgmType.GeneratorIsBeingFixed] : 0, | |||||
| FacingDirection = player.FacingDirection.Angle(), | |||||
| BulletType = Transformation.ToBulletType((Preparation.Utility.BulletType)player.BulletOfPlayer) | |||||
| } | |||||
| }; | |||||
| msg.TrickerMessage.X = player.Position.x; | |||||
| msg.TrickerMessage.Y = player.Position.y; | |||||
| msg.TrickerMessage.Speed = player.MoveSpeed; | |||||
| foreach (var keyValue in player.TimeUntilActiveSkillAvailable) | foreach (var keyValue in player.TimeUntilActiveSkillAvailable) | ||||
| msg.TrickerMessage.TimeUntilSkillAvailable.Add(keyValue.Value); | msg.TrickerMessage.TimeUntilSkillAvailable.Add(keyValue.Value); | ||||
| for (int i = 0; i < GameData.maxNumOfSkill - player.TimeUntilActiveSkillAvailable.Count(); ++i) | |||||
| for (int i = 0; i < GameData.maxNumOfSkill - player.TimeUntilActiveSkillAvailable.Count; ++i) | |||||
| msg.TrickerMessage.TimeUntilSkillAvailable.Add(-1); | msg.TrickerMessage.TimeUntilSkillAvailable.Add(-1); | ||||
| msg.TrickerMessage.Place = Transformation.ToPlaceType((Preparation.Utility.PlaceType)player.Place); | |||||
| foreach (var value in player.PropInventory) | foreach (var value in player.PropInventory) | ||||
| msg.TrickerMessage.Prop.Add(Transformation.ToPropType(value.GetPropType())); | msg.TrickerMessage.Prop.Add(Transformation.ToPropType(value.GetPropType())); | ||||
| msg.TrickerMessage.TrickerType = Transformation.ToTrickerType(player.CharacterType); | |||||
| msg.TrickerMessage.Guid = player.ID; | |||||
| msg.TrickerMessage.Score = player.Score; | |||||
| msg.TrickerMessage.PlayerId = player.PlayerID; | |||||
| msg.TrickerMessage.ViewRange = player.ViewRange; | |||||
| msg.TrickerMessage.Radius = player.Radius; | |||||
| msg.TrickerMessage.PlayerState = Transformation.ToPlayerState((PlayerStateType)player.PlayerState); | |||||
| msg.TrickerMessage.TrickDesire = (player.BgmDictionary.ContainsKey(BgmType.StudentIsApproaching)) ? player.BgmDictionary[BgmType.StudentIsApproaching] : 0; | |||||
| msg.TrickerMessage.ClassVolume = (player.BgmDictionary.ContainsKey(BgmType.GeneratorIsBeingFixed)) ? player.BgmDictionary[BgmType.GeneratorIsBeingFixed] : 0; | |||||
| msg.TrickerMessage.FacingDirection = player.FacingDirection.Angle(); | |||||
| msg.TrickerMessage.BulletType = Transformation.ToBulletType((Preparation.Utility.BulletType)player.BulletOfPlayer); | |||||
| foreach (KeyValuePair<Preparation.Utility.BuffType, bool> kvp in player.Buff) | foreach (KeyValuePair<Preparation.Utility.BuffType, bool> kvp in player.Buff) | ||||
| { | { | ||||
| if (kvp.Value) | if (kvp.Value) | ||||
| msg.TrickerMessage.Buff.Add(Transformation.ToTrickerBuffType(kvp.Key)); | msg.TrickerMessage.Buff.Add(Transformation.ToTrickerBuffType(kvp.Key)); | ||||
| } | } | ||||
| return msg; | return msg; | ||||
| } | } | ||||
| private static MessageOfObj Bullet(Bullet bullet) | private static MessageOfObj Bullet(Bullet bullet) | ||||
| { | { | ||||
| MessageOfObj msg = new MessageOfObj(); | |||||
| msg.BulletMessage = new(); | |||||
| msg.BulletMessage.X = bullet.Position.x; | |||||
| msg.BulletMessage.Y = bullet.Position.y; | |||||
| msg.BulletMessage.FacingDirection = bullet.FacingDirection.Angle(); | |||||
| msg.BulletMessage.Guid = bullet.ID; | |||||
| msg.BulletMessage.Team = (bullet.Parent.IsGhost()) ? PlayerType.TrickerPlayer : PlayerType.StudentPlayer; | |||||
| msg.BulletMessage.Place = Transformation.ToPlaceType((Preparation.Utility.PlaceType)bullet.Place); | |||||
| msg.BulletMessage.BombRange = bullet.BulletBombRange; | |||||
| msg.BulletMessage.Speed = bullet.Speed; | |||||
| MessageOfObj msg = new() | |||||
| { | |||||
| BulletMessage = new() | |||||
| { | |||||
| X = bullet.Position.x, | |||||
| Y = bullet.Position.y, | |||||
| FacingDirection = bullet.FacingDirection.Angle(), | |||||
| Guid = bullet.ID, | |||||
| Team = (bullet.Parent.IsGhost()) ? PlayerType.TrickerPlayer : PlayerType.StudentPlayer, | |||||
| Place = Transformation.ToPlaceType((Preparation.Utility.PlaceType)bullet.Place), | |||||
| BombRange = bullet.BulletBombRange, | |||||
| Speed = bullet.Speed | |||||
| } | |||||
| }; | |||||
| return msg; | return msg; | ||||
| } | } | ||||
| private static MessageOfObj Prop(Prop prop) | private static MessageOfObj Prop(Prop prop) | ||||
| { | { | ||||
| MessageOfObj msg = new MessageOfObj(); | |||||
| msg.PropMessage = new(); | |||||
| msg.PropMessage.Type = Transformation.ToPropType(prop.GetPropType()); | |||||
| msg.PropMessage.X = prop.Position.x; | |||||
| msg.PropMessage.Y = prop.Position.y; | |||||
| msg.PropMessage.FacingDirection = prop.FacingDirection.Angle(); | |||||
| msg.PropMessage.Guid = prop.ID; | |||||
| msg.PropMessage.Place = Transformation.ToPlaceType((Preparation.Utility.PlaceType)prop.Place); | |||||
| MessageOfObj msg = new() | |||||
| { | |||||
| PropMessage = new() | |||||
| { | |||||
| Type = Transformation.ToPropType(prop.GetPropType()), | |||||
| X = prop.Position.x, | |||||
| Y = prop.Position.y, | |||||
| FacingDirection = prop.FacingDirection.Angle(), | |||||
| Guid = prop.ID, | |||||
| Place = Transformation.ToPlaceType((Preparation.Utility.PlaceType)prop.Place) | |||||
| } | |||||
| }; | |||||
| return msg; | return msg; | ||||
| } | } | ||||
| private static MessageOfObj BombedBullet(BombedBullet bombedBullet) | private static MessageOfObj BombedBullet(BombedBullet bombedBullet) | ||||
| { | { | ||||
| MessageOfObj msg = new MessageOfObj(); | |||||
| msg.BombedBulletMessage = new(); | |||||
| msg.BombedBulletMessage.X = bombedBullet.bulletHasBombed.Position.x; | |||||
| msg.BombedBulletMessage.Y = bombedBullet.bulletHasBombed.Position.y; | |||||
| msg.BombedBulletMessage.FacingDirection = bombedBullet.FacingDirection.Angle(); | |||||
| msg.BombedBulletMessage.MappingId = bombedBullet.MappingID; | |||||
| msg.BombedBulletMessage.BombRange = bombedBullet.bulletHasBombed.BulletBombRange; | |||||
| MessageOfObj msg = new() | |||||
| { | |||||
| BombedBulletMessage = new() | |||||
| { | |||||
| X = bombedBullet.bulletHasBombed.Position.x, | |||||
| Y = bombedBullet.bulletHasBombed.Position.y, | |||||
| FacingDirection = bombedBullet.FacingDirection.Angle(), | |||||
| MappingId = bombedBullet.MappingID, | |||||
| BombRange = bombedBullet.bulletHasBombed.BulletBombRange | |||||
| } | |||||
| }; | |||||
| return msg; | return msg; | ||||
| } | } | ||||
| @@ -188,48 +208,69 @@ namespace Server | |||||
| private static MessageOfObj Classroom(Generator generator) | private static MessageOfObj Classroom(Generator generator) | ||||
| { | { | ||||
| MessageOfObj msg = new MessageOfObj(); | |||||
| msg.ClassroomMessage = new(); | |||||
| msg.ClassroomMessage.X = generator.Position.x; | |||||
| msg.ClassroomMessage.Y = generator.Position.y; | |||||
| msg.ClassroomMessage.Progress = generator.DegreeOfRepair; | |||||
| MessageOfObj msg = new() | |||||
| { | |||||
| ClassroomMessage = new() | |||||
| { | |||||
| X = generator.Position.x, | |||||
| Y = generator.Position.y, | |||||
| Progress = generator.DegreeOfRepair | |||||
| } | |||||
| }; | |||||
| return msg; | return msg; | ||||
| } | } | ||||
| private static MessageOfObj Gate(Doorway doorway) | |||||
| private static MessageOfObj Gate(Doorway doorway, int time) | |||||
| { | { | ||||
| MessageOfObj msg = new MessageOfObj(); | |||||
| msg.GateMessage = new(); | |||||
| msg.GateMessage.X = doorway.Position.x; | |||||
| msg.GateMessage.Y = doorway.Position.y; | |||||
| msg.GateMessage.Progress = doorway.OpenDegree; | |||||
| MessageOfObj msg = new() | |||||
| { | |||||
| GateMessage = new() | |||||
| { | |||||
| X = doorway.Position.x, | |||||
| Y = doorway.Position.y | |||||
| } | |||||
| }; | |||||
| int progress = ((doorway.OpenStartTime > 0) ? (time - doorway.OpenStartTime) : 0) + doorway.OpenDegree; | |||||
| msg.GateMessage.Progress = (progress > GameData.degreeOfOpenedDoorway) ? GameData.degreeOfOpenedDoorway : progress; | |||||
| return msg; | return msg; | ||||
| } | } | ||||
| private static MessageOfObj HiddenGate(EmergencyExit Exit) | private static MessageOfObj HiddenGate(EmergencyExit Exit) | ||||
| { | { | ||||
| MessageOfObj msg = new MessageOfObj(); | |||||
| msg.HiddenGateMessage = new(); | |||||
| msg.HiddenGateMessage.X = Exit.Position.x; | |||||
| msg.HiddenGateMessage.Y = Exit.Position.y; | |||||
| msg.HiddenGateMessage.Opened = Exit.IsOpen; | |||||
| MessageOfObj msg = new() | |||||
| { | |||||
| HiddenGateMessage = new() | |||||
| { | |||||
| X = Exit.Position.x, | |||||
| Y = Exit.Position.y, | |||||
| Opened = Exit.IsOpen | |||||
| } | |||||
| }; | |||||
| return msg; | return msg; | ||||
| } | } | ||||
| private static MessageOfObj Door(Door door) | private static MessageOfObj Door(Door door) | ||||
| { | { | ||||
| MessageOfObj msg = new MessageOfObj(); | |||||
| msg.DoorMessage = new(); | |||||
| msg.DoorMessage.X = door.Position.x; | |||||
| msg.DoorMessage.Y = door.Position.y; | |||||
| msg.DoorMessage.Progress = door.OpenOrLockDegree; | |||||
| msg.DoorMessage.IsOpen = door.IsOpen; | |||||
| MessageOfObj msg = new() | |||||
| { | |||||
| DoorMessage = new() | |||||
| { | |||||
| X = door.Position.x, | |||||
| Y = door.Position.y, | |||||
| Progress = door.OpenOrLockDegree, | |||||
| IsOpen = door.IsOpen | |||||
| } | |||||
| }; | |||||
| return msg; | return msg; | ||||
| } | } | ||||
| private static MessageOfObj Chest(Chest chest, int time) | private static MessageOfObj Chest(Chest chest, int time) | ||||
| { | { | ||||
| MessageOfObj msg = new MessageOfObj(); | |||||
| msg.ChestMessage = new(); | |||||
| msg.ChestMessage.X = chest.Position.x; | |||||
| msg.ChestMessage.Y = chest.Position.y; | |||||
| MessageOfObj msg = new() | |||||
| { | |||||
| ChestMessage = new() | |||||
| { | |||||
| X = chest.Position.x, | |||||
| Y = chest.Position.y | |||||
| } | |||||
| }; | |||||
| int progress = (chest.OpenStartTime > 0) ? ((time - chest.OpenStartTime) * chest.WhoOpen.SpeedOfOpenChest) : 0; | int progress = (chest.OpenStartTime > 0) ? ((time - chest.OpenStartTime) * chest.WhoOpen.SpeedOfOpenChest) : 0; | ||||
| msg.ChestMessage.Progress = (progress > GameData.degreeOfOpenedChest) ? GameData.degreeOfOpenedChest : progress; | msg.ChestMessage.Progress = (progress > GameData.degreeOfOpenedChest) ? GameData.degreeOfOpenedChest : progress; | ||||
| return msg; | return msg; | ||||
| @@ -252,7 +252,7 @@ | |||||
| - 特性 | - 特性 | ||||
| - 冥想 | - 冥想 | ||||
| - 当玩家处于可接受指令状态且不在修机时,会积累学习进度,速度为0.3%/ms | - 当玩家处于可接受指令状态且不在修机时,会积累学习进度,速度为0.3%/ms | ||||
| - 受到攻击(并非伤害)或眩晕或翻窗(或攻击他人)学习进度清零 | |||||
| - 受到攻击(并非伤害)或学习或进入不可接受治疗状态(包括翻窗)学习进度清零 | |||||
| - 主动技能5 | - 主动技能5 | ||||
| - 写答案 | - 写答案 | ||||
| - CD:30s | - CD:30s | ||||
| @@ -401,6 +401,7 @@ public: | |||||
| ### 人物 | ### 人物 | ||||
| - 被唤醒或被勉励不属于交互状态,翻窗属于交互状态 | - 被唤醒或被勉励不属于交互状态,翻窗属于交互状态 | ||||
| - EndAllAction()及Move指令调用数总和一帧内不超过10次 | |||||
| ### 初始状态 | ### 初始状态 | ||||
| - 玩家出生点固定且一定为空地 | - 玩家出生点固定且一定为空地 | ||||