diff --git a/logic/GameClass/GameObj/Bullet/Bullet.Ghost.cs b/logic/GameClass/GameObj/Bullet/Bullet.Ghost.cs
index d4a1895..5af9533 100644
--- a/logic/GameClass/GameObj/Bullet/Bullet.Ghost.cs
+++ b/logic/GameClass/GameObj/Bullet/Bullet.Ghost.cs
@@ -22,7 +22,11 @@ namespace GameClass.GameObj
{
return false;
}
-
+ public override bool CanBeBombed(GameObjType gameObjType)
+ {
+ if (gameObjType == GameObjType.Character) return true;
+ return false;
+ }
public override BulletType TypeOfBullet => BulletType.CommonAttackOfGhost;
}
@@ -44,6 +48,11 @@ namespace GameClass.GameObj
{
return false;
}
+ public override bool CanBeBombed(GameObjType gameObjType)
+ {
+ if (gameObjType == GameObjType.Character) return true;
+ return false;
+ }
public override BulletType TypeOfBullet => BulletType.FlyingKnife;
@@ -68,6 +77,11 @@ namespace GameClass.GameObj
// 圆形攻击范围
return XY.Distance(this.Position, target.Position) <= BulletBombRange;
}
+ public override bool CanBeBombed(GameObjType gameObjType)
+ {
+ if (gameObjType == GameObjType.Character) return true;
+ return false;
+ }
public override BulletType TypeOfBullet => BulletType.AtomBomb;
@@ -92,6 +106,11 @@ namespace GameClass.GameObj
// 圆形攻击范围
return XY.Distance(this.Position, target.Position) <= BulletBombRange;
}
+ public override bool CanBeBombed(GameObjType gameObjType)
+ {
+ if (gameObjType == GameObjType.Character) return true;
+ return false;
+ }
public override BulletType TypeOfBullet => BulletType.OrdinaryBullet;
}
@@ -116,6 +135,11 @@ namespace GameClass.GameObj
// 圆形攻击范围
return XY.Distance(this.Position, target.Position) <= BulletBombRange;
}
+ public override bool CanBeBombed(GameObjType gameObjType)
+ {
+ if (gameObjType == GameObjType.Character) return true;
+ return false;
+ }
public override BulletType TypeOfBullet => BulletType.FastBullet;
}
@@ -135,6 +159,11 @@ namespace GameClass.GameObj
public override int RecoveryFromHit => GameData.basicRecoveryFromHit;
public override bool IsToBomb => true;
+ public override bool CanBeBombed(GameObjType gameObjType)
+ {
+ if (gameObjType == GameObjType.Character) return true;
+ return false;
+ }
public override bool CanAttack(GameObj target)
{
double FacingAngle = Math.Atan2(this.FacingDirection.y, this.FacingDirection.x);
diff --git a/logic/GameClass/GameObj/Bullet/Bullet.Student.cs b/logic/GameClass/GameObj/Bullet/Bullet.Student.cs
index 6140d57..26510a3 100644
--- a/logic/GameClass/GameObj/Bullet/Bullet.Student.cs
+++ b/logic/GameClass/GameObj/Bullet/Bullet.Student.cs
@@ -1,7 +1,32 @@
-using Preparation.Interface;
-using Preparation.Utility;
-using System;
+using Preparation.Utility;
namespace GameClass.GameObj
{
+ /* internal sealed class Ram : Bullet
+ {
+ public Ram(Character player, PlaceType placeType, XY pos, int radius = GameData.bulletRadius) :
+ base(player, radius, placeType, pos)
+ {
+ }
+ public override double BulletBombRange => 0;
+ public override double BulletAttackRange => 0;
+ public override int AP => 7220;
+ public override int Speed => 0;
+ public override bool IsToBomb => false;
+ public override int CastTime => 0;
+ public override int Backswing => 0;
+ public override int RecoveryFromHit => 0;
+ public override bool CanAttack(GameObj target)
+ {
+ return false;
+ }
+ public override bool CanBeBombed(GameObjType gameObjType)
+ {
+ // if (gameObjType == GameObjType.Character) return true;
+ return false;
+ }
+
+ public override BulletType TypeOfBullet => BulletType.Ram;
+
+ }*/
}
diff --git a/logic/GameClass/GameObj/Bullet/Bullet.cs b/logic/GameClass/GameObj/Bullet/Bullet.cs
index 2e4611c..0020a2f 100644
--- a/logic/GameClass/GameObj/Bullet/Bullet.cs
+++ b/logic/GameClass/GameObj/Bullet/Bullet.cs
@@ -30,6 +30,7 @@ namespace GameClass.GameObj
/// 被尝试攻击者
/// 是否可以攻击到
public abstract bool CanAttack(GameObj target);
+ public abstract bool CanBeBombed(GameObjType gameObjType);
protected override bool IgnoreCollideExecutor(IGameObj targetObj)
{
diff --git a/logic/GameClass/GameObj/Character/Character.Skill.cs b/logic/GameClass/GameObj/Character/Character.Skill.cs
index db44536..1ebcc7c 100644
--- a/logic/GameClass/GameObj/Character/Character.Skill.cs
+++ b/logic/GameClass/GameObj/Character/Character.Skill.cs
@@ -12,9 +12,22 @@ namespace GameClass.GameObj
private readonly IOccupation occupation;
public IOccupation Occupation => occupation;
+
private Dictionary timeUntilActiveSkillAvailable = new();
public Dictionary TimeUntilActiveSkillAvailable => timeUntilActiveSkillAvailable;
+ private Dictionary iActiveSkillDictionary = new();
+ public Dictionary IActiveSkillDictionary => iActiveSkillDictionary;
+
+ public IActiveSkill? UseIActiveSkill(ActiveSkillType activeSkillType)
+ {
+ if (Occupation.ListOfIActiveSkill.Contains(activeSkillType))
+ {
+ return IActiveSkillDictionary[activeSkillType];
+ }
+ return null;
+ }
+
public bool SetTimeUntilActiveSkillAvailable(ActiveSkillType activeSkillType, int timeUntilActiveSkillAvailable)
{
if (TimeUntilActiveSkillAvailable.ContainsKey(activeSkillType))
@@ -73,10 +86,13 @@ namespace GameClass.GameObj
this.concealment = Occupation.Concealment;
this.alertnessRadius = Occupation.AlertnessRadius;
this.characterType = characterType;
+ this.TimeOfOpeningOrLocking = Occupation.TimeOfOpeningOrLocking;
+ this.TimeOfClimbingThroughWindows = Occupation.TimeOfClimbingThroughWindows;
foreach (var activeSkill in this.Occupation.ListOfIActiveSkill)
{
this.TimeUntilActiveSkillAvailable.Add(activeSkill, 0);
+ this.IActiveSkillDictionary.Add(activeSkill, SkillFactory.FindIActiveSkill(activeSkill));
}
// UsePassiveSkill(); //创建player时开始被动技能,这一过程也可以放到gamestart时进行
diff --git a/logic/GameClass/GameObj/Character/Character.cs b/logic/GameClass/GameObj/Character/Character.cs
index 6d7b927..ba33b4c 100644
--- a/logic/GameClass/GameObj/Character/Character.cs
+++ b/logic/GameClass/GameObj/Character/Character.cs
@@ -72,6 +72,13 @@ namespace GameClass.GameObj
}
}
+ public bool Commandable() => (playerState != PlayerStateType.IsDeceased && playerState != PlayerStateType.IsEscaped
+ && playerState != PlayerStateType.IsAddicted && playerState != PlayerStateType.IsStunned
+ && playerState != PlayerStateType.IsSwinging && playerState != PlayerStateType.IsTryingToAttack
+ && playerState != PlayerStateType.IsClimbingThroughWindows);
+ public bool InteractingWithMapWithoutMoving() => (playerState == PlayerStateType.IsLockingTheDoor || playerState == PlayerStateType.IsFixing || playerState == PlayerStateType.IsOpeningTheChest);
+ public bool NullOrMoving() => (playerState == PlayerStateType.Null || playerState == PlayerStateType.IsMoving);
+
// private int deathCount = 0;
// public int DeathCount => deathCount; // 玩家的死亡次数
@@ -130,8 +137,8 @@ namespace GameClass.GameObj
}
}
- private Prop? propInventory;
- public Prop? PropInventory // 持有的道具
+ private Prop[] propInventory = new Prop[GameData.maxNumOfPropInPropInventory];
+ public Prop[] PropInventory
{
get => propInventory;
set
@@ -148,16 +155,30 @@ namespace GameClass.GameObj
/// 使用物品栏中的道具
///
/// 被使用的道具
- public Prop? UseProp()
+ public Prop? UseProp(int indexing)
{
+ if (indexing < 0 || indexing >= GameData.maxNumOfPropInPropInventory)
+ return null;
lock (gameObjLock)
{
- var oldProp = PropInventory;
- PropInventory = null;
- return oldProp;
+ Prop prop = propInventory[indexing];
+ PropInventory[indexing] = null;
+ return prop;
}
}
+ ///
+ /// 如果indexing==GameData.maxNumOfPropInPropInventory表明道具栏为满
+ ///
+ public int IndexingOfAddProp()
+ {
+ int indexing = 0;
+ for (; indexing < GameData.maxNumOfPropInPropInventory; ++indexing)
+ if (PropInventory[indexing] == null)
+ break;
+ return indexing;
+ }
+
///
/// 是否在隐身
///
@@ -226,7 +247,18 @@ namespace GameClass.GameObj
}
}
-
+ private int timeOfClimbingThroughWindows;
+ public int TimeOfClimbingThroughWindows
+ {
+ get => timeOfClimbingThroughWindows;
+ set
+ {
+ lock (gameObjLock)
+ {
+ timeOfClimbingThroughWindows = value;
+ }
+ }
+ }
///
/// 进行一次攻击
diff --git a/logic/GameClass/GameObj/Character/Skill.cs b/logic/GameClass/GameObj/Character/Skill.cs
new file mode 100644
index 0000000..0a28727
--- /dev/null
+++ b/logic/GameClass/GameObj/Character/Skill.cs
@@ -0,0 +1,98 @@
+using Preparation.Interface;
+using Preparation.Utility;
+
+namespace GameClass.GameObj
+{
+ 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 IsBeingUsed { get; set; }
+ }
+ public class CanBeginToCharge : IActiveSkill
+ {
+ public int SkillCD => GameData.commonSkillCD / 5;
+ public int DurationTime => GameData.commonSkillTime / 10 * 6;
+
+ private readonly object commonSkillLock = new object();
+ public object ActiveSkillLock => commonSkillLock;
+
+ public bool IsBeingUsed { get; set; }
+ }
+
+ 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 IsBeingUsed { get; set; }
+ }
+
+ 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 IsBeingUsed { get; set; }
+ }
+
+ 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 IsBeingUsed { get; set; }
+ }
+
+ 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 IsBeingUsed { get; set; }
+ }
+
+ public static class SkillFactory
+ {
+ public static IActiveSkill? FindIActiveSkill(ActiveSkillType activeSkillType)
+ {
+ switch (activeSkillType)
+ {
+ case ActiveSkillType.BecomeInvisible:
+ return new BecomeInvisible();
+ case ActiveSkillType.UseKnife:
+ return new UseKnife();
+ default:
+ return null;
+ }
+ }
+
+ public static ActiveSkillType FindActiveSkillType(IActiveSkill ActiveSkill)
+ {
+ switch (ActiveSkill)
+ {
+ case BecomeInvisible:
+ return ActiveSkillType.BecomeInvisible;
+ case UseKnife:
+ return ActiveSkillType.UseKnife;
+ case CanBeginToCharge:
+ return ActiveSkillType.CanBeginToCharge;
+ default:
+ return ActiveSkillType.Null;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/logic/GameClass/GameObj/Map/Chest.cs b/logic/GameClass/GameObj/Map/Chest.cs
new file mode 100644
index 0000000..975e1cf
--- /dev/null
+++ b/logic/GameClass/GameObj/Map/Chest.cs
@@ -0,0 +1,34 @@
+using Preparation.Utility;
+using System.Collections.Generic;
+
+namespace GameClass.GameObj
+{
+ ///
+ /// 箱子
+ ///
+ public class Chest : GameObj
+ {
+ public Chest(XY initPos) :
+ base(initPos, GameData.numOfPosGridPerCell / 2, GameObjType.Chest)
+ {
+ this.place = PlaceType.Chest;
+ this.CanMove = false;
+ }
+ public override bool IsRigid => true;
+ public override ShapeType Shape => ShapeType.Square;
+
+ private Prop[] propInChest = new Prop[GameData.maxNumOfPropInChest];
+ public Prop[] PropInChest => propInChest;
+
+ private bool isOpen = false;
+ public bool IsOpen
+ {
+ get => isOpen;
+ set
+ {
+ lock (gameObjLock)
+ isOpen = value;
+ }
+ }
+ }
+}
diff --git a/logic/GameClass/GameObj/Map/Map.cs b/logic/GameClass/GameObj/Map/Map.cs
index 0a373f6..cecd378 100644
--- a/logic/GameClass/GameObj/Map/Map.cs
+++ b/logic/GameClass/GameObj/Map/Map.cs
@@ -96,6 +96,18 @@ namespace GameClass.GameObj
}
return flag;
}
+ public bool RemoveJustFromMap(GameObj gameObj)
+ {
+ GameObjLockDict[gameObj.Type].EnterWriteLock();
+ try
+ {
+ return GameObjDict[gameObj.Type].Remove(gameObj);
+ }
+ finally
+ {
+ GameObjLockDict[gameObj.Type].ExitWriteLock();
+ }
+ }
public void Add(GameObj gameObj)
{
GameObjLockDict[gameObj.Type].EnterWriteLock();
@@ -134,55 +146,22 @@ namespace GameClass.GameObj
{
case (uint)PlaceType.Wall:
{
- GameObjLockDict[GameObjType.Wall].EnterWriteLock();
- try
- {
- GameObjDict[GameObjType.Wall].Add(new Wall(GameData.GetCellCenterPos(i, j)));
- }
- finally
- {
- GameObjLockDict[GameObjType.Wall].ExitWriteLock();
- }
+ Add(new Wall(GameData.GetCellCenterPos(i, j)));
break;
}
case (uint)PlaceType.Doorway:
{
- GameObjLockDict[GameObjType.Doorway].EnterWriteLock();
- try
- {
- GameObjDict[GameObjType.Doorway].Add(new Doorway(GameData.GetCellCenterPos(i, j)));
- }
- finally
- {
- GameObjLockDict[GameObjType.Doorway].ExitWriteLock();
- }
+ Add(new Doorway(GameData.GetCellCenterPos(i, j)));
break;
}
-
case (uint)PlaceType.EmergencyExit:
{
- GameObjLockDict[GameObjType.EmergencyExit].EnterWriteLock();
- try
- {
- GameObjDict[GameObjType.EmergencyExit].Add(new EmergencyExit(GameData.GetCellCenterPos(i, j)));
- }
- finally
- {
- GameObjLockDict[GameObjType.EmergencyExit].ExitWriteLock();
- }
+ Add(new EmergencyExit(GameData.GetCellCenterPos(i, j)));
break;
}
case (uint)PlaceType.Generator:
{
- GameObjLockDict[GameObjType.Generator].EnterWriteLock();
- try
- {
- GameObjDict[GameObjType.Generator].Add(new Generator(GameData.GetCellCenterPos(i, j)));
- }
- finally
- {
- GameObjLockDict[GameObjType.Generator].ExitWriteLock();
- }
+ Add(new Generator(GameData.GetCellCenterPos(i, j)));
break;
}
case (uint)PlaceType.BirthPoint1:
diff --git a/logic/GameClass/GameObj/Prop.cs b/logic/GameClass/GameObj/Prop.cs
index 5ebcdbd..9e4fea2 100644
--- a/logic/GameClass/GameObj/Prop.cs
+++ b/logic/GameClass/GameObj/Prop.cs
@@ -12,7 +12,8 @@ namespace GameClass.GameObj
protected override bool IgnoreCollideExecutor(IGameObj targetObj)
{
- if (targetObj.Type == GameObjType.Prop || targetObj.Type == GameObjType.Bullet || targetObj.Type == GameObjType.Character)
+ if (targetObj.Type == GameObjType.Prop || targetObj.Type == GameObjType.Bullet
+ || targetObj.Type == GameObjType.Character || targetObj.Type == GameObjType.Chest)
return true;
return false;
}
diff --git a/logic/GameEngine/MoveEngine.cs b/logic/GameEngine/MoveEngine.cs
index 4169731..0f728ff 100644
--- a/logic/GameEngine/MoveEngine.cs
+++ b/logic/GameEngine/MoveEngine.cs
@@ -74,12 +74,12 @@ namespace GameEngine
{
if (obj.IsMoving) // 已经移动的物体不能再移动
return;
+ if (!obj.IsAvailable || !gameTimer.IsGaming)
+ return;
new Thread
(
() =>
{
- if (!obj.IsAvailable && gameTimer.IsGaming)
- return;
lock (obj.MoveLock)
obj.IsMoving = true;
@@ -93,7 +93,7 @@ namespace GameEngine
() =>
{
moveVecLength = obj.MoveSpeed / GameData.numOfStepPerSecond;
- XY res = new XY(direction, moveVecLength);
+ res = new XY(direction, moveVecLength);
// 越界情况处理:如果越界,则与越界方块碰撞
bool flag; // 循环标志
@@ -136,7 +136,7 @@ namespace GameEngine
if (!isDestroyed)
{
moveVecLength = deltaLen + leftTime * obj.MoveSpeed / GameData.numOfPosGridPerCell;
- XY res = new XY(direction, moveVecLength);
+ res = new XY(direction, moveVecLength);
if ((collisionObj = collisionChecker.CheckCollision(obj, res)) == null)
{
obj.MovingSetPos(res, GetPlaceType(obj.Position + res));
diff --git a/logic/Gaming/ActionManager.cs b/logic/Gaming/ActionManager.cs
index 14c0441..c088076 100644
--- a/logic/Gaming/ActionManager.cs
+++ b/logic/Gaming/ActionManager.cs
@@ -25,11 +25,7 @@ namespace Gaming
public bool Stop(Character player)
{
- if (player.PlayerState == PlayerStateType.IsRescuing || player.PlayerState == PlayerStateType.IsRescued
- || player.PlayerState == PlayerStateType.IsFixing || player.PlayerState == PlayerStateType.IsMoving
- || player.PlayerState == PlayerStateType.IsTreated || player.PlayerState == PlayerStateType.IsTreating
- || player.PlayerState == PlayerStateType.IsRummagingInTheChest || player.PlayerState == PlayerStateType.IsLockingTheDoor
- || player.PlayerState == PlayerStateType.IsClimbingThroughWindows)
+ if (player.Commandable())
{
player.PlayerState = PlayerStateType.Null;
return true;
@@ -82,11 +78,11 @@ namespace Gaming
.Start();
if (generatorForFix.DegreeOfFRepair == GameData.degreeOfFixedGenerator)
{
- gameMap.GameObjLockDict[GameObjType.Generator].EnterReadLock();
- try
+ Doorway exit = (Doorway)gameMap.GameObjDict[GameObjType.Doorway][1];
+ if (!exit.PowerSupply)
{
- Doorway exit = (Doorway)gameMap.GameObjDict[GameObjType.Doorway][1];
- if (!exit.PowerSupply)
+ gameMap.GameObjLockDict[GameObjType.Generator].EnterReadLock();
+ try
{
int numOfFixedGenerator = 0;
foreach (Generator generator in gameMap.GameObjDict[GameObjType.Generator])
@@ -106,12 +102,12 @@ namespace Gaming
}
}
}
+ finally
+ {
+ gameMap.GameObjLockDict[GameObjType.Generator].ExitReadLock();
+ }
}
- finally
- {
- gameMap.GameObjLockDict[GameObjType.Generator].ExitReadLock();
- }
}
}
@@ -156,7 +152,9 @@ namespace Gaming
public bool Treat(Student player, Student playerTreated)
{
- if (playerTreated.PlayerState == PlayerStateType.Null || player.PlayerState == PlayerStateType.Null || playerTreated.HP == playerTreated.MaxHp || !GameData.ApproachToInteract(playerTreated.Position, player.Position))
+ if (!((playerTreated.NullOrMoving() || playerTreated.InteractingWithMapWithoutMoving())
+ && (player.NullOrMoving() || player.InteractingWithMapWithoutMoving()))
+ || playerTreated.HP == playerTreated.MaxHp || !GameData.ApproachToInteract(playerTreated.Position, player.Position))
return false;
if (playerTreated.HP + playerTreated.DegreeOfTreatment >= playerTreated.MaxHp)
diff --git a/logic/Gaming/AttackManager.cs b/logic/Gaming/AttackManager.cs
index bd30d58..55dd75d 100644
--- a/logic/Gaming/AttackManager.cs
+++ b/logic/Gaming/AttackManager.cs
@@ -68,6 +68,32 @@ namespace Gaming
{ IsBackground = true }.Start();
}
+ public void BeStunned(Character player, int time)
+ {
+ new Thread
+ (() =>
+ {
+ player.PlayerState = PlayerStateType.IsStunned;
+ new FrameRateTaskExecutor(
+ () => player.PlayerState == PlayerStateType.IsStunned && gameMap.Timer.IsGaming,
+ () =>
+ {
+ },
+ timeInterval: GameData.frameDuration,
+ () =>
+ {
+ if (player.PlayerState == PlayerStateType.IsStunned)
+ player.PlayerState = PlayerStateType.Null;
+ return 0;
+ },
+ maxTotalDuration: time
+ )
+ .Start();
+ }
+ )
+ { IsBackground = true }.Start();
+ }
+
private void Die(Character player)
{
@@ -82,22 +108,14 @@ namespace Gaming
// gameMap.GameObjLockDict[GameObjType.Character].ExitWriteLock();
// }
- Prop? dropProp = null;
- if (player.PropInventory != null) // 若角色原来有道具,则原始道具掉落在原地
- {
- dropProp = player.PropInventory;
- XY res = GameData.GetCellCenterPos(player.Position.x / GameData.numOfPosGridPerCell, player.Position.y / GameData.numOfPosGridPerCell);
- dropProp.ReSetPos(res, gameMap.GetPlaceType(res));
- }
- gameMap.GameObjLockDict[GameObjType.Prop].EnterWriteLock();
- try
+ for (int i = 0; i < GameData.maxNumOfPropInPropInventory; i++)
{
- if (dropProp != null)
- gameMap.GameObjDict[GameObjType.Prop].Add(dropProp);
- }
- finally
- {
- gameMap.GameObjLockDict[GameObjType.Prop].ExitWriteLock();
+ Prop? prop = player.UseProp(i);
+ if (prop != null)
+ {
+ prop.ReSetPos(player.Position, gameMap.GetPlaceType(player.Position));
+ gameMap.Add(prop);
+ }
}
// player.Reset();
@@ -129,21 +147,21 @@ namespace Gaming
*/
}
- private bool CanBeBombed(Bullet bullet, GameObjType gameObjType)
- {
- if (gameObjType == GameObjType.Character) return true;
- return false;
- }
private void BombObj(Bullet bullet, GameObj objBeingShot)
{
switch (objBeingShot.Type)
{
case GameObjType.Character:
- if (!((Character)objBeingShot).IsGhost())
+
+ if ((!((Character)objBeingShot).IsGhost()) && bullet.Parent.IsGhost())
if (((Character)objBeingShot).BeAttacked(bullet))
{
BeAddictedToGame((Student)objBeingShot);
}
+ // if (((Character)objBeingShot).IsGhost() && !bullet.Parent.IsGhost() && bullet.TypeOfBullet == BulletType.Ram)
+ // BeStunned((Character)objBeingShot, bullet.AP);
+ break;
+ default:
break;
}
}
@@ -218,9 +236,9 @@ namespace Gaming
foreach (var kvp in gameMap.GameObjDict)
{
- if (CanBeBombed(bullet, kvp.Key))
+ if (bullet.CanBeBombed(kvp.Key))
{
- gameMap.GameObjLockDict[kvp.Key].EnterWriteLock();
+ gameMap.GameObjLockDict[kvp.Key].EnterReadLock();
try
{
foreach (var item in gameMap.GameObjDict[kvp.Key])
@@ -232,7 +250,7 @@ namespace Gaming
}
finally
{
- gameMap.GameObjLockDict[kvp.Key].ExitWriteLock();
+ gameMap.GameObjLockDict[kvp.Key].ExitReadLock();
}
}
}
@@ -304,55 +322,51 @@ namespace Gaming
(int)((player.Radius + BulletFactory.BulletRadius(player.BulletOfPlayer)) * Math.Sin(angle))
);
- Bullet? bullet = player.Attack(
- res, gameMap.GetPlaceType(res)
- );
- if (bullet.CastTime > 0)
+ Bullet? bullet = player.Attack(res, gameMap.GetPlaceType(res));
+
+ if (bullet != null)
{
- player.PlayerState = PlayerStateType.IsTryingToAttack;
+ bullet.CanMove = true;
+ gameMap.Add(bullet);
+ moveEngine.MoveObj(bullet, (int)((bullet.BulletAttackRange - player.Radius - BulletFactory.BulletRadius(player.BulletOfPlayer)) * 1000 / bullet.MoveSpeed), angle); // 这里时间参数除出来的单位要是ms
- new Thread
- (() =>
- {
- new FrameRateTaskExecutor(
- loopCondition: () => player.PlayerState == PlayerStateType.IsTryingToAttack && gameMap.Timer.IsGaming,
- loopToDo: () =>
- {
- },
- timeInterval: GameData.frameDuration,
- finallyReturn: () => 0,
- maxTotalDuration: bullet.CastTime
- )
-
- .Start();
-
- if (gameMap.Timer.IsGaming)
+
+ if (bullet.CastTime > 0)
+ {
+ player.PlayerState = PlayerStateType.IsTryingToAttack;
+
+ new Thread
+ (() =>
{
- if (player.PlayerState == PlayerStateType.IsTryingToAttack)
+ new FrameRateTaskExecutor(
+ loopCondition: () => player.PlayerState == PlayerStateType.IsTryingToAttack && gameMap.Timer.IsGaming,
+ loopToDo: () =>
+ {
+ },
+ timeInterval: GameData.frameDuration,
+ finallyReturn: () => 0,
+ maxTotalDuration: bullet.CastTime
+ )
+
+ .Start();
+
+ if (gameMap.Timer.IsGaming)
{
- player.PlayerState = PlayerStateType.Null;
+ if (player.PlayerState == PlayerStateType.IsTryingToAttack)
+ {
+ player.PlayerState = PlayerStateType.Null;
+ }
+ else
+ bullet.IsMoving = false;
+ gameMap.Remove(bullet);
}
- else
- bullet.IsMoving = false;
- gameMap.Remove(bullet);
}
- }
- )
- { IsBackground = true }.Start();
+ )
+ { IsBackground = true }.Start();
+ }
}
if (bullet != null)
{
- bullet.CanMove = true;
- gameMap.GameObjLockDict[GameObjType.Bullet].EnterWriteLock();
- try
- {
- gameMap.GameObjDict[GameObjType.Bullet].Add(bullet);
- }
- finally
- {
- gameMap.GameObjLockDict[GameObjType.Bullet].ExitWriteLock();
- }
- moveEngine.MoveObj(bullet, (int)((bullet.BulletAttackRange - player.Radius - BulletFactory.BulletRadius(player.BulletOfPlayer)) * 1000 / bullet.MoveSpeed), angle); // 这里时间参数除出来的单位要是ms
#if DEBUG
Console.WriteLine($"playerID:{player.ID} successfully attacked!");
#endif
@@ -368,4 +382,4 @@ namespace Gaming
}
}
}
-}
+}
\ No newline at end of file
diff --git a/logic/Gaming/Game.cs b/logic/Gaming/Game.cs
index 2807231..d11a9c6 100644
--- a/logic/Gaming/Game.cs
+++ b/logic/Gaming/Game.cs
@@ -197,14 +197,6 @@ namespace Gaming
public void EndGame()
{
- gameMap.GameObjLockDict[GameObjType.Character].EnterWriteLock();
- /*try
- {
- }
- finally
- {
- }*/
- gameMap.GameObjLockDict[GameObjType.Character].ExitWriteLock();
}
public bool MovePlayer(long playerID, int moveTimeInMilliseconds, double angle)
{
@@ -301,24 +293,24 @@ namespace Gaming
_ = attackManager.Attack(player, angle);
}
}
- public void UseProp(long playerID)
+ public void UseProp(long playerID, int indexing)
{
if (!gameMap.Timer.IsGaming)
return;
Character? player = gameMap.FindPlayer(playerID);
if (player != null)
{
- propManager.UseProp(player);
+ propManager.UseProp(player, indexing);
}
}
- public void ThrowProp(long playerID, int timeInmillionSeconds, double angle)
+ public void ThrowProp(long playerID, int indexing)
{
if (!gameMap.Timer.IsGaming)
return;
Character? player = gameMap.FindPlayer(playerID);
if (player != null)
{
- propManager.ThrowProp(player, timeInmillionSeconds, angle);
+ propManager.ThrowProp(player, indexing);
}
}
public bool PickProp(long playerID, PropType propType = PropType.Null)
diff --git a/logic/Gaming/PropManager.cs b/logic/Gaming/PropManager.cs
index 716631a..d84787a 100644
--- a/logic/Gaming/PropManager.cs
+++ b/logic/Gaming/PropManager.cs
@@ -28,11 +28,11 @@ namespace Gaming
ProduceProp();
}
- public void UseProp(Character player)
+ public void UseProp(Character player, int indexing)
{
if (player.IsResetting)
return;
- Prop? prop = player.UseProp();
+ Prop? prop = player.UseProp(indexing);
switch (prop?.GetPropType())
{
case PropType.Spear:
@@ -62,6 +62,10 @@ namespace Gaming
{
if (player.IsResetting)
return false;
+ int indexing = player.IndexingOfAddProp();
+ if (indexing == GameData.maxNumOfPropInPropInventory)
+ return false;
+
Prop? pickProp = null;
if (propType == PropType.Null) // 自动检查有无道具可捡
{
@@ -70,9 +74,9 @@ namespace Gaming
{
foreach (Prop prop in gameMap.GameObjDict[GameObjType.Prop])
{
- if (GameData.IsInTheSameCell(prop.Position, player.Position) && prop.CanMove == false)
+ if (GameData.IsInTheSameCell(prop.Position, player.Position))
{
- pickProp = prop;
+ player.PropInventory[indexing] = prop;
}
}
}
@@ -92,7 +96,7 @@ namespace Gaming
{
if (GameData.IsInTheSameCell(prop.Position, player.Position) && prop.CanMove == false)
{
- pickProp = prop;
+ player.PropInventory[indexing] = prop;
}
}
}
@@ -105,66 +109,26 @@ namespace Gaming
if (pickProp != null)
{
- // pickProp.CanMove = false;
- Prop? dropProp = null;
- if (player.PropInventory != null) // 若角色原来有道具,则原始道具掉落在原地
- {
- dropProp = player.PropInventory;
- XY res = GameData.GetCellCenterPos(player.Position.x / GameData.numOfPosGridPerCell, player.Position.y / GameData.numOfPosGridPerCell);
- dropProp.ReSetPos(res, gameMap.GetPlaceType(res));
- }
- player.PropInventory = pickProp;
- gameMap.GameObjLockDict[GameObjType.Prop].EnterWriteLock();
- try
- {
- gameMap.GameObjDict[GameObjType.Prop].Remove((Preparation.Interface.IGameObj)pickProp);
- if (dropProp != null)
- gameMap.GameObjDict[GameObjType.Prop].Add((Preparation.Interface.IGameObj)dropProp);
- }
- finally
- {
- gameMap.GameObjLockDict[GameObjType.Prop].ExitWriteLock();
- }
- gameMap.GameObjLockDict[GameObjType.PickedProp].EnterWriteLock();
- try
- {
- gameMap.GameObjDict[GameObjType.PickedProp].Add(new PickedProp(pickProp));
- }
- finally
- {
- gameMap.GameObjLockDict[GameObjType.PickedProp].ExitWriteLock();
- }
-
+ gameMap.Remove(pickProp);
+ gameMap.Add(new PickedProp(pickProp));
return true;
}
else
return false;
}
- public void ThrowProp(Character player, int timeInMilliseconds, double angle)
+ public void ThrowProp(Character player, int indexing)
{
- if (!gameMap.Timer.IsGaming)
+ if (!gameMap.Timer.IsGaming || player.IsResetting)
return;
- if (player.IsResetting) // 移动中也能扔,但由于“惯性”,可能初始位置会有点变化
- return;
- Prop? prop = player.UseProp();
+ Prop? prop = player.UseProp(indexing);
if (prop == null)
return;
- prop.CanMove = true;
prop.ReSetPos(player.Position, gameMap.GetPlaceType(player.Position));
- gameMap.GameObjLockDict[GameObjType.Prop].EnterWriteLock();
- try
- {
- gameMap.GameObjDict[GameObjType.Prop].Add((Preparation.Interface.IGameObj)prop);
- }
- finally
- {
- gameMap.GameObjLockDict[GameObjType.Prop].ExitWriteLock();
- }
- timeInMilliseconds = timeInMilliseconds < GameData.PropMaxMoveDistance / prop.MoveSpeed * 1000 ? timeInMilliseconds : GameData.PropMaxMoveDistance / prop.MoveSpeed * 1000;
- moveEngine.MoveObj(prop, timeInMilliseconds, angle);
+ gameMap.Add(prop);
}
+
private void ProduceProp()
{
int len = availableCellForGenerateProp.Count;
@@ -182,30 +146,23 @@ namespace Gaming
int rand = r.Next(0, len);
XY randPos = availableCellForGenerateProp[rand];
- gameMap.GameObjLockDict[GameObjType.Prop].EnterWriteLock();
- try
- {
- switch (r.Next(0, 4))
- {
- case 0:
- gameMap.GameObjDict[GameObjType.Prop].Add((Preparation.Interface.IGameObj)new AddLIFE(randPos, gameMap.GetPlaceType(randPos)));
- break;
- case 1:
- gameMap.GameObjDict[GameObjType.Prop].Add((Preparation.Interface.IGameObj)new AddSpeed(randPos, gameMap.GetPlaceType(randPos)));
- break;
- case 2:
- gameMap.GameObjDict[GameObjType.Prop].Add((Preparation.Interface.IGameObj)new Shield(randPos, gameMap.GetPlaceType(randPos)));
- break;
- case 3:
- gameMap.GameObjDict[GameObjType.Prop].Add((Preparation.Interface.IGameObj)new Spear(randPos, gameMap.GetPlaceType(randPos)));
- break;
- default:
- break;
- }
- }
- finally
+
+ switch (r.Next(0, 4))
{
- gameMap.GameObjLockDict[GameObjType.Prop].ExitWriteLock();
+ case 0:
+ gameMap.Add(new AddLIFE(randPos, gameMap.GetPlaceType(randPos)));
+ break;
+ case 1:
+ gameMap.Add(new AddSpeed(randPos, gameMap.GetPlaceType(randPos)));
+ break;
+ case 2:
+ gameMap.Add(new Shield(randPos, gameMap.GetPlaceType(randPos)));
+ break;
+ case 3:
+ gameMap.Add(new Spear(randPos, gameMap.GetPlaceType(randPos)));
+ break;
+ default:
+ break;
}
},
GameData.PropProduceTime,
diff --git a/logic/Gaming/SkillManager/ActiveSkill.cs b/logic/Gaming/SkillManager/ActiveSkill.cs
deleted file mode 100644
index f16c093..0000000
--- a/logic/Gaming/SkillManager/ActiveSkill.cs
+++ /dev/null
@@ -1,238 +0,0 @@
-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(
- () => !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(
- () => 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;
- }
- }
- }
-
- }
-
- }
-}
diff --git a/logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs b/logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs
new file mode 100644
index 0000000..73961e1
--- /dev/null
+++ b/logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs
@@ -0,0 +1,193 @@
+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 bool BecomeVampire(Character player)
+ {
+ return ActiveSkillEffect(player.UseIActiveSkill(ActiveSkillType.BecomeVampire), 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 bool CanBeginToCharge(Character player)
+ {
+
+ if ((!player.Commandable())) return false;
+ IActiveSkill skill = player.UseIActiveSkill(ActiveSkillType.CanBeginToCharge);
+ return ActiveSkillEffect(skill, player, () =>
+ {
+ player.AddMoveSpeed(skill.DurationTime, 3.0);
+ //player.BulletOfPlayer = BulletType.Ram;
+ new Thread
+ (
+ () =>
+ {
+ new FrameRateTaskExecutor(
+ loopCondition: () => player.Commandable() && gameMap.Timer.IsGaming,
+ loopToDo: () =>
+ {
+ gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock();
+ try
+ {
+ foreach (Character character in gameMap.GameObjDict[GameObjType.Character])
+ {
+ if (character.IsGhost() != player.IsGhost() && XY.Distance(player.Position + new XY(player.FacingDirection, player.Radius), character.Position) <= character.Radius)
+ {
+ attackManager.BeStunned(character, GameData.TimeOfGhostFainting);
+ attackManager.BeStunned(player, GameData.TimeOfStudentFainting);
+ break;
+ }
+ }
+ }
+ finally
+ {
+ gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock();
+ }
+ },
+ timeInterval: GameData.frameDuration,
+ finallyReturn: () => 0,
+ maxTotalDuration: skill.DurationTime
+ )
+
+ .Start();
+ }
+
+ )
+ { IsBackground = true }.Start();
+ Debugger.Output(player, "can begin to charge!");
+ },
+ () =>
+ {
+ double tempVam = player.Vampire - 0.5;
+ player.Vampire = tempVam < player.OriVampire ? player.OriVampire : tempVam;
+ });
+ }
+
+
+ public bool BecomeInvisible(Character player)
+ {
+ return ActiveSkillEffect(player.UseIActiveSkill(ActiveSkillType.BecomeInvisible), player, () =>
+ {
+ player.IsInvisible = true;
+ Debugger.Output(player, "become invisible!");
+ },
+ () =>
+ { player.IsInvisible = false; });
+ }
+
+ public bool NuclearWeapon(Character player)
+ {
+ return ActiveSkillEffect(player.UseIActiveSkill(ActiveSkillType.NuclearWeapon), player, () =>
+ {
+ player.BulletOfPlayer = BulletType.AtomBomb;
+ Debugger.Output(player, "uses atombomb!");
+ },
+ () =>
+ { player.BulletOfPlayer = player.OriBulletOfPlayer; });
+ }
+
+
+ public bool UseKnife(Character player)
+ {
+ return ActiveSkillEffect(player.UseIActiveSkill(ActiveSkillType.UseKnife), player, () =>
+ {
+ player.BulletOfPlayer = BulletType.FlyingKnife;
+ Debugger.Output(player, "uses flyingknife!");
+ },
+ () =>
+ { player.BulletOfPlayer = player.OriBulletOfPlayer; });
+ }
+
+ public bool SuperFast(Character player)
+ {
+ return ActiveSkillEffect(player.UseIActiveSkill(ActiveSkillType.SuperFast), player, () =>
+ {
+ player.AddMoveSpeed(player.UseIActiveSkill(ActiveSkillType.SuperFast).DurationTime, 3.0);
+ Debugger.Output(player, "moves very fast!");
+ },
+ () =>
+ { });
+ }
+
+
+ public static bool ActiveSkillEffect(IActiveSkill activeSkill, Character player, Action startSkill, Action endSkill)
+ {
+ lock (activeSkill.ActiveSkillLock)
+ {
+ ActiveSkillType activeSkillType = SkillFactory.FindActiveSkillType(activeSkill);
+ if (player.TimeUntilActiveSkillAvailable[activeSkillType] == 0)
+ {
+
+ player.SetTimeUntilActiveSkillAvailable(activeSkillType, activeSkill.SkillCD);
+ new Thread
+ (() =>
+ {
+ startSkill();
+ new FrameRateTaskExecutor(
+ () => !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(
+ loopCondition: () => player.TimeUntilActiveSkillAvailable[activeSkillType] > 0 && !player.IsResetting,
+ loopToDo: () =>
+ {
+ player.AddTimeUntilActiveSkillAvailable(activeSkillType, -(int)GameData.frameDuration);
+ },
+ timeInterval: GameData.frameDuration,
+ finallyReturn: () => 0
+ )
+ {
+ 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;
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/logic/Gaming/SkillManager/PassiveSkill.cs b/logic/Gaming/SkillManager/SkillManager.PassiveSkill.cs
similarity index 100%
rename from logic/Gaming/SkillManager/PassiveSkill.cs
rename to logic/Gaming/SkillManager/SkillManager.PassiveSkill.cs
diff --git a/logic/Gaming/SkillManager/SkillManager.cs b/logic/Gaming/SkillManager/SkillManager.cs
index 0d5363e..31b249c 100644
--- a/logic/Gaming/SkillManager/SkillManager.cs
+++ b/logic/Gaming/SkillManager/SkillManager.cs
@@ -14,7 +14,20 @@ namespace Gaming
public bool UseActiveSkill(Character character, ActiveSkillType activeSkillType)
{
if (character.Occupation.ListOfIActiveSkill.Contains(activeSkillType))
- return FindIActiveSkill(activeSkillType).SkillEffect(character);
+ switch (activeSkillType)
+ {
+ case ActiveSkillType.BecomeInvisible:
+ BecomeInvisible(character);
+ break;
+ case ActiveSkillType.UseKnife:
+ UseKnife(character);
+ break;
+ case ActiveSkillType.CanBeginToCharge:
+ CanBeginToCharge(character);
+ break;
+ default:
+ return false;
+ }
return false;
}
public void UsePassiveSkill(Character character, PassiveSkillType passiveSkillType)
diff --git a/logic/Preparation/Interface/IOccupation.cs b/logic/Preparation/Interface/IOccupation.cs
index 16895a2..e510a98 100644
--- a/logic/Preparation/Interface/IOccupation.cs
+++ b/logic/Preparation/Interface/IOccupation.cs
@@ -15,6 +15,7 @@ namespace Preparation.Interface
public double Concealment { get; }
public int AlertnessRadius { get; }
public int TimeOfOpeningOrLocking { get; }
+ public int TimeOfClimbingThroughWindows { get; }
}
public interface IGhost : IOccupation
@@ -53,6 +54,10 @@ namespace Preparation.Interface
public int timeOfOpeningOrLocking = GameData.basicTimeOfOpeningOrLocking;
public int TimeOfOpeningOrLocking => timeOfOpeningOrLocking;
+
+ public int timeOfClimbingThroughWindows = GameData.basicTimeOfClimbingThroughWindows;
+ public int TimeOfClimbingThroughWindows => timeOfClimbingThroughWindows;
+
}
public class Athlete : IStudent
{
@@ -70,7 +75,7 @@ namespace Preparation.Interface
public BulletType InitBullet => BulletType.Null;
- public List ListOfIActiveSkill => new(new ActiveSkillType[] { ActiveSkillType.BeginToCharge });
+ public List ListOfIActiveSkill => new(new ActiveSkillType[] { ActiveSkillType.CanBeginToCharge });
public List ListOfIPassiveSkill => new(new PassiveSkillType[] { });
public const int fixSpeed = GameData.basicFixSpeed / 10 * 6;
@@ -82,7 +87,10 @@ namespace Preparation.Interface
public const int alertnessRadius = (int)(GameData.basicAlertnessRadius * 0.9);
public int AlertnessRadius => alertnessRadius;
- public int timeOfOpeningOrLocking = GameData.basicTimeOfOpeningOrLocking;
+ public int timeOfOpeningOrLocking = GameData.basicTimeOfOpeningOrLocking * 12 / 10;
public int TimeOfOpeningOrLocking => timeOfOpeningOrLocking;
+
+ public int timeOfClimbingThroughWindows = GameData.basicTimeOfClimbingThroughWindows / 87 * 80;
+ public int TimeOfClimbingThroughWindows => timeOfClimbingThroughWindows;
}
}
diff --git a/logic/Preparation/Interface/ISkill.cs b/logic/Preparation/Interface/ISkill.cs
new file mode 100644
index 0000000..c38663b
--- /dev/null
+++ b/logic/Preparation/Interface/ISkill.cs
@@ -0,0 +1,16 @@
+namespace Preparation.Interface
+{
+ public interface ISkill
+ {
+ }
+ public interface IPassiveSkill : ISkill
+ {
+ }
+ public interface IActiveSkill : ISkill
+ {
+ public int SkillCD { get; }
+ public int DurationTime { get; } //技能持续时间
+ public object ActiveSkillLock { get; }
+ public bool IsBeingUsed { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/logic/Preparation/Utility/EnumType.cs b/logic/Preparation/Utility/EnumType.cs
index c082442..5247c50 100644
--- a/logic/Preparation/Utility/EnumType.cs
+++ b/logic/Preparation/Utility/EnumType.cs
@@ -20,8 +20,9 @@ namespace Preparation.Utility
IsStunned = 11,
IsTryingToAttack = 12,//指前摇
IsLockingTheDoor = 13,
- IsRummagingInTheChest = 14,
+ IsOpeningTheChest = 14,
IsClimbingThroughWindows = 15,
+ IsUsingSpecialSkill = 16,
}
public enum GameObjType
{
@@ -40,6 +41,7 @@ namespace Preparation.Utility
OutOfBoundBlock = 11, // 范围外
Window = 12,
Door = 13,
+ Chest = 14,
}
public enum ShapeType
{
@@ -55,7 +57,8 @@ namespace Preparation.Utility
FastBullet = 3, // 快速子弹
LineBullet = 4, // 直线子弹
FlyingKnife = 5, //飞刀
- CommonAttackOfGhost = 6
+ CommonAttackOfGhost = 6,
+ // Ram = 7,
}
public enum PropType // 道具类型
{
@@ -84,7 +87,7 @@ namespace Preparation.Utility
NuclearWeapon = 3,
SuperFast = 4,
UseKnife = 5,
- BeginToCharge = 6
+ CanBeginToCharge = 6
}
public enum PassiveSkillType
{
diff --git a/logic/Preparation/Utility/GameData.cs b/logic/Preparation/Utility/GameData.cs
index 3e0cc28..b1e5b2b 100644
--- a/logic/Preparation/Utility/GameData.cs
+++ b/logic/Preparation/Utility/GameData.cs
@@ -52,38 +52,28 @@ namespace Preparation.Utility
#endregion
#region 角色相关
- public const int characterRadius = numOfPosGridPerCell / 2; // 人物半径
- public const int basicApOfGhost = 1500000; // 攻击力
+ public const int characterRadius = numOfPosGridPerCell / 2 / 5 * 4; // 人物半径
+
public const int basicTreatSpeed = 100;
public const int basicFixSpeed = 100;
+ public const int basicTimeOfOpeningOrLocking = 3000;
+ public const int basicTimeOfClimbingThroughWindows = 870;
+
+ public const int basicHp = 3000000; // 初始血量
public const int basicMaxGamingAddiction = 60000;//基本完全沉迷时间
public const int BeginGamingAddiction = 10003;
public const int MidGamingAddiction = 30000;
public const int basicTreatmentDegree = 1500000;
public const int basicRescueDegree = 100000;
- public const int basicHp = 3000000; // 初始血量
- public const int basicCD = 3000; // 初始子弹冷却
- public const int basicCastTime = 500;//基本前摇时间
- public const int basicBackswing = 500;//基本后摇时间
- public const int basicRecoveryFromHit = 4300;//基本命中攻击恢复时长
- public const int basicBulletNum = 3; // 基本初始子弹量
- public const int MinAP = 0; // 最小攻击力
- public const int MaxAP = int.MaxValue; // 最大攻击力
- public const double basicRemoteAttackRange = 9000; // 基本远程攻击范围
- public const double basicAttackShortRange = 2700; // 基本近程攻击范围
- public const double basicBulletBombRange = 3000; // 基本子弹爆炸范围
+
public const int basicMoveSpeed = 1260; // 基本移动速度,单位:s-1
- public const int basicBulletMoveSpeed = 2700; // 基本子弹移动速度,单位:s-1
public const int characterMaxSpeed = 12000; // 最大速度
+ public const int basicBulletMoveSpeed = 2700; // 基本子弹移动速度,单位:s-1
+
public const double basicConcealment = 1.0;
public const int basicAlertnessRadius = 30700;
- public const int basicTimeOfOpeningOrLocking = 3000;
+ public const int maxNumOfPropInPropInventory = 3;
public const int addScoreWhenKillOneLevelPlayer = 30; // 击杀一级角色获得的加分
- public const int commonSkillCD = 30000; // 普通技能标准冷却时间
- public const int commonSkillTime = 10000; // 普通技能标准持续时间
- public const int bulletRadius = 200; // 默认子弹半径
- public const int reviveTime = 30000; // 复活时间
- public const int shieldTimeAtBirth = 3000; // 复活时的护盾时间
public static XY PosWhoDie = new XY(1, 1);
@@ -95,6 +85,32 @@ namespace Preparation.Utility
_ => false,
};
}
+ #endregion
+ #region 攻击与子弹相关
+ public const int basicApOfGhost = 1500000; // 捣蛋鬼攻击力
+ public const int MinAP = 0; // 最小攻击力
+ public const int MaxAP = int.MaxValue; // 最大攻击力
+
+ public const int basicCD = 3000; // 初始子弹冷却
+ public const int basicCastTime = 500;//基本前摇时间
+ public const int basicBackswing = 500;//基本后摇时间
+ public const int basicRecoveryFromHit = 4300;//基本命中攻击恢复时长
+
+ public const int bulletRadius = 200; // 默认子弹半径
+ public const int basicBulletNum = 3; // 基本初始子弹量
+ public const double basicRemoteAttackRange = 9000; // 基本远程攻击范围
+ public const double basicAttackShortRange = 2700; // 基本近程攻击范围
+ public const double basicBulletBombRange = 3000; // 基本子弹爆炸范围
+ #endregion
+ #region 技能相关
+ public const int commonSkillCD = 30000; // 普通技能标准冷却时间
+ public const int commonSkillTime = 10000; // 普通技能标准持续时间
+ ///
+ /// BeginToCharge
+ ///
+ public const int TimeOfGhostFainting = 7220;//=AP of Ram
+ public const int TimeOfStudentFainting = 2090;
+
#endregion
#region 道具相关
public const int MinPropTypeNum = 1;
@@ -108,8 +124,8 @@ namespace Preparation.Utility
#endregion
#region 物体相关
public const int degreeOfFixedGenerator = 10300000;
+ public const int maxNumOfPropInChest = 2;
#endregion
-
#region 游戏帧相关
public const long checkInterval = 50; // 检查位置标志、补充子弹的帧时长
#endregion
diff --git a/logic/Preparation/Utility/XY.cs b/logic/Preparation/Utility/XY.cs
index 8f4a29f..7fc87ae 100644
--- a/logic/Preparation/Utility/XY.cs
+++ b/logic/Preparation/Utility/XY.cs
@@ -17,6 +17,11 @@ namespace Preparation.Utility
this.x = (int)(length * Math.Cos(angle));
this.y = (int)(length * Math.Sin(angle));
}
+ public XY(XY Direction, double length)
+ {
+ this.x = (int)(length * Math.Cos(Direction.Angle()));
+ this.y = (int)(length * Math.Sin(Direction.Angle()));
+ }
public override string ToString()
{
return "(" + x.ToString() + "," + y.ToString() + ")";
diff --git a/logic/规则Logic.md b/logic/规则Logic.md
index ef62a11..aa881fb 100644
--- a/logic/规则Logic.md
+++ b/logic/规则Logic.md
@@ -9,7 +9,10 @@
## 游戏简介
- 1位监管者对抗4位求生者的非对称竞技模式
-- 略
+- [本届THUAI电子系赛道为以4名同学和1名捣蛋鬼的求学与阻挠展开的非对称竞技模式,同学需要完成足够的家庭作业和考试,相互督促以避免沉迷娱乐生活,利用道具地形躲避捣蛋鬼的各种干扰诱惑,完成学业;捣蛋鬼则要极力阻止。]
+- [我们的设计是一个非对称游戏,类似第五人格,分为学生、捣蛋鬼两个阵营。在游戏中,学生修完若干课程之后通过考试即可顺利毕业,捣蛋鬼试图干扰学生使其沉迷游戏,以致于无法修完规定课程,直至挂科、退学。]
+[对于选手来说,需要提前制定好学生的学习方案以抵御对方捣蛋鬼的干扰,类似地,也需要制定好捣蛋鬼的行动策略以影响对方学生的学习,也即每队至少要写好两份代码以执行不同阵营的不同策略。]
+[当一局比赛结束(场上的学生有且仅有两种状态:退学或毕业)时,分别记录双方总得分;之后双方换边进行下半场比赛。最终将每队的学生方、捣蛋鬼方的得分相加,比较总得分判断胜负。]
## 地图
- 地图为矩形区域,地图上的游戏对象坐标为(x, y),且x和y均为整数。x坐标轴正方向竖直向下,
@@ -91,16 +94,24 @@
IsStunned = 11,
IsTryingToAttack = 12,//指前摇
IsLockingTheDoor = 13,
- IsRummagingInTheChest = 14,
+ IsOpeningTheChest = 14,
IsClimbingThroughWindows = 15,
+ IsUsingSpecialSkill = 16,
}
~~~
+- 可执行指令的(不用给选手)
+ ~~~csharp
+ public bool Commandable() => (playerState!=PlayerStateType.IsDeceased&&playerState!=PlayerStateType.IsEscaped
+ &&playerState!=PlayerStateType.IsAddicted &&playerState!=PlayerStateType.IsStunned
+ &&playerState!=PlayerStateType.IsSwinging&&playerState!=PlayerStateType.IsTryingToAttack
+ &&playerState!=PlayerStateType.IsClimbingThroughWindows);
+ ~~~
- Bgm(字典)
- 得分
- ~~回血率/原始回血率~~
- 当前子弹类型
- 原始子弹类型
-- 持有道具 *(最多三个)(列表)*
+- 持有道具 (最多三个)(数组)
- 是否隐身
- 队伍ID
- 玩家ID
@@ -111,7 +122,7 @@
- 各个主动技能CD(字典)
- 警戒半径
- double 隐蔽度
-- *翻窗时间*
+- 翻窗时间
- 开锁门时间
### 学生:人物
@@ -210,7 +221,7 @@
3. 修理电机
4. 开锁门
5. 翻窗
-6. 翻找箱子
+6. 开启箱子
### 门
- *门分别属于三个教学区:三教,五教,六教*
@@ -227,10 +238,31 @@
- *翻越窗户是一种交互行为,执行时,实质是限定方向的减速运动*
### 箱子
-- *监管者和求生者都能与箱子交互,同一时刻就允许一人进行翻找*
+- *监管者和求生者都能与箱子交互,同一时刻只允许一人进行开启*
- *开启箱子有不同概率获得不同道具。*
-- *搜寻物品的基础持续时间为10秒。*
-- *未搜寻完成的箱子在下一次需要重新开始搜寻。*
+- *开启箱子的基础持续时间为10秒。*
+- *未开启完成的箱子在下一次需要重新开始开启。*
+- *箱子开启后其中道具才可以被观测和拿取*
+- [箱子道具不刷新]
+- [箱子不可被关闭]
+- [箱子内道具最多两个]
+
+### 道具
+- 每次玩家试图捡起道具时,需要确保道具栏有空位
+- indexing指道具栏数组下标从0开始
+- 扔道具
+ - Logic内实现
+ ~~~csharp
+ public void ThrowProp(long playerID, int indexing)
+ ~~~
+ - 对应下标出现空位,不会对数组进行重新排序
+- 使用道具
+ - Logic内实现
+ ~~~csharp
+ public void UseProp(long playerID,int indexing)
+ ~~~
+ - 对应下标出现空位,不会对数组进行重新排序
+
### 治疗
- 可行动的求生者可以对受伤的其他求生者进行治疗,治疗完成后会回复被治疗程度的血量。