Browse Source

refactor: 🎨 add the CharacterManager

tags/0.1.0
shangfengh 3 years ago
parent
commit
812fe9145f
14 changed files with 462 additions and 361 deletions
  1. +2
    -1
      dependency/proto/MessageType.proto
  2. +6
    -0
      logic/GameClass/GameObj/Character/Character.Skill.cs
  3. +19
    -0
      logic/GameClass/GameObj/Character/Character.Student.cs
  4. +1
    -29
      logic/GameClass/GameObj/Character/Skill.cs
  5. +3
    -3
      logic/Gaming/ActionManager.cs
  6. +12
    -153
      logic/Gaming/AttackManager.cs
  7. +306
    -0
      logic/Gaming/CharacterManager .cs
  8. +8
    -166
      logic/Gaming/Game.cs
  9. +3
    -3
      logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs
  10. +3
    -1
      logic/Gaming/SkillManager/SkillManager.cs
  11. +88
    -3
      logic/Preparation/Interface/IOccupation.cs
  12. +2
    -1
      logic/Preparation/Utility/EnumType.cs
  13. +8
    -0
      logic/Server/CopyInfo.cs
  14. +1
    -1
      logic/Server/GameServer.cs

+ 2
- 1
dependency/proto/MessageType.proto View File

@@ -109,7 +109,8 @@ enum StudentType
ATHLETE = 1;
STUDENTTYPE2 = 2;//Teacher
STUDENTTYPE3 = 3;//StraightAStudent
STUDENTTYPE4 = 4;
STUDENTTYPE4 = 4;//Robot
TECH_OTAKU =5;
}

enum TrickerType


+ 6
- 0
logic/GameClass/GameObj/Character/Character.Skill.cs View File

@@ -66,6 +66,9 @@ namespace GameClass.GameObj
case CharacterType.Assassin:
this.occupation = new Assassin();
break;
case CharacterType.Robot:
this.occupation = new Robot();
break;
case CharacterType.Teacher:
this.occupation = new Teacher();
break;
@@ -78,6 +81,9 @@ namespace GameClass.GameObj
case CharacterType.ANoisyPerson:
this.occupation = new ANoisyPerson();
break;
case CharacterType.TechOtaku:
this.occupation = new TechOtaku();
break;
case CharacterType.Athlete:
default:
this.occupation = new Athlete();


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

@@ -167,4 +167,23 @@ namespace GameClass.GameObj
this.MaxGamingAddiction = ((IStudent)Occupation).MaxGamingAddiction;
}
}
public class Golem : Student
{
private Character? parent; // 主人
public Character? Parent
{
get => parent;
set
{
lock (gameObjLock)
{
parent = value;
}
}
}
public Golem(XY initPos, int initRadius, Character? parent) : base(initPos, initRadius, CharacterType.Robot)
{
this.parent = parent;
}
}
}

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

@@ -3,20 +3,6 @@ using Preparation.Utility;

namespace GameClass.GameObj
{
public class BecomeVampire : IActiveSkill // 化身吸血鬼
{
public int SkillCD => GameData.commonSkillCD * 4 / 3;
public int DurationTime => GameData.commonSkillTime;

private readonly object commonSkillLock = new object();
public object ActiveSkillLock => commonSkillLock;

public bool isBeingUsed = false;
public bool IsBeingUsed
{
get => isBeingUsed; set => isBeingUsed = value;
}
}
public class CanBeginToCharge : IActiveSkill
{
public int SkillCD => GameData.commonSkillCD / 5;
@@ -79,7 +65,7 @@ namespace GameClass.GameObj

public class JumpyBomb : IActiveSkill
{
public int SkillCD => GameData.commonSkillCD / 30 * 5;
public int SkillCD => GameData.commonSkillCD / 25 * 5;
public int DurationTime => GameData.commonSkillTime / 2;
private readonly object commonSkillLock = new object();
public object ActiveSkillLock => commonSkillLock;
@@ -105,20 +91,6 @@ namespace GameClass.GameObj
}
}

public class SuperFast : IActiveSkill // 3倍速
{
public int SkillCD => GameData.commonSkillCD;
public int DurationTime => GameData.commonSkillTime * 4 / 10;
private readonly object commonSkillLock = new object();
public object ActiveSkillLock => commonSkillLock;

public bool isBeingUsed = false;
public bool IsBeingUsed
{
get => isBeingUsed; set => isBeingUsed = value;
}
}

public class WriteAnswers : IActiveSkill
{
public int SkillCD => GameData.commonSkillCD;


+ 3
- 3
logic/Gaming/ActionManager.cs View File

@@ -23,16 +23,16 @@ namespace Gaming
{
if (((Bullet)collisionObj).Parent != player && ((Bullet)collisionObj).TypeOfBullet == BulletType.JumpyDumpty)
{
if (AttackManager.BeStunned((Character)player, ((Bullet)collisionObj).AP / GameData.timeFactorOfGhostFainting))
if (CharacterManager.BeStunned((Character)player, ((Bullet)collisionObj).AP / GameData.timeFactorOfGhostFainting))
player.AddScore(GameData.TrickerScoreStudentBeStunned(((Bullet)collisionObj).AP / GameData.timeFactorOfGhostFainting));
gameMap.Remove((GameObj)collisionObj);
}
}
if (player.FindIActiveSkill(ActiveSkillType.CanBeginToCharge).IsBeingUsed && collisionObj.Type == GameObjType.Character && ((Character)collisionObj).IsGhost())
{
if (AttackManager.BeStunned((Character)collisionObj, GameData.TimeOfGhostFaintingWhenCharge))
if (CharacterManager.BeStunned((Character)collisionObj, GameData.TimeOfGhostFaintingWhenCharge))
player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.TimeOfGhostFaintingWhenCharge));
AttackManager.BeStunned(player, GameData.TimeOfStudentFaintingWhenCharge);
CharacterManager.BeStunned(player, GameData.TimeOfStudentFaintingWhenCharge);
}
}
public bool MovePlayer(Character playerToMove, int moveTimeInMilliseconds, double moveDirection)


+ 12
- 153
logic/Gaming/AttackManager.cs View File

@@ -17,7 +17,9 @@ namespace Gaming
{
readonly Map gameMap;
readonly MoveEngine moveEngine;
public AttackManager(Map gameMap)
readonly CharacterManager characterManager;

public AttackManager(Map gameMap, CharacterManager characterManager)
{
this.gameMap = gameMap;
this.moveEngine = new MoveEngine(
@@ -29,121 +31,12 @@ namespace Gaming
},
EndMove: obj =>
{
#if DEBUG
Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64);

#endif
if (obj.CanMove && ((Bullet)obj).TypeOfBullet != BulletType.JumpyDumpty)
BulletBomb((Bullet)obj, null);
}
);
}

private void BeAddictedToGame(Student player, Ghost ghost)
{
ghost.AddScore(GameData.TrickerScoreStudentBeAddicted);
new Thread
(() =>
{
if (player.GamingAddiction > GameData.BeginGamingAddiction && player.GamingAddiction < GameData.MidGamingAddiction)
player.GamingAddiction = GameData.MidGamingAddiction;
player.PlayerState = PlayerStateType.Addicted;
#if DEBUG
Debugger.Output(player, " is addicted ");
#endif
new FrameRateTaskExecutor<int>(
() => (player.PlayerState == PlayerStateType.Addicted || player.PlayerState == PlayerStateType.Rescued) && player.GamingAddiction < player.MaxGamingAddiction && gameMap.Timer.IsGaming,
() =>
{
player.GamingAddiction += (player.PlayerState == PlayerStateType.Addicted) ? GameData.frameDuration : 0;
},
timeInterval: GameData.frameDuration,
() =>
{
if (player.GamingAddiction == player.MaxGamingAddiction && gameMap.Timer.IsGaming)
{
ghost.AddScore(GameData.TrickerScoreStudentDie);
Die(player);
}
return 0;
}
)
.Start();
}
)
{ IsBackground = true }.Start();
}

public static bool BeStunned(Character player, int time)
{
if (player.PlayerState == PlayerStateType.Stunned || player.NoHp()) return false;
new Thread
(() =>
{
player.PlayerState = PlayerStateType.Stunned;
Thread.Sleep(time);
if (player.PlayerState == PlayerStateType.Stunned)
player.PlayerState = PlayerStateType.Null;
}
)
{ IsBackground = true }.Start();
return true;
}
public static bool BackSwing(Character? player, int time)
{
if (player == null && time <= 0) return false;
if (player.PlayerState == PlayerStateType.Swinging || (!player.Commandable() && player.PlayerState != PlayerStateType.TryingToAttack)) return false;
player.PlayerState = PlayerStateType.Swinging;

new Thread
(() =>
{
Thread.Sleep(time);

if (player.PlayerState == PlayerStateType.Swinging)
{
player.PlayerState = PlayerStateType.Null;
}
}
)
{ IsBackground = true }.Start();
return true;
}

private void Die(Character player)
{
#if DEBUG
Debugger.Output(player, "die.");
#endif
player.Die(PlayerStateType.Deceased);

for (int i = 0; i < GameData.maxNumOfPropInPropInventory; i++)
{
Prop? prop = player.UseProp(i);
if (prop != null)
{
prop.ReSetPos(player.Position, gameMap.GetPlaceType(player.Position));
gameMap.Add(prop);
}
}
++gameMap.NumOfDeceasedStudent;
if (GameData.numOfStudent - gameMap.NumOfDeceasedStudent - gameMap.NumOfEscapedStudent == 1)
{
gameMap.GameObjLockDict[GameObjType.EmergencyExit].EnterReadLock();
try
{
foreach (EmergencyExit emergencyExit in gameMap.GameObjDict[GameObjType.EmergencyExit])
if (emergencyExit.CanOpen)
{
emergencyExit.IsOpen = true;
break;
}
}
finally
{
gameMap.GameObjLockDict[GameObjType.EmergencyExit].ExitReadLock();
}
}
this.characterManager = characterManager;
}

private void BombObj(Bullet bullet, GameObj objBeingShot)
@@ -164,11 +57,11 @@ namespace Gaming
}
if (whoBeAttacked.BeAttacked(bullet))
{
BeAddictedToGame(whoBeAttacked, (Ghost)bullet.Parent);
characterManager.BeAddictedToGame(whoBeAttacked, (Ghost)bullet.Parent);
}
if (whoBeAttacked.CanBeAwed())
{
if (BeStunned(whoBeAttacked, GameData.basicStunnedTimeOfStudent))
if (CharacterManager.BeStunned(whoBeAttacked, GameData.basicStunnedTimeOfStudent))
bullet.Parent.AddScore(GameData.TrickerScoreStudentBeStunned(GameData.basicStunnedTimeOfStudent));
}
}
@@ -201,14 +94,14 @@ namespace Gaming
{
if (objBeingShot == null)
{
BackSwing((Character?)bullet.Parent, bullet.Backswing);
CharacterManager.BackSwing((Character?)bullet.Parent, bullet.Backswing);
return;
}

Debugger.Output(bullet, bullet.TypeOfBullet.ToString());

BombObj(bullet, objBeingShot);
BackSwing((Character?)bullet.Parent, bullet.RecoveryFromHit);
CharacterManager.BackSwing((Character?)bullet.Parent, bullet.RecoveryFromHit);
return;
}

@@ -259,48 +152,14 @@ namespace Gaming
{
BombObj(bullet, beAttackedObj);
}
beAttackedList.Clear();

if (objBeingShot == null)
{
if (bullet.Backswing > 0)
{
bullet.Parent.PlayerState = PlayerStateType.Swinging;

new Thread
(() =>
{
Thread.Sleep(bullet.Backswing);

if (gameMap.Timer.IsGaming && bullet.Parent.PlayerState == PlayerStateType.Swinging)
{
bullet.Parent.PlayerState = PlayerStateType.Null;
}
}
)
{ IsBackground = true }.Start();
}
CharacterManager.BackSwing((Character?)bullet.Parent, bullet.Backswing);
}
else
{
if (bullet.RecoveryFromHit > 0)
{
bullet.Parent.PlayerState = PlayerStateType.Swinging;

new Thread
(() =>
{

Thread.Sleep(bullet.RecoveryFromHit);

if (gameMap.Timer.IsGaming && bullet.Parent.PlayerState == PlayerStateType.Swinging)
{
bullet.Parent.PlayerState = PlayerStateType.Null;
}
}
)
{ IsBackground = true }.Start();
}
}
beAttackedList.Clear();
CharacterManager.BackSwing((Character?)bullet.Parent, bullet.RecoveryFromHit);
}

public bool Attack(Character? player, double angle)


+ 306
- 0
logic/Gaming/CharacterManager .cs View File

@@ -0,0 +1,306 @@
using System;
using System.Threading;
using System.Collections.Generic;
using GameClass.GameObj;
using Preparation.Utility;
using GameEngine;
using Preparation.Interface;
using Timothy.FrameRateTask;
using System.Numerics;

namespace Gaming
{
public partial class Game
{
private readonly CharacterManager characterManager;
private class CharacterManager
{
readonly Map gameMap;
public CharacterManager(Map gameMap)
{
this.gameMap = gameMap;
}


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

if (characterType == CharacterType.Robot)
{
newPlayer = new Golem(pos, GameData.characterRadius, parent);
}
else newPlayer = (GameData.IsGhost(characterType)) ? new Ghost(pos, GameData.characterRadius, characterType) : new Student(pos, GameData.characterRadius, characterType);
gameMap.Add(newPlayer);

newPlayer.TeamID = teamID;
newPlayer.PlayerID = playerID;
#region 人物装弹
new Thread
(
() =>
{
while (!gameMap.Timer.IsGaming)
Thread.Sleep(Math.Max(newPlayer.CD, GameData.checkInterval));
long lastTime = Environment.TickCount64;
new FrameRateTaskExecutor<int>(
loopCondition: () => gameMap.Timer.IsGaming && !newPlayer.IsResetting,
loopToDo: () =>
{
long nowTime = Environment.TickCount64;
if (newPlayer.BulletNum == newPlayer.MaxBulletNum)
lastTime = nowTime;
else if (nowTime - lastTime >= newPlayer.CD)
{
_ = newPlayer.TryAddBulletNum();
lastTime = nowTime;
}
},
timeInterval: GameData.checkInterval,
finallyReturn: () => 0
)
{
AllowTimeExceed = true/*,
MaxTolerantTimeExceedCount = 5,
TimeExceedAction = exceedTooMuch =>
{
if (exceedTooMuch) Console.WriteLine("The computer runs too slow that it cannot check the color below the player in time!");
}*/
}
.Start();
}
)
{ IsBackground = true }.Start();
#endregion
#region BGM,牵制得分更新
new Thread
(
() =>
{
while (!gameMap.Timer.IsGaming)
Thread.Sleep(GameData.checkInterval);
int TimePinningDown = 0, ScoreAdded = 0;

bool noise = false;
if (!newPlayer.IsGhost())
{
gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock();
try
{
foreach (Character person in gameMap.GameObjDict[GameObjType.Character])
{
if (person.IsGhost())
{
if (person.CharacterType == CharacterType.ANoisyPerson)
{
noise = true;
newPlayer.AddBgm(BgmType.GhostIsComing, 1411180);
newPlayer.AddBgm(BgmType.GeneratorIsBeingFixed, 154991);
}
}
}
}
finally
{
gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock();
}
}
new FrameRateTaskExecutor<int>(
loopCondition: () => gameMap.Timer.IsGaming && !newPlayer.IsResetting,
loopToDo: () =>
{
gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock();
try
{
if (newPlayer.IsGhost())
{
double bgmVolume = 0;
foreach (Character person in gameMap.GameObjDict[GameObjType.Character])
{
if (!person.IsGhost() && XY.Distance(newPlayer.Position, person.Position) <= (newPlayer.AlertnessRadius / person.Concealment))
{
if ((double)newPlayer.AlertnessRadius / XY.Distance(newPlayer.Position, person.Position) > bgmVolume)
bgmVolume = newPlayer.AlertnessRadius / XY.Distance(newPlayer.Position, person.Position);
}
}
if (bgmVolume > 0)
newPlayer.AddBgm(BgmType.StudentIsApproaching, bgmVolume);
}
else
{
foreach (Character person in gameMap.GameObjDict[GameObjType.Character])
{
if (person.IsGhost())
{
if (!noise && XY.Distance(newPlayer.Position, person.Position) <= (newPlayer.AlertnessRadius / person.Concealment))
newPlayer.AddBgm(BgmType.GhostIsComing, (double)newPlayer.AlertnessRadius / XY.Distance(newPlayer.Position, person.Position));
if (XY.Distance(newPlayer.Position, person.Position) <= GameData.basicViewRange)
{
TimePinningDown += GameData.checkInterval;
newPlayer.AddScore(GameData.StudentScorePinDown(TimePinningDown) - ScoreAdded);
ScoreAdded = GameData.StudentScorePinDown(TimePinningDown);
}
else TimePinningDown = ScoreAdded = 0;
break;
}
}
}
}
finally
{
gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock();
}

if (!noise)
{
gameMap.GameObjLockDict[GameObjType.Generator].EnterReadLock();
try
{
double bgmVolume = 0;
foreach (Generator generator in gameMap.GameObjDict[GameObjType.Generator])
{
if (XY.Distance(newPlayer.Position, generator.Position) <= newPlayer.AlertnessRadius)
{
if ((double)newPlayer.AlertnessRadius * generator.DegreeOfRepair / GameData.degreeOfFixedGenerator / XY.Distance(newPlayer.Position, generator.Position) > bgmVolume)
bgmVolume = (double)newPlayer.AlertnessRadius * generator.DegreeOfRepair / GameData.degreeOfFixedGenerator / XY.Distance(newPlayer.Position, generator.Position);
}
}
if (bgmVolume > 0)
newPlayer.AddBgm(BgmType.GeneratorIsBeingFixed, bgmVolume);
}
finally
{
gameMap.GameObjLockDict[GameObjType.Generator].ExitReadLock();
}
}
},
timeInterval: GameData.checkInterval,
finallyReturn: () => 0
)
{
AllowTimeExceed = true/*,
MaxTolerantTimeExceedCount = 5,
TimeExceedAction = exceedTooMuch =>
{
if (exceedTooMuch) Console.WriteLine("The computer runs too slow that it cannot check the color below the player in time!");
}*/
}
.Start();
}
)
{ IsBackground = true }.Start();
#endregion

return newPlayer;
}

public void BeAddictedToGame(Student player, Ghost ghost)
{
ghost.AddScore(GameData.TrickerScoreStudentBeAddicted);
new Thread
(() =>
{
if (player.GamingAddiction > GameData.BeginGamingAddiction && player.GamingAddiction < GameData.MidGamingAddiction)
player.GamingAddiction = GameData.MidGamingAddiction;
player.PlayerState = PlayerStateType.Addicted;
#if DEBUG
Debugger.Output(player, " is addicted ");
#endif
new FrameRateTaskExecutor<int>(
() => (player.PlayerState == PlayerStateType.Addicted || player.PlayerState == PlayerStateType.Rescued) && player.GamingAddiction < player.MaxGamingAddiction && gameMap.Timer.IsGaming,
() =>
{
player.GamingAddiction += (player.PlayerState == PlayerStateType.Addicted) ? GameData.frameDuration : 0;
},
timeInterval: GameData.frameDuration,
() =>
{
if (player.GamingAddiction == player.MaxGamingAddiction && gameMap.Timer.IsGaming)
{
ghost.AddScore(GameData.TrickerScoreStudentDie);
Die(player);
}
return 0;
}
)
.Start();
}
)
{ IsBackground = true }.Start();
}

public static bool BeStunned(Character player, int time)
{
if (player.PlayerState == PlayerStateType.Stunned || player.NoHp()) return false;
new Thread
(() =>
{
player.PlayerState = PlayerStateType.Stunned;
Thread.Sleep(time);
if (player.PlayerState == PlayerStateType.Stunned)
player.PlayerState = PlayerStateType.Null;
}
)
{ IsBackground = true }.Start();
return true;
}
public static bool BackSwing(Character? player, int time)
{
if (player == null || time <= 0) return false;
if (player.PlayerState == PlayerStateType.Swinging || (!player.Commandable() && player.PlayerState != PlayerStateType.TryingToAttack)) return false;
player.PlayerState = PlayerStateType.Swinging;

new Thread
(() =>
{
Thread.Sleep(time);

if (player.PlayerState == PlayerStateType.Swinging)
{
player.PlayerState = PlayerStateType.Null;
}
}
)
{ IsBackground = true }.Start();
return true;
}

private void Die(Character player)
{
#if DEBUG
Debugger.Output(player, "die.");
#endif
player.Die(PlayerStateType.Deceased);

for (int i = 0; i < GameData.maxNumOfPropInPropInventory; i++)
{
Prop? prop = player.UseProp(i);
if (prop != null)
{
prop.ReSetPos(player.Position, gameMap.GetPlaceType(player.Position));
gameMap.Add(prop);
}
}
++gameMap.NumOfDeceasedStudent;
if (GameData.numOfStudent - gameMap.NumOfDeceasedStudent - gameMap.NumOfEscapedStudent == 1)
{
gameMap.GameObjLockDict[GameObjType.EmergencyExit].EnterReadLock();
try
{
foreach (EmergencyExit emergencyExit in gameMap.GameObjDict[GameObjType.EmergencyExit])
if (emergencyExit.CanOpen)
{
emergencyExit.IsOpen = true;
break;
}
}
finally
{
gameMap.GameObjLockDict[GameObjType.EmergencyExit].ExitReadLock();
}
}
}

}
}
}

+ 8
- 166
logic/Gaming/Game.cs View File

@@ -14,10 +14,10 @@ namespace Gaming
public struct PlayerInitInfo
{
public uint birthPointIndex;
public long teamID;
public long playerID;
public int teamID;
public int playerID;
public CharacterType characterType;
public PlayerInitInfo(uint birthPointIndex, long teamID, long playerID, CharacterType characterType)
public PlayerInitInfo(uint birthPointIndex, int teamID, int playerID, CharacterType characterType)
{
this.birthPointIndex = birthPointIndex;
this.teamID = teamID;
@@ -39,171 +39,12 @@ namespace Gaming
return GameObj.invalidID;

XY pos = gameMap.BirthPointList[playerInitInfo.birthPointIndex];
Character? newPlayer = characterManager.AddPlayer(pos, playerInitInfo.teamID, playerInitInfo.playerID, playerInitInfo.characterType);
if (newPlayer == null) return GameObj.invalidID;
// Console.WriteLine($"x,y: {pos.x},{pos.y}");

Character newPlayer = (GameData.IsGhost(playerInitInfo.characterType)) ? new Ghost(pos, GameData.characterRadius, playerInitInfo.characterType) : new Student(pos, GameData.characterRadius, playerInitInfo.characterType);
gameMap.Add(newPlayer);

// Console.WriteLine($"GameObjDict[GameObjType.Character] length:{gameMap.GameObjDict[GameObjType.Character].Count}");
teamList[(int)playerInitInfo.teamID].AddPlayer(newPlayer);
newPlayer.TeamID = playerInitInfo.teamID;
newPlayer.PlayerID = playerInitInfo.playerID;
#region 人物装弹
new Thread
(
() =>
{
while (!gameMap.Timer.IsGaming)
Thread.Sleep(Math.Max(newPlayer.CD, GameData.checkInterval));
long lastTime = Environment.TickCount64;
new FrameRateTaskExecutor<int>(
loopCondition: () => gameMap.Timer.IsGaming && !newPlayer.IsResetting,
loopToDo: () =>
{
long nowTime = Environment.TickCount64;
if (newPlayer.BulletNum == newPlayer.MaxBulletNum)
lastTime = nowTime;
else if (nowTime - lastTime >= newPlayer.CD)
{
_ = newPlayer.TryAddBulletNum();
lastTime = nowTime;
}
},
timeInterval: GameData.checkInterval,
finallyReturn: () => 0
)
{
AllowTimeExceed = true/*,
MaxTolerantTimeExceedCount = 5,
TimeExceedAction = exceedTooMuch =>
{
if (exceedTooMuch) Console.WriteLine("The computer runs too slow that it cannot check the color below the player in time!");
}*/
}
.Start();
}
)
{ IsBackground = true }.Start();
#endregion
#region BGM,牵制得分更新
new Thread
(
() =>
{
while (!gameMap.Timer.IsGaming)
Thread.Sleep(GameData.checkInterval);
int TimePinningDown = 0, ScoreAdded = 0;

bool noise = false;
if (!newPlayer.IsGhost())
{
gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock();
try
{
foreach (Character person in gameMap.GameObjDict[GameObjType.Character])
{
if (person.IsGhost())
{
if (person.CharacterType == CharacterType.ANoisyPerson)
{
noise = true;
newPlayer.AddBgm(BgmType.GhostIsComing, 1411180);
newPlayer.AddBgm(BgmType.GeneratorIsBeingFixed, 154991);
}
}
}
}
finally
{
gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock();
}
}
new FrameRateTaskExecutor<int>(
loopCondition: () => gameMap.Timer.IsGaming && !newPlayer.IsResetting,
loopToDo: () =>
{
gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock();
try
{
if (newPlayer.IsGhost())
{
double bgmVolume = 0;
foreach (Character person in gameMap.GameObjDict[GameObjType.Character])
{
if (!person.IsGhost() && XY.Distance(newPlayer.Position, person.Position) <= (newPlayer.AlertnessRadius / person.Concealment))
{
if ((double)newPlayer.AlertnessRadius / XY.Distance(newPlayer.Position, person.Position) > bgmVolume)
bgmVolume = newPlayer.AlertnessRadius / XY.Distance(newPlayer.Position, person.Position);
}
}
if (bgmVolume > 0)
newPlayer.AddBgm(BgmType.StudentIsApproaching, bgmVolume);
}
else
{
foreach (Character person in gameMap.GameObjDict[GameObjType.Character])
{
if (person.IsGhost())
{
if (!noise && XY.Distance(newPlayer.Position, person.Position) <= (newPlayer.AlertnessRadius / person.Concealment))
newPlayer.AddBgm(BgmType.GhostIsComing, (double)newPlayer.AlertnessRadius / XY.Distance(newPlayer.Position, person.Position));
if (XY.Distance(newPlayer.Position, person.Position) <= GameData.basicViewRange)
{
TimePinningDown += GameData.checkInterval;
newPlayer.AddScore(GameData.StudentScorePinDown(TimePinningDown) - ScoreAdded);
ScoreAdded = GameData.StudentScorePinDown(TimePinningDown);
}
else TimePinningDown = ScoreAdded = 0;
break;
}
}
}
}
finally
{
gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock();
}

if (!noise)
{
gameMap.GameObjLockDict[GameObjType.Generator].EnterReadLock();
try
{
double bgmVolume = 0;
foreach (Generator generator in gameMap.GameObjDict[GameObjType.Generator])
{
if (XY.Distance(newPlayer.Position, generator.Position) <= newPlayer.AlertnessRadius)
{
if ((double)newPlayer.AlertnessRadius * generator.DegreeOfRepair / GameData.degreeOfFixedGenerator / XY.Distance(newPlayer.Position, generator.Position) > bgmVolume)
bgmVolume = (double)newPlayer.AlertnessRadius * generator.DegreeOfRepair / GameData.degreeOfFixedGenerator / XY.Distance(newPlayer.Position, generator.Position);
}
}
if (bgmVolume > 0)
newPlayer.AddBgm(BgmType.GeneratorIsBeingFixed, bgmVolume);
}
finally
{
gameMap.GameObjLockDict[GameObjType.Generator].ExitReadLock();
}
}
},
timeInterval: GameData.checkInterval,
finallyReturn: () => 0
)
{
AllowTimeExceed = true/*,
MaxTolerantTimeExceedCount = 5,
TimeExceedAction = exceedTooMuch =>
{
if (exceedTooMuch) Console.WriteLine("The computer runs too slow that it cannot check the color below the player in time!");
}*/
}
.Start();
}
)
{ IsBackground = true }.Start();
#endregion

return newPlayer.ID;
}
public bool StartGame(int milliSeconds)
@@ -529,10 +370,11 @@ namespace Gaming
teamList.Add(new Team());
}

attackManager = new AttackManager(gameMap);
characterManager = new CharacterManager(gameMap);
attackManager = new AttackManager(gameMap, characterManager);
actionManager = new ActionManager(gameMap);
propManager = new PropManager(gameMap);
skillManager = new SkillManager(gameMap, actionManager, attackManager, propManager);
skillManager = new SkillManager(gameMap, actionManager, attackManager, propManager, characterManager);
}
}
}

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

@@ -106,7 +106,7 @@ namespace Gaming
{
if (!character.IsGhost() && XY.Distance(character.Position, player.Position) <= player.ViewRange)
{
if (AttackManager.BeStunned(character, GameData.TimeOfStudentFaintingWhenHowl))
if (CharacterManager.BeStunned(character, GameData.TimeOfStudentFaintingWhenHowl))
player.AddScore(GameData.TrickerScoreStudentBeStunned(GameData.TimeOfStudentFaintingWhenHowl));
break;
}
@@ -116,7 +116,7 @@ namespace Gaming
{
gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock();
}
AttackManager.BackSwing(player, GameData.TimeOfGhostSwingingAfterHowl);
CharacterManager.BackSwing(player, GameData.TimeOfGhostSwingingAfterHowl);
Debugger.Output(player, "howled!");
},
() =>
@@ -137,7 +137,7 @@ namespace Gaming
|| character.PlayerState == PlayerStateType.UsingSkill || character.PlayerState == PlayerStateType.LockingOrOpeningTheDoor || character.PlayerState == PlayerStateType.OpeningTheChest)
&& gameMap.CanSee(player, character))
{
if (AttackManager.BeStunned(character, GameData.TimeOfGhostFaintingWhenPunish + (player.MaxHp - player.HP) / GameData.timeFactorOfGhostFainting))
if (CharacterManager.BeStunned(character, GameData.TimeOfGhostFaintingWhenPunish + (player.MaxHp - player.HP) / GameData.timeFactorOfGhostFainting))
player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.TimeOfGhostFaintingWhenPunish + (player.MaxHp - player.HP) / GameData.timeFactorOfGhostFainting));
break;
}


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

@@ -69,15 +69,17 @@ namespace Gaming
}

private readonly Map gameMap;
private readonly CharacterManager characterManager;
private readonly ActionManager actionManager;
private readonly AttackManager attackManager;
private readonly PropManager propManager;
public SkillManager(Map gameMap, ActionManager action, AttackManager attack, PropManager prop)
public SkillManager(Map gameMap, ActionManager action, AttackManager attack, PropManager prop, CharacterManager characterManager)
{
this.gameMap = gameMap;
this.actionManager = action;
this.propManager = prop;
this.attackManager = attack;
this.characterManager = characterManager;
}
}
}


+ 88
- 3
logic/Preparation/Interface/IOccupation.cs View File

@@ -98,7 +98,6 @@ namespace Preparation.Interface
public int speedOfOpenChest = (int)(GameData.basicSpeedOfOpenChest * 1.1);
public int SpeedOfOpenChest => speedOfOpenChest;
}

public class ANoisyPerson : IGhost
{
private const int moveSpeed = (int)(GameData.basicMoveSpeed * 1.1);
@@ -250,7 +249,7 @@ namespace Preparation.Interface
public const int alertnessRadius = (int)(GameData.basicAlertnessRadius * 0.9);
public int AlertnessRadius => alertnessRadius;

public int viewRange = GameData.basicViewRange;
public int viewRange = (int)(GameData.basicViewRange * 0.9);
public int ViewRange => viewRange;

public int timeOfOpeningOrLocking = GameData.basicSpeedOfOpeningOrLocking;
@@ -262,4 +261,90 @@ namespace Preparation.Interface
public int speedOfOpenChest = GameData.basicSpeedOfOpenChest;
public int SpeedOfOpenChest => speedOfOpenChest;
}
}
public class Robot : IStudent
{
private const int moveSpeed = (int)(GameData.basicMoveSpeed);
public int MoveSpeed => moveSpeed;

private const int maxHp = (int)(GameData.basicHp / 2.5);
public int MaxHp => maxHp;

private const int maxGamingAddiction = 0;
public int MaxGamingAddiction => maxGamingAddiction;

public const int maxBulletNum = 0;
public int MaxBulletNum => maxBulletNum;

public BulletType InitBullet => BulletType.Null;

public List<ActiveSkillType> ListOfIActiveSkill => new(new ActiveSkillType[] { });
public List<PassiveSkillType> ListOfIPassiveSkill => new(new PassiveSkillType[] { });

public const int fixSpeed = GameData.basicFixSpeed;
public int FixSpeed => fixSpeed;

public const int treatSpeed = GameData.basicTreatSpeed * 8 / 10;
public int TreatSpeed => treatSpeed;

public const double concealment = GameData.basicConcealment;
public double Concealment => concealment;

public const int alertnessRadius = (int)(GameData.basicAlertnessRadius);
public int AlertnessRadius => alertnessRadius;

public int viewRange = GameData.basicViewRange;
public int ViewRange => viewRange;

public int timeOfOpeningOrLocking = GameData.basicSpeedOfOpeningOrLocking;
public int TimeOfOpeningOrLocking => timeOfOpeningOrLocking;

public int speedOfClimbingThroughWindows = 1;
public int SpeedOfClimbingThroughWindows => speedOfClimbingThroughWindows;

public int speedOfOpenChest = GameData.basicSpeedOfOpenChest;
public int SpeedOfOpenChest => speedOfOpenChest;
}
public class TechOtaku : IStudent
{
private const int moveSpeed = (int)(GameData.basicMoveSpeed * 0.75);
public int MoveSpeed => moveSpeed;

private const int maxHp = (int)(GameData.basicHp * 0.9);
public int MaxHp => maxHp;

private const int maxGamingAddiction = (int)(GameData.basicMaxGamingAddiction * 1.1);
public int MaxGamingAddiction => maxGamingAddiction;

public const int maxBulletNum = 0;
public int MaxBulletNum => maxBulletNum;

public BulletType InitBullet => BulletType.Null;

public List<ActiveSkillType> ListOfIActiveSkill => new(new ActiveSkillType[] { });
public List<PassiveSkillType> ListOfIPassiveSkill => new(new PassiveSkillType[] { });

public const int fixSpeed = (int)(GameData.basicFixSpeed * 1.1);
public int FixSpeed => fixSpeed;

public const int treatSpeed = GameData.basicTreatSpeed * 9 / 10;
public int TreatSpeed => treatSpeed;

public const double concealment = GameData.basicConcealment;
public double Concealment => concealment;

public const int alertnessRadius = (int)(GameData.basicAlertnessRadius);
public int AlertnessRadius => alertnessRadius;

public int viewRange = (int)(GameData.basicViewRange * 0.9);
public int ViewRange => viewRange;

public int timeOfOpeningOrLocking = GameData.basicSpeedOfOpeningOrLocking;
public int TimeOfOpeningOrLocking => timeOfOpeningOrLocking;

public int speedOfClimbingThroughWindows = (int)(GameData.basicStudentSpeedOfClimbingThroughWindows * 3 / 4);
public int SpeedOfClimbingThroughWindows => speedOfClimbingThroughWindows;

public int speedOfOpenChest = GameData.basicSpeedOfOpenChest;
public int SpeedOfOpenChest => speedOfOpenChest;
}
}

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

@@ -77,10 +77,11 @@ namespace Preparation.Utility
Assassin = 1,
Athlete = 2,
Klee = 3,
SpeedUpWhenLeavingGrass = 4,
TechOtaku = 4,
Teacher = 5,
StraightAStudent = 6,
ANoisyPerson = 7,
Robot = 8,
}
public enum ActiveSkillType // 主动技能
{


+ 8
- 0
logic/Server/CopyInfo.cs View File

@@ -182,6 +182,10 @@ namespace Server
return StudentType._2;
case CharacterType.StraightAStudent:
return StudentType._3;
case CharacterType.Robot:
return StudentType._4;
case CharacterType.TechOtaku:
return StudentType.TechOtaku;
default:
return Protobuf.StudentType.NullStudentType;
}
@@ -197,6 +201,10 @@ namespace Server
return Preparation.Utility.CharacterType.Teacher;
case StudentType._3:
return CharacterType.StraightAStudent;
case StudentType._4:
return CharacterType.Robot;
case StudentType.TechOtaku:
return CharacterType.TechOtaku;
default:
return Preparation.Utility.CharacterType.Null;
}


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

@@ -312,7 +312,7 @@ namespace Server

lock (addPlayerLock)
{
Game.PlayerInitInfo playerInitInfo = new(GetBirthPointIdx(request.PlayerId), PlayerTypeToTeamID(request.PlayerType), request.PlayerId, characterType);
Game.PlayerInitInfo playerInitInfo = new(GetBirthPointIdx(request.PlayerId), PlayerTypeToTeamID(request.PlayerType), (int)request.PlayerId, characterType);
long newPlayerID = game.AddPlayer(playerInitInfo);
if (newPlayerID == GameObj.invalidID)
return;


Loading…
Cancel
Save