feat: ✨ add new CharacterType Klee and fix some bugs
tags/0.1.0
| @@ -43,7 +43,7 @@ enum PropType // 地图中的可拾取道具类型 | |||
| { | |||
| NULL_PROP_TYPE = 0; | |||
| ADD_SPEED = 1; | |||
| ADD_LIFE_OR_AP = 2; | |||
| ADD_LIFE_OR_AP = 2;//ADD_LIFE_OR_Clairaudience | |||
| ADD_HP_OR_AP = 3; | |||
| SHIELD_OR_SPEAR = 4; | |||
| KEY3 = 5; | |||
| @@ -54,9 +54,9 @@ enum PropType // 地图中的可拾取道具类型 | |||
| enum StudentBuffType // 人类可用的增益效果类型 | |||
| { | |||
| NULL_SBUFF_TYPE = 0; | |||
| SBUFFTYPE1 = 1; | |||
| SBUFFTYPE2 = 2; | |||
| SBUFFTYPE3 = 3; | |||
| SBUFFTYPE1 = 1;//AddSpeed | |||
| SBUFFTYPE2 = 2;//AddLIFE | |||
| SBUFFTYPE3 = 3;//Shield | |||
| SBUFFTYPE4 = 4; | |||
| } | |||
| @@ -86,10 +86,11 @@ enum PlayerState | |||
| enum TrickerBuffType // 屠夫可用的增益效果类型 | |||
| { | |||
| NULL_TBUFF_TYPE = 0; | |||
| TBUFFTYPE1 = 1; | |||
| TBUFFTYPE2 = 2; | |||
| TBUFFTYPE3 = 3; | |||
| TBUFFTYPE4 = 4; | |||
| TBUFFTYPE1 = 1;//AddSpeed | |||
| TBUFFTYPE2 = 2;//Spear | |||
| TBUFFTYPE3 = 3;//AddAp | |||
| TBUFFTYPE4 = 4;//Clairaudience | |||
| INVISIBLE = 5; | |||
| } | |||
| // 特别说明:由于Student阵营和Tricker阵营有显著的隔离,且暂定职业、主动技能和被动效果相互绑定,故不按照THUAI5的方式区分ActiveSkillType和CharacterType,而是选择了按照阵营来给不同阵营赋予不同的职业(及技能)。 | |||
| @@ -114,7 +115,7 @@ enum TrickerType | |||
| { | |||
| NULL_TRICKER_TYPE = 0; | |||
| ASSASSIN = 1; | |||
| TRICKERTYPE2 = 2; | |||
| TRICKERTYPE2 = 2;//KLEE | |||
| TRICKERTYPE3 = 3; | |||
| TRICKERTYPE4 = 4; | |||
| } | |||
| @@ -23,9 +23,9 @@ namespace GameClass.GameObj | |||
| } | |||
| } | |||
| public override int Speed => GameData.basicBulletMoveSpeed; | |||
| public override bool IsToBomb => false; | |||
| public override bool IsRemoteAttack => false; | |||
| public override int CastTime => GameData.basicCastTime; | |||
| public override int CastTime => (int)BulletAttackRange / Speed; | |||
| public override int Backswing => GameData.basicBackswing; | |||
| public override int RecoveryFromHit => GameData.basicRecoveryFromHit; | |||
| public const int cd = GameData.basicBackswing; | |||
| @@ -68,11 +68,11 @@ namespace GameClass.GameObj | |||
| } | |||
| } | |||
| public override int Speed => GameData.basicBulletMoveSpeed * 2; | |||
| public override bool IsToBomb => false; | |||
| public override bool IsRemoteAttack => true; | |||
| public override int CastTime => GameData.basicCastTime; | |||
| public override int Backswing => GameData.basicBackswing * 2 / 5; | |||
| public override int RecoveryFromHit => GameData.basicBackswing * 3 / 4; | |||
| public override int Backswing => 0; | |||
| public override int RecoveryFromHit => 0; | |||
| public const int cd = GameData.basicBackswing * 2 / 5 + 100; | |||
| public override int CD => cd; | |||
| @@ -94,4 +94,95 @@ namespace GameClass.GameObj | |||
| public override BulletType TypeOfBullet => BulletType.FlyingKnife; | |||
| } | |||
| internal sealed class BombBomb : Bullet | |||
| { | |||
| public BombBomb(Character player, PlaceType placeType, XY pos, int radius = GameData.bulletRadius) : | |||
| base(player, radius, placeType, pos) | |||
| { | |||
| } | |||
| public override double BulletBombRange => GameData.basicBulletBombRange; | |||
| public override double BulletAttackRange => GameData.basicAttackShortRange; | |||
| public int ap = (int)(GameData.basicApOfGhost * 6.0 / 5); | |||
| public override int AP | |||
| { | |||
| get => ap; | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| ap = value; | |||
| } | |||
| } | |||
| 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 => GameData.basicBackswing; | |||
| public override int RecoveryFromHit => GameData.basicRecoveryFromHit; | |||
| public const int cd = GameData.basicCD; | |||
| 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; | |||
| } | |||
| } | |||
| public override BulletType TypeOfBullet => BulletType.BombBomb; | |||
| } | |||
| internal sealed class JumpyDumpty : Bullet | |||
| { | |||
| public JumpyDumpty(Character player, PlaceType placeType, XY pos, int radius = GameData.bulletRadius) : | |||
| base(player, radius, placeType, pos) | |||
| { | |||
| } | |||
| 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 AP | |||
| { | |||
| get => ap; | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| ap = value; | |||
| } | |||
| } | |||
| 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; | |||
| } | |||
| } | |||
| public override BulletType TypeOfBullet => BulletType.JumpyDumpty; | |||
| } | |||
| } | |||
| @@ -12,7 +12,7 @@ namespace GameClass.GameObj | |||
| public override double BulletAttackRange => 0; | |||
| public override int AP => 7220; | |||
| public override int Speed => 0; | |||
| public override bool IsToBomb => false; | |||
| public override bool IsRemoteAttack => false; | |||
| public override int CastTime => 0; | |||
| public override int Backswing => 0; | |||
| public override int RecoveryFromHit => 0; | |||
| @@ -13,7 +13,7 @@ namespace GameClass.GameObj | |||
| public abstract double BulletAttackRange { get; } | |||
| public abstract int AP { get; set; } | |||
| public abstract int Speed { get; } | |||
| public abstract bool IsToBomb { get; } | |||
| public abstract bool IsRemoteAttack { get; } | |||
| public abstract int CastTime { get; } | |||
| public abstract int Backswing { get; } | |||
| public abstract int RecoveryFromHit { get; } | |||
| @@ -45,7 +45,7 @@ namespace GameClass.GameObj | |||
| this.place = placeType; | |||
| this.CanMove = true; | |||
| this.moveSpeed = this.Speed; | |||
| this.hasSpear = player.HasSpear; | |||
| this.hasSpear = player.TryUseSpear(); | |||
| this.Parent = player; | |||
| } | |||
| public override bool IsRigid => true; // 默认为true | |||
| @@ -63,6 +63,10 @@ namespace GameClass.GameObj | |||
| return new FlyingKnife(character, place, pos); | |||
| case BulletType.CommonAttackOfGhost: | |||
| return new CommonAttackOfGhost(character, place, pos); | |||
| case BulletType.JumpyDumpty: | |||
| return new JumpyDumpty(character, place, pos); | |||
| case BulletType.BombBomb: | |||
| return new BombBomb(character, place, pos); | |||
| default: | |||
| return null; | |||
| } | |||
| @@ -71,10 +75,6 @@ namespace GameClass.GameObj | |||
| { | |||
| switch (bulletType) | |||
| { | |||
| case BulletType.AtomBomb: | |||
| case BulletType.LineBullet: | |||
| case BulletType.FastBullet: | |||
| case BulletType.OrdinaryBullet: | |||
| case BulletType.FlyingKnife: | |||
| default: | |||
| return GameData.bulletRadius; | |||
| @@ -88,10 +88,10 @@ namespace GameClass.GameObj | |||
| return CommonAttackOfGhost.cd; | |||
| case BulletType.FlyingKnife: | |||
| return FlyingKnife.cd; | |||
| case BulletType.AtomBomb: | |||
| case BulletType.LineBullet: | |||
| case BulletType.FastBullet: | |||
| case BulletType.OrdinaryBullet: | |||
| case BulletType.BombBomb: | |||
| return BombBomb.cd; | |||
| case BulletType.JumpyDumpty: | |||
| return JumpyDumpty.cd; | |||
| default: | |||
| return GameData.basicCD; | |||
| } | |||
| @@ -1,5 +1,6 @@ | |||
| using System; | |||
| using System.Collections.Generic; | |||
| using System.Linq; | |||
| using System.Runtime.InteropServices; | |||
| using System.Threading; | |||
| using Preparation.Utility; | |||
| @@ -183,6 +184,44 @@ namespace GameClass.GameObj | |||
| } | |||
| } | |||
| } | |||
| public bool TryUseSpear() | |||
| { | |||
| if (HasSpear) | |||
| { | |||
| lock (buffListLock[(int)BuffType.Spear]) | |||
| { | |||
| buffList[(int)BuffType.Spear].RemoveFirst(); | |||
| } | |||
| return true; | |||
| } | |||
| return false; | |||
| } | |||
| public void AddClairaudience(int shieldTime) => AddBuff(new BuffValue(), shieldTime, BuffType.Clairaudience, () => | |||
| { }); | |||
| public bool HasClairaudience | |||
| { | |||
| get | |||
| { | |||
| lock (buffListLock[(int)BuffType.Clairaudience]) | |||
| { | |||
| return buffList[(int)BuffType.Clairaudience].Count != 0; | |||
| } | |||
| } | |||
| } | |||
| public void AddInvisible(int shieldTime) => AddBuff(new BuffValue(), shieldTime, BuffType.Invisible, () => | |||
| { }); | |||
| public bool HasInvisible | |||
| { | |||
| get | |||
| { | |||
| lock (buffListLock[(int)BuffType.Invisible]) | |||
| { | |||
| return buffList[(int)BuffType.Invisible].Count != 0; | |||
| } | |||
| } | |||
| } | |||
| /// <summary> | |||
| /// 清除所有buff | |||
| @@ -66,6 +66,12 @@ namespace GameClass.GameObj | |||
| case CharacterType.Assassin: | |||
| this.occupation = new Assassin(); | |||
| break; | |||
| case CharacterType.Teacher: | |||
| this.occupation = new Teacher(); | |||
| break; | |||
| case CharacterType.Klee: | |||
| this.occupation = new Klee(); | |||
| break; | |||
| case CharacterType.Athlete: | |||
| default: | |||
| this.occupation = new Athlete(); | |||
| @@ -82,7 +88,7 @@ namespace GameClass.GameObj | |||
| this.characterType = characterType; | |||
| this.SpeedOfOpeningOrLocking = Occupation.TimeOfOpeningOrLocking; | |||
| this.SpeedOfClimbingThroughWindows = Occupation.SpeedOfClimbingThroughWindows; | |||
| this.SpeedOfOpenChest = Occupation.TimeOfOpenChest; | |||
| this.SpeedOfOpenChest = Occupation.SpeedOfOpenChest; | |||
| foreach (var activeSkill in this.Occupation.ListOfIActiveSkill) | |||
| { | |||
| @@ -47,7 +47,8 @@ namespace GameClass.GameObj | |||
| lock (gameObjLock) | |||
| { | |||
| bulletOfPlayer = value; | |||
| CD = BulletFactory.BulletCD(value); | |||
| OrgCD = (BulletFactory.BulletCD(value)); | |||
| CD = 0; | |||
| } | |||
| } | |||
| } | |||
| @@ -123,22 +124,6 @@ namespace GameClass.GameObj | |||
| }*/ | |||
| #endregion | |||
| #region 感知相关的基本属性及方法 | |||
| /// <summary> | |||
| /// 是否在隐身 | |||
| /// </summary> | |||
| private bool isInvisible = false; | |||
| public bool IsInvisible | |||
| { | |||
| get => isInvisible; | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| isInvisible = value; | |||
| } | |||
| } | |||
| } | |||
| private Dictionary<BgmType, double> bgmDictionary = new(); | |||
| public Dictionary<BgmType, double> BgmDictionary | |||
| { | |||
| @@ -350,7 +335,7 @@ namespace GameClass.GameObj | |||
| 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.Treated || playerState == PlayerStateType.Stunned | |||
| || playerState == PlayerStateType.Null || playerState == PlayerStateType.Moving); | |||
| private int score = 0; | |||
| @@ -519,6 +504,12 @@ namespace GameClass.GameObj | |||
| public void AddSpear(int spearTime) => buffManager.AddSpear(spearTime); | |||
| public bool HasSpear => buffManager.HasSpear; | |||
| public void AddClairaudience(int time) => buffManager.AddClairaudience(time); | |||
| public bool HasClairaudience => buffManager.HasClairaudience; | |||
| public void AddInvisible(int time) => buffManager.AddInvisible(time); | |||
| public bool HasInvisible => buffManager.HasInvisible; | |||
| private Array buffTypeArray = Enum.GetValues(typeof(BuffType)); | |||
| public Dictionary<BuffType, bool> Buff | |||
| { | |||
| @@ -568,6 +559,11 @@ namespace GameClass.GameObj | |||
| return false; | |||
| } | |||
| public bool TryUseSpear() | |||
| { | |||
| return buffManager.TryUseSpear(); | |||
| } | |||
| public bool TryUseShield() | |||
| { | |||
| if (buffManager.TryUseShield()) | |||
| @@ -62,10 +62,10 @@ namespace GameClass.GameObj | |||
| } | |||
| } | |||
| public class NuclearWeapon : IActiveSkill // 核武器 | |||
| public class JumpyBomb : IActiveSkill | |||
| { | |||
| public int SkillCD => GameData.commonSkillCD * 7 / 3; | |||
| public int DurationTime => GameData.commonSkillTime / 10; | |||
| public int SkillCD => GameData.commonSkillCD / 30 * 5; | |||
| public int DurationTime => GameData.commonSkillTime / 2; | |||
| private readonly object commonSkillLock = new object(); | |||
| public object ActiveSkillLock => commonSkillLock; | |||
| @@ -132,6 +132,8 @@ namespace GameClass.GameObj | |||
| return new CanBeginToCharge(); | |||
| case ActiveSkillType.Punish: | |||
| return new Punish(); | |||
| case ActiveSkillType.JumpyBomb: | |||
| return new JumpyBomb(); | |||
| default: | |||
| return new NullSkill(); | |||
| } | |||
| @@ -149,6 +151,8 @@ namespace GameClass.GameObj | |||
| return ActiveSkillType.CanBeginToCharge; | |||
| case Punish: | |||
| return ActiveSkillType.Punish; | |||
| case JumpyBomb: | |||
| return ActiveSkillType.JumpyBomb; | |||
| default: | |||
| return ActiveSkillType.Null; | |||
| } | |||
| @@ -251,7 +251,7 @@ namespace GameClass.GameObj | |||
| } | |||
| public bool CanSee(Character player, GameObj gameObj) | |||
| { | |||
| if ((gameObj.Type == GameObjType.Character) && !((Character)gameObj).IsInvisible) return false; | |||
| if ((gameObj.Type == GameObjType.Character) && !((Character)gameObj).HasInvisible) return false; | |||
| XY pos1 = player.Position; | |||
| XY pos2 = gameObj.Position; | |||
| XY del = pos1 - pos2; | |||
| @@ -52,13 +52,13 @@ namespace GameClass.GameObj | |||
| /// <summary> | |||
| /// 复活甲 | |||
| /// </summary> | |||
| public sealed class AddLifeOrAp : Prop | |||
| public sealed class AddLifeOrClairaudience : Prop | |||
| { | |||
| public AddLifeOrAp(XY initPos, PlaceType placeType) : | |||
| public AddLifeOrClairaudience(XY initPos, PlaceType placeType) : | |||
| base(initPos, placeType) | |||
| { | |||
| } | |||
| public override PropType GetPropType() => PropType.AddLifeOrAp; | |||
| public override PropType GetPropType() => PropType.AddLifeOrClairaudience; | |||
| } | |||
| public sealed class AddHpOrAp : Prop | |||
| { | |||
| @@ -141,8 +141,8 @@ namespace GameClass.GameObj | |||
| { | |||
| case PropType.AddSpeed: | |||
| return new AddSpeed(pos, place); | |||
| case PropType.AddLifeOrAp: | |||
| return new AddLifeOrAp(pos, place); | |||
| case PropType.AddLifeOrClairaudience: | |||
| return new AddLifeOrClairaudience(pos, place); | |||
| case PropType.ShieldOrSpear: | |||
| return new ShieldOrSpear(pos, place); | |||
| case PropType.AddHpOrAp: | |||
| @@ -158,4 +158,4 @@ namespace GameClass.GameObj | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -17,8 +17,16 @@ namespace Gaming | |||
| { | |||
| // 人物移动 | |||
| private void SkillWhenMove(Character player, IGameObj collisionObj) | |||
| private static 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)) | |||
| player.AddScore(GameData.StudentScoreTrickerBeStunned(((Bullet)collisionObj).AP / GameData.timeFactorOfGhostFainting)); | |||
| } | |||
| } | |||
| if (player.UseIActiveSkill(ActiveSkillType.CanBeginToCharge).IsBeingUsed && collisionObj.Type == GameObjType.Character && ((Character)collisionObj).IsGhost()) | |||
| { | |||
| if (AttackManager.BeStunned((Character)collisionObj, GameData.TimeOfGhostFaintingWhenCharge)) | |||
| @@ -188,7 +196,7 @@ namespace Gaming | |||
| playerTreated = gameMap.StudentForInteract(player.Position); | |||
| if (playerTreated == null) return false; | |||
| } | |||
| if ((!player.Commandable()) || player.PlayerState == PlayerStateType.Treating || | |||
| if (player == playerTreated || (!player.Commandable()) || player.PlayerState == PlayerStateType.Treating || | |||
| (!playerTreated.Commandable()) || | |||
| playerTreated.HP == playerTreated.MaxHp || !GameData.ApproachToInteract(playerTreated.Position, player.Position)) | |||
| return false; | |||
| @@ -254,11 +262,12 @@ namespace Gaming | |||
| playerRescued = gameMap.StudentForInteract(player.Position); | |||
| if (playerRescued == null) return false; | |||
| } | |||
| if ((!player.Commandable()) || playerRescued.PlayerState != PlayerStateType.Addicted || !GameData.ApproachToInteract(playerRescued.Position, player.Position)) | |||
| if ((!player.Commandable()) || playerRescued.PlayerState != PlayerStateType.Addicted || player == playerRescued | |||
| || !GameData.ApproachToInteract(playerRescued.Position, player.Position) || playerRescued.TimeOfRescue > 0) | |||
| return false; | |||
| player.PlayerState = PlayerStateType.Rescuing; | |||
| playerRescued.PlayerState = PlayerStateType.Rescued; | |||
| player.TimeOfRescue = 0; | |||
| new Thread | |||
| ( | |||
| () => | |||
| @@ -267,7 +276,7 @@ namespace Gaming | |||
| loopCondition: () => playerRescued.PlayerState == PlayerStateType.Rescued && player.PlayerState == PlayerStateType.Rescuing && gameMap.Timer.IsGaming && GameData.ApproachToInteract(playerRescued.Position, player.Position), | |||
| loopToDo: () => | |||
| { | |||
| player.TimeOfRescue += GameData.frameDuration; | |||
| playerRescued.TimeOfRescue += GameData.frameDuration; | |||
| }, | |||
| timeInterval: GameData.frameDuration, | |||
| finallyReturn: () => 0, | |||
| @@ -277,16 +286,17 @@ namespace Gaming | |||
| if (playerRescued.PlayerState == PlayerStateType.Rescued) | |||
| { | |||
| if (player.TimeOfRescue >= GameData.basicTimeOfRescue) | |||
| if (playerRescued.TimeOfRescue >= GameData.basicTimeOfRescue) | |||
| { | |||
| playerRescued.PlayerState = PlayerStateType.Null; | |||
| playerRescued.HP = GameData.RemainHpWhenAddLife; | |||
| player.AddScore(GameData.StudentScoreRescue); | |||
| } | |||
| else | |||
| playerRescued.PlayerState = PlayerStateType.Addicted; | |||
| } | |||
| if (player.PlayerState == PlayerStateType.Rescuing) player.PlayerState = PlayerStateType.Null; | |||
| player.TimeOfRescue = 0; | |||
| playerRescued.TimeOfRescue = 0; | |||
| } | |||
| ) | |||
| { IsBackground = true }.Start(); | |||
| @@ -494,7 +504,7 @@ namespace Gaming | |||
| gameMap: gameMap, | |||
| OnCollision: (obj, collisionObj, moveVec) => | |||
| { | |||
| SkillWhenMove((Character)obj, collisionObj); | |||
| SkillWhenColliding((Character)obj, collisionObj); | |||
| //if (collisionObj is Mine) | |||
| //{ | |||
| // ActivateMine((Character)obj, (Mine)collisionObj); | |||
| @@ -33,7 +33,7 @@ namespace Gaming | |||
| Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64); | |||
| #endif | |||
| if (obj.CanMove) | |||
| if (obj.CanMove && ((Bullet)obj).TypeOfBullet != BulletType.JumpyDumpty) | |||
| BulletBomb((Bullet)obj, null); | |||
| } | |||
| ); | |||
| @@ -124,10 +124,6 @@ namespace Gaming | |||
| gameMap.GameObjLockDict[GameObjType.EmergencyExit].ExitReadLock(); | |||
| } | |||
| } | |||
| // player.Reset(); | |||
| // ((Character?)bullet.Parent)?.AddScore(GameData.addScoreWhenKillOneLevelPlayer); // 给击杀者加分 | |||
| } | |||
| private void BombObj(Bullet bullet, GameObj objBeingShot) | |||
| @@ -174,10 +170,10 @@ namespace Gaming | |||
| #endif | |||
| bullet.CanMove = false; | |||
| if (gameMap.Remove(bullet) && bullet.IsToBomb) | |||
| if (gameMap.Remove(bullet) && bullet.BulletBombRange > 0) | |||
| gameMap.Add(new BombedBullet(bullet)); | |||
| if (!bullet.IsToBomb) | |||
| if (bullet.BulletBombRange == 0) | |||
| { | |||
| if (objBeingShot == null) | |||
| { | |||
| @@ -201,7 +197,14 @@ 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); | |||
| } | |||
| BombObj(bullet, objBeingShot); | |||
| if (bullet.RecoveryFromHit > 0) | |||
| { | |||
| @@ -304,7 +307,7 @@ namespace Gaming | |||
| beAttackedList.Clear(); | |||
| } | |||
| public bool Attack(Character? player, double angle) // 射出去的子弹泼出去的水(狗头) | |||
| public bool Attack(Character? player, double angle) | |||
| { // 子弹如果没有和其他物体碰撞,将会一直向前直到超出人物的attackRange | |||
| if (player == null) | |||
| { | |||
| @@ -31,10 +31,10 @@ namespace Gaming | |||
| player.AddSpear(GameData.PropDuration); | |||
| else player.AddShield(GameData.PropDuration); | |||
| break; | |||
| case PropType.AddLifeOrAp: | |||
| case PropType.AddLifeOrClairaudience: | |||
| if (!player.IsGhost()) | |||
| player.AddLIFE(GameData.PropDuration); | |||
| else player.AddAp(GameData.PropDuration); | |||
| else player.AddClairaudience(GameData.PropDuration); | |||
| break; | |||
| case PropType.AddSpeed: | |||
| player.AddMoveSpeed(GameData.PropDuration); | |||
| @@ -118,7 +118,7 @@ namespace Gaming | |||
| private Prop ProduceOnePropNotKey(Random r, XY Pos) | |||
| { | |||
| return PropFactory.GetProp((PropType)r.Next(0, GameData.numOfPropTypeNotKey), Pos, gameMap.GetPlaceType(Pos)); | |||
| return PropFactory.GetProp((PropType)r.Next(GameData.numOfTeachingBuilding + 1, GameData.numOfPropSpecies + 1), Pos, gameMap.GetPlaceType(Pos)); | |||
| } | |||
| private Chest GetChest(Random r) | |||
| @@ -36,7 +36,7 @@ namespace Gaming | |||
| return ActiveSkillEffect(skill, player, () => | |||
| { | |||
| player.AddMoveSpeed(skill.DurationTime, 3.0); | |||
| //See SkillWhenMove in ActionManager | |||
| //See SkillWhenColliding in ActionManager | |||
| }, | |||
| () => | |||
| { }); | |||
| @@ -45,21 +45,22 @@ namespace Gaming | |||
| public static bool BecomeInvisible(Character player) | |||
| { | |||
| return ActiveSkillEffect(player.UseIActiveSkill(ActiveSkillType.BecomeInvisible), player, () => | |||
| IActiveSkill activeSkill = player.UseIActiveSkill(ActiveSkillType.BecomeInvisible); | |||
| return ActiveSkillEffect(activeSkill, player, () => | |||
| { | |||
| player.IsInvisible = true; | |||
| player.AddInvisible(activeSkill.DurationTime); | |||
| Debugger.Output(player, "become invisible!"); | |||
| }, | |||
| () => | |||
| { player.IsInvisible = false; }); | |||
| { }); | |||
| } | |||
| public bool NuclearWeapon(Character player) | |||
| public bool JumpyBomb(Character player) | |||
| { | |||
| return ActiveSkillEffect(player.UseIActiveSkill(ActiveSkillType.NuclearWeapon), player, () => | |||
| return ActiveSkillEffect(player.UseIActiveSkill(ActiveSkillType.JumpyBomb), player, () => | |||
| { | |||
| player.BulletOfPlayer = BulletType.AtomBomb; | |||
| Debugger.Output(player, "uses atombomb!"); | |||
| player.BulletOfPlayer = BulletType.BombBomb; | |||
| Debugger.Output(player, "uses jumpybomb!"); | |||
| }, | |||
| () => | |||
| { player.BulletOfPlayer = player.OriBulletOfPlayer; }); | |||
| @@ -91,8 +92,8 @@ namespace Gaming | |||
| || player.PlayerState == PlayerStateType.UsingSkill || player.PlayerState == PlayerStateType.LockingOrOpeningTheDoor || player.PlayerState == PlayerStateType.OpeningTheChest) | |||
| && gameMap.CanSee(player, character)) | |||
| { | |||
| if (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; | |||
| } | |||
| } | |||
| @@ -28,6 +28,9 @@ namespace Gaming | |||
| case ActiveSkillType.Punish: | |||
| Punish(character); | |||
| break; | |||
| case ActiveSkillType.JumpyBomb: | |||
| JumpyBomb(character); | |||
| break; | |||
| default: | |||
| return false; | |||
| } | |||
| @@ -11,6 +11,8 @@ namespace Preparation.Interface | |||
| public void AddScore(int add); | |||
| public double Vampire { get; } | |||
| public PlayerStateType PlayerState { get; set; } | |||
| public BulletType BulletOfPlayer { get; set; } | |||
| public bool IsGhost(); | |||
| } | |||
| } | |||
| @@ -16,7 +16,7 @@ namespace Preparation.Interface | |||
| public int ViewRange { get; } | |||
| public int TimeOfOpeningOrLocking { get; } | |||
| public int SpeedOfClimbingThroughWindows { get; } | |||
| public int TimeOfOpenChest { get; } | |||
| public int SpeedOfOpenChest { get; } | |||
| } | |||
| public interface IGhost : IOccupation | |||
| @@ -32,7 +32,7 @@ namespace Preparation.Interface | |||
| public class Assassin : IGhost | |||
| { | |||
| private const int moveSpeed = GameData.basicMoveSpeed * 473 / 380; | |||
| private const int moveSpeed = (int)(GameData.basicMoveSpeed * 473.0 / 380); | |||
| public int MoveSpeed => moveSpeed; | |||
| private const int maxHp = GameData.basicHp; | |||
| @@ -61,8 +61,42 @@ namespace Preparation.Interface | |||
| public int speedOfClimbingThroughWindows = GameData.basicGhostSpeedOfClimbingThroughWindows; | |||
| public int SpeedOfClimbingThroughWindows => speedOfClimbingThroughWindows; | |||
| public int timeOfOpenChest = GameData.basicSpeedOfOpenChest; | |||
| public int TimeOfOpenChest => timeOfOpenChest; | |||
| public int speedOfOpenChest = GameData.basicSpeedOfOpenChest; | |||
| public int SpeedOfOpenChest => speedOfOpenChest; | |||
| } | |||
| public class Klee : IGhost | |||
| { | |||
| private const int moveSpeed = (int)(GameData.basicMoveSpeed * 155 / 127); | |||
| public int MoveSpeed => moveSpeed; | |||
| private const int maxHp = GameData.basicHp; | |||
| public int MaxHp => maxHp; | |||
| public const int maxBulletNum = 1; | |||
| public int MaxBulletNum => maxBulletNum; | |||
| public BulletType InitBullet => BulletType.CommonAttackOfGhost; | |||
| public List<ActiveSkillType> ListOfIActiveSkill => new(new ActiveSkillType[] { ActiveSkillType.JumpyBomb }); | |||
| public List<PassiveSkillType> ListOfIPassiveSkill => new(new PassiveSkillType[] { }); | |||
| public double concealment = GameData.basicConcealment; | |||
| public double Concealment => concealment; | |||
| public int alertnessRadius = (int)(GameData.basicAlertnessRadius * 1.069); | |||
| public int AlertnessRadius => alertnessRadius; | |||
| public int viewRange = (int)(GameData.basicViewRange * 1.1); | |||
| public int ViewRange => viewRange; | |||
| public int timeOfOpeningOrLocking = (int)(GameData.basicSpeedOfOpeningOrLocking / 1.1); | |||
| public int TimeOfOpeningOrLocking => timeOfOpeningOrLocking; | |||
| public int speedOfClimbingThroughWindows = (int)(GameData.basicGhostSpeedOfClimbingThroughWindows / 1.1); | |||
| public int SpeedOfClimbingThroughWindows => speedOfClimbingThroughWindows; | |||
| public int speedOfOpenChest = (int)(GameData.basicSpeedOfOpenChest * 1.1); | |||
| public int SpeedOfOpenChest => speedOfOpenChest; | |||
| } | |||
| public class Teacher : IStudent | |||
| { | |||
| @@ -104,8 +138,8 @@ namespace Preparation.Interface | |||
| public int speedOfClimbingThroughWindows = GameData.basicStudentSpeedOfClimbingThroughWindows / 2; | |||
| public int SpeedOfClimbingThroughWindows => speedOfClimbingThroughWindows; | |||
| public int timeOfOpenChest = GameData.basicSpeedOfOpenChest; | |||
| public int TimeOfOpenChest => timeOfOpenChest; | |||
| public int speedOfOpenChest = GameData.basicSpeedOfOpenChest; | |||
| public int SpeedOfOpenChest => speedOfOpenChest; | |||
| } | |||
| public class Athlete : IStudent | |||
| { | |||
| @@ -147,7 +181,7 @@ namespace Preparation.Interface | |||
| public int speedOfClimbingThroughWindows = GameData.basicStudentSpeedOfClimbingThroughWindows * 12 / 10; | |||
| public int SpeedOfClimbingThroughWindows => speedOfClimbingThroughWindows; | |||
| public int timeOfOpenChest = GameData.basicSpeedOfOpenChest; | |||
| public int TimeOfOpenChest => timeOfOpenChest; | |||
| public int speedOfOpenChest = GameData.basicSpeedOfOpenChest; | |||
| public int SpeedOfOpenChest => speedOfOpenChest; | |||
| } | |||
| } | |||
| @@ -53,31 +53,30 @@ namespace Preparation.Utility | |||
| public enum BulletType // 子弹类型 | |||
| { | |||
| Null = 0, | |||
| OrdinaryBullet = 1, // 普通子弹 | |||
| AtomBomb = 2, // 原子弹 | |||
| FastBullet = 3, // 快速子弹 | |||
| LineBullet = 4, // 直线子弹 | |||
| FlyingKnife = 5, //飞刀 | |||
| CommonAttackOfGhost = 6, | |||
| FlyingKnife = 1, //飞刀 | |||
| CommonAttackOfGhost = 2, | |||
| JumpyDumpty = 3, | |||
| BombBomb = 4, | |||
| // Ram = 7, | |||
| } | |||
| public enum PropType // 道具类型 | |||
| { | |||
| {//numOfPropSpecies 见Gamedata | |||
| Null = 0, | |||
| AddSpeed = 1, | |||
| AddLifeOrAp = 2, | |||
| AddHpOrAp = 3, | |||
| ShieldOrSpear = 4, | |||
| Key3 = 5, | |||
| Key5 = 6, | |||
| Key6 = 7, | |||
| Key3 = 1, | |||
| Key5 = 2, | |||
| Key6 = 3, | |||
| AddSpeed = 4, | |||
| AddLifeOrClairaudience = 5, | |||
| AddHpOrAp = 6, | |||
| ShieldOrSpear = 7, | |||
| RecoveryFromDizziness = 8, | |||
| } | |||
| public enum CharacterType // 职业 | |||
| { | |||
| Null = 0, | |||
| Assassin = 1, | |||
| Athlete = 2, | |||
| RecoverAfterBattle = 3, | |||
| Klee = 3, | |||
| SpeedUpWhenLeavingGrass = 4, | |||
| Teacher = 5, | |||
| PSkill5 = 6 | |||
| @@ -87,7 +86,7 @@ namespace Preparation.Utility | |||
| Null = 0, | |||
| BecomeInvisible = 1, | |||
| BecomeVampire = 2, | |||
| NuclearWeapon = 3, | |||
| JumpyBomb = 3, | |||
| SuperFast = 4, | |||
| UseKnife = 5, | |||
| CanBeginToCharge = 6, | |||
| @@ -111,8 +110,9 @@ namespace Preparation.Utility | |||
| Shield = 3, | |||
| Spear = 4, | |||
| AddAp = 5, | |||
| Clairaudience = 6, | |||
| Invisible = 7, | |||
| } | |||
| public enum PlaceType | |||
| { | |||
| Null = 0, | |||
| @@ -35,6 +35,14 @@ namespace Preparation.Utility | |||
| { | |||
| return gameObjType != GameObjType.Null && gameObjType != GameObjType.Grass && gameObjType != GameObjType.OutOfBoundBlock && gameObjType != GameObjType.Window && gameObjType != GameObjType.Wall; | |||
| } | |||
| /* public static bool Collide(GameObjType gameObjType) | |||
| { | |||
| return gameObjType != GameObjType.Null && gameObjType != GameObjType.Grass | |||
| && gameObjType != GameObjType.OutOfBoundBlock && gameObjType != GameObjType.Window | |||
| && gameObjType != GameObjType.Bullet&&gameObjType != GameObjType.Prop | |||
| &&gameObjType != GameObjType.PickedProp&&gameObjType != GameObjType.BombedBullet | |||
| &&gameObjType != GameObjType.EmergencyExit&&gameObjType != GameObjType.Doorway; | |||
| }*/ | |||
| public static XY GetCellCenterPos(int x, int y) // 求格子的中心坐标 | |||
| { | |||
| @@ -59,10 +67,12 @@ namespace Preparation.Utility | |||
| } | |||
| public static bool ApproachToInteract(XY pos1, XY pos2) | |||
| { | |||
| if (pos1 == pos2) return false; | |||
| return Math.Abs(PosGridToCellX(pos1) - PosGridToCellX(pos2)) <= 1 && Math.Abs(PosGridToCellY(pos1) - PosGridToCellY(pos2)) <= 1; | |||
| } | |||
| public static bool ApproachToInteractInACross(XY pos1, XY pos2) | |||
| { | |||
| if (pos1 == pos2) return false; | |||
| return (Math.Abs(PosGridToCellX(pos1) - PosGridToCellX(pos2)) + Math.Abs(PosGridToCellY(pos1) - PosGridToCellY(pos2))) <= 1; | |||
| } | |||
| #endregion | |||
| @@ -104,6 +114,7 @@ namespace Preparation.Utility | |||
| return characterType switch | |||
| { | |||
| CharacterType.Assassin => true, | |||
| CharacterType.Klee => true, | |||
| _ => false, | |||
| }; | |||
| } | |||
| @@ -159,13 +170,13 @@ namespace Preparation.Utility | |||
| public const int basicCD = 3000; // 初始子弹冷却 | |||
| public const int basicCastTime = 500;//基本前摇时间 | |||
| public const int basicBackswing = 818;//基本后摇时间 | |||
| public const int basicRecoveryFromHit = 4300;//基本命中攻击恢复时长 | |||
| public const int basicRecoveryFromHit = 3700;//基本命中攻击恢复时长 | |||
| public const int basicStunnedTimeOfStudent = 4130; | |||
| public const int basicBulletMoveSpeed = 2700; // 基本子弹移动速度,单位:s-1 | |||
| public const double basicRemoteAttackRange = 9000; // 基本远程攻击范围 | |||
| public const double basicAttackShortRange = 2700; // 基本近程攻击范围 | |||
| public const double basicBulletBombRange = 3000; // 基本子弹爆炸范围 | |||
| public const int basicBulletMoveSpeed = 1800; // 基本子弹移动速度,单位:s-1 | |||
| public const double basicRemoteAttackRange = 3000; // 基本远程攻击范围 | |||
| public const double basicAttackShortRange = 900; // 基本近程攻击范围 | |||
| public const double basicBulletBombRange = 1000; // 基本子弹爆炸范围 | |||
| #endregion | |||
| #region 技能相关 | |||
| public const int maxNumOfSkill = 3; | |||
| @@ -181,11 +192,9 @@ namespace Preparation.Utility | |||
| /// Punish | |||
| /// </summary> | |||
| public const int TimeOfGhostFaintingWhenPunish = 3070; | |||
| public const int TimeFactorOfGhostFainting = 1000; | |||
| public const int timeFactorOfGhostFainting = 250; | |||
| #endregion | |||
| #region 道具相关 | |||
| public const int MinPropTypeNum = 1; | |||
| public const int MaxPropTypeNum = 10; | |||
| public const int PropRadius = numOfPosGridPerCell / 2; | |||
| public const int PropMoveSpeed = 3000; | |||
| public const int PropMaxMoveDistance = 15 * numOfPosGridPerCell; | |||
| @@ -196,6 +205,7 @@ namespace Preparation.Utility | |||
| public const int ApSpearAdd = basicApOfGhost * 6 / 10; | |||
| public const int RemainHpWhenAddLife = 100; | |||
| public const int numOfPropSpecies = 8; | |||
| public const int numOfKeyEachArea = 2; | |||
| public const int numOfPropTypeNotKey = 4; | |||
| public const int numOfTeachingBuilding = 3; | |||
| @@ -54,6 +54,14 @@ namespace Preparation.Utility | |||
| { | |||
| return new XY(v1.x - v2.x, v1.y - v2.y); | |||
| } | |||
| public static bool operator ==(XY v1, XY v2) | |||
| { | |||
| return v1.x == v2.x && v1.y == v2.y; | |||
| } | |||
| public static bool operator !=(XY v1, XY v2) | |||
| { | |||
| return v1.x != v2.x || v1.y != v2.y; | |||
| } | |||
| public static double Distance(XY p1, XY p2) | |||
| { | |||
| return Math.Sqrt(((long)(p1.x - p2.x) * (p1.x - p2.x)) + ((long)(p1.y - p2.y) * (p1.y - p2.y))); | |||
| @@ -66,5 +74,15 @@ namespace Preparation.Utility | |||
| { | |||
| return Math.Atan2(y, x); | |||
| } | |||
| public override bool Equals(object obj) | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| public override int GetHashCode() | |||
| { | |||
| throw new NotImplementedException(); | |||
| } | |||
| } | |||
| } | |||
| @@ -50,7 +50,7 @@ namespace Server | |||
| { | |||
| case Preparation.Utility.PropType.AddSpeed: | |||
| return Protobuf.PropType.AddSpeed; | |||
| case Preparation.Utility.PropType.AddLifeOrAp: | |||
| case Preparation.Utility.PropType.AddLifeOrClairaudience: | |||
| return Protobuf.PropType.AddLifeOrAp; | |||
| case Preparation.Utility.PropType.AddHpOrAp: | |||
| return Protobuf.PropType.AddHpOrAp; | |||
| @@ -74,7 +74,7 @@ namespace Server | |||
| case Protobuf.PropType.AddSpeed: | |||
| return Preparation.Utility.PropType.AddSpeed; | |||
| case Protobuf.PropType.AddLifeOrAp: | |||
| return Preparation.Utility.PropType.AddLifeOrAp; | |||
| return Preparation.Utility.PropType.AddLifeOrClairaudience; | |||
| case Protobuf.PropType.AddHpOrAp: | |||
| return Preparation.Utility.PropType.AddHpOrAp; | |||
| case Protobuf.PropType.ShieldOrSpear: | |||
| @@ -195,6 +195,8 @@ namespace Server | |||
| { | |||
| case Preparation.Utility.CharacterType.Assassin: | |||
| return Protobuf.TrickerType.Assassin; | |||
| case Preparation.Utility.CharacterType.Klee: | |||
| return Protobuf.TrickerType._2; | |||
| default: | |||
| return Protobuf.TrickerType.NullTrickerType; | |||
| } | |||
| @@ -206,6 +208,8 @@ namespace Server | |||
| { | |||
| case Protobuf.TrickerType.Assassin: | |||
| return Preparation.Utility.CharacterType.Assassin; | |||
| case Protobuf.TrickerType._2: | |||
| return Preparation.Utility.CharacterType.Klee; | |||
| default: | |||
| return Preparation.Utility.CharacterType.Null; | |||
| } | |||
| @@ -240,7 +240,13 @@ namespace Server | |||
| { | |||
| switch (n) | |||
| { | |||
| case 0: return Protobuf.PlaceType.Land; | |||
| case 0: | |||
| case 1: | |||
| case 2: | |||
| case 3: | |||
| case 4: | |||
| case 5: | |||
| return Protobuf.PlaceType.Land; | |||
| case 6: return Protobuf.PlaceType.Wall; | |||
| case 7: return Protobuf.PlaceType.Grass; | |||
| case 8: return Protobuf.PlaceType.Classroom; | |||
| @@ -1,142 +0,0 @@ | |||
| | |||
| namespace Preparation.Utility | |||
| { | |||
| /// <summary> | |||
| /// 存放所有用到的枚举类型 | |||
| /// </summary> | |||
| public enum PlayerStateType | |||
| { | |||
| Null = 0, | |||
| Addicted = 1, | |||
| Escaped = 2, | |||
| Swinging = 3,//指后摇 | |||
| Deceased = 4, | |||
| Moving = 5, | |||
| Treating = 6, | |||
| Rescuing = 7, | |||
| Fixing = 8, | |||
| Treated = 9, | |||
| Rescued = 10, | |||
| Stunned = 11, | |||
| TryingToAttack = 12,//指前摇 | |||
| LockingOrOpeningTheDoor = 13, | |||
| OpeningTheChest = 14, | |||
| ClimbingThroughWindows = 15, | |||
| UsingSkill = 16, | |||
| OpeningTheDoorway = 17, | |||
| } | |||
| public enum GameObjType | |||
| { | |||
| Null = 0, | |||
| Character = 1, | |||
| Prop = 2, | |||
| PickedProp = 3, | |||
| Bullet = 4, | |||
| BombedBullet = 5, | |||
| Wall = 6, | |||
| Grass = 7, | |||
| Generator = 8, // 发电机 | |||
| Doorway = 9, | |||
| EmergencyExit = 10, | |||
| OutOfBoundBlock = 11, // 范围外 | |||
| Window = 12, | |||
| Door = 13, | |||
| Chest = 14, | |||
| } | |||
| public enum ShapeType | |||
| { | |||
| Null = 0, | |||
| Circle = 1, // 子弹和人物为圆形,格子为方形 | |||
| Square = 2 | |||
| } | |||
| public enum BulletType // 子弹类型 | |||
| { | |||
| Null = 0, | |||
| OrdinaryBullet = 1, // 普通子弹 | |||
| AtomBomb = 2, // 原子弹 | |||
| FastBullet = 3, // 快速子弹 | |||
| LineBullet = 4, // 直线子弹 | |||
| FlyingKnife = 5, //飞刀 | |||
| CommonAttackOfGhost = 6, | |||
| // Ram = 7, | |||
| } | |||
| public enum PropType // 道具类型 | |||
| { | |||
| Null = 0, | |||
| AddSpeed = 1, | |||
| AddLifeOrAp = 2, | |||
| AddHpOrAp = 3, | |||
| ShieldOrSpear = 4, | |||
| Key3 = 5, | |||
| Key5 = 6, | |||
| Key6 = 7, | |||
| } | |||
| public enum CharacterType // 职业 | |||
| { | |||
| Null = 0, | |||
| Assassin = 1, | |||
| Athlete = 2, | |||
| RecoverAfterBattle = 3, | |||
| SpeedUpWhenLeavingGrass = 4, | |||
| Teacher = 5, | |||
| PSkill5 = 6 | |||
| } | |||
| public enum ActiveSkillType // 主动技能 | |||
| { | |||
| Null = 0, | |||
| BecomeInvisible = 1, | |||
| BecomeVampire = 2, | |||
| NuclearWeapon = 3, | |||
| SuperFast = 4, | |||
| UseKnife = 5, | |||
| CanBeginToCharge = 6, | |||
| Punish = 7, | |||
| } | |||
| public enum PassiveSkillType | |||
| { | |||
| Null = 0, | |||
| BecomeInvisible = 1, | |||
| BecomeVampire = 2, | |||
| NuclearWeapon = 3, | |||
| SuperFast = 4, | |||
| ASkill4 = 5, | |||
| ASkill5 = 6 | |||
| } | |||
| public enum BuffType // buff | |||
| { | |||
| Null = 0, | |||
| AddSpeed = 1, | |||
| AddLIFE = 2, | |||
| Shield = 3, | |||
| Spear = 4, | |||
| AddAp = 5, | |||
| } | |||
| public enum PlaceType | |||
| { | |||
| Null = 0, | |||
| BirthPoint1 = 1,//必须从1开始 | |||
| BirthPoint2 = 2, | |||
| BirthPoint3 = 3, | |||
| BirthPoint4 = 4, | |||
| BirthPoint5 = 5, | |||
| Wall = 6, | |||
| Grass = 7, | |||
| Generator = 8, // 发电机 | |||
| Doorway = 9, | |||
| EmergencyExit = 10, | |||
| Window = 11, | |||
| Door3 = 12, | |||
| Door5 = 13, | |||
| Door6 = 14, | |||
| Chest = 15, | |||
| } | |||
| public enum BgmType | |||
| { | |||
| Null = 0, | |||
| GhostIsComing = 1, | |||
| StudentIsApproaching = 2, | |||
| GeneratorIsBeingFixed = 3, | |||
| } | |||
| } | |||
| @@ -7,10 +7,6 @@ | |||
| <Nullable>enable</Nullable> | |||
| </PropertyGroup> | |||
| <ItemGroup> | |||
| <Compile Remove="Properties\EnumType.cs" /> | |||
| </ItemGroup> | |||
| <ItemGroup> | |||
| <PackageReference Include="CommandLineParser" Version="2.9.1" /> | |||
| <PackageReference Include="FrameRateTask" Version="1.2.0" /> | |||
| @@ -4,7 +4,7 @@ start cmd /k ..\Server\bin\Debug\net6.0\Server.exe --ip 0.0.0.0 --port 8888 --s | |||
| ping -n 2 127.0.0.1 > NUL | |||
| start cmd /k ..\Client\bin\Debug\net6.0-windows\Client.exe --cl --port 8888 --characterID 4 --type 2 --occupation 1 | |||
| start cmd /k ..\Client\bin\Debug\net6.0-windows\Client.exe --cl --port 8888 --characterID 4 --type 2 --occupation 2 | |||
| ping -n 2 127.0.0.1 > NUL | |||
| @@ -154,7 +154,7 @@ | |||
| - 子弹爆炸范围 | |||
| - 子弹攻击力 | |||
| - 是否可以穿墙 | |||
| - 是否可以爆炸 | |||
| - 是否为远程攻击 | |||
| - 移动速度 | |||
| - 子弹类型 | |||
| @@ -347,7 +347,7 @@ | |||
| | 道具 | 对学生增益 | [学生得分条件] | 对搞蛋鬼增益 | [搞蛋鬼得分条件] | | |||
| | :-------- | :-------------------------------------- | :-----------------| :-------------------------------------- |:-----------------| | |||
| | AddSpeed | 提高移动速度,持续10s |不得分| 提高移动速度,持续10s |不得分| | |||
| | AddLifeOrAp |若在10s内Hp归零,该增益消失以使Hp保留100|在10s内Hp归零,得分? |10秒内下一次攻击增伤1800000|10秒内有一次攻击,得分? | | |||
| | AddLifeOrClairaudience |若在10s内Hp归零,该增益消失以使Hp保留100|在10s内Hp归零,得分? |10秒内下一次攻击增伤1800000|10秒内有一次攻击,得分? | | |||
| | AddHpOrAp |回血1500000 | 回血成功 | 10秒内下一次攻击增伤1800000|10秒内有一次攻击,得分? | | |||
| | ShieldOrSpear | 10秒内能抵挡一次伤害 | 10秒内成功抵挡一次伤害 |10秒内下一次攻击能破盾,如果对方无盾,则增伤900000| 10秒内攻击中学生| | |||
| | Key3 | 能开启3教的门 |不得分| 能开启3教的门 |不得分| | |||
| @@ -494,168 +494,13 @@ | |||
| public int SkillCD => GameData.commonSkillCD; | |||
| public int DurationTime => 0; | |||
| ~~~ | |||
| 使用瞬间,在视野范围内的捣蛋鬼会被眩晕(3070+ 玩家损失的血量 / 1000)ms, | |||
| 使用瞬间,在可视范围内的使用技能状态中、攻击前后摇、开锁门、开箱的捣蛋鬼会被眩晕(3070+ 玩家损失的血量 / 1000)ms, | |||
| ## 游戏数据 | |||
| ### 基本常数 | |||
| ~~~csharp | |||
| public const int numOfStepPerSecond = 20; // 每秒行走的步数 | |||
| public const int frameDuration = 50; // 每帧时长 | |||
| public const int checkInterval = 50; // 检查位置标志、补充子弹的帧时长 | |||
| public const long gameDuration = 600000; // 游戏时长600000ms = 10min | |||
| public const int MinSpeed = 1; // 最小速度 | |||
| public const int MaxSpeed = int.MaxValue; // 最大速度 | |||
| #endregion | |||
| #region 地图相关 | |||
| public const int numOfPosGridPerCell = 1000; // 每格的【坐标单位】数 | |||
| public const int lengthOfMap = 50000; // 地图长度 | |||
| public const int rows = 50; // 行数 | |||
| public const int cols = 50; // 列数 | |||
| public const int numOfBirthPoint = 5; | |||
| public const int numOfGenerator = 9; | |||
| public const int numOfChest = 8; | |||
| public static XY GetCellCenterPos(int x, int y) // 求格子的中心坐标 | |||
| { | |||
| XY ret = new(x * numOfPosGridPerCell + numOfPosGridPerCell / 2, y * numOfPosGridPerCell + numOfPosGridPerCell / 2); | |||
| return ret; | |||
| } | |||
| public static int PosGridToCellX(XY pos) // 求坐标所在的格子的x坐标 | |||
| { | |||
| return pos.x / numOfPosGridPerCell; | |||
| } | |||
| public static int PosGridToCellY(XY pos) // 求坐标所在的格子的y坐标 | |||
| { | |||
| return pos.y / numOfPosGridPerCell; | |||
| } | |||
| public static XY PosGridToCellXY(XY pos) // 求坐标所在的格子的Xy坐标 | |||
| { | |||
| return new XY(pos.x / numOfPosGridPerCell, pos.y / numOfPosGridPerCell); | |||
| } | |||
| ~~~ | |||
| ### 角色相关 | |||
| ~~~csharp | |||
| public const int numOfStudent = 4; | |||
| public const int characterRadius = numOfPosGridPerCell / 2 / 5 * 4; // 人物半径 | |||
| public const int basicTreatSpeed = 100; | |||
| public const int basicFixSpeed = 100; | |||
| public const int basicSpeedOfOpeningOrLocking = 3280; | |||
| public const int basicStudentSpeedOfClimbingThroughWindows = 611; | |||
| public const int basicGhostSpeedOfClimbingThroughWindows = 1270; | |||
| public const int basicSpeedOfOpenChest = 1000; | |||
| public const int basicHp = 3000000; // 初始血量 | |||
| public const int basicMaxGamingAddiction = 60000;//基本完全沉迷时间 | |||
| public const int BeginGamingAddiction = 10003; | |||
| public const int MidGamingAddiction = 30000; | |||
| public const int basicTreatmentDegree = 1500000; | |||
| public const int basicTimeOfRescue = 1000; | |||
| public const int basicMoveSpeed = 1270; // 基本移动速度,单位:s-1 | |||
| public const int characterMaxSpeed = 12000; // 最大速度 | |||
| public const int basicBulletMoveSpeed = 2700; // 基本子弹移动速度,单位:s-1 | |||
| public const double basicConcealment = 1.0; | |||
| public const int basicAlertnessRadius = 10700; | |||
| public const int basicViewRange = 5 * numOfPosGridPerCell; | |||
| public const int maxNumOfPropInPropInventory = 3; | |||
| ~~~ | |||
| ### 得分相关 | |||
| ~~~csharp | |||
| public static int TrickerScoreAttackStudent(int damage) | |||
| { | |||
| return damage * 100 / basicApOfGhost; | |||
| } | |||
| public const int TrickerScoreStudentBeAddicted = 50; | |||
| public const int TrickerScoreStudentBeStunned = 25; | |||
| public const int TrickerScoreStudentDie = 1000; | |||
| public static int StudentScoreFix(int degreeOfFix) | |||
| { | |||
| return degreeOfFix; | |||
| } | |||
| public const int StudentScoreFixed = 25; | |||
| public static int StudentScorePinDown(int timeOfPiningDown) | |||
| { | |||
| return 0; | |||
| } | |||
| public const int StudentScoreTrickerBeStunned = 25; | |||
| public const int StudentScoreRescue = 100; | |||
| public static int StudentScoreTreat(int degree) | |||
| { | |||
| return degree; | |||
| } | |||
| public const int StudentScoreEscape = 1000; | |||
| public const int ScorePropRemainHp = 20; | |||
| public const int ScorePropUseShield = 20; | |||
| public const int ScorePropUseSpear = 20; | |||
| public const int ScorePropAddAp = 10; | |||
| public const int ScorePropAddHp = 50; | |||
| ~~~ | |||
| ### 攻击与子弹相关 | |||
| ~~~csharp | |||
| public const int basicApOfGhost = 1500000; // 捣蛋鬼攻击力 | |||
| 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 basicBulletMoveSpeed = 2700; // 基本子弹移动速度,单位:s-1 | |||
| public const double basicRemoteAttackRange = 9000; // 基本远程攻击范围 | |||
| public const double basicAttackShortRange = 2700; // 基本近程攻击范围 | |||
| public const double basicBulletBombRange = 3000; // 基本子弹爆炸范围 | |||
| ~~~ | |||
| ### 技能相关 | |||
| ~~~csharp | |||
| public const int maxNumOfSkill = 3; | |||
| public const int commonSkillCD = 30000; // 普通技能标准冷却时间 | |||
| public const int commonSkillTime = 10000; // 普通技能标准持续时间 | |||
| ~~~ | |||
| ### 道具相关 | |||
| ~~~csharp | |||
| public const int MinPropTypeNum = 1; | |||
| public const int MaxPropTypeNum = 10; | |||
| public const int PropRadius = numOfPosGridPerCell / 2; | |||
| public const int PropMoveSpeed = 3000; | |||
| public const int PropMaxMoveDistance = 15 * numOfPosGridPerCell; | |||
| public const long PropProduceTime = 20000; | |||
| public const int PropDuration = 10000; | |||
| public const int ApPropAdd = basicApOfGhost * 12 / 10; | |||
| public const int ApSpearAdd = basicApOfGhost * 6 / 10; | |||
| public const int RemainHpWhenAddLife = 100; | |||
| public const int numOfKeyEachArea = 2; | |||
| public const int numOfPropTypeNotKey = 4; | |||
| public const int numOfTeachingBuilding = 3; | |||
| ~~~ | |||
| ### 物体相关 | |||
| ~~~csharp | |||
| public const int degreeOfFixedGenerator = 10300000; | |||
| public const int degreeOfLockingOrOpeningTheDoor = 10000; | |||
| public const int degreeOfOpeningChest = 10000; | |||
| public const int degreeOfOpenedDoorway = 18000; | |||
| public const int maxNumOfPropInChest = 2; | |||
| public const int numOfGeneratorRequiredForRepair = 7; | |||
| public const int numOfGeneratorRequiredForEmergencyExit = 3; | |||
| ~~~ | |||
| 请自行查看Logic/Preparation/Utility/GameData.cs | |||
| ## 键鼠控制 | |||
| @@ -686,3 +531,4 @@ | |||
| >>>>>>> 4219415cba0600879a5b134a4067e729c868e84b | |||