| @@ -1,5 +1,4 @@ | |||||
| using GameClass.Skill; | |||||
| using Preparation.Interface; | |||||
| using Preparation.Interface; | |||||
| using Preparation.Utility; | using Preparation.Utility; | ||||
| using System; | using System; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| @@ -1,5 +1,4 @@ | |||||
| using GameClass.Skill; | |||||
| using Preparation.Utility; | |||||
| using Preparation.Utility; | |||||
| using Preparation.Interface; | using Preparation.Interface; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System; | using System; | ||||
| @@ -37,20 +36,6 @@ namespace GameClass.GameObj | |||||
| return false; | return false; | ||||
| } | } | ||||
| public bool UseActiveSkill(Map map, ActiveSkillType activeSkillType) | |||||
| { | |||||
| if (Occupation.ListOfIActiveSkill.Contains(activeSkillType)) | |||||
| return ActiveSkillFactory.FindIActiveSkill(activeSkillType).SkillEffect(map, this); | |||||
| return false; | |||||
| } | |||||
| public void UsePassiveSkill(Map map, PassiveSkillType passiveSkillType) | |||||
| { | |||||
| if (Occupation.ListOfIPassiveSkill.Contains(passiveSkillType)) | |||||
| PassiveSkillFactory.FindIPassiveSkill(passiveSkillType).SkillEffect(map, this); | |||||
| return; | |||||
| } | |||||
| public bool IsGhost() | public bool IsGhost() | ||||
| { | { | ||||
| return GameData.IsGhost(CharacterType); | return GameData.IsGhost(CharacterType); | ||||
| @@ -1,5 +1,4 @@ | |||||
| using GameClass.Skill; | |||||
| using Preparation.Utility; | |||||
| using Preparation.Utility; | |||||
| using Preparation.Interface; | using Preparation.Interface; | ||||
| namespace GameClass.GameObj | namespace GameClass.GameObj | ||||
| @@ -40,20 +39,6 @@ namespace GameClass.GameObj | |||||
| } | } | ||||
| public int OrgTreatSpeed { get; protected set; } = GameData.basicTreatSpeed; | public int OrgTreatSpeed { get; protected set; } = GameData.basicTreatSpeed; | ||||
| protected int rescueSpeed = GameData.basicRescueSpeed; | |||||
| public int RescueSpeed | |||||
| { | |||||
| get => rescueSpeed; | |||||
| set | |||||
| { | |||||
| lock (gameObjLock) | |||||
| { | |||||
| rescueSpeed = value; | |||||
| } | |||||
| } | |||||
| } | |||||
| public int OrgRescueSpeed { get; protected set; } = GameData.basicRescueSpeed; | |||||
| public int MaxGamingAddiction { get; protected set; } | public int MaxGamingAddiction { get; protected set; } | ||||
| private int gamingAddiction; | private int gamingAddiction; | ||||
| public int GamingAddiction | public int GamingAddiction | ||||
| @@ -59,7 +59,6 @@ namespace GameClass.GameObj | |||||
| { | { | ||||
| get | get | ||||
| { | { | ||||
| if (IsResetting) return PlayerStateType.IsDeceased; | |||||
| if (IsMoving) return PlayerStateType.IsMoving; | if (IsMoving) return PlayerStateType.IsMoving; | ||||
| return playerState; | return playerState; | ||||
| } | } | ||||
| @@ -214,6 +213,21 @@ namespace GameClass.GameObj | |||||
| } | } | ||||
| } | } | ||||
| private int timeOfOpeningOrLocking; | |||||
| public int TimeOfOpeningOrLocking | |||||
| { | |||||
| get => timeOfOpeningOrLocking; | |||||
| set | |||||
| { | |||||
| lock (gameObjLock) | |||||
| { | |||||
| timeOfOpeningOrLocking = value; | |||||
| } | |||||
| } | |||||
| } | |||||
| /// <summary> | /// <summary> | ||||
| /// 进行一次攻击 | /// 进行一次攻击 | ||||
| /// </summary> | /// </summary> | ||||
| @@ -1,227 +0,0 @@ | |||||
| using GameClass.GameObj; | |||||
| using System.Threading; | |||||
| using Preparation.Interface; | |||||
| using Preparation.Utility; | |||||
| using System; | |||||
| using Timothy.FrameRateTask; | |||||
| namespace GameClass.Skill | |||||
| { | |||||
| public class BecomeVampire : IActiveSkill // 化身吸血鬼 | |||||
| { | |||||
| public int SkillCD => GameData.commonSkillCD / 3 * 4; | |||||
| public int DurationTime => GameData.commonSkillTime; | |||||
| private readonly object commonSkillLock = new object(); | |||||
| public object ActiveSkillLock => commonSkillLock; | |||||
| public bool SkillEffect(Map map, Character player) | |||||
| { | |||||
| return ActiveSkillFactory.SkillEffect(this, player, () => | |||||
| { | |||||
| player.Vampire += 0.5; | |||||
| Debugger.Output(player, "becomes vampire!"); | |||||
| }, | |||||
| () => | |||||
| { | |||||
| double tempVam = player.Vampire - 0.5; | |||||
| player.Vampire = tempVam < player.OriVampire ? player.OriVampire : tempVam; | |||||
| }); | |||||
| } | |||||
| } | |||||
| public class BeginToCharge : IActiveSkill | |||||
| { | |||||
| public int SkillCD => GameData.commonSkillCD / 3 * 4; | |||||
| public int DurationTime => GameData.commonSkillTime; | |||||
| private readonly object commonSkillLock = new object(); | |||||
| public object ActiveSkillLock => commonSkillLock; | |||||
| public bool SkillEffect(Map map, Character player) | |||||
| { | |||||
| return ActiveSkillFactory.SkillEffect(this, player, () => | |||||
| { | |||||
| player.Vampire += 0.5; | |||||
| Debugger.Output(player, "becomes vampire!"); | |||||
| }, | |||||
| () => | |||||
| { | |||||
| double tempVam = player.Vampire - 0.5; | |||||
| player.Vampire = tempVam < player.OriVampire ? player.OriVampire : tempVam; | |||||
| }); | |||||
| } | |||||
| } | |||||
| public class BecomeInvisible : IActiveSkill | |||||
| { | |||||
| public int SkillCD => GameData.commonSkillCD; | |||||
| public int DurationTime => GameData.commonSkillTime / 10 * 6; | |||||
| private readonly object commonSkillLock = new object(); | |||||
| public object ActiveSkillLock => commonSkillLock; | |||||
| public bool SkillEffect(Map map, Character player) | |||||
| { | |||||
| return ActiveSkillFactory.SkillEffect(this, player, () => | |||||
| { | |||||
| player.IsInvisible = true; | |||||
| Debugger.Output(player, "uses atombomb!"); | |||||
| }, | |||||
| () => | |||||
| { player.IsInvisible = false; }); | |||||
| } | |||||
| } | |||||
| public class NuclearWeapon : IActiveSkill // 核武器 | |||||
| { | |||||
| public int SkillCD => GameData.commonSkillCD / 3 * 7; | |||||
| public int DurationTime => GameData.commonSkillTime / 10; | |||||
| private readonly object commonSkillLock = new object(); | |||||
| public object ActiveSkillLock => commonSkillLock; | |||||
| public bool SkillEffect(Map map, Character player) | |||||
| { | |||||
| return ActiveSkillFactory.SkillEffect(this, player, () => | |||||
| { | |||||
| player.BulletOfPlayer = BulletType.AtomBomb; | |||||
| Debugger.Output(player, "uses atombomb!"); | |||||
| }, | |||||
| () => | |||||
| { player.BulletOfPlayer = player.OriBulletOfPlayer; }); | |||||
| } | |||||
| } | |||||
| public class UseKnife : IActiveSkill | |||||
| { | |||||
| public int SkillCD => GameData.commonSkillCD / 3 * 2; | |||||
| public int DurationTime => GameData.commonSkillTime / 10; | |||||
| private readonly object commonSkillLock = new object(); | |||||
| public object ActiveSkillLock => commonSkillLock; | |||||
| public bool SkillEffect(Map map, Character player) | |||||
| { | |||||
| return ActiveSkillFactory.SkillEffect(this, player, () => | |||||
| { | |||||
| player.BulletOfPlayer = BulletType.FlyingKnife; | |||||
| Debugger.Output(player, "uses flyingknife!"); | |||||
| }, | |||||
| () => | |||||
| { player.BulletOfPlayer = player.OriBulletOfPlayer; }); | |||||
| } | |||||
| } | |||||
| public class SuperFast : IActiveSkill // 3倍速 | |||||
| { | |||||
| public int SkillCD => GameData.commonSkillCD; | |||||
| public int DurationTime => GameData.commonSkillTime / 10 * 4; | |||||
| private readonly object commonSkillLock = new object(); | |||||
| public object ActiveSkillLock => commonSkillLock; | |||||
| public bool SkillEffect(Map map, Character player) | |||||
| { | |||||
| return ActiveSkillFactory.SkillEffect(this, player, () => | |||||
| { | |||||
| player.AddMoveSpeed(this.DurationTime, 3.0); | |||||
| Debugger.Output(player, "moves very fast!"); | |||||
| }, | |||||
| () => | |||||
| { }); | |||||
| } | |||||
| } | |||||
| public class NoCommonSkill : IActiveSkill // 这种情况不该发生,定义着以防意外 | |||||
| { | |||||
| public int SkillCD => GameData.commonSkillCD; | |||||
| public int DurationTime => GameData.commonSkillTime; | |||||
| private readonly object commonSkillLock = new object(); | |||||
| public object ActiveSkillLock => commonSkillLock; | |||||
| public bool SkillEffect(Map map, Character player) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| public static class ActiveSkillFactory | |||||
| { | |||||
| public static bool SkillEffect(IActiveSkill activeSkill, Character player, Action startSkill, Action endSkill) | |||||
| { | |||||
| lock (activeSkill.ActiveSkillLock) | |||||
| { | |||||
| ActiveSkillType activeSkillType = FindActiveSkillType(activeSkill); | |||||
| if (player.TimeUntilActiveSkillAvailable[activeSkillType] == 0) | |||||
| { | |||||
| player.SetTimeUntilActiveSkillAvailable(activeSkillType, activeSkill.SkillCD); | |||||
| new Thread | |||||
| (() => | |||||
| { | |||||
| startSkill(); | |||||
| new FrameRateTaskExecutor<int>( | |||||
| () => !player.IsResetting, | |||||
| () => | |||||
| { | |||||
| player.AddTimeUntilActiveSkillAvailable(activeSkillType, -(int)GameData.frameDuration); | |||||
| }, | |||||
| timeInterval: GameData.frameDuration, | |||||
| () => 0, | |||||
| maxTotalDuration: (long)(activeSkill.DurationTime) | |||||
| ) | |||||
| { | |||||
| AllowTimeExceed = true, | |||||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||||
| } | |||||
| .Start(); | |||||
| endSkill(); | |||||
| Debugger.Output(player, "return to normal."); | |||||
| new FrameRateTaskExecutor<int>( | |||||
| () => player.TimeUntilActiveSkillAvailable[activeSkillType] > 0 && !player.IsResetting, | |||||
| () => | |||||
| { | |||||
| player.AddTimeUntilActiveSkillAvailable(activeSkillType, -(int)GameData.frameDuration); | |||||
| }, | |||||
| timeInterval: GameData.frameDuration, | |||||
| () => 0, | |||||
| maxTotalDuration: (long)(activeSkill.SkillCD - activeSkill.DurationTime) | |||||
| ) | |||||
| { | |||||
| AllowTimeExceed = true, | |||||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||||
| } | |||||
| .Start(); | |||||
| player.SetTimeUntilActiveSkillAvailable(activeSkillType, 0); | |||||
| Debugger.Output(player, "CommonSkill is ready."); | |||||
| } | |||||
| ) | |||||
| { IsBackground = true }.Start(); | |||||
| return true; | |||||
| } | |||||
| else | |||||
| { | |||||
| Debugger.Output(player, "CommonSkill is cooling down!"); | |||||
| return false; | |||||
| } | |||||
| } | |||||
| } | |||||
| public static IActiveSkill? FindIActiveSkill(ActiveSkillType activeSkillType) | |||||
| { | |||||
| switch (activeSkillType) | |||||
| { | |||||
| case ActiveSkillType.BecomeInvisible: | |||||
| return new BecomeInvisible(); | |||||
| default: | |||||
| return null; | |||||
| } | |||||
| } | |||||
| public static ActiveSkillType FindActiveSkillType(IActiveSkill ActiveSkill) | |||||
| { | |||||
| switch (ActiveSkill) | |||||
| { | |||||
| case BecomeInvisible: | |||||
| return ActiveSkillType.BecomeInvisible; | |||||
| case UseKnife: | |||||
| return ActiveSkillType.UseKnife; | |||||
| case BeginToCharge: | |||||
| return ActiveSkillType.BeginToCharge; | |||||
| default: | |||||
| return ActiveSkillType.Null; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -1,21 +0,0 @@ | |||||
| using Preparation.Utility; | |||||
| using GameClass.GameObj; | |||||
| using System.Collections.Generic; | |||||
| namespace GameClass.Skill | |||||
| { | |||||
| public interface ISkill | |||||
| { | |||||
| } | |||||
| public interface IPassiveSkill : ISkill | |||||
| { | |||||
| public void SkillEffect(Map map, Character player); | |||||
| } | |||||
| public interface IActiveSkill : ISkill | |||||
| { | |||||
| public int SkillCD { get; } | |||||
| public int DurationTime { get; } //技能持续时间 | |||||
| public object ActiveSkillLock { get; } | |||||
| public bool SkillEffect(Map map, Character player); | |||||
| } | |||||
| } | |||||
| @@ -1,161 +0,0 @@ | |||||
| using System; | |||||
| using System.Threading; | |||||
| using GameClass.GameObj; | |||||
| using Preparation.Interface; | |||||
| using Preparation.Utility; | |||||
| using Timothy.FrameRateTask; | |||||
| namespace GameClass.Skill // 被动技能开局时就释放,持续到游戏结束 | |||||
| { | |||||
| public class RecoverAfterBattle : IPassiveSkill // 脱战回血,普通子弹 | |||||
| { | |||||
| public void SkillEffect(Map map, Character player) | |||||
| { | |||||
| const int recoverDegree = 5; // 每帧回复血量 | |||||
| int nowHP = player.HP; | |||||
| int lastHP = nowHP; | |||||
| long waitTime = 0; | |||||
| const long interval = 10000; // 每隔interval时间不受伤害,角色即开始回血 | |||||
| new Thread | |||||
| ( | |||||
| () => | |||||
| { | |||||
| new FrameRateTaskExecutor<int> | |||||
| ( | |||||
| () => true, | |||||
| () => | |||||
| { | |||||
| lastHP = nowHP; // lastHP等于上一帧的HP | |||||
| nowHP = player.HP; // nowHP更新为这一帧的HP | |||||
| if (lastHP > nowHP) // 这一帧扣血了 | |||||
| { | |||||
| waitTime = 0; | |||||
| } | |||||
| else if (waitTime < interval) | |||||
| { | |||||
| waitTime += GameData.frameDuration; | |||||
| } | |||||
| if (waitTime >= interval) // 回复时,每帧(50ms)回复5,即1s回复100。 | |||||
| player.TryAddHp(recoverDegree); | |||||
| }, | |||||
| timeInterval: GameData.frameDuration, | |||||
| () => 0, | |||||
| maxTotalDuration: GameData.gameDuration | |||||
| ) | |||||
| { | |||||
| AllowTimeExceed = true, | |||||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||||
| TimeExceedAction = b => | |||||
| { | |||||
| if (b) | |||||
| Console.WriteLine("Fetal Error: The computer runs so slow that passive skill time exceeds!!!!!!"); | |||||
| #if DEBUG | |||||
| else | |||||
| { | |||||
| Console.WriteLine("Debug info: passive skill time exceeds for once."); | |||||
| } | |||||
| #endif | |||||
| } | |||||
| }.Start(); | |||||
| } | |||||
| ) | |||||
| { IsBackground = true }.Start(); | |||||
| } | |||||
| } | |||||
| public class SpeedUpWhenLeavingGrass : IPassiveSkill // 3倍速 | |||||
| { | |||||
| public void SkillEffect(Map map, Character player) | |||||
| { | |||||
| PlaceType nowPlace = map.GetPlaceType(player.Position); | |||||
| PlaceType lastPlace = nowPlace; | |||||
| bool speedup = false; | |||||
| const int SpeedUpTime = 2000; // 加速时间:2s | |||||
| new Thread | |||||
| ( | |||||
| () => | |||||
| { | |||||
| new FrameRateTaskExecutor<int> | |||||
| ( | |||||
| () => true, | |||||
| () => | |||||
| { | |||||
| lastPlace = nowPlace; | |||||
| nowPlace = map.GetPlaceType(player.Position); | |||||
| if ((lastPlace == PlaceType.Grass) && nowPlace == PlaceType.Null) | |||||
| { | |||||
| if (!speedup) | |||||
| { | |||||
| new Thread(() => | |||||
| { | |||||
| speedup = true; | |||||
| player.AddMoveSpeed(SpeedUpTime, 3.0); | |||||
| speedup = false; | |||||
| }) | |||||
| { IsBackground = true }.Start(); | |||||
| } | |||||
| } | |||||
| }, | |||||
| timeInterval: GameData.frameDuration, | |||||
| () => 0, | |||||
| maxTotalDuration: GameData.gameDuration | |||||
| ) | |||||
| { | |||||
| AllowTimeExceed = true, | |||||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||||
| TimeExceedAction = b => | |||||
| { | |||||
| if (b) | |||||
| Console.WriteLine("Fetal Error: The computer runs so slow that passive skill time exceeds!!!!!!"); | |||||
| #if DEBUG | |||||
| else | |||||
| { | |||||
| Console.WriteLine("Debug info: passive skill time exceeds for once."); | |||||
| } | |||||
| #endif | |||||
| } | |||||
| }.Start(); | |||||
| } | |||||
| ) | |||||
| { IsBackground = true }.Start(); | |||||
| } | |||||
| } | |||||
| public class Vampire : IPassiveSkill // 被动就是吸血,普通子弹 | |||||
| { | |||||
| public void SkillEffect(Map map, Character player) | |||||
| { | |||||
| player.OriVampire = 0.5; | |||||
| player.Vampire = player.OriVampire; | |||||
| } | |||||
| } | |||||
| public class NoPassiveSkill : IPassiveSkill // 没技能,这种情况不应该发生,先定义着以防意外 | |||||
| { | |||||
| public void SkillEffect(Map map, Character player) | |||||
| { | |||||
| } | |||||
| } | |||||
| public static class PassiveSkillFactory | |||||
| { | |||||
| public static IPassiveSkill? FindIPassiveSkill(PassiveSkillType passiveSkillType) | |||||
| { | |||||
| switch (passiveSkillType) | |||||
| { | |||||
| default: | |||||
| return null; | |||||
| } | |||||
| } | |||||
| public static PassiveSkillType FindpassiveSkillType(IPassiveSkill passiveSkill) | |||||
| { | |||||
| switch (passiveSkill) | |||||
| { | |||||
| default: | |||||
| return PassiveSkillType.Null; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -28,7 +28,7 @@ namespace Gaming | |||||
| if (player.PlayerState == PlayerStateType.IsRescuing || player.PlayerState == PlayerStateType.IsRescued | if (player.PlayerState == PlayerStateType.IsRescuing || player.PlayerState == PlayerStateType.IsRescued | ||||
| || player.PlayerState == PlayerStateType.IsFixing || player.PlayerState == PlayerStateType.IsMoving | || player.PlayerState == PlayerStateType.IsFixing || player.PlayerState == PlayerStateType.IsMoving | ||||
| || player.PlayerState == PlayerStateType.IsTreated || player.PlayerState == PlayerStateType.IsTreating | || player.PlayerState == PlayerStateType.IsTreated || player.PlayerState == PlayerStateType.IsTreating | ||||
| || player.PlayerState == PlayerStateType.IsRummagingInTheDrawer || player.PlayerState == PlayerStateType.IsLockingTheDoor | |||||
| || player.PlayerState == PlayerStateType.IsRummagingInTheChest || player.PlayerState == PlayerStateType.IsLockingTheDoor | |||||
| || player.PlayerState == PlayerStateType.IsClimbingThroughWindows) | || player.PlayerState == PlayerStateType.IsClimbingThroughWindows) | ||||
| { | { | ||||
| player.PlayerState = PlayerStateType.Null; | player.PlayerState = PlayerStateType.Null; | ||||
| @@ -150,7 +150,7 @@ namespace Gaming | |||||
| finally | finally | ||||
| { | { | ||||
| gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); | |||||
| gameMap.GameObjLockDict[GameObjType.Generator].ExitReadLock(); | |||||
| } | } | ||||
| }, | }, | ||||
| timeInterval: GameData.checkInterval, | timeInterval: GameData.checkInterval, | ||||
| @@ -179,11 +179,17 @@ namespace Gaming | |||||
| propManager.StartProducing(); | propManager.StartProducing(); | ||||
| // 开始游戏 | |||||
| if (!gameMap.Timer.StartGame(milliSeconds)) | |||||
| return false; | |||||
| new Thread | |||||
| ( | |||||
| () => | |||||
| { | |||||
| if (!gameMap.Timer.StartGame(milliSeconds)) | |||||
| return; | |||||
| EndGame(); // 游戏结束时要做的事 | |||||
| EndGame(); // 游戏结束时要做的事 | |||||
| } | |||||
| ) | |||||
| { IsBackground = true }.Start(); | |||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -333,7 +339,7 @@ namespace Gaming | |||||
| Character? player = gameMap.FindPlayer(playerID); | Character? player = gameMap.FindPlayer(playerID); | ||||
| if (player != null) | if (player != null) | ||||
| { | { | ||||
| return skillManager.UseActiveSkill(this.GameMap, player, activeSkillType); | |||||
| return skillManager.UseActiveSkill(player, activeSkillType); | |||||
| } | } | ||||
| else | else | ||||
| return false; | return false; | ||||
| @@ -348,7 +354,7 @@ namespace Gaming | |||||
| { | { | ||||
| foreach (Character player in gameMap.GameObjDict[GameObjType.Character]) | foreach (Character player in gameMap.GameObjDict[GameObjType.Character]) | ||||
| { | { | ||||
| skillManager.UseAllPassiveSkill(this.GameMap, player); | |||||
| skillManager.UseAllPassiveSkill(player); | |||||
| } | } | ||||
| } | } | ||||
| finally | finally | ||||
| @@ -439,10 +445,10 @@ namespace Gaming | |||||
| teamList.Add(new Team()); | teamList.Add(new Team()); | ||||
| } | } | ||||
| skillManager = new SkillManager(); | |||||
| attackManager = new AttackManager(gameMap); | attackManager = new AttackManager(gameMap); | ||||
| actionManager = new ActionManager(gameMap); | actionManager = new ActionManager(gameMap); | ||||
| propManager = new PropManager(gameMap); | propManager = new PropManager(gameMap); | ||||
| skillManager = new SkillManager(gameMap, actionManager, attackManager, propManager); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,29 +0,0 @@ | |||||
| using System; | |||||
| using Preparation.Utility; | |||||
| using GameClass.GameObj; | |||||
| using System.Reflection; | |||||
| using GameClass.Skill; | |||||
| namespace Gaming | |||||
| { | |||||
| public partial class Game | |||||
| { | |||||
| readonly SkillManager skillManager; | |||||
| private class SkillManager | |||||
| { | |||||
| public bool UseActiveSkill(Map gamemap, Character character, ActiveSkillType activeSkillType) | |||||
| { | |||||
| return character.UseActiveSkill(gamemap, activeSkillType); | |||||
| } | |||||
| public void UsePassiveSkill(Map gamemap, Character character, PassiveSkillType passiveSkillType) | |||||
| { | |||||
| character.UsePassiveSkill(gamemap, passiveSkillType); | |||||
| } | |||||
| public void UseAllPassiveSkill(Map gamemap, Character character) | |||||
| { | |||||
| foreach (var passiveSkill in character.Occupation.ListOfIPassiveSkill) | |||||
| character.UsePassiveSkill(gamemap, passiveSkill); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,238 @@ | |||||
| using GameClass.GameObj; | |||||
| using System.Threading; | |||||
| using Preparation.Interface; | |||||
| using Preparation.Utility; | |||||
| using System; | |||||
| using Timothy.FrameRateTask; | |||||
| namespace Gaming | |||||
| { | |||||
| public partial class Game | |||||
| { | |||||
| private partial class SkillManager | |||||
| { | |||||
| public interface IActiveSkill | |||||
| { | |||||
| public int SkillCD { get; } | |||||
| public int DurationTime { get; } //技能持续时间 | |||||
| public object ActiveSkillLock { get; } | |||||
| public bool SkillEffect(Character player); | |||||
| } | |||||
| public class BecomeVampire : IActiveSkill // 化身吸血鬼 | |||||
| { | |||||
| public int SkillCD => GameData.commonSkillCD / 3 * 4; | |||||
| public int DurationTime => GameData.commonSkillTime; | |||||
| private readonly object commonSkillLock = new object(); | |||||
| public object ActiveSkillLock => commonSkillLock; | |||||
| public bool SkillEffect(Character player) | |||||
| { | |||||
| return ActiveSkillEffect(this, player, () => | |||||
| { | |||||
| player.Vampire += 0.5; | |||||
| Debugger.Output(player, "becomes vampire!"); | |||||
| }, | |||||
| () => | |||||
| { | |||||
| double tempVam = player.Vampire - 0.5; | |||||
| player.Vampire = tempVam < player.OriVampire ? player.OriVampire : tempVam; | |||||
| }); | |||||
| } | |||||
| } | |||||
| private IActiveSkill becomeVampire = new BecomeVampire(); | |||||
| public class BeginToCharge : IActiveSkill | |||||
| { | |||||
| public int SkillCD => GameData.commonSkillCD / 3 * 4; | |||||
| public int DurationTime => GameData.commonSkillTime; | |||||
| private readonly object commonSkillLock = new object(); | |||||
| public object ActiveSkillLock => commonSkillLock; | |||||
| public bool SkillEffect(Character player) | |||||
| { | |||||
| return ActiveSkillEffect(this, player, () => | |||||
| { | |||||
| player.Vampire += 0.5; | |||||
| Debugger.Output(player, "becomes vampire!"); | |||||
| }, | |||||
| () => | |||||
| { | |||||
| double tempVam = player.Vampire - 0.5; | |||||
| player.Vampire = tempVam < player.OriVampire ? player.OriVampire : tempVam; | |||||
| }); | |||||
| } | |||||
| } | |||||
| private IActiveSkill beginToCharge = new BeginToCharge(); | |||||
| public class BecomeInvisible : IActiveSkill | |||||
| { | |||||
| public int SkillCD => GameData.commonSkillCD; | |||||
| public int DurationTime => GameData.commonSkillTime / 10 * 6; | |||||
| private readonly object commonSkillLock = new object(); | |||||
| public object ActiveSkillLock => commonSkillLock; | |||||
| public bool SkillEffect(Character player) | |||||
| { | |||||
| return ActiveSkillEffect(this, player, () => | |||||
| { | |||||
| player.IsInvisible = true; | |||||
| Debugger.Output(player, "become invisible!"); | |||||
| }, | |||||
| () => | |||||
| { player.IsInvisible = false; }); | |||||
| } | |||||
| } | |||||
| private IActiveSkill becomeInvisible = new BecomeInvisible(); | |||||
| public class NuclearWeapon : IActiveSkill // 核武器 | |||||
| { | |||||
| public int SkillCD => GameData.commonSkillCD / 3 * 7; | |||||
| public int DurationTime => GameData.commonSkillTime / 10; | |||||
| private readonly object commonSkillLock = new object(); | |||||
| public object ActiveSkillLock => commonSkillLock; | |||||
| public bool SkillEffect(Character player) | |||||
| { | |||||
| return ActiveSkillEffect(this, player, () => | |||||
| { | |||||
| player.BulletOfPlayer = BulletType.AtomBomb; | |||||
| Debugger.Output(player, "uses atombomb!"); | |||||
| }, | |||||
| () => | |||||
| { player.BulletOfPlayer = player.OriBulletOfPlayer; }); | |||||
| } | |||||
| } | |||||
| private IActiveSkill nuclearWeapon = new NuclearWeapon(); | |||||
| public class UseKnife : IActiveSkill | |||||
| { | |||||
| public int SkillCD => GameData.commonSkillCD / 3 * 2; | |||||
| public int DurationTime => GameData.commonSkillTime / 10; | |||||
| private readonly object commonSkillLock = new object(); | |||||
| public object ActiveSkillLock => commonSkillLock; | |||||
| public bool SkillEffect(Character player) | |||||
| { | |||||
| return ActiveSkillEffect(this, player, () => | |||||
| { | |||||
| player.BulletOfPlayer = BulletType.FlyingKnife; | |||||
| Debugger.Output(player, "uses flyingknife!"); | |||||
| }, | |||||
| () => | |||||
| { player.BulletOfPlayer = player.OriBulletOfPlayer; }); | |||||
| } | |||||
| } | |||||
| private IActiveSkill useKnife = new UseKnife(); | |||||
| public class SuperFast : IActiveSkill // 3倍速 | |||||
| { | |||||
| public int SkillCD => GameData.commonSkillCD; | |||||
| public int DurationTime => GameData.commonSkillTime / 10 * 4; | |||||
| private readonly object commonSkillLock = new object(); | |||||
| public object ActiveSkillLock => commonSkillLock; | |||||
| public bool SkillEffect(Character player) | |||||
| { | |||||
| return ActiveSkillEffect(this, player, () => | |||||
| { | |||||
| player.AddMoveSpeed(this.DurationTime, 3.0); | |||||
| Debugger.Output(player, "moves very fast!"); | |||||
| }, | |||||
| () => | |||||
| { }); | |||||
| } | |||||
| } | |||||
| private IActiveSkill superFast = new SuperFast(); | |||||
| public IActiveSkill? FindIActiveSkill(ActiveSkillType activeSkillType) | |||||
| { | |||||
| switch (activeSkillType) | |||||
| { | |||||
| case ActiveSkillType.BecomeInvisible: | |||||
| return this.becomeInvisible; | |||||
| default: | |||||
| return null; | |||||
| } | |||||
| } | |||||
| public static ActiveSkillType FindActiveSkillType(IActiveSkill ActiveSkill) | |||||
| { | |||||
| switch (ActiveSkill) | |||||
| { | |||||
| case BecomeInvisible: | |||||
| return ActiveSkillType.BecomeInvisible; | |||||
| case UseKnife: | |||||
| return ActiveSkillType.UseKnife; | |||||
| case BeginToCharge: | |||||
| return ActiveSkillType.BeginToCharge; | |||||
| default: | |||||
| return ActiveSkillType.Null; | |||||
| } | |||||
| } | |||||
| public static bool ActiveSkillEffect(IActiveSkill activeSkill, Character player, Action startSkill, Action endSkill) | |||||
| { | |||||
| lock (activeSkill.ActiveSkillLock) | |||||
| { | |||||
| ActiveSkillType activeSkillType = FindActiveSkillType(activeSkill); | |||||
| if (player.TimeUntilActiveSkillAvailable[activeSkillType] == 0) | |||||
| { | |||||
| player.SetTimeUntilActiveSkillAvailable(activeSkillType, activeSkill.SkillCD); | |||||
| new Thread | |||||
| (() => | |||||
| { | |||||
| startSkill(); | |||||
| new FrameRateTaskExecutor<int>( | |||||
| () => !player.IsResetting, | |||||
| () => | |||||
| { | |||||
| player.AddTimeUntilActiveSkillAvailable(activeSkillType, -(int)GameData.frameDuration); | |||||
| }, | |||||
| timeInterval: GameData.frameDuration, | |||||
| () => 0, | |||||
| maxTotalDuration: (long)(activeSkill.DurationTime) | |||||
| ) | |||||
| { | |||||
| AllowTimeExceed = true, | |||||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||||
| } | |||||
| .Start(); | |||||
| endSkill(); | |||||
| Debugger.Output(player, "return to normal."); | |||||
| new FrameRateTaskExecutor<int>( | |||||
| () => player.TimeUntilActiveSkillAvailable[activeSkillType] > 0 && !player.IsResetting, | |||||
| () => | |||||
| { | |||||
| player.AddTimeUntilActiveSkillAvailable(activeSkillType, -(int)GameData.frameDuration); | |||||
| }, | |||||
| timeInterval: GameData.frameDuration, | |||||
| () => 0, | |||||
| maxTotalDuration: (long)(activeSkill.SkillCD - activeSkill.DurationTime) | |||||
| ) | |||||
| { | |||||
| AllowTimeExceed = true, | |||||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||||
| } | |||||
| .Start(); | |||||
| player.SetTimeUntilActiveSkillAvailable(activeSkillType, 0); | |||||
| Debugger.Output(player, "ActiveSkill is ready."); | |||||
| } | |||||
| ) | |||||
| { IsBackground = true }.Start(); | |||||
| return true; | |||||
| } | |||||
| else | |||||
| { | |||||
| Debugger.Output(player, "CommonSkill is cooling down!"); | |||||
| return false; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,131 @@ | |||||
| using System; | |||||
| using System.Threading; | |||||
| using GameClass.GameObj; | |||||
| using Preparation.Interface; | |||||
| using Preparation.Utility; | |||||
| using Timothy.FrameRateTask; | |||||
| namespace Gaming // 被动技能开局时就释放,持续到游戏结束 | |||||
| { | |||||
| public partial class Game | |||||
| { | |||||
| private partial class SkillManager | |||||
| { | |||||
| public void RecoverAfterBattle(Character player) | |||||
| { | |||||
| const int recoverDegree = 5; // 每帧回复血量 | |||||
| int nowHP = player.HP; | |||||
| int lastHP = nowHP; | |||||
| long waitTime = 0; | |||||
| const long interval = 10000; // 每隔interval时间不受伤害,角色即开始回血 | |||||
| new Thread | |||||
| ( | |||||
| () => | |||||
| { | |||||
| new FrameRateTaskExecutor<int> | |||||
| ( | |||||
| () => true, | |||||
| () => | |||||
| { | |||||
| lastHP = nowHP; // lastHP等于上一帧的HP | |||||
| nowHP = player.HP; // nowHP更新为这一帧的HP | |||||
| if (lastHP > nowHP) // 这一帧扣血了 | |||||
| { | |||||
| waitTime = 0; | |||||
| } | |||||
| else if (waitTime < interval) | |||||
| { | |||||
| waitTime += GameData.frameDuration; | |||||
| } | |||||
| if (waitTime >= interval) // 回复时,每帧(50ms)回复5,即1s回复100。 | |||||
| player.TryAddHp(recoverDegree); | |||||
| }, | |||||
| timeInterval: GameData.frameDuration, | |||||
| () => 0, | |||||
| maxTotalDuration: GameData.gameDuration | |||||
| ) | |||||
| { | |||||
| AllowTimeExceed = true, | |||||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||||
| TimeExceedAction = b => | |||||
| { | |||||
| if (b) | |||||
| Console.WriteLine("Fetal Error: The computer runs so slow that passive skill time exceeds!!!!!!"); | |||||
| #if DEBUG | |||||
| else | |||||
| { | |||||
| Console.WriteLine("Debug info: passive skill time exceeds for once."); | |||||
| } | |||||
| #endif | |||||
| } | |||||
| }.Start(); | |||||
| } | |||||
| ) | |||||
| { IsBackground = true }.Start(); | |||||
| } | |||||
| public void SpeedUpWhenLeavingGrass(Character player) | |||||
| { | |||||
| PlaceType nowPlace = gameMap.GetPlaceType(player.Position); | |||||
| PlaceType lastPlace = nowPlace; | |||||
| bool speedup = false; | |||||
| const int SpeedUpTime = 2000; // 加速时间:2s | |||||
| new Thread | |||||
| ( | |||||
| () => | |||||
| { | |||||
| new FrameRateTaskExecutor<int> | |||||
| ( | |||||
| () => true, | |||||
| () => | |||||
| { | |||||
| lastPlace = nowPlace; | |||||
| nowPlace = gameMap.GetPlaceType(player.Position); | |||||
| if ((lastPlace == PlaceType.Grass) && nowPlace == PlaceType.Null) | |||||
| { | |||||
| if (!speedup) | |||||
| { | |||||
| new Thread(() => | |||||
| { | |||||
| speedup = true; | |||||
| player.AddMoveSpeed(SpeedUpTime, 3.0); | |||||
| speedup = false; | |||||
| }) | |||||
| { IsBackground = true }.Start(); | |||||
| } | |||||
| } | |||||
| }, | |||||
| timeInterval: GameData.frameDuration, | |||||
| () => 0, | |||||
| maxTotalDuration: GameData.gameDuration | |||||
| ) | |||||
| { | |||||
| AllowTimeExceed = true, | |||||
| MaxTolerantTimeExceedCount = ulong.MaxValue, | |||||
| TimeExceedAction = b => | |||||
| { | |||||
| if (b) | |||||
| Console.WriteLine("Fetal Error: The computer runs so slow that passive skill time exceeds!!!!!!"); | |||||
| #if DEBUG | |||||
| else | |||||
| { | |||||
| Console.WriteLine("Debug info: passive skill time exceeds for once."); | |||||
| } | |||||
| #endif | |||||
| } | |||||
| }.Start(); | |||||
| } | |||||
| ) | |||||
| { IsBackground = true }.Start(); | |||||
| } | |||||
| public void Vampire(Character player) | |||||
| { | |||||
| player.OriVampire = 0.5; | |||||
| player.Vampire = player.OriVampire; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,53 @@ | |||||
| using System; | |||||
| using Preparation.Utility; | |||||
| using GameClass.GameObj; | |||||
| using System.Reflection; | |||||
| using GameEngine; | |||||
| namespace Gaming | |||||
| { | |||||
| public partial class Game | |||||
| { | |||||
| readonly SkillManager skillManager; | |||||
| private partial class SkillManager | |||||
| { | |||||
| public bool UseActiveSkill(Character character, ActiveSkillType activeSkillType) | |||||
| { | |||||
| if (character.Occupation.ListOfIActiveSkill.Contains(activeSkillType)) | |||||
| return FindIActiveSkill(activeSkillType).SkillEffect(character); | |||||
| return false; | |||||
| } | |||||
| public void UsePassiveSkill(Character character, PassiveSkillType passiveSkillType) | |||||
| { | |||||
| if (character.Occupation.ListOfIPassiveSkill.Contains(passiveSkillType)) | |||||
| switch (passiveSkillType) | |||||
| { | |||||
| default: | |||||
| return; | |||||
| } | |||||
| return; | |||||
| } | |||||
| public void UseAllPassiveSkill(Character character) | |||||
| { | |||||
| foreach (var passiveSkill in character.Occupation.ListOfIPassiveSkill) | |||||
| switch (passiveSkill) | |||||
| { | |||||
| default: | |||||
| return; | |||||
| } | |||||
| } | |||||
| private readonly Map gameMap; | |||||
| private readonly ActionManager actionManager; | |||||
| private readonly AttackManager attackManager; | |||||
| private readonly PropManager propManager; | |||||
| public SkillManager(Map gameMap, ActionManager action, AttackManager attack, PropManager prop) | |||||
| { | |||||
| this.gameMap = gameMap; | |||||
| this.actionManager = action; | |||||
| this.propManager = prop; | |||||
| this.attackManager = attack; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -14,6 +14,7 @@ namespace Preparation.Interface | |||||
| public List<PassiveSkillType> ListOfIPassiveSkill { get; } | public List<PassiveSkillType> ListOfIPassiveSkill { get; } | ||||
| public double Concealment { get; } | public double Concealment { get; } | ||||
| public int AlertnessRadius { get; } | public int AlertnessRadius { get; } | ||||
| public int TimeOfOpeningOrLocking { get; } | |||||
| } | } | ||||
| public interface IGhost : IOccupation | public interface IGhost : IOccupation | ||||
| @@ -49,6 +50,9 @@ namespace Preparation.Interface | |||||
| public int alertnessRadius = (int)(GameData.basicAlertnessRadius * 1.3); | public int alertnessRadius = (int)(GameData.basicAlertnessRadius * 1.3); | ||||
| public int AlertnessRadius => alertnessRadius; | public int AlertnessRadius => alertnessRadius; | ||||
| public int timeOfOpeningOrLocking = GameData.basicTimeOfOpeningOrLocking; | |||||
| public int TimeOfOpeningOrLocking => timeOfOpeningOrLocking; | |||||
| } | } | ||||
| public class Athlete : IStudent | public class Athlete : IStudent | ||||
| { | { | ||||
| @@ -77,5 +81,8 @@ namespace Preparation.Interface | |||||
| public const int alertnessRadius = (int)(GameData.basicAlertnessRadius * 0.9); | public const int alertnessRadius = (int)(GameData.basicAlertnessRadius * 0.9); | ||||
| public int AlertnessRadius => alertnessRadius; | public int AlertnessRadius => alertnessRadius; | ||||
| public int timeOfOpeningOrLocking = GameData.basicTimeOfOpeningOrLocking; | |||||
| public int TimeOfOpeningOrLocking => timeOfOpeningOrLocking; | |||||
| } | } | ||||
| } | } | ||||
| @@ -20,7 +20,7 @@ namespace Preparation.Utility | |||||
| IsStunned = 11, | IsStunned = 11, | ||||
| IsTryingToAttack = 12,//指前摇 | IsTryingToAttack = 12,//指前摇 | ||||
| IsLockingTheDoor = 13, | IsLockingTheDoor = 13, | ||||
| IsRummagingInTheDrawer = 14, | |||||
| IsRummagingInTheChest = 14, | |||||
| IsClimbingThroughWindows = 15, | IsClimbingThroughWindows = 15, | ||||
| } | } | ||||
| public enum GameObjType | public enum GameObjType | ||||
| @@ -120,6 +120,7 @@ namespace Preparation.Utility | |||||
| EmergencyExit = 10, | EmergencyExit = 10, | ||||
| Window = 11, | Window = 11, | ||||
| Door = 12, | Door = 12, | ||||
| Chest = 13, | |||||
| } | } | ||||
| public enum BgmType | public enum BgmType | ||||
| { | { | ||||
| @@ -56,7 +56,6 @@ namespace Preparation.Utility | |||||
| public const int basicApOfGhost = 1500000; // 攻击力 | public const int basicApOfGhost = 1500000; // 攻击力 | ||||
| public const int basicTreatSpeed = 100; | public const int basicTreatSpeed = 100; | ||||
| public const int basicFixSpeed = 100; | public const int basicFixSpeed = 100; | ||||
| public const int basicRescueSpeed = 100; | |||||
| public const int basicMaxGamingAddiction = 60000;//基本完全沉迷时间 | public const int basicMaxGamingAddiction = 60000;//基本完全沉迷时间 | ||||
| public const int BeginGamingAddiction = 10003; | public const int BeginGamingAddiction = 10003; | ||||
| public const int MidGamingAddiction = 30000; | public const int MidGamingAddiction = 30000; | ||||
| @@ -73,11 +72,12 @@ namespace Preparation.Utility | |||||
| public const double basicRemoteAttackRange = 9000; // 基本远程攻击范围 | public const double basicRemoteAttackRange = 9000; // 基本远程攻击范围 | ||||
| public const double basicAttackShortRange = 2700; // 基本近程攻击范围 | public const double basicAttackShortRange = 2700; // 基本近程攻击范围 | ||||
| public const double basicBulletBombRange = 3000; // 基本子弹爆炸范围 | public const double basicBulletBombRange = 3000; // 基本子弹爆炸范围 | ||||
| public const int basicMoveSpeed = 3800; // 基本移动速度,单位:s-1 | |||||
| public const int basicBulletMoveSpeed = 5400; // 基本子弹移动速度,单位:s-1 | |||||
| public const int basicMoveSpeed = 1260; // 基本移动速度,单位:s-1 | |||||
| public const int basicBulletMoveSpeed = 2700; // 基本子弹移动速度,单位:s-1 | |||||
| public const int characterMaxSpeed = 12000; // 最大速度 | public const int characterMaxSpeed = 12000; // 最大速度 | ||||
| public const double basicConcealment = 1.0; | public const double basicConcealment = 1.0; | ||||
| public const int basicAlertnessRadius = 30700; | public const int basicAlertnessRadius = 30700; | ||||
| public const int basicTimeOfOpeningOrLocking = 3000; | |||||
| public const int addScoreWhenKillOneLevelPlayer = 30; // 击杀一级角色获得的加分 | public const int addScoreWhenKillOneLevelPlayer = 30; // 击杀一级角色获得的加分 | ||||
| public const int commonSkillCD = 30000; // 普通技能标准冷却时间 | public const int commonSkillCD = 30000; // 普通技能标准冷却时间 | ||||
| public const int commonSkillTime = 10000; // 普通技能标准持续时间 | public const int commonSkillTime = 10000; // 普通技能标准持续时间 | ||||
| @@ -106,7 +106,6 @@ namespace Preparation.Utility | |||||
| public const long PropProduceTime = 10000; | public const long PropProduceTime = 10000; | ||||
| public const int PropDuration = 10000; | public const int PropDuration = 10000; | ||||
| #endregion | #endregion | ||||
| #region 物体相关 | #region 物体相关 | ||||
| public const int degreeOfFixedGenerator = 10300000; | public const int degreeOfFixedGenerator = 10300000; | ||||
| #endregion | #endregion | ||||
| @@ -5,6 +5,7 @@ | |||||
| - 该规则直接服务于Sever,并非选手版本 | - 该规则直接服务于Sever,并非选手版本 | ||||
| - *斜体表示Logic底层尚未(完全)实现* | - *斜体表示Logic底层尚未(完全)实现* | ||||
| - []表示待决定 | - []表示待决定 | ||||
| - ~~表示暂不实现~~ | |||||
| ## 游戏简介 | ## 游戏简介 | ||||
| - 1位监管者对抗4位求生者的非对称竞技模式 | - 1位监管者对抗4位求生者的非对称竞技模式 | ||||
| @@ -90,11 +91,11 @@ | |||||
| IsStunned = 11, | IsStunned = 11, | ||||
| IsTryingToAttack = 12,//指前摇 | IsTryingToAttack = 12,//指前摇 | ||||
| IsLockingTheDoor = 13, | IsLockingTheDoor = 13, | ||||
| IsRummagingInTheDrawer = 14, | |||||
| IsRummagingInTheChest = 14, | |||||
| IsClimbingThroughWindows = 15, | IsClimbingThroughWindows = 15, | ||||
| } | } | ||||
| ~~~ | ~~~ | ||||
| - *Bgm(字典)* | |||||
| - Bgm(字典) | |||||
| - 得分 | - 得分 | ||||
| - ~~回血率/原始回血率~~ | - ~~回血率/原始回血率~~ | ||||
| - 当前子弹类型 | - 当前子弹类型 | ||||
| @@ -108,15 +109,15 @@ | |||||
| - 拥有的被动技能(列表) | - 拥有的被动技能(列表) | ||||
| - 拥有的主动技能(列表) | - 拥有的主动技能(列表) | ||||
| - 各个主动技能CD(字典) | - 各个主动技能CD(字典) | ||||
| - *警戒半径* | |||||
| - *double 隐蔽度* | |||||
| - *翻墙速度* | |||||
| - *开锁门速度* | |||||
| - 警戒半径 | |||||
| - double 隐蔽度 | |||||
| - *翻窗时间* | |||||
| - 开锁门时间 | |||||
| ### 学生:人物 | ### 学生:人物 | ||||
| - 修理电机速度 | - 修理电机速度 | ||||
| - 治疗速度 | - 治疗速度 | ||||
| - 救人速度 | |||||
| - ~~救人速度~~ | |||||
| - ~~自愈次数~~ | - ~~自愈次数~~ | ||||
| - 沉迷游戏程度 | - 沉迷游戏程度 | ||||
| - 最大沉迷游戏程度 | - 最大沉迷游戏程度 | ||||
| @@ -171,6 +172,7 @@ | |||||
| ### 箱子:物体 | ### 箱子:物体 | ||||
| - *里面的道具* | - *里面的道具* | ||||
| - *是否开启* | |||||
| ### 门:物体 | ### 门:物体 | ||||
| - *属于那个教学区* | - *属于那个教学区* | ||||
| @@ -225,7 +227,7 @@ | |||||
| - *翻越窗户是一种交互行为,执行时,实质是限定方向的减速运动* | - *翻越窗户是一种交互行为,执行时,实质是限定方向的减速运动* | ||||
| ### 箱子 | ### 箱子 | ||||
| - *监管者和求生者都能与箱子交互。* | |||||
| - *监管者和求生者都能与箱子交互,同一时刻就允许一人进行翻找* | |||||
| - *开启箱子有不同概率获得不同道具。* | - *开启箱子有不同概率获得不同道具。* | ||||
| - *搜寻物品的基础持续时间为10秒。* | - *搜寻物品的基础持续时间为10秒。* | ||||
| - *未搜寻完成的箱子在下一次需要重新开始搜寻。* | - *未搜寻完成的箱子在下一次需要重新开始搜寻。* | ||||