| @@ -30,6 +30,8 @@ namespace GameClass.GameObj | |||
| public override int RecoveryFromHit => GameData.basicRecoveryFromHit; | |||
| public const int cd = GameData.basicBackswing; | |||
| public override int CD => cd; | |||
| public const int maxBulletNum = 1; | |||
| public override int MaxBulletNum => maxBulletNum; | |||
| public override bool CanAttack(GameObj target) | |||
| { | |||
| @@ -75,6 +77,8 @@ namespace GameClass.GameObj | |||
| public override int RecoveryFromHit => 0; | |||
| public const int cd = GameData.basicBackswing * 2 / 5 + 100; | |||
| public override int CD => cd; | |||
| public const int maxBulletNum = 1; | |||
| public override int MaxBulletNum => maxBulletNum; | |||
| public override bool CanAttack(GameObj target) | |||
| { | |||
| @@ -117,10 +121,12 @@ namespace GameClass.GameObj | |||
| public override bool IsRemoteAttack => false; | |||
| public override int CastTime => (int)BulletAttackRange / Speed; | |||
| public override int Backswing => GameData.basicBackswing; | |||
| public override int RecoveryFromHit => GameData.basicRecoveryFromHit; | |||
| public override int Backswing => 0; | |||
| public override int RecoveryFromHit => 0; | |||
| public const int cd = GameData.basicCD; | |||
| public override int CD => cd; | |||
| public const int maxBulletNum = 1; | |||
| public override int MaxBulletNum => maxBulletNum; | |||
| public override bool CanAttack(GameObj target) | |||
| { | |||
| @@ -166,6 +172,8 @@ namespace GameClass.GameObj | |||
| public override int RecoveryFromHit => 0; | |||
| public const int cd = 0; | |||
| public override int CD => cd; | |||
| public const int maxBulletNum = 4; | |||
| public override int MaxBulletNum => maxBulletNum; | |||
| public override bool CanAttack(GameObj target) | |||
| { | |||
| @@ -18,6 +18,7 @@ namespace GameClass.GameObj | |||
| public abstract int Backswing { get; } | |||
| public abstract int RecoveryFromHit { get; } | |||
| public abstract int CD { get; } | |||
| public abstract int MaxBulletNum { get; } | |||
| private readonly bool hasSpear; | |||
| /// <summary> | |||
| @@ -96,5 +97,21 @@ namespace GameClass.GameObj | |||
| return GameData.basicCD; | |||
| } | |||
| } | |||
| public static int BulletNum(BulletType bulletType) | |||
| { | |||
| switch (bulletType) | |||
| { | |||
| case BulletType.CommonAttackOfGhost: | |||
| return CommonAttackOfGhost.maxBulletNum; | |||
| case BulletType.FlyingKnife: | |||
| return FlyingKnife.maxBulletNum; | |||
| case BulletType.BombBomb: | |||
| return BombBomb.maxBulletNum; | |||
| case BulletType.JumpyDumpty: | |||
| return JumpyDumpty.maxBulletNum; | |||
| default: | |||
| return GameData.basicCD; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -49,6 +49,7 @@ namespace GameClass.GameObj | |||
| bulletOfPlayer = value; | |||
| OrgCD = (BulletFactory.BulletCD(value)); | |||
| CD = 0; | |||
| maxBulletNum = bulletNum = (BulletFactory.BulletNum(value)); | |||
| } | |||
| } | |||
| } | |||
| @@ -17,14 +17,15 @@ namespace Gaming | |||
| { | |||
| // 人物移动 | |||
| private static void SkillWhenColliding(Character player, IGameObj collisionObj) | |||
| private void SkillWhenColliding(Character player, IGameObj collisionObj) | |||
| { | |||
| if (collisionObj.Type == GameObjType.Bullet) | |||
| { | |||
| if (((Bullet)collisionObj).TypeOfBullet == BulletType.JumpyDumpty) | |||
| { | |||
| if (AttackManager.BeStunned((Character)collisionObj, ((Bullet)collisionObj).AP / GameData.timeFactorOfGhostFainting)) | |||
| if (AttackManager.BeStunned((Character)player, ((Bullet)collisionObj).AP / GameData.timeFactorOfGhostFainting)) | |||
| player.AddScore(GameData.StudentScoreTrickerBeStunned(((Bullet)collisionObj).AP / GameData.timeFactorOfGhostFainting)); | |||
| gameMap.Remove((GameObj)collisionObj); | |||
| } | |||
| } | |||
| if (player.UseIActiveSkill(ActiveSkillType.CanBeginToCharge).IsBeingUsed && collisionObj.Type == GameObjType.Character && ((Character)collisionObj).IsGhost()) | |||
| @@ -197,14 +197,8 @@ namespace Gaming | |||
| return; | |||
| } | |||
| if (bullet.TypeOfBullet == BulletType.BombBomb) | |||
| { | |||
| bullet.Parent.BulletOfPlayer = BulletType.JumpyDumpty; | |||
| Attack((Character)bullet.Parent, 0.0); | |||
| Attack((Character)bullet.Parent, Math.PI); | |||
| Attack((Character)bullet.Parent, Math.PI / 2.0); | |||
| Attack((Character)bullet.Parent, Math.PI * 3.0 / 2.0); | |||
| } | |||
| Debugger.Output(bullet, bullet.TypeOfBullet.ToString()); | |||
| BombObj(bullet, objBeingShot); | |||
| if (bullet.RecoveryFromHit > 0) | |||
| { | |||
| @@ -213,7 +207,6 @@ namespace Gaming | |||
| new Thread | |||
| (() => | |||
| { | |||
| Thread.Sleep(bullet.RecoveryFromHit); | |||
| if (gameMap.Timer.IsGaming && bullet.Parent.PlayerState == PlayerStateType.Swinging) | |||
| @@ -236,6 +229,17 @@ namespace Gaming | |||
| }*/ | |||
| // 子弹爆炸会发生的事↓↓↓ | |||
| if (bullet.TypeOfBullet == BulletType.BombBomb && objBeingShot != null) | |||
| { | |||
| bullet.Parent.BulletOfPlayer = BulletType.JumpyDumpty; | |||
| Debugger.Output(bullet, "JumpyDumpty!"); | |||
| Attack((Character)bullet.Parent, bullet.FacingDirection.Angle()); | |||
| Attack((Character)bullet.Parent, bullet.FacingDirection.Angle() + Math.PI); | |||
| Attack((Character)bullet.Parent, bullet.FacingDirection.Angle() + Math.PI / 2.0); | |||
| Attack((Character)bullet.Parent, bullet.FacingDirection.Angle() + Math.PI * 3.0 / 2.0); | |||
| } | |||
| var beAttackedList = new List<IGameObj>(); | |||
| foreach (var kvp in gameMap.GameObjDict) | |||
| @@ -311,9 +315,6 @@ namespace Gaming | |||
| { // 子弹如果没有和其他物体碰撞,将会一直向前直到超出人物的attackRange | |||
| if (player == null) | |||
| { | |||
| #if DEBUG | |||
| Console.WriteLine("the player who will attack is NULL!"); | |||
| #endif | |||
| return false; | |||
| } | |||
| @@ -330,6 +331,7 @@ namespace Gaming | |||
| if (bullet != null) | |||
| { | |||
| Debugger.Output(player, "Attack in" + bullet.ToString()); | |||
| bullet.AP += player.TryAddAp() ? GameData.ApPropAdd : 0; | |||
| bullet.CanMove = true; | |||
| gameMap.Add(bullet); | |||
| @@ -440,6 +440,97 @@ | |||
| } | |||
| ~~~ | |||
| #### Klee | |||
| - 普通攻击为 CommonAttackOfGhost | |||
| ~~~csharp | |||
| int moveSpeed = (int)(GameData.basicMoveSpeed * 155 / 127); | |||
| int maxHp = GameData.basicHp; | |||
| int maxBulletNum = 1; | |||
| BulletType InitBullet => BulletType.CommonAttackOfGhost; | |||
| List<ActiveSkillType> ListOfIActiveSkill => new(new ActiveSkillType[] { ActiveSkillType.JumpyBomb }); | |||
| List<PassiveSkillType> ListOfIPassiveSkill => new(new PassiveSkillType[] { }); | |||
| double concealment = GameData.basicConcealment; | |||
| int alertnessRadius = (int)(GameData.basicAlertnessRadius * 1.069); | |||
| int viewRange = (int)(GameData.basicViewRange * 1.1); | |||
| int timeOfOpeningOrLocking = (int)(GameData.basicSpeedOfOpeningOrLocking / 1.1); | |||
| int speedOfClimbingThroughWindows = (int)(GameData.basicGhostSpeedOfClimbingThroughWindows / 1.1); | |||
| int speedOfOpenChest = (int)(GameData.basicSpeedOfOpenChest * 1.1); | |||
| ~~~ | |||
| - 主动技能 | |||
| - 蹦蹦炸弹 | |||
| ~~~csharp | |||
| public int SkillCD => GameData.commonSkillCD / 30 * 5; | |||
| public int DurationTime => GameData.commonSkillTime / 2; | |||
| ~~~ | |||
| - 在DurationTime内,攻击类型变为蹦蹦炸弹 | |||
| ~~~csharp | |||
| internal sealed class BombBomb : Bullet | |||
| { | |||
| public override double BulletBombRange => GameData.basicBulletBombRange; | |||
| public override double BulletAttackRange => GameData.basicAttackShortRange; | |||
| public int ap = (int)(GameData.basicApOfGhost * 6.0 / 5); | |||
| public override int Speed => (int)(GameData.basicBulletMoveSpeed * 0.8); | |||
| public override bool IsRemoteAttack => false; | |||
| public override int CastTime => (int)BulletAttackRange / Speed; | |||
| public override int Backswing => 0; | |||
| public override int RecoveryFromHit => 0; | |||
| public const int cd = GameData.basicCD; | |||
| public override bool CanAttack(GameObj target) | |||
| { | |||
| return XY.Distance(this.Position, target.Position) <= BulletBombRange; | |||
| } | |||
| public override bool CanBeBombed(GameObjType gameObjType) | |||
| { | |||
| switch (gameObjType) | |||
| { | |||
| case GameObjType.Character: | |||
| case GameObjType.Generator: | |||
| return true; | |||
| default: | |||
| return false; | |||
| } | |||
| } | |||
| } | |||
| ~~~ | |||
| - 当蹦蹦炸弹因为碰撞而爆炸,向子弹方向上加上0°,90°,180°,270° 发出四个小炸弹 | |||
| - 四个小炸弹只会因为碰撞爆炸,停止运动后学生碰撞会造成眩晕(AP / GameData.timeFactorOfGhostFainting)ms | |||
| ~~~csharp | |||
| internal sealed class JumpyDumpty : Bullet | |||
| { | |||
| public override double BulletBombRange => GameData.basicBulletBombRange / 2; | |||
| public override double BulletAttackRange => GameData.basicAttackShortRange * 2; | |||
| public int ap = (int)(GameData.basicApOfGhost * 0.6); | |||
| public override int Speed => (int)(GameData.basicBulletMoveSpeed * 1.2); | |||
| public override bool IsRemoteAttack => false; | |||
| public override int CastTime => 0; | |||
| public override int Backswing => 0; | |||
| public override int RecoveryFromHit => 0; | |||
| public const int cd = 0; | |||
| public override int CD => cd; | |||
| public override bool CanAttack(GameObj target) | |||
| { | |||
| return XY.Distance(this.Position, target.Position) <= BulletBombRange; | |||
| } | |||
| public override bool CanBeBombed(GameObjType gameObjType) | |||
| { | |||
| switch (gameObjType) | |||
| { | |||
| case GameObjType.Character: | |||
| case GameObjType.Generator: | |||
| return true; | |||
| default: | |||
| return false; | |||
| } | |||
| } | |||
| } | |||
| ~~~ | |||
| ### 学生(&老师) | |||
| #### 运动员 | |||