| @@ -976,7 +976,7 @@ namespace Client | |||
| MoveMsg msgW = new() | |||
| { | |||
| PlayerId = playerID, | |||
| TimeInMilliseconds = 50, | |||
| TimeInMilliseconds = 25, | |||
| Angle = Math.PI | |||
| }; | |||
| client.Move(msgW); | |||
| @@ -986,7 +986,7 @@ namespace Client | |||
| MoveMsg msgS = new() | |||
| { | |||
| PlayerId = playerID, | |||
| TimeInMilliseconds = 50, | |||
| TimeInMilliseconds = 25, | |||
| Angle = 0 | |||
| }; | |||
| client.Move(msgS); | |||
| @@ -996,7 +996,7 @@ namespace Client | |||
| MoveMsg msgD = new() | |||
| { | |||
| PlayerId = playerID, | |||
| TimeInMilliseconds = 50, | |||
| TimeInMilliseconds = 25, | |||
| Angle = Math.PI / 2 | |||
| }; | |||
| client.Move(msgD); | |||
| @@ -1006,7 +1006,7 @@ namespace Client | |||
| MoveMsg msgA = new() | |||
| { | |||
| PlayerId = playerID, | |||
| TimeInMilliseconds = 50, | |||
| TimeInMilliseconds = 25, | |||
| Angle = 3 * Math.PI / 2 | |||
| }; | |||
| client.Move(msgA); | |||
| @@ -6,69 +6,6 @@ namespace GameClass.GameObj | |||
| { | |||
| public class Student : Character | |||
| { | |||
| /// <summary> | |||
| /// 遭受攻击 | |||
| /// </summary> | |||
| /// <param name="subHP"></param> | |||
| /// <param name="hasSpear"></param> | |||
| /// <param name="attacker">伤害来源</param> | |||
| /// <returns>人物在受到攻击后死了吗</returns> | |||
| public bool BeAttacked(Bullet bullet) | |||
| { | |||
| #if DEBUG | |||
| Debugger.Output(this, "is being shot!"); | |||
| #endif | |||
| lock (beAttackedLock) | |||
| { | |||
| if (hp <= 0 || NoHp()) | |||
| return false; // 原来已经死了 | |||
| if (bullet.Parent.IsGhost() != this.IsGhost()) | |||
| { | |||
| #if DEBUG | |||
| Debugger.Output(bullet, " 's AP is " + bullet.AP.ToString()); | |||
| #endif | |||
| if (TryUseShield()) | |||
| { | |||
| if (bullet.HasSpear) | |||
| { | |||
| int subHp = TrySubHp(bullet.AP); | |||
| #if DEBUG | |||
| Debugger.Output(this, "is being shot! Now his hp is" + HP.ToString()); | |||
| #endif | |||
| bullet.Parent.AddScore(GameData.TrickerScoreAttackStudent(subHp) + GameData.ScorePropUseSpear); | |||
| bullet.Parent.HP = (int)(bullet.Parent.HP + (bullet.Parent.Vampire * subHp)); | |||
| } | |||
| else | |||
| return false; | |||
| } | |||
| else | |||
| { | |||
| int subHp; | |||
| if (bullet.HasSpear) | |||
| { | |||
| subHp = TrySubHp(bullet.AP + GameData.ApSpearAdd); | |||
| #if DEBUG | |||
| Debugger.Output(this, "is being shot with Spear! Now his hp is" + HP.ToString()); | |||
| #endif | |||
| } | |||
| else | |||
| { | |||
| subHp = TrySubHp(bullet.AP); | |||
| #if DEBUG | |||
| Debugger.Output(this, "is being shot! Now his hp is" + HP.ToString()); | |||
| #endif | |||
| } | |||
| bullet.Parent.AddScore(GameData.TrickerScoreAttackStudent(subHp)); | |||
| bullet.Parent.HP = (int)(bullet.Parent.HP + (bullet.Parent.Vampire * subHp)); | |||
| } | |||
| if (hp <= 0) | |||
| TryActivatingLIFE(); // 如果有复活甲 | |||
| } | |||
| return hp <= 0; | |||
| } | |||
| } | |||
| protected int fixSpeed; | |||
| /// <summary> | |||
| /// 修理电机速度 | |||
| @@ -541,7 +541,7 @@ namespace GameClass.GameObj | |||
| return false; | |||
| } | |||
| } | |||
| protected void TryActivatingLIFE() | |||
| public void TryActivatingLIFE() | |||
| { | |||
| if (buffManager.TryActivatingLIFE()) | |||
| { | |||
| @@ -164,7 +164,7 @@ namespace Gaming | |||
| { | |||
| if (!(player.Commandable()) || player.CharacterType == CharacterType.Robot) | |||
| return false; | |||
| Doorway? doorwayForEscape = (Doorway?)gameMap.OneForInteractInACross(player.Position, GameObjType.Doorway); | |||
| Doorway? doorwayForEscape = (Doorway?)gameMap.OneForInteract(player.Position, GameObjType.Doorway); | |||
| if (doorwayForEscape != null && doorwayForEscape.IsOpen()) | |||
| { | |||
| player.AddScore(GameData.StudentScoreEscape); | |||
| @@ -174,7 +174,7 @@ namespace Gaming | |||
| } | |||
| else | |||
| { | |||
| EmergencyExit? emergencyExit = (EmergencyExit?)gameMap.OneForInteractInACross(player.Position, GameObjType.EmergencyExit); | |||
| EmergencyExit? emergencyExit = (EmergencyExit?)gameMap.OneForInteract(player.Position, GameObjType.EmergencyExit); | |||
| if (emergencyExit != null && emergencyExit.IsOpen) | |||
| { | |||
| ++gameMap.NumOfEscapedStudent; | |||
| @@ -353,12 +353,23 @@ namespace Gaming | |||
| if (windowForClimb == null || windowForClimb.WhoIsClimbing != null) | |||
| return false; | |||
| XY windowToPlayer = new( | |||
| (Math.Abs(player.Position.x - windowForClimb.Position.x) > GameData.numOfPosGridPerCell / 2) ? (GameData.numOfPosGridPerCell / 2 * (player.Position.x > windowForClimb.Position.x ? 1 : -1)) : 0, | |||
| (Math.Abs(player.Position.y - windowForClimb.Position.y) > GameData.numOfPosGridPerCell / 2) ? (GameData.numOfPosGridPerCell / 2 * (player.Position.y > windowForClimb.Position.y ? 1 : -1)) : 0); | |||
| Character? characterInWindow = (Character?)gameMap.OneInTheSameCell(windowForClimb.Position - 2 * windowToPlayer, GameObjType.Character); | |||
| if (characterInWindow != null) | |||
| { | |||
| if (player.IsGhost() && !characterInWindow.IsGhost()) | |||
| characterManager.BeAttacked((Student)(characterInWindow), player.Attack(characterInWindow.Position, PlaceType.Null)); | |||
| return false; | |||
| } | |||
| Wall addWall = new Wall(windowForClimb.Position - 2 * windowToPlayer); | |||
| gameMap.Add(addWall); | |||
| player.PlayerState = PlayerStateType.ClimbingThroughWindows; | |||
| windowForClimb.WhoIsClimbing = player; | |||
| XY windowToPlayer = new XY( | |||
| (Math.Abs(player.Position.x - windowForClimb.Position.x) > GameData.numOfPosGridPerCell / 2) ? (GameData.numOfPosGridPerCell / 2 * (player.Position.x > windowForClimb.Position.x ? 1 : -1)) : 0, | |||
| (Math.Abs(player.Position.y - windowForClimb.Position.y) > GameData.numOfPosGridPerCell / 2) ? (GameData.numOfPosGridPerCell / 2 * (player.Position.y > windowForClimb.Position.y ? 1 : -1)) : 0) | |||
| ; | |||
| new Thread | |||
| ( | |||
| () => | |||
| @@ -396,6 +407,7 @@ namespace Gaming | |||
| player.ReSetPos(PosJumpOff, gameMap.GetPlaceType(PosJumpOff)); | |||
| player.MoveSpeed = player.ReCalculateBuff(BuffType.AddSpeed, player.OrgMoveSpeed, GameData.MaxSpeed, GameData.MinSpeed); | |||
| windowForClimb.WhoIsClimbing = null; | |||
| gameMap.Remove(addWall); | |||
| if (player.PlayerState == PlayerStateType.ClimbingThroughWindows) | |||
| { | |||
| player.PlayerState = PlayerStateType.Null; | |||
| @@ -494,10 +506,12 @@ namespace Gaming | |||
| */ | |||
| private readonly Map gameMap; | |||
| private readonly CharacterManager characterManager; | |||
| public readonly MoveEngine moveEngine; | |||
| public ActionManager(Map gameMap) | |||
| public ActionManager(Map gameMap, CharacterManager characterManager) | |||
| { | |||
| this.gameMap = gameMap; | |||
| this.moveEngine = new MoveEngine( | |||
| gameMap: gameMap, | |||
| OnCollision: (obj, collisionObj, moveVec) => | |||
| @@ -516,6 +530,7 @@ namespace Gaming | |||
| // Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64); | |||
| } | |||
| ); | |||
| this.characterManager = characterManager; | |||
| } | |||
| } | |||
| } | |||
| @@ -50,20 +50,7 @@ namespace Gaming | |||
| if ((!(((Character)objBeingShot).IsGhost())) && bullet.Parent.IsGhost()) | |||
| { | |||
| Student whoBeAttacked = (Student)objBeingShot; | |||
| if (whoBeAttacked.CharacterType == CharacterType.StraightAStudent) | |||
| { | |||
| ((WriteAnswers)whoBeAttacked.FindIActiveSkill(ActiveSkillType.WriteAnswers)).DegreeOfMeditation = 0; | |||
| } | |||
| if (whoBeAttacked.BeAttacked(bullet)) | |||
| { | |||
| characterManager.BeAddictedToGame(whoBeAttacked, (Ghost)bullet.Parent); | |||
| } | |||
| if (whoBeAttacked.CanBeAwed()) | |||
| { | |||
| if (CharacterManager.BeStunned(whoBeAttacked, GameData.basicStunnedTimeOfStudent)) | |||
| bullet.Parent.AddScore(GameData.TrickerScoreStudentBeStunned(GameData.basicStunnedTimeOfStudent)); | |||
| } | |||
| characterManager.BeAttacked((Student)objBeingShot, bullet); | |||
| } | |||
| // if (((Character)objBeingShot).IsGhost() && !bullet.Parent.IsGhost() && bullet.TypeOfBullet == BulletType.Ram) | |||
| // BeStunned((Character)objBeingShot, bullet.AP); | |||
| @@ -134,7 +134,7 @@ namespace Gaming | |||
| { | |||
| if (!noise && XY.Distance(newPlayer.Position, person.Position) <= (newPlayer.AlertnessRadius / person.Concealment)) | |||
| newPlayer.AddBgm(BgmType.GhostIsComing, (double)newPlayer.AlertnessRadius / XY.Distance(newPlayer.Position, person.Position)); | |||
| if (XY.Distance(newPlayer.Position, person.Position) <= GameData.basicViewRange) | |||
| if (newPlayer.CharacterType != CharacterType.Teacher && XY.Distance(newPlayer.Position, person.Position) <= GameData.basicViewRange) | |||
| { | |||
| TimePinningDown += GameData.checkInterval; | |||
| newPlayer.AddScore(GameData.StudentScorePinDown(TimePinningDown) - ScoreAdded); | |||
| @@ -250,6 +250,81 @@ namespace Gaming | |||
| { IsBackground = true }.Start(); | |||
| return true; | |||
| } | |||
| public static bool TryBeAwed(Student character, Bullet bullet) | |||
| { | |||
| if (character.CanBeAwed()) | |||
| { | |||
| if (BeStunned(character, GameData.basicStunnedTimeOfStudent)) | |||
| bullet.Parent.AddScore(GameData.TrickerScoreStudentBeStunned(GameData.basicStunnedTimeOfStudent)); | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| /// <summary> | |||
| /// 遭受攻击 | |||
| /// </summary> | |||
| /// <param name="subHP"></param> | |||
| /// <param name="hasSpear"></param> | |||
| /// <param name="attacker">伤害来源</param> | |||
| /// <returns>人物在受到攻击后死了吗</returns> | |||
| public void BeAttacked(Student student, Bullet bullet) | |||
| { | |||
| #if DEBUG | |||
| Debugger.Output(student, "is being shot!"); | |||
| #endif | |||
| if (student.NoHp()) return; // 原来已经死了 | |||
| if (!bullet.Parent.IsGhost()) return; | |||
| if (student.CharacterType == CharacterType.StraightAStudent) | |||
| { | |||
| ((WriteAnswers)student.FindIActiveSkill(ActiveSkillType.WriteAnswers)).DegreeOfMeditation = 0; | |||
| } | |||
| #if DEBUG | |||
| Debugger.Output(bullet, " 's AP is " + bullet.AP.ToString()); | |||
| #endif | |||
| if (student.TryUseShield()) | |||
| { | |||
| if (bullet.HasSpear) | |||
| { | |||
| int subHp = student.TrySubHp(bullet.AP); | |||
| #if DEBUG | |||
| Debugger.Output(this, "is being shot! Now his hp is" + student.HP.ToString()); | |||
| #endif | |||
| bullet.Parent.AddScore(GameData.TrickerScoreAttackStudent(subHp) + GameData.ScorePropUseSpear); | |||
| bullet.Parent.HP = (int)(bullet.Parent.HP + (bullet.Parent.Vampire * subHp)); | |||
| } | |||
| else return; | |||
| } | |||
| else | |||
| { | |||
| int subHp; | |||
| if (bullet.HasSpear) | |||
| { | |||
| subHp = student.TrySubHp(bullet.AP + GameData.ApSpearAdd); | |||
| #if DEBUG | |||
| Debugger.Output(this, "is being shot with Spear! Now his hp is" + student.HP.ToString()); | |||
| #endif | |||
| } | |||
| else | |||
| { | |||
| subHp = student.TrySubHp(bullet.AP); | |||
| #if DEBUG | |||
| Debugger.Output(this, "is being shot! Now his hp is" + student.HP.ToString()); | |||
| #endif | |||
| } | |||
| bullet.Parent.AddScore(GameData.TrickerScoreAttackStudent(subHp)); | |||
| bullet.Parent.HP = (int)(bullet.Parent.HP + (bullet.Parent.Vampire * subHp)); | |||
| } | |||
| if (student.HP <= 0) | |||
| student.TryActivatingLIFE(); // 如果有复活甲 | |||
| if (student.HP <= 0) | |||
| BeAddictedToGame(student, (Ghost)bullet.Parent); | |||
| else TryBeAwed(student, bullet); | |||
| } | |||
| public static bool BackSwing(Character? player, int time) | |||
| { | |||
| if (player == null || time <= 0) return false; | |||
| @@ -393,7 +393,7 @@ namespace Gaming | |||
| characterManager = new CharacterManager(gameMap); | |||
| attackManager = new AttackManager(gameMap, characterManager); | |||
| actionManager = new ActionManager(gameMap); | |||
| actionManager = new ActionManager(gameMap, characterManager); | |||
| propManager = new PropManager(gameMap); | |||
| skillManager = new SkillManager(gameMap, actionManager, attackManager, propManager, characterManager); | |||
| } | |||
| @@ -147,10 +147,10 @@ namespace Gaming | |||
| { | |||
| if (character.IsGhost() && | |||
| (character.PlayerState == PlayerStateType.TryingToAttack || character.PlayerState == PlayerStateType.Swinging | |||
| || character.PlayerState == PlayerStateType.UsingSkill || character.PlayerState == PlayerStateType.LockingOrOpeningTheDoor || character.PlayerState == PlayerStateType.OpeningTheChest) | |||
| || character.PlayerState == PlayerStateType.UsingSkill) | |||
| && gameMap.CanSee(player, character)) | |||
| { | |||
| if (CharacterManager.BeStunned(character, GameData.TimeOfGhostFaintingWhenPunish + (player.MaxHp - player.HP) / GameData.timeFactorOfGhostFainting)) | |||
| if (CharacterManager.BeStunned(character, GameData.TimeOfGhostFaintingWhenPunish)) | |||
| player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.TimeOfGhostFaintingWhenPunish + (player.MaxHp - player.HP) / GameData.timeFactorOfGhostFainting)); | |||
| break; | |||
| } | |||
| @@ -31,7 +31,7 @@ namespace Preparation.Interface | |||
| public class Assassin : IGhost | |||
| { | |||
| private const int moveSpeed = (int)(GameData.basicMoveSpeed * 473.0 / 380); | |||
| private const int moveSpeed = (int)(GameData.basicGhostMoveSpeed * 1.1); | |||
| public int MoveSpeed => moveSpeed; | |||
| private const int maxHp = GameData.basicHp; | |||
| @@ -62,7 +62,7 @@ namespace Preparation.Interface | |||
| } | |||
| public class Klee : IGhost | |||
| { | |||
| private const int moveSpeed = (int)(GameData.basicMoveSpeed * 155 / 127); | |||
| private const int moveSpeed = (int)(GameData.basicStudentMoveSpeed * 155 / 127); | |||
| public int MoveSpeed => moveSpeed; | |||
| private const int maxHp = GameData.basicHp; | |||
| @@ -93,7 +93,7 @@ namespace Preparation.Interface | |||
| } | |||
| public class ANoisyPerson : IGhost | |||
| { | |||
| private const int moveSpeed = (int)(GameData.basicMoveSpeed * 1.1); | |||
| private const int moveSpeed = (int)(GameData.basicStudentMoveSpeed * 1.07); | |||
| public int MoveSpeed => moveSpeed; | |||
| private const int maxHp = GameData.basicHp * 12 / 10; | |||
| @@ -124,7 +124,7 @@ namespace Preparation.Interface | |||
| } | |||
| public class Teacher : IStudent | |||
| { | |||
| private const int moveSpeed = GameData.basicMoveSpeed * 3 / 4; | |||
| private const int moveSpeed = GameData.basicStudentMoveSpeed * 3 / 4; | |||
| public int MoveSpeed => moveSpeed; | |||
| private const int maxHp = GameData.basicHp * 10; | |||
| @@ -164,7 +164,7 @@ namespace Preparation.Interface | |||
| } | |||
| public class Athlete : IStudent | |||
| { | |||
| private const int moveSpeed = GameData.basicMoveSpeed * 40 / 38; | |||
| private const int moveSpeed = GameData.basicStudentMoveSpeed * 40 / 38; | |||
| public int MoveSpeed => moveSpeed; | |||
| private const int maxHp = GameData.basicHp * 32 / 30; | |||
| @@ -204,7 +204,7 @@ namespace Preparation.Interface | |||
| } | |||
| public class StraightAStudent : IStudent | |||
| { | |||
| private const int moveSpeed = (int)(GameData.basicMoveSpeed * 0.8); | |||
| private const int moveSpeed = (int)(GameData.basicStudentMoveSpeed * 0.8); | |||
| public int MoveSpeed => moveSpeed; | |||
| private const int maxHp = (int)(GameData.basicHp * 1.1); | |||
| @@ -244,7 +244,7 @@ namespace Preparation.Interface | |||
| } | |||
| public class Robot : IStudent | |||
| { | |||
| private const int moveSpeed = (int)(GameData.basicMoveSpeed); | |||
| private const int moveSpeed = (int)(GameData.basicStudentMoveSpeed); | |||
| public int MoveSpeed => moveSpeed; | |||
| private const int maxHp = (int)(GameData.basicHp / 2.5); | |||
| @@ -284,7 +284,7 @@ namespace Preparation.Interface | |||
| } | |||
| public class TechOtaku : IStudent | |||
| { | |||
| private const int moveSpeed = (int)(GameData.basicMoveSpeed * 0.75); | |||
| private const int moveSpeed = (int)(GameData.basicStudentMoveSpeed * 0.75); | |||
| public int MoveSpeed => moveSpeed; | |||
| private const int maxHp = (int)(GameData.basicHp * 0.9); | |||
| @@ -324,7 +324,7 @@ namespace Preparation.Interface | |||
| } | |||
| public class Sunshine : IStudent | |||
| { | |||
| private const int moveSpeed = GameData.basicMoveSpeed; | |||
| private const int moveSpeed = GameData.basicStudentMoveSpeed; | |||
| public int MoveSpeed => moveSpeed; | |||
| private const int maxHp = GameData.basicHp * 32 / 30; | |||
| @@ -97,10 +97,11 @@ namespace Preparation.Utility | |||
| public const int basicTimeOfRescue = 1000; | |||
| #if DEBUG | |||
| public const int basicMoveSpeed = 9000;// 基本移动速度,单位:s-1 | |||
| public const int basicStudentMoveSpeed = 9000;// 基本移动速度,单位:s-1 | |||
| #else | |||
| public const int basicMoveSpeed = 1270; | |||
| public const int basicStudentMoveSpeed = 1270; | |||
| #endif | |||
| public const int basicGhostMoveSpeed = (int)(basicStudentMoveSpeed * 45.0 / 38); | |||
| public const int characterMaxSpeed = 12000; // 最大速度 | |||
| @@ -181,7 +182,7 @@ namespace Preparation.Utility | |||
| public const int basicBulletMoveSpeed = 1800; // 基本子弹移动速度,单位:s-1 | |||
| public const double basicRemoteAttackRange = 3000; // 基本远程攻击范围 | |||
| public const double basicAttackShortRange = 900; // 基本近程攻击范围 | |||
| public const double basicAttackShortRange = 1100; // 基本近程攻击范围 | |||
| public const double basicBulletBombRange = 1000; // 基本子弹爆炸范围 | |||
| #endregion | |||
| #region 技能相关 | |||
| @@ -1,6 +1,6 @@ | |||
| @echo off | |||
| start cmd /k ..\Server\bin\Debug\net6.0\Server.exe --ip 0.0.0.0 --port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --fileName test | |||
| start cmd /k ..\Server\bin\Debug\net6.0\Server.exe --ip 0.0.0.0 --port 8888 --studentCount 2 --trickerCount 1 --gameTimeInSecond 600 --fileName test | |||
| ping -n 2 127.0.0.1 > NUL | |||
| @@ -25,8 +25,8 @@ | |||
| - 地图上的每个格子有自己的区域类型:墙、草地、电机、出口、紧急出口、门、窗、箱子 | |||
| ### 交互 | |||
| - 除了逃离和翻窗,交互目标与交互者在一个九宫格内则为可交互 | |||
| - 逃离或翻窗时玩家应当在目标前后左右一个格子内 | |||
| - 除了翻窗,交互目标与交互者在一个九宫格内则为可交互 | |||
| - 翻窗时玩家应当在目标前后左右一个格子内 | |||
| ### 破译与逃脱 | |||
| - 每张地图都有10台电机,求生者需要破译其中的7台,并开启任意一个大门(总所需时间为18秒)后从任意一个开启的大门逃脱,亦或者在只剩1名求生者的情况下从紧急出口逃脱; | |||
| @@ -430,7 +430,9 @@ | |||
| public int SkillCD => GameData.commonSkillCD; | |||
| public int DurationTime => 0; | |||
| ~~~ | |||
| 使用瞬间,在可视范围内的使用技能状态中、攻击前后摇、开锁门、开箱的捣蛋鬼会被眩晕(3070+ 玩家损失的血量 / 1000)ms, | |||
| 使用瞬间,在可视范围内的使用技能状态中、攻击前后摇的捣蛋鬼会被眩晕(3070)ms, | |||
| - 特性 | |||
| 教师无法获得牵制得分 | |||
| #### 学霸 | |||
| - 被动技能 | |||