Browse Source

Merge pull request #205 from shangfengh/new

feat:  add new CharacterType Klee and fix some bugs
tags/0.1.0
Shawqeem GitHub 2 years ago
parent
commit
b5fb12bbf1
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 355 additions and 427 deletions
  1. +10
    -9
      dependency/proto/MessageType.proto
  2. +96
    -5
      logic/GameClass/GameObj/Bullet/Bullet.Ghost.cs
  3. +1
    -1
      logic/GameClass/GameObj/Bullet/Bullet.Student.cs
  4. +10
    -10
      logic/GameClass/GameObj/Bullet/Bullet.cs
  5. +39
    -0
      logic/GameClass/GameObj/Character/Character.BuffManager.cs
  6. +7
    -1
      logic/GameClass/GameObj/Character/Character.Skill.cs
  7. +14
    -18
      logic/GameClass/GameObj/Character/Character.cs
  8. +7
    -3
      logic/GameClass/GameObj/Character/Skill.cs
  9. +1
    -1
      logic/GameClass/GameObj/Map/Map.cs
  10. +6
    -6
      logic/GameClass/GameObj/Prop.cs
  11. +18
    -8
      logic/Gaming/ActionManager.cs
  12. +12
    -9
      logic/Gaming/AttackManager.cs
  13. +3
    -3
      logic/Gaming/PropManager.cs
  14. +11
    -10
      logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs
  15. +3
    -0
      logic/Gaming/SkillManager/SkillManager.cs
  16. +2
    -0
      logic/Preparation/Interface/ICharacter.cs
  17. +42
    -8
      logic/Preparation/Interface/IOccupation.cs
  18. +17
    -17
      logic/Preparation/Utility/EnumType.cs
  19. +18
    -8
      logic/Preparation/Utility/GameData.cs
  20. +18
    -0
      logic/Preparation/Utility/XY.cs
  21. +6
    -2
      logic/Server/CopyInfo.cs
  22. +7
    -1
      logic/Server/GameServer.cs
  23. +0
    -142
      logic/Server/Properties/EnumType.cs
  24. +0
    -4
      logic/Server/Server.csproj
  25. +1
    -1
      logic/cmd/gameServer.cmd
  26. +6
    -160
      logic/规则Logic.md

+ 10
- 9
dependency/proto/MessageType.proto View File

@@ -43,7 +43,7 @@ enum PropType // 地图中的可拾取道具类型
{
NULL_PROP_TYPE = 0;
ADD_SPEED = 1;
ADD_LIFE_OR_AP = 2;
ADD_LIFE_OR_AP = 2;//ADD_LIFE_OR_Clairaudience
ADD_HP_OR_AP = 3;
SHIELD_OR_SPEAR = 4;
KEY3 = 5;
@@ -54,9 +54,9 @@ enum PropType // 地图中的可拾取道具类型
enum StudentBuffType // 人类可用的增益效果类型
{
NULL_SBUFF_TYPE = 0;
SBUFFTYPE1 = 1;
SBUFFTYPE2 = 2;
SBUFFTYPE3 = 3;
SBUFFTYPE1 = 1;//AddSpeed
SBUFFTYPE2 = 2;//AddLIFE
SBUFFTYPE3 = 3;//Shield
SBUFFTYPE4 = 4;
}

@@ -86,10 +86,11 @@ enum PlayerState
enum TrickerBuffType // 屠夫可用的增益效果类型
{
NULL_TBUFF_TYPE = 0;
TBUFFTYPE1 = 1;
TBUFFTYPE2 = 2;
TBUFFTYPE3 = 3;
TBUFFTYPE4 = 4;
TBUFFTYPE1 = 1;//AddSpeed
TBUFFTYPE2 = 2;//Spear
TBUFFTYPE3 = 3;//AddAp
TBUFFTYPE4 = 4;//Clairaudience
INVISIBLE = 5;
}

// 特别说明:由于Student阵营和Tricker阵营有显著的隔离,且暂定职业、主动技能和被动效果相互绑定,故不按照THUAI5的方式区分ActiveSkillType和CharacterType,而是选择了按照阵营来给不同阵营赋予不同的职业(及技能)。
@@ -114,7 +115,7 @@ enum TrickerType
{
NULL_TRICKER_TYPE = 0;
ASSASSIN = 1;
TRICKERTYPE2 = 2;
TRICKERTYPE2 = 2;//KLEE
TRICKERTYPE3 = 3;
TRICKERTYPE4 = 4;
}


+ 96
- 5
logic/GameClass/GameObj/Bullet/Bullet.Ghost.cs View File

@@ -23,9 +23,9 @@ namespace GameClass.GameObj
}
}
public override int Speed => GameData.basicBulletMoveSpeed;
public override bool IsToBomb => false;
public override bool IsRemoteAttack => false;

public override int CastTime => GameData.basicCastTime;
public override int CastTime => (int)BulletAttackRange / Speed;
public override int Backswing => GameData.basicBackswing;
public override int RecoveryFromHit => GameData.basicRecoveryFromHit;
public const int cd = GameData.basicBackswing;
@@ -68,11 +68,11 @@ namespace GameClass.GameObj
}
}
public override int Speed => GameData.basicBulletMoveSpeed * 2;
public override bool IsToBomb => false;
public override bool IsRemoteAttack => true;

public override int CastTime => GameData.basicCastTime;
public override int Backswing => GameData.basicBackswing * 2 / 5;
public override int RecoveryFromHit => GameData.basicBackswing * 3 / 4;
public override int Backswing => 0;
public override int RecoveryFromHit => 0;
public const int cd = GameData.basicBackswing * 2 / 5 + 100;
public override int CD => cd;

@@ -94,4 +94,95 @@ namespace GameClass.GameObj
public override BulletType TypeOfBullet => BulletType.FlyingKnife;

}

internal sealed class BombBomb : Bullet
{
public BombBomb(Character player, PlaceType placeType, XY pos, int radius = GameData.bulletRadius) :
base(player, radius, placeType, pos)
{
}
public override double BulletBombRange => GameData.basicBulletBombRange;
public override double BulletAttackRange => GameData.basicAttackShortRange;
public int ap = (int)(GameData.basicApOfGhost * 6.0 / 5);
public override int AP
{
get => ap;
set
{
lock (gameObjLock)
ap = value;
}
}
public override int Speed => (int)(GameData.basicBulletMoveSpeed * 0.8);
public override bool IsRemoteAttack => false;

public override int CastTime => (int)BulletAttackRange / Speed;
public override int Backswing => GameData.basicBackswing;
public override int RecoveryFromHit => GameData.basicRecoveryFromHit;
public const int cd = GameData.basicCD;
public override int CD => cd;

public override bool CanAttack(GameObj target)
{
return XY.Distance(this.Position, target.Position) <= BulletBombRange;
}
public override bool CanBeBombed(GameObjType gameObjType)
{
switch (gameObjType)
{
case GameObjType.Character:
case GameObjType.Generator:
return true;
default:
return false;
}
}
public override BulletType TypeOfBullet => BulletType.BombBomb;

}
internal sealed class JumpyDumpty : Bullet
{
public JumpyDumpty(Character player, PlaceType placeType, XY pos, int radius = GameData.bulletRadius) :
base(player, radius, placeType, pos)
{
}
public override double BulletBombRange => GameData.basicBulletBombRange / 2;
public override double BulletAttackRange => GameData.basicAttackShortRange * 2;
public int ap = (int)(GameData.basicApOfGhost * 0.6);
public override int AP
{
get => ap;
set
{
lock (gameObjLock)
ap = value;
}
}
public override int Speed => (int)(GameData.basicBulletMoveSpeed * 1.2);
public override bool IsRemoteAttack => false;

public override int CastTime => 0;
public override int Backswing => 0;
public override int RecoveryFromHit => 0;
public const int cd = 0;
public override int CD => cd;

public override bool CanAttack(GameObj target)
{
return XY.Distance(this.Position, target.Position) <= BulletBombRange;
}
public override bool CanBeBombed(GameObjType gameObjType)
{
switch (gameObjType)
{
case GameObjType.Character:
case GameObjType.Generator:
return true;
default:
return false;
}
}
public override BulletType TypeOfBullet => BulletType.JumpyDumpty;

}
}

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

@@ -12,7 +12,7 @@ namespace GameClass.GameObj
public override double BulletAttackRange => 0;
public override int AP => 7220;
public override int Speed => 0;
public override bool IsToBomb => false;
public override bool IsRemoteAttack => false;
public override int CastTime => 0;
public override int Backswing => 0;
public override int RecoveryFromHit => 0;


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

@@ -13,7 +13,7 @@ namespace GameClass.GameObj
public abstract double BulletAttackRange { get; }
public abstract int AP { get; set; }
public abstract int Speed { get; }
public abstract bool IsToBomb { get; }
public abstract bool IsRemoteAttack { get; }
public abstract int CastTime { get; }
public abstract int Backswing { get; }
public abstract int RecoveryFromHit { get; }
@@ -45,7 +45,7 @@ namespace GameClass.GameObj
this.place = placeType;
this.CanMove = true;
this.moveSpeed = this.Speed;
this.hasSpear = player.HasSpear;
this.hasSpear = player.TryUseSpear();
this.Parent = player;
}
public override bool IsRigid => true; // 默认为true
@@ -63,6 +63,10 @@ namespace GameClass.GameObj
return new FlyingKnife(character, place, pos);
case BulletType.CommonAttackOfGhost:
return new CommonAttackOfGhost(character, place, pos);
case BulletType.JumpyDumpty:
return new JumpyDumpty(character, place, pos);
case BulletType.BombBomb:
return new BombBomb(character, place, pos);
default:
return null;
}
@@ -71,10 +75,6 @@ namespace GameClass.GameObj
{
switch (bulletType)
{
case BulletType.AtomBomb:
case BulletType.LineBullet:
case BulletType.FastBullet:
case BulletType.OrdinaryBullet:
case BulletType.FlyingKnife:
default:
return GameData.bulletRadius;
@@ -88,10 +88,10 @@ namespace GameClass.GameObj
return CommonAttackOfGhost.cd;
case BulletType.FlyingKnife:
return FlyingKnife.cd;
case BulletType.AtomBomb:
case BulletType.LineBullet:
case BulletType.FastBullet:
case BulletType.OrdinaryBullet:
case BulletType.BombBomb:
return BombBomb.cd;
case BulletType.JumpyDumpty:
return JumpyDumpty.cd;
default:
return GameData.basicCD;
}


+ 39
- 0
logic/GameClass/GameObj/Character/Character.BuffManager.cs View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using Preparation.Utility;
@@ -183,6 +184,44 @@ namespace GameClass.GameObj
}
}
}
public bool TryUseSpear()
{
if (HasSpear)
{
lock (buffListLock[(int)BuffType.Spear])
{
buffList[(int)BuffType.Spear].RemoveFirst();
}
return true;
}
return false;
}

public void AddClairaudience(int shieldTime) => AddBuff(new BuffValue(), shieldTime, BuffType.Clairaudience, () =>
{ });
public bool HasClairaudience
{
get
{
lock (buffListLock[(int)BuffType.Clairaudience])
{
return buffList[(int)BuffType.Clairaudience].Count != 0;
}
}
}

public void AddInvisible(int shieldTime) => AddBuff(new BuffValue(), shieldTime, BuffType.Invisible, () =>
{ });
public bool HasInvisible
{
get
{
lock (buffListLock[(int)BuffType.Invisible])
{
return buffList[(int)BuffType.Invisible].Count != 0;
}
}
}

/// <summary>
/// 清除所有buff


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

@@ -66,6 +66,12 @@ namespace GameClass.GameObj
case CharacterType.Assassin:
this.occupation = new Assassin();
break;
case CharacterType.Teacher:
this.occupation = new Teacher();
break;
case CharacterType.Klee:
this.occupation = new Klee();
break;
case CharacterType.Athlete:
default:
this.occupation = new Athlete();
@@ -82,7 +88,7 @@ namespace GameClass.GameObj
this.characterType = characterType;
this.SpeedOfOpeningOrLocking = Occupation.TimeOfOpeningOrLocking;
this.SpeedOfClimbingThroughWindows = Occupation.SpeedOfClimbingThroughWindows;
this.SpeedOfOpenChest = Occupation.TimeOfOpenChest;
this.SpeedOfOpenChest = Occupation.SpeedOfOpenChest;

foreach (var activeSkill in this.Occupation.ListOfIActiveSkill)
{


+ 14
- 18
logic/GameClass/GameObj/Character/Character.cs View File

@@ -47,7 +47,8 @@ namespace GameClass.GameObj
lock (gameObjLock)
{
bulletOfPlayer = value;
CD = BulletFactory.BulletCD(value);
OrgCD = (BulletFactory.BulletCD(value));
CD = 0;
}
}
}
@@ -123,22 +124,6 @@ namespace GameClass.GameObj
}*/
#endregion
#region 感知相关的基本属性及方法
/// <summary>
/// 是否在隐身
/// </summary>
private bool isInvisible = false;
public bool IsInvisible
{
get => isInvisible;
set
{
lock (gameObjLock)
{
isInvisible = value;
}
}
}

private Dictionary<BgmType, double> bgmDictionary = new();
public Dictionary<BgmType, double> BgmDictionary
{
@@ -350,7 +335,7 @@ namespace GameClass.GameObj
public bool NullOrMoving() => (playerState == PlayerStateType.Null || playerState == PlayerStateType.Moving);
public bool CanBeAwed() => !(playerState == PlayerStateType.Deceased || playerState == PlayerStateType.Escaped
|| playerState == PlayerStateType.Addicted || playerState == PlayerStateType.Rescued
|| playerState == PlayerStateType.Treated || playerState != PlayerStateType.Stunned
|| playerState == PlayerStateType.Treated || playerState == PlayerStateType.Stunned
|| playerState == PlayerStateType.Null || playerState == PlayerStateType.Moving);

private int score = 0;
@@ -519,6 +504,12 @@ namespace GameClass.GameObj
public void AddSpear(int spearTime) => buffManager.AddSpear(spearTime);
public bool HasSpear => buffManager.HasSpear;

public void AddClairaudience(int time) => buffManager.AddClairaudience(time);
public bool HasClairaudience => buffManager.HasClairaudience;

public void AddInvisible(int time) => buffManager.AddInvisible(time);
public bool HasInvisible => buffManager.HasInvisible;

private Array buffTypeArray = Enum.GetValues(typeof(BuffType));
public Dictionary<BuffType, bool> Buff
{
@@ -568,6 +559,11 @@ namespace GameClass.GameObj
return false;
}

public bool TryUseSpear()
{
return buffManager.TryUseSpear();
}

public bool TryUseShield()
{
if (buffManager.TryUseShield())


+ 7
- 3
logic/GameClass/GameObj/Character/Skill.cs View File

@@ -62,10 +62,10 @@ namespace GameClass.GameObj
}
}

public class NuclearWeapon : IActiveSkill // 核武器
public class JumpyBomb : IActiveSkill
{
public int SkillCD => GameData.commonSkillCD * 7 / 3;
public int DurationTime => GameData.commonSkillTime / 10;
public int SkillCD => GameData.commonSkillCD / 30 * 5;
public int DurationTime => GameData.commonSkillTime / 2;
private readonly object commonSkillLock = new object();
public object ActiveSkillLock => commonSkillLock;

@@ -132,6 +132,8 @@ namespace GameClass.GameObj
return new CanBeginToCharge();
case ActiveSkillType.Punish:
return new Punish();
case ActiveSkillType.JumpyBomb:
return new JumpyBomb();
default:
return new NullSkill();
}
@@ -149,6 +151,8 @@ namespace GameClass.GameObj
return ActiveSkillType.CanBeginToCharge;
case Punish:
return ActiveSkillType.Punish;
case JumpyBomb:
return ActiveSkillType.JumpyBomb;
default:
return ActiveSkillType.Null;
}


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

@@ -251,7 +251,7 @@ namespace GameClass.GameObj
}
public bool CanSee(Character player, GameObj gameObj)
{
if ((gameObj.Type == GameObjType.Character) && !((Character)gameObj).IsInvisible) return false;
if ((gameObj.Type == GameObjType.Character) && !((Character)gameObj).HasInvisible) return false;
XY pos1 = player.Position;
XY pos2 = gameObj.Position;
XY del = pos1 - pos2;


+ 6
- 6
logic/GameClass/GameObj/Prop.cs View File

@@ -52,13 +52,13 @@ namespace GameClass.GameObj
/// <summary>
/// 复活甲
/// </summary>
public sealed class AddLifeOrAp : Prop
public sealed class AddLifeOrClairaudience : Prop
{
public AddLifeOrAp(XY initPos, PlaceType placeType) :
public AddLifeOrClairaudience(XY initPos, PlaceType placeType) :
base(initPos, placeType)
{
}
public override PropType GetPropType() => PropType.AddLifeOrAp;
public override PropType GetPropType() => PropType.AddLifeOrClairaudience;
}
public sealed class AddHpOrAp : Prop
{
@@ -141,8 +141,8 @@ namespace GameClass.GameObj
{
case PropType.AddSpeed:
return new AddSpeed(pos, place);
case PropType.AddLifeOrAp:
return new AddLifeOrAp(pos, place);
case PropType.AddLifeOrClairaudience:
return new AddLifeOrClairaudience(pos, place);
case PropType.ShieldOrSpear:
return new ShieldOrSpear(pos, place);
case PropType.AddHpOrAp:
@@ -158,4 +158,4 @@ namespace GameClass.GameObj
}
}
}
}
}

+ 18
- 8
logic/Gaming/ActionManager.cs View File

@@ -17,8 +17,16 @@ namespace Gaming
{

// 人物移动
private void SkillWhenMove(Character player, IGameObj collisionObj)
private static void SkillWhenColliding(Character player, IGameObj collisionObj)
{
if (collisionObj.Type == GameObjType.Bullet)
{
if (((Bullet)collisionObj).TypeOfBullet == BulletType.JumpyDumpty)
{
if (AttackManager.BeStunned((Character)collisionObj, ((Bullet)collisionObj).AP / GameData.timeFactorOfGhostFainting))
player.AddScore(GameData.StudentScoreTrickerBeStunned(((Bullet)collisionObj).AP / GameData.timeFactorOfGhostFainting));
}
}
if (player.UseIActiveSkill(ActiveSkillType.CanBeginToCharge).IsBeingUsed && collisionObj.Type == GameObjType.Character && ((Character)collisionObj).IsGhost())
{
if (AttackManager.BeStunned((Character)collisionObj, GameData.TimeOfGhostFaintingWhenCharge))
@@ -188,7 +196,7 @@ namespace Gaming
playerTreated = gameMap.StudentForInteract(player.Position);
if (playerTreated == null) return false;
}
if ((!player.Commandable()) || player.PlayerState == PlayerStateType.Treating ||
if (player == playerTreated || (!player.Commandable()) || player.PlayerState == PlayerStateType.Treating ||
(!playerTreated.Commandable()) ||
playerTreated.HP == playerTreated.MaxHp || !GameData.ApproachToInteract(playerTreated.Position, player.Position))
return false;
@@ -254,11 +262,12 @@ namespace Gaming
playerRescued = gameMap.StudentForInteract(player.Position);
if (playerRescued == null) return false;
}
if ((!player.Commandable()) || playerRescued.PlayerState != PlayerStateType.Addicted || !GameData.ApproachToInteract(playerRescued.Position, player.Position))
if ((!player.Commandable()) || playerRescued.PlayerState != PlayerStateType.Addicted || player == playerRescued
|| !GameData.ApproachToInteract(playerRescued.Position, player.Position) || playerRescued.TimeOfRescue > 0)
return false;
player.PlayerState = PlayerStateType.Rescuing;
playerRescued.PlayerState = PlayerStateType.Rescued;
player.TimeOfRescue = 0;
new Thread
(
() =>
@@ -267,7 +276,7 @@ namespace Gaming
loopCondition: () => playerRescued.PlayerState == PlayerStateType.Rescued && player.PlayerState == PlayerStateType.Rescuing && gameMap.Timer.IsGaming && GameData.ApproachToInteract(playerRescued.Position, player.Position),
loopToDo: () =>
{
player.TimeOfRescue += GameData.frameDuration;
playerRescued.TimeOfRescue += GameData.frameDuration;
},
timeInterval: GameData.frameDuration,
finallyReturn: () => 0,
@@ -277,16 +286,17 @@ namespace Gaming

if (playerRescued.PlayerState == PlayerStateType.Rescued)
{
if (player.TimeOfRescue >= GameData.basicTimeOfRescue)
if (playerRescued.TimeOfRescue >= GameData.basicTimeOfRescue)
{
playerRescued.PlayerState = PlayerStateType.Null;
playerRescued.HP = GameData.RemainHpWhenAddLife;
player.AddScore(GameData.StudentScoreRescue);
}
else
playerRescued.PlayerState = PlayerStateType.Addicted;
}
if (player.PlayerState == PlayerStateType.Rescuing) player.PlayerState = PlayerStateType.Null;
player.TimeOfRescue = 0;
playerRescued.TimeOfRescue = 0;
}
)
{ IsBackground = true }.Start();
@@ -494,7 +504,7 @@ namespace Gaming
gameMap: gameMap,
OnCollision: (obj, collisionObj, moveVec) =>
{
SkillWhenMove((Character)obj, collisionObj);
SkillWhenColliding((Character)obj, collisionObj);
//if (collisionObj is Mine)
//{
// ActivateMine((Character)obj, (Mine)collisionObj);


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

@@ -33,7 +33,7 @@ namespace Gaming
Debugger.Output(obj, " end move at " + obj.Position.ToString() + " At time: " + Environment.TickCount64);

#endif
if (obj.CanMove)
if (obj.CanMove && ((Bullet)obj).TypeOfBullet != BulletType.JumpyDumpty)
BulletBomb((Bullet)obj, null);
}
);
@@ -124,10 +124,6 @@ namespace Gaming
gameMap.GameObjLockDict[GameObjType.EmergencyExit].ExitReadLock();
}
}

// player.Reset();
// ((Character?)bullet.Parent)?.AddScore(GameData.addScoreWhenKillOneLevelPlayer); // 给击杀者加分

}

private void BombObj(Bullet bullet, GameObj objBeingShot)
@@ -174,10 +170,10 @@ namespace Gaming
#endif
bullet.CanMove = false;

if (gameMap.Remove(bullet) && bullet.IsToBomb)
if (gameMap.Remove(bullet) && bullet.BulletBombRange > 0)
gameMap.Add(new BombedBullet(bullet));

if (!bullet.IsToBomb)
if (bullet.BulletBombRange == 0)
{
if (objBeingShot == null)
{
@@ -201,7 +197,14 @@ namespace Gaming
return;
}


if (bullet.TypeOfBullet == BulletType.BombBomb)
{
bullet.Parent.BulletOfPlayer = BulletType.JumpyDumpty;
Attack((Character)bullet.Parent, 0.0);
Attack((Character)bullet.Parent, Math.PI);
Attack((Character)bullet.Parent, Math.PI / 2.0);
Attack((Character)bullet.Parent, Math.PI * 3.0 / 2.0);
}
BombObj(bullet, objBeingShot);
if (bullet.RecoveryFromHit > 0)
{
@@ -304,7 +307,7 @@ namespace Gaming
beAttackedList.Clear();
}

public bool Attack(Character? player, double angle) // 射出去的子弹泼出去的水(狗头)
public bool Attack(Character? player, double angle)
{ // 子弹如果没有和其他物体碰撞,将会一直向前直到超出人物的attackRange
if (player == null)
{


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

@@ -31,10 +31,10 @@ namespace Gaming
player.AddSpear(GameData.PropDuration);
else player.AddShield(GameData.PropDuration);
break;
case PropType.AddLifeOrAp:
case PropType.AddLifeOrClairaudience:
if (!player.IsGhost())
player.AddLIFE(GameData.PropDuration);
else player.AddAp(GameData.PropDuration);
else player.AddClairaudience(GameData.PropDuration);
break;
case PropType.AddSpeed:
player.AddMoveSpeed(GameData.PropDuration);
@@ -118,7 +118,7 @@ namespace Gaming

private Prop ProduceOnePropNotKey(Random r, XY Pos)
{
return PropFactory.GetProp((PropType)r.Next(0, GameData.numOfPropTypeNotKey), Pos, gameMap.GetPlaceType(Pos));
return PropFactory.GetProp((PropType)r.Next(GameData.numOfTeachingBuilding + 1, GameData.numOfPropSpecies + 1), Pos, gameMap.GetPlaceType(Pos));
}

private Chest GetChest(Random r)


+ 11
- 10
logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs View File

@@ -36,7 +36,7 @@ namespace Gaming
return ActiveSkillEffect(skill, player, () =>
{
player.AddMoveSpeed(skill.DurationTime, 3.0);
//See SkillWhenMove in ActionManager
//See SkillWhenColliding in ActionManager
},
() =>
{ });
@@ -45,21 +45,22 @@ namespace Gaming

public static bool BecomeInvisible(Character player)
{
return ActiveSkillEffect(player.UseIActiveSkill(ActiveSkillType.BecomeInvisible), player, () =>
IActiveSkill activeSkill = player.UseIActiveSkill(ActiveSkillType.BecomeInvisible);
return ActiveSkillEffect(activeSkill, player, () =>
{
player.IsInvisible = true;
player.AddInvisible(activeSkill.DurationTime);
Debugger.Output(player, "become invisible!");
},
() =>
{ player.IsInvisible = false; });
{ });
}

public bool NuclearWeapon(Character player)
public bool JumpyBomb(Character player)
{
return ActiveSkillEffect(player.UseIActiveSkill(ActiveSkillType.NuclearWeapon), player, () =>
return ActiveSkillEffect(player.UseIActiveSkill(ActiveSkillType.JumpyBomb), player, () =>
{
player.BulletOfPlayer = BulletType.AtomBomb;
Debugger.Output(player, "uses atombomb!");
player.BulletOfPlayer = BulletType.BombBomb;
Debugger.Output(player, "uses jumpybomb!");
},
() =>
{ player.BulletOfPlayer = player.OriBulletOfPlayer; });
@@ -91,8 +92,8 @@ namespace Gaming
|| player.PlayerState == PlayerStateType.UsingSkill || player.PlayerState == PlayerStateType.LockingOrOpeningTheDoor || player.PlayerState == PlayerStateType.OpeningTheChest)
&& gameMap.CanSee(player, character))
{
if (AttackManager.BeStunned(character, GameData.TimeOfGhostFaintingWhenPunish + (player.MaxHp - player.HP) / GameData.TimeFactorOfGhostFainting))
player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.TimeOfGhostFaintingWhenPunish + (player.MaxHp - player.HP) / GameData.TimeFactorOfGhostFainting));
if (AttackManager.BeStunned(character, GameData.TimeOfGhostFaintingWhenPunish + (player.MaxHp - player.HP) / GameData.timeFactorOfGhostFainting))
player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.TimeOfGhostFaintingWhenPunish + (player.MaxHp - player.HP) / GameData.timeFactorOfGhostFainting));
break;
}
}


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

@@ -28,6 +28,9 @@ namespace Gaming
case ActiveSkillType.Punish:
Punish(character);
break;
case ActiveSkillType.JumpyBomb:
JumpyBomb(character);
break;
default:
return false;
}


+ 2
- 0
logic/Preparation/Interface/ICharacter.cs View File

@@ -11,6 +11,8 @@ namespace Preparation.Interface
public void AddScore(int add);
public double Vampire { get; }
public PlayerStateType PlayerState { get; set; }
public BulletType BulletOfPlayer { get; set; }

public bool IsGhost();
}
}

+ 42
- 8
logic/Preparation/Interface/IOccupation.cs View File

@@ -16,7 +16,7 @@ namespace Preparation.Interface
public int ViewRange { get; }
public int TimeOfOpeningOrLocking { get; }
public int SpeedOfClimbingThroughWindows { get; }
public int TimeOfOpenChest { get; }
public int SpeedOfOpenChest { get; }
}

public interface IGhost : IOccupation
@@ -32,7 +32,7 @@ namespace Preparation.Interface

public class Assassin : IGhost
{
private const int moveSpeed = GameData.basicMoveSpeed * 473 / 380;
private const int moveSpeed = (int)(GameData.basicMoveSpeed * 473.0 / 380);
public int MoveSpeed => moveSpeed;

private const int maxHp = GameData.basicHp;
@@ -61,8 +61,42 @@ namespace Preparation.Interface
public int speedOfClimbingThroughWindows = GameData.basicGhostSpeedOfClimbingThroughWindows;
public int SpeedOfClimbingThroughWindows => speedOfClimbingThroughWindows;

public int timeOfOpenChest = GameData.basicSpeedOfOpenChest;
public int TimeOfOpenChest => timeOfOpenChest;
public int speedOfOpenChest = GameData.basicSpeedOfOpenChest;
public int SpeedOfOpenChest => speedOfOpenChest;
}
public class Klee : IGhost
{
private const int moveSpeed = (int)(GameData.basicMoveSpeed * 155 / 127);
public int MoveSpeed => moveSpeed;

private const int maxHp = GameData.basicHp;
public int MaxHp => maxHp;

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

public BulletType InitBullet => BulletType.CommonAttackOfGhost;

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

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

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

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

public int timeOfOpeningOrLocking = (int)(GameData.basicSpeedOfOpeningOrLocking / 1.1);
public int TimeOfOpeningOrLocking => timeOfOpeningOrLocking;

public int speedOfClimbingThroughWindows = (int)(GameData.basicGhostSpeedOfClimbingThroughWindows / 1.1);
public int SpeedOfClimbingThroughWindows => speedOfClimbingThroughWindows;

public int speedOfOpenChest = (int)(GameData.basicSpeedOfOpenChest * 1.1);
public int SpeedOfOpenChest => speedOfOpenChest;
}
public class Teacher : IStudent
{
@@ -104,8 +138,8 @@ namespace Preparation.Interface
public int speedOfClimbingThroughWindows = GameData.basicStudentSpeedOfClimbingThroughWindows / 2;
public int SpeedOfClimbingThroughWindows => speedOfClimbingThroughWindows;

public int timeOfOpenChest = GameData.basicSpeedOfOpenChest;
public int TimeOfOpenChest => timeOfOpenChest;
public int speedOfOpenChest = GameData.basicSpeedOfOpenChest;
public int SpeedOfOpenChest => speedOfOpenChest;
}
public class Athlete : IStudent
{
@@ -147,7 +181,7 @@ namespace Preparation.Interface
public int speedOfClimbingThroughWindows = GameData.basicStudentSpeedOfClimbingThroughWindows * 12 / 10;
public int SpeedOfClimbingThroughWindows => speedOfClimbingThroughWindows;

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

+ 17
- 17
logic/Preparation/Utility/EnumType.cs View File

@@ -53,31 +53,30 @@ namespace Preparation.Utility
public enum BulletType // 子弹类型
{
Null = 0,
OrdinaryBullet = 1, // 普通子弹
AtomBomb = 2, // 原子弹
FastBullet = 3, // 快速子弹
LineBullet = 4, // 直线子弹
FlyingKnife = 5, //飞刀
CommonAttackOfGhost = 6,
FlyingKnife = 1, //飞刀
CommonAttackOfGhost = 2,
JumpyDumpty = 3,
BombBomb = 4,
// Ram = 7,
}
public enum PropType // 道具类型
{
{//numOfPropSpecies 见Gamedata
Null = 0,
AddSpeed = 1,
AddLifeOrAp = 2,
AddHpOrAp = 3,
ShieldOrSpear = 4,
Key3 = 5,
Key5 = 6,
Key6 = 7,
Key3 = 1,
Key5 = 2,
Key6 = 3,
AddSpeed = 4,
AddLifeOrClairaudience = 5,
AddHpOrAp = 6,
ShieldOrSpear = 7,
RecoveryFromDizziness = 8,
}
public enum CharacterType // 职业
{
Null = 0,
Assassin = 1,
Athlete = 2,
RecoverAfterBattle = 3,
Klee = 3,
SpeedUpWhenLeavingGrass = 4,
Teacher = 5,
PSkill5 = 6
@@ -87,7 +86,7 @@ namespace Preparation.Utility
Null = 0,
BecomeInvisible = 1,
BecomeVampire = 2,
NuclearWeapon = 3,
JumpyBomb = 3,
SuperFast = 4,
UseKnife = 5,
CanBeginToCharge = 6,
@@ -111,8 +110,9 @@ namespace Preparation.Utility
Shield = 3,
Spear = 4,
AddAp = 5,
Clairaudience = 6,
Invisible = 7,
}

public enum PlaceType
{
Null = 0,


+ 18
- 8
logic/Preparation/Utility/GameData.cs View File

@@ -35,6 +35,14 @@ namespace Preparation.Utility
{
return gameObjType != GameObjType.Null && gameObjType != GameObjType.Grass && gameObjType != GameObjType.OutOfBoundBlock && gameObjType != GameObjType.Window && gameObjType != GameObjType.Wall;
}
/* public static bool Collide(GameObjType gameObjType)
{
return gameObjType != GameObjType.Null && gameObjType != GameObjType.Grass
&& gameObjType != GameObjType.OutOfBoundBlock && gameObjType != GameObjType.Window
&& gameObjType != GameObjType.Bullet&&gameObjType != GameObjType.Prop
&&gameObjType != GameObjType.PickedProp&&gameObjType != GameObjType.BombedBullet
&&gameObjType != GameObjType.EmergencyExit&&gameObjType != GameObjType.Doorway;
}*/

public static XY GetCellCenterPos(int x, int y) // 求格子的中心坐标
{
@@ -59,10 +67,12 @@ namespace Preparation.Utility
}
public static bool ApproachToInteract(XY pos1, XY pos2)
{
if (pos1 == pos2) return false;
return Math.Abs(PosGridToCellX(pos1) - PosGridToCellX(pos2)) <= 1 && Math.Abs(PosGridToCellY(pos1) - PosGridToCellY(pos2)) <= 1;
}
public static bool ApproachToInteractInACross(XY pos1, XY pos2)
{
if (pos1 == pos2) return false;
return (Math.Abs(PosGridToCellX(pos1) - PosGridToCellX(pos2)) + Math.Abs(PosGridToCellY(pos1) - PosGridToCellY(pos2))) <= 1;
}
#endregion
@@ -104,6 +114,7 @@ namespace Preparation.Utility
return characterType switch
{
CharacterType.Assassin => true,
CharacterType.Klee => true,
_ => false,
};
}
@@ -159,13 +170,13 @@ namespace Preparation.Utility
public const int basicCD = 3000; // 初始子弹冷却
public const int basicCastTime = 500;//基本前摇时间
public const int basicBackswing = 818;//基本后摇时间
public const int basicRecoveryFromHit = 4300;//基本命中攻击恢复时长
public const int basicRecoveryFromHit = 3700;//基本命中攻击恢复时长
public const int basicStunnedTimeOfStudent = 4130;

public const int basicBulletMoveSpeed = 2700; // 基本子弹移动速度,单位:s-1
public const double basicRemoteAttackRange = 9000; // 基本远程攻击范围
public const double basicAttackShortRange = 2700; // 基本近程攻击范围
public const double basicBulletBombRange = 3000; // 基本子弹爆炸范围
public const int basicBulletMoveSpeed = 1800; // 基本子弹移动速度,单位:s-1
public const double basicRemoteAttackRange = 3000; // 基本远程攻击范围
public const double basicAttackShortRange = 900; // 基本近程攻击范围
public const double basicBulletBombRange = 1000; // 基本子弹爆炸范围
#endregion
#region 技能相关
public const int maxNumOfSkill = 3;
@@ -181,11 +192,9 @@ namespace Preparation.Utility
/// Punish
/// </summary>
public const int TimeOfGhostFaintingWhenPunish = 3070;
public const int TimeFactorOfGhostFainting = 1000;
public const int timeFactorOfGhostFainting = 250;
#endregion
#region 道具相关
public const int MinPropTypeNum = 1;
public const int MaxPropTypeNum = 10;
public const int PropRadius = numOfPosGridPerCell / 2;
public const int PropMoveSpeed = 3000;
public const int PropMaxMoveDistance = 15 * numOfPosGridPerCell;
@@ -196,6 +205,7 @@ namespace Preparation.Utility
public const int ApSpearAdd = basicApOfGhost * 6 / 10;
public const int RemainHpWhenAddLife = 100;

public const int numOfPropSpecies = 8;
public const int numOfKeyEachArea = 2;
public const int numOfPropTypeNotKey = 4;
public const int numOfTeachingBuilding = 3;


+ 18
- 0
logic/Preparation/Utility/XY.cs View File

@@ -54,6 +54,14 @@ namespace Preparation.Utility
{
return new XY(v1.x - v2.x, v1.y - v2.y);
}
public static bool operator ==(XY v1, XY v2)
{
return v1.x == v2.x && v1.y == v2.y;
}
public static bool operator !=(XY v1, XY v2)
{
return v1.x != v2.x || v1.y != v2.y;
}
public static double Distance(XY p1, XY p2)
{
return Math.Sqrt(((long)(p1.x - p2.x) * (p1.x - p2.x)) + ((long)(p1.y - p2.y) * (p1.y - p2.y)));
@@ -66,5 +74,15 @@ namespace Preparation.Utility
{
return Math.Atan2(y, x);
}

public override bool Equals(object obj)
{
throw new NotImplementedException();
}

public override int GetHashCode()
{
throw new NotImplementedException();
}
}
}

+ 6
- 2
logic/Server/CopyInfo.cs View File

@@ -50,7 +50,7 @@ namespace Server
{
case Preparation.Utility.PropType.AddSpeed:
return Protobuf.PropType.AddSpeed;
case Preparation.Utility.PropType.AddLifeOrAp:
case Preparation.Utility.PropType.AddLifeOrClairaudience:
return Protobuf.PropType.AddLifeOrAp;
case Preparation.Utility.PropType.AddHpOrAp:
return Protobuf.PropType.AddHpOrAp;
@@ -74,7 +74,7 @@ namespace Server
case Protobuf.PropType.AddSpeed:
return Preparation.Utility.PropType.AddSpeed;
case Protobuf.PropType.AddLifeOrAp:
return Preparation.Utility.PropType.AddLifeOrAp;
return Preparation.Utility.PropType.AddLifeOrClairaudience;
case Protobuf.PropType.AddHpOrAp:
return Preparation.Utility.PropType.AddHpOrAp;
case Protobuf.PropType.ShieldOrSpear:
@@ -195,6 +195,8 @@ namespace Server
{
case Preparation.Utility.CharacterType.Assassin:
return Protobuf.TrickerType.Assassin;
case Preparation.Utility.CharacterType.Klee:
return Protobuf.TrickerType._2;
default:
return Protobuf.TrickerType.NullTrickerType;
}
@@ -206,6 +208,8 @@ namespace Server
{
case Protobuf.TrickerType.Assassin:
return Preparation.Utility.CharacterType.Assassin;
case Protobuf.TrickerType._2:
return Preparation.Utility.CharacterType.Klee;
default:
return Preparation.Utility.CharacterType.Null;
}


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

@@ -240,7 +240,13 @@ namespace Server
{
switch (n)
{
case 0: return Protobuf.PlaceType.Land;
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
return Protobuf.PlaceType.Land;
case 6: return Protobuf.PlaceType.Wall;
case 7: return Protobuf.PlaceType.Grass;
case 8: return Protobuf.PlaceType.Classroom;


+ 0
- 142
logic/Server/Properties/EnumType.cs View File

@@ -1,142 +0,0 @@

namespace Preparation.Utility
{
/// <summary>
/// 存放所有用到的枚举类型
/// </summary>
public enum PlayerStateType
{
Null = 0,
Addicted = 1,
Escaped = 2,
Swinging = 3,//指后摇
Deceased = 4,
Moving = 5,
Treating = 6,
Rescuing = 7,
Fixing = 8,
Treated = 9,
Rescued = 10,
Stunned = 11,
TryingToAttack = 12,//指前摇
LockingOrOpeningTheDoor = 13,
OpeningTheChest = 14,
ClimbingThroughWindows = 15,
UsingSkill = 16,
OpeningTheDoorway = 17,
}
public enum GameObjType
{
Null = 0,
Character = 1,
Prop = 2,
PickedProp = 3,
Bullet = 4,
BombedBullet = 5,

Wall = 6,
Grass = 7,
Generator = 8, // 发电机
Doorway = 9,
EmergencyExit = 10,
OutOfBoundBlock = 11, // 范围外
Window = 12,
Door = 13,
Chest = 14,
}
public enum ShapeType
{
Null = 0,
Circle = 1, // 子弹和人物为圆形,格子为方形
Square = 2
}
public enum BulletType // 子弹类型
{
Null = 0,
OrdinaryBullet = 1, // 普通子弹
AtomBomb = 2, // 原子弹
FastBullet = 3, // 快速子弹
LineBullet = 4, // 直线子弹
FlyingKnife = 5, //飞刀
CommonAttackOfGhost = 6,
// Ram = 7,
}
public enum PropType // 道具类型
{
Null = 0,
AddSpeed = 1,
AddLifeOrAp = 2,
AddHpOrAp = 3,
ShieldOrSpear = 4,
Key3 = 5,
Key5 = 6,
Key6 = 7,
}
public enum CharacterType // 职业
{
Null = 0,
Assassin = 1,
Athlete = 2,
RecoverAfterBattle = 3,
SpeedUpWhenLeavingGrass = 4,
Teacher = 5,
PSkill5 = 6
}
public enum ActiveSkillType // 主动技能
{
Null = 0,
BecomeInvisible = 1,
BecomeVampire = 2,
NuclearWeapon = 3,
SuperFast = 4,
UseKnife = 5,
CanBeginToCharge = 6,
Punish = 7,
}
public enum PassiveSkillType
{
Null = 0,
BecomeInvisible = 1,
BecomeVampire = 2,
NuclearWeapon = 3,
SuperFast = 4,
ASkill4 = 5,
ASkill5 = 6
}
public enum BuffType // buff
{
Null = 0,
AddSpeed = 1,
AddLIFE = 2,
Shield = 3,
Spear = 4,
AddAp = 5,
}

public enum PlaceType
{
Null = 0,
BirthPoint1 = 1,//必须从1开始
BirthPoint2 = 2,
BirthPoint3 = 3,
BirthPoint4 = 4,
BirthPoint5 = 5,
Wall = 6,
Grass = 7,
Generator = 8, // 发电机
Doorway = 9,
EmergencyExit = 10,
Window = 11,
Door3 = 12,
Door5 = 13,
Door6 = 14,
Chest = 15,
}
public enum BgmType
{
Null = 0,
GhostIsComing = 1,
StudentIsApproaching = 2,
GeneratorIsBeingFixed = 3,
}
}

+ 0
- 4
logic/Server/Server.csproj View File

@@ -7,10 +7,6 @@
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<Compile Remove="Properties\EnumType.cs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="FrameRateTask" Version="1.2.0" />


+ 1
- 1
logic/cmd/gameServer.cmd View File

@@ -4,7 +4,7 @@ start cmd /k ..\Server\bin\Debug\net6.0\Server.exe --ip 0.0.0.0 --port 8888 --s

ping -n 2 127.0.0.1 > NUL

start cmd /k ..\Client\bin\Debug\net6.0-windows\Client.exe --cl --port 8888 --characterID 4 --type 2 --occupation 1
start cmd /k ..\Client\bin\Debug\net6.0-windows\Client.exe --cl --port 8888 --characterID 4 --type 2 --occupation 2

ping -n 2 127.0.0.1 > NUL



+ 6
- 160
logic/规则Logic.md View File

@@ -154,7 +154,7 @@
- 子弹爆炸范围
- 子弹攻击力
- 是否可以穿墙
- 是否可以爆炸
- 是否为远程攻击
- 移动速度
- 子弹类型

@@ -347,7 +347,7 @@
| 道具 | 对学生增益 | [学生得分条件] | 对搞蛋鬼增益 | [搞蛋鬼得分条件] |
| :-------- | :-------------------------------------- | :-----------------| :-------------------------------------- |:-----------------|
| AddSpeed | 提高移动速度,持续10s |不得分| 提高移动速度,持续10s |不得分|
| AddLifeOrAp |若在10s内Hp归零,该增益消失以使Hp保留100|在10s内Hp归零,得分? |10秒内下一次攻击增伤1800000|10秒内有一次攻击,得分? |
| AddLifeOrClairaudience |若在10s内Hp归零,该增益消失以使Hp保留100|在10s内Hp归零,得分? |10秒内下一次攻击增伤1800000|10秒内有一次攻击,得分? |
| AddHpOrAp |回血1500000 | 回血成功 | 10秒内下一次攻击增伤1800000|10秒内有一次攻击,得分? |
| ShieldOrSpear | 10秒内能抵挡一次伤害 | 10秒内成功抵挡一次伤害 |10秒内下一次攻击能破盾,如果对方无盾,则增伤900000| 10秒内攻击中学生|
| Key3 | 能开启3教的门 |不得分| 能开启3教的门 |不得分|
@@ -494,168 +494,13 @@
public int SkillCD => GameData.commonSkillCD;
public int DurationTime => 0;
~~~
使用瞬间,在视野范围内的捣蛋鬼会被眩晕(3070+ 玩家损失的血量 / 1000)ms,
使用瞬间,在可视范围内的使用技能状态中、攻击前后摇、开锁门、开箱的捣蛋鬼会被眩晕(3070+ 玩家损失的血量 / 1000)ms,


## 游戏数据

### 基本常数
~~~csharp
public const int numOfStepPerSecond = 20; // 每秒行走的步数
public const int frameDuration = 50; // 每帧时长
public const int checkInterval = 50; // 检查位置标志、补充子弹的帧时长

public const long gameDuration = 600000; // 游戏时长600000ms = 10min

public const int MinSpeed = 1; // 最小速度
public const int MaxSpeed = int.MaxValue; // 最大速度
#endregion
#region 地图相关
public const int numOfPosGridPerCell = 1000; // 每格的【坐标单位】数
public const int lengthOfMap = 50000; // 地图长度
public const int rows = 50; // 行数
public const int cols = 50; // 列数

public const int numOfBirthPoint = 5;
public const int numOfGenerator = 9;
public const int numOfChest = 8;

public static XY GetCellCenterPos(int x, int y) // 求格子的中心坐标
{
XY ret = new(x * numOfPosGridPerCell + numOfPosGridPerCell / 2, y * numOfPosGridPerCell + numOfPosGridPerCell / 2);
return ret;
}
public static int PosGridToCellX(XY pos) // 求坐标所在的格子的x坐标
{
return pos.x / numOfPosGridPerCell;
}
public static int PosGridToCellY(XY pos) // 求坐标所在的格子的y坐标
{
return pos.y / numOfPosGridPerCell;
}
public static XY PosGridToCellXY(XY pos) // 求坐标所在的格子的Xy坐标
{
return new XY(pos.x / numOfPosGridPerCell, pos.y / numOfPosGridPerCell);
}
~~~

### 角色相关
~~~csharp
public const int numOfStudent = 4;
public const int characterRadius = numOfPosGridPerCell / 2 / 5 * 4; // 人物半径

public const int basicTreatSpeed = 100;
public const int basicFixSpeed = 100;
public const int basicSpeedOfOpeningOrLocking = 3280;
public const int basicStudentSpeedOfClimbingThroughWindows = 611;
public const int basicGhostSpeedOfClimbingThroughWindows = 1270;
public const int basicSpeedOfOpenChest = 1000;

public const int basicHp = 3000000; // 初始血量
public const int basicMaxGamingAddiction = 60000;//基本完全沉迷时间
public const int BeginGamingAddiction = 10003;
public const int MidGamingAddiction = 30000;
public const int basicTreatmentDegree = 1500000;
public const int basicTimeOfRescue = 1000;

public const int basicMoveSpeed = 1270; // 基本移动速度,单位:s-1
public const int characterMaxSpeed = 12000; // 最大速度
public const int basicBulletMoveSpeed = 2700; // 基本子弹移动速度,单位:s-1

public const double basicConcealment = 1.0;
public const int basicAlertnessRadius = 10700;
public const int basicViewRange = 5 * numOfPosGridPerCell;
public const int maxNumOfPropInPropInventory = 3;
~~~

### 得分相关
~~~csharp
public static int TrickerScoreAttackStudent(int damage)
{
return damage * 100 / basicApOfGhost;
}
public const int TrickerScoreStudentBeAddicted = 50;
public const int TrickerScoreStudentBeStunned = 25;
public const int TrickerScoreStudentDie = 1000;

public static int StudentScoreFix(int degreeOfFix)
{
return degreeOfFix;
}
public const int StudentScoreFixed = 25;
public static int StudentScorePinDown(int timeOfPiningDown)
{
return 0;
}
public const int StudentScoreTrickerBeStunned = 25;
public const int StudentScoreRescue = 100;
public static int StudentScoreTreat(int degree)
{
return degree;
}
public const int StudentScoreEscape = 1000;
public const int ScorePropRemainHp = 20;
public const int ScorePropUseShield = 20;
public const int ScorePropUseSpear = 20;
public const int ScorePropAddAp = 10;
public const int ScorePropAddHp = 50;

~~~
### 攻击与子弹相关
~~~csharp
public const int basicApOfGhost = 1500000; // 捣蛋鬼攻击力
public const int MinAP = 0; // 最小攻击力
public const int MaxAP = int.MaxValue; // 最大攻击力

public const int factorDamageGenerator = 2;//子弹对电机的破坏=factorDamageGenerator*AP;
public const int bulletRadius = 200; // 默认子弹半径
public const int basicBulletNum = 3; // 基本初始子弹量

public const int basicCD = 3000; // 初始子弹冷却
public const int basicCastTime = 500;//基本前摇时间
public const int basicBackswing = 818;//基本后摇时间
public const int basicRecoveryFromHit = 4300;//基本命中攻击恢复时长
public const int basicStunnedTimeOfStudent = 4130;

public const int basicBulletMoveSpeed = 2700; // 基本子弹移动速度,单位:s-1
public const double basicRemoteAttackRange = 9000; // 基本远程攻击范围
public const double basicAttackShortRange = 2700; // 基本近程攻击范围
public const double basicBulletBombRange = 3000; // 基本子弹爆炸范围
~~~

### 技能相关
~~~csharp
public const int maxNumOfSkill = 3;
public const int commonSkillCD = 30000; // 普通技能标准冷却时间
public const int commonSkillTime = 10000; // 普通技能标准持续时间
~~~
### 道具相关
~~~csharp
public const int MinPropTypeNum = 1;
public const int MaxPropTypeNum = 10;
public const int PropRadius = numOfPosGridPerCell / 2;
public const int PropMoveSpeed = 3000;
public const int PropMaxMoveDistance = 15 * numOfPosGridPerCell;
public const long PropProduceTime = 20000;
public const int PropDuration = 10000;

public const int ApPropAdd = basicApOfGhost * 12 / 10;
public const int ApSpearAdd = basicApOfGhost * 6 / 10;
public const int RemainHpWhenAddLife = 100;

public const int numOfKeyEachArea = 2;
public const int numOfPropTypeNotKey = 4;
public const int numOfTeachingBuilding = 3;
~~~
### 物体相关
~~~csharp
public const int degreeOfFixedGenerator = 10300000;
public const int degreeOfLockingOrOpeningTheDoor = 10000;
public const int degreeOfOpeningChest = 10000;
public const int degreeOfOpenedDoorway = 18000;
public const int maxNumOfPropInChest = 2;
public const int numOfGeneratorRequiredForRepair = 7;
public const int numOfGeneratorRequiredForEmergencyExit = 3;
~~~
请自行查看Logic/Preparation/Utility/GameData.cs

## 键鼠控制

@@ -686,3 +531,4 @@



>>>>>>> 4219415cba0600879a5b134a4067e729c868e84b

Loading…
Cancel
Save