| @@ -147,8 +147,8 @@ start python .\CAPI\python\PyAPI\main.py -I 127.0.0.1 -P 8888 -p 0 -d -o -w | |||
| | 1 | Athlete | | |||
| | 2 | Teacher | | |||
| | 3 | StraightAStudent | | |||
| | 4 | Robot(目前未实现所有功能) | | |||
| | 5 | TechOtaku(目前未实现所有功能) | | |||
| | 4 | Robot | | |||
| | 5 | TechOtaku | | |||
| | 6 | Sunshine | | |||
| * 捣蛋鬼 | |||
| @@ -51,7 +51,6 @@ v1.6 | |||
| - Teacher | |||
| - 学习速度由0改为50 | |||
| - 警戒范围由7500改为10000 | |||
| - 视野范围由9000降为8000 | |||
| - 翻窗速度改为1000 | |||
| - 特质: | |||
| - 扣血则得分100×受到伤害/基本伤害(1500000) | |||
| @@ -60,7 +59,7 @@ v1.6 | |||
| - “使用瞬间,在**视野距离/3范围内(不是可视范围)的**翻窗、开锁门、攻击前后摇、**使用技能期间**的捣蛋鬼会被眩晕(3070+**500***已受伤害/基本伤害(1500000))ms” | |||
| - 技能喝茶(HaveTea)(新增) | |||
| - CD:90s | |||
| - 在有队友受过伤的情况下,使用瞬间,向当前方向瞬移3000(可以穿墙),如果会碰撞则失败。 | |||
| - 使用瞬间,向额外参数/1000.0的角度瞬移3000(可以穿墙),如果会碰撞则失败。 | |||
| - Robot(新增) | |||
| - 无技能 | |||
| - 特性 | |||
| @@ -71,14 +70,14 @@ v1.6 | |||
| - 不可使用道具(可以捡起和扔道具) | |||
| - TechOtaku(新增) | |||
| - 一名TechOtaku最多可以在场上同时最多拥有3个Robot,无法共享视野 | |||
| 0. SummonGolem | |||
| 1. SummonGolem | |||
| - CD:40s,持续时间:6s | |||
| - 在持续时间中,学生进入人物状态进入UsingSpecialSkill(不能移动),进入其他状态会导致制作机器人失败。 | |||
| - 在持续时间中,学生面前生成道具CraftingBench;学生进入其他状态或该道具被碰撞后,CraftingBench消失且制作机器人失败。 | |||
| - 持续时间结束后,道具CraftingBench所在位置生成一个Robot,CraftingBench消失 | |||
| - TechOtaku的Robot的PlayerId = TechOtaku的PlayerId + n×5(一局游戏理论人数),其中1<=n<=3(自己的n为0) | |||
| - 新造的Robot的PlayerId的n总是尽量小 | |||
| 1. UseRobot | |||
| 2. UseRobot | |||
| - CD:2s,持续时间:0s | |||
| - 输入额外参数PlayerID,切换到要使用的角色。 | |||
| - 切换到其他角色时,自己进入UsingSkill状态。 | |||
| @@ -94,7 +93,7 @@ v1.6 | |||
| | 勉励速度/ms | 80 | 90 | 100 | 120 | 0 | 100 | | |||
| | 隐蔽度 | 0.5 | 0.9 | 0.9 | 0.8 | 0.8 | 1.1 | | |||
| | 警戒范围 | 10000 | 15000 | 13500 | 15000 | 0 | 15000 | | |||
| | 视野范围 | 8000 | 11000 | 9000 | 10000 | 0 | 9000 | | |||
| | 视野范围 | 9000 | 11000 | 9000 | 10000 | 0 | 9000 | | |||
| | 开锁门速度/ms | 5000 | 5000 | 5000 | 3500 | 0 | 5000 | | |||
| | 翻窗速度/ms | 1000 | 1466 | 1018 | 1222 | 1 | 1100 | | |||
| | 翻箱速度/ms | 1250 | 1250 | 1250 | 1125 | 1000 | 1100 | | |||
| @@ -44,5 +44,10 @@ | |||
| - fix:修复了InSpire会给Tricker加速的问题 | |||
| - fix:修复了开锁门的bug | |||
| # 5月19日15:00更新 | |||
| - docs:更新了 游戏机制与平衡性调整更新草案.pdf | |||
| - hotfix:修复了移动状态设置错误 | |||
| # 最新更新 | |||
| - feat:Assassin、Teacher已调整 | |||
| - docs:更新了 游戏机制与平衡性调整更新草案.pdf | |||
| @@ -14,7 +14,7 @@ namespace GameClass.GameObj | |||
| protected int ap; | |||
| public int AP | |||
| { | |||
| get => Interlocked.CompareExchange(ref ap, 0, 1); | |||
| get => Interlocked.CompareExchange(ref ap, 0, 0); | |||
| } | |||
| public void AddAP(int addAp) | |||
| { | |||
| @@ -362,8 +362,7 @@ namespace GameClass.GameObj | |||
| lock (actionLock) | |||
| { | |||
| if (playerState == PlayerStateType.Moving) | |||
| if (IsMoving == 1) return PlayerStateType.Moving; | |||
| else return PlayerStateType.Null; | |||
| return (IsMoving == 1) ? PlayerStateType.Moving : PlayerStateType.Null; | |||
| return playerState; | |||
| } | |||
| } | |||
| @@ -540,27 +539,41 @@ namespace GameClass.GameObj | |||
| ThreadNum.Release(); | |||
| } | |||
| case PlayerStateType.UsingSkill: | |||
| if (CharacterType == CharacterType.TechOtaku) | |||
| { | |||
| if (typeof(CraftingBench).IsInstanceOfType(whatInteractingWith)) | |||
| switch (CharacterType) | |||
| { | |||
| try | |||
| { | |||
| ((CraftingBench)whatInteractingWith!).StopSkill(); | |||
| case CharacterType.TechOtaku: | |||
| { | |||
| if (typeof(CraftingBench).IsInstanceOfType(whatInteractingWith)) | |||
| { | |||
| try | |||
| { | |||
| ((CraftingBench)whatInteractingWith!).StopSkill(); | |||
| return ChangePlayerState(value, gameObj); | |||
| } | |||
| finally | |||
| { | |||
| ThreadNum.Release(); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if (value != PlayerStateType.UsingSkill) | |||
| ((UseRobot)FindActiveSkill(ActiveSkillType.UseRobot)).NowPlayerID = (int)playerID; | |||
| return ChangePlayerState(value, gameObj); | |||
| } | |||
| } | |||
| case CharacterType.Assassin: | |||
| if (value == PlayerStateType.Moving) return StateNum; | |||
| else | |||
| { | |||
| TryDeleteInvisible(); | |||
| return ChangePlayerState(value, gameObj); | |||
| } | |||
| default: | |||
| return ChangePlayerState(value, gameObj); | |||
| } | |||
| finally | |||
| { | |||
| ThreadNum.Release(); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if (value != PlayerStateType.UsingSkill) | |||
| ((UseRobot)FindActiveSkill(ActiveSkillType.UseRobot)).NowPlayerID = (int)playerID; | |||
| } | |||
| } | |||
| return ChangePlayerState(value, gameObj); | |||
| default: | |||
| return ChangePlayerState(value, gameObj); | |||
| } | |||
| @@ -50,7 +50,7 @@ namespace GameClass.GameObj | |||
| private int isMoving = 0; | |||
| public int IsMoving | |||
| { | |||
| get => Interlocked.CompareExchange(ref isMoving, 0, 1); | |||
| get => Interlocked.CompareExchange(ref isMoving, 0, 0); | |||
| set => Interlocked.Exchange(ref isMoving, value); | |||
| } | |||
| @@ -157,7 +157,7 @@ namespace GameClass.GameObj | |||
| /// </summary> | |||
| public int MoveSpeed | |||
| { | |||
| get => Interlocked.CompareExchange(ref moveSpeed, 0, 1); | |||
| get => Interlocked.CompareExchange(ref moveSpeed, 0, 0); | |||
| set => Interlocked.Exchange(ref moveSpeed, value); | |||
| } | |||
| /// <summary> | |||
| @@ -13,7 +13,6 @@ namespace Gaming | |||
| { | |||
| public static bool CanBeginToCharge(Character player) | |||
| { | |||
| if ((!player.Commandable())) return false; | |||
| ActiveSkill skill = player.FindActiveSkill(ActiveSkillType.CanBeginToCharge); | |||
| Debugger.Output(player, "can begin to charge!"); | |||
| @@ -93,19 +92,32 @@ namespace Gaming | |||
| public static bool BecomeInvisible(Character player) | |||
| { | |||
| if ((!player.Commandable())) return false; | |||
| ActiveSkill activeSkill = player.FindActiveSkill(ActiveSkillType.BecomeInvisible); | |||
| long stateNum = player.SetPlayerState(PlayerStateType.UsingSkill); | |||
| if (stateNum == -1) | |||
| { | |||
| return false; | |||
| } | |||
| return ActiveSkillEffect(activeSkill, player, () => | |||
| { | |||
| player.AddScore(GameData.ScoreBecomeInvisible); | |||
| player.AddInvisible(activeSkill.DurationTime); | |||
| Debugger.Output(player, "become invisible!"); | |||
| }, | |||
| () => | |||
| { }); | |||
| () => | |||
| { | |||
| lock (player.ActionLock) | |||
| { | |||
| if (stateNum == player.StateNum) | |||
| { | |||
| player.SetPlayerStateNaturally(); | |||
| } | |||
| } | |||
| } | |||
| ); | |||
| } | |||
| public bool UseRobot(Character player, int robotID) | |||
| public static bool UseRobot(Character player, int robotID) | |||
| { | |||
| if ((robotID - player.PlayerID) % GameData.numOfPeople != 0) return false; | |||
| if ((robotID - (int)player.PlayerID) / GameData.numOfPeople < 0 || (robotID - (int)player.PlayerID) / GameData.numOfPeople > GameData.maxSummonedGolemNum) return false; | |||
| @@ -261,8 +273,7 @@ namespace Gaming | |||
| } | |||
| craftingBench.ParentStateNum = stateNum; | |||
| gameMap.Add(craftingBench); | |||
| /* | |||
| */ | |||
| return ActiveSkillEffect(activeSkill, player, () => | |||
| { | |||
| }, | |||
| @@ -343,8 +354,8 @@ namespace Gaming | |||
| || character.PlayerState == PlayerStateType.ClimbingThroughWindows) | |||
| && XY.DistanceFloor3(character.Position, player.Position) <= player.ViewRange / 3) | |||
| { | |||
| if (CharacterManager.BeStunned(character, GameData.timeOfGhostStunnedWhenPunish + GameData.factorOfTimeStunnedWhenPunish * (player.MaxHp - player.HP)) > 0) | |||
| player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.timeOfGhostStunnedWhenPunish + GameData.factorOfTimeStunnedWhenPunish * (player.MaxHp - player.HP))); | |||
| if (CharacterManager.BeStunned(character, GameData.timeOfGhostStunnedWhenPunish + GameData.factorOfTimeStunnedWhenPunish * (player.MaxHp - player.HP) / GameData.basicApOfGhost) > 0) | |||
| player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.timeOfGhostStunnedWhenPunish + GameData.factorOfTimeStunnedWhenPunish * (player.MaxHp - player.HP) / GameData.basicApOfGhost)); | |||
| break; | |||
| } | |||
| } | |||
| @@ -359,6 +370,41 @@ namespace Gaming | |||
| { }); | |||
| } | |||
| public bool HaveTea(Character player, int angle1000) | |||
| { | |||
| long stateNum = player.SetPlayerState(PlayerStateType.UsingSkill); | |||
| if (stateNum == -1) | |||
| { | |||
| return false; | |||
| } | |||
| player.ThreadNum.WaitOne(); | |||
| XY res = player.Position + new XY(angle1000 / 1000.0, GameData.distanceOfHaveTea); | |||
| Debugger.Output(res.ToString()); | |||
| if (actionManager.moveEngine.CheckCollision(player, res) != null) | |||
| { | |||
| player.ThreadNum.Release(); | |||
| return false; | |||
| } | |||
| Debugger.Output("NO Collision!"); | |||
| player.ReSetPos(res); | |||
| lock (player.ActionLock) | |||
| { | |||
| if (player.StateNum == stateNum) | |||
| { | |||
| player.SetPlayerStateNaturally(); | |||
| } | |||
| } | |||
| player.ThreadNum.Release(); | |||
| return ActiveSkillEffect(player.FindActiveSkill(ActiveSkillType.HaveTea), player, () => | |||
| { | |||
| Debugger.Output(player, "have tea!"); | |||
| }, | |||
| () => | |||
| { }); | |||
| } | |||
| public bool Rouse(Character player) | |||
| { | |||
| if ((!player.Commandable())) return false; | |||
| @@ -30,6 +30,8 @@ namespace Gaming | |||
| return Encourage(character); | |||
| case ActiveSkillType.Punish: | |||
| return Punish(character); | |||
| case ActiveSkillType.HaveTea: | |||
| return HaveTea(character, parameter); | |||
| case ActiveSkillType.JumpyBomb: | |||
| return JumpyBomb(character); | |||
| case ActiveSkillType.SparksNSplash: | |||
| @@ -166,7 +166,7 @@ namespace Preparation.Interface | |||
| public BulletType InitBullet => BulletType.Null; | |||
| public List<ActiveSkillType> ListOfIActiveSkill => new(new ActiveSkillType[] { ActiveSkillType.Punish }); | |||
| public List<ActiveSkillType> ListOfIActiveSkill => new(new ActiveSkillType[] { ActiveSkillType.Punish, ActiveSkillType.HaveTea }); | |||
| public List<PassiveSkillType> ListOfIPassiveSkill => new(new PassiveSkillType[] { }); | |||
| public const int fixSpeed = 50; | |||
| @@ -181,7 +181,7 @@ namespace Preparation.Interface | |||
| public const int alertnessRadius = GameData.basicStudentAlertnessRadius * 2 / 3; | |||
| public int AlertnessRadius => alertnessRadius; | |||
| public int viewRange = GameData.basicStudentViewRange * 8 / 10; | |||
| public int viewRange = GameData.basicStudentViewRange * 9 / 10; | |||
| public int ViewRange => viewRange; | |||
| public int speedOfOpeningOrLocking = GameData.basicSpeedOfOpeningOrLocking; | |||
| @@ -34,7 +34,7 @@ namespace Preparation.Interface | |||
| { | |||
| get | |||
| { | |||
| return Interlocked.CompareExchange(ref timeUntilActiveSkillAvailable, 0, 1); | |||
| return Interlocked.CompareExchange(ref timeUntilActiveSkillAvailable, 0, 0); | |||
| } | |||
| set | |||
| { | |||
| @@ -47,7 +47,7 @@ namespace Preparation.Interface | |||
| public int isBeingUsed = 0;//实为bool | |||
| public int IsBeingUsed | |||
| { | |||
| get => Interlocked.CompareExchange(ref isBeingUsed, 0, 1); | |||
| get => Interlocked.CompareExchange(ref isBeingUsed, 0, 0); | |||
| set => Interlocked.Exchange(ref isBeingUsed, value); | |||
| } | |||
| } | |||
| @@ -70,6 +70,12 @@ namespace Preparation.Interface | |||
| public override int DurationTime => 0; | |||
| } | |||
| public class HaveTea : ActiveSkill | |||
| { | |||
| public override int SkillCD => GameData.commonSkillCD * 3; | |||
| public override int DurationTime => 0; | |||
| } | |||
| public class Rouse : ActiveSkill | |||
| { | |||
| public override int SkillCD => GameData.commonSkillCD * 4; | |||
| @@ -163,7 +169,7 @@ namespace Preparation.Interface | |||
| private int degreeOfMeditation = 0; | |||
| public int DegreeOfMeditation | |||
| { | |||
| get => Interlocked.CompareExchange(ref degreeOfMeditation, 0, 1); | |||
| get => Interlocked.CompareExchange(ref degreeOfMeditation, 0, 0); | |||
| set => Interlocked.Exchange(ref degreeOfMeditation, value); | |||
| } | |||
| } | |||
| @@ -245,6 +251,8 @@ namespace Preparation.Interface | |||
| return new CanBeginToCharge(); | |||
| case ActiveSkillType.Punish: | |||
| return new Punish(); | |||
| case ActiveSkillType.HaveTea: | |||
| return new HaveTea(); | |||
| case ActiveSkillType.JumpyBomb: | |||
| return new JumpyBomb(); | |||
| case ActiveSkillType.SparksNSplash: | |||
| @@ -284,6 +292,8 @@ namespace Preparation.Interface | |||
| return ActiveSkillType.Inspire; | |||
| case Punish: | |||
| return ActiveSkillType.Punish; | |||
| case HaveTea: | |||
| return ActiveSkillType.HaveTea; | |||
| case JumpyBomb: | |||
| return ActiveSkillType.JumpyBomb; | |||
| case SparksNSplash: | |||
| @@ -214,8 +214,9 @@ namespace Preparation.Utility | |||
| public const int timeOfStudentStunnedWhenCharge = 2090; | |||
| public const int timeOfGhostStunnedWhenPunish = 3070; | |||
| public const int factorOfTimeStunnedWhenPunish = 500 / basicApOfGhost; | |||
| public const int factorOfScoreWhenTeacherAttacked = 100;//每个 | |||
| public const int factorOfTimeStunnedWhenPunish = 500; | |||
| public const int factorOfScoreWhenTeacherAttacked = 100; | |||
| public const int distanceOfHaveTea = 3000; | |||
| public const int timeOfGhostSwingingAfterHowl = 800; | |||
| public const int timeOfStudentStunnedWhenHowl = 5500; | |||