| @@ -1,5 +1,5 @@ | |||||
| # 规则 | # 规则 | ||||
| V5.5 | |||||
| V5.6 | |||||
| - [规则](#规则) | - [规则](#规则) | ||||
| - [简则](#简则) | - [简则](#简则) | ||||
| - [地图](#地图) | - [地图](#地图) | ||||
| @@ -192,7 +192,7 @@ $$ | |||||
| | :------------ | :--------------------- | :--------------------- | :--------------------- | :--------------------- | | | :------------ | :--------------------- | :--------------------- | :--------------------- | :--------------------- | | ||||
| | 移动速度/s | 3960 | 3600 | 3852 | 3600 | | | 移动速度/s | 3960 | 3600 | 3852 | 3600 | | ||||
| | 隐蔽度 | 1.5 | 1 | 0.8 | 0.75| | | 隐蔽度 | 1.5 | 1 | 0.8 | 0.75| | ||||
| | 警戒范围 | 22,100 | 17000 | 15300 | 17000 | |||||
| | 警戒范围 | 22100 | 17000 | 15300 | 17000| | |||||
| | 视野范围 | 15600 | 13000 | 13000 | 14300| | | 视野范围 | 15600 | 13000 | 13000 | 14300| | ||||
| | 开锁门速度/ms | 4000 | 4000 | 4000 |4000 | | | 开锁门速度/ms | 4000 | 4000 | 4000 |4000 | | ||||
| | 翻窗速度/s | 2540 | 2540 | 2794 | 2540| | | 翻窗速度/s | 2540 | 2540 | 2794 | 2540| | ||||
| @@ -246,14 +246,14 @@ $$ | |||||
| | :------------ | :--------------------- | :--------------------- | :--------------------- | :--------------------- | | | :------------ | :--------------------- | :--------------------- | :--------------------- | :--------------------- | | ||||
| | 移动速度/s | 2700 | 3150 | 2880 | 3000 | | | 移动速度/s | 2700 | 3150 | 2880 | 3000 | | ||||
| | 最大毅力值 | 30000000 | 3000000 | 3300000 | 3200000 | | | 最大毅力值 | 30000000 | 3000000 | 3300000 | 3200000 | | ||||
| | 最大沉迷度 | 600000 | 54,000 | 78,000 | 66,000 | | |||||
| | 学习一科速度 | 0 | 73 | 135 | 123 | | |||||
| | 最大沉迷度 | 600000 | 54000 | 78000 | 66000 | | |||||
| | 学习速度/ms | 0 | 73 | 135 | 123 | | |||||
| | 勉励速度/ms | 80 | 90 | 100 | 120 | | | 勉励速度/ms | 80 | 90 | 100 | 120 | | ||||
| | 隐蔽度 | 0.5 | 0.9 | 0.9 | 0.8 | | | 隐蔽度 | 0.5 | 0.9 | 0.9 | 0.8 | | ||||
| | 警戒范围 | 7500 | 15000 | 13,500 | 15000 | | |||||
| | 视野范围 | 9,000 | 11000 | 9,000 | 10000 | | |||||
| | 警戒范围 | 7500 | 15000 | 13500 | 15000 | | |||||
| | 视野范围 | 9000 | 11000 | 9000 | 10000 | | |||||
| | 开锁门速度/ms | 4000 | 4000 | 4000 | 2800 | | | 开锁门速度/ms | 4000 | 4000 | 4000 | 2800 | | ||||
| | 翻窗速度/ms | 1270 | 3048 | 2116 | 2540 | | |||||
| | 翻窗速度/ms | 611 | 1466 | 1018 | 1222 | | |||||
| | 翻箱速度/ms | 1000 | 1000 | 1000 | 900 | | | 翻箱速度/ms | 1000 | 1000 | 1000 | 900 | | ||||
| #### 运动员 | #### 运动员 | ||||
| @@ -0,0 +1,89 @@ | |||||
| # 游戏机制与平衡性调整更新草案 | |||||
| v1.0 | |||||
| ## 说明 | |||||
| - 该草案尚未完全确定,请大家不要过分依靠该文档进行修改自己的代码 | |||||
| - 有任何问题都可以在选手群中提出建议和讨论 | |||||
| ## 游戏接口 | |||||
| 删除structures.h中Player的属性place | |||||
| ## 游戏规则 | |||||
| ## 游戏机制 | |||||
| ## 攻击 | |||||
| - 飞刀FlyingKnife | |||||
| - 前摇变为600ms | |||||
| - 搞蛋鬼的一般攻击CommonAttackOfTricker | |||||
| - 改为“不能攻击未写完的作业” | |||||
| - 蹦蹦炸弹BombBomb | |||||
| - 增强为“可以攻击未写完的作业” | |||||
| - 增强为“可以攻击使门被打开(可以重新被锁上)” | |||||
| - strike(新增) | |||||
| - 可以攻击未写完的作业 | |||||
| 修改后: | |||||
| | 攻击(子弹)类型 |搞蛋鬼的一般攻击CommonAttackOfTricker|飞刀FlyingKnife | 蹦蹦炸弹BombBomb | 小炸弹JumpyDumpty | strike | | |||||
| | :--------------------- | :---------------------| :--------------------- | :--------------------- | :--------------------- | :--------------------- | | |||||
| | 子弹爆炸范围 | 0 | 0 | 2000 | 1000 | 0 | | |||||
| | 子弹攻击距离 | 2200 | 78000 | 2200 | 4400 | 2000 | | |||||
| | 攻击力 | 1500000 | 1200000 | 1800000 | 900000 | 1600000 | | |||||
| | 移动速度/s | 7400 | 18500 | 6000 | 8600 | 6250 | | |||||
| | 前摇(ms) | 297 | 600 | 366 | - | 320 | | |||||
| |未攻击至目标时的后摇(ms)| 800 | 0 | 3700 | - | 800 | | |||||
| |攻击至目标时的后摇(ms) | 3700 | 0 | 3700 | - | 3700 | | |||||
| | CD(ms) | 800 | 400 | 3000 | - | 800 | | |||||
| | 最大子弹容量 | 1 | 1 | 1 | - | 1 | | |||||
| ## 职业 | |||||
| - 所有角色开锁门速度加速至1.25倍 | |||||
| - 所有角色翻箱速度加速至1.25倍 | |||||
| ### 学生 | |||||
| - 先前学生翻窗数据有误 | |||||
| - Teacher | |||||
| - Teacher的学习速度由0改为43 | |||||
| - 警戒范围由7500改为13000 | |||||
| - 技能惩罚(Punish)强化为“使用瞬间,在**视野距离范围内(不是可视范围)的**、翻窗、开锁门、攻击前后摇、**使用技能期间**的捣蛋鬼会被眩晕(3070+**500***已受伤害/基本伤害(1500000))ms” | |||||
| - Robot(新增) | |||||
| - 无技能 | |||||
| - 特性 | |||||
| - 不可被眩晕 | |||||
| - 不可毕业 | |||||
| - 无牵制得分 | |||||
| - 不可使用道具(可以捡起和扔道具) | |||||
| - TechOtaku(新增) | |||||
| - 一名TechOtaku最多可以在场上同时最多拥有3个Robot | |||||
| 0. SummonGolem | |||||
| - CD:40s,持续时间:6s | |||||
| - 在持续时间中,学生进入人物状态进入UsingSpecialSkill,进入其他状态会导致制作机器人失败 | |||||
| - 在持续时间中,学生面前生成道具CraftingBench,该道具被碰撞后消失且制作机器人失败 | |||||
| - 持续时间结束后,道具CraftingBench所在位置生成一个Robot | |||||
| 1. UseRobot | |||||
| - CD:0s,持续时间:0s | |||||
| - TechOtaku的Robot的PlayerId = TechOtaku的PlayerId + n*5(一局游戏理论人数),其中1<=n<=3 | |||||
| 修改后: | |||||
| | 学生职业 | 教师Teacher | 健身狂Athlete |学霸StraightAStudent | 开心果Sunshine | 机器人Robot | TechOtaku | | |||||
| | :------------ | :------------------ | :------------------ | :------------------ | :------------------ | :------------------ | :------------------ | | |||||
| | 移动速度/s | 2700 | 3150 | 2880 | 3000 | 2600 | 2250 | | |||||
| | 最大毅力值 | 30000000 | 3000000 | 3300000 | 3200000 | 900000 | 2700000 | | |||||
| | 最大沉迷度 | 600000 | 54000 | 78000 | 60000 | 0 | 60000 | | |||||
| | 学习速度/ms | 43 | 73 | 135 | 123 | 100 | 130 | | |||||
| | 勉励速度/ms | 80 | 90 | 100 | 120 | 0 | 90 | | |||||
| | 隐蔽度 | 0.5 | 0.9 | 0.9 | 0.8 | 0.8 | 1.1 | | |||||
| | 警戒范围 | 7500 | 15000 | 13500 | 15000 | 0 | 15000 | | |||||
| | 视野范围 | 9000 | 11000 | 9000 | 10000 | 0 | 9000 | | |||||
| | 开锁门速度/ms | 5000 | 5000 | 5000 | 3500 | 0 | 5000 | | |||||
| | 翻窗速度/ms | 611 | 1466 | 1018 | 1222 | 1 | 916 | | |||||
| | 翻箱速度/ms | 1250 | 1250 | 1250 | 1125 | 1000 | 750 | | |||||
| ### 捣蛋鬼 | |||||
| - Assassin | |||||
| - 技能隐身(BecomeInvisible)添加约束条件“使用隐身技能后,人物状态进入UsingSpecialSkill,进入其他状态会使得隐身状态解除" | |||||
| - 喧哗者ANoisyPerson | |||||
| - 普通攻击改为strike | |||||
| - Klee | |||||
| - 被动技能Lucky!(新增):开局获得随机的一个道具(不会是钥匙) | |||||
| @@ -0,0 +1,9 @@ | |||||
| # 版本更新说明 | |||||
| # 说明 | |||||
| - 只说明对于选手较为重要的修改 | |||||
| # 等待更新的更改 | |||||
| - docs:添加了 游戏机制与平衡性调整更新草案.pdf | |||||
| - docs:添加了 版本更新说明.pdf | |||||
| - docs&hotfix: 修正了GameRules.pdf中学生翻窗速度的错误 | |||||
| @@ -13,7 +13,6 @@ namespace GameClass.GameObj | |||||
| public BombedBullet(Bullet bullet) : | public BombedBullet(Bullet bullet) : | ||||
| base(bullet.Position, bullet.Radius, GameObjType.BombedBullet) | base(bullet.Position, bullet.Radius, GameObjType.BombedBullet) | ||||
| { | { | ||||
| this.place = bullet.Place; | |||||
| this.bulletHasBombed = bullet; | this.bulletHasBombed = bullet; | ||||
| this.MappingID = bullet.ID; | this.MappingID = bullet.ID; | ||||
| this.FacingDirection = bullet.FacingDirection; | this.FacingDirection = bullet.FacingDirection; | ||||
| @@ -5,8 +5,8 @@ namespace GameClass.GameObj | |||||
| { | { | ||||
| internal sealed class CommonAttackOfGhost : Bullet | internal sealed class CommonAttackOfGhost : Bullet | ||||
| { | { | ||||
| public CommonAttackOfGhost(Character player, PlaceType placeType, XY pos, int radius = GameData.bulletRadius) : | |||||
| base(player, radius, placeType, pos) | |||||
| public CommonAttackOfGhost(Character player, XY pos, int radius = GameData.bulletRadius) : | |||||
| base(player, radius, pos) | |||||
| { | { | ||||
| } | } | ||||
| public override double BulletBombRange => 0; | public override double BulletBombRange => 0; | ||||
| @@ -52,8 +52,8 @@ namespace GameClass.GameObj | |||||
| internal sealed class FlyingKnife : Bullet | internal sealed class FlyingKnife : Bullet | ||||
| { | { | ||||
| public FlyingKnife(Character player, PlaceType placeType, XY pos, int radius = GameData.bulletRadius) : | |||||
| base(player, radius, placeType, pos) | |||||
| public FlyingKnife(Character player, XY pos, int radius = GameData.bulletRadius) : | |||||
| base(player, radius, pos) | |||||
| { | { | ||||
| } | } | ||||
| public override double BulletBombRange => 0; | public override double BulletBombRange => 0; | ||||
| @@ -100,8 +100,7 @@ namespace GameClass.GameObj | |||||
| internal sealed class BombBomb : Bullet | internal sealed class BombBomb : Bullet | ||||
| { | { | ||||
| public BombBomb(Character player, PlaceType placeType, XY pos, int radius = GameData.bulletRadius) : | |||||
| base(player, radius, placeType, pos) | |||||
| public BombBomb(Character player, XY pos, int radius = GameData.bulletRadius) : base(player, radius, pos) | |||||
| { | { | ||||
| } | } | ||||
| public override double BulletBombRange => GameData.basicBulletBombRange; | public override double BulletBombRange => GameData.basicBulletBombRange; | ||||
| @@ -146,8 +145,7 @@ namespace GameClass.GameObj | |||||
| } | } | ||||
| internal sealed class JumpyDumpty : Bullet | internal sealed class JumpyDumpty : Bullet | ||||
| { | { | ||||
| public JumpyDumpty(Character player, PlaceType placeType, XY pos, int radius = GameData.bulletRadius) : | |||||
| base(player, radius, placeType, pos) | |||||
| public JumpyDumpty(Character player, XY pos, int radius = GameData.bulletRadius) : base(player, radius, pos) | |||||
| { | { | ||||
| } | } | ||||
| public override double BulletBombRange => GameData.basicBulletBombRange / 2; | public override double BulletBombRange => GameData.basicBulletBombRange / 2; | ||||
| @@ -41,10 +41,9 @@ namespace GameClass.GameObj | |||||
| return true; | return true; | ||||
| return false; | return false; | ||||
| } | } | ||||
| public Bullet(Character player, int radius, PlaceType placeType, XY Position) : | |||||
| public Bullet(Character player, int radius, XY Position) : | |||||
| base(Position, radius, GameObjType.Bullet) | base(Position, radius, GameObjType.Bullet) | ||||
| { | { | ||||
| this.place = placeType; | |||||
| this.CanMove = true; | this.CanMove = true; | ||||
| this.moveSpeed = this.Speed; | this.moveSpeed = this.Speed; | ||||
| this.hasSpear = player.TryUseSpear(); | this.hasSpear = player.TryUseSpear(); | ||||
| @@ -57,18 +56,18 @@ namespace GameClass.GameObj | |||||
| public static class BulletFactory | public static class BulletFactory | ||||
| { | { | ||||
| public static Bullet? GetBullet(Character character, PlaceType place, XY pos) | |||||
| public static Bullet? GetBullet(Character character, XY pos) | |||||
| { | { | ||||
| switch (character.BulletOfPlayer) | switch (character.BulletOfPlayer) | ||||
| { | { | ||||
| case BulletType.FlyingKnife: | case BulletType.FlyingKnife: | ||||
| return new FlyingKnife(character, place, pos); | |||||
| return new FlyingKnife(character, pos); | |||||
| case BulletType.CommonAttackOfGhost: | case BulletType.CommonAttackOfGhost: | ||||
| return new CommonAttackOfGhost(character, place, pos); | |||||
| return new CommonAttackOfGhost(character, pos); | |||||
| case BulletType.JumpyDumpty: | case BulletType.JumpyDumpty: | ||||
| return new JumpyDumpty(character, place, pos); | |||||
| return new JumpyDumpty(character, pos); | |||||
| case BulletType.BombBomb: | case BulletType.BombBomb: | ||||
| return new BombBomb(character, place, pos); | |||||
| return new BombBomb(character, pos); | |||||
| default: | default: | ||||
| return null; | return null; | ||||
| } | } | ||||
| @@ -57,7 +57,6 @@ namespace GameClass.GameObj | |||||
| protected Character(XY initPos, int initRadius, CharacterType characterType) : | protected Character(XY initPos, int initRadius, CharacterType characterType) : | ||||
| base(initPos, initRadius, GameObjType.Character) | base(initPos, initRadius, GameObjType.Character) | ||||
| { | { | ||||
| this.place = PlaceType.Null; | |||||
| this.CanMove = true; | this.CanMove = true; | ||||
| this.score = 0; | this.score = 0; | ||||
| this.buffManager = new BuffManager(); | this.buffManager = new BuffManager(); | ||||
| @@ -58,10 +58,10 @@ namespace GameClass.GameObj | |||||
| /// 进行一次攻击 | /// 进行一次攻击 | ||||
| /// </summary> | /// </summary> | ||||
| /// <returns>攻击操作发出的子弹</returns> | /// <returns>攻击操作发出的子弹</returns> | ||||
| public Bullet? Attack(XY pos, PlaceType place) | |||||
| public Bullet? Attack(XY pos) | |||||
| { | { | ||||
| if (TrySubBulletNum()) | if (TrySubBulletNum()) | ||||
| return BulletFactory.GetBullet(this, place, pos); | |||||
| return BulletFactory.GetBullet(this, pos); | |||||
| else | else | ||||
| return null; | return null; | ||||
| } | } | ||||
| @@ -365,7 +365,6 @@ namespace GameClass.GameObj | |||||
| CanMove = false; | CanMove = false; | ||||
| IsResetting = true; | IsResetting = true; | ||||
| Position = GameData.PosWhoDie; | Position = GameData.PosWhoDie; | ||||
| place = PlaceType.Grass; | |||||
| } | } | ||||
| } | } | ||||
| #endregion | #endregion | ||||
| @@ -14,20 +14,22 @@ namespace GameClass.GameObj | |||||
| protected readonly XY birthPos; | protected readonly XY birthPos; | ||||
| private GameObjType type; | |||||
| private readonly GameObjType type; | |||||
| public GameObjType Type => type; | public GameObjType Type => type; | ||||
| private static long currentMaxID = 0; // 目前游戏对象的最大ID | private static long currentMaxID = 0; // 目前游戏对象的最大ID | ||||
| public const long invalidID = long.MaxValue; // 无效的ID | public const long invalidID = long.MaxValue; // 无效的ID | ||||
| public const long noneID = long.MinValue; | |||||
| public long ID { get; } | public long ID { get; } | ||||
| private XY position; | private XY position; | ||||
| public XY Position | public XY Position | ||||
| { | { | ||||
| get => position; | |||||
| protected | |||||
| set | |||||
| get | |||||
| { | |||||
| lock (gameObjLock) | |||||
| return position; | |||||
| } | |||||
| set | |||||
| { | { | ||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| { | { | ||||
| @@ -36,13 +38,14 @@ namespace GameClass.GameObj | |||||
| } | } | ||||
| } | } | ||||
| protected PlaceType place; | |||||
| public PlaceType Place { get => place; } | |||||
| private XY facingDirection = new(1, 0); | private XY facingDirection = new(1, 0); | ||||
| public XY FacingDirection | public XY FacingDirection | ||||
| { | { | ||||
| get => facingDirection; | |||||
| get | |||||
| { | |||||
| lock (gameObjLock) | |||||
| return facingDirection; | |||||
| } | |||||
| set | set | ||||
| { | { | ||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| @@ -11,7 +11,6 @@ namespace GameClass.GameObj | |||||
| public Chest(XY initPos) : | public Chest(XY initPos) : | ||||
| base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Chest) | base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Chest) | ||||
| { | { | ||||
| this.place = PlaceType.Chest; | |||||
| this.CanMove = false; | this.CanMove = false; | ||||
| } | } | ||||
| public override bool IsRigid => true; | public override bool IsRigid => true; | ||||
| @@ -11,9 +11,25 @@ namespace GameClass.GameObj | |||||
| public Door(XY initPos, PlaceType placeType) : | public Door(XY initPos, PlaceType placeType) : | ||||
| base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Door) | base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Door) | ||||
| { | { | ||||
| this.place = placeType; | |||||
| switch (placeType) | |||||
| { | |||||
| case PlaceType.Door3: | |||||
| doorNum = 3; | |||||
| break; | |||||
| case PlaceType.Door5: | |||||
| doorNum = 5; | |||||
| break; | |||||
| case PlaceType.Door6: | |||||
| default: | |||||
| doorNum = 6; | |||||
| break; | |||||
| } | |||||
| this.CanMove = false; | this.CanMove = false; | ||||
| } | } | ||||
| private readonly int doorNum; | |||||
| public int DoorNum => doorNum; | |||||
| public override bool IsRigid => !isOpen; | public override bool IsRigid => !isOpen; | ||||
| public override ShapeType Shape => ShapeType.Square; | public override ShapeType Shape => ShapeType.Square; | ||||
| @@ -11,7 +11,6 @@ namespace GameClass.GameObj | |||||
| public Doorway(XY initPos) : | public Doorway(XY initPos) : | ||||
| base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Doorway) | base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Doorway) | ||||
| { | { | ||||
| this.place = PlaceType.Doorway; | |||||
| this.CanMove = false; | this.CanMove = false; | ||||
| } | } | ||||
| public override bool IsRigid => true; | public override bool IsRigid => true; | ||||
| @@ -11,7 +11,6 @@ namespace GameClass.GameObj | |||||
| public EmergencyExit(XY initPos) : | public EmergencyExit(XY initPos) : | ||||
| base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.EmergencyExit) | base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.EmergencyExit) | ||||
| { | { | ||||
| this.place = PlaceType.EmergencyExit; | |||||
| this.CanMove = false; | this.CanMove = false; | ||||
| } | } | ||||
| public override bool IsRigid => true; | public override bool IsRigid => true; | ||||
| @@ -10,7 +10,6 @@ namespace GameClass.GameObj | |||||
| public Generator(XY initPos) : | public Generator(XY initPos) : | ||||
| base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Generator) | base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Generator) | ||||
| { | { | ||||
| this.place = PlaceType.Generator; | |||||
| this.CanMove = false; | this.CanMove = false; | ||||
| } | } | ||||
| public override bool IsRigid => true; | public override bool IsRigid => true; | ||||
| @@ -10,7 +10,6 @@ namespace GameClass.GameObj | |||||
| public Wall(XY initPos) : | public Wall(XY initPos) : | ||||
| base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Wall) | base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Wall) | ||||
| { | { | ||||
| this.place = PlaceType.Wall; | |||||
| this.CanMove = false; | this.CanMove = false; | ||||
| } | } | ||||
| public override bool IsRigid => true; | public override bool IsRigid => true; | ||||
| @@ -11,7 +11,6 @@ namespace GameClass.GameObj | |||||
| public Window(XY initPos) : | public Window(XY initPos) : | ||||
| base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Window) | base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Window) | ||||
| { | { | ||||
| this.place = PlaceType.Window; | |||||
| this.CanMove = false; | this.CanMove = false; | ||||
| } | } | ||||
| public override bool IsRigid => true; | public override bool IsRigid => true; | ||||
| @@ -48,27 +48,17 @@ namespace GameClass.GameObj | |||||
| public int OrgMoveSpeed { get; protected set; } | public int OrgMoveSpeed { get; protected set; } | ||||
| // 移动,改变坐标 | // 移动,改变坐标 | ||||
| public long MovingSetPos(XY moveVec, PlaceType place) | |||||
| public long MovingSetPos(XY moveVec) | |||||
| { | { | ||||
| if (moveVec.x != 0 || moveVec.y != 0) | if (moveVec.x != 0 || moveVec.y != 0) | ||||
| lock (gameObjLock) | lock (gameObjLock) | ||||
| { | { | ||||
| FacingDirection = moveVec; | FacingDirection = moveVec; | ||||
| this.Position += moveVec; | this.Position += moveVec; | ||||
| this.place = place; | |||||
| } | } | ||||
| return moveVec * moveVec; | return moveVec * moveVec; | ||||
| } | } | ||||
| public void ReSetPos(XY pos, PlaceType place) | |||||
| { | |||||
| lock (gameObjLock) | |||||
| { | |||||
| this.Position = pos; | |||||
| this.place = place; | |||||
| } | |||||
| } | |||||
| /// <summary> | /// <summary> | ||||
| /// 设置移动速度 | /// 设置移动速度 | ||||
| /// </summary> | /// </summary> | ||||
| @@ -11,7 +11,6 @@ namespace GameClass.GameObj | |||||
| public OutOfBoundBlock(XY initPos) : | public OutOfBoundBlock(XY initPos) : | ||||
| base(initPos, int.MaxValue, GameObjType.OutOfBoundBlock) | base(initPos, int.MaxValue, GameObjType.OutOfBoundBlock) | ||||
| { | { | ||||
| this.place = PlaceType.Wall; | |||||
| this.CanMove = false; | this.CanMove = false; | ||||
| } | } | ||||
| @@ -17,7 +17,6 @@ namespace GameClass.GameObj | |||||
| public PickedProp(Prop prop) : | public PickedProp(Prop prop) : | ||||
| base(prop.Position, prop.Radius, GameObjType.PickedProp) | base(prop.Position, prop.Radius, GameObjType.PickedProp) | ||||
| { | { | ||||
| this.place = prop.Place; | |||||
| this.PropHasPicked = prop; | this.PropHasPicked = prop; | ||||
| this.MappingID = prop.ID; | this.MappingID = prop.ID; | ||||
| } | } | ||||
| @@ -19,10 +19,9 @@ namespace GameClass.GameObj | |||||
| public abstract PropType GetPropType(); | public abstract PropType GetPropType(); | ||||
| public Prop(XY initPos, PlaceType place, int radius = GameData.PropRadius) : | |||||
| public Prop(XY initPos, int radius = GameData.PropRadius) : | |||||
| base(initPos, radius, GameObjType.Prop) | base(initPos, radius, GameObjType.Prop) | ||||
| { | { | ||||
| this.place = place; | |||||
| this.CanMove = false; | this.CanMove = false; | ||||
| this.moveSpeed = GameData.PropMoveSpeed; | this.moveSpeed = GameData.PropMoveSpeed; | ||||
| } | } | ||||
| @@ -43,8 +42,8 @@ namespace GameClass.GameObj | |||||
| /// </summary> | /// </summary> | ||||
| public sealed class AddSpeed : Prop | public sealed class AddSpeed : Prop | ||||
| { | { | ||||
| public AddSpeed(XY initPos, PlaceType placeType) : | |||||
| base(initPos, placeType) | |||||
| public AddSpeed(XY initPos) : | |||||
| base(initPos) | |||||
| { | { | ||||
| } | } | ||||
| public override PropType GetPropType() => PropType.AddSpeed; | public override PropType GetPropType() => PropType.AddSpeed; | ||||
| @@ -54,24 +53,24 @@ namespace GameClass.GameObj | |||||
| /// </summary> | /// </summary> | ||||
| public sealed class AddLifeOrClairaudience : Prop | public sealed class AddLifeOrClairaudience : Prop | ||||
| { | { | ||||
| public AddLifeOrClairaudience(XY initPos, PlaceType placeType) : | |||||
| base(initPos, placeType) | |||||
| public AddLifeOrClairaudience(XY initPos) : | |||||
| base(initPos) | |||||
| { | { | ||||
| } | } | ||||
| public override PropType GetPropType() => PropType.AddLifeOrClairaudience; | public override PropType GetPropType() => PropType.AddLifeOrClairaudience; | ||||
| } | } | ||||
| public sealed class AddHpOrAp : Prop | public sealed class AddHpOrAp : Prop | ||||
| { | { | ||||
| public AddHpOrAp(XY initPos, PlaceType placeType) : | |||||
| base(initPos, placeType) | |||||
| public AddHpOrAp(XY initPos) : | |||||
| base(initPos) | |||||
| { | { | ||||
| } | } | ||||
| public override PropType GetPropType() => PropType.AddHpOrAp; | public override PropType GetPropType() => PropType.AddHpOrAp; | ||||
| } | } | ||||
| public sealed class RecoveryFromDizziness : Prop | public sealed class RecoveryFromDizziness : Prop | ||||
| { | { | ||||
| public RecoveryFromDizziness(XY initPos, PlaceType placeType) : | |||||
| base(initPos, placeType) | |||||
| public RecoveryFromDizziness(XY initPos) : | |||||
| base(initPos) | |||||
| { | { | ||||
| } | } | ||||
| public override PropType GetPropType() => PropType.RecoveryFromDizziness; | public override PropType GetPropType() => PropType.RecoveryFromDizziness; | ||||
| @@ -81,35 +80,35 @@ namespace GameClass.GameObj | |||||
| /// </summary> | /// </summary> | ||||
| public sealed class ShieldOrSpear : Prop | public sealed class ShieldOrSpear : Prop | ||||
| { | { | ||||
| public ShieldOrSpear(XY initPos, PlaceType placeType) : base(initPos, placeType) | |||||
| public ShieldOrSpear(XY initPos) : base(initPos) | |||||
| { | { | ||||
| } | } | ||||
| public override PropType GetPropType() => PropType.ShieldOrSpear; | public override PropType GetPropType() => PropType.ShieldOrSpear; | ||||
| } | } | ||||
| public sealed class Key3 : Prop | public sealed class Key3 : Prop | ||||
| { | { | ||||
| public Key3(XY initPos, PlaceType placeType) : base(initPos, placeType) | |||||
| public Key3(XY initPos) : base(initPos) | |||||
| { | { | ||||
| } | } | ||||
| public override PropType GetPropType() => PropType.Key3; | public override PropType GetPropType() => PropType.Key3; | ||||
| } | } | ||||
| public sealed class Key5 : Prop | public sealed class Key5 : Prop | ||||
| { | { | ||||
| public Key5(XY initPos, PlaceType placeType) : base(initPos, placeType) | |||||
| public Key5(XY initPos) : base(initPos) | |||||
| { | { | ||||
| } | } | ||||
| public override PropType GetPropType() => PropType.Key5; | public override PropType GetPropType() => PropType.Key5; | ||||
| } | } | ||||
| public sealed class Key6 : Prop | public sealed class Key6 : Prop | ||||
| { | { | ||||
| public Key6(XY initPos, PlaceType placeType) : base(initPos, placeType) | |||||
| public Key6(XY initPos) : base(initPos) | |||||
| { | { | ||||
| } | } | ||||
| public override PropType GetPropType() => PropType.Key6; | public override PropType GetPropType() => PropType.Key6; | ||||
| } | } | ||||
| public sealed class NullProp : Prop | public sealed class NullProp : Prop | ||||
| { | { | ||||
| public NullProp(PlaceType placeType = PlaceType.Wall) : base(new XY(1, 1), placeType) | |||||
| public NullProp() : base(new XY(1, 1)) | |||||
| { | { | ||||
| } | } | ||||
| public override PropType GetPropType() => PropType.Null; | public override PropType GetPropType() => PropType.Null; | ||||
| @@ -143,26 +142,26 @@ namespace GameClass.GameObj | |||||
| // #endregion | // #endregion | ||||
| public static class PropFactory | public static class PropFactory | ||||
| { | { | ||||
| public static Prop GetProp(PropType propType, XY pos, PlaceType place) | |||||
| public static Prop GetProp(PropType propType, XY pos) | |||||
| { | { | ||||
| switch (propType) | switch (propType) | ||||
| { | { | ||||
| case PropType.AddSpeed: | case PropType.AddSpeed: | ||||
| return new AddSpeed(pos, place); | |||||
| return new AddSpeed(pos); | |||||
| case PropType.AddLifeOrClairaudience: | case PropType.AddLifeOrClairaudience: | ||||
| return new AddLifeOrClairaudience(pos, place); | |||||
| return new AddLifeOrClairaudience(pos); | |||||
| case PropType.ShieldOrSpear: | case PropType.ShieldOrSpear: | ||||
| return new ShieldOrSpear(pos, place); | |||||
| return new ShieldOrSpear(pos); | |||||
| case PropType.AddHpOrAp: | case PropType.AddHpOrAp: | ||||
| return new AddHpOrAp(pos, place); | |||||
| return new AddHpOrAp(pos); | |||||
| case PropType.RecoveryFromDizziness: | case PropType.RecoveryFromDizziness: | ||||
| return new RecoveryFromDizziness(pos, place); | |||||
| return new RecoveryFromDizziness(pos); | |||||
| case PropType.Key3: | case PropType.Key3: | ||||
| return new Key3(pos, place); | |||||
| return new Key3(pos); | |||||
| case PropType.Key5: | case PropType.Key5: | ||||
| return new Key5(pos, place); | |||||
| return new Key5(pos); | |||||
| case PropType.Key6: | case PropType.Key6: | ||||
| return new Key6(pos, place); | |||||
| return new Key6(pos); | |||||
| default: | default: | ||||
| return new NullProp(); | return new NullProp(); | ||||
| } | } | ||||
| @@ -70,7 +70,7 @@ namespace GameEngine | |||||
| XY nextPos = obj.Position + moveVec; | XY nextPos = obj.Position + moveVec; | ||||
| double maxLen = collisionChecker.FindMax(obj, nextPos, moveVec); | double maxLen = collisionChecker.FindMax(obj, nextPos, moveVec); | ||||
| maxLen = Math.Min(maxLen, obj.MoveSpeed / GameData.numOfStepPerSecond); | maxLen = Math.Min(maxLen, obj.MoveSpeed / GameData.numOfStepPerSecond); | ||||
| obj.MovingSetPos(new XY(moveVec, maxLen), GetPlaceType(nextPos)); | |||||
| obj.MovingSetPos(new XY(moveVec, maxLen)); | |||||
| } | } | ||||
| public void MoveObj(IMoveable obj, int moveTime, double direction) | public void MoveObj(IMoveable obj, int moveTime, double direction) | ||||
| @@ -90,7 +90,7 @@ namespace GameEngine | |||||
| double moveVecLength = 0.0; | double moveVecLength = 0.0; | ||||
| XY res = new(direction, moveVecLength); | XY res = new(direction, moveVecLength); | ||||
| double deltaLen = moveVecLength - Math.Sqrt(obj.MovingSetPos(res, GetPlaceType(obj.Position + res))); // 转向,并用deltaLen存储行走的误差 | |||||
| double deltaLen = moveVecLength - Math.Sqrt(obj.MovingSetPos(res)); // 转向,并用deltaLen存储行走的误差 | |||||
| IGameObj? collisionObj = null; | IGameObj? collisionObj = null; | ||||
| bool isDestroyed = false; | bool isDestroyed = false; | ||||
| @@ -156,7 +156,7 @@ namespace GameEngine | |||||
| } while (flag); | } while (flag); | ||||
| if (threadNum == 0 || ((ICharacter)obj).ThreadNum == threadNum) | if (threadNum == 0 || ((ICharacter)obj).ThreadNum == threadNum) | ||||
| deltaLen += moveVecLength - Math.Sqrt(obj.MovingSetPos(res, GetPlaceType(obj.Position + res))); | |||||
| deltaLen += moveVecLength - Math.Sqrt(obj.MovingSetPos(res)); | |||||
| return true; | return true; | ||||
| }, | }, | ||||
| @@ -175,7 +175,7 @@ namespace GameEngine | |||||
| if ((collisionObj = collisionChecker.CheckCollisionWhenMoving(obj, res)) == null) | if ((collisionObj = collisionChecker.CheckCollisionWhenMoving(obj, res)) == null) | ||||
| { | { | ||||
| if (threadNum == 0 || ((ICharacter)obj).ThreadNum == threadNum) | if (threadNum == 0 || ((ICharacter)obj).ThreadNum == threadNum) | ||||
| obj.MovingSetPos(res, GetPlaceType(obj.Position + res)); | |||||
| obj.MovingSetPos(res); | |||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| @@ -267,7 +267,7 @@ namespace Gaming | |||||
| { | { | ||||
| Prop prop = chestToOpen.PropInChest[i]; | Prop prop = chestToOpen.PropInChest[i]; | ||||
| chestToOpen.PropInChest[i] = new NullProp(); | chestToOpen.PropInChest[i] = new NullProp(); | ||||
| prop.ReSetPos(player.Position, gameMap.GetPlaceType(player.Position)); | |||||
| prop.Position = player.Position; | |||||
| gameMap.Add(prop); | gameMap.Add(prop); | ||||
| } | } | ||||
| } | } | ||||
| @@ -295,7 +295,7 @@ namespace Gaming | |||||
| if (characterInWindow != null) | if (characterInWindow != null) | ||||
| { | { | ||||
| if (player.IsGhost() && !characterInWindow.IsGhost()) | if (player.IsGhost() && !characterInWindow.IsGhost()) | ||||
| characterManager.BeAttacked((Student)(characterInWindow), player.Attack(characterInWindow.Position, PlaceType.Null)); | |||||
| characterManager.BeAttacked((Student)(characterInWindow), player.Attack(characterInWindow.Position)); | |||||
| return false; | return false; | ||||
| }*/ | }*/ | ||||
| @@ -323,7 +323,7 @@ namespace Gaming | |||||
| return; | return; | ||||
| } | } | ||||
| player.ReSetPos(windowToPlayer + windowForClimb.Position, PlaceType.Window); | |||||
| player.Position = windowToPlayer + windowForClimb.Position; | |||||
| player.MoveSpeed = player.SpeedOfClimbingThroughWindows; | 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()); | ||||
| @@ -339,7 +339,7 @@ namespace Gaming | |||||
| ) | ) | ||||
| .Start(); | .Start(); | ||||
| XY PosJumpOff = windowForClimb.Position - 2 * windowToPlayer; | XY PosJumpOff = windowForClimb.Position - 2 * windowToPlayer; | ||||
| player.ReSetPos(PosJumpOff, gameMap.GetPlaceType(PosJumpOff)); | |||||
| player.Position = PosJumpOff; | |||||
| player.MoveSpeed = player.ReCalculateBuff(BuffType.AddSpeed, player.OrgMoveSpeed, GameData.MaxSpeed, GameData.MinSpeed); | player.MoveSpeed = player.ReCalculateBuff(BuffType.AddSpeed, player.OrgMoveSpeed, GameData.MaxSpeed, GameData.MinSpeed); | ||||
| windowForClimb.WhoIsClimbing = null; | windowForClimb.WhoIsClimbing = null; | ||||
| // gameMap.Remove(addWall); | // gameMap.Remove(addWall); | ||||
| @@ -367,15 +367,15 @@ namespace Gaming | |||||
| switch (prop.GetPropType()) | switch (prop.GetPropType()) | ||||
| { | { | ||||
| case PropType.Key3: | case PropType.Key3: | ||||
| if (doorToLock.Place == PlaceType.Door3) | |||||
| if (doorToLock.DoorNum == 3) | |||||
| flag = true; | flag = true; | ||||
| break; | break; | ||||
| case PropType.Key5: | case PropType.Key5: | ||||
| if (doorToLock.Place == PlaceType.Door5) | |||||
| if (doorToLock.DoorNum == 5) | |||||
| flag = true; | flag = true; | ||||
| break; | break; | ||||
| case PropType.Key6: | case PropType.Key6: | ||||
| if (doorToLock.Place == PlaceType.Door6) | |||||
| if (doorToLock.DoorNum == 6) | |||||
| flag = true; | flag = true; | ||||
| break; | break; | ||||
| default: | default: | ||||
| @@ -178,7 +178,7 @@ namespace Gaming | |||||
| (int)(Math.Abs((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Sin(angle))) * ((Math.Sin(angle) > 0) ? 1 : -1) | (int)(Math.Abs((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Sin(angle))) * ((Math.Sin(angle) > 0) ? 1 : -1) | ||||
| ); | ); | ||||
| Bullet? bullet = player.Attack(res, gameMap.GetPlaceType(res)); | |||||
| Bullet? bullet = player.Attack(res); | |||||
| if (bullet != null) | if (bullet != null) | ||||
| { | { | ||||
| @@ -407,7 +407,7 @@ namespace Gaming | |||||
| Prop? prop = player.UseProp(i); | Prop? prop = player.UseProp(i); | ||||
| if (prop != null) | if (prop != null) | ||||
| { | { | ||||
| prop.ReSetPos(player.Position, gameMap.GetPlaceType(player.Position)); | |||||
| prop.Position = player.Position; | |||||
| gameMap.Add(prop); | gameMap.Add(prop); | ||||
| } | } | ||||
| } | } | ||||
| @@ -124,13 +124,13 @@ namespace Gaming | |||||
| if (prop.GetPropType() == PropType.Null) | if (prop.GetPropType() == PropType.Null) | ||||
| return; | return; | ||||
| prop.ReSetPos(player.Position, gameMap.GetPlaceType(player.Position)); | |||||
| prop.Position = player.Position; | |||||
| gameMap.Add(prop); | gameMap.Add(prop); | ||||
| } | } | ||||
| private Prop ProduceOnePropNotKey(Random r, XY Pos) | |||||
| private static Prop ProduceOnePropNotKey(Random r, XY Pos) | |||||
| { | { | ||||
| return PropFactory.GetProp((PropType)r.Next(GameData.numOfTeachingBuilding + 1, GameData.numOfPropSpecies + 1), Pos, gameMap.GetPlaceType(Pos)); | |||||
| return PropFactory.GetProp((PropType)r.Next(GameData.numOfTeachingBuilding + 1, GameData.numOfPropSpecies + 1), Pos); | |||||
| } | } | ||||
| private Chest GetChest(Random r) | private Chest GetChest(Random r) | ||||
| @@ -153,7 +153,7 @@ namespace Gaming | |||||
| { | { | ||||
| ++cou; | ++cou; | ||||
| Chest chest = GetChest(r); | Chest chest = GetChest(r); | ||||
| chest.PropInChest[1] = new Key3(chest.Position, PlaceType.Chest); | |||||
| chest.PropInChest[1] = new Key3(chest.Position); | |||||
| chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); | chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); | ||||
| } | } | ||||
| cou = 0; | cou = 0; | ||||
| @@ -161,7 +161,7 @@ namespace Gaming | |||||
| { | { | ||||
| ++cou; | ++cou; | ||||
| Chest chest = GetChest(r); | Chest chest = GetChest(r); | ||||
| chest.PropInChest[1] = new Key5(chest.Position, PlaceType.Chest); | |||||
| chest.PropInChest[1] = new Key5(chest.Position); | |||||
| chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); | chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); | ||||
| } | } | ||||
| cou = 0; | cou = 0; | ||||
| @@ -169,7 +169,7 @@ namespace Gaming | |||||
| { | { | ||||
| ++cou; | ++cou; | ||||
| Chest chest = GetChest(r); | Chest chest = GetChest(r); | ||||
| chest.PropInChest[1] = new Key6(chest.Position, PlaceType.Chest); | |||||
| chest.PropInChest[1] = new Key6(chest.Position); | |||||
| chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); | chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); | ||||
| } | } | ||||
| @@ -7,7 +7,6 @@ namespace Preparation.Interface | |||||
| public GameObjType Type { get; } | public GameObjType Type { get; } | ||||
| public long ID { get; } | public long ID { get; } | ||||
| public XY Position { get; } // if Square, Pos equals the center | public XY Position { get; } // if Square, Pos equals the center | ||||
| public PlaceType Place { get; } | |||||
| public XY FacingDirection { get; } | public XY FacingDirection { get; } | ||||
| public bool IsRigid { get; } | public bool IsRigid { get; } | ||||
| public ShapeType Shape { get; } | public ShapeType Shape { get; } | ||||
| @@ -9,8 +9,7 @@ namespace Preparation.Interface | |||||
| public int MoveSpeed { get; } | public int MoveSpeed { get; } | ||||
| public bool IsMoving { get; set; } | public bool IsMoving { get; set; } | ||||
| public bool IsAvailable { get; } | public bool IsAvailable { get; } | ||||
| public long MovingSetPos(XY moveVec, PlaceType place); | |||||
| public void ReSetPos(XY pos, PlaceType place); | |||||
| public long MovingSetPos(XY moveVec); | |||||
| public bool WillCollideWith(IGameObj? targetObj, XY nextPos) // 检查下一位置是否会和目标物碰撞 | public bool WillCollideWith(IGameObj? targetObj, XY nextPos) // 检查下一位置是否会和目标物碰撞 | ||||
| { | { | ||||
| if (targetObj == null) | if (targetObj == null) | ||||
| @@ -1,6 +1,5 @@ | |||||
| using Preparation.Interface; | using Preparation.Interface; | ||||
| using System; | using System; | ||||
| using System.Net.NetworkInformation; | |||||
| namespace Preparation.Utility | namespace Preparation.Utility | ||||
| { | { | ||||
| @@ -61,7 +61,6 @@ namespace Server | |||||
| Speed = player.MoveSpeed, | Speed = player.MoveSpeed, | ||||
| Determination = player.HP, | Determination = player.HP, | ||||
| Addiction = player.GamingAddiction, | Addiction = player.GamingAddiction, | ||||
| Place = Transformation.ToPlaceType((Preparation.Utility.PlaceType)player.Place), | |||||
| Guid = player.ID, | Guid = player.ID, | ||||
| PlayerState = Transformation.ToPlayerState((PlayerStateType)player.PlayerState), | PlayerState = Transformation.ToPlayerState((PlayerStateType)player.PlayerState), | ||||
| @@ -108,7 +107,6 @@ namespace Server | |||||
| X = player.Position.x, | X = player.Position.x, | ||||
| Y = player.Position.y, | Y = player.Position.y, | ||||
| Speed = player.MoveSpeed, | Speed = player.MoveSpeed, | ||||
| Place = Transformation.ToPlaceType((Preparation.Utility.PlaceType)player.Place), | |||||
| TrickerType = Transformation.ToTrickerType(player.CharacterType), | TrickerType = Transformation.ToTrickerType(player.CharacterType), | ||||
| Guid = player.ID, | Guid = player.ID, | ||||
| @@ -152,7 +150,6 @@ namespace Server | |||||
| FacingDirection = bullet.FacingDirection.Angle(), | FacingDirection = bullet.FacingDirection.Angle(), | ||||
| Guid = bullet.ID, | Guid = bullet.ID, | ||||
| Team = (bullet.Parent!.IsGhost()) ? PlayerType.TrickerPlayer : PlayerType.StudentPlayer, | Team = (bullet.Parent!.IsGhost()) ? PlayerType.TrickerPlayer : PlayerType.StudentPlayer, | ||||
| Place = Transformation.ToPlaceType((Preparation.Utility.PlaceType)bullet.Place), | |||||
| BombRange = bullet.BulletBombRange, | BombRange = bullet.BulletBombRange, | ||||
| Speed = bullet.Speed | Speed = bullet.Speed | ||||
| } | } | ||||
| @@ -170,8 +167,7 @@ namespace Server | |||||
| X = prop.Position.x, | X = prop.Position.x, | ||||
| Y = prop.Position.y, | Y = prop.Position.y, | ||||
| FacingDirection = prop.FacingDirection.Angle(), | FacingDirection = prop.FacingDirection.Angle(), | ||||
| Guid = prop.ID, | |||||
| Place = Transformation.ToPlaceType((Preparation.Utility.PlaceType)prop.Place) | |||||
| Guid = prop.ID | |||||
| } | } | ||||
| }; | }; | ||||
| return msg; | return msg; | ||||
| @@ -1,6 +1,6 @@ | |||||
| @echo off | @echo off | ||||
| start cmd /k ..\Server\bin\Debug\net6.0\Server.exe --ip 0.0.0.0 --port 8888 --studentCount 0 --trickerCount 1 --gameTimeInSecond 600 --fileName test | |||||
| start cmd /k ..\Server\bin\Debug\net6.0\Server.exe --ip 0.0.0.0 --port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --fileName test | |||||
| ping -n 2 127.0.0.1 > NUL | ping -n 2 127.0.0.1 > NUL | ||||