feat: ✨ add the judgment of the end ofthe Game, and implement Skills "CanBeginToCharge" and "Punish" again
tags/0.1.0
| @@ -37,8 +37,14 @@ namespace GameClass.GameObj | |||
| } | |||
| public override bool CanBeBombed(GameObjType gameObjType) | |||
| { | |||
| if (gameObjType == GameObjType.Character) return true; | |||
| return false; | |||
| switch (gameObjType) | |||
| { | |||
| case GameObjType.Character: | |||
| case GameObjType.Generator: | |||
| return true; | |||
| default: | |||
| return false; | |||
| } | |||
| } | |||
| public override BulletType TypeOfBullet => BulletType.CommonAttackOfGhost; | |||
| @@ -76,8 +82,13 @@ namespace GameClass.GameObj | |||
| } | |||
| public override bool CanBeBombed(GameObjType gameObjType) | |||
| { | |||
| if (gameObjType == GameObjType.Character) return true; | |||
| return false; | |||
| switch (gameObjType) | |||
| { | |||
| case GameObjType.Character: | |||
| return true; | |||
| default: | |||
| return false; | |||
| } | |||
| } | |||
| public override BulletType TypeOfBullet => BulletType.FlyingKnife; | |||
| @@ -5,61 +5,103 @@ namespace GameClass.GameObj | |||
| { | |||
| public class BecomeVampire : IActiveSkill // 化身吸血鬼 | |||
| { | |||
| public int SkillCD => GameData.commonSkillCD / 3 * 4; | |||
| public int SkillCD => GameData.commonSkillCD * 4 / 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 CanBeginToCharge : IActiveSkill | |||
| { | |||
| public int SkillCD => GameData.commonSkillCD / 5; | |||
| public int DurationTime => GameData.commonSkillTime / 10 * 6; | |||
| public int DurationTime => GameData.commonSkillTime * 6 / 10; | |||
| private readonly object commonSkillLock = new object(); | |||
| public object ActiveSkillLock => commonSkillLock; | |||
| public bool isBeingUsed = false; | |||
| public bool IsBeingUsed | |||
| { | |||
| get => isBeingUsed; set => isBeingUsed = value; | |||
| } | |||
| } | |||
| public class BecomeInvisible : IActiveSkill | |||
| { | |||
| public int SkillCD => GameData.commonSkillCD; | |||
| public int DurationTime => GameData.commonSkillTime / 10 * 6; | |||
| public int DurationTime => GameData.commonSkillTime * 6 / 10; | |||
| private readonly object commonSkillLock = new object(); | |||
| public object ActiveSkillLock => commonSkillLock; | |||
| public bool isBeingUsed = false; | |||
| public bool IsBeingUsed | |||
| { | |||
| get => isBeingUsed; set => isBeingUsed = value; | |||
| } | |||
| } | |||
| public class Punish : IActiveSkill | |||
| { | |||
| public int SkillCD => GameData.commonSkillCD; | |||
| public int DurationTime => GameData.commonSkillTime / 10 * 6; | |||
| public int DurationTime => 0; | |||
| private readonly object commonSkillLock = new object(); | |||
| public object ActiveSkillLock => commonSkillLock; | |||
| public bool isBeingUsed = false; | |||
| public bool IsBeingUsed | |||
| { | |||
| get => isBeingUsed; set => isBeingUsed = value; | |||
| } | |||
| } | |||
| public class NuclearWeapon : IActiveSkill // 核武器 | |||
| { | |||
| public int SkillCD => GameData.commonSkillCD / 3 * 7; | |||
| public int SkillCD => GameData.commonSkillCD * 7 / 3; | |||
| public int DurationTime => GameData.commonSkillTime / 10; | |||
| private readonly object commonSkillLock = new object(); | |||
| public object ActiveSkillLock => commonSkillLock; | |||
| public bool isBeingUsed = false; | |||
| public bool IsBeingUsed | |||
| { | |||
| get => isBeingUsed; set => isBeingUsed = value; | |||
| } | |||
| } | |||
| public class UseKnife : IActiveSkill | |||
| { | |||
| public int SkillCD => GameData.commonSkillCD / 3 * 2; | |||
| public int SkillCD => GameData.commonSkillCD * 2 / 3; | |||
| public int DurationTime => GameData.commonSkillTime / 10; | |||
| private readonly object commonSkillLock = new object(); | |||
| public object ActiveSkillLock => commonSkillLock; | |||
| public bool isBeingUsed = false; | |||
| public bool IsBeingUsed | |||
| { | |||
| get => isBeingUsed; set => isBeingUsed = value; | |||
| } | |||
| } | |||
| public class SuperFast : IActiveSkill // 3倍速 | |||
| { | |||
| public int SkillCD => GameData.commonSkillCD; | |||
| public int DurationTime => GameData.commonSkillTime / 10 * 4; | |||
| public int DurationTime => GameData.commonSkillTime * 4 / 10; | |||
| private readonly object commonSkillLock = new object(); | |||
| public object ActiveSkillLock => commonSkillLock; | |||
| public bool isBeingUsed = false; | |||
| public bool IsBeingUsed | |||
| { | |||
| get => isBeingUsed; set => isBeingUsed = value; | |||
| } | |||
| } | |||
| public class NullSkill : IActiveSkill | |||
| @@ -68,6 +110,12 @@ namespace GameClass.GameObj | |||
| 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 = false; | |||
| } | |||
| } | |||
| public static class SkillFactory | |||
| @@ -21,7 +21,9 @@ namespace GameClass.GameObj | |||
| set | |||
| { | |||
| lock (lockForNum) | |||
| { | |||
| numOfRepairedGenerators = value; | |||
| } | |||
| } | |||
| } | |||
| private uint numOfDeceasedStudent = 0; | |||
| @@ -31,7 +33,13 @@ namespace GameClass.GameObj | |||
| set | |||
| { | |||
| lock (lockForNum) | |||
| { | |||
| numOfDeceasedStudent = value; | |||
| if (numOfDeceasedStudent + numOfEscapedStudent == GameData.numOfStudent) | |||
| { | |||
| Timer.IsGaming = false; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| private uint numOfEscapedStudent = 0; | |||
| @@ -41,7 +49,13 @@ namespace GameClass.GameObj | |||
| set | |||
| { | |||
| lock (lockForNum) | |||
| { | |||
| numOfEscapedStudent = value; | |||
| if (numOfDeceasedStudent + numOfEscapedStudent == GameData.numOfStudent) | |||
| { | |||
| Timer.IsGaming = false; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -235,6 +249,50 @@ namespace GameClass.GameObj | |||
| } | |||
| return GameObjForInteract; | |||
| } | |||
| public bool CanSee(XY pos1, XY pos2, int viewRange) | |||
| { | |||
| XY del = pos1 - pos2; | |||
| if (del * del > viewRange * viewRange) return false; | |||
| if (del.x > del.y) | |||
| { | |||
| if (GetPlaceType(pos1) == PlaceType.Grass && GetPlaceType(pos2) == PlaceType.Grass) | |||
| { | |||
| for (int x = GameData.PosGridToCellX(pos1) + GameData.numOfPosGridPerCell; x < GameData.PosGridToCellX(pos2); x += GameData.numOfPosGridPerCell) | |||
| { | |||
| if (GetPlaceType(pos1 + del * (x / del.x)) != PlaceType.Grass) | |||
| return false; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| for (int x = GameData.PosGridToCellX(pos1) + GameData.numOfPosGridPerCell; x < GameData.PosGridToCellX(pos2); x += GameData.numOfPosGridPerCell) | |||
| { | |||
| if (GetPlaceType(pos1 + del * (x / del.x)) == PlaceType.Wall) | |||
| return false; | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if (GetPlaceType(pos1) == PlaceType.Grass && GetPlaceType(pos2) == PlaceType.Grass) | |||
| { | |||
| for (int y = GameData.PosGridToCellY(pos1) + GameData.numOfPosGridPerCell; y < GameData.PosGridToCellY(pos2); y += GameData.numOfPosGridPerCell) | |||
| { | |||
| if (GetPlaceType(pos1 + del * (y / del.y)) != PlaceType.Grass) | |||
| return false; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| for (int y = GameData.PosGridToCellY(pos1) + GameData.numOfPosGridPerCell; y < GameData.PosGridToCellY(pos2); y += GameData.numOfPosGridPerCell) | |||
| { | |||
| if (GetPlaceType(pos1 + del * (y / del.y)) == PlaceType.Wall) | |||
| return false; | |||
| } | |||
| } | |||
| } | |||
| return true; | |||
| } | |||
| public Map(uint[,] mapResource) | |||
| { | |||
| gameObjDict = new Dictionary<GameObjType, IList<IGameObj>>(); | |||
| @@ -11,7 +11,15 @@ namespace GameClass.GameObj | |||
| public class GameTimer : ITimer | |||
| { | |||
| private bool isGaming = false; | |||
| public bool IsGaming => isGaming; | |||
| public bool IsGaming | |||
| { | |||
| get => isGaming; | |||
| set | |||
| { | |||
| lock (isGamingLock) | |||
| isGaming = value; | |||
| } | |||
| } | |||
| readonly object isGamingLock = new(); | |||
| @@ -15,6 +15,15 @@ namespace Gaming | |||
| { | |||
| // 人物移动 | |||
| private void SkillWhenMove(Character player, IGameObj collisionObj) | |||
| { | |||
| if (player.UseIActiveSkill(ActiveSkillType.CanBeginToCharge).IsBeingUsed && collisionObj.Type == GameObjType.Character && ((Character)collisionObj).IsGhost()) | |||
| { | |||
| if (AttackManager.BeStunned((Character)collisionObj, GameData.TimeOfGhostFaintingWhenCharge)) | |||
| player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.TimeOfGhostFaintingWhenCharge)); | |||
| AttackManager.BeStunned(player, GameData.TimeOfStudentFaintingWhenCharge); | |||
| } | |||
| } | |||
| public bool MovePlayer(Character playerToMove, int moveTimeInMilliseconds, double moveDirection) | |||
| { | |||
| if (!playerToMove.Commandable()) return false; | |||
| @@ -479,6 +488,7 @@ namespace Gaming | |||
| gameMap: gameMap, | |||
| OnCollision: (obj, collisionObj, moveVec) => | |||
| { | |||
| SkillWhenMove((Character)obj, collisionObj); | |||
| //if (collisionObj is Mine) | |||
| //{ | |||
| // ActivateMine((Character)obj, (Mine)collisionObj); | |||
| @@ -71,8 +71,9 @@ namespace Gaming | |||
| { IsBackground = true }.Start(); | |||
| } | |||
| public static void BeStunned(Character player, int time) | |||
| public static bool BeStunned(Character player, int time) | |||
| { | |||
| if (player.PlayerState == PlayerStateType.Stunned || player.NoHp()) return false; | |||
| new Thread | |||
| (() => | |||
| { | |||
| @@ -83,6 +84,7 @@ namespace Gaming | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| return true; | |||
| } | |||
| private void Die(Character player) | |||
| @@ -134,20 +136,24 @@ namespace Gaming | |||
| if ((!(((Character)objBeingShot).IsGhost())) && bullet.Parent.IsGhost()) | |||
| { | |||
| Student oneBeAttacked = (Student)objBeingShot; | |||
| if (oneBeAttacked.BeAttacked(bullet)) | |||
| Student whoBeAttacked = (Student)objBeingShot; | |||
| if (whoBeAttacked.BeAttacked(bullet)) | |||
| { | |||
| BeAddictedToGame(oneBeAttacked, (Ghost)bullet.Parent); | |||
| BeAddictedToGame(whoBeAttacked, (Ghost)bullet.Parent); | |||
| } | |||
| if (oneBeAttacked.CanBeAwed()) | |||
| if (whoBeAttacked.CanBeAwed()) | |||
| { | |||
| bullet.Parent.AddScore(GameData.TrickerScoreStudentBeStunned); | |||
| BeStunned(oneBeAttacked, GameData.basicStunnedTimeOfStudent); | |||
| if (BeStunned(whoBeAttacked, GameData.basicStunnedTimeOfStudent)) | |||
| bullet.Parent.AddScore(GameData.TrickerScoreStudentBeStunned); | |||
| } | |||
| } | |||
| // if (((Character)objBeingShot).IsGhost() && !bullet.Parent.IsGhost() && bullet.TypeOfBullet == BulletType.Ram) | |||
| // BeStunned((Character)objBeingShot, bullet.AP); | |||
| break; | |||
| case GameObjType.Generator: | |||
| if (bullet.CanBeBombed(GameObjType.Generator)) | |||
| ((Generator)objBeingShot).DegreeOfRepair -= bullet.AP * GameData.factorDamageGenerator; | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| @@ -36,49 +36,10 @@ namespace Gaming | |||
| return ActiveSkillEffect(skill, player, () => | |||
| { | |||
| player.AddMoveSpeed(skill.DurationTime, 3.0); | |||
| new Thread | |||
| ( | |||
| () => | |||
| { | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => player.Commandable() && gameMap.Timer.IsGaming, | |||
| loopToDo: () => | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); | |||
| try | |||
| { | |||
| foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) | |||
| { | |||
| if (character.IsGhost() != player.IsGhost() && Math.Max(XY.Distance(player.Position, character.Position), XY.Distance(player.Position + new XY(player.FacingDirection, player.Radius), character.Position)) <= character.Radius + player.Radius + GameData.tolerancesLength) | |||
| { | |||
| AttackManager.BeStunned(character, GameData.TimeOfGhostFaintingWhenCharge); | |||
| player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.TimeOfGhostFaintingWhenCharge)); | |||
| AttackManager.BeStunned(player, GameData.TimeOfStudentFaintingWhenCharge); | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| finally | |||
| { | |||
| gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); | |||
| } | |||
| }, | |||
| timeInterval: GameData.frameDuration, | |||
| finallyReturn: () => 0, | |||
| maxTotalDuration: skill.DurationTime | |||
| ) | |||
| .Start(); | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| //See SkillWhenMove in ActionManager | |||
| }, | |||
| () => | |||
| { | |||
| double tempVam = player.Vampire - 0.5; | |||
| player.Vampire = tempVam < player.OriVampire ? player.OriVampire : tempVam; | |||
| }); | |||
| { }); | |||
| } | |||
| @@ -125,10 +86,10 @@ namespace Gaming | |||
| { | |||
| foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) | |||
| { | |||
| if (player.IsGhost() && XY.Distance(player.Position, character.Position) <= player.ViewRange) | |||
| if (player.IsGhost() && gameMap.CanSee(player.Position, character.Position, player.ViewRange)) | |||
| { | |||
| AttackManager.BeStunned(character, GameData.TimeOfGhostFaintingWhenPunish + (player.MaxHp - player.HP) / GameData.TimeFactorOfGhostFainting); | |||
| player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.TimeOfGhostFaintingWhenPunish + (player.MaxHp - player.HP) / GameData.TimeFactorOfGhostFainting)); | |||
| if (AttackManager.BeStunned(character, GameData.TimeOfGhostFaintingWhenPunish + (player.MaxHp - player.HP) / GameData.TimeFactorOfGhostFainting)) | |||
| player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.TimeOfGhostFaintingWhenPunish + (player.MaxHp - player.HP) / GameData.TimeFactorOfGhostFainting)); | |||
| break; | |||
| } | |||
| } | |||
| @@ -167,6 +128,7 @@ namespace Gaming | |||
| (() => | |||
| { | |||
| startSkill(); | |||
| activeSkill.IsBeingUsed = true; | |||
| new FrameRateTaskExecutor<int>( | |||
| () => !player.IsResetting, | |||
| () => | |||
| @@ -184,6 +146,7 @@ namespace Gaming | |||
| .Start(); | |||
| endSkill(); | |||
| activeSkill.IsBeingUsed = false; | |||
| Debugger.Output(player, "return to normal."); | |||
| new FrameRateTaskExecutor<int>( | |||
| @@ -97,7 +97,7 @@ namespace Preparation.Interface | |||
| public int timeOfOpeningOrLocking = GameData.basicSpeedOfOpeningOrLocking; | |||
| public int TimeOfOpeningOrLocking => timeOfOpeningOrLocking; | |||
| public int speedOfClimbingThroughWindows = GameData.basicStudentSpeedOfClimbingThroughWindows * 9 / 10; | |||
| public int speedOfClimbingThroughWindows = GameData.basicStudentSpeedOfClimbingThroughWindows / 2; | |||
| public int SpeedOfClimbingThroughWindows => speedOfClimbingThroughWindows; | |||
| public int timeOfOpenChest = GameData.basicSpeedOfOpenChest; | |||
| @@ -11,5 +11,6 @@ | |||
| public int SkillCD { get; } | |||
| public int DurationTime { get; } //技能持续时间 | |||
| public object ActiveSkillLock { get; } | |||
| public bool IsBeingUsed { get; set; } | |||
| } | |||
| } | |||
| @@ -3,7 +3,7 @@ namespace Preparation.Interface | |||
| { | |||
| public interface ITimer | |||
| { | |||
| bool IsGaming { get; } | |||
| bool IsGaming { get; set; } | |||
| public bool StartGame(int timeInMilliseconds); | |||
| } | |||
| } | |||
| @@ -46,7 +46,7 @@ namespace Preparation.Utility | |||
| { | |||
| return pos.y / numOfPosGridPerCell; | |||
| } | |||
| public static XY PosGridToCellXY(XY pos) // 求坐标所在的格子的y坐标 | |||
| public static XY PosGridToCellXY(XY pos) // 求坐标所在的格子的xy坐标 | |||
| { | |||
| return new XY(pos.x / numOfPosGridPerCell, pos.y / numOfPosGridPerCell); | |||
| } | |||
| @@ -90,7 +90,7 @@ namespace Preparation.Utility | |||
| public const int characterMaxSpeed = 12000; // 最大速度 | |||
| public const double basicConcealment = 1.0; | |||
| public const int basicAlertnessRadius = 30700; | |||
| public const int basicAlertnessRadius = 10700; | |||
| public const int basicViewRange = 5 * numOfPosGridPerCell; | |||
| public const int maxNumOfPropInPropInventory = 3; | |||
| @@ -148,7 +148,10 @@ namespace Preparation.Utility | |||
| public const int basicApOfGhost = 1500000; // 捣蛋鬼攻击力 | |||
| public const int MinAP = 0; // 最小攻击力 | |||
| public const int MaxAP = int.MaxValue; // 最大攻击力 | |||
| public const int basicBulletMoveSpeed = 2700; // 基本子弹移动速度,单位:s-1 | |||
| public const int factorDamageGenerator = 2;//子弹对电机的破坏=factorDamageGenerator*AP; | |||
| public const int bulletRadius = 200; // 默认子弹半径 | |||
| public const int basicBulletNum = 3; // 基本初始子弹量 | |||
| public const int basicCD = 3000; // 初始子弹冷却 | |||
| public const int basicCastTime = 500;//基本前摇时间 | |||
| @@ -156,8 +159,7 @@ namespace Preparation.Utility | |||
| public const int basicRecoveryFromHit = 4300;//基本命中攻击恢复时长 | |||
| public const int basicStunnedTimeOfStudent = 4130; | |||
| public const int bulletRadius = 200; // 默认子弹半径 | |||
| public const int basicBulletNum = 3; // 基本初始子弹量 | |||
| public const int basicBulletMoveSpeed = 2700; // 基本子弹移动速度,单位:s-1 | |||
| public const double basicRemoteAttackRange = 9000; // 基本远程攻击范围 | |||
| public const double basicAttackShortRange = 2700; // 基本近程攻击范围 | |||
| public const double basicBulletBombRange = 3000; // 基本子弹爆炸范围 | |||
| @@ -184,6 +184,8 @@ namespace Server | |||
| { | |||
| case Protobuf.StudentType.Athlete: | |||
| return Preparation.Utility.CharacterType.Athlete; | |||
| case StudentType._2: | |||
| return Preparation.Utility.CharacterType.Teacher; | |||
| default: | |||
| return Preparation.Utility.CharacterType.Null; | |||
| } | |||
| @@ -363,7 +363,6 @@ | |||
| { | |||
| private const int moveSpeed = GameData.basicMoveSpeed * 473 / 380; | |||
| private const int maxHp = GameData.basicHp; | |||
| public const int maxBulletNum = 1; | |||
| public BulletType InitBullet => BulletType.CommonAttackOfGhost; | |||
| @@ -378,17 +377,124 @@ | |||
| public int timeOfOpenChest = GameData.basicSpeedOfOpenChest; | |||
| } | |||
| ~~~ | |||
| - 普通攻击为 CommonAttackOfGhost | |||
| ~~~csharp | |||
| public CommonAttackOfGhost... | |||
| { | |||
| public override double BulletBombRange => 0; | |||
| public override double BulletAttackRange => GameData.basicAttackShortRange; | |||
| public int ap = GameData.basicApOfGhost; | |||
| public override int Speed => GameData.basicBulletMoveSpeed; | |||
| public override bool IsToBomb => false; | |||
| public override int CastTime => GameData.basicCastTime; | |||
| public override int Backswing => GameData.basicBackswing; | |||
| public override int RecoveryFromHit => GameData.basicRecoveryFromHit; | |||
| public const int cd = GameData.basicBackswing; | |||
| public override bool CanBeBombed(GameObjType gameObjType) | |||
| { | |||
| switch (gameObjType) | |||
| { | |||
| case GameObjType.Character: | |||
| case GameObjType.Generator: | |||
| return true; | |||
| default: | |||
| return false; | |||
| } | |||
| } | |||
| } | |||
| ~~~ | |||
| - 主动技能 | |||
| - 隐身 | |||
| ~~~csharp | |||
| public int SkillCD => GameData.commonSkillCD; | |||
| public int DurationTime => GameData.commonSkillTime / 10 * 6; | |||
| ~~~ | |||
| 在DurationTime时间内玩家隐身 | |||
| - 使用飞刀 | |||
| ~~~csharp | |||
| public int SkillCD => GameData.commonSkillCD* 2 / 3 ; | |||
| public int DurationTime => GameData.commonSkillTime / 10; | |||
| ~~~ | |||
| 在DurationTime时间内,攻击类型变为飞刀 | |||
| ~~~csharp | |||
| internal sealed class FlyingKnife : Bullet | |||
| { | |||
| public override double BulletBombRange => 0; | |||
| public override double BulletAttackRange => GameData.basicRemoteAttackRange * 13; | |||
| public int ap = GameData.basicApOfGhost * 4 / 5; | |||
| public override int Speed => GameData.basicBulletMoveSpeed * 2; | |||
| public override bool IsToBomb => false; | |||
| public override int CastTime => GameData.basicCastTime; | |||
| public override int Backswing => GameData.basicBackswing * 2 / 5; | |||
| public override int RecoveryFromHit => GameData.basicBackswing * 3 / 4; | |||
| public const int cd = GameData.basicBackswing * 2 / 5 + 100; | |||
| public override bool CanBeBombed(GameObjType gameObjType) | |||
| { | |||
| if (gameObjType == GameObjType.Character) return true; | |||
| return false; | |||
| } | |||
| } | |||
| ~~~ | |||
| ### 学生(&老师) | |||
| #### 运动员 | |||
| ~~~csharp | |||
| private const int moveSpeed = GameData.basicMoveSpeed * 40 / 38; | |||
| private const int maxHp = GameData.basicHp * 32 / 30; | |||
| public const int maxBulletNum = 0; | |||
| public BulletType InitBullet => BulletType.Null; | |||
| public List<ActiveSkillType> ListOfIActiveSkill => new(new ActiveSkillType[] { ActiveSkillType.CanBeginToCharge }); | |||
| public List<PassiveSkillType> ListOfIPassiveSkill => new(new PassiveSkillType[] { }); | |||
| public const int fixSpeed = GameData.basicFixSpeed * 6 / 10; | |||
| int treatSpeed = GameData.basicTreatSpeed * 8 / 10; | |||
| public const double concealment = GameData.basicConcealment * 0.9; | |||
| int alertnessRadius = (int)(GameData.basicAlertnessRadius * 0.9); | |||
| int viewRange = (int)(GameData.basicViewRange * 1.1); | |||
| int timeOfOpeningOrLocking = GameData.basicSpeedOfOpeningOrLocking * 12 / 10; | |||
| int speedOfClimbingThroughWindows = GameData.basicStudentSpeedOfClimbingThroughWindows * 12 / 10; | |||
| int timeOfOpenChest = GameData.basicSpeedOfOpenChest; | |||
| ~~~ | |||
| - 主动技能 | |||
| - 冲撞 | |||
| ~~~csharp | |||
| public int SkillCD => GameData.commonSkillCD / 5; | |||
| public int DurationTime => GameData.commonSkillTime * 6 / 10; | |||
| ~~~ | |||
| 在DurationTime内,速度变为三倍,期间撞到捣蛋鬼,会导致捣蛋鬼眩晕7.22s,学生眩晕2.09s | |||
| #### 教师 | |||
| ~~~csharp | |||
| private const int moveSpeed = GameData.basicMoveSpeed * 3 / 4; | |||
| int maxHp = GameData.basicHp * 10; | |||
| int maxBulletNum = 0; | |||
| BulletType InitBullet => BulletType.Null; | |||
| public List<ActiveSkillType> ListOfIActiveSkill => new(new ActiveSkillType[] { ActiveSkillType.Punish }); | |||
| public List<PassiveSkillType> ListOfIPassiveSkill => new(new PassiveSkillType[] { }); | |||
| public const int fixSpeed = 0; | |||
| int treatSpeed = GameData.basicTreatSpeed; | |||
| double concealment = GameData.basicConcealment * 0.5; | |||
| int alertnessRadius = GameData.basicAlertnessRadius / 2; | |||
| int viewRange = GameData.basicViewRange * 9 / 10; | |||
| int timeOfOpeningOrLocking = GameData.basicSpeedOfOpeningOrLocking; | |||
| int speedOfClimbingThroughWindows = GameData.basicStudentSpeedOfClimbingThroughWindows /2; | |||
| int timeOfOpenChest = GameData.basicSpeedOfOpenChest; | |||
| ~~~ | |||
| - 主动技能 | |||
| - 惩罚 | |||
| ~~~csharp | |||
| public int SkillCD => GameData.commonSkillCD; | |||
| public int DurationTime => 0; | |||
| ~~~ | |||
| 使用瞬间,在视野范围内的捣蛋鬼会被眩晕(3070+ 玩家损失的血量 / 1000)ms, | |||
| ## 游戏数据 | |||
| @@ -426,7 +532,7 @@ | |||
| { | |||
| return pos.y / numOfPosGridPerCell; | |||
| } | |||
| public static XY PosGridToCellXY(XY pos) // 求坐标所在的格子的y坐标 | |||
| public static XY PosGridToCellXY(XY pos) // 求坐标所在的格子的Xy坐标 | |||
| { | |||
| return new XY(pos.x / numOfPosGridPerCell, pos.y / numOfPosGridPerCell); | |||
| } | |||
| @@ -456,7 +562,7 @@ | |||
| public const int basicBulletMoveSpeed = 2700; // 基本子弹移动速度,单位:s-1 | |||
| public const double basicConcealment = 1.0; | |||
| public const int basicAlertnessRadius = 30700; | |||
| public const int basicAlertnessRadius = 10700; | |||
| public const int basicViewRange = 5 * numOfPosGridPerCell; | |||
| public const int maxNumOfPropInPropInventory = 3; | |||
| ~~~ | |||
| @@ -500,14 +606,17 @@ | |||
| public const int MinAP = 0; // 最小攻击力 | |||
| public const int MaxAP = int.MaxValue; // 最大攻击力 | |||
| public const int factorDamageGenerator = 2;//子弹对电机的破坏=factorDamageGenerator*AP; | |||
| public const int bulletRadius = 200; // 默认子弹半径 | |||
| public const int basicBulletNum = 3; // 基本初始子弹量 | |||
| public const int basicCD = 3000; // 初始子弹冷却 | |||
| public const int basicCastTime = 500;//基本前摇时间 | |||
| public const int basicBackswing = 818;//基本后摇时间 | |||
| public const int basicRecoveryFromHit = 4300;//基本命中攻击恢复时长 | |||
| public const int basicStunnedTimeOfStudent = 4130; | |||
| public const int bulletRadius = 200; // 默认子弹半径 | |||
| public const int basicBulletNum = 3; // 基本初始子弹量 | |||
| public const int basicBulletMoveSpeed = 2700; // 基本子弹移动速度,单位:s-1 | |||
| public const double basicRemoteAttackRange = 9000; // 基本远程攻击范围 | |||
| public const double basicAttackShortRange = 2700; // 基本近程攻击范围 | |||
| public const double basicBulletBombRange = 3000; // 基本子弹爆炸范围 | |||
| @@ -526,7 +635,7 @@ | |||
| public const int PropRadius = numOfPosGridPerCell / 2; | |||
| public const int PropMoveSpeed = 3000; | |||
| public const int PropMaxMoveDistance = 15 * numOfPosGridPerCell; | |||
| public const long PropProduceTime = 10000; | |||
| public const long PropProduceTime = 20000; | |||
| public const int PropDuration = 10000; | |||
| public const int ApPropAdd = basicApOfGhost * 12 / 10; | |||