| @@ -108,7 +108,7 @@ enum StudentType | |||||
| NULL_STUDENT_TYPE = 0; | NULL_STUDENT_TYPE = 0; | ||||
| ATHLETE = 1; | ATHLETE = 1; | ||||
| STUDENTTYPE2 = 2;//Teacher | STUDENTTYPE2 = 2;//Teacher | ||||
| STUDENTTYPE3 = 3; | |||||
| STUDENTTYPE3 = 3;//StraightAStudent | |||||
| STUDENTTYPE4 = 4; | STUDENTTYPE4 = 4; | ||||
| } | } | ||||
| @@ -110,7 +110,7 @@ namespace GameClass.GameObj | |||||
| case BulletType.JumpyDumpty: | case BulletType.JumpyDumpty: | ||||
| return JumpyDumpty.maxBulletNum; | return JumpyDumpty.maxBulletNum; | ||||
| default: | default: | ||||
| return GameData.basicCD; | |||||
| return 1; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -19,7 +19,7 @@ namespace GameClass.GameObj | |||||
| private Dictionary<ActiveSkillType, IActiveSkill> iActiveSkillDictionary = new(); | private Dictionary<ActiveSkillType, IActiveSkill> iActiveSkillDictionary = new(); | ||||
| public Dictionary<ActiveSkillType, IActiveSkill> IActiveSkillDictionary => iActiveSkillDictionary; | public Dictionary<ActiveSkillType, IActiveSkill> IActiveSkillDictionary => iActiveSkillDictionary; | ||||
| public IActiveSkill UseIActiveSkill(ActiveSkillType activeSkillType) | |||||
| public IActiveSkill FindIActiveSkill(ActiveSkillType activeSkillType) | |||||
| { | { | ||||
| if (Occupation.ListOfIActiveSkill.Contains(activeSkillType)) | if (Occupation.ListOfIActiveSkill.Contains(activeSkillType)) | ||||
| { | { | ||||
| @@ -72,6 +72,9 @@ namespace GameClass.GameObj | |||||
| case CharacterType.Klee: | case CharacterType.Klee: | ||||
| this.occupation = new Klee(); | this.occupation = new Klee(); | ||||
| break; | break; | ||||
| case CharacterType.StraightAStudent: | |||||
| this.occupation = new StraightAStudent(); | |||||
| break; | |||||
| case CharacterType.Athlete: | case CharacterType.Athlete: | ||||
| default: | default: | ||||
| this.occupation = new Athlete(); | this.occupation = new Athlete(); | ||||
| @@ -104,6 +104,33 @@ namespace GameClass.GameObj | |||||
| } | } | ||||
| } | } | ||||
| public class WriteAnswers : IActiveSkill | |||||
| { | |||||
| public int SkillCD => GameData.commonSkillCD; | |||||
| public int DurationTime => 0; | |||||
| private readonly object commonSkillLock = new object(); | |||||
| public object ActiveSkillLock => commonSkillLock; | |||||
| private int degreeOfMeditation = 0; | |||||
| public int DegreeOfMeditation | |||||
| { | |||||
| get => degreeOfMeditation; | |||||
| set | |||||
| { | |||||
| lock (commonSkillLock) | |||||
| { | |||||
| degreeOfMeditation = value; | |||||
| } | |||||
| } | |||||
| } | |||||
| public bool isBeingUsed = false; | |||||
| public bool IsBeingUsed | |||||
| { | |||||
| get => isBeingUsed; set => isBeingUsed = value; | |||||
| } | |||||
| } | |||||
| public class NullSkill : IActiveSkill | public class NullSkill : IActiveSkill | ||||
| { | { | ||||
| public int SkillCD => GameData.commonSkillCD; | public int SkillCD => GameData.commonSkillCD; | ||||
| @@ -134,6 +161,8 @@ namespace GameClass.GameObj | |||||
| return new Punish(); | return new Punish(); | ||||
| case ActiveSkillType.JumpyBomb: | case ActiveSkillType.JumpyBomb: | ||||
| return new JumpyBomb(); | return new JumpyBomb(); | ||||
| case ActiveSkillType.WriteAnswers: | |||||
| return new WriteAnswers(); | |||||
| default: | default: | ||||
| return new NullSkill(); | return new NullSkill(); | ||||
| } | } | ||||
| @@ -153,6 +182,8 @@ namespace GameClass.GameObj | |||||
| return ActiveSkillType.Punish; | return ActiveSkillType.Punish; | ||||
| case JumpyBomb: | case JumpyBomb: | ||||
| return ActiveSkillType.JumpyBomb; | return ActiveSkillType.JumpyBomb; | ||||
| case WriteAnswers: | |||||
| return ActiveSkillType.WriteAnswers; | |||||
| default: | default: | ||||
| return ActiveSkillType.Null; | return ActiveSkillType.Null; | ||||
| } | } | ||||
| @@ -21,14 +21,14 @@ namespace Gaming | |||||
| { | { | ||||
| if (collisionObj.Type == GameObjType.Bullet) | if (collisionObj.Type == GameObjType.Bullet) | ||||
| { | { | ||||
| if (((Bullet)collisionObj).TypeOfBullet == BulletType.JumpyDumpty) | |||||
| if (((Bullet)collisionObj).Parent != player && ((Bullet)collisionObj).TypeOfBullet == BulletType.JumpyDumpty) | |||||
| { | { | ||||
| if (AttackManager.BeStunned((Character)player, ((Bullet)collisionObj).AP / GameData.timeFactorOfGhostFainting)) | if (AttackManager.BeStunned((Character)player, ((Bullet)collisionObj).AP / GameData.timeFactorOfGhostFainting)) | ||||
| player.AddScore(GameData.StudentScoreTrickerBeStunned(((Bullet)collisionObj).AP / GameData.timeFactorOfGhostFainting)); | player.AddScore(GameData.StudentScoreTrickerBeStunned(((Bullet)collisionObj).AP / GameData.timeFactorOfGhostFainting)); | ||||
| gameMap.Remove((GameObj)collisionObj); | gameMap.Remove((GameObj)collisionObj); | ||||
| } | } | ||||
| } | } | ||||
| if (player.UseIActiveSkill(ActiveSkillType.CanBeginToCharge).IsBeingUsed && collisionObj.Type == GameObjType.Character && ((Character)collisionObj).IsGhost()) | |||||
| if (player.FindIActiveSkill(ActiveSkillType.CanBeginToCharge).IsBeingUsed && collisionObj.Type == GameObjType.Character && ((Character)collisionObj).IsGhost()) | |||||
| { | { | ||||
| if (AttackManager.BeStunned((Character)collisionObj, GameData.TimeOfGhostFaintingWhenCharge)) | if (AttackManager.BeStunned((Character)collisionObj, GameData.TimeOfGhostFaintingWhenCharge)) | ||||
| player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.TimeOfGhostFaintingWhenCharge)); | player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.TimeOfGhostFaintingWhenCharge)); | ||||
| @@ -138,6 +138,10 @@ namespace Gaming | |||||
| if ((!(((Character)objBeingShot).IsGhost())) && bullet.Parent.IsGhost()) | if ((!(((Character)objBeingShot).IsGhost())) && bullet.Parent.IsGhost()) | ||||
| { | { | ||||
| Student whoBeAttacked = (Student)objBeingShot; | Student whoBeAttacked = (Student)objBeingShot; | ||||
| if (whoBeAttacked.CharacterType == CharacterType.StraightAStudent) | |||||
| { | |||||
| ((WriteAnswers)whoBeAttacked.FindIActiveSkill(ActiveSkillType.WriteAnswers)).DegreeOfMeditation = 0; | |||||
| } | |||||
| if (whoBeAttacked.BeAttacked(bullet)) | if (whoBeAttacked.BeAttacked(bullet)) | ||||
| { | { | ||||
| BeAddictedToGame(whoBeAttacked, (Ghost)bullet.Parent); | BeAddictedToGame(whoBeAttacked, (Ghost)bullet.Parent); | ||||
| @@ -13,7 +13,7 @@ namespace Gaming | |||||
| { | { | ||||
| public bool BecomeVampire(Character player) | public bool BecomeVampire(Character player) | ||||
| { | { | ||||
| return ActiveSkillEffect(player.UseIActiveSkill(ActiveSkillType.BecomeVampire), player, () => | |||||
| return ActiveSkillEffect(player.FindIActiveSkill(ActiveSkillType.BecomeVampire), player, () => | |||||
| { | { | ||||
| player.Vampire += 0.5; | player.Vampire += 0.5; | ||||
| Debugger.Output(player, "becomes vampire!"); | Debugger.Output(player, "becomes vampire!"); | ||||
| @@ -29,7 +29,7 @@ namespace Gaming | |||||
| { | { | ||||
| if ((!player.Commandable())) return false; | if ((!player.Commandable())) return false; | ||||
| IActiveSkill skill = player.UseIActiveSkill(ActiveSkillType.CanBeginToCharge); | |||||
| IActiveSkill skill = player.FindIActiveSkill(ActiveSkillType.CanBeginToCharge); | |||||
| Debugger.Output(player, "can begin to charge!"); | Debugger.Output(player, "can begin to charge!"); | ||||
| @@ -45,7 +45,7 @@ namespace Gaming | |||||
| public static bool BecomeInvisible(Character player) | public static bool BecomeInvisible(Character player) | ||||
| { | { | ||||
| IActiveSkill activeSkill = player.UseIActiveSkill(ActiveSkillType.BecomeInvisible); | |||||
| IActiveSkill activeSkill = player.FindIActiveSkill(ActiveSkillType.BecomeInvisible); | |||||
| return ActiveSkillEffect(activeSkill, player, () => | return ActiveSkillEffect(activeSkill, player, () => | ||||
| { | { | ||||
| player.AddInvisible(activeSkill.DurationTime); | player.AddInvisible(activeSkill.DurationTime); | ||||
| @@ -57,7 +57,7 @@ namespace Gaming | |||||
| public bool JumpyBomb(Character player) | public bool JumpyBomb(Character player) | ||||
| { | { | ||||
| return ActiveSkillEffect(player.UseIActiveSkill(ActiveSkillType.JumpyBomb), player, () => | |||||
| return ActiveSkillEffect(player.FindIActiveSkill(ActiveSkillType.JumpyBomb), player, () => | |||||
| { | { | ||||
| player.BulletOfPlayer = BulletType.BombBomb; | player.BulletOfPlayer = BulletType.BombBomb; | ||||
| Debugger.Output(player, "uses jumpybomb!"); | Debugger.Output(player, "uses jumpybomb!"); | ||||
| @@ -66,10 +66,27 @@ namespace Gaming | |||||
| { player.BulletOfPlayer = player.OriBulletOfPlayer; }); | { player.BulletOfPlayer = player.OriBulletOfPlayer; }); | ||||
| } | } | ||||
| public bool WriteAnswers(Character player) | |||||
| { | |||||
| IActiveSkill activeSkill = player.FindIActiveSkill(ActiveSkillType.WriteAnswers); | |||||
| return ActiveSkillEffect(activeSkill, player, () => | |||||
| { | |||||
| Generator? generator = (Generator?)gameMap.OneForInteract(player.Position, GameObjType.Generator); | |||||
| if (generator != null) | |||||
| { | |||||
| generator.Repair(((WriteAnswers)activeSkill).DegreeOfMeditation); | |||||
| Debugger.Output(player, "uses WriteAnswers in" + generator.ToString() + "with " + (((WriteAnswers)activeSkill).DegreeOfMeditation).ToString()); | |||||
| ((WriteAnswers)activeSkill).DegreeOfMeditation = 0; | |||||
| } | |||||
| }, | |||||
| () => | |||||
| { }); | |||||
| } | |||||
| public static bool UseKnife(Character player) | public static bool UseKnife(Character player) | ||||
| { | { | ||||
| return ActiveSkillEffect(player.UseIActiveSkill(ActiveSkillType.UseKnife), player, () => | |||||
| return ActiveSkillEffect(player.FindIActiveSkill(ActiveSkillType.UseKnife), player, () => | |||||
| { | { | ||||
| player.BulletOfPlayer = BulletType.FlyingKnife; | player.BulletOfPlayer = BulletType.FlyingKnife; | ||||
| Debugger.Output(player, "uses flyingknife!"); | Debugger.Output(player, "uses flyingknife!"); | ||||
| @@ -80,7 +97,7 @@ namespace Gaming | |||||
| public bool Punish(Character player) | public bool Punish(Character player) | ||||
| { | { | ||||
| return ActiveSkillEffect(player.UseIActiveSkill(ActiveSkillType.Punish), player, () => | |||||
| return ActiveSkillEffect(player.FindIActiveSkill(ActiveSkillType.Punish), player, () => | |||||
| { | { | ||||
| gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); | gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); | ||||
| try | try | ||||
| @@ -110,9 +127,9 @@ namespace Gaming | |||||
| public bool SuperFast(Character player) | public bool SuperFast(Character player) | ||||
| { | { | ||||
| return ActiveSkillEffect(player.UseIActiveSkill(ActiveSkillType.SuperFast), player, () => | |||||
| return ActiveSkillEffect(player.FindIActiveSkill(ActiveSkillType.SuperFast), player, () => | |||||
| { | { | ||||
| player.AddMoveSpeed(player.UseIActiveSkill(ActiveSkillType.SuperFast).DurationTime, 3.0); | |||||
| player.AddMoveSpeed(player.FindIActiveSkill(ActiveSkillType.SuperFast).DurationTime, 3.0); | |||||
| Debugger.Output(player, "moves very fast!"); | Debugger.Output(player, "moves very fast!"); | ||||
| }, | }, | ||||
| () => | () => | ||||
| @@ -1,4 +1,5 @@ | |||||
| using System; | using System; | ||||
| using System.Reflection.Emit; | |||||
| using System.Threading; | using System.Threading; | ||||
| using GameClass.GameObj; | using GameClass.GameObj; | ||||
| using Preparation.Interface; | using Preparation.Interface; | ||||
| @@ -11,6 +12,48 @@ namespace Gaming // 被动技能开局时就释放,持续到游戏结束 | |||||
| { | { | ||||
| private partial class SkillManager | private partial class SkillManager | ||||
| { | { | ||||
| public void Meditate(Character player) | |||||
| { | |||||
| const int learningDegree = GameData.basicFixSpeed / 4; | |||||
| WriteAnswers activeSkill = (WriteAnswers)player.FindIActiveSkill(ActiveSkillType.WriteAnswers); | |||||
| new Thread | |||||
| ( | |||||
| () => | |||||
| { | |||||
| new FrameRateTaskExecutor<int> | |||||
| ( | |||||
| () => gameMap.Timer.IsGaming && !player.IsResetting, | |||||
| () => | |||||
| { | |||||
| if (player.Commandable()) activeSkill.DegreeOfMeditation += learningDegree; | |||||
| else activeSkill.DegreeOfMeditation = 0; | |||||
| Debugger.Output(player, "with " + (((WriteAnswers)activeSkill).DegreeOfMeditation).ToString()); | |||||
| }, | |||||
| 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 RecoverAfterBattle(Character player) | public void RecoverAfterBattle(Character player) | ||||
| { | { | ||||
| const int recoverDegree = 5; // 每帧回复血量 | const int recoverDegree = 5; // 每帧回复血量 | ||||
| @@ -31,6 +31,9 @@ namespace Gaming | |||||
| case ActiveSkillType.JumpyBomb: | case ActiveSkillType.JumpyBomb: | ||||
| JumpyBomb(character); | JumpyBomb(character); | ||||
| break; | break; | ||||
| case ActiveSkillType.WriteAnswers: | |||||
| WriteAnswers(character); | |||||
| break; | |||||
| default: | default: | ||||
| return false; | return false; | ||||
| } | } | ||||
| @@ -41,6 +44,9 @@ namespace Gaming | |||||
| if (character.Occupation.ListOfIPassiveSkill.Contains(passiveSkillType)) | if (character.Occupation.ListOfIPassiveSkill.Contains(passiveSkillType)) | ||||
| switch (passiveSkillType) | switch (passiveSkillType) | ||||
| { | { | ||||
| case PassiveSkillType.Meditate: | |||||
| Meditate(character); | |||||
| break; | |||||
| default: | default: | ||||
| return; | return; | ||||
| } | } | ||||
| @@ -51,6 +57,9 @@ namespace Gaming | |||||
| foreach (var passiveSkill in character.Occupation.ListOfIPassiveSkill) | foreach (var passiveSkill in character.Occupation.ListOfIPassiveSkill) | ||||
| switch (passiveSkill) | switch (passiveSkill) | ||||
| { | { | ||||
| case PassiveSkillType.Meditate: | |||||
| Meditate(character); | |||||
| break; | |||||
| default: | default: | ||||
| return; | return; | ||||
| } | } | ||||
| @@ -184,4 +184,48 @@ namespace Preparation.Interface | |||||
| public int speedOfOpenChest = GameData.basicSpeedOfOpenChest; | public int speedOfOpenChest = GameData.basicSpeedOfOpenChest; | ||||
| public int SpeedOfOpenChest => speedOfOpenChest; | public int SpeedOfOpenChest => speedOfOpenChest; | ||||
| } | } | ||||
| public class StraightAStudent : IStudent | |||||
| { | |||||
| private const int moveSpeed = (int)(GameData.basicMoveSpeed * 0.8); | |||||
| public int MoveSpeed => moveSpeed; | |||||
| private const int maxHp = (int)(GameData.basicHp * 1.1); | |||||
| public int MaxHp => maxHp; | |||||
| private const int maxGamingAddiction = (int)(GameData.basicMaxGamingAddiction * 1.5); | |||||
| public int MaxGamingAddiction => maxGamingAddiction; | |||||
| public const int maxBulletNum = 0; | |||||
| public int MaxBulletNum => maxBulletNum; | |||||
| public BulletType InitBullet => BulletType.Null; | |||||
| public List<ActiveSkillType> ListOfIActiveSkill => new(new ActiveSkillType[] { ActiveSkillType.WriteAnswers }); | |||||
| public List<PassiveSkillType> ListOfIPassiveSkill => new(new PassiveSkillType[] { PassiveSkillType.Meditate }); | |||||
| public const int fixSpeed = GameData.basicFixSpeed * 13 / 10; | |||||
| public int FixSpeed => fixSpeed; | |||||
| public const int treatSpeed = GameData.basicTreatSpeed * 8 / 10; | |||||
| public int TreatSpeed => treatSpeed; | |||||
| public const double concealment = GameData.basicConcealment * 0.9; | |||||
| public double Concealment => concealment; | |||||
| public const int alertnessRadius = (int)(GameData.basicAlertnessRadius * 0.9); | |||||
| public int AlertnessRadius => alertnessRadius; | |||||
| public int viewRange = GameData.basicViewRange; | |||||
| public int ViewRange => viewRange; | |||||
| public int timeOfOpeningOrLocking = GameData.basicSpeedOfOpeningOrLocking; | |||||
| public int TimeOfOpeningOrLocking => timeOfOpeningOrLocking; | |||||
| public int speedOfClimbingThroughWindows = (int)(GameData.basicStudentSpeedOfClimbingThroughWindows * 10 / 12.0); | |||||
| public int SpeedOfClimbingThroughWindows => speedOfClimbingThroughWindows; | |||||
| public int speedOfOpenChest = GameData.basicSpeedOfOpenChest; | |||||
| public int SpeedOfOpenChest => speedOfOpenChest; | |||||
| } | |||||
| } | } | ||||
| @@ -79,7 +79,7 @@ namespace Preparation.Utility | |||||
| Klee = 3, | Klee = 3, | ||||
| SpeedUpWhenLeavingGrass = 4, | SpeedUpWhenLeavingGrass = 4, | ||||
| Teacher = 5, | Teacher = 5, | ||||
| PSkill5 = 6 | |||||
| StraightAStudent = 6 | |||||
| } | } | ||||
| public enum ActiveSkillType // 主动技能 | public enum ActiveSkillType // 主动技能 | ||||
| { | { | ||||
| @@ -91,6 +91,7 @@ namespace Preparation.Utility | |||||
| UseKnife = 5, | UseKnife = 5, | ||||
| CanBeginToCharge = 6, | CanBeginToCharge = 6, | ||||
| Punish = 7, | Punish = 7, | ||||
| WriteAnswers = 8, | |||||
| } | } | ||||
| public enum PassiveSkillType | public enum PassiveSkillType | ||||
| { | { | ||||
| @@ -99,7 +100,7 @@ namespace Preparation.Utility | |||||
| BecomeVampire = 2, | BecomeVampire = 2, | ||||
| NuclearWeapon = 3, | NuclearWeapon = 3, | ||||
| SuperFast = 4, | SuperFast = 4, | ||||
| ASkill4 = 5, | |||||
| Meditate = 5, | |||||
| ASkill5 = 6 | ASkill5 = 6 | ||||
| } | } | ||||
| public enum BuffType // buff | public enum BuffType // buff | ||||
| @@ -176,6 +176,8 @@ namespace Server | |||||
| return Protobuf.StudentType.Athlete; | return Protobuf.StudentType.Athlete; | ||||
| case Preparation.Utility.CharacterType.Teacher: | case Preparation.Utility.CharacterType.Teacher: | ||||
| return StudentType._2; | return StudentType._2; | ||||
| case CharacterType.StraightAStudent: | |||||
| return StudentType._3; | |||||
| default: | default: | ||||
| return Protobuf.StudentType.NullStudentType; | return Protobuf.StudentType.NullStudentType; | ||||
| } | } | ||||
| @@ -189,6 +191,8 @@ namespace Server | |||||
| return Preparation.Utility.CharacterType.Athlete; | return Preparation.Utility.CharacterType.Athlete; | ||||
| case StudentType._2: | case StudentType._2: | ||||
| return Preparation.Utility.CharacterType.Teacher; | return Preparation.Utility.CharacterType.Teacher; | ||||
| case StudentType._3: | |||||
| return CharacterType.StraightAStudent; | |||||
| default: | default: | ||||
| return Preparation.Utility.CharacterType.Null; | return Preparation.Utility.CharacterType.Null; | ||||
| } | } | ||||
| @@ -12,6 +12,6 @@ start cmd /k ..\Client\bin\Debug\net6.0-windows\Client.exe --cl --port 8888 --ch | |||||
| ping -n 2 127.0.0.1 > NUL | ping -n 2 127.0.0.1 > NUL | ||||
| start cmd /k ..\Client\bin\Debug\net6.0-windows\Client.exe --cl --port 8888 --characterID 1 --type 1 --occupation 1 | |||||
| start cmd /k ..\Client\bin\Debug\net6.0-windows\Client.exe --cl --port 8888 --characterID 1 --type 1 --occupation 3 | |||||
| ping -n 2 127.0.0.1 > NUL | ping -n 2 127.0.0.1 > NUL | ||||