From db9f11dc0bf0dd6c52dd04d126b498327783e45f Mon Sep 17 00:00:00 2001 From: shangfengh <3495281661@qq.com> Date: Mon, 10 Apr 2023 15:39:31 +0800 Subject: [PATCH] perf: :zap: add whatInteractingWith to make a great optimization --- .../GameClass/GameObj/Character/Character.cs | 55 +++++++++------ logic/GameClass/GameObj/Map/Chest.cs | 27 ++++--- logic/Gaming/ActionManager.cs | 70 ++++++++----------- logic/Gaming/AttackManager.cs | 4 +- logic/Gaming/CharacterManager .cs | 10 +-- logic/Gaming/PropManager.cs | 2 +- .../SkillManager/SkillManager.ActiveSkill.cs | 27 ++++++- logic/Preparation/Interface/ICharacter.cs | 2 +- logic/Preparation/Interface/IOccupation.cs | 31 ++++++++ logic/Preparation/Interface/ISkill.cs | 19 ++++- logic/Preparation/Utility/EnumType.cs | 1 + logic/Server/CopyInfo.cs | 10 +-- logic/Server/GameServer.cs | 13 ++-- logic/规则Logic.md | 36 +++++----- 14 files changed, 191 insertions(+), 116 deletions(-) diff --git a/logic/GameClass/GameObj/Character/Character.cs b/logic/GameClass/GameObj/Character/Character.cs index 78e81a4..7340b4f 100644 --- a/logic/GameClass/GameObj/Character/Character.cs +++ b/logic/GameClass/GameObj/Character/Character.cs @@ -300,14 +300,6 @@ namespace GameClass.GameObj if (playerState == PlayerStateType.Null && IsMoving) return PlayerStateType.Moving; return playerState; } - set - { - if (value != PlayerStateType.Moving) - lock (gameObjLock) - IsMoving = false; - - lock (gameObjLock) playerState = (value == PlayerStateType.Moving) ? PlayerStateType.Null : value; - } } public bool NoHp() => (playerState == PlayerStateType.Deceased || playerState == PlayerStateType.Escaped @@ -323,6 +315,38 @@ namespace GameClass.GameObj || playerState == PlayerStateType.Treated || playerState == PlayerStateType.Stunned || playerState == PlayerStateType.Null || playerState == PlayerStateType.Moving); + private GameObj? whatInteractingWith = null; + public GameObj? WhatInteractingWith => whatInteractingWith; + + public void SetPlayerState(PlayerStateType value = PlayerStateType.Null, GameObj? gameObj = null) + { + lock (gameObjLock) + { + switch (playerState) + { + case PlayerStateType.OpeningTheChest: + ((Chest)whatInteractingWith).StopOpen(); + break; + default: + break; + } + whatInteractingWith = gameObj; + if (value != PlayerStateType.Moving) + IsMoving = false; + playerState = (value == PlayerStateType.Moving) ? PlayerStateType.Null : value; + //Debugger.Output(this,playerState.ToString()+" "+IsMoving.ToString()); + } + } + + public void SetPlayerStateNaturally() + { + lock (gameObjLock) + { + whatInteractingWith = null; + playerState = PlayerStateType.Null; + } + } + private int score = 0; public int Score { @@ -382,21 +406,6 @@ namespace GameClass.GameObj } } } - /// - /// 角色携带的信息 - /// - private string message = "THUAI6"; - public string Message - { - get => message; - set - { - lock (gameObjLock) - { - message = value; - } - } - } #region 道具和buff相关属性、方法 private Prop[] propInventory = new Prop[GameData.maxNumOfPropInPropInventory] diff --git a/logic/GameClass/GameObj/Map/Chest.cs b/logic/GameClass/GameObj/Map/Chest.cs index 23ee8d0..23d9571 100644 --- a/logic/GameClass/GameObj/Map/Chest.cs +++ b/logic/GameClass/GameObj/Map/Chest.cs @@ -20,20 +20,25 @@ namespace GameClass.GameObj private Prop[] propInChest = new Prop[GameData.maxNumOfPropInChest] { new NullProp(), new NullProp() }; public Prop[] PropInChest => propInChest; - private int openDegree = 0; - public int OpenDegree + private int openStartTime = 0; + public int OpenStartTime => openStartTime; + private Character? whoOpen = null; + public Character? WhoOpen => whoOpen; + public void Open(int startTime, Character character) { - get => openDegree; - set + lock (gameObjLock) { - if (value > 0) - lock (gameObjLock) - openDegree = (value > GameData.degreeOfOpenedChest) ? GameData.degreeOfOpenedChest : value; - else - lock (gameObjLock) - openDegree = 0; + openStartTime = startTime; + whoOpen = character; + } + } + public void StopOpen() + { + lock (gameObjLock) + { + openStartTime = 0; + whoOpen = null; } } - public bool IsOpen() => (OpenDegree == GameData.degreeOfOpenedChest); } } diff --git a/logic/Gaming/ActionManager.cs b/logic/Gaming/ActionManager.cs index 875d1fd..a58efee 100644 --- a/logic/Gaming/ActionManager.cs +++ b/logic/Gaming/ActionManager.cs @@ -38,7 +38,7 @@ namespace Gaming public bool MovePlayer(Character playerToMove, int moveTimeInMilliseconds, double moveDirection) { if (!playerToMove.Commandable()) return false; - playerToMove.PlayerState = PlayerStateType.Moving; + playerToMove.SetPlayerState(PlayerStateType.Moving); moveEngine.MoveObj(playerToMove, moveTimeInMilliseconds, moveDirection); return true; } @@ -47,7 +47,7 @@ namespace Gaming { if (player.Commandable()) { - player.PlayerState = PlayerStateType.Null; + player.SetPlayerState(); return true; } return false; @@ -63,7 +63,7 @@ namespace Gaming return false; ++generatorForFix.NumOfFixing; - player.PlayerState = PlayerStateType.Fixing; + player.SetPlayerState(PlayerStateType.Fixing); new Thread ( () => @@ -74,7 +74,7 @@ namespace Gaming { if (generatorForFix.Repair(player.FixSpeed * GameData.frameDuration, player)) { - player.PlayerState = PlayerStateType.Null; + player.SetPlayerState(); gameMap.NumOfRepairedGenerators++; } }, @@ -99,7 +99,7 @@ namespace Gaming if (doorwayToOpen == null || doorwayToOpen.IsOpening || !doorwayToOpen.PowerSupply) return false; - player.PlayerState = PlayerStateType.OpeningTheDoorway; + player.SetPlayerState(PlayerStateType.OpeningTheDoorway); doorwayToOpen.IsOpening = true; new Thread ( @@ -120,7 +120,7 @@ namespace Gaming if (doorwayToOpen.OpenDegree >= GameData.degreeOfOpenedDoorway) { if (player.PlayerState == PlayerStateType.OpeningTheDoorway) - player.PlayerState = PlayerStateType.Null; + player.SetPlayerState(); } } @@ -163,7 +163,7 @@ namespace Gaming playerTreated = gameMap.StudentForInteract(player.Position); if (playerTreated == null) return false; } - if (player == playerTreated || (!player.Commandable()) || player.PlayerState == PlayerStateType.Treating || + if (player == playerTreated || (!player.Commandable()) || playerTreated.PlayerState == PlayerStateType.Treated || (!playerTreated.Commandable()) || playerTreated.HP == playerTreated.MaxHp || !GameData.ApproachToInteract(playerTreated.Position, player.Position)) return false; @@ -172,22 +172,22 @@ namespace Gaming ( () => { - playerTreated.PlayerState = PlayerStateType.Treated; - player.PlayerState = PlayerStateType.Treating; + playerTreated.SetPlayerState(PlayerStateType.Treated); + player.SetPlayerState(PlayerStateType.Treating); new FrameRateTaskExecutor( loopCondition: () => playerTreated.PlayerState == PlayerStateType.Treated && player.PlayerState == PlayerStateType.Treating && gameMap.Timer.IsGaming, loopToDo: () => { if (playerTreated.AddDegreeOfTreatment(GameData.frameDuration * player.TreatSpeed, player)) - playerTreated.PlayerState = PlayerStateType.Null; + playerTreated.SetPlayerState(); }, timeInterval: GameData.frameDuration, finallyReturn: () => 0 ) .Start(); - if (player.PlayerState == PlayerStateType.Treating) player.PlayerState = PlayerStateType.Null; - else if (playerTreated.PlayerState == PlayerStateType.Treated) playerTreated.PlayerState = PlayerStateType.Null; + if (player.PlayerState == PlayerStateType.Treating) player.SetPlayerState(); + else if (playerTreated.PlayerState == PlayerStateType.Treated) playerTreated.SetPlayerState(); } ) { IsBackground = true }.Start(); @@ -200,11 +200,10 @@ namespace Gaming playerRescued = gameMap.StudentForInteract(player.Position); if (playerRescued == null) return false; } - if ((!player.Commandable()) || playerRescued.PlayerState != PlayerStateType.Addicted || player == playerRescued - || !GameData.ApproachToInteract(playerRescued.Position, player.Position) || playerRescued.TimeOfRescue > 0) + if ((!player.Commandable()) || playerRescued.PlayerState != PlayerStateType.Addicted || !GameData.ApproachToInteract(playerRescued.Position, player.Position)) return false; - player.PlayerState = PlayerStateType.Rescuing; - playerRescued.PlayerState = PlayerStateType.Rescued; + player.SetPlayerState(PlayerStateType.Rescuing); + playerRescued.SetPlayerState(PlayerStateType.Rescued); new Thread ( @@ -226,14 +225,14 @@ namespace Gaming { if (playerRescued.TimeOfRescue >= GameData.basicTimeOfRescue) { - playerRescued.PlayerState = PlayerStateType.Null; + playerRescued.SetPlayerState(); playerRescued.HP = playerRescued.MaxHp / 2; player.AddScore(GameData.StudentScoreRescue); } else - playerRescued.PlayerState = PlayerStateType.Addicted; + playerRescued.SetPlayerState(PlayerStateType.Addicted); } - if (player.PlayerState == PlayerStateType.Rescuing) player.PlayerState = PlayerStateType.Null; + if (player.PlayerState == PlayerStateType.Rescuing) player.SetPlayerState(); playerRescued.TimeOfRescue = 0; } ) @@ -247,30 +246,21 @@ namespace Gaming return false; Chest? chestToOpen = (Chest?)gameMap.OneForInteract(player.Position, GameObjType.Chest); - if (chestToOpen == null || chestToOpen.OpenDegree > 0) + if (chestToOpen == null || chestToOpen.OpenStartTime > 0) return false; - player.PlayerState = PlayerStateType.OpeningTheChest; + player.SetPlayerState(PlayerStateType.OpeningTheChest, chestToOpen); + int startTime = gameMap.Timer.nowTime(); + chestToOpen.Open(startTime, player); new Thread ( () => { - new FrameRateTaskExecutor( - loopCondition: () => player.PlayerState == PlayerStateType.OpeningTheChest && gameMap.Timer.IsGaming && (!chestToOpen.IsOpen()), - loopToDo: () => - { - chestToOpen.OpenDegree += GameData.frameDuration * player.SpeedOfOpenChest; - }, - timeInterval: GameData.frameDuration, - finallyReturn: () => 0 - ) + Thread.Sleep(GameData.degreeOfOpenedChest / player.SpeedOfOpenChest); - .Start(); - - if (chestToOpen.IsOpen()) + if (chestToOpen.OpenStartTime == startTime) { - if (player.PlayerState == PlayerStateType.OpeningTheChest) - player.PlayerState = PlayerStateType.Null; + player.SetPlayerStateNaturally(); for (int i = 0; i < GameData.maxNumOfPropInChest; ++i) { Prop prop = chestToOpen.PropInChest[i]; @@ -279,8 +269,6 @@ namespace Gaming gameMap.Add(prop); } } - else chestToOpen.OpenDegree = 0; - } ) @@ -312,7 +300,7 @@ namespace Gaming //Wall addWall = new Wall(windowForClimb.Position - 2 * windowToPlayer); // gameMap.Add(addWall); - player.PlayerState = PlayerStateType.ClimbingThroughWindows; + player.SetPlayerState(PlayerStateType.ClimbingThroughWindows); windowForClimb.WhoIsClimbing = player; new Thread ( @@ -354,7 +342,7 @@ namespace Gaming // gameMap.Remove(addWall); if (player.PlayerState == PlayerStateType.ClimbingThroughWindows) { - player.PlayerState = PlayerStateType.Null; + player.SetPlayerState(); } } @@ -394,7 +382,7 @@ namespace Gaming } if (!flag) return false; - player.PlayerState = PlayerStateType.LockingOrOpeningTheDoor; + player.SetPlayerState(PlayerStateType.LockingOrOpeningTheDoor); new Thread ( () => @@ -417,7 +405,7 @@ namespace Gaming doorToLock.IsOpen = (!doorToLock.IsOpen); } if (player.PlayerState == PlayerStateType.LockingOrOpeningTheDoor) - player.PlayerState = PlayerStateType.Null; + player.SetPlayerState(); doorToLock.OpenOrLockDegree = 0; } diff --git a/logic/Gaming/AttackManager.cs b/logic/Gaming/AttackManager.cs index 1d77685..842d53a 100644 --- a/logic/Gaming/AttackManager.cs +++ b/logic/Gaming/AttackManager.cs @@ -174,7 +174,7 @@ namespace Gaming if (bullet.CastTime > 0) { - player.PlayerState = PlayerStateType.TryingToAttack; + player.SetPlayerState(PlayerStateType.TryingToAttack); new Thread (() => @@ -195,7 +195,7 @@ namespace Gaming { if (player.PlayerState == PlayerStateType.TryingToAttack) { - player.PlayerState = PlayerStateType.Null; + player.SetPlayerState(); } else bullet.IsMoving = false; diff --git a/logic/Gaming/CharacterManager .cs b/logic/Gaming/CharacterManager .cs index 8ec3d2c..5d0d062 100644 --- a/logic/Gaming/CharacterManager .cs +++ b/logic/Gaming/CharacterManager .cs @@ -216,7 +216,7 @@ namespace Gaming return; } } - player.PlayerState = PlayerStateType.Addicted; + player.SetPlayerState(PlayerStateType.Addicted); new Thread (() => { @@ -252,10 +252,10 @@ namespace Gaming new Thread (() => { - player.PlayerState = PlayerStateType.Stunned; + player.SetPlayerState(PlayerStateType.Stunned); Thread.Sleep(time); if (player.PlayerState == PlayerStateType.Stunned) - player.PlayerState = PlayerStateType.Null; + player.SetPlayerState(); } ) { IsBackground = true }.Start(); @@ -341,7 +341,7 @@ namespace Gaming { if (player == null || time <= 0) return false; if (player.PlayerState == PlayerStateType.Swinging || (!player.Commandable() && player.PlayerState != PlayerStateType.TryingToAttack)) return false; - player.PlayerState = PlayerStateType.Swinging; + player.SetPlayerState(PlayerStateType.Swinging); new Thread (() => @@ -350,7 +350,7 @@ namespace Gaming if (player.PlayerState == PlayerStateType.Swinging) { - player.PlayerState = PlayerStateType.Null; + player.SetPlayerState(); } } ) diff --git a/logic/Gaming/PropManager.cs b/logic/Gaming/PropManager.cs index ac14bb1..3914b87 100644 --- a/logic/Gaming/PropManager.cs +++ b/logic/Gaming/PropManager.cs @@ -57,7 +57,7 @@ namespace Gaming if (player.PlayerState == PlayerStateType.Stunned) { player.AddScore(GameData.ScorePropRecoverFromDizziness); - player.PlayerState = PlayerStateType.Null; + player.SetPlayerState(); } break; default: diff --git a/logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs b/logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs index 2f2f72e..5496e79 100644 --- a/logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs +++ b/logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs @@ -28,6 +28,31 @@ namespace Gaming { }); } + public static bool ShowTime(Character player) + { + if ((!player.Commandable())) return false; + IActiveSkill skill = player.FindIActiveSkill(ActiveSkillType.ShowTime); + Debugger.Output(player, ": It's show time!"); + + return ActiveSkillEffect(skill, player, () => + { + /* Thread + * new FrameRateTaskExecutor( + loopCondition: () => player.PlayerState == PlayerStateType.OpeningTheChest && gameMap.Timer.IsGaming && (!chestToOpen.IsOpen()), + loopToDo: () => + { + chestToOpen.OpenStartTime += GameData.frameDuration * player.SpeedOfOpenChest; + }, + timeInterval: GameData.frameDuration, + finallyReturn: () => 0 + ) + + .Start();*/ + }, + () => + { }); + } + public static bool BecomeInvisible(Character player) { if ((!player.Commandable())) return false; @@ -180,7 +205,7 @@ namespace Gaming { if ((character.PlayerState == PlayerStateType.Addicted) && gameMap.CanSee(player, character)) { - character.PlayerState = PlayerStateType.Null; + character.SetPlayerState(); character.HP = GameData.RemainHpWhenAddLife; ((Student)character).TimeOfRescue = 0; player.AddScore(GameData.StudentScoreRescue); diff --git a/logic/Preparation/Interface/ICharacter.cs b/logic/Preparation/Interface/ICharacter.cs index c4b175c..5975b8c 100644 --- a/logic/Preparation/Interface/ICharacter.cs +++ b/logic/Preparation/Interface/ICharacter.cs @@ -10,7 +10,7 @@ namespace Preparation.Interface public int Score { get; } public void AddScore(int add); public double Vampire { get; } - public PlayerStateType PlayerState { get; set; } + public PlayerStateType PlayerState { get; } public BulletType BulletOfPlayer { get; set; } public bool IsGhost(); diff --git a/logic/Preparation/Interface/IOccupation.cs b/logic/Preparation/Interface/IOccupation.cs index 3e3eb70..b37bda6 100644 --- a/logic/Preparation/Interface/IOccupation.cs +++ b/logic/Preparation/Interface/IOccupation.cs @@ -91,6 +91,37 @@ namespace Preparation.Interface public int speedOfOpenChest = (int)(GameData.basicSpeedOfOpenChest * 1.1); public int SpeedOfOpenChest => speedOfOpenChest; } + public class Idol : IGhostType + { + private const int moveSpeed = GameData.basicGhostMoveSpeed; + public int MoveSpeed => moveSpeed; + + private const int maxHp = GameData.basicHp; + public int MaxHp => maxHp; + + public BulletType InitBullet => BulletType.CommonAttackOfGhost; + + public List ListOfIActiveSkill => new(new ActiveSkillType[] { }); + public List ListOfIPassiveSkill => new(new PassiveSkillType[] { }); + + public double concealment = GameData.basicConcealment; + public double Concealment => concealment; + + public int alertnessRadius = GameData.basicGhostAlertnessRadius; + public int AlertnessRadius => alertnessRadius; + + public int viewRange = GameData.basicGhostViewRange * 11 / 10; + public int ViewRange => viewRange; + + public int speedOfOpeningOrLocking = GameData.basicSpeedOfOpeningOrLocking; + public int SpeedOfOpeningOrLocking => speedOfOpeningOrLocking; + + public int speedOfClimbingThroughWindows = GameData.basicGhostSpeedOfClimbingThroughWindows; + public int SpeedOfClimbingThroughWindows => speedOfClimbingThroughWindows; + + public int speedOfOpenChest = GameData.basicSpeedOfOpenChest; + public int SpeedOfOpenChest => speedOfOpenChest; + } public class ANoisyPerson : IGhostType { private const int moveSpeed = (int)(GameData.basicGhostMoveSpeed * 1.07); diff --git a/logic/Preparation/Interface/ISkill.cs b/logic/Preparation/Interface/ISkill.cs index f0a16f6..04950e8 100644 --- a/logic/Preparation/Interface/ISkill.cs +++ b/logic/Preparation/Interface/ISkill.cs @@ -33,7 +33,7 @@ namespace Preparation.Interface public class BecomeInvisible : IActiveSkill { - public int SkillCD => GameData.commonSkillCD; + public int SkillCD => GameData.commonSkillCD * 2; public int DurationTime => GameData.commonSkillTime * 6 / 10; private readonly object commonSkillLock = new object(); @@ -121,6 +121,21 @@ namespace Preparation.Interface } } + public class ShowTime : IActiveSkill + { + public int SkillCD => GameData.commonSkillCD * 3; + public int DurationTime => GameData.commonSkillTime; + + private readonly object commonSkillLock = new object(); + public object ActiveSkillLock => commonSkillLock; + + public bool isBeingUsed = false; + public bool IsBeingUsed + { + get => isBeingUsed; set => isBeingUsed = value; + } + } + public class JumpyBomb : IActiveSkill { public int SkillCD => GameData.commonSkillCD / 2; @@ -137,7 +152,7 @@ namespace Preparation.Interface public class UseKnife : IActiveSkill { - public int SkillCD => GameData.commonSkillCD * 2 / 3; + public int SkillCD => GameData.commonSkillCD; public int DurationTime => GameData.commonSkillTime / 10; private readonly object commonSkillLock = new object(); public object ActiveSkillLock => commonSkillLock; diff --git a/logic/Preparation/Utility/EnumType.cs b/logic/Preparation/Utility/EnumType.cs index cbc4028..fc9b4d7 100644 --- a/logic/Preparation/Utility/EnumType.cs +++ b/logic/Preparation/Utility/EnumType.cs @@ -100,6 +100,7 @@ namespace Preparation.Utility Rouse = 11, Encourage = 12, Inspire = 13, + ShowTime = 14, } public enum PassiveSkillType { diff --git a/logic/Server/CopyInfo.cs b/logic/Server/CopyInfo.cs index 8cf0a76..a192063 100644 --- a/logic/Server/CopyInfo.cs +++ b/logic/Server/CopyInfo.cs @@ -3,13 +3,14 @@ using System.Collections.Generic; using GameClass.GameObj; using System.Numerics; using Preparation.Utility; +using Gaming; namespace Server { public static class CopyInfo { - public static MessageOfObj? Auto(GameObj gameObj) + public static MessageOfObj? Auto(GameObj gameObj, int time) { switch (gameObj.Type) { @@ -29,7 +30,7 @@ namespace Server case Preparation.Utility.GameObjType.Generator: return Classroom((Generator)gameObj); case Preparation.Utility.GameObjType.Chest: - return Chest((Chest)gameObj); + return Chest((Chest)gameObj, time); case Preparation.Utility.GameObjType.Doorway: return Gate((Doorway)gameObj); case Preparation.Utility.GameObjType.EmergencyExit: @@ -223,13 +224,14 @@ namespace Server msg.DoorMessage.IsOpen = door.IsOpen; return msg; } - private static MessageOfObj Chest(Chest chest) + 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; - msg.ChestMessage.Progress = chest.OpenDegree; + int progress = (chest.OpenStartTime > 0) ? ((time - chest.OpenStartTime) * chest.WhoOpen.SpeedOfOpenChest) : 0; + msg.ChestMessage.Progress = (progress > GameData.degreeOfOpenedChest) ? GameData.degreeOfOpenedChest : progress; return msg; } } diff --git a/logic/Server/GameServer.cs b/logic/Server/GameServer.cs index c0a1abf..b997885 100644 --- a/logic/Server/GameServer.cs +++ b/logic/Server/GameServer.cs @@ -135,22 +135,23 @@ namespace Server currentGameInfo.ObjMessage.Add(currentMapMsg); IsSpectatorJoin = false; } + int time = game.GameMap.Timer.nowTime(); foreach (GameObj gameObj in gameObjList) { - MessageOfObj? msg = CopyInfo.Auto(gameObj); - if (msg != null) currentGameInfo.ObjMessage.Add(CopyInfo.Auto(gameObj)); + MessageOfObj? msg = CopyInfo.Auto(gameObj, time); + if (msg != null) currentGameInfo.ObjMessage.Add(msg); } lock (newsLock) { foreach (var news in currentNews) { MessageOfObj? msg = CopyInfo.Auto(news); - if (msg != null) currentGameInfo.ObjMessage.Add(CopyInfo.Auto(news)); + if (msg != null) currentGameInfo.ObjMessage.Add(msg); } currentNews.Clear(); } currentGameInfo.GameState = gameState; - currentGameInfo.AllMessage = GetMessageOfAll(); + currentGameInfo.AllMessage = GetMessageOfAll(time); mwr?.WriteOne(currentGameInfo); break; default: @@ -211,10 +212,10 @@ namespace Server return false; } - private MessageOfAll GetMessageOfAll() + private MessageOfAll GetMessageOfAll(int time) { MessageOfAll msg = new MessageOfAll(); - msg.GameTime = game.GameMap.Timer.nowTime(); + msg.GameTime = time; msg.SubjectFinished = (int)game.GameMap.NumOfRepairedGenerators; msg.StudentGraduated = (int)game.GameMap.NumOfEscapedStudent; msg.StudentQuited = (int)game.GameMap.NumOfDeceasedStudent; diff --git a/logic/规则Logic.md b/logic/规则Logic.md index 7f9bbe0..af2fc86 100644 --- a/logic/规则Logic.md +++ b/logic/规则Logic.md @@ -8,10 +8,10 @@ - **极坐标以x坐标轴为极轴,角度逆时针为正方向**。 - 地图由50 * 50个格子构成,其中每个格子代表1000 * 1000的正方形。每个格子的编号(CellX,CellY)可以计算得到: - 略 -- 地图上的每个格子有自己的区域类型:陆地、墙、草地、教室、校门、隐藏校门、门、窗、箱子 +- 地图上格子有自己的区域类型:陆地、墙、草地、教室、校门、隐藏校门、门、窗、箱子 ### 移动 -- `std::future Move(int64_t timeInMilliseconds, double angleInRadian)`:移动,`timeInMilliseconds` 为移动时间,单位毫秒;`angleInRadian` 表示移动的方向,单位弧度,使用极坐标,**竖直向下方向为x轴,水平向右方向为y轴** +- `std::future Move(int64_t timeInMilliseconds, double angleInRadian)`:移动,`timeInMilliseconds` 为移动时间,单位毫秒;`angleInRadian` 表示移动方向,单位弧度,使用极坐标,**竖直向下方向为x轴,水平向右方向为y轴** ### 使用技能 - `std::future UseSkill(int32_t skillID)`:使用对应序号的主动技能 @@ -20,6 +20,7 @@ - 人物半径为800 - 人物共有17种不可叠加的状态: 1. (可)移动状态 +- `std::future EndAllAction()`:可以使处在下者八项状态中的玩家终止交互 2. 学习 3. 被勉励 4. 在勉励 @@ -28,7 +29,7 @@ 7. 使用技能 8. 开启校门 9. 唤醒他人中 - +- 之后八项为不可行动状态 10. 被唤醒中 11. 沉迷 12. 退学 @@ -38,9 +39,6 @@ 16. 后摇 17. 翻窗 -- 其中后8项为不可行动状态 -- `std::future EndAllAction()`:可以使处在2-9状态的玩家终止对应交互,对于后8项状态无效 - ### 攻击 - `std::future Attack(double angleInRadian)`:`angleInRadian`为攻击方向,无论近战远程均产生bullet表示攻击 - 攻击类型CommonAttackOfGhost攻击未写完的作业,会造成对应攻击力的损坏 @@ -67,17 +65,17 @@ - 每张地图都有10间教室,学生需要完成其中的**7间**教室的作业,才可以开启任意校门。 - `std::future StartLearning()`:在教室(旁)做作业 - `std::future StartOpenGate()`:开启校门,所需时间为18秒,开启的进度不清空 -- 隐藏校门会在**3间**教室的作业完成的情况下在3-5个隐藏校门刷新点之一随机显现,当学生只剩1名时,隐藏校门将会自动打开。 +- 当**3间**教室的作业完成时,隐藏校门在3-5个刷新点之一随机显现;当只剩1名学生时,隐藏校门自动打开。 - `std::future Graduate()`:从开启的校门或隐藏校门毕业。 #### 勉励(Treat) -- `std::future StartTreatMate(int64_t mateID)`:勉励对应玩家ID的学生,当达到被勉励程度达到1500000或者最大血量与当前血量的差值时,勉励结束。 +- `std::future StartTreatMate(int64_t mateID)`:勉励对应玩家ID的学生,当达到被勉励程度达到1500000或者最大学习毅力与当前学习毅力的差值时,勉励完成,学生毅力增加对应被勉励程度。 - 勉励中断时,被勉励程度保留;遭到攻击时被勉励程度清空 #### 沉迷与唤醒 -- 当学生血量归零时,学生原地进入沉迷状态,每毫秒增加1沉迷度 -- `std::future StartRescueMate(int64_t mateID)`:唤醒对应玩家ID的沉迷的学生,需要时间1秒,之后血量恢复至1/2。沉迷程度不清空。 -- 进入沉迷状态时。如果学生原沉迷程度在(0,该玩家最大沉迷度/3)中,沉迷程度直接变为其最大沉迷度/3;原沉迷程度在[其最大沉迷度/3,其最大沉迷度x2/3)中,沉迷程度直接变为其最大沉迷度x2/3;原沉迷程度大于其最大沉迷度x2/3,从游戏中出局; +- 当学生学习毅力归零时,学生原地进入沉迷状态,每毫秒增加1沉迷度 +- `std::future StartRescueMate(int64_t mateID)`:唤醒对应玩家ID的沉迷的学生,需要时间1秒,之后学习毅力恢复至1/2。沉迷程度不清空。 +- 进入沉迷状态时,如果学生原沉迷程度在(0,该玩家最大沉迷度/3)中,沉迷程度直接变为其最大沉迷度/3;原沉迷程度在[其最大沉迷度/3,其最大沉迷度x2/3)中,沉迷程度直接变为其最大沉迷度x2/3;原沉迷程度大于其最大沉迷度x2/3,从游戏中出局; - 当学生沉迷程度达到其最大沉迷程度时,从游戏中出局 #### 门 @@ -99,12 +97,12 @@ 3. 学习的声音: 捣蛋鬼警戒半径内有人学习时收到;bgmVolume=(警戒半径x学习进度百分比)/二者距离 ### 队内信息 -- `std::future SendMessage(int64_t, std::string)`:给同队的队友发送消息。`toPlayerID`指定发送的对象,`message`指定发送的内容。`message`的长度不能超过 64,否则将发送失败! +- `std::future SendMessage(int64_t, std::string)`:给同队的队友发送消息。第一个参数指定发送的对象,第二个参数指定发送的内容。 - `bool HaveMessage()`:是否有队友发来的尚未接收的信息。 +- `std::pair GetMessage()`:从玩家ID为第一个参数的队友获取信息。 -### 信息受限 -- 主动行为每 50ms 最多总共可以调用 50 次; -- `bool Wait()`:asynchronous 为 true 的情况下,选手可以调用此函数,阻塞当前线程,直到下一次消息更新时继续运行。 +### 线程控制 +- `bool Wait()`:阻塞当前线程,直到下一次消息更新时继续运行。 ### 信息获取 `std::vector> GetStudents() const` :返回所有可视学生的信息。 @@ -189,11 +187,11 @@ - 普通攻击为 搞蛋鬼的一般攻击 - 主动技能 - 隐身 - - CD:30s 持续时间:6s + - CD:60s 持续时间:6s - 在持续时间内玩家隐身 - 使用瞬间得分 - 使用飞刀 - - CD:20s 持续时间:1s + - CD:30s 持续时间:1s - 在持续时间内,攻击类型变为飞刀 - 不直接得分 @@ -412,14 +410,14 @@ public: ### 交互 - 在指令仍在进行时,重复发出同一类型的交互指令是无效的,你需要先发出Stop指令终止进行的指令 - - 实际上救援或勉励不同的人是有效的 + - 实际上唤醒或勉励不同的人是有效的 ### 破译与逃脱 - 隐藏校门与校门对于人有碰撞体积 - 一个校门同时最多可以由一人开启 ### 攻击 -- 每次学生受到攻击后会损失对应子弹的攻击力的血量 +- 每次学生受到攻击后会损失对应子弹的攻击力的学习毅力 - 前摇期间攻击被打断时,子弹消失。 - 此处,前摇指 从播放攻击动作开始 攻击者不能交互 的时间