| @@ -133,7 +133,7 @@ namespace GameClass.GameObj | |||||
| if (!(bouncer?.TeamID == this.TeamID)) | if (!(bouncer?.TeamID == this.TeamID)) | ||||
| { | { | ||||
| if (hasSpear || !HasShield) | if (hasSpear || !HasShield) | ||||
| _ = TrySubHp(subHP); | |||||
| _ = SubHp(subHP); | |||||
| if (hp <= 0) | if (hp <= 0) | ||||
| TryActivatingLIFE(); | TryActivatingLIFE(); | ||||
| } | } | ||||
| @@ -218,7 +218,8 @@ namespace GameClass.GameObj | |||||
| HPReadWriterLock.ExitWriteLock(); | HPReadWriterLock.ExitWriteLock(); | ||||
| } | } | ||||
| } | } | ||||
| } // 最大血量 | |||||
| } | |||||
| // 最大血量 | |||||
| protected long hp; | protected long hp; | ||||
| public long HP | public long HP | ||||
| { | { | ||||
| @@ -234,22 +235,23 @@ namespace GameClass.GameObj | |||||
| HPReadWriterLock.ExitReadLock(); | HPReadWriterLock.ExitReadLock(); | ||||
| } | } | ||||
| } | } | ||||
| set | |||||
| } | |||||
| public long SetHP(long value) | |||||
| { | |||||
| HPReadWriterLock.EnterWriteLock(); | |||||
| try | |||||
| { | { | ||||
| HPReadWriterLock.EnterWriteLock(); | |||||
| try | |||||
| if (value > 0) | |||||
| { | { | ||||
| if (value > 0) | |||||
| { | |||||
| hp = value <= maxHp ? value : maxHp; | |||||
| } | |||||
| else | |||||
| hp = 0; | |||||
| } | |||||
| finally | |||||
| { | |||||
| HPReadWriterLock.ExitWriteLock(); | |||||
| return hp = value <= maxHp ? value : maxHp; | |||||
| } | } | ||||
| else | |||||
| return hp = 0; | |||||
| } | |||||
| finally | |||||
| { | |||||
| HPReadWriterLock.ExitWriteLock(); | |||||
| } | } | ||||
| } | } | ||||
| @@ -257,7 +259,7 @@ namespace GameClass.GameObj | |||||
| /// 尝试减血 | /// 尝试减血 | ||||
| /// </summary> | /// </summary> | ||||
| /// <param name="sub">减血量</param> | /// <param name="sub">减血量</param> | ||||
| public long TrySubHp(long sub) | |||||
| public long SubHp(long sub) | |||||
| { | { | ||||
| HPReadWriterLock.EnterWriteLock(); | HPReadWriterLock.EnterWriteLock(); | ||||
| try | try | ||||
| @@ -280,6 +282,20 @@ namespace GameClass.GameObj | |||||
| } | } | ||||
| } | } | ||||
| public long AddHP(long add) | |||||
| { | |||||
| HPReadWriterLock.EnterWriteLock(); | |||||
| try | |||||
| { | |||||
| long previousHp = hp; | |||||
| return (hp = (hp + add > maxHp) ? maxHp : hp + add) - previousHp; | |||||
| } | |||||
| finally | |||||
| { | |||||
| HPReadWriterLock.ExitWriteLock(); | |||||
| } | |||||
| } | |||||
| private readonly object vampireLock = new(); | private readonly object vampireLock = new(); | ||||
| public object VampireLock => vampire; | public object VampireLock => vampire; | ||||
| @@ -537,13 +553,7 @@ namespace GameClass.GameObj | |||||
| if (value == PlayerStateType.Rescued) return -1; | if (value == PlayerStateType.Rescued) return -1; | ||||
| Door door = (Door)lastObj!; | Door door = (Door)lastObj!; | ||||
| door.StopOpen(); | door.StopOpen(); | ||||
| ReleaseTool(door.DoorNum switch | |||||
| { | |||||
| 3 => PropType.Key3, | |||||
| 5 => PropType.Key5, | |||||
| _ => PropType.Key6, | |||||
| } | |||||
| ); | |||||
| ReleaseTool(door.KeyType); | |||||
| return ChangePlayerState(runningState, value, gameObj); | return ChangePlayerState(runningState, value, gameObj); | ||||
| case PlayerStateType.UsingSkill: | case PlayerStateType.UsingSkill: | ||||
| { | { | ||||
| @@ -13,23 +13,16 @@ namespace GameClass.GameObj | |||||
| public Door(XY initPos, PlaceType placeType) : | public Door(XY initPos, PlaceType placeType) : | ||||
| base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Door) | base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Door) | ||||
| { | { | ||||
| switch (placeType) | |||||
| keyType = placeType switch | |||||
| { | { | ||||
| case PlaceType.Door3: | |||||
| doorNum = 3; | |||||
| break; | |||||
| case PlaceType.Door5: | |||||
| doorNum = 5; | |||||
| break; | |||||
| case PlaceType.Door6: | |||||
| default: | |||||
| doorNum = 6; | |||||
| break; | |||||
| } | |||||
| PlaceType.Door3 => PropType.Key3, | |||||
| PlaceType.Door5 => PropType.Key5, | |||||
| _ => PropType.Key6, | |||||
| }; | |||||
| } | } | ||||
| private readonly int doorNum; | |||||
| public int DoorNum => doorNum; | |||||
| private readonly PropType keyType; | |||||
| public PropType KeyType => keyType; | |||||
| public override bool IsRigid => !isOpen; | public override bool IsRigid => !isOpen; | ||||
| public override ShapeType Shape => ShapeType.Square; | public override ShapeType Shape => ShapeType.Square; | ||||
| @@ -151,12 +144,7 @@ namespace GameClass.GameObj | |||||
| { | { | ||||
| if (character.PlayerState == PlayerStateType.OpeningTheDoor) | if (character.PlayerState == PlayerStateType.OpeningTheDoor) | ||||
| { | { | ||||
| character.ReleaseTool(DoorNum switch | |||||
| { | |||||
| 3 => PropType.Key3, | |||||
| 5 => PropType.Key5, | |||||
| _ => PropType.Key6, | |||||
| }); | |||||
| character.ReleaseTool(KeyType); | |||||
| character.SetPlayerStateNaturally(); | character.SetPlayerStateNaturally(); | ||||
| } | } | ||||
| else if (character.PlayerState == PlayerStateType.LockingTheDoor) | else if (character.PlayerState == PlayerStateType.LockingTheDoor) | ||||
| @@ -1,5 +1,4 @@ | |||||
| using Google.Protobuf.WellKnownTypes; | |||||
| using Preparation.Interface; | |||||
| using Preparation.Interface; | |||||
| using Preparation.Utility; | using Preparation.Utility; | ||||
| using System; | using System; | ||||
| @@ -321,7 +321,7 @@ namespace Gaming | |||||
| if (playerRescued.AddTimeOfRescue(GameData.checkInterval)) | if (playerRescued.AddTimeOfRescue(GameData.checkInterval)) | ||||
| { | { | ||||
| playerRescued.SetPlayerStateNaturally(); | playerRescued.SetPlayerStateNaturally(); | ||||
| playerRescued.HP = playerRescued.MaxHp / 2; | |||||
| playerRescued.SetHP(playerRescued.MaxHp / 2); | |||||
| player.AddScore(GameData.StudentScoreRescue); | player.AddScore(GameData.StudentScoreRescue); | ||||
| return false; | return false; | ||||
| } | } | ||||
| @@ -479,19 +479,12 @@ namespace Gaming | |||||
| Door? doorToLock = (Door?)gameMap.OneForInteract(player.Position, GameObjType.Door); | Door? doorToLock = (Door?)gameMap.OneForInteract(player.Position, GameObjType.Door); | ||||
| if (doorToLock == null) return false; | if (doorToLock == null) return false; | ||||
| PropType propType = doorToLock.DoorNum switch | |||||
| { | |||||
| 3 => PropType.Key3, | |||||
| 5 => PropType.Key5, | |||||
| _ => PropType.Key6, | |||||
| }; | |||||
| if (!player.UseTool(propType)) return false; | |||||
| if (!player.UseTool(doorToLock.KeyType)) return false; | |||||
| long stateNum = player.SetPlayerState(RunningStateType.Waiting, PlayerStateType.LockingTheDoor, doorToLock); | long stateNum = player.SetPlayerState(RunningStateType.Waiting, PlayerStateType.LockingTheDoor, doorToLock); | ||||
| if (stateNum == -1) | if (stateNum == -1) | ||||
| { | { | ||||
| player.ReleaseTool(propType); | |||||
| player.ReleaseTool(doorToLock.KeyType); | |||||
| return false; | return false; | ||||
| } | } | ||||
| @@ -502,13 +495,13 @@ namespace Gaming | |||||
| player.ThreadNum.WaitOne(); | player.ThreadNum.WaitOne(); | ||||
| if (!player.StartThread(stateNum, RunningStateType.RunningActively)) | if (!player.StartThread(stateNum, RunningStateType.RunningActively)) | ||||
| { | { | ||||
| player.ReleaseTool(propType); | |||||
| player.ReleaseTool(doorToLock.KeyType); | |||||
| player.ThreadNum.Release(); | player.ThreadNum.Release(); | ||||
| return; | return; | ||||
| } | } | ||||
| if (!doorToLock.TryLock(player)) | if (!doorToLock.TryLock(player)) | ||||
| { | { | ||||
| player.ReleaseTool(propType); | |||||
| player.ReleaseTool(doorToLock.KeyType); | |||||
| player.ResetPlayerState(stateNum); | player.ResetPlayerState(stateNum); | ||||
| player.ThreadNum.Release(); | player.ThreadNum.Release(); | ||||
| return; | return; | ||||
| @@ -529,7 +522,7 @@ namespace Gaming | |||||
| ) | ) | ||||
| .Start(); | .Start(); | ||||
| doorToLock.StopLock(); | doorToLock.StopLock(); | ||||
| player.ReleaseTool(propType); | |||||
| player.ReleaseTool(doorToLock.KeyType); | |||||
| player.ThreadNum.Release(); | player.ThreadNum.Release(); | ||||
| player.ResetPlayerState(stateNum); | player.ResetPlayerState(stateNum); | ||||
| } | } | ||||
| @@ -542,22 +535,15 @@ namespace Gaming | |||||
| public bool OpenDoor(Character player) | public bool OpenDoor(Character player) | ||||
| { | { | ||||
| if (player.CharacterType == CharacterType.Robot) return false; | if (player.CharacterType == CharacterType.Robot) return false; | ||||
| Door? doorToLock = (Door?)gameMap.OneForInteract(player.Position, GameObjType.Door); | |||||
| if (doorToLock == null) return false; | |||||
| PropType propType = doorToLock.DoorNum switch | |||||
| { | |||||
| 3 => PropType.Key3, | |||||
| 5 => PropType.Key5, | |||||
| _ => PropType.Key6, | |||||
| }; | |||||
| Door? doorToOpen = (Door?)gameMap.OneForInteract(player.Position, GameObjType.Door); | |||||
| if (doorToOpen == null) return false; | |||||
| if (!player.UseTool(propType)) return false; | |||||
| if (!player.UseTool(doorToOpen.KeyType)) return false; | |||||
| long stateNum = player.SetPlayerState(RunningStateType.Waiting, PlayerStateType.OpeningTheDoor, doorToLock); | |||||
| long stateNum = player.SetPlayerState(RunningStateType.Waiting, PlayerStateType.OpeningTheDoor, doorToOpen); | |||||
| if (stateNum == -1) | if (stateNum == -1) | ||||
| { | { | ||||
| player.ReleaseTool(propType); | |||||
| player.ReleaseTool(doorToOpen.KeyType); | |||||
| return false; | return false; | ||||
| } | } | ||||
| @@ -568,13 +554,13 @@ namespace Gaming | |||||
| player.ThreadNum.WaitOne(); | player.ThreadNum.WaitOne(); | ||||
| if (!player.StartThread(stateNum, RunningStateType.RunningSleepily)) | if (!player.StartThread(stateNum, RunningStateType.RunningSleepily)) | ||||
| { | { | ||||
| player.ReleaseTool(propType); | |||||
| player.ReleaseTool(doorToOpen.KeyType); | |||||
| player.ThreadNum.Release(); | player.ThreadNum.Release(); | ||||
| return; | return; | ||||
| } | } | ||||
| if (!doorToLock.TryOpen(player)) | |||||
| if (!doorToOpen.TryOpen(player)) | |||||
| { | { | ||||
| player.ReleaseTool(propType); | |||||
| player.ReleaseTool(doorToOpen.KeyType); | |||||
| if (player.ResetPlayerState(stateNum)) | if (player.ResetPlayerState(stateNum)) | ||||
| player.ThreadNum.Release(); | player.ThreadNum.Release(); | ||||
| return; | return; | ||||
| @@ -583,8 +569,8 @@ namespace Gaming | |||||
| if (player.ResetPlayerState(stateNum)) | if (player.ResetPlayerState(stateNum)) | ||||
| { | { | ||||
| doorToLock.StopOpen(); | |||||
| player.ReleaseTool(propType); | |||||
| doorToOpen.StopOpen(); | |||||
| player.ReleaseTool(doorToOpen.KeyType); | |||||
| player.ThreadNum.Release(); | player.ThreadNum.Release(); | ||||
| } | } | ||||
| } | } | ||||
| @@ -326,12 +326,12 @@ namespace Gaming | |||||
| { | { | ||||
| if (bullet.HasSpear) | if (bullet.HasSpear) | ||||
| { | { | ||||
| long subHp = student.TrySubHp(bullet.AP); | |||||
| long subHp = student.SubHp(bullet.AP); | |||||
| #if DEBUG | #if DEBUG | ||||
| Debugger.Output(this, "is being shot! Now his hp is" + student.HP.ToString()); | Debugger.Output(this, "is being shot! Now his hp is" + student.HP.ToString()); | ||||
| #endif | #endif | ||||
| bullet.Parent.AddScore(GameData.TrickerScoreAttackStudent(subHp) + GameData.ScorePropUseSpear); | bullet.Parent.AddScore(GameData.TrickerScoreAttackStudent(subHp) + GameData.ScorePropUseSpear); | ||||
| bullet.Parent.HP = (long)(bullet.Parent.HP + (bullet.Parent.Vampire * subHp)); | |||||
| bullet.Parent.AddHP((long)bullet.Parent.Vampire * subHp); | |||||
| } | } | ||||
| else return; | else return; | ||||
| } | } | ||||
| @@ -340,14 +340,14 @@ namespace Gaming | |||||
| long subHp; | long subHp; | ||||
| if (bullet.HasSpear) | if (bullet.HasSpear) | ||||
| { | { | ||||
| subHp = student.TrySubHp(bullet.AP + GameData.ApSpearAdd); | |||||
| subHp = student.SubHp(bullet.AP + GameData.ApSpearAdd); | |||||
| #if DEBUG | #if DEBUG | ||||
| Debugger.Output(this, "is being shot with Spear! Now his hp is" + student.HP.ToString()); | Debugger.Output(this, "is being shot with Spear! Now his hp is" + student.HP.ToString()); | ||||
| #endif | #endif | ||||
| } | } | ||||
| else | else | ||||
| { | { | ||||
| subHp = student.TrySubHp(bullet.AP); | |||||
| subHp = student.SubHp(bullet.AP); | |||||
| #if DEBUG | #if DEBUG | ||||
| Debugger.Output(this, "is being shot! Now his hp is" + student.HP.ToString()); | Debugger.Output(this, "is being shot! Now his hp is" + student.HP.ToString()); | ||||
| #endif | #endif | ||||
| @@ -358,7 +358,7 @@ namespace Gaming | |||||
| student.AddScore(subHp * GameData.factorOfScoreWhenTeacherAttacked / GameData.basicApOfGhost / FactorTeacher); | student.AddScore(subHp * GameData.factorOfScoreWhenTeacherAttacked / GameData.basicApOfGhost / FactorTeacher); | ||||
| } | } | ||||
| bullet.Parent.HP = (int)(bullet.Parent.HP + (bullet.Parent.Vampire * subHp)); | |||||
| bullet.Parent.AddHP((long)(bullet.Parent.Vampire * subHp)); | |||||
| } | } | ||||
| if (student.HP <= 0) | if (student.HP <= 0) | ||||
| student.TryActivatingLIFE(); // 如果有复活甲 | student.TryActivatingLIFE(); // 如果有复活甲 | ||||
| @@ -46,7 +46,7 @@ namespace Gaming | |||||
| if (!player.IsGhost()) | if (!player.IsGhost()) | ||||
| if (player.HP < player.MaxHp) | if (player.HP < player.MaxHp) | ||||
| { | { | ||||
| player.HP += GameData.basicTreatmentDegree / 2; | |||||
| player.AddHP(GameData.basicTreatmentDegree / 2); | |||||
| player.AddScore(GameData.ScorePropAddHp); | player.AddScore(GameData.ScorePropAddHp); | ||||
| } | } | ||||
| else player.AddAp(GameData.PropDuration); | else player.AddAp(GameData.PropDuration); | ||||
| @@ -421,7 +421,7 @@ namespace Gaming | |||||
| if ((character.PlayerState == PlayerStateType.Addicted) && gameMap.CanSee(player, character)) | if ((character.PlayerState == PlayerStateType.Addicted) && gameMap.CanSee(player, character)) | ||||
| { | { | ||||
| character.SetPlayerStateNaturally(); | character.SetPlayerStateNaturally(); | ||||
| character.HP = GameData.RemainHpWhenAddLife; | |||||
| character.SetHP(GameData.RemainHpWhenAddLife); | |||||
| ((Student)character).SetTimeOfRescue(0); | ((Student)character).SetTimeOfRescue(0); | ||||
| player.AddScore(GameData.StudentScoreRescue); | player.AddScore(GameData.StudentScoreRescue); | ||||
| break; | break; | ||||
| @@ -452,7 +452,7 @@ namespace Gaming | |||||
| if ((character.HP < character.MaxHp) && gameMap.CanSee(player, character)) | if ((character.HP < character.MaxHp) && gameMap.CanSee(player, character)) | ||||
| { | { | ||||
| player.AddScore(GameData.StudentScoreTreat(GameData.addHpWhenEncourage)); | player.AddScore(GameData.StudentScoreTreat(GameData.addHpWhenEncourage)); | ||||
| character.HP += GameData.addHpWhenEncourage; | |||||
| character.AddHP(GameData.addHpWhenEncourage); | |||||
| ((Student)character).SetDegreeOfTreatment0(); | ((Student)character).SetDegreeOfTreatment0(); | ||||
| break; | break; | ||||
| } | } | ||||
| @@ -6,7 +6,8 @@ namespace Preparation.Interface | |||||
| public interface ICharacter : IMoveable | public interface ICharacter : IMoveable | ||||
| { | { | ||||
| public long TeamID { get; } | public long TeamID { get; } | ||||
| public long HP { get; set; } | |||||
| public long HP { get; } | |||||
| public long AddHP(long add); | |||||
| public long Score { get; } | public long Score { get; } | ||||
| public void AddScore(long add); | public void AddScore(long add); | ||||
| public double Vampire { get; } | public double Vampire { get; } | ||||