diff --git a/logic/GameClass/GameObj/Character/Character.SkillManager.cs b/logic/GameClass/GameObj/Character/Character.Skill.cs similarity index 95% rename from logic/GameClass/GameObj/Character/Character.SkillManager.cs rename to logic/GameClass/GameObj/Character/Character.Skill.cs index f657030..825bf75 100644 --- a/logic/GameClass/GameObj/Character/Character.SkillManager.cs +++ b/logic/GameClass/GameObj/Character/Character.Skill.cs @@ -53,11 +53,7 @@ namespace GameClass.GameObj public bool IsGhost() { - return this.CharacterType switch - { - CharacterType.Assassin => true, - _ => false, - }; + return GameData.IsGhost(CharacterType); } protected Character(XY initPos, int initRadius, CharacterType characterType) : @@ -88,6 +84,8 @@ namespace GameClass.GameObj this.bulletNum = maxBulletNum; this.bulletOfPlayer = Occupation.InitBullet; this.OriBulletOfPlayer = Occupation.InitBullet; + this.concealment = Occupation.Concealment; + this.alertnessRadius = Occupation.AlertnessRadius; this.characterType = characterType; foreach (var activeSkill in this.Occupation.ListOfIActiveSkill) diff --git a/logic/GameClass/GameObj/Character/Character.cs b/logic/GameClass/GameObj/Character/Character.cs index ea17b85..8de5763 100644 --- a/logic/GameClass/GameObj/Character/Character.cs +++ b/logic/GameClass/GameObj/Character/Character.cs @@ -175,6 +175,45 @@ namespace GameClass.GameObj } } + private Dictionary bgmDictionary = new(); + public Dictionary BgmDictionary + { + get => bgmDictionary; + set + { + lock (gameObjLock) + { + bgmDictionary = value; + } + } + } + + private int alertnessRadius; + public int AlertnessRadius + { + get => alertnessRadius; + set + { + lock (gameObjLock) + { + alertnessRadius = value; + } + } + } + + private double concealment; + public double Concealment + { + get => concealment; + set + { + lock (gameObjLock) + { + concealment = value; + } + } + } + /// /// 进行一次远程攻击 /// diff --git a/logic/Gaming/ActionManager.cs b/logic/Gaming/ActionManager.cs index e10c668..6290dac 100644 --- a/logic/Gaming/ActionManager.cs +++ b/logic/Gaming/ActionManager.cs @@ -1,4 +1,5 @@ using System; +using System.Numerics; using System.Runtime.InteropServices; using System.Threading; using GameClass.GameObj; @@ -38,7 +39,7 @@ namespace Gaming public bool Fix(Student player)// 自动检查有无发电机可修 { - if (player.PlayerState != PlayerStateType.Null || player.IsGhost()) + if (player.IsGhost() || (player.PlayerState != PlayerStateType.Null && player.PlayerState != PlayerStateType.IsMoving)) return false; Generator? generatorForFix = null; @@ -72,7 +73,7 @@ namespace Gaming loopCondition: () => player.PlayerState == PlayerStateType.IsFixing && gameMap.Timer.IsGaming && generatorForFix.DegreeOfFRepair < GameData.degreeOfFixedGenerator && GameData.ApproachToInteract(player.Position, generatorForFix.Position), loopToDo: () => { - return !generatorForFix.Repair(player.FixSpeed * GameData.frameDuration); + generatorForFix.Repair(player.FixSpeed * GameData.frameDuration); }, timeInterval: GameData.frameDuration, finallyReturn: () => 0 diff --git a/logic/Gaming/AttackManager.cs b/logic/Gaming/AttackManager.cs index c6f964e..6345176 100644 --- a/logic/Gaming/AttackManager.cs +++ b/logic/Gaming/AttackManager.cs @@ -38,7 +38,7 @@ namespace Gaming ); } - public void BeAddictedToGame(Student player) + private void BeAddictedToGame(Student player) { new Thread (() => @@ -68,11 +68,10 @@ namespace Gaming { IsBackground = true }.Start(); } - public void Die(Character player) + private void Die(Character player) { - player.CanMove = false; - player.IsResetting = true; + player.Die(PlayerStateType.IsDeceased); // gameMap.GameObjLockDict[GameObjType.Character].EnterWriteLock(); // try //{ diff --git a/logic/Gaming/Game.cs b/logic/Gaming/Game.cs index 6bb3949..aaebe29 100644 --- a/logic/Gaming/Game.cs +++ b/logic/Gaming/Game.cs @@ -5,6 +5,7 @@ using Preparation.Utility; using Timothy.FrameRateTask; using Preparation.Interface; using GameClass.GameObj; +using System.Numerics; namespace Gaming { @@ -41,21 +42,14 @@ namespace Gaming // Console.WriteLine($"x,y: {pos.x},{pos.y}"); Character newPlayer = (GameData.IsGhost(playerInitInfo.characterType)) ? new Ghost(pos, GameData.characterRadius, playerInitInfo.characterType) : new Student(pos, GameData.characterRadius, playerInitInfo.characterType); - gameMap.GameObjLockDict[GameObjType.Character].EnterWriteLock(); - try - { - gameMap.GameObjDict[GameObjType.Character].Add(newPlayer); - } - finally - { - gameMap.GameObjLockDict[GameObjType.Character].ExitWriteLock(); - } + gameMap.Add(newPlayer); + // Console.WriteLine($"GameObjDict[GameObjType.Character] length:{gameMap.GameObjDict[GameObjType.Character].Count}"); teamList[(int)playerInitInfo.teamID].AddPlayer(newPlayer); newPlayer.TeamID = playerInitInfo.teamID; newPlayer.PlayerID = playerInitInfo.playerID; - - new Thread //人物装弹 + #region 人物装弹 + new Thread ( () => { @@ -63,19 +57,16 @@ namespace Gaming Thread.Sleep(newPlayer.CD); long lastTime = Environment.TickCount64; new FrameRateTaskExecutor( - loopCondition: () => gameMap.Timer.IsGaming, + loopCondition: () => gameMap.Timer.IsGaming && !newPlayer.IsResetting, loopToDo: () => { - if (!newPlayer.IsResetting) + long nowTime = Environment.TickCount64; + if (newPlayer.BulletNum == newPlayer.MaxBulletNum) + lastTime = nowTime; + if (nowTime - lastTime >= newPlayer.CD) { - long nowTime = Environment.TickCount64; - if (newPlayer.BulletNum == newPlayer.MaxBulletNum) - lastTime = nowTime; - if (nowTime - lastTime >= newPlayer.CD) - { - _ = newPlayer.TryAddBulletNum(); - lastTime = nowTime; - } + _ = newPlayer.TryAddBulletNum(); + lastTime = nowTime; } }, timeInterval: GameData.checkInterval, @@ -93,6 +84,91 @@ namespace Gaming } ) { IsBackground = true }.Start(); + #endregion + #region BGM更新 + new Thread + ( + () => + { + while (!gameMap.Timer.IsGaming) + Thread.Sleep((int)GameData.checkInterval); + new FrameRateTaskExecutor( + loopCondition: () => gameMap.Timer.IsGaming && !newPlayer.IsResetting, + loopToDo: () => + { + gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); + try + { + if (newPlayer.IsGhost()) + { + double bgmVolume = 0; + foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) + { + if (!person.IsGhost() && XY.Distance(newPlayer.Position, person.Position) <= (newPlayer.AlertnessRadius / person.Concealment)) + { + if ((double)newPlayer.AlertnessRadius / XY.Distance(newPlayer.Position, person.Position) > bgmVolume) + bgmVolume = newPlayer.AlertnessRadius / XY.Distance(newPlayer.Position, person.Position); + } + } + if (bgmVolume > 0) + newPlayer.BgmDictionary.Add(BgmType.StudentIsApproaching, bgmVolume); + } + else + { + foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) + { + if (person.IsGhost()) + { + if (XY.Distance(newPlayer.Position, person.Position) <= (newPlayer.AlertnessRadius / person.Concealment)) + newPlayer.BgmDictionary.Add(BgmType.GhostIsComing, (double)newPlayer.AlertnessRadius / XY.Distance(newPlayer.Position, person.Position)); + break; + } + } + } + } + finally + { + gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); + } + + gameMap.GameObjLockDict[GameObjType.Generator].EnterReadLock(); + try + { + double bgmVolume = 0; + foreach (Generator generator in gameMap.GameObjDict[GameObjType.Generator]) + { + if (XY.Distance(newPlayer.Position, generator.Position) <= newPlayer.AlertnessRadius) + { + if ((double)newPlayer.AlertnessRadius * generator.DegreeOfFRepair / GameData.degreeOfFixedGenerator / XY.Distance(newPlayer.Position, generator.Position) > bgmVolume) + bgmVolume = (double)newPlayer.AlertnessRadius * generator.DegreeOfFRepair / GameData.degreeOfFixedGenerator / XY.Distance(newPlayer.Position, generator.Position); + } + } + if (bgmVolume > 0) + newPlayer.BgmDictionary.Add(BgmType.StudentIsApproaching, bgmVolume); + } + + + finally + { + gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); + } + }, + timeInterval: GameData.checkInterval, + finallyReturn: () => 0 + ) + { + AllowTimeExceed = true/*, + MaxTolerantTimeExceedCount = 5, + TimeExceedAction = exceedTooMuch => + { + if (exceedTooMuch) Console.WriteLine("The computer runs too slow that it cannot check the color below the player in time!"); + }*/ + } + .Start(); + } + ) + { IsBackground = true }.Start(); + #endregion return newPlayer.ID; } @@ -100,20 +176,6 @@ namespace Gaming { if (gameMap.Timer.IsGaming) return false; - gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); - try - { - foreach (Character player in gameMap.GameObjDict[GameObjType.Character]) - { - player.CanMove = true; - - player.AddShield(GameData.shieldTimeAtBirth); - } - } - finally - { - gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); - } propManager.StartProducing(); diff --git a/logic/Preparation/Interface/IOccupation.cs b/logic/Preparation/Interface/IOccupation.cs index 648ebf7..3175d4b 100644 --- a/logic/Preparation/Interface/IOccupation.cs +++ b/logic/Preparation/Interface/IOccupation.cs @@ -12,6 +12,8 @@ namespace Preparation.Interface public int MaxBulletNum { get; } public List ListOfIActiveSkill { get; } public List ListOfIPassiveSkill { get; } + public double Concealment { get; } + public int AlertnessRadius { get; } } public interface IGhost : IOccupation @@ -41,6 +43,12 @@ namespace Preparation.Interface public List ListOfIActiveSkill => new(new ActiveSkillType[] { ActiveSkillType.BecomeInvisible, ActiveSkillType.UseKnife }); public List ListOfIPassiveSkill => new(new PassiveSkillType[] { }); + + public double concealment = GameData.basicConcealment * 1.5; + public double Concealment => concealment; + + public int alertnessRadius = (int)(GameData.basicAlertnessRadius * 1.3); + public int AlertnessRadius => alertnessRadius; } public class Athlete : IStudent { @@ -61,6 +69,13 @@ namespace Preparation.Interface public List ListOfIActiveSkill => new(new ActiveSkillType[] { ActiveSkillType.BeginToCharge }); public List ListOfIPassiveSkill => new(new PassiveSkillType[] { }); - public int FixSpeed => GameData.basicFixSpeed / 10 * 6; + public const int fixSpeed = GameData.basicFixSpeed / 10 * 6; + public int FixSpeed => fixSpeed; + + public const double concealment = GameData.basicConcealment * 0.9; + public double Concealment => concealment; + + public const int alertnessRadius = (int)(GameData.basicAlertnessRadius * 0.9); + public int AlertnessRadius => alertnessRadius; } } diff --git a/logic/Preparation/Utility/GameData.cs b/logic/Preparation/Utility/GameData.cs index 9dbcf60..a581f1b 100644 --- a/logic/Preparation/Utility/GameData.cs +++ b/logic/Preparation/Utility/GameData.cs @@ -1,5 +1,6 @@ using System; using System.Reflection.Metadata.Ecma335; +using System.Threading; namespace Preparation.Utility { @@ -75,12 +76,15 @@ namespace Preparation.Utility public const int basicMoveSpeed = 3800; // 基本移动速度,单位:s-1 public const int basicBulletMoveSpeed = 5400; // 基本子弹移动速度,单位:s-1 public const int characterMaxSpeed = 12000; // 最大速度 + public const double basicConcealment = 1.0; + public const int basicAlertnessRadius = 30700; public const int addScoreWhenKillOneLevelPlayer = 30; // 击杀一级角色获得的加分 public const int commonSkillCD = 30000; // 普通技能标准冷却时间 public const int commonSkillTime = 10000; // 普通技能标准持续时间 public const int bulletRadius = 200; // 默认子弹半径 public const int reviveTime = 30000; // 复活时间 public const int shieldTimeAtBirth = 3000; // 复活时的护盾时间 + public static XY PosWhoDie = new XY(1, 1); public static bool IsGhost(CharacterType characterType) @@ -101,9 +105,12 @@ namespace Preparation.Utility public const long GemProduceTime = 10000; public const long PropProduceTime = 10000; public const int PropDuration = 10000; + #endregion + #region 物体相关 public const int degreeOfFixedGenerator = 10300000; #endregion + #region 游戏帧相关 public const long checkInterval = 50; // 检查位置标志、补充子弹的帧时长 #endregion diff --git a/logic/规则Logic.md b/logic/规则Logic.md index 2beb5b1..661fbc4 100644 --- a/logic/规则Logic.md +++ b/logic/规则Logic.md @@ -1,7 +1,7 @@ # 规则Logic ## 说明 -- 版本V1.003 +- 版本V2.0 - 该规则直接服务于Sever,并非选手版本 - *斜体表示Logic底层尚未(完全)实现* - []表示待决定 @@ -23,13 +23,11 @@ - 底层实现中的属性,不代表界面全部都需要展示,也可能需要额外展示信息 - 只展示外部需要的属性,部分属性被省略 -### Bgm -- *double bgmVolume* -- *BgmType bgmType* - 对于枚举类BgmType - 1. *不详的感觉:监管者进入(求生者的警戒半径/监管者的隐蔽度)时,求生者收到;监管者距离求生者越近,Bgm音量越大。bgmVolume=(警戒半径/二者距离)* - 2. *期待搞事的感觉:求生者进入(监管者的警戒半径/求生者的隐蔽度)时,监管者收到;监管者距离求生者越近,Bgm音量2.越大。bgmVolume=(警戒半径/二者距离)* - 3. *修理电机的声音: 警戒半径内有电机正在被修理时,全员收到;bgmVolume=(警戒半径/二者距离)*电机修理程度/10300000* +### BgmType +- 枚举类BgmType + 1. 不详的感觉:监管者进入(求生者的警戒半径/监管者的隐蔽度)时,求生者收到;监管者距离求生者越近,Bgm音量越大。bgmVolume=(警戒半径/二者距离) + 2. 期待搞事的感觉:求生者进入(监管者的警戒半径/求生者的隐蔽度)时,监管者收到;监管者距离求生者越近,Bgm音量越大。bgmVolume=(警戒半径/可被发觉的最近的求生者距离) + 3. 修理电机的声音: 警戒半径内有电机正在被修理时收到;bgmVolume=(警戒半径*电机修理程度/二者距离)/10300000 ~~~csharp public enum BgmType { @@ -95,20 +93,20 @@ IsClimbingThroughWindows = 15, } ~~~ -- *Bgm(数组)* +- *Bgm(字典)* - 得分 - ~~回血率/原始回血率~~ - 当前子弹类型 - 原始子弹类型 -- 持有道具*(最多三个)(数组)* +- 持有道具 *(最多三个)(列表)* - 是否隐身 - 队伍ID - 玩家ID - 当前Buff - 职业类型 -- 拥有的被动技能(数组) -- 拥有的主动技能(数组) -- 各个主动技能CD(数组) +- 拥有的被动技能(列表) +- 拥有的主动技能(列表) +- 各个主动技能CD(字典) - *警戒半径* - *double 隐蔽度* - *翻墙速度*