| @@ -17,7 +17,7 @@ | |||
| #### 人物 | |||
| - `std::future<bool> EndAllAction()`:可以使不处在不可行动状态中的玩家终止当前行动 | |||
| - 在指令仍在进行时,重复发出同一类型的交互指令和移动指令是无效的,你需要先发出 Stop 指令终止进行的指令 | |||
| - 实际上唤醒或勉励不同的人是有效的 | |||
| - EndAllAction() 及 Move 指令调用数总和一帧内不超过 10 次 | |||
| #### 攻击 | |||
| - `std::future<bool> Attack(double angleInRadian)`:`angleInRadian`为攻击方向 | |||
| @@ -22,7 +22,6 @@ | |||
| - `def EndAllAction(self) -> Future[bool]`:可以使不处在不可行动状态中的玩家终止当前行动 | |||
| - 在指令仍在进行时,重复发出同一类型的交互指令和移动指令是无效的,你需要先发出 Stop 指令终止进行的指令 | |||
| - 实际上唤醒或勉励不同的人是有效的 | |||
| - EndAllAction() 及 Move 指令调用数总和一帧内不超过 10 次 | |||
| #### 攻击 | |||
| @@ -11,10 +11,10 @@ | |||
| # 5月6日12点更新 | |||
| - hotfix: 修复了突然的bug(物件锁的相关问题) | |||
| - rule:增加了每帧最多50条主动指令的限制 | |||
| - rule:增加了每帧最多50条主动指令的限制 | |||
| # 5月8日更新 | |||
| - feat:增加了可选地图功能 | |||
| - feat:增加了可选地图功能 | |||
| - **脚本RunServer(ForDebug).cmd/sh现在支持可选地图功能,但想选择地图,选手需要自行参照使用文档修改命令行或在云盘下载脚本** | |||
| # 5月9日19:30更新 | |||
| @@ -23,5 +23,9 @@ | |||
| # 最新更新 | |||
| - fix:修复JumpyDumpty的初始位置错误的问题 | |||
| - fix:修正和重新说明攻击距离 | |||
| - **攻击距离是指攻击(子弹)的移动距离,也就是说理论上最远被攻击的学生的中心与捣蛋鬼的中心=学生的半径+捣蛋鬼的半径+攻击距离+子弹半径(200)×2** | |||
| - fix:修正和重新说明攻击距离 | |||
| - **攻击距离是指攻击(子弹)的移动距离,也就是说理论上最远被攻击的学生的中心与捣蛋鬼的中心=学生的半径+捣蛋鬼的半径+攻击距离+子弹半径(200)×2** | |||
| - hotfix:修复小炸弹初始化类型错误的问题 | |||
| - remove:去除了“实际上唤醒或勉励不同的人是有效的” | |||
| - **重复发出同一类型的交互指令和移动指令是无效的** | |||
| - feat&fix:修复并**将`SendMessage`改为`SendTextMessage`与`SendBinaryMessage`** | |||
| @@ -304,24 +304,51 @@ namespace GameClass.GameObj | |||
| { | |||
| get | |||
| { | |||
| if (playerState == PlayerStateType.Null && IsMoving) return PlayerStateType.Moving; | |||
| return playerState; | |||
| lock (actionLock) | |||
| { | |||
| if (playerState == PlayerStateType.Null && IsMoving) return PlayerStateType.Moving; | |||
| return playerState; | |||
| } | |||
| } | |||
| } | |||
| public bool NoHp() => (playerState == PlayerStateType.Deceased || playerState == PlayerStateType.Escaped | |||
| || playerState == PlayerStateType.Addicted || playerState == PlayerStateType.Rescued); | |||
| public bool Commandable() => (playerState != PlayerStateType.Deceased && playerState != PlayerStateType.Escaped | |||
| && playerState != PlayerStateType.Addicted && playerState != PlayerStateType.Rescued | |||
| && playerState != PlayerStateType.Swinging && playerState != PlayerStateType.TryingToAttack | |||
| && playerState != PlayerStateType.ClimbingThroughWindows && playerState != PlayerStateType.Stunned); | |||
| public bool InteractingWithMapWithoutMoving() => (playerState == PlayerStateType.LockingOrOpeningTheDoor || playerState == PlayerStateType.Fixing || playerState == PlayerStateType.OpeningTheChest); | |||
| public bool NullOrMoving() => (playerState == PlayerStateType.Null || playerState == PlayerStateType.Moving); | |||
| public bool CanBeAwed() => !(playerState == PlayerStateType.Deceased || playerState == PlayerStateType.Escaped | |||
| || playerState == PlayerStateType.Addicted || playerState == PlayerStateType.Rescued | |||
| || playerState == PlayerStateType.Treated || playerState == PlayerStateType.Stunned | |||
| || playerState == PlayerStateType.Null || playerState == PlayerStateType.Moving); | |||
| public bool NoHp() | |||
| { | |||
| lock (actionLock) | |||
| return (playerState == PlayerStateType.Deceased || playerState == PlayerStateType.Escaped || playerState == PlayerStateType.Addicted || playerState == PlayerStateType.Rescued); | |||
| } | |||
| public bool Commandable() | |||
| { | |||
| lock (actionLock) | |||
| { | |||
| return (playerState != PlayerStateType.Deceased && playerState != PlayerStateType.Escaped | |||
| && playerState != PlayerStateType.Addicted && playerState != PlayerStateType.Rescued | |||
| && playerState != PlayerStateType.Swinging && playerState != PlayerStateType.TryingToAttack | |||
| && playerState != PlayerStateType.ClimbingThroughWindows && playerState != PlayerStateType.Stunned); | |||
| } | |||
| } | |||
| public bool InteractingWithMapWithoutMoving() | |||
| { | |||
| lock (actionLock) | |||
| { | |||
| return (playerState == PlayerStateType.LockingOrOpeningTheDoor || playerState == PlayerStateType.Fixing || playerState == PlayerStateType.OpeningTheChest); | |||
| } | |||
| } | |||
| public bool NullOrMoving() | |||
| { | |||
| lock (actionLock) | |||
| { | |||
| return (playerState == PlayerStateType.Null || playerState == PlayerStateType.Moving); | |||
| } | |||
| } | |||
| public bool CanBeAwed() | |||
| { | |||
| lock (actionLock) | |||
| return !(playerState == PlayerStateType.Deceased || playerState == PlayerStateType.Escaped | |||
| || playerState == PlayerStateType.Addicted || playerState == PlayerStateType.Rescued | |||
| || playerState == PlayerStateType.Treated || playerState == PlayerStateType.Stunned | |||
| || playerState == PlayerStateType.Null || playerState == PlayerStateType.Moving); | |||
| } | |||
| private GameObj? whatInteractingWith = null; | |||
| public GameObj? WhatInteractingWith => whatInteractingWith; | |||
| @@ -21,14 +21,14 @@ namespace Gaming | |||
| { | |||
| if (((Bullet)collisionObj).Parent != player && ((Bullet)collisionObj).TypeOfBullet == BulletType.JumpyDumpty) | |||
| { | |||
| if (characterManager.BeStunned((Character)player, GameData.timeOfStunnedWhenJumpyDumpty)) | |||
| if (characterManager.BeStunned((Character)player, GameData.timeOfStunnedWhenJumpyDumpty) > 0) | |||
| player.AddScore(GameData.TrickerScoreStudentBeStunned(GameData.timeOfStunnedWhenJumpyDumpty)); | |||
| gameMap.Remove((GameObj)collisionObj); | |||
| } | |||
| } | |||
| if (player.FindIActiveSkill(ActiveSkillType.CanBeginToCharge).IsBeingUsed && collisionObj.Type == GameObjType.Character && ((Character)collisionObj).IsGhost()) | |||
| { | |||
| if (characterManager.BeStunned((Character)collisionObj, GameData.timeOfGhostStunnedWhenCharge)) | |||
| if (characterManager.BeStunned((Character)collisionObj, GameData.timeOfGhostStunnedWhenCharge) > 0) | |||
| player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.timeOfGhostStunnedWhenCharge)); | |||
| characterManager.BeStunned(player, GameData.timeOfStudentStunnedWhenCharge); | |||
| } | |||
| @@ -37,7 +37,6 @@ namespace Gaming | |||
| { | |||
| if (moveTimeInMilliseconds < 5) return false; | |||
| if (!playerToMove.Commandable()) return false; | |||
| if (playerToMove.IsMoving) return false; | |||
| moveEngine.MoveObj(playerToMove, moveTimeInMilliseconds, moveDirection, | |||
| characterManager.SetPlayerState(playerToMove, PlayerStateType.Moving)); | |||
| return true; | |||
| @@ -139,7 +139,7 @@ namespace Gaming | |||
| (int)(Math.Abs((bullet.Radius + BulletFactory.BulletRadius(BulletType.JumpyDumpty)) * Math.Cos(angle))) * Math.Sign(Math.Cos(angle)), | |||
| (int)(Math.Abs((bullet.Radius + BulletFactory.BulletRadius(BulletType.JumpyDumpty)) * Math.Sin(angle))) * Math.Sign(Math.Sin(angle)) | |||
| ); | |||
| ProduceBulletNaturally(BulletType.JumpyDumpty, (Character)bullet.Parent, angle, pos); | |||
| ProduceBulletNaturally(BulletType.JumpyDumpty, (Character)bullet.Parent!, angle, pos); | |||
| angle = bullet.FacingDirection.Angle() + Math.PI * 3.0 / 2.0; | |||
| pos = bullet.Position + new XY // 子弹紧贴人物生成。 | |||
| @@ -147,7 +147,7 @@ namespace Gaming | |||
| (int)(Math.Abs((bullet.Radius + BulletFactory.BulletRadius(BulletType.JumpyDumpty)) * Math.Cos(angle))) * Math.Sign(Math.Cos(angle)), | |||
| (int)(Math.Abs((bullet.Radius + BulletFactory.BulletRadius(BulletType.JumpyDumpty)) * Math.Sin(angle))) * Math.Sign(Math.Sin(angle)) | |||
| ); | |||
| ProduceBulletNaturally(BulletType.JumpyDumpty, (Character)bullet.Parent, angle, pos); | |||
| ProduceBulletNaturally(BulletType.JumpyDumpty, (Character)bullet.Parent!, angle, pos); | |||
| } | |||
| var beAttackedList = new List<IGameObj>(); | |||
| @@ -21,12 +21,16 @@ namespace Gaming | |||
| { | |||
| lock (player.ActionLock) | |||
| { | |||
| switch (player.PlayerState) | |||
| PlayerStateType nowPlayerState = player.PlayerState; | |||
| if (nowPlayerState == value) return -1; | |||
| switch (nowPlayerState) | |||
| { | |||
| case PlayerStateType.OpeningTheChest: | |||
| if (player.NoHp()) return -1; | |||
| ((Chest)player.WhatInteractingWith!).StopOpen(); | |||
| return player.ChangePlayerState(value, gameObj); | |||
| case PlayerStateType.OpeningTheDoorway: | |||
| if (player.NoHp()) return -1; | |||
| Doorway doorway = (Doorway)player.WhatInteractingWith!; | |||
| doorway.OpenDegree += gameMap.Timer.nowTime() - doorway.OpenStartTime; | |||
| doorway.OpenStartTime = 0; | |||
| @@ -42,6 +46,7 @@ namespace Gaming | |||
| else | |||
| return player.ChangePlayerState(value, gameObj); | |||
| default: | |||
| if (player.NoHp()) return -1; | |||
| return player.ChangePlayerState(value, gameObj); | |||
| } | |||
| } | |||
| @@ -270,28 +275,28 @@ namespace Gaming | |||
| { IsBackground = true }.Start(); | |||
| } | |||
| public bool BeStunned(Character player, int time) | |||
| public long BeStunned(Character player, int time) | |||
| { | |||
| if (player.PlayerState == PlayerStateType.Stunned || player.NoHp() || player.CharacterType == CharacterType.Robot) return false; | |||
| if (player.CharacterType == CharacterType.Robot) return -1; | |||
| long threadNum = SetPlayerState(player, PlayerStateType.Stunned); | |||
| if (threadNum == -1) return -1; | |||
| new Thread | |||
| (() => | |||
| { | |||
| SetPlayerState(player, PlayerStateType.Stunned); | |||
| long threadNum = player.StateNum; | |||
| Thread.Sleep(time); | |||
| if (threadNum == player.StateNum) | |||
| SetPlayerState(player); | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| return true; | |||
| return threadNum; | |||
| } | |||
| public bool TryBeAwed(Student character, Bullet bullet) | |||
| { | |||
| if (character.CanBeAwed()) | |||
| { | |||
| if (BeStunned(character, GameData.basicStunnedTimeOfStudent)) | |||
| if (BeStunned(character, GameData.basicStunnedTimeOfStudent) > 0) | |||
| bullet.Parent!.AddScore(GameData.TrickerScoreStudentBeStunned(GameData.basicStunnedTimeOfStudent)); | |||
| return true; | |||
| } | |||
| @@ -188,7 +188,7 @@ namespace Gaming | |||
| { | |||
| if (!character.IsGhost() && !character.NoHp() && XY.DistanceFloor3(character.Position, player.Position) <= player.ViewRange) | |||
| { | |||
| if (characterManager.BeStunned(character, GameData.timeOfStudentStunnedWhenHowl)) | |||
| if (characterManager.BeStunned(character, GameData.timeOfStudentStunnedWhenHowl) > 0) | |||
| player.AddScore(GameData.TrickerScoreStudentBeStunned(GameData.timeOfStudentStunnedWhenHowl)); | |||
| } | |||
| } | |||
| @@ -219,7 +219,7 @@ namespace Gaming | |||
| || character.PlayerState == PlayerStateType.UsingSkill || character.PlayerState == PlayerStateType.LockingOrOpeningTheDoor || character.PlayerState == PlayerStateType.ClimbingThroughWindows) | |||
| && gameMap.CanSee(player, character)) | |||
| { | |||
| if (characterManager.BeStunned(character, GameData.timeOfGhostStunnedWhenPunish + GameData.factorOfTimeStunnedWhenPunish * (player.MaxHp - player.HP))) | |||
| if (characterManager.BeStunned(character, GameData.timeOfGhostStunnedWhenPunish + GameData.factorOfTimeStunnedWhenPunish * (player.MaxHp - player.HP)) > 0) | |||
| player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.timeOfGhostStunnedWhenPunish + GameData.factorOfTimeStunnedWhenPunish * (player.MaxHp - player.HP))); | |||
| break; | |||
| } | |||