fix: 🐛 fix the initialization about JumpyDumpty and fix the AttackDistance
tags/v0.1.0
| @@ -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 次 | |||
| #### 攻击 | |||
| @@ -89,13 +89,14 @@ $$ | |||
| 8. 翻窗 Climbing | |||
| ### 攻击 | |||
| - 攻击距离是指攻击(子弹)的移动距离,也就是说理论上最远被攻击的学生的中心与捣蛋鬼的中心=学生的半径+捣蛋鬼的半径+攻击距离+子弹半径(200)*2 | |||
| - 攻击类型CommonAttackOfTricker攻击未写完的作业,会造成对应攻击力的损坏 | |||
| - 捣蛋鬼攻击交互状态或前后摇的学生,将使学生眩晕4.3s | |||
| | 攻击(子弹)类型 |搞蛋鬼的一般攻击CommonAttackOfTricker| 飞刀FlyingKnife | 蹦蹦炸弹BombBomb | 小炸弹JumpyDumpty | | |||
| | :------------ | :--------------------- | :--------------------- | :--------------------- | :--------------------- | | |||
| | 子弹爆炸范围 | 0 | 0 | 2000 | 1000 | | |||
| | 子弹攻击距离 | 2200 | 78000 | 2200 | 4400 | | |||
| | 爆炸范围 | 0 | 0 | 2000 | 1000 | | |||
| | 攻击距离 | 2200 | 78000 | 2200 | 4400 | | |||
| | 攻击力 | 1500000 | 1200000 | 1800000 | 900000 | | |||
| | 移动速度/s | 7400 | 18500 | 6000 | 8600 | | |||
| | 前摇(ms) | 297 | 400 | 366 | - | | |||
| @@ -11,11 +11,21 @@ | |||
| # 5月6日12点更新 | |||
| - hotfix: 修复了突然的bug(物件锁的相关问题) | |||
| - rule:增加了每帧最多50条主动指令的限制 | |||
| - rule:增加了每帧最多50条主动指令的限制 | |||
| # 5月8日更新 | |||
| - feat:增加了可选地图功能 | |||
| - feat:增加了可选地图功能 | |||
| - **脚本RunServer(ForDebug).cmd/sh现在支持可选地图功能,但想选择地图,选手需要自行参照使用文档修改命令行或在云盘下载脚本** | |||
| # 5月9日19:30更新 | |||
| - docs:更新了 游戏机制与平衡性调整更新草案.pdf | |||
| - change:更改了地图的文件路径 | |||
| # 最新更新 | |||
| - docs:更新了 游戏机制与平衡性调整更新草案.pdf | |||
| - fix:修复JumpyDumpty的初始位置错误的问题 | |||
| - fix:修正和重新说明攻击距离 | |||
| - **攻击距离是指攻击(子弹)的移动距离,也就是说理论上最远被攻击的学生的中心与捣蛋鬼的中心=学生的半径+捣蛋鬼的半径+攻击距离+子弹半径(200)×2** | |||
| - hotfix:修复小炸弹初始化类型错误的问题 | |||
| - remove:去除了“实际上唤醒或勉励不同的人是有效的” | |||
| - **重复发出同一类型的交互指令和移动指令是无效的** | |||
| - feat&fix:修复并**将`SendMessage`改为`SendTextMessage`与`SendBinaryMessage`** | |||
| @@ -10,7 +10,7 @@ namespace GameClass.GameObj | |||
| { | |||
| } | |||
| public override double BulletBombRange => 0; | |||
| public override double BulletAttackRange => GameData.basicAttackShortRange; | |||
| public override double AttackDistance => GameData.basicAttackShortRange; | |||
| public int ap = GameData.basicApOfGhost; | |||
| public override int AP | |||
| { | |||
| @@ -24,7 +24,7 @@ namespace GameClass.GameObj | |||
| public override int Speed => GameData.basicBulletMoveSpeed; | |||
| public override bool IsRemoteAttack => false; | |||
| public override int CastTime => (int)BulletAttackRange * 1000 / Speed; | |||
| public override int CastTime => (int)AttackDistance * 1000 / Speed; | |||
| public override int Backswing => GameData.basicBackswing; | |||
| public override int RecoveryFromHit => GameData.basicRecoveryFromHit; | |||
| public const int cd = GameData.basicBackswing; | |||
| @@ -57,7 +57,7 @@ namespace GameClass.GameObj | |||
| { | |||
| } | |||
| public override double BulletBombRange => 0; | |||
| public override double BulletAttackRange => GameData.basicRemoteAttackRange * 13; | |||
| public override double AttackDistance => GameData.basicRemoteAttackRange * 13; | |||
| public int ap = GameData.basicApOfGhost * 4 / 5; | |||
| public override int AP | |||
| { | |||
| @@ -104,7 +104,7 @@ namespace GameClass.GameObj | |||
| { | |||
| } | |||
| public override double BulletBombRange => GameData.basicBulletBombRange; | |||
| public override double BulletAttackRange => GameData.basicAttackShortRange; | |||
| public override double AttackDistance => GameData.basicAttackShortRange; | |||
| public int ap = (int)(GameData.basicApOfGhost * 6.0 / 5); | |||
| public override int AP | |||
| { | |||
| @@ -118,7 +118,7 @@ namespace GameClass.GameObj | |||
| public override int Speed => (int)(GameData.basicBulletMoveSpeed * 30 / 37); | |||
| public override bool IsRemoteAttack => false; | |||
| public override int CastTime => (int)(BulletAttackRange * 1000 / Speed); | |||
| public override int CastTime => (int)(AttackDistance * 1000 / Speed); | |||
| public override int Backswing => GameData.basicRecoveryFromHit; | |||
| public override int RecoveryFromHit => GameData.basicRecoveryFromHit; | |||
| public const int cd = GameData.basicCD; | |||
| @@ -149,7 +149,7 @@ namespace GameClass.GameObj | |||
| { | |||
| } | |||
| public override double BulletBombRange => GameData.basicBulletBombRange / 2; | |||
| public override double BulletAttackRange => GameData.basicAttackShortRange * 2; | |||
| public override double AttackDistance => GameData.basicAttackShortRange * 2; | |||
| public int ap = (int)(GameData.basicApOfGhost * 0.6); | |||
| public override int AP | |||
| { | |||
| @@ -9,7 +9,7 @@ namespace GameClass.GameObj | |||
| { | |||
| } | |||
| public override double BulletBombRange => 0; | |||
| public override double BulletAttackRange => 0; | |||
| public override double AttackDistance => 0; | |||
| public override int AP => 7220; | |||
| public override int Speed => 0; | |||
| public override bool IsRemoteAttack => false; | |||
| @@ -10,7 +10,7 @@ namespace GameClass.GameObj | |||
| /// //攻击力 | |||
| /// </summary> | |||
| public abstract double BulletBombRange { get; } | |||
| public abstract double BulletAttackRange { get; } | |||
| public abstract double AttackDistance { get; } | |||
| public abstract int AP { get; set; } | |||
| public abstract int Speed { get; } | |||
| public abstract bool IsRemoteAttack { get; } | |||
| @@ -56,9 +56,9 @@ namespace GameClass.GameObj | |||
| public static class BulletFactory | |||
| { | |||
| public static Bullet? GetBullet(Character character, XY pos) | |||
| public static Bullet? GetBullet(Character character, XY pos, BulletType bulletType) | |||
| { | |||
| switch (character.BulletOfPlayer) | |||
| switch (bulletType) | |||
| { | |||
| case BulletType.FlyingKnife: | |||
| return new FlyingKnife(character, pos); | |||
| @@ -1,8 +1,6 @@ | |||
| using Preparation.Utility; | |||
| using Preparation.Interface; | |||
| using System.Collections.Generic; | |||
| using System; | |||
| using System.Numerics; | |||
| namespace GameClass.GameObj | |||
| { | |||
| @@ -8,9 +8,6 @@ namespace GameClass.GameObj | |||
| public partial class Character : Moveable, ICharacter // 负责人LHR摆烂终了 | |||
| { | |||
| #region 装弹、攻击相关的基本属性及方法 | |||
| private readonly object attackLock = new(); | |||
| public object AttackLock => attackLock; | |||
| /// <summary> | |||
| /// 装弹冷却 | |||
| /// </summary> | |||
| @@ -19,7 +16,7 @@ namespace GameClass.GameObj | |||
| { | |||
| get | |||
| { | |||
| lock (attackLock) | |||
| lock (actionLock) | |||
| { | |||
| return cd; | |||
| } | |||
| @@ -33,14 +30,14 @@ namespace GameClass.GameObj | |||
| { | |||
| get | |||
| { | |||
| lock (attackLock) | |||
| lock (actionLock) | |||
| { | |||
| return bulletOfPlayer; | |||
| } | |||
| } | |||
| set | |||
| { | |||
| lock (attackLock) | |||
| lock (actionLock) | |||
| { | |||
| bulletOfPlayer = value; | |||
| cd = OrgCD = (BulletFactory.BulletCD(value)); | |||
| @@ -55,7 +52,7 @@ namespace GameClass.GameObj | |||
| { | |||
| get | |||
| { | |||
| lock (attackLock) | |||
| lock (actionLock) | |||
| { | |||
| return maxBulletNum; | |||
| } | |||
| @@ -66,7 +63,7 @@ namespace GameClass.GameObj | |||
| public int UpdateBulletNum(int time) | |||
| { | |||
| lock (attackLock) | |||
| lock (actionLock) | |||
| { | |||
| if (bulletNum < maxBulletNum) | |||
| { | |||
| @@ -84,7 +81,7 @@ namespace GameClass.GameObj | |||
| /// <returns>攻击操作发出的子弹</returns> | |||
| public Bullet? Attack(double angle, int time) | |||
| { | |||
| lock (attackLock) | |||
| lock (actionLock) | |||
| { | |||
| if (bulletOfPlayer == BulletType.Null) | |||
| return null; | |||
| @@ -92,14 +89,16 @@ namespace GameClass.GameObj | |||
| { | |||
| if (bulletNum == maxBulletNum) updateTimeOfBulletNum = time; | |||
| --bulletNum; | |||
| XY res = Position + new XY // 子弹紧贴人物生成。 | |||
| ( | |||
| (int)(Math.Abs((Radius + BulletFactory.BulletRadius(bulletOfPlayer)) * Math.Cos(angle))) * ((Math.Cos(angle) > 0) ? 1 : -1), | |||
| (int)(Math.Abs((Radius + BulletFactory.BulletRadius(bulletOfPlayer)) * Math.Sin(angle))) * ((Math.Sin(angle) > 0) ? 1 : -1) | |||
| (int)(Math.Abs((Radius + BulletFactory.BulletRadius(bulletOfPlayer)) * Math.Cos(angle))) * Math.Sign(Math.Cos(angle)), | |||
| (int)(Math.Abs((Radius + BulletFactory.BulletRadius(bulletOfPlayer)) * Math.Sin(angle))) * Math.Sign(Math.Sin(angle)) | |||
| ); | |||
| Bullet? bullet = BulletFactory.GetBullet(this, res); | |||
| Bullet? bullet = BulletFactory.GetBullet(this, res, this.bulletOfPlayer); | |||
| if (bullet == null) return null; | |||
| facingDirection = new(angle, bullet.BulletAttackRange); | |||
| bullet.AP += TryAddAp() ? GameData.ApPropAdd : 0; | |||
| facingDirection = new(angle, bullet.AttackDistance); | |||
| return bullet; | |||
| } | |||
| else | |||
| @@ -305,63 +304,88 @@ 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; | |||
| private long threadNum = 0; | |||
| public long ThreadNum => threadNum; | |||
| public void ChangePlayerState(PlayerStateType value = PlayerStateType.Null, GameObj? gameObj = null) | |||
| public long ChangePlayerState(PlayerStateType value = PlayerStateType.Null, GameObj? gameObj = null) | |||
| { | |||
| lock (moveObjLock) | |||
| lock (actionLock) | |||
| { | |||
| ++threadNum; | |||
| whatInteractingWith = gameObj; | |||
| if (value != PlayerStateType.Moving) | |||
| IsMoving = false; | |||
| playerState = (value == PlayerStateType.Moving) ? PlayerStateType.Null : value; | |||
| //Debugger.Output(this,playerState.ToString()+" "+IsMoving.ToString()); | |||
| return ++stateNum; | |||
| } | |||
| } | |||
| public void ChangePlayerStateInOneThread(PlayerStateType value = PlayerStateType.Null, GameObj? gameObj = null) | |||
| public long ChangePlayerStateInOneThread(PlayerStateType value = PlayerStateType.Null, GameObj? gameObj = null) | |||
| { | |||
| lock (moveObjLock) | |||
| lock (actionLock) | |||
| { | |||
| whatInteractingWith = gameObj; | |||
| if (value != PlayerStateType.Moving) | |||
| IsMoving = false; | |||
| playerState = (value == PlayerStateType.Moving) ? PlayerStateType.Null : value; | |||
| //Debugger.Output(this,playerState.ToString()+" "+IsMoving.ToString()); | |||
| return stateNum; | |||
| } | |||
| } | |||
| public void SetPlayerStateNaturally() | |||
| public long SetPlayerStateNaturally() | |||
| { | |||
| lock (moveObjLock) | |||
| lock (actionLock) | |||
| { | |||
| ++threadNum; | |||
| whatInteractingWith = null; | |||
| IsMoving = false; | |||
| playerState = PlayerStateType.Null; | |||
| return ++stateNum; | |||
| } | |||
| } | |||
| @@ -370,11 +394,11 @@ namespace GameClass.GameObj | |||
| MoveReaderWriterLock.EnterWriteLock(); | |||
| try | |||
| { | |||
| lock (moveObjLock) | |||
| lock (actionLock) | |||
| { | |||
| playerState = playerStateType; | |||
| canMove = false; | |||
| isResetting = true; | |||
| isRemoved = true; | |||
| position = GameData.PosWhoDie; | |||
| } | |||
| } | |||
| @@ -623,7 +647,7 @@ namespace GameClass.GameObj | |||
| public override ShapeType Shape => ShapeType.Circle; | |||
| public override bool IgnoreCollideExecutor(IGameObj targetObj) | |||
| { | |||
| if (IsResetting) | |||
| if (IsRemoved) | |||
| return true; | |||
| if (targetObj.Type == GameObjType.Prop) | |||
| { | |||
| @@ -6,17 +6,30 @@ namespace GameClass.GameObj | |||
| { | |||
| public abstract class Moveable : GameObj, IMoveable | |||
| { | |||
| protected readonly object moveObjLock = new(); | |||
| public object MoveLock => moveObjLock; | |||
| protected readonly object actionLock = new(); | |||
| public object ActionLock => actionLock; | |||
| private readonly ReaderWriterLockSlim moveReaderWriterLock = new(); | |||
| public ReaderWriterLockSlim MoveReaderWriterLock => moveReaderWriterLock; | |||
| //规定moveReaderWriterLock>moveObjLock | |||
| protected long stateNum = 0; | |||
| public long StateNum | |||
| { | |||
| get | |||
| { | |||
| lock (actionLock) | |||
| return stateNum; | |||
| } | |||
| set | |||
| { | |||
| lock (actionLock) stateNum = value; | |||
| } | |||
| } | |||
| //规定moveReaderWriterLock>actionLock | |||
| public override XY Position | |||
| { | |||
| get | |||
| { | |||
| lock (moveObjLock) | |||
| lock (actionLock) | |||
| return position; | |||
| } | |||
| } | |||
| @@ -25,7 +38,7 @@ namespace GameClass.GameObj | |||
| { | |||
| get | |||
| { | |||
| lock (moveObjLock) | |||
| lock (actionLock) | |||
| return facingDirection; | |||
| } | |||
| } | |||
| @@ -35,12 +48,12 @@ namespace GameClass.GameObj | |||
| { | |||
| get | |||
| { | |||
| lock (moveObjLock) | |||
| lock (actionLock) | |||
| return isMoving; | |||
| } | |||
| set | |||
| { | |||
| lock (moveObjLock) | |||
| lock (actionLock) | |||
| { | |||
| isMoving = value; | |||
| } | |||
| @@ -51,7 +64,7 @@ namespace GameClass.GameObj | |||
| public long MovingSetPos(XY moveVec) | |||
| { | |||
| if (moveVec.x != 0 || moveVec.y != 0) | |||
| lock (moveObjLock) | |||
| lock (actionLock) | |||
| { | |||
| facingDirection = moveVec; | |||
| this.position += moveVec; | |||
| @@ -61,7 +74,7 @@ namespace GameClass.GameObj | |||
| public void ReSetPos(XY position) | |||
| { | |||
| lock (moveObjLock) | |||
| lock (actionLock) | |||
| { | |||
| this.position = position; | |||
| } | |||
| @@ -88,7 +101,7 @@ namespace GameClass.GameObj | |||
| moveReaderWriterLock.EnterWriteLock(); | |||
| try | |||
| { | |||
| lock (moveObjLock) | |||
| lock (actionLock) | |||
| { | |||
| canMove = value; | |||
| } | |||
| @@ -99,15 +112,15 @@ namespace GameClass.GameObj | |||
| } | |||
| } | |||
| protected bool isResetting; | |||
| public bool IsResetting | |||
| protected bool isRemoved; | |||
| public bool IsRemoved | |||
| { | |||
| get | |||
| { | |||
| moveReaderWriterLock.EnterReadLock(); | |||
| try | |||
| { | |||
| return isResetting; | |||
| return isRemoved; | |||
| } | |||
| finally | |||
| { | |||
| @@ -116,7 +129,22 @@ namespace GameClass.GameObj | |||
| } | |||
| } | |||
| public bool IsAvailable => !IsMoving && CanMove && !IsResetting; // 是否能接收指令 | |||
| public bool IsAvailableForMove // 是否能接收移动指令 | |||
| { | |||
| get | |||
| { | |||
| moveReaderWriterLock.EnterReadLock(); | |||
| try | |||
| { | |||
| lock (actionLock) | |||
| return !isMoving && canMove && !isRemoved; | |||
| } | |||
| finally | |||
| { | |||
| moveReaderWriterLock.ExitReadLock(); | |||
| } | |||
| } | |||
| } | |||
| protected int moveSpeed; | |||
| /// <summary> | |||
| @@ -141,7 +169,7 @@ namespace GameClass.GameObj | |||
| moveReaderWriterLock.EnterWriteLock(); | |||
| try | |||
| { | |||
| lock (moveObjLock) | |||
| lock (actionLock) | |||
| { | |||
| moveSpeed = value; | |||
| } | |||
| @@ -167,7 +195,7 @@ namespace GameClass.GameObj | |||
| this.FacingDirection = new XY(1, 0); | |||
| isMoving = false; | |||
| CanMove = false; | |||
| IsResetting = true; | |||
| IsRemoved = true; | |||
| this.Position = birthPos; | |||
| this.Place= place; | |||
| } | |||
| @@ -73,24 +73,21 @@ namespace GameEngine | |||
| obj.MovingSetPos(new XY(moveVec, maxLen)); | |||
| } | |||
| public void MoveObj(IMoveable obj, int moveTime, double direction) | |||
| public void MoveObj(IMoveable obj, int moveTime, double direction, long threadNum) | |||
| { | |||
| if (obj.IsMoving) // 已经移动的物体不能再移动 | |||
| return; | |||
| if (!obj.IsAvailable || !gameTimer.IsGaming) | |||
| return; | |||
| long threadNum = (obj.Type == GameObjType.Character) ? ((ICharacter)obj).ThreadNum : 0;//对人特殊处理 | |||
| if (!gameTimer.IsGaming) return; | |||
| lock (obj.ActionLock) | |||
| { | |||
| if (!obj.IsAvailableForMove) return; | |||
| obj.IsMoving = true; | |||
| } | |||
| new Thread | |||
| ( | |||
| () => | |||
| { | |||
| lock (obj.MoveLock) | |||
| obj.IsMoving = true; | |||
| double moveVecLength = 0.0; | |||
| XY res = new(direction, moveVecLength); | |||
| double deltaLen = moveVecLength - Math.Sqrt(obj.MovingSetPos(res)); // 转向,并用deltaLen存储行走的误差 | |||
| double deltaLen = 0; // 转向,并用deltaLen存储行走的误差 | |||
| IGameObj? collisionObj = null; | |||
| bool isDestroyed = false; | |||
| @@ -119,14 +116,14 @@ namespace GameEngine | |||
| if (!isDestroyed) | |||
| { | |||
| new FrameRateTaskExecutor<int>( | |||
| () => gameTimer.IsGaming && obj.CanMove && !obj.IsResetting && obj.IsMoving, | |||
| () => gameTimer.IsGaming && obj.CanMove && !obj.IsRemoved && obj.IsMoving, | |||
| () => | |||
| { | |||
| moveVecLength = obj.MoveSpeed / GameData.numOfStepPerSecond; | |||
| res = new XY(direction, moveVecLength); | |||
| //对人特殊处理 | |||
| if (threadNum > 0 && ((ICharacter)obj).ThreadNum != threadNum) return false; | |||
| if (threadNum > 0 && obj.StateNum != threadNum) return false; | |||
| // 越界情况处理:如果越界,则与越界方块碰撞 | |||
| bool flag; // 循环标志 | |||
| @@ -147,7 +144,7 @@ namespace GameEngine | |||
| isDestroyed = true; | |||
| return false; | |||
| case AfterCollision.MoveMax: | |||
| if (threadNum == 0 || ((ICharacter)obj).ThreadNum == threadNum) | |||
| if (threadNum == 0 || obj.StateNum == threadNum) | |||
| MoveMax(obj, res); | |||
| moveVecLength = 0; | |||
| res = new XY(direction, moveVecLength); | |||
| @@ -155,7 +152,7 @@ namespace GameEngine | |||
| } | |||
| } while (flag); | |||
| if (threadNum == 0 || ((ICharacter)obj).ThreadNum == threadNum) | |||
| if (threadNum == 0 || obj.StateNum == threadNum) | |||
| deltaLen += moveVecLength - Math.Sqrt(obj.MovingSetPos(res)); | |||
| return true; | |||
| @@ -174,7 +171,7 @@ namespace GameEngine | |||
| res = new XY(direction, moveVecLength); | |||
| if ((collisionObj = collisionChecker.CheckCollisionWhenMoving(obj, res)) == null) | |||
| { | |||
| if (threadNum == 0 || ((ICharacter)obj).ThreadNum == threadNum) | |||
| if (threadNum == 0 || obj.StateNum == threadNum) | |||
| obj.MovingSetPos(res); | |||
| } | |||
| else | |||
| @@ -189,7 +186,7 @@ namespace GameEngine | |||
| isDestroyed = true; | |||
| break; | |||
| case AfterCollision.MoveMax: | |||
| if (threadNum == 0 || ((ICharacter)obj).ThreadNum == threadNum) | |||
| if (threadNum == 0 || obj.StateNum == threadNum) | |||
| MoveMax(obj, res); | |||
| moveVecLength = 0; | |||
| res = new XY(direction, moveVecLength); | |||
| @@ -202,7 +199,7 @@ namespace GameEngine | |||
| { | |||
| Thread.Sleep(leftTime); // 多移动的在这里补回来 | |||
| } | |||
| lock (obj.MoveLock) | |||
| lock (obj.ActionLock) | |||
| obj.IsMoving = false; // 结束移动 | |||
| EndMove(obj); | |||
| return 0; | |||
| @@ -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,9 +37,8 @@ namespace Gaming | |||
| { | |||
| if (moveTimeInMilliseconds < 5) return false; | |||
| if (!playerToMove.Commandable()) return false; | |||
| if (playerToMove.IsMoving) return false; | |||
| characterManager.SetPlayerState(playerToMove, PlayerStateType.Moving); | |||
| moveEngine.MoveObj(playerToMove, moveTimeInMilliseconds, moveDirection); | |||
| moveEngine.MoveObj(playerToMove, moveTimeInMilliseconds, moveDirection, | |||
| characterManager.SetPlayerState(playerToMove, PlayerStateType.Moving)); | |||
| return true; | |||
| } | |||
| @@ -47,7 +46,7 @@ namespace Gaming | |||
| { | |||
| if (!playerToMove.Commandable() && playerToMove.PlayerState != PlayerStateType.Stunned) return false; | |||
| characterManager.BeStunned(playerToMove, moveTimeInMilliseconds); | |||
| moveEngine.MoveObj(playerToMove, moveTimeInMilliseconds, moveDirection); | |||
| moveEngine.MoveObj(playerToMove, moveTimeInMilliseconds, moveDirection, playerToMove.StateNum); | |||
| return true; | |||
| } | |||
| @@ -72,14 +71,14 @@ namespace Gaming | |||
| ++generatorForFix.NumOfFixing; | |||
| characterManager.SetPlayerState(player, PlayerStateType.Fixing); | |||
| long threadNum = player.ThreadNum; | |||
| long threadNum = player.StateNum; | |||
| new Thread | |||
| ( | |||
| () => | |||
| { | |||
| Thread.Sleep(GameData.frameDuration); | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => gameMap.Timer.IsGaming && threadNum == player.ThreadNum, | |||
| loopCondition: () => gameMap.Timer.IsGaming && threadNum == player.StateNum, | |||
| loopToDo: () => | |||
| { | |||
| if (generatorForFix.Repair(player.FixSpeed * GameData.frameDuration, player)) | |||
| @@ -173,10 +172,10 @@ namespace Gaming | |||
| { | |||
| characterManager.SetPlayerState(playerTreated, PlayerStateType.Treated); | |||
| characterManager.SetPlayerState(player, PlayerStateType.Treating); | |||
| long threadNum = player.ThreadNum; | |||
| long threadNum = player.StateNum; | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => playerTreated.PlayerState == PlayerStateType.Treated && threadNum == player.ThreadNum && gameMap.Timer.IsGaming, | |||
| loopCondition: () => playerTreated.PlayerState == PlayerStateType.Treated && threadNum == player.StateNum && gameMap.Timer.IsGaming, | |||
| loopToDo: () => | |||
| { | |||
| if (playerTreated.AddDegreeOfTreatment(GameData.frameDuration * player.TreatSpeed, player)) | |||
| @@ -187,7 +186,7 @@ namespace Gaming | |||
| ) | |||
| .Start(); | |||
| if (threadNum == player.ThreadNum) characterManager.SetPlayerState(player); | |||
| if (threadNum == player.StateNum) characterManager.SetPlayerState(player); | |||
| else if (playerTreated.PlayerState == PlayerStateType.Treated) characterManager.SetPlayerState(playerTreated); | |||
| } | |||
| ) | |||
| @@ -205,14 +204,14 @@ namespace Gaming | |||
| return false; | |||
| characterManager.SetPlayerState(player, PlayerStateType.Rescuing); | |||
| characterManager.SetPlayerState(playerRescued, PlayerStateType.Rescued); | |||
| long threadNum = player.ThreadNum; | |||
| long threadNum = player.StateNum; | |||
| new Thread | |||
| ( | |||
| () => | |||
| { | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => playerRescued.PlayerState == PlayerStateType.Rescued && threadNum == player.ThreadNum && gameMap.Timer.IsGaming, | |||
| loopCondition: () => playerRescued.PlayerState == PlayerStateType.Rescued && threadNum == player.StateNum && gameMap.Timer.IsGaming, | |||
| loopToDo: () => | |||
| { | |||
| playerRescued.TimeOfRescue += GameData.frameDuration; | |||
| @@ -234,7 +233,7 @@ namespace Gaming | |||
| else | |||
| characterManager.SetPlayerState(playerRescued, PlayerStateType.Addicted); | |||
| } | |||
| if (threadNum == player.ThreadNum) characterManager.SetPlayerState(player); | |||
| if (threadNum == player.StateNum) characterManager.SetPlayerState(player); | |||
| playerRescued.TimeOfRescue = 0; | |||
| } | |||
| ) | |||
| @@ -303,14 +302,14 @@ namespace Gaming | |||
| // gameMap.Add(addWall); | |||
| characterManager.SetPlayerState(player, PlayerStateType.ClimbingThroughWindows); | |||
| long threadNum = player.ThreadNum; | |||
| long threadNum = player.StateNum; | |||
| windowForClimb.WhoIsClimbing = player; | |||
| new Thread | |||
| ( | |||
| () => | |||
| { | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => threadNum == player.ThreadNum && gameMap.Timer.IsGaming, | |||
| loopCondition: () => threadNum == player.StateNum && gameMap.Timer.IsGaming, | |||
| loopToDo: () => { }, | |||
| timeInterval: GameData.frameDuration, | |||
| finallyReturn: () => 0, | |||
| @@ -326,10 +325,10 @@ namespace Gaming | |||
| player.ReSetPos(windowToPlayer + windowForClimb.Position); | |||
| player.MoveSpeed = player.SpeedOfClimbingThroughWindows; | |||
| moveEngine.MoveObj(player, (int)(windowToPlayer.Length() * 3.0 * 1000 / player.MoveSpeed), (-1 * windowToPlayer).Angle()); | |||
| moveEngine.MoveObj(player, (int)(windowToPlayer.Length() * 3.0 * 1000 / player.MoveSpeed), (-1 * windowToPlayer).Angle(), threadNum); | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => threadNum == player.ThreadNum && gameMap.Timer.IsGaming, | |||
| loopCondition: () => threadNum == player.StateNum && gameMap.Timer.IsGaming, | |||
| loopToDo: () => | |||
| { | |||
| }, | |||
| @@ -343,7 +342,7 @@ namespace Gaming | |||
| player.MoveSpeed = player.ReCalculateBuff(BuffType.AddSpeed, player.OrgMoveSpeed, GameData.MaxSpeed, GameData.MinSpeed); | |||
| windowForClimb.WhoIsClimbing = null; | |||
| // gameMap.Remove(addWall); | |||
| if (threadNum == player.ThreadNum) | |||
| if (threadNum == player.StateNum) | |||
| { | |||
| characterManager.SetPlayerState(player); | |||
| } | |||
| @@ -386,13 +385,13 @@ namespace Gaming | |||
| if (!flag) return false; | |||
| characterManager.SetPlayerState(player, PlayerStateType.LockingOrOpeningTheDoor); | |||
| long threadNum = player.ThreadNum; | |||
| long threadNum = player.StateNum; | |||
| new Thread | |||
| ( | |||
| () => | |||
| { | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => flag && threadNum == player.ThreadNum && gameMap.Timer.IsGaming && doorToLock.OpenOrLockDegree < GameData.degreeOfLockingOrOpeningTheDoor, | |||
| loopCondition: () => flag && threadNum == player.StateNum && gameMap.Timer.IsGaming && doorToLock.OpenOrLockDegree < GameData.degreeOfLockingOrOpeningTheDoor, | |||
| loopToDo: () => | |||
| { | |||
| flag = ((gameMap.PartInTheSameCell(doorToLock.Position, GameObjType.Character)) == null); | |||
| @@ -407,7 +406,7 @@ namespace Gaming | |||
| { | |||
| doorToLock.IsOpen = (!doorToLock.IsOpen); | |||
| } | |||
| if (threadNum == player.ThreadNum) | |||
| if (threadNum == player.StateNum) | |||
| characterManager.SetPlayerState(player); | |||
| doorToLock.OpenOrLockDegree = 0; | |||
| } | |||
| @@ -39,6 +39,17 @@ namespace Gaming | |||
| this.characterManager = characterManager; | |||
| } | |||
| public void ProduceBulletNaturally(BulletType bulletType, Character player, double angle, XY pos) | |||
| { | |||
| // 子弹如果没有和其他物体碰撞,将会一直向前直到超出人物的attackRange | |||
| if (bulletType == BulletType.Null) return; | |||
| Bullet? bullet = BulletFactory.GetBullet(player, pos, bulletType); | |||
| if (bullet == null) return; | |||
| Debugger.Output(bullet, "Attack in " + pos.ToString()); | |||
| gameMap.Add(bullet); | |||
| moveEngine.MoveObj(bullet, (int)(bullet.AttackDistance * 1000 / bullet.MoveSpeed), angle, ++bullet.StateNum); // 这里时间参数除出来的单位要是ms | |||
| } | |||
| private void BombObj(Bullet bullet, GameObj objBeingShot) | |||
| { | |||
| #if DEBUG | |||
| @@ -122,9 +133,21 @@ namespace Gaming | |||
| if (bullet.TypeOfBullet == BulletType.BombBomb && objBeingShot != null) | |||
| { | |||
| bullet.Parent!.BulletOfPlayer = BulletType.JumpyDumpty; | |||
| Attack((Character)bullet.Parent, bullet.FacingDirection.Angle() + Math.PI / 2.0); | |||
| Attack((Character)bullet.Parent, bullet.FacingDirection.Angle() + Math.PI * 3.0 / 2.0); | |||
| double angle = bullet.FacingDirection.Angle() + Math.PI / 2.0; | |||
| XY pos = bullet.Position + new XY // 子弹紧贴人物生成。 | |||
| ( | |||
| (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); | |||
| angle = bullet.FacingDirection.Angle() + Math.PI * 3.0 / 2.0; | |||
| pos = bullet.Position + new XY // 子弹紧贴人物生成。 | |||
| ( | |||
| (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); | |||
| } | |||
| var beAttackedList = new List<IGameObj>(); | |||
| @@ -171,19 +194,18 @@ namespace Gaming | |||
| if (bullet != null) | |||
| { | |||
| Debugger.Output(bullet, "Attack in " + bullet.Position.ToString()); | |||
| bullet.AP += player.TryAddAp() ? GameData.ApPropAdd : 0; | |||
| gameMap.Add(bullet); | |||
| moveEngine.MoveObj(bullet, (int)((bullet.BulletAttackRange - player.Radius - BulletFactory.BulletRadius(player.BulletOfPlayer)) * 1000 / bullet.MoveSpeed), angle); // 这里时间参数除出来的单位要是ms | |||
| moveEngine.MoveObj(bullet, (int)(bullet.AttackDistance * 1000 / bullet.MoveSpeed), angle, ++bullet.StateNum); // 这里时间参数除出来的单位要是ms | |||
| if (bullet.CastTime > 0) | |||
| { | |||
| characterManager.SetPlayerState(player, PlayerStateType.TryingToAttack); | |||
| long threadNum = player.ThreadNum; | |||
| long threadNum = player.StateNum; | |||
| new Thread | |||
| (() => | |||
| { | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => threadNum == player.ThreadNum && gameMap.Timer.IsGaming, | |||
| loopCondition: () => threadNum == player.StateNum && gameMap.Timer.IsGaming, | |||
| loopToDo: () => | |||
| { | |||
| }, | |||
| @@ -195,7 +217,7 @@ namespace Gaming | |||
| if (gameMap.Timer.IsGaming) | |||
| { | |||
| if (threadNum == player.ThreadNum) | |||
| if (threadNum == player.StateNum) | |||
| { | |||
| characterManager.SetPlayerState(player); | |||
| } | |||
| @@ -1,5 +1,4 @@ | |||
| using System; | |||
| using System.Threading; | |||
| using System.Threading; | |||
| using GameClass.GameObj; | |||
| using Preparation.Utility; | |||
| using Preparation.Interface; | |||
| @@ -18,37 +17,37 @@ namespace Gaming | |||
| this.gameMap = gameMap; | |||
| } | |||
| public void SetPlayerState(Character player, PlayerStateType value = PlayerStateType.Null, GameObj? gameObj = null) | |||
| public long SetPlayerState(Character player, PlayerStateType value = PlayerStateType.Null, GameObj? gameObj = null) | |||
| { | |||
| lock (player.MoveLock) | |||
| 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(); | |||
| player.ChangePlayerState(value, gameObj); | |||
| break; | |||
| 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; | |||
| player.ChangePlayerState(value, gameObj); | |||
| break; | |||
| return player.ChangePlayerState(value, gameObj); | |||
| case PlayerStateType.Addicted: | |||
| if (value == PlayerStateType.Rescued) | |||
| player.ChangePlayerStateInOneThread(value, gameObj); | |||
| return player.ChangePlayerStateInOneThread(value, gameObj); | |||
| else | |||
| player.ChangePlayerState(value, gameObj); | |||
| break; | |||
| return player.ChangePlayerState(value, gameObj); | |||
| case PlayerStateType.Rescued: | |||
| if (value == PlayerStateType.Addicted) | |||
| player.ChangePlayerStateInOneThread(value, gameObj); | |||
| return player.ChangePlayerStateInOneThread(value, gameObj); | |||
| else | |||
| player.ChangePlayerState(value, gameObj); | |||
| break; | |||
| return player.ChangePlayerState(value, gameObj); | |||
| default: | |||
| player.ChangePlayerState(value, gameObj); | |||
| break; | |||
| if (player.NoHp()) return -1; | |||
| return player.ChangePlayerState(value, gameObj); | |||
| } | |||
| } | |||
| } | |||
| @@ -75,7 +74,7 @@ namespace Gaming | |||
| Thread.Sleep(Math.Max(newPlayer.CD, GameData.checkInterval)); | |||
| long lastTime = Environment.TickCount64; | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => gameMap.Timer.IsGaming && !newPlayer.IsResetting, | |||
| loopCondition: () => gameMap.Timer.IsGaming && !newPlayer.IsRemoved, | |||
| loopToDo: () => | |||
| { | |||
| long nowTime = Environment.TickCount64; | |||
| @@ -133,7 +132,7 @@ namespace Gaming | |||
| } | |||
| } | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => gameMap.Timer.IsGaming && !newPlayer.IsResetting, | |||
| loopCondition: () => gameMap.Timer.IsGaming && !newPlayer.IsRemoved, | |||
| loopToDo: () => | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); | |||
| @@ -246,7 +245,7 @@ namespace Gaming | |||
| } | |||
| } | |||
| SetPlayerState(player, PlayerStateType.Addicted); | |||
| long threadNum = player.ThreadNum; | |||
| long threadNum = player.StateNum; | |||
| new Thread | |||
| (() => | |||
| { | |||
| @@ -254,7 +253,7 @@ namespace Gaming | |||
| Debugger.Output(player, " is addicted "); | |||
| #endif | |||
| new FrameRateTaskExecutor<int>( | |||
| () => threadNum == player.ThreadNum && player.GamingAddiction < player.MaxGamingAddiction && gameMap.Timer.IsGaming, | |||
| () => threadNum == player.StateNum && player.GamingAddiction < player.MaxGamingAddiction && gameMap.Timer.IsGaming, | |||
| () => | |||
| { | |||
| player.GamingAddiction += (player.PlayerState == PlayerStateType.Addicted) ? GameData.frameDuration : 0; | |||
| @@ -276,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.ThreadNum; | |||
| Thread.Sleep(time); | |||
| if (threadNum == player.ThreadNum) | |||
| 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; | |||
| } | |||
| @@ -373,14 +372,14 @@ namespace Gaming | |||
| if (time <= 0) return false; | |||
| if (player.PlayerState == PlayerStateType.Swinging || (!player.Commandable() && player.PlayerState != PlayerStateType.TryingToAttack)) return false; | |||
| SetPlayerState(player, PlayerStateType.Swinging); | |||
| long threadNum = player.ThreadNum; | |||
| long threadNum = player.StateNum; | |||
| new Thread | |||
| (() => | |||
| { | |||
| Thread.Sleep(time); | |||
| if (threadNum == player.ThreadNum) | |||
| if (threadNum == player.StateNum) | |||
| { | |||
| SetPlayerState(player); | |||
| } | |||
| @@ -21,7 +21,7 @@ namespace Gaming | |||
| public void UseProp(Character player, PropType propType) | |||
| { | |||
| if (player.IsResetting || player.CharacterType == CharacterType.Robot) | |||
| if (player.IsRemoved || player.CharacterType == CharacterType.Robot) | |||
| return; | |||
| Prop prop = player.UseProp(propType); | |||
| switch (prop.GetPropType()) | |||
| @@ -73,7 +73,7 @@ namespace Gaming | |||
| /// <returns></returns> | |||
| public bool PickProp(Character player, PropType propType = PropType.Null) | |||
| { | |||
| if (player.IsResetting) | |||
| if (player.IsRemoved) | |||
| return false; | |||
| int indexing = player.IndexingOfAddProp(); | |||
| if (indexing == GameData.maxNumOfPropInPropInventory) | |||
| @@ -118,7 +118,7 @@ namespace Gaming | |||
| public void ThrowProp(Character player, PropType propType) | |||
| { | |||
| if (!gameMap.Timer.IsGaming || player.IsResetting) | |||
| if (!gameMap.Timer.IsGaming || player.IsRemoved) | |||
| return; | |||
| Prop prop = player.UseProp(propType); | |||
| if (prop.GetPropType() == PropType.Null) | |||
| @@ -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; | |||
| } | |||
| @@ -335,7 +335,7 @@ namespace Gaming | |||
| startSkill(); | |||
| activeSkill.IsBeingUsed = true; | |||
| new FrameRateTaskExecutor<int>( | |||
| () => !player.IsResetting, | |||
| () => !player.IsRemoved, | |||
| () => | |||
| { | |||
| player.AddTimeUntilActiveSkillAvailable(activeSkillType, -(int)GameData.frameDuration); | |||
| @@ -355,7 +355,7 @@ namespace Gaming | |||
| Debugger.Output(player, "return to normal."); | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => player.TimeUntilActiveSkillAvailable[activeSkillType] > 0 && !player.IsResetting, | |||
| loopCondition: () => player.TimeUntilActiveSkillAvailable[activeSkillType] > 0 && !player.IsRemoved, | |||
| loopToDo: () => | |||
| { | |||
| player.AddTimeUntilActiveSkillAvailable(activeSkillType, -(int)GameData.frameDuration); | |||
| @@ -22,7 +22,7 @@ namespace Gaming // 被动技能开局时就释放,持续到游戏结束 | |||
| { | |||
| new FrameRateTaskExecutor<int> | |||
| ( | |||
| () => gameMap.Timer.IsGaming && !player.IsResetting, | |||
| () => gameMap.Timer.IsGaming && !player.IsRemoved, | |||
| () => | |||
| { | |||
| if (player.Commandable() && player.PlayerState != PlayerStateType.Fixing) activeSkill.DegreeOfMeditation += learningDegree * GameData.frameDuration; | |||
| @@ -14,7 +14,6 @@ namespace Preparation.Interface | |||
| public BulletType BulletOfPlayer { get; set; } | |||
| public CharacterType CharacterType { get; } | |||
| public int UpdateBulletNum(int time); | |||
| public long ThreadNum { get; } | |||
| public bool IsGhost(); | |||
| } | |||
| @@ -5,11 +5,12 @@ namespace Preparation.Interface | |||
| { | |||
| public interface IMoveable : IGameObj | |||
| { | |||
| object MoveLock { get; } | |||
| object ActionLock { get; } | |||
| public int MoveSpeed { get; } | |||
| public bool IsMoving { get; set; } | |||
| public bool IsResetting { get; } // reviving | |||
| public bool IsAvailable { get; } | |||
| public bool IsRemoved { get; } | |||
| public bool IsAvailableForMove { get; } | |||
| public long StateNum { get; } | |||
| public long MovingSetPos(XY moveVec); | |||
| public void ReSetCanMove(bool value); | |||
| public bool WillCollideWith(IGameObj? targetObj, XY nextPos) // 检查下一位置是否会和目标物碰撞 | |||