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