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)
{
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 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)
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();
public ReaderWriterLockSlim HPReadWriterLock => hpReaderWriterLock;
private readonly object vampireLock = new();
public object VampireLock => vampire;
private readonly object inventoryLock = new();
public object InventoryLock => inventoryLock;

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

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);
else return -1;
case PlayerStateType.Stunned:
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);
else return -1;
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;
case PlayerStateType.ClimbingThroughWindows:
if (value != PlayerStateType.Moving)
if (value != PlayerStateType.Moving && value != PlayerStateType.LockingTheDoor && value != PlayerStateType.OpeningTheDoor)
{
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;

case PlayerStateType.OpeningTheChest:
((Chest)WhatInteractingWith!).StopOpen();
((Chest)whatInteractingWith!).StopOpen();
return ChangePlayerState(value, gameObj);
case PlayerStateType.OpeningTheDoorway:
Doorway doorway = (Doorway)WhatInteractingWith!;
Doorway doorway = (Doorway)whatInteractingWith!;
doorway.StopOpenning();
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:
return ChangePlayerState(value, gameObj);
}
@@ -547,67 +574,52 @@ namespace GameClass.GameObj
}
#endregion

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

/// <summary>
/// 加分
/// </summary>
/// <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>
/// 角色所属队伍ID
/// </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相关属性、方法
private Consumables[] propInventory = new Consumables[GameData.maxNumOfPropInPropInventory]
private Gadget[] propInventory = new Gadget[GameData.maxNumOfPropInPropInventory]
{new NullProp(), new NullProp(),new NullProp() };
public Consumables[] PropInventory
public Gadget[] PropInventory
{
get => propInventory;
get
{
lock (inventoryLock)
return propInventory;
}
set
{
lock (gameObjLock)
{
lock (inventoryLock)
propInventory = value;
Debugger.Output(this, " prop becomes " + (PropInventory == null ? "null" : PropInventory.ToString()));
}
}
}

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

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


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

@@ -17,7 +17,7 @@ namespace GameClass.GameObj
{
int score = 0;
foreach (var player in playerList)
score += player.Score;
score += (int)player.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 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;
public int OpenStartTime => openStartTime;


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

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

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

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

private bool isOpen = true;
public bool IsOpen
{
get => isOpen;
set
get
{
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
{
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.Utility;
using System.Threading;

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

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)
return true;
return false;
@@ -17,21 +18,47 @@ namespace GameClass.GameObj

public override ShapeType Shape => ShapeType.Square;

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

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

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.MoveSpeed = GameData.PropMoveSpeed;
this.MoveSpeed = 0;
}
}

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

public sealed class CraftingBench : Prop
public sealed class CraftingBench : Item
{
public CraftingBench(XY 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 bool IsRigid => false;
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.MappingID = prop.ID;


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

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

return true;
}
public bool LockOrOpenDoor(Character player)
public bool LockDoor(Character player)
{
if (player.CharacterType == CharacterType.Robot) return false;
Door? doorToLock = (Door?)gameMap.OneForInteract(player.Position, GameObjType.Door);
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;
}

player.SetPlayerState(PlayerStateType.LockingOrOpeningTheDoor);
long threadNum = player.StateNum;
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();

return true;


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

@@ -17,7 +17,7 @@ namespace Gaming
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;

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

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


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

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

namespace Gaming
{
@@ -14,10 +12,10 @@ namespace Gaming
public struct PlayerInitInfo
{
public uint birthPointIndex;
public int teamID;
public int playerID;
public long teamID;
public long playerID;
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.teamID = teamID;
@@ -199,14 +197,25 @@ namespace Gaming
}
return false;
}
public bool LockOrOpenDoor(long playerID)
public bool LockDoor(long playerID)
{
if (!gameMap.Timer.IsGaming)
return false;
Character? player = gameMap.FindPlayerToAction(playerID);
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;
}


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

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

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

Consumables pickProp = new NullProp();
Gadget pickProp = new NullProp();
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
{
gameMap.GameObjLockDict[GameObjType.Consumables].EnterReadLock();
gameMap.GameObjLockDict[GameObjType.Gadget].EnterReadLock();
try
{
foreach (Consumables prop in gameMap.GameObjDict[GameObjType.Consumables])
foreach (Gadget prop in gameMap.GameObjDict[GameObjType.Gadget])
{
if (prop.GetPropType() == propType)
{
@@ -102,14 +101,14 @@ namespace Gaming
}
finally
{
gameMap.GameObjLockDict[GameObjType.Consumables].ExitReadLock();
gameMap.GameObjLockDict[GameObjType.Gadget].ExitReadLock();
}
}

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

@@ -128,7 +127,7 @@ namespace Gaming
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);
}


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

@@ -216,7 +216,9 @@ namespace Gaming
{
if (character.IsGhost() &&
(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))
{
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 int TeamID { get; }
public long TeamID { get; }
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 PlayerStateType PlayerState { get; }
public BulletType BulletOfPlayer { get; set; }


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

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



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

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


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

@@ -33,10 +33,10 @@ namespace Server
else return null;
case Preparation.Utility.GameObjType.Door:
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;
}
}
@@ -68,7 +68,7 @@ namespace Server
ViewRange = player.ViewRange,
Radius = player.Radius,
DangerAlert = (player.BgmDictionary.ContainsKey(BgmType.GhostIsComing)) ? player.BgmDictionary[BgmType.GhostIsComing] : 0,
Score = player.Score,
Score = (int)player.Score,
TreatProgress = player.DegreeOfTreatment,
RescueProgress = player.TimeOfRescue,

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

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

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

private static MessageOfObj Prop(Prop prop)
private static MessageOfObj Prop(Item prop)
{
MessageOfObj msg = new()
{
@@ -256,7 +256,7 @@ namespace Server
{
X = door.Position.x,
Y = door.Position.y,
Progress = door.OpenOrLockDegree,
Progress = door.LockDegree,
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])
{
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)
{
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);
if (newPlayerID == GameObj.invalidID)
return;
@@ -471,7 +471,7 @@ namespace Server
return Task.FromResult(boolRes);
}
var gameID = communicationToGameID[request.PlayerId];
boolRes.ActSuccess = game.LockOrOpenDoor(gameID);
boolRes.ActSuccess = game.OpenDoor(gameID);
return Task.FromResult(boolRes);
}

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



Loading…
Cancel
Save