using Preparation.Interface;
using Preparation.Utility;
using System;
using System.Collections.Generic;
using System.Threading;
namespace GameClass.GameObj
{
public partial class Character : Moveable, ICharacter // 负责人LHR摆烂终了
{
#region 装弹、攻击相关的基本属性及方法
private readonly object attackLock = new();
public IntNumUpdateByCD BulletNum { get; } = new IntNumUpdateByCD();
private int orgCD;
public int OrgCD
{
get
{
lock (attackLock)
return orgCD;
}
}
public readonly BulletType OriBulletOfPlayer;
private BulletType bulletOfPlayer;
public BulletType BulletOfPlayer
{
get
{
lock (attackLock)
{
return bulletOfPlayer;
}
}
set
{
lock (attackLock)
{
bulletOfPlayer = value;
orgCD = (BulletFactory.BulletCD(value));
BulletNum.SetCD(orgCD);
Debugger.Output(this, string.Format("'s CD has been set to: {0}.", orgCD));
BulletNum.SetPositiveMaxNumAndNum(BulletFactory.BulletNum(value));
}
}
}
///
/// 进行一次攻击
///
/// 攻击操作发出的子弹
public Bullet? Attack(double angle)
{
lock (attackLock)
{
if (bulletOfPlayer == BulletType.Null)
return null;
if (BulletNum.TrySub(1) == 1)
{
XY res = Position + new XY // 子弹紧贴人物生成。
(
(int)(Math.Abs((Radius + BulletFactory.BulletRadius(bulletOfPlayer)) * Math.Cos(angle))) * Math.Sign(Math.Cos(angle)),
(int)(Math.Abs((Radius + BulletFactory.BulletRadius(bulletOfPlayer)) * Math.Sin(angle))) * Math.Sign(Math.Sin(angle))
);
Bullet? bullet = BulletFactory.GetBullet(this, res, this.bulletOfPlayer);
if (bullet == null) return null;
if (TryAddAp()) bullet.AP.Add(GameData.ApPropAdd);
FacingDirection = new(angle, bullet.AttackDistance);
return bullet;
}
else
return null;
}
}
#endregion
#region 感知相关的基本属性及方法
private readonly object bgmLock = new();
private Dictionary bgmDictionary = new() { { BgmType.GhostIsComing, 0 }, { BgmType.StudentIsApproaching, 0 }, { BgmType.GeneratorIsBeingFixed, 0 } };
public Dictionary BgmDictionary
{
get
{
lock (bgmLock)
return bgmDictionary;
}
}
public void AddBgm(BgmType bgm, double value)
{
lock (bgmLock)
bgmDictionary[bgm] = value;
}
private readonly int alertnessRadius;
public int AlertnessRadius => alertnessRadius;
private readonly double concealment;
public double Concealment => concealment;
private readonly int viewRange;
public int ViewRange => viewRange;
#endregion
#region 交互相关的基本属性及方法
private readonly int speedOfOpeningOrLocking;
public int SpeedOfOpeningOrLocking
{
get => speedOfOpeningOrLocking;
}
private readonly int speedOfClimbingThroughWindows;
public int SpeedOfClimbingThroughWindows
{
get => speedOfClimbingThroughWindows;
}
private readonly int speedOfOpenChest;
public int SpeedOfOpenChest
{
get => speedOfOpenChest;
}
#endregion
#region 血量相关的基本属性及方法
public LongWithVariableRange HP { get; }
private readonly object vampireLock = new();
public object VampireLock => vampire;
private double vampire = 0; // 回血率:0-1之间
public double Vampire
{
get
{
lock (vampireLock)
return vampire;
}
set
{
lock (vampireLock)
{
if (value > 1)
vampire = 1;
else if (value < 0)
vampire = 0;
else
vampire = value;
}
}
}
public double OriVampire { get; protected set; }
private readonly object treatLock = new();
private int degreeOfTreatment = 0;
public int DegreeOfTreatment
{
get
{
lock (treatLock)
return degreeOfTreatment;
}
}
public void SetDegreeOfTreatment0()
{
lock (treatLock)
degreeOfTreatment = 0;
}
public bool AddDegreeOfTreatment(int value, Student whoTreatYou)
{
lock (treatLock)
{
degreeOfTreatment += value;
long addV = HP.TryAddAll(degreeOfTreatment);
if (addV == 0)
{
degreeOfTreatment = 0;
return false;
}
if (addV > 0)
{
whoTreatYou.AddScore(GameData.StudentScoreTreat(addV));
degreeOfTreatment = 0;
return true;
}
if (degreeOfTreatment >= GameData.basicTreatmentDegree)
{
whoTreatYou.AddScore(GameData.StudentScoreTreat(GameData.basicTreatmentDegree));
HP.AddPositiveV(GameData.basicTreatmentDegree);
degreeOfTreatment = 0;
return true;
}
return false;
}
}
#endregion
#region 查询状态相关的基本属性与方法
private PlayerStateType playerState = PlayerStateType.Null;
public PlayerStateType PlayerState
{
get
{
lock (actionLock)
{
if (playerState == PlayerStateType.Moving)
return (IsMoving) ? PlayerStateType.Moving : PlayerStateType.Null;
return playerState;
}
}
}
public bool NoHp()
{
lock (actionLock)
return (playerState == PlayerStateType.Deceased || playerState == PlayerStateType.Escaped || playerState == PlayerStateType.Addicted || playerState == PlayerStateType.Rescued);
}
public bool Commandable()
{
lock (actionLock)
{
return (playerState != PlayerStateType.Deceased && playerState != PlayerStateType.Escaped
&& playerState != PlayerStateType.Addicted && playerState != PlayerStateType.Rescued
&& playerState != PlayerStateType.Swinging && playerState != PlayerStateType.TryingToAttack
&& playerState != PlayerStateType.ClimbingThroughWindows
&& playerState != PlayerStateType.Stunned && playerState != PlayerStateType.Charmed);
}
}
public bool CanPinDown()
{
lock (actionLock)
{
return (playerState != PlayerStateType.Deceased && playerState != PlayerStateType.Escaped
&& playerState != PlayerStateType.Addicted && playerState != PlayerStateType.Rescued
&& playerState != PlayerStateType.Stunned && playerState != PlayerStateType.Charmed);
}
}
public bool InteractingWithMapWithoutMoving()
{
lock (actionLock)
{
return (playerState == PlayerStateType.LockingTheDoor || playerState == PlayerStateType.OpeningTheDoor
|| playerState == PlayerStateType.Fixing || playerState == PlayerStateType.OpeningTheChest);
}
}
public bool NullOrMoving()
{
lock (actionLock)
{
return (playerState == PlayerStateType.Null || playerState == PlayerStateType.Moving);
}
}
public bool CanBeAwed()
{
lock (actionLock)
return !(playerState == PlayerStateType.Deceased || playerState == PlayerStateType.Escaped
|| playerState == PlayerStateType.Addicted
|| playerState == PlayerStateType.Rescued || playerState == PlayerStateType.Treated
|| playerState == PlayerStateType.Stunned || playerState == PlayerStateType.Charmed
|| playerState == PlayerStateType.Null || playerState == PlayerStateType.Moving);
}
#endregion
#region 更改状态相关的属性和方法
private GameObj? whatInteractingWith = null;
public GameObj? WhatInteractingWith
{
get
{
lock (actionLock)
{
return whatInteractingWith;
}
}
}
private long ChangePlayerState(RunningStateType running, PlayerStateType value = PlayerStateType.Null, GameObj? gameObj = null)
{
//只能被SetPlayerState引用
if (runningState == RunningStateType.RunningSleepily)
{
ThreadNum.Release();
}
runningState = running;
whatInteractingWith = gameObj;
playerState = value;
return ++stateNum;
}
private long ChangePlayerStateInOneThread(RunningStateType running, PlayerStateType value = PlayerStateType.Null, GameObj? gameObj = null)
{
if (runningState == RunningStateType.RunningSleepily)
{
ThreadNum.Release();
}
runningState = running;
//只能被SetPlayerState引用
whatInteractingWith = gameObj;
playerState = value;
return stateNum;
}
public long SetPlayerState(RunningStateType runningState, PlayerStateType value = PlayerStateType.Null, IGameObj? obj = null)
{
GameObj? gameObj = (GameObj?)obj;
lock (actionLock)
{
PlayerStateType nowPlayerState = PlayerState;
if (nowPlayerState == value && value != PlayerStateType.UsingSkill) return -1;
GameObj? lastObj = whatInteractingWith;
switch (nowPlayerState)
{
case PlayerStateType.Escaped:
case PlayerStateType.Deceased:
return -1;
case PlayerStateType.Addicted:
if (value == PlayerStateType.Rescued)
return ChangePlayerStateInOneThread(runningState, value, gameObj);
else if (value == PlayerStateType.Null || value == PlayerStateType.Deceased)
return ChangePlayerState(runningState, value, gameObj);
else return -1;
case PlayerStateType.Rescued:
if (value == PlayerStateType.Addicted)
return ChangePlayerStateInOneThread(runningState, value, gameObj);
else if (value == PlayerStateType.Null || value == PlayerStateType.Deceased)
return ChangePlayerState(runningState, value, gameObj);
else return -1;
case PlayerStateType.TryingToAttack:
if (value == PlayerStateType.Addicted || value == PlayerStateType.Swinging
|| value == PlayerStateType.Deceased || value == PlayerStateType.Stunned
|| value == PlayerStateType.Charmed || value == PlayerStateType.Null)
return ChangePlayerState(runningState, value, gameObj);
else return -1;
case PlayerStateType.Stunned:
case PlayerStateType.Charmed:
if (value == PlayerStateType.Addicted || value == PlayerStateType.Deceased
|| value == PlayerStateType.Null)
return ChangePlayerState(runningState, value, gameObj);
else return -1;
case PlayerStateType.Swinging:
if (value == PlayerStateType.Addicted
|| value == PlayerStateType.Deceased || value == PlayerStateType.Stunned
|| value == PlayerStateType.Charmed || value == PlayerStateType.Null)
return ChangePlayerState(runningState, value, gameObj);
else return -1;
case PlayerStateType.ClimbingThroughWindows:
if (value == PlayerStateType.Addicted
|| value == PlayerStateType.Deceased || value == PlayerStateType.Stunned
|| value == PlayerStateType.Charmed || value == PlayerStateType.Null)
{
Window window = (Window)lastObj!;
if (window.Stage.x != 0) ReSetPos(window.Stage);
window.FinishClimbing();
return ChangePlayerState(runningState, value, gameObj);
}
else return -1;
case PlayerStateType.OpeningTheChest:
if (value == PlayerStateType.Rescued) return -1;
((Chest)lastObj!).OpenProgress.Set0();
return ChangePlayerState(runningState, value, gameObj);
case PlayerStateType.OpeningTheDoorway:
if (value == PlayerStateType.Rescued) return -1;
Doorway doorway = (Doorway)lastObj!;
doorway.StopOpenning();
return ChangePlayerState(runningState, value, gameObj);
case PlayerStateType.OpeningTheDoor:
if (value == PlayerStateType.Rescued) return -1;
Door door = (Door)lastObj!;
door.StopOpen();
ReleaseTool(door.KeyType);
return ChangePlayerState(runningState, value, gameObj);
case PlayerStateType.UsingSkill:
{
if (value == PlayerStateType.Rescued) return -1;
switch (CharacterType)
{
case CharacterType.TechOtaku:
{
if (typeof(CraftingBench).IsInstanceOfType(lastObj))
{
((CraftingBench)lastObj!).StopSkill();
return ChangePlayerState(runningState, value, gameObj);
}
else
{
if (value != PlayerStateType.UsingSkill)
((UseRobot)FindActiveSkill(ActiveSkillType.UseRobot)).NowPlayerID = (int)PlayerID;
return ChangePlayerState(runningState, value, gameObj);
}
}
case CharacterType.Assassin:
if (value == PlayerStateType.Moving) return StateNum;
else
{
TryDeleteInvisible();
return ChangePlayerState(runningState, value, gameObj);
}
default:
return ChangePlayerState(runningState, value, gameObj);
}
}
default:
if (value == PlayerStateType.Rescued) return -1;
return ChangePlayerState(runningState, value, gameObj);
}
}
}
public long SetPlayerStateNaturally()
{
lock (actionLock)
{
runningState = RunningStateType.Null;
whatInteractingWith = null;
playerState = PlayerStateType.Null;
return ++stateNum;
}
}
public bool ResetPlayerState(long state, RunningStateType running = RunningStateType.Null, PlayerStateType value = PlayerStateType.Null, IGameObj? obj = null)
{
lock (actionLock)
{
if (state != stateNum) return false;
this.runningState = running;
whatInteractingWith = (GameObj?)obj;
playerState = value;
++stateNum;
return true;
}
}
public bool ResetPlayerStateInOneThread(long state, RunningStateType running = RunningStateType.Null, PlayerStateType value = PlayerStateType.Null, IGameObj? obj = null)
{
lock (actionLock)
{
if (state != stateNum) return false;
this.runningState = running;
whatInteractingWith = (GameObj?)obj;
playerState = value;
return true;
}
}
public bool StartThread(long stateNum, RunningStateType runningState)
{
lock (ActionLock)
{
if (this.StateNum == stateNum)
{
this.runningState = runningState;
return true;
}
}
return false;
}
public bool TryToRemoveFromGame(PlayerStateType playerStateType)
{
lock (actionLock)
{
if (SetPlayerState(RunningStateType.RunningForcibly, playerStateType) == -1) return false;
TryToRemove();
CanMove.SetReturnOri(false);
position = GameData.PosWhoDie;
}
return true;
}
#endregion
private long score = 0;
public long Score
{
get => Interlocked.Read(ref score);
}
///
/// 加分
///
/// 增加量
public virtual void AddScore(long add)
{
Interlocked.Add(ref score, add);
//Debugger.Output(this, " 's score has been added to: " + score.ToString());
}
///
/// 角色所属队伍ID
///
public AtomicLong TeamID { get; } = new AtomicLong(long.MaxValue);
public AtomicLong PlayerID { get; } = new AtomicLong(long.MaxValue);
#region 道具和buff相关属性、方法
private readonly object inventoryLock = new();
public object InventoryLock => inventoryLock;
private Gadget[] propInventory = new Gadget[GameData.maxNumOfPropInPropInventory]
{new NullProp(), new NullProp(),new NullProp() };
public Gadget[] PropInventory
{
get
{
lock (inventoryLock)
return propInventory;
}
set
{
lock (inventoryLock)
propInventory = value;
}
}
///
/// 使用物品栏中的道具
///
/// 被使用的道具
public Gadget ConsumeProp(int indexing)
{
if (indexing < 0 || indexing >= GameData.maxNumOfPropInPropInventory)
return new NullProp();
lock (inventoryLock)
{
Gadget prop = propInventory[indexing];
if (!prop.IsUsable()) return new NullProp();
PropInventory[indexing] = new NullProp();
return prop;
}
}
public Gadget ConsumeProp(PropType propType)
{
if (propType == PropType.Null)
{
lock (inventoryLock)
{
for (int indexing = 0; indexing < GameData.maxNumOfPropInPropInventory; ++indexing)
{
if (PropInventory[indexing].IsUsable())
{
Gadget prop = PropInventory[indexing];
PropInventory[indexing] = new NullProp();
return prop;
}
}
}
}
else
{
lock (inventoryLock)
{
for (int indexing = 0; indexing < GameData.maxNumOfPropInPropInventory; ++indexing)
{
if (PropInventory[indexing].GetPropType() == propType && PropInventory[indexing].IsUsable())
{
Gadget prop = PropInventory[indexing];
PropInventory[indexing] = new NullProp();
return prop;
}
}
}
}
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;
}
}
}
}
///
/// 如果indexing==GameData.maxNumOfPropInPropInventory表明道具栏为满
///
public int IndexingOfAddProp()
{
int indexing = 0;
lock (inventoryLock)
for (; indexing < GameData.maxNumOfPropInPropInventory; ++indexing)
if (propInventory[indexing].GetPropType() == PropType.Null)
break;
return indexing;
}
public void AddMoveSpeed(int buffTime, double add = 1.0) => buffManager.AddMoveSpeed(add, buffTime, newVal =>
{ MoveSpeed.SetReturnOri(newVal < GameData.characterMaxSpeed ? newVal : GameData.characterMaxSpeed); },
OrgMoveSpeed);
public bool HasFasterSpeed => buffManager.HasFasterSpeed;
public void AddShield(int shieldTime) => buffManager.AddShield(shieldTime);
public bool HasShield => buffManager.HasShield;
public void AddLife(int LIFETime) => buffManager.AddLife(LIFETime);
public bool HasLIFE => buffManager.HasLIFE;
public void AddAp(int time) => buffManager.AddAp(time);
public bool HasAp => buffManager.HasAp;
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 Buff
{
get
{
Dictionary buff = new Dictionary();
foreach (BuffType type in buffTypeArray)
{
if (type != BuffType.Null)
buff.Add(type, GetBuffStatus(type));
}
return buff;
}
}
private bool GetBuffStatus(BuffType type)
{
switch (type)
{
case BuffType.Spear:
return this.HasSpear;
case BuffType.AddSpeed:
return this.HasFasterSpeed;
case BuffType.Shield:
return this.HasShield;
case BuffType.AddLife:
return this.HasLIFE;
case BuffType.AddAp:
return this.HasAp;
case BuffType.Clairaudience:
return this.HasClairaudience;
case BuffType.Invisible:
return this.HasInvisible;
default:
return false;
}
}
public void TryActivatingLIFE()
{
if (buffManager.TryActivatingLIFE())
{
AddScore(GameData.ScorePropRemainHp);
HP.SetPositiveV(GameData.RemainHpWhenAddLife);
}
}
public bool TryAddAp()
{
if (buffManager.TryAddAp())
{
AddScore(GameData.ScorePropAddAp);
return true;
}
return false;
}
public bool TryUseSpear()
{
return buffManager.TryUseSpear();
}
public bool TryDeleteInvisible()
{
return buffManager.TryDeleteInvisible();
}
public bool TryUseShield()
{
if (buffManager.TryUseShield())
{
AddScore(GameData.ScorePropUseShield);
return true;
}
return false;
}
#endregion
/* public override void Reset() // 要加锁吗?
{
lock (gameObjLock)
{
// _ = AddDeathCount();
base.Reset();
this.MoveSpeed = OrgMoveSpeed;
HP = MaxHp;
PropInventory = null;
BulletOfPlayer = OriBulletOfPlayer;
lock (gameObjLock)
bulletNum = maxBulletNum;
buffManager.ClearAll();
IsInvisible = false;
this.Vampire = this.OriVampire;
}
}*/
public override bool IsRigid => true;
public override ShapeType Shape => ShapeType.Circle;
public override bool IgnoreCollideExecutor(IGameObj targetObj)
{
if (IsRemoved)
return true;
if (targetObj.Type == GameObjType.Gadget)
{
return true;
}
if (targetObj.Type == GameObjType.Character && XY.DistanceCeil3(targetObj.Position, this.Position) < this.Radius + targetObj.Radius - GameData.adjustLength)
return true;
return false;
}
}
}