Browse Source

Merge pull request #547 from shangfengh/new

refactor: 🚧 add tool, gadget,and item
tags/v0.1.0
Changli Tang GitHub 2 years ago
parent
commit
a8e22cf2aa
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 466 additions and 215 deletions
  1. +1
    -0
      docs/GameRules.md
  2. +1
    -1
      logic/GameClass/GameObj/Bullet/Bullet.cs
  3. +1
    -1
      logic/GameClass/GameObj/Character/Character.Student.cs
  4. +130
    -81
      logic/GameClass/GameObj/Character/Character.cs
  5. +1
    -1
      logic/GameClass/GameObj/Character/Team.cs
  6. +2
    -2
      logic/GameClass/GameObj/Map/Chest.cs
  7. +107
    -12
      logic/GameClass/GameObj/Map/Door.cs
  8. +40
    -12
      logic/GameClass/GameObj/Prop/Gadget.cs
  9. +6
    -6
      logic/GameClass/GameObj/Prop/Item.cs
  10. +4
    -4
      logic/GameClass/GameObj/Prop/PickedProp.cs
  11. +116
    -50
      logic/Gaming/ActionManager.cs
  12. +2
    -2
      logic/Gaming/CharacterManager.cs
  13. +16
    -7
      logic/Gaming/Game.cs
  14. +11
    -12
      logic/Gaming/PropManager.cs
  15. +3
    -1
      logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs
  16. +3
    -3
      logic/Preparation/Interface/ICharacter.cs
  17. +4
    -3
      logic/Preparation/Utility/EnumType.cs
  18. +2
    -2
      logic/Preparation/Utility/GameData.cs
  19. +2
    -1
      logic/Preparation/Utility/Transformation.cs
  20. +9
    -9
      logic/Server/CopyInfo.cs
  21. +2
    -2
      logic/Server/GameServer.cs
  22. +3
    -3
      logic/Server/RpcServices.cs

+ 1
- 0
docs/GameRules.md View File

@@ -316,6 +316,7 @@ $$


### 道具 ### 道具
- 使用钥匙相当于销毁 - 使用钥匙相当于销毁
- 可接受指令状态下能捡起或扔道具,在场上即可使用道具


### 交互 ### 交互
- 被唤醒或被勉励不属于交互状态,翻窗属于交互状态 - 被唤醒或被勉励不属于交互状态,翻窗属于交互状态


+ 1
- 1
logic/GameClass/GameObj/Bullet/Bullet.cs View File

@@ -35,7 +35,7 @@ namespace GameClass.GameObj
public override bool IgnoreCollideExecutor(IGameObj targetObj) public override bool IgnoreCollideExecutor(IGameObj targetObj)
{ {
if (targetObj == Parent) return true; if (targetObj == Parent) return true;
if (targetObj.Type == GameObjType.Consumables || targetObj.Type == GameObjType.Bullet)
if (targetObj.Type == GameObjType.Gadget || targetObj.Type == GameObjType.Bullet)
return true; return true;
return false; return false;
} }


+ 1
- 1
logic/GameClass/GameObj/Character/Character.Student.cs View File

@@ -141,7 +141,7 @@ namespace GameClass.GameObj
} }
} }
} }
public override void AddScore(int add)
public override void AddScore(long add)
{ {
if (parent == null) if (parent == null)
base.AddScore(add); base.AddScore(add);


+ 130
- 81
logic/GameClass/GameObj/Character/Character.cs View File

@@ -11,6 +11,10 @@ namespace GameClass.GameObj


private readonly ReaderWriterLockSlim hpReaderWriterLock = new(); private readonly ReaderWriterLockSlim hpReaderWriterLock = new();
public ReaderWriterLockSlim HPReadWriterLock => hpReaderWriterLock; public ReaderWriterLockSlim HPReadWriterLock => hpReaderWriterLock;
private readonly object vampireLock = new();
public object VampireLock => vampire;
private readonly object inventoryLock = new();
public object InventoryLock => inventoryLock;


#region 装弹、攻击相关的基本属性及方法 #region 装弹、攻击相关的基本属性及方法
/// <summary> /// <summary>
@@ -331,20 +335,12 @@ namespace GameClass.GameObj
{ {
get get
{ {
HPReadWriterLock.EnterReadLock();
try
{
lock (vampireLock)
return vampire; return vampire;
}
finally
{
HPReadWriterLock.ExitReadLock();
}
} }
set set
{ {
HPReadWriterLock.EnterWriteLock();
try
lock (vampireLock)
{ {
if (value > 1) if (value > 1)
vampire = 1; vampire = 1;
@@ -353,10 +349,6 @@ namespace GameClass.GameObj
else else
vampire = value; vampire = value;
} }
finally
{
HPReadWriterLock.ExitWriteLock();
}
} }
} }
public double OriVampire { get; protected set; } public double OriVampire { get; protected set; }
@@ -404,7 +396,8 @@ namespace GameClass.GameObj
{ {
lock (actionLock) lock (actionLock)
{ {
return (playerState == PlayerStateType.LockingOrOpeningTheDoor || playerState == PlayerStateType.Fixing || playerState == PlayerStateType.OpeningTheChest);
return (playerState == PlayerStateType.LockingTheDoor || playerState == PlayerStateType.OpeningTheDoor
|| playerState == PlayerStateType.Fixing || playerState == PlayerStateType.OpeningTheChest);
} }
} }
public bool NullOrMoving() public bool NullOrMoving()
@@ -475,41 +468,75 @@ namespace GameClass.GameObj
else return -1; else return -1;


case PlayerStateType.TryingToAttack: case PlayerStateType.TryingToAttack:
if (value != PlayerStateType.Moving && value != PlayerStateType.ClimbingThroughWindows)
if (value != PlayerStateType.Moving && value != PlayerStateType.ClimbingThroughWindows
&& value != PlayerStateType.LockingTheDoor && value != PlayerStateType.OpeningTheDoor)
return ChangePlayerState(value, gameObj); return ChangePlayerState(value, gameObj);
else return -1; else return -1;
case PlayerStateType.Stunned: case PlayerStateType.Stunned:
case PlayerStateType.Charmed: case PlayerStateType.Charmed:
if (value != PlayerStateType.Moving && value != PlayerStateType.ClimbingThroughWindows && value != PlayerStateType.Swinging)
if (value != PlayerStateType.Moving && value != PlayerStateType.ClimbingThroughWindows
&& value != PlayerStateType.LockingTheDoor && value != PlayerStateType.OpeningTheDoor
&& value != PlayerStateType.Swinging)
return ChangePlayerState(value, gameObj); return ChangePlayerState(value, gameObj);
else return -1; else return -1;
case PlayerStateType.Swinging: case PlayerStateType.Swinging:
if (value != PlayerStateType.Moving && value != PlayerStateType.ClimbingThroughWindows)
if (value != PlayerStateType.Moving && value != PlayerStateType.ClimbingThroughWindows
&& value != PlayerStateType.LockingTheDoor && value != PlayerStateType.OpeningTheDoor)
{ {
ThreadNum.Release();
return ChangePlayerState(value, gameObj);
try
{
return ChangePlayerState(value, gameObj);
}
finally
{
ThreadNum.Release();
}
} }
else return -1; else return -1;
case PlayerStateType.ClimbingThroughWindows: case PlayerStateType.ClimbingThroughWindows:
if (value != PlayerStateType.Moving)
if (value != PlayerStateType.Moving && value != PlayerStateType.LockingTheDoor && value != PlayerStateType.OpeningTheDoor)
{ {
Window window = (Window)WhatInteractingWith!; Window window = (Window)WhatInteractingWith!;
window.FinishClimbing();
if (window.Stage.x == 0)
ThreadNum.Release();
else ReSetPos(window.Stage);
return ChangePlayerState(value, gameObj);
try
{
window.FinishClimbing();
return ChangePlayerState(value, gameObj);
}
finally
{
if (window.Stage.x == 0)
ThreadNum.Release();
else ReSetPos(window.Stage);
}
} }
else return -1; else return -1;


case PlayerStateType.OpeningTheChest: case PlayerStateType.OpeningTheChest:
((Chest)WhatInteractingWith!).StopOpen();
((Chest)whatInteractingWith!).StopOpen();
return ChangePlayerState(value, gameObj); return ChangePlayerState(value, gameObj);
case PlayerStateType.OpeningTheDoorway: case PlayerStateType.OpeningTheDoorway:
Doorway doorway = (Doorway)WhatInteractingWith!;
Doorway doorway = (Doorway)whatInteractingWith!;
doorway.StopOpenning(); doorway.StopOpenning();
return ChangePlayerState(value, gameObj); return ChangePlayerState(value, gameObj);


case PlayerStateType.OpeningTheDoor:
Door door = (Door)whatInteractingWith!;
try
{
door.StopOpen();
ReleaseTool(door.DoorNum switch
{
3 => PropType.Key3,
5 => PropType.Key5,
_ => PropType.Key6,
}
);
return ChangePlayerState(value, gameObj);
}
finally
{
ThreadNum.Release();
}
default: default:
return ChangePlayerState(value, gameObj); return ChangePlayerState(value, gameObj);
} }
@@ -547,67 +574,52 @@ namespace GameClass.GameObj
} }
#endregion #endregion


private int score = 0;
public int Score
private long score = 0;
public long Score
{ {
get => score;
get => Interlocked.Read(ref score);
} }


/// <summary> /// <summary>
/// 加分 /// 加分
/// </summary> /// </summary>
/// <param name="add">增加量</param> /// <param name="add">增加量</param>
public virtual void AddScore(int add)
public virtual void AddScore(long add)
{ {
lock (gameObjLock)
{
score += add;
//Debugger.Output(this, " 's score has been added to: " + score.ToString());
}
Interlocked.Add(ref score, add);
//Debugger.Output(this, " 's score has been added to: " + score.ToString());
} }


/// <summary> /// <summary>
/// 角色所属队伍ID /// 角色所属队伍ID
/// </summary> /// </summary>
private int teamID = int.MaxValue;
public int TeamID
private long teamID = long.MaxValue;
public long TeamID
{ {
get => teamID;
set
{
lock (gameObjLock)
{
teamID = value;
Debugger.Output(this, " joins in the team: " + value.ToString());
}
}
get => Interlocked.Read(ref teamID);
set => Interlocked.Exchange(ref teamID, value);
} }
private int playerID = int.MaxValue;
public int PlayerID
private long playerID = long.MaxValue;
public long PlayerID
{ {
get => playerID;
set
{
lock (gameObjLock)
{
playerID = value;
}
}
get => Interlocked.Read(ref playerID);
set => Interlocked.Exchange(ref playerID, value);
} }


#region 道具和buff相关属性、方法 #region 道具和buff相关属性、方法
private Consumables[] propInventory = new Consumables[GameData.maxNumOfPropInPropInventory]
private Gadget[] propInventory = new Gadget[GameData.maxNumOfPropInPropInventory]
{new NullProp(), new NullProp(),new NullProp() }; {new NullProp(), new NullProp(),new NullProp() };
public Consumables[] PropInventory
public Gadget[] PropInventory
{ {
get => propInventory;
get
{
lock (inventoryLock)
return propInventory;
}
set set
{ {
lock (gameObjLock)
{
lock (inventoryLock)
propInventory = value; propInventory = value;
Debugger.Output(this, " prop becomes " + (PropInventory == null ? "null" : PropInventory.ToString()));
}
} }
} }


@@ -615,45 +627,81 @@ namespace GameClass.GameObj
/// 使用物品栏中的道具 /// 使用物品栏中的道具
/// </summary> /// </summary>
/// <returns>被使用的道具</returns> /// <returns>被使用的道具</returns>
public Consumables UseProp(int indexing)
public Gadget UseProp(int indexing)
{ {
if (indexing < 0 || indexing >= GameData.maxNumOfPropInPropInventory) if (indexing < 0 || indexing >= GameData.maxNumOfPropInPropInventory)
return new NullProp(); return new NullProp();
lock (gameObjLock)
lock (inventoryLock)
{ {
Consumables prop = propInventory[indexing];
Gadget prop = propInventory[indexing];
if (!prop.IsUsable()) return new NullProp();
PropInventory[indexing] = new NullProp(); PropInventory[indexing] = new NullProp();
return prop; return prop;
} }
} }


public Consumables UseProp(PropType propType)
public Gadget UseProp(PropType propType)
{ {
lock (gameObjLock)
if (propType == PropType.Null)
{ {
if (propType == PropType.Null)
lock (inventoryLock)
{ {
for (int indexing = 0; indexing < GameData.maxNumOfPropInPropInventory; ++indexing) for (int indexing = 0; indexing < GameData.maxNumOfPropInPropInventory; ++indexing)
{ {
if (PropInventory[indexing].GetPropType() != PropType.Null)
if (PropInventory[indexing].IsUsable())
{ {
Consumables prop = PropInventory[indexing];
Gadget prop = PropInventory[indexing];
PropInventory[indexing] = new NullProp(); PropInventory[indexing] = new NullProp();
return prop; return prop;
} }
} }
} }
else
}
else
{
lock (inventoryLock)
{
for (int indexing = 0; indexing < GameData.maxNumOfPropInPropInventory; ++indexing) for (int indexing = 0; indexing < GameData.maxNumOfPropInPropInventory; ++indexing)
{ {
if (PropInventory[indexing].GetPropType() == propType)
if (PropInventory[indexing].GetPropType() == propType && PropInventory[indexing].IsUsable())
{ {
Consumables prop = PropInventory[indexing];
Gadget prop = PropInventory[indexing];
PropInventory[indexing] = new NullProp(); PropInventory[indexing] = new NullProp();
return prop; return prop;
} }
} }
return new NullProp();
}
}
return new NullProp();
}

public bool UseTool(PropType propType)
{
lock (inventoryLock)
{
for (int indexing = 0; indexing < GameData.maxNumOfPropInPropInventory; ++indexing)
{
if (PropInventory[indexing].GetPropType() == propType && PropInventory[indexing].IsUsable())
{
return ((Tool)PropInventory[indexing]).IsUsed = true;
}
}
}
return false;
}

public void ReleaseTool(PropType propType)
{
lock (inventoryLock)
{
for (int indexing = 0; indexing < GameData.maxNumOfPropInPropInventory; ++indexing)
{
if (PropInventory[indexing].GetPropType() == propType && ((Tool)PropInventory[indexing]).IsUsed)
{
((Tool)PropInventory[indexing]).IsUsed = false;
break;
}
}
} }
} }


@@ -663,9 +711,10 @@ namespace GameClass.GameObj
public int IndexingOfAddProp() public int IndexingOfAddProp()
{ {
int indexing = 0; int indexing = 0;
for (; indexing < GameData.maxNumOfPropInPropInventory; ++indexing)
if (PropInventory[indexing].GetPropType() == PropType.Null)
break;
lock (inventoryLock)
for (; indexing < GameData.maxNumOfPropInPropInventory; ++indexing)
if (propInventory[indexing].GetPropType() == PropType.Null)
break;
return indexing; return indexing;
} }


@@ -787,7 +836,7 @@ namespace GameClass.GameObj
{ {
if (IsRemoved) if (IsRemoved)
return true; return true;
if (targetObj.Type == GameObjType.Consumables)
if (targetObj.Type == GameObjType.Gadget)
{ {
return true; return true;
} }


+ 1
- 1
logic/GameClass/GameObj/Character/Team.cs View File

@@ -17,7 +17,7 @@ namespace GameClass.GameObj
{ {
int score = 0; int score = 0;
foreach (var player in playerList) foreach (var player in playerList)
score += player.Score;
score += (int)player.Score;
return score; return score;
} }
} }


+ 2
- 2
logic/GameClass/GameObj/Map/Chest.cs View File

@@ -15,8 +15,8 @@ namespace GameClass.GameObj
public override bool IsRigid => true; public override bool IsRigid => true;
public override ShapeType Shape => ShapeType.Square; public override ShapeType Shape => ShapeType.Square;


private readonly Consumables[] propInChest = new Consumables[GameData.maxNumOfPropInChest] { new NullProp(), new NullProp() };
public Consumables[] PropInChest => propInChest;
private readonly Gadget[] propInChest = new Gadget[GameData.maxNumOfPropInChest] { new NullProp(), new NullProp() };
public Gadget[] PropInChest => propInChest;


private int openStartTime = 0; private int openStartTime = 0;
public int OpenStartTime => openStartTime; public int OpenStartTime => openStartTime;


+ 107
- 12
logic/GameClass/GameObj/Map/Door.cs View File

@@ -1,5 +1,7 @@
using Preparation.Interface; using Preparation.Interface;
using Preparation.Utility; using Preparation.Utility;
using System;
using System.Threading;


namespace GameClass.GameObj namespace GameClass.GameObj
{ {
@@ -32,30 +34,123 @@ namespace GameClass.GameObj
public override bool IsRigid => !isOpen; public override bool IsRigid => !isOpen;
public override ShapeType Shape => ShapeType.Square; public override ShapeType Shape => ShapeType.Square;


private Character? whoLockOrOpen = null;
public Character? WhoLockOrOpen
{
get
{
lock (gameObjLock)
return whoLockOrOpen;
}
}

private bool isOpen = true; private bool isOpen = true;
public bool IsOpen public bool IsOpen
{ {
get => isOpen;
set
get
{ {
lock (gameObjLock) lock (gameObjLock)
isOpen = value;
return isOpen;
} }
} }


private int openOrLockDegree = 0;
public int OpenOrLockDegree
private int lockDegree = 0;
public int LockDegree
{ {
get => openOrLockDegree;
get
{
lock (gameObjLock)
return lockDegree;
}
set set
{ {
if (value > 0)
lock (gameObjLock)
openOrLockDegree = (value > GameData.degreeOfLockingOrOpeningTheDoor) ? GameData.degreeOfLockingOrOpeningTheDoor : value;
else
lock (gameObjLock)
openOrLockDegree = 0;
value = (value > GameData.degreeOfLockingOrOpeningTheDoor) ? GameData.degreeOfLockingOrOpeningTheDoor : value;
lock (gameObjLock)
lockDegree = value;
}
}

private long openStartTime = 0;
public long OpenStartTime
{
get
{
lock (gameObjLock)
return openStartTime;
}
}

public bool TryOpen(Character character)
{
lock (gameObjLock)
{
if (isOpen) return false;
if (whoLockOrOpen != null) return false;
openStartTime = Environment.TickCount64;
whoLockOrOpen = character;
return true;
}
}
public void StopOpen()
{
lock (gameObjLock)
{
if (whoLockOrOpen != null)
{
if (Environment.TickCount64 - openStartTime >= GameData.degreeOfLockingOrOpeningTheDoor)
isOpen = true;
whoLockOrOpen = null;
}
}
}
public void FinishOpen()
{
lock (gameObjLock)
{
isOpen = true;
whoLockOrOpen = null;
}
}

public bool TryLock(Character character)
{
lock (gameObjLock)
{
if (!isOpen) return false;
if (whoLockOrOpen != null) return false;
lockDegree = 0;
whoLockOrOpen = character;
return true;
}
}
public void StopLock()
{
lock (gameObjLock)
{
if (lockDegree >= GameData.degreeOfLockingOrOpeningTheDoor)
isOpen = true;
whoLockOrOpen = null;
}
}
public void FinishLock()
{
lock (gameObjLock)
{
isOpen = false;
whoLockOrOpen = null;
}
}

public void ForceToOpen()
{
Character? character;
lock (gameObjLock)
{
character = whoLockOrOpen;
whoLockOrOpen = null;
isOpen = true;
} }
if (character != null) character.SetPlayerState();
} }
} }
} }

logic/GameClass/GameObj/Prop/Consumables.cs → logic/GameClass/GameObj/Prop/Gadget.cs View File

@@ -1,15 +1,16 @@
using Preparation.Interface; using Preparation.Interface;
using Preparation.Utility; using Preparation.Utility;
using System.Threading;


namespace GameClass.GameObj namespace GameClass.GameObj
{ {
public abstract class Consumables : ObjOfCharacter
public abstract class Gadget : ObjOfCharacter
{ {
public override bool IsRigid => true; public override bool IsRigid => true;


public override bool IgnoreCollideExecutor(IGameObj targetObj) public override bool IgnoreCollideExecutor(IGameObj targetObj)
{ {
if (targetObj.Type == GameObjType.Consumables || targetObj.Type == GameObjType.Bullet
if (targetObj.Type == GameObjType.Gadget || targetObj.Type == GameObjType.Bullet
|| targetObj.Type == GameObjType.Character || targetObj.Type == GameObjType.Chest) || targetObj.Type == GameObjType.Character || targetObj.Type == GameObjType.Chest)
return true; return true;
return false; return false;
@@ -17,21 +18,47 @@ namespace GameClass.GameObj


public override ShapeType Shape => ShapeType.Square; public override ShapeType Shape => ShapeType.Square;


public abstract bool IsUsable();
public abstract PropType GetPropType(); public abstract PropType GetPropType();


public Consumables(XY initPos, int radius = GameData.PropRadius) :
base(initPos, radius, GameObjType.Consumables)
public Gadget(XY initPos, int radius = GameData.PropRadius) :
base(initPos, radius, GameObjType.Gadget)
{ {
this.canMove = false; this.canMove = false;
this.MoveSpeed = GameData.PropMoveSpeed; this.MoveSpeed = GameData.PropMoveSpeed;
} }
} }

public abstract class Tool : Gadget
{
private bool isUsed = false;
public bool IsUsed
{
get
{
lock (gameObjLock)
return isUsed;
}
set
{
lock (gameObjLock)
{
isUsed = value;
}
}
}
public override bool IsUsable() => !IsUsed;
public Tool(XY initPos) : base(initPos) { }
}
public abstract class Consumables : Gadget
{
public override bool IsUsable() => true;
public Consumables(XY initPos) : base(initPos) { }
}


///// <summary> ///// <summary>
///// 坑人地雷 ///// 坑人地雷
///// </summary> ///// </summary>
// public abstract class DebuffMine : Consumables
// public abstract class DebuffMine : Gadget
//{ //{
// public DebuffMine(XYPosition initPos) : base(initPos) { } // public DebuffMine(XYPosition initPos) : base(initPos) { }
// } // }
@@ -86,35 +113,36 @@ namespace GameClass.GameObj
} }
public override PropType GetPropType() => PropType.ShieldOrSpear; public override PropType GetPropType() => PropType.ShieldOrSpear;
} }
public sealed class Key3 : Consumables
#endregion
public sealed class Key3 : Tool
{ {
public Key3(XY initPos) : base(initPos) public Key3(XY initPos) : base(initPos)
{ {
} }
public override PropType GetPropType() => PropType.Key3; public override PropType GetPropType() => PropType.Key3;
} }
public sealed class Key5 : Consumables
public sealed class Key5 : Tool
{ {
public Key5(XY initPos) : base(initPos) public Key5(XY initPos) : base(initPos)
{ {
} }
public override PropType GetPropType() => PropType.Key5; public override PropType GetPropType() => PropType.Key5;
} }
public sealed class Key6 : Consumables
public sealed class Key6 : Tool
{ {
public Key6(XY initPos) : base(initPos) public Key6(XY initPos) : base(initPos)
{ {
} }
public override PropType GetPropType() => PropType.Key6; public override PropType GetPropType() => PropType.Key6;
} }
public sealed class NullProp : Consumables
public sealed class NullProp : Gadget
{ {
public override bool IsUsable() => false;
public NullProp() : base(new XY(1, 1)) public NullProp() : base(new XY(1, 1))
{ {
} }
public override PropType GetPropType() => PropType.Null; public override PropType GetPropType() => PropType.Null;
} }
#endregion
// #region 所有坑人地雷 // #region 所有坑人地雷
///// <summary> ///// <summary>
///// 减速 ///// 减速
@@ -143,7 +171,7 @@ namespace GameClass.GameObj
// #endregion // #endregion
public static class PropFactory public static class PropFactory
{ {
public static Consumables GetConsumables(PropType propType, XY pos)
public static Gadget GetConsumables(PropType propType, XY pos)
{ {
switch (propType) switch (propType)
{ {

logic/GameClass/GameObj/Prop/Prop.cs → logic/GameClass/GameObj/Prop/Item.cs View File

@@ -3,7 +3,7 @@ using Preparation.Utility;


namespace GameClass.GameObj namespace GameClass.GameObj
{ {
public abstract class Prop : ObjOfCharacter
public abstract class Item : ObjOfCharacter
{ {
public override bool IsRigid => true; public override bool IsRigid => true;


@@ -13,11 +13,11 @@ namespace GameClass.GameObj


public abstract PropType GetPropType(); public abstract PropType GetPropType();


public Prop(XY initPos, int radius = GameData.PropRadius) :
base(initPos, radius, GameObjType.Prop)
public Item(XY initPos, int radius = GameData.PropRadius) :
base(initPos, radius, GameObjType.Item)
{ {
this.canMove = false; this.canMove = false;
this.MoveSpeed = GameData.PropMoveSpeed;
this.MoveSpeed = 0;
} }
} }


@@ -25,12 +25,12 @@ namespace GameClass.GameObj
///// <summary> ///// <summary>
///// 坑人地雷 ///// 坑人地雷
///// </summary> ///// </summary>
// public abstract class DebuffMine : Consumables
// public abstract class DebuffMine : Gadget
//{ //{
// public DebuffMine(XYPosition initPos) : base(initPos) { } // public DebuffMine(XYPosition initPos) : base(initPos) { }
// } // }


public sealed class CraftingBench : Prop
public sealed class CraftingBench : Item
{ {
public CraftingBench(XY initPos) : public CraftingBench(XY initPos) :
base(initPos) base(initPos)

+ 4
- 4
logic/GameClass/GameObj/Prop/PickedProp.cs View File

@@ -4,14 +4,14 @@ namespace GameClass.GameObj
{ {
// 为方便界面组做道具拾起特效,现引入“被捡起的道具”,在每帧发送给界面组 // 为方便界面组做道具拾起特效,现引入“被捡起的道具”,在每帧发送给界面组
/* /*
public class Prop : Immovable
public class Item : Immovable
{ {
public override ShapeType Shape => ShapeType.Circle; public override ShapeType Shape => ShapeType.Circle;
public override bool IsRigid => false; public override bool IsRigid => false;
public long MappingID { get; } public long MappingID { get; }
public readonly Consumables propHasPicked;
public Prop(Consumables prop) :
base(prop.Position, prop.Radius, GameObjType.Prop)
public readonly Gadget propHasPicked;
public Item(Gadget prop) :
base(prop.Position, prop.Radius, GameObjType.Item)
{ {
this.propHasPicked = prop; this.propHasPicked = prop;
this.MappingID = prop.ID; this.MappingID = prop.ID;


+ 116
- 50
logic/Gaming/ActionManager.cs View File

@@ -303,7 +303,7 @@ namespace Gaming
player.SetPlayerStateNaturally(); player.SetPlayerStateNaturally();
for (int i = 0; i < GameData.maxNumOfPropInChest; ++i) for (int i = 0; i < GameData.maxNumOfPropInChest; ++i)
{ {
Consumables prop = chestToOpen.PropInChest[i];
Gadget prop = chestToOpen.PropInChest[i];
chestToOpen.PropInChest[i] = new NullProp(); chestToOpen.PropInChest[i] = new NullProp();
prop.ReSetPos(player.Position); prop.ReSetPos(player.Position);
gameMap.Add(prop); gameMap.Add(prop);
@@ -389,67 +389,133 @@ namespace Gaming


return true; return true;
} }
public bool LockOrOpenDoor(Character player)
public bool LockDoor(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); Door? doorToLock = (Door?)gameMap.OneForInteract(player.Position, GameObjType.Door);
if (doorToLock == null) return false; if (doorToLock == null) return false;
bool flag = false;
foreach (Consumables prop in player.PropInventory)

PropType propType = doorToLock.DoorNum switch
{
3 => PropType.Key3,
5 => PropType.Key5,
_ => PropType.Key6,
};

if (!player.UseTool(propType)) return false;

long stateNum = player.SetPlayerState(PlayerStateType.LockingTheDoor, doorToLock);
if (stateNum == -1)
{ {
switch (prop.GetPropType())
player.ReleaseTool(propType);
return false;
}

new Thread
(
() =>
{ {
case PropType.Key3:
if (doorToLock.DoorNum == 3)
flag = true;
break;
case PropType.Key5:
if (doorToLock.DoorNum == 5)
flag = true;
break;
case PropType.Key6:
if (doorToLock.DoorNum == 6)
flag = true;
break;
default:
break;
player.ThreadNum.WaitOne();
if (stateNum != player.StateNum)
{
player.ReleaseTool(propType);
player.ThreadNum.Release();
}
else
{
if (!doorToLock.TryLock(player))
{
player.ReleaseTool(propType);
player.SetPlayerState();
player.ThreadNum.Release();
}
else
{
Thread.Sleep(GameData.checkInterval);
new FrameRateTaskExecutor<int>(
loopCondition: () => stateNum == player.StateNum && gameMap.Timer.IsGaming && doorToLock.LockDegree < GameData.degreeOfLockingOrOpeningTheDoor,
loopToDo: () =>
{
if ((gameMap.PartInTheSameCell(doorToLock.Position, GameObjType.Character)) != null)
return false;
doorToLock.LockDegree += GameData.checkInterval * player.SpeedOfOpeningOrLocking;
return true;
},
timeInterval: GameData.checkInterval,
finallyReturn: () => 0
)
.Start();
doorToLock.StopLock();
if (stateNum == player.StateNum) player.SetPlayerState();
player.ReleaseTool(propType);
player.ThreadNum.Release();
}
}
} }
if (flag) break;
}
if (!flag) return false;
)
{ IsBackground = true }.Start();


if (doorToLock.OpenOrLockDegree > 0 || gameMap.PartInTheSameCell(doorToLock.Position, GameObjType.Character) != null)
return false;
if (!(player.Commandable()) || player.PlayerState == PlayerStateType.LockingOrOpeningTheDoor)
return true;
}

public bool OpenDoor(Character player)
{
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,
};

if (!player.UseTool(propType)) return false;

long stateNum = player.SetPlayerState(PlayerStateType.OpeningTheDoor, doorToLock);
if (stateNum == -1)
{
player.ReleaseTool(propType);
return false; return false;
}


player.SetPlayerState(PlayerStateType.LockingOrOpeningTheDoor);
long threadNum = player.StateNum;
new Thread new Thread
(
() =>
{
new FrameRateTaskExecutor<int>(
loopCondition: () => flag && threadNum == player.StateNum && gameMap.Timer.IsGaming && doorToLock.OpenOrLockDegree < GameData.degreeOfLockingOrOpeningTheDoor,
loopToDo: () =>
{
flag = ((gameMap.PartInTheSameCell(doorToLock.Position, GameObjType.Character)) == null);
doorToLock.OpenOrLockDegree += GameData.frameDuration * player.SpeedOfOpeningOrLocking;
},
timeInterval: GameData.frameDuration,
finallyReturn: () => 0
)
.Start();
if (doorToLock.OpenOrLockDegree >= GameData.degreeOfLockingOrOpeningTheDoor)
{
doorToLock.IsOpen = (!doorToLock.IsOpen);
}
if (threadNum == player.StateNum)
player.SetPlayerState();
doorToLock.OpenOrLockDegree = 0;
}
(
() =>
{
player.ThreadNum.WaitOne();
if (stateNum != player.StateNum)
{
player.ReleaseTool(propType);
player.ThreadNum.Release();
}
else
{
if (!doorToLock.TryOpen(player))
{
player.ReleaseTool(propType);
player.SetPlayerState();
player.ThreadNum.Release();
}
else
{
Thread.Sleep(GameData.degreeOfLockingOrOpeningTheDoor / player.SpeedOfOpeningOrLocking);


)
lock (player.ActionLock)
{
if (stateNum == player.StateNum)
{
player.SetPlayerState();
doorToLock.StopOpen();
player.ReleaseTool(propType);
player.ThreadNum.Release();
}
}
}
}
}
)
{ IsBackground = true }.Start(); { IsBackground = true }.Start();


return true; return true;


+ 2
- 2
logic/Gaming/CharacterManager.cs View File

@@ -17,7 +17,7 @@ namespace Gaming
this.gameMap = gameMap; this.gameMap = gameMap;
} }


public Character? AddPlayer(XY pos, int teamID, int playerID, CharacterType characterType, Character? parent = null)
public Character? AddPlayer(XY pos, long teamID, long playerID, CharacterType characterType, Character? parent = null)
{ {
Character newPlayer; Character newPlayer;


@@ -370,7 +370,7 @@ namespace Gaming


for (int i = 0; i < GameData.maxNumOfPropInPropInventory; i++) for (int i = 0; i < GameData.maxNumOfPropInPropInventory; i++)
{ {
Consumables? prop = player.UseProp(i);
Gadget? prop = player.UseProp(i);
if (prop != null) if (prop != null)
{ {
prop.ReSetPos(player.Position); prop.ReSetPos(player.Position);


+ 16
- 7
logic/Gaming/Game.cs View File

@@ -2,10 +2,8 @@
using System.Threading; using System.Threading;
using System.Collections.Generic; using System.Collections.Generic;
using Preparation.Utility; using Preparation.Utility;
using Timothy.FrameRateTask;
using Preparation.Interface; using Preparation.Interface;
using GameClass.GameObj; using GameClass.GameObj;
using System.Numerics;


namespace Gaming namespace Gaming
{ {
@@ -14,10 +12,10 @@ namespace Gaming
public struct PlayerInitInfo public struct PlayerInitInfo
{ {
public uint birthPointIndex; public uint birthPointIndex;
public int teamID;
public int playerID;
public long teamID;
public long playerID;
public CharacterType characterType; public CharacterType characterType;
public PlayerInitInfo(uint birthPointIndex, int teamID, int playerID, CharacterType characterType)
public PlayerInitInfo(uint birthPointIndex, long teamID, long playerID, CharacterType characterType)
{ {
this.birthPointIndex = birthPointIndex; this.birthPointIndex = birthPointIndex;
this.teamID = teamID; this.teamID = teamID;
@@ -199,14 +197,25 @@ namespace Gaming
} }
return false; return false;
} }
public bool LockOrOpenDoor(long playerID)
public bool LockDoor(long playerID)
{ {
if (!gameMap.Timer.IsGaming) if (!gameMap.Timer.IsGaming)
return false; return false;
Character? player = gameMap.FindPlayerToAction(playerID); Character? player = gameMap.FindPlayerToAction(playerID);
if (player != null) if (player != null)
{ {
return actionManager.LockOrOpenDoor(player);
return actionManager.LockDoor(player);
}
return false;
}
public bool OpenDoor(long playerID)
{
if (!gameMap.Timer.IsGaming)
return false;
Character? player = gameMap.FindPlayerToAction(playerID);
if (player != null)
{
return actionManager.OpenDoor(player);
} }
return false; return false;
} }


+ 11
- 12
logic/Gaming/PropManager.cs View File

@@ -21,9 +21,9 @@ namespace Gaming


public void UseProp(Character player, PropType propType) public void UseProp(Character player, PropType propType)
{ {
if (player.IsRemoved || player.CharacterType == CharacterType.Robot)
if (player.CharacterType == CharacterType.Robot || player.IsRemoved)
return; return;
Consumables prop = player.UseProp(propType);
Gadget prop = player.UseProp(propType);
switch (prop.GetPropType()) switch (prop.GetPropType())
{ {
case PropType.ShieldOrSpear: case PropType.ShieldOrSpear:
@@ -73,23 +73,22 @@ namespace Gaming
/// <returns></returns> /// <returns></returns>
public bool PickProp(Character player, PropType propType = PropType.Null) public bool PickProp(Character player, PropType propType = PropType.Null)
{ {
if (player.IsRemoved)
return false;
if (!player.Commandable()) return false;
int indexing = player.IndexingOfAddProp(); int indexing = player.IndexingOfAddProp();
if (indexing == GameData.maxNumOfPropInPropInventory) if (indexing == GameData.maxNumOfPropInPropInventory)
return false; return false;


Consumables pickProp = new NullProp();
Gadget pickProp = new NullProp();
if (propType == PropType.Null) // 自动检查有无道具可捡 if (propType == PropType.Null) // 自动检查有无道具可捡
{ {
pickProp = player.PropInventory[indexing] = ((Consumables?)gameMap.OneInTheSameCell(player.Position, GameObjType.Consumables)) ?? new NullProp();
pickProp = player.PropInventory[indexing] = ((Gadget?)gameMap.OneInTheSameCell(player.Position, GameObjType.Gadget)) ?? new NullProp();
} }
else else
{ {
gameMap.GameObjLockDict[GameObjType.Consumables].EnterReadLock();
gameMap.GameObjLockDict[GameObjType.Gadget].EnterReadLock();
try try
{ {
foreach (Consumables prop in gameMap.GameObjDict[GameObjType.Consumables])
foreach (Gadget prop in gameMap.GameObjDict[GameObjType.Gadget])
{ {
if (prop.GetPropType() == propType) if (prop.GetPropType() == propType)
{ {
@@ -102,14 +101,14 @@ namespace Gaming
} }
finally finally
{ {
gameMap.GameObjLockDict[GameObjType.Consumables].ExitReadLock();
gameMap.GameObjLockDict[GameObjType.Gadget].ExitReadLock();
} }
} }


if (pickProp.GetPropType() != PropType.Null) if (pickProp.GetPropType() != PropType.Null)
{ {
gameMap.Remove(pickProp); gameMap.Remove(pickProp);
//gameMap.Add(new Prop(pickProp));
//gameMap.Add(new Item(pickProp));
return true; return true;
} }
else else
@@ -120,7 +119,7 @@ namespace Gaming
{ {
if (!gameMap.Timer.IsGaming || player.IsRemoved) if (!gameMap.Timer.IsGaming || player.IsRemoved)
return; return;
Consumables prop = player.UseProp(propType);
Gadget prop = player.UseProp(propType);
if (prop.GetPropType() == PropType.Null) if (prop.GetPropType() == PropType.Null)
return; return;


@@ -128,7 +127,7 @@ namespace Gaming
gameMap.Add(prop); gameMap.Add(prop);
} }


private static Consumables ProduceOnePropNotKey(Random r, XY Pos)
private static Gadget ProduceOnePropNotKey(Random r, XY Pos)
{ {
return PropFactory.GetConsumables((PropType)r.Next(GameData.numOfTeachingBuilding + 1, GameData.numOfPropSpecies + 1), Pos); return PropFactory.GetConsumables((PropType)r.Next(GameData.numOfTeachingBuilding + 1, GameData.numOfPropSpecies + 1), Pos);
} }


+ 3
- 1
logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs View File

@@ -216,7 +216,9 @@ namespace Gaming
{ {
if (character.IsGhost() && if (character.IsGhost() &&
(character.PlayerState == PlayerStateType.TryingToAttack || character.PlayerState == PlayerStateType.Swinging (character.PlayerState == PlayerStateType.TryingToAttack || character.PlayerState == PlayerStateType.Swinging
|| character.PlayerState == PlayerStateType.UsingSkill || character.PlayerState == PlayerStateType.LockingOrOpeningTheDoor || character.PlayerState == PlayerStateType.ClimbingThroughWindows)
|| character.PlayerState == PlayerStateType.UsingSkill
|| character.PlayerState == PlayerStateType.LockingTheDoor || character.PlayerState == PlayerStateType.OpeningTheDoor
|| character.PlayerState == PlayerStateType.ClimbingThroughWindows)
&& gameMap.CanSee(player, character)) && gameMap.CanSee(player, character))
{ {
if (characterManager.BeStunned(character, GameData.timeOfGhostStunnedWhenPunish + GameData.factorOfTimeStunnedWhenPunish * (player.MaxHp - player.HP)) > 0) if (characterManager.BeStunned(character, GameData.timeOfGhostStunnedWhenPunish + GameData.factorOfTimeStunnedWhenPunish * (player.MaxHp - player.HP)) > 0)


+ 3
- 3
logic/Preparation/Interface/ICharacter.cs View File

@@ -5,10 +5,10 @@ namespace Preparation.Interface
{ {
public interface ICharacter : IGameObj public interface ICharacter : IGameObj
{ {
public int TeamID { get; }
public long TeamID { get; }
public int HP { get; set; } public int HP { get; set; }
public int Score { get; }
public void AddScore(int add);
public long Score { get; }
public void AddScore(long add);
public double Vampire { get; } public double Vampire { get; }
public PlayerStateType PlayerState { get; } public PlayerStateType PlayerState { get; }
public BulletType BulletOfPlayer { get; set; } public BulletType BulletOfPlayer { get; set; }


+ 4
- 3
logic/Preparation/Utility/EnumType.cs View File

@@ -19,19 +19,20 @@ namespace Preparation.Utility
Rescued = 10, Rescued = 10,
Stunned = 11, Stunned = 11,
TryingToAttack = 12,//指前摇 TryingToAttack = 12,//指前摇
LockingOrOpeningTheDoor = 13,
LockingTheDoor = 13,
OpeningTheChest = 14, OpeningTheChest = 14,
ClimbingThroughWindows = 15, ClimbingThroughWindows = 15,
UsingSkill = 16, UsingSkill = 16,
OpeningTheDoorway = 17, OpeningTheDoorway = 17,
Charmed = 18, Charmed = 18,
OpeningTheDoor = 19,
} }
public enum GameObjType public enum GameObjType
{ {
Null = 0, Null = 0,
Character = 1, Character = 1,
Consumables = 2,
Prop = 3,
Gadget = 2,
Item = 3,
Bullet = 4, Bullet = 4,
BombedBullet = 5, BombedBullet = 5,




+ 2
- 2
logic/Preparation/Utility/GameData.cs View File

@@ -45,8 +45,8 @@ namespace Preparation.Utility
{ {
return gameObjType != GameObjType.Null && gameObjType != GameObjType.Grass return gameObjType != GameObjType.Null && gameObjType != GameObjType.Grass
&& gameObjType != GameObjType.OutOfBoundBlock && gameObjType != GameObjType.Window && gameObjType != GameObjType.OutOfBoundBlock && gameObjType != GameObjType.Window
&& gameObjType != GameObjType.Bullet&&gameObjType != GameObjType.Consumables
&&gameObjType != GameObjType.Prop&&gameObjType != GameObjType.BombedBullet
&& gameObjType != GameObjType.Bullet&&gameObjType != GameObjType.Gadget
&&gameObjType != GameObjType.Item&&gameObjType != GameObjType.BombedBullet
&&gameObjType != GameObjType.EmergencyExit&&gameObjType != GameObjType.Doorway; &&gameObjType != GameObjType.EmergencyExit&&gameObjType != GameObjType.Doorway;
}*/ }*/




+ 2
- 1
logic/Preparation/Utility/Transformation.cs View File

@@ -107,7 +107,8 @@ namespace Preparation.Utility
return PlayerState.Graduated; return PlayerState.Graduated;
case Preparation.Utility.PlayerStateType.Fixing: case Preparation.Utility.PlayerStateType.Fixing:
return PlayerState.Learning; return PlayerState.Learning;
case Preparation.Utility.PlayerStateType.LockingOrOpeningTheDoor:
case Preparation.Utility.PlayerStateType.LockingTheDoor:
case PlayerStateType.OpeningTheDoor:
return PlayerState.Locking; return PlayerState.Locking;
case Preparation.Utility.PlayerStateType.OpeningTheChest: case Preparation.Utility.PlayerStateType.OpeningTheChest:
return PlayerState.OpeningAChest; return PlayerState.OpeningAChest;


+ 9
- 9
logic/Server/CopyInfo.cs View File

@@ -33,10 +33,10 @@ namespace Server
else return null; else return null;
case Preparation.Utility.GameObjType.Door: case Preparation.Utility.GameObjType.Door:
return Door((Door)gameObj); return Door((Door)gameObj);
case GameObjType.Prop:
return Prop((Prop)gameObj);
case Preparation.Utility.GameObjType.Consumables:
return Prop((Consumables)gameObj);
case GameObjType.Item:
return Prop((Item)gameObj);
case Preparation.Utility.GameObjType.Gadget:
return Prop((Gadget)gameObj);
default: return null; default: return null;
} }
} }
@@ -68,7 +68,7 @@ namespace Server
ViewRange = player.ViewRange, ViewRange = player.ViewRange,
Radius = player.Radius, Radius = player.Radius,
DangerAlert = (player.BgmDictionary.ContainsKey(BgmType.GhostIsComing)) ? player.BgmDictionary[BgmType.GhostIsComing] : 0, DangerAlert = (player.BgmDictionary.ContainsKey(BgmType.GhostIsComing)) ? player.BgmDictionary[BgmType.GhostIsComing] : 0,
Score = player.Score,
Score = (int)player.Score,
TreatProgress = player.DegreeOfTreatment, TreatProgress = player.DegreeOfTreatment,
RescueProgress = player.TimeOfRescue, RescueProgress = player.TimeOfRescue,


@@ -110,7 +110,7 @@ namespace Server


TrickerType = Transformation.ToTrickerType(player.CharacterType), TrickerType = Transformation.ToTrickerType(player.CharacterType),
Guid = player.ID, Guid = player.ID,
Score = player.Score,
Score = (int)player.Score,
PlayerId = player.PlayerID, PlayerId = player.PlayerID,
ViewRange = player.ViewRange, ViewRange = player.ViewRange,
Radius = player.Radius, Radius = player.Radius,
@@ -157,7 +157,7 @@ namespace Server
return msg; return msg;
} }


private static MessageOfObj Prop(Consumables prop)
private static MessageOfObj Prop(Gadget prop)
{ {
MessageOfObj msg = new() MessageOfObj msg = new()
{ {
@@ -173,7 +173,7 @@ namespace Server
return msg; return msg;
} }


private static MessageOfObj Prop(Prop prop)
private static MessageOfObj Prop(Item prop)
{ {
MessageOfObj msg = new() MessageOfObj msg = new()
{ {
@@ -256,7 +256,7 @@ namespace Server
{ {
X = door.Position.x, X = door.Position.x,
Y = door.Position.y, Y = door.Position.y,
Progress = door.OpenOrLockDegree,
Progress = door.LockDegree,
IsOpen = door.IsOpen IsOpen = door.IsOpen
} }
}; };


+ 2
- 2
logic/Server/GameServer.cs View File

@@ -196,8 +196,8 @@ namespace Server
{ {
foreach (Character character in game.GameMap.GameObjDict[GameObjType.Character]) foreach (Character character in game.GameMap.GameObjDict[GameObjType.Character])
{ {
if (!character.IsGhost()) score[0] += character.Score;
else score[1] += character.Score;
if (!character.IsGhost()) score[0] += (int)character.Score;
else score[1] += (int)character.Score;
} }


} }


+ 3
- 3
logic/Server/RpcServices.cs View File

@@ -121,7 +121,7 @@ namespace Server


lock (addPlayerLock) lock (addPlayerLock)
{ {
Game.PlayerInitInfo playerInitInfo = new(GetBirthPointIdx(request.PlayerId), PlayerTypeToTeamID(request.PlayerType), (int)request.PlayerId, characterType);
Game.PlayerInitInfo playerInitInfo = new(GetBirthPointIdx(request.PlayerId), PlayerTypeToTeamID(request.PlayerType), request.PlayerId, characterType);
long newPlayerID = game.AddPlayer(playerInitInfo); long newPlayerID = game.AddPlayer(playerInitInfo);
if (newPlayerID == GameObj.invalidID) if (newPlayerID == GameObj.invalidID)
return; return;
@@ -471,7 +471,7 @@ namespace Server
return Task.FromResult(boolRes); return Task.FromResult(boolRes);
} }
var gameID = communicationToGameID[request.PlayerId]; var gameID = communicationToGameID[request.PlayerId];
boolRes.ActSuccess = game.LockOrOpenDoor(gameID);
boolRes.ActSuccess = game.OpenDoor(gameID);
return Task.FromResult(boolRes); return Task.FromResult(boolRes);
} }


@@ -487,7 +487,7 @@ namespace Server
return Task.FromResult(boolRes); return Task.FromResult(boolRes);
} }
var gameID = communicationToGameID[request.PlayerId]; var gameID = communicationToGameID[request.PlayerId];
boolRes.ActSuccess = game.LockOrOpenDoor(gameID);
boolRes.ActSuccess = game.LockDoor(gameID);
return Task.FromResult(boolRes); return Task.FromResult(boolRes);
} }




Loading…
Cancel
Save