using CommonAI.RTS; using CommonLang.Vector; using CommonAI.Zone.Helper; using CommonAI.Zone.Formula; using CommonLang; using System; using System.Collections.Generic; using System.Linq; using System.Text; using CommonLang.IO; using CommonAI.Data; using CommonAI.Zone.ZoneEditor.EventTrigger; using CommonAI.ZoneClient; namespace CommonAI.Zone.Instance { /// /// 可自动战斗的可操作单位 /// public class InstancePlayer : InstanceUnit { private readonly string mPlayerUUID; //private HashMap mKilledPlayersID = new HashMap(); private CommonAI.ZoneClient.SyncMode mCurrentSyncMode; private bool mIsSkillControlByServer = true; //自动拾取范围 protected float mAutoPickRange = XmdsConstConfig.AUTOPICK_RANGE; protected float mAutoPickSearchRange = XmdsConstConfig.AUTOPICK_RANGE * 3; protected TimeInterval mCheckGuard; protected HashMap mQuests = new HashMap(); protected UnitLaunchSkillAction mWaitingSkill; protected StatePlayerControlMove mControlMove; protected StatePlayerUpdateMove mUpdateMove; protected StateFollowAndAttack mFocusTarget; protected StateFollowAndPickItem mFocusPickItem; protected StatePlayerAttackTo mAttackTo; public virtual bool isTeamMemberAndFollow() { return false; } public override string PlayerUUID { get { return mPlayerUUID; } } public string ClientID { get; set; } public bool IsGuard { get; set; } public bool IsReady { get; private set; } public override bool IsPlayer { get { return true; } } public override bool IsPlayerUnit { get { return true; } } public override bool IntersectObj { get { return (Templates.CFG.PLAYER_NONE_TOUCH) ? false : base.IntersectObj; } } public override bool IsSkillControllableByServer { get { return mIsSkillControlByServer; } } public CommonAI.ZoneClient.SyncMode ClientSyncMode { get { return mCurrentSyncMode; } } public bool IsRobot { get; set; } public InstancePlayer(InstanceZone zone, UnitInfo info, string name, int force, int level, int alliesForce) : base(zone, info, name, force, level, false, alliesForce) { this.mPlayerUUID = string.IsNullOrEmpty(name) ? "" : name; this.mSyncInfo.PlayerUUID = mPlayerUUID; this.mControlMove = new StatePlayerControlMove(this); this.mUpdateMove = new StatePlayerUpdateMove(this); this.mCheckGuard = new TimeInterval(Templates.CFG.AI_VIEW_TRIGGER_CHECK_TIME_MS); } protected override void Disposing() { /* mControlMove = null; mUpdateMove = null; mFocusTarget = null; mFocusPickItem = null; mAttackTo = null; */ base.Disposing(); } /// /// 联网模式,断开连接。 /// public virtual void OnDisconnected() { } /// /// 联网模式,重新连接。 /// public virtual void OnReconnected(UnitInfo temp, int force, int level, Vector2 enterPos) { } public virtual LockActorEvent GenLockActorEvent(string displayName, float inRange, float outRange, int updateInterval) { // 准备发送当前场景信息 // var loc = new LockActorEvent(); loc.ServerUpdateInterval = updateInterval; loc.ClientSyncObjectRange = inRange; loc.ClientSyncObjectOutRange = outRange; loc.UnitData = IOUtil.CloneIExternalizable(TemplateManager.MessageCodec, this.GenSyncUnitInfo(true)); loc.UnitData.Name = displayName; loc.UnitData.x = this.X; loc.UnitData.y = this.Y; loc.GameServerProp = CUtils.TryClone(this.Info.Properties); loc.Skills = this.GetSkillEvent(); loc.UnitData.CurrentBuffStatus = this.GetCurrentBuffStatus(); loc.CurrentSkillStatus = this.GetCurrentSkillStatus(); loc.CurrentItemStatus = this.GetCurrentItemStatus(); loc.CurrentPlayerVars = this.GetCurrentUnitVars(); loc.CurrentZoneVars = Parent.GetCurrentZoneVars(); return loc; } protected override void onUpdateRecover() { base.onUpdateRecover(); } override protected void onResetAI() { this.cleanFocus(); this.doSomething(); } protected override void onAdded(bool pointLv) { base.onAdded(pointLv); this.doSomething(); } // override protected void onDead(InstanceUnit attacker) // { // if (attacker is IPlayerUnit) // { // var killer = attacker as IPlayerUnit; // killer.PutKillPlayer(this.PlayerUUID); // } // } override protected void onUpdate(bool slowRefresh) { base.onUpdate(slowRefresh); this.updateGuard(); this.updateCurrentSkill(); this.updateAttackTo(); } protected virtual void updateCurrentSkill() { if (CurrentState is StateSkill) { var current = CurrentState as StateSkill; if (mWaitingSkill != null && current.IsCancelableBySkill) { doLaunchSkill(mWaitingSkill); } else if (IsGuard) { if ((mFocusTarget != null)) { tryLaunchRandomSkillAndCancelCurrentSkill(mFocusTarget.TargetUnit, true); } } } } protected virtual void updateGuard() { if (mFocusTarget != null && !mFocusTarget.IsActive) { mFocusTarget = null; } if (mFocusPickItem != null && !mFocusPickItem.IsActive) { mFocusPickItem = null; } if (IsGuard) { // 旋风斩贴近目标 // if (mFocusTarget != null && CurrentState is StateSkill) { var state = CurrentState as StateSkill; if (state.IsControlMoveable && !state.unit.IsCannotMove) { state.setMoveTo(mFocusTarget.Target.X, mFocusTarget.Target.Y); } } // 没目标定期检测目标 // if ((mFocusTarget == null) && (mFocusPickItem == null)) { if (mCheckGuard.Update(Parent.UpdateIntervalMS)) { var item = findGuardPickItem(); if (item != null) { doFocusPickItem(item); return; } var enemy = findGuardTarget(SkillTemplate.CastTarget.Enemy, AttackReason.Look); if (enemy != null) { doFocusAttack(enemy, SkillTemplate.CastTarget.Enemy); return; } var alias = findGuardTarget(SkillTemplate.CastTarget.AlliesIncludeSelf, AttackReason.Look); if (alias != null) { doFocusAttack(alias, SkillTemplate.CastTarget.AlliesIncludeSelf); return; } } } } } protected virtual void updateAttackTo() { if (mAttackTo != null) { if (mAttackTo.IsDone) { mAttackTo = null; } else if (!mAttackTo.IsAttack) { cleanFocus(); } } } public override void doSomething() { if (mWaitingSkill != null && CurrentState is StateSkill) { if (doLaunchSkill(mWaitingSkill)) { return; } } else if (IsGuard) { if (mFocusPickItem != null && mFocusPickItem.IsActive) { changeState(mFocusPickItem); return; } else { mFocusPickItem = null; } if (mFocusTarget != null && mFocusTarget.IsActive) { if (Parent.IsAttackable(this, mFocusTarget.TargetUnit, SkillTemplate.CastTarget.AlliesIncludeSelf, AttackReason.Attack, Info)) { mFocusTarget = null; } else { changeState(mFocusTarget); return; } } else { mFocusTarget = null; } if (mAttackTo != null && !mAttackTo.IsDone) { changeState(mAttackTo); return; } } base.doSomething(); } public virtual InstanceUnit findGuardTarget(SkillTemplate.CastTarget expect = SkillTemplate.CastTarget.Enemy, AttackReason reason = AttackReason.Look) { InstanceUnit min = null; if (getAvailableSkill(expect) != null) { float min_len = float.MaxValue; Parent.ForEachNearObjects(this.X, this.Y, this.Info.GuardRange, (InstanceUnit u, ref bool cancel) => { if (Parent.IsAttackable(this, u, expect, reason, Info)) { float len = MathVector.getDistanceSquare(u.X, u.Y, this.X, this.Y); if (min_len > len) { min_len = len; min = u; } } }); } return min; } public virtual StateFollowAndAttack doFocusAttack(InstanceUnit target, SkillTemplate.CastTarget expect_target = SkillTemplate.CastTarget.Enemy) { if ((mAttackTo == null || mAttackTo.IsAttack) && Parent.IsAttackable(this, target, expect_target, AttackReason.Tracing, Info)) { if (mFocusTarget != null) { if (mFocusTarget.TargetUnit != target) { mFocusTarget = new StateFollowAndAttack(this, target, expect_target, true); if (changeState(mFocusTarget)) { queueEvent(new PlayerFocuseTargetEvent(this.ID, target.ID, expect_target)); } } } else { mFocusTarget = new StateFollowAndAttack(this, target, expect_target, true); if (changeState(mFocusTarget)) { queueEvent(new PlayerFocuseTargetEvent(this.ID, target.ID, expect_target)); } } } else { mFocusTarget = null; } return mFocusTarget; } //可被自动拾取的,是那种没有进度条的 public virtual InstanceItem findGuardPickItem() { InstanceItem min = null; float min_len = float.MaxValue; Parent.ForEachNearObjects(this.X, this.Y, this.mAutoPickRange, (InstanceItem u, ref bool cancel) => { if (u.IsPickable(this)) { float len = MathVector.getDistanceSquare(u.X, u.Y, this.X, this.Y); if (min_len > len) { min_len = len; min = u; } } }); return min; } public virtual StateFollowAndPickItem doFocusPickItem(InstanceItem target, bool doPick = true) { if (mAttackTo == null || mAttackTo.IsAttack) { if (mFocusPickItem != null) { if (mFocusPickItem.Target != target) { StateFollowAndPickItem focusPickItem = new StateFollowAndPickItem(this, target, doPick); if (changeState(focusPickItem)) { mFocusPickItem = focusPickItem; queueEvent(new PlayerFocuseTargetEvent(this.ID, target.ID, SkillTemplate.CastTarget.NA)); } } } else { StateFollowAndPickItem focusPickItem = new StateFollowAndPickItem(this, target, doPick); if (changeState(focusPickItem)) { mFocusPickItem = focusPickItem; queueEvent(new PlayerFocuseTargetEvent(this.ID, target.ID, SkillTemplate.CastTarget.NA)); } } } else { mFocusPickItem = null; } return mFocusPickItem; } protected virtual void cleanFocus() { mFocusPickItem = null; mFocusTarget = null; } // internal void PutKillPlayer(string killed) // { // int count = 0; // if (mKilledPlayersID.TryGetValue(killed, out count)) // { // mKilledPlayersID.Put(killed, count + 1); // } // else // { // mKilledPlayersID.Put(killed, 1); // } // } //-------------------------------------------------------------------------------------- public virtual bool doRequest(ActorRequest req) { if (req is UnitGetStatisticRequest) { doGetStatisticRequest(req as UnitGetStatisticRequest); return true; } return false; } //设置自动拾取范围 public override void SetAutoPickRange(int value) { this.mAutoPickRange = value; this.mAutoPickSearchRange = value * 3; } protected override void onAction(ObjectAction act) { //log.Info("------(focus.targetUnitID); if ((src is InstanceUnit)) { if (!IsNoneSkill && ((src as InstanceUnit).IsActive)) { doFocusAttack(src as InstanceUnit); } } else if ((src is InstanceItem)) { if (src.Enable) { doFocusPickItem(src as InstanceItem); } } else { cleanFocus(); } } } protected virtual void doAttackTo(UnitAttackToAction act) { if (!act.attack) { cleanFocus(); } mAttackTo = new StatePlayerAttackTo(this, act.targetX, act.targetY, act.attack); changeState(mAttackTo); } protected virtual void doUseItem(UnitUseItemAction use) { UseInventoryItem(use.Index, use.Count); } protected virtual void doPickObject(UnitPickObjectAction pick) { InstanceZoneObject obj = Parent.getObject(pick.PickableObjectID); if (obj is InstanceItem) { InstanceItem item = obj as InstanceItem; item.PickItem(this); } else if (obj is InstanceUnit) { InstanceUnit unit = obj as InstanceUnit; this.PickUnit(unit); } } protected virtual void doChat(ChatAction chat) { ChatEvent send = new ChatEvent(chat.To); send.FromPlayerUUID = this.PlayerUUID; send.Message = chat.Message; switch (chat.To) { case ChatMessageType.PlayerToPlayer: InstancePlayer target = Parent.getPlayerByUUID(chat.TargetPlayerUUID); if (target != null) { send.ToPlayerUUID = target.PlayerUUID; Parent.queueEvent(send); } break; case ChatMessageType.PlayerToForce: send.Force = this.Force; Parent.queueEvent(send); break; case ChatMessageType.PlayerToAll: Parent.queueEvent(send); break; } } protected virtual void doUnitUpdatePos(UnitUpdatePosAction act) { //Console.WriteLine("-------------------UnitUpdatePosAction : " + TimeUtil.GetTimestampMS() + ", " + act.x + ", " + act.y + " \t \t" + act.d); if (mCurrentSyncMode == ZoneClient.SyncMode.MoveByClient_PreSkillByClient && !this.IsCannotMove) { //mWaitingSkill = null; mUpdateMove.SetPos(act); if (CurrentState is StateSkill) { var ss = CurrentState as StateSkill; ss.doUpdatePosByClient(act); //服务器判断下,蓄力阶段才同步客户端蓄力状态 if (ss.CurrentActionIndex < ss.SkillData.ActionQueue.Count && ss.SkillData.ActionQueue[ss.CurrentActionIndex].SigleActionType == ActionEnum.chargeAtk) { if (act.st == UnitActionStatus.ChargeAtkMove) { this.RemoveActionSubState(UnitActionSubStatus.ChargeAtkIdle); this.AddActionSubState(UnitActionSubStatus.ChargeAtkMove); } else if (act.st == UnitActionStatus.ChargeAtkIdle) { this.RemoveActionSubState(UnitActionSubStatus.ChargeAtkMove); this.AddActionSubState(UnitActionSubStatus.ChargeAtkIdle); } } } else if (CurrentState is StatePickObject) { if (act.st == UnitActionStatus.Move) { this.faceTo(act.d); this.setPos(act.x, act.y, this.IntersectMap); changeState(mUpdateMove); } } else if (CurrentState is StateDamage || CurrentState is StateDead || CurrentState is IStateNoneControllable) { } else if (CurrentActionStatus == UnitActionStatus.DaZuo || CurrentActionStatus == UnitActionStatus.DaZuoRecoveryAttr || CurrentActionStatus == UnitActionStatus.Idle || CurrentActionStatus == UnitActionStatus.Move) { //changestate在帧中切换状态,这里提前判断下一个动作能否转向 bool canChangeDircetion = true; StateSkill nextSkill = this.NextState as StateSkill; if (nextSkill != null && nextSkill.Skill != null) { UnitActionData action = nextSkill.Skill.GetCurAction(); if(action != null && !action.IsControlFaceable) { canChangeDircetion = false; } } if (canChangeDircetion) { this.faceTo(act.d); } this.setPos(act.x, act.y, this.IntersectMap); if (act.st == UnitActionStatus.Idle) { doSomething(); } else if (act.st == UnitActionStatus.Move) { changeState(mUpdateMove); } //Console.WriteLine("st=" + act.d); } } } protected virtual void doGuard(UnitGuardAction act) { if (this.IsGuard != act.guard) { var IsInCancelingGuard = this.IsGuard; this.IsGuard = act.guard; this.mIsSkillControlByServer = IsGuard || (mCurrentSyncMode != ZoneClient.SyncMode.MoveByClient_PreSkillByClient); if (IsGuard == false) { mAttackTo = null; cleanFocus(); } else { mCheckGuard.Reset(); } resetAI(); if (NextState == null && IsInCancelingGuard && CurrentState is StateSkill) { TryEnqueueIdleState(); } //通知待机状态\ //if (act.forceNotify) { this.Virtual.doEvent(JSGCustomOpType.UpdateAutoBattleFlag); } } } public virtual void doEnterAutoFight() { this.IsGuard = true; } protected virtual void doFollow(UnitFollowAction act) { this.mIsSkillControlByServer = act.follow || (mCurrentSyncMode != ZoneClient.SyncMode.MoveByClient_PreSkillByClient); //this.mIsSkillControlByServer = (mCurrentSyncMode != ZoneClient.SyncMode.MoveByClient_PreSkillByClient); } protected virtual void doSetSyncMode(UnitSetSyncModeAction act) { this.mCurrentSyncMode = act.Mode; this.mIsSkillControlByServer = IsGuard || (mCurrentSyncMode != ZoneClient.SyncMode.MoveByClient_PreSkillByClient); } protected virtual void doCancelBuff(UnitCancelBuffAction act) { BuffState bs = this.GetBuffByID(act.BuffID); if (bs != null && bs.Data.IsCancelBySelf) { this.removeBuff(act.BuffID, BuffState.EndResult_ByClientRemoved); } } protected virtual void doUnitSetSubStateAction(UnitSetSubStateAction act) { base.AddActionSubState((UnitActionSubStatus)(act.UnitSubState)); } protected virtual void doPetTeleportAction(PlayPetTeleportAction act) { InstanceUnit petUnit = this.Virtual.GetPetUnit(); if (petUnit != null) { if (petUnit.petTeleportTime < CommonLang.CUtils.CurrentTimeMS) { petUnit.petTeleportTime = CommonLang.CUtils.CurrentTimeMS+10*1000; petUnit.lastTeleportTime = CommonLang.CUtils.CurrentTimeMS+3*1000; //3秒之后开始返回 //获取玩家当前坐标 float x = this.get_x(); float y = this.get_y(); petUnit.setPos(this.get_x(), this.get_y(), this.IntersectMap); petUnit.faceTo(this.get_direction()); State s = new PetLockState(petUnit); petUnit.changeState(s); } else { if (petUnit.lastTeleportTime < CommonLang.CUtils.CurrentTimeMS) { petUnit.lastTeleportTime = CommonLang.CUtils.CurrentTimeMS+3*1000; //3秒之后开始返回 this.Virtual.SendMsgToClient(CommonAI.XmdsConstConfig.TIPS_CALL_BACK_BTN); } } } } #endregion // -------------------------------------------------------------------------------------- #region PlayerQuests public virtual void InitQuestData(ICollection datas) { foreach (QuestData q in datas) { if (q.QuestID != null) { mQuests.Put(q.QuestID, q); } } } internal QuestData doQuestAccepted(string quest) { if (!string.IsNullOrEmpty(quest)) { QuestData qd = new QuestData(quest); qd.State = QuestState.Accepted; mQuests.Put(quest, qd); return qd; } return null; } internal QuestData doQuestCommitted(string quest) { QuestData qd = mQuests.RemoveByKey(quest); if (qd != null) { qd.State = QuestState.Commited; onQuestCommitted(qd); } return qd; } /// /// 当任务完成时,子类覆盖的方法被调用 /// /// protected virtual void onQuestCommitted(QuestData qd) { } internal QuestData doQuestDropped(string quest) { QuestData qd = mQuests.RemoveByKey(quest); if (qd != null) { qd.State = QuestState.Uncharted; } return qd; } internal QuestData doQuestStatusChanged(string quest, string key, string value) { QuestData qd = mQuests.Get(quest); if (qd != null) { qd.Attributes.Put(key, value); } return qd; } public virtual bool IsQuestAccepted(string quest) { QuestData qd = mQuests.Get(quest); if (qd != null) { string ret; if (qd.Attributes.TryGetValue("state", out ret)) { return ret == "0"; } return qd.State == QuestState.Accepted; } return false; } public virtual string GetQuestStatus(string quest, string key) { QuestData qd = mQuests.Get(quest); if (qd != null) { string value; if (qd.Attributes.TryGetValue(key, out value)) { return value; } } return null; } public virtual QuestData GetQuest(string quest) { return mQuests.Get(quest); } #endregion //-------------------------------------------------------------------------------------- /// /// 更新坐标移动状态 /// public class StatePlayerUpdateMove : State { private UnitUpdatePosAction act; public bool IsPosChanged { get { if (act != null) { return act.x != unit.X || act.y != unit.Y; } return false; } } public StatePlayerUpdateMove(InstancePlayer unit) : base(unit) { } public void SetPos(UnitUpdatePosAction act) { // TODO 检测作弊 this.act = act; } public override bool onBlock(State new_state) { return true; } protected override void onStart() { unit.SetActionStatus(UnitActionStatus.Move); } protected override void onUpdate() { unit.SetActionStatus(UnitActionStatus.Move); } protected override void onStop() { } } //-------------------------------------------------------------------------------------- /// /// 摇杆控制移动状态 /// protected class StatePlayerControlMove : State { private float mDirection; private UnitAxisAction mAction; public UnitAxisAction Action { get { return mAction; } set { mAction = value; mDirection = MathVector.getDegree(value.dx, value.dy); } } public float Direction { get { return mDirection; } } public StatePlayerControlMove(InstancePlayer unit) : base(unit) { } public override bool onBlock(State new_state) { return true; } protected override void onStart() { unit.SetActionStatus(UnitActionStatus.Move); } protected override void onUpdate() { unit.faceTo(mDirection); unit.moveBlockTo(unit.Direction, unit.MoveSpeedSEC, zone.UpdateIntervalMS); unit.SetActionStatus(UnitActionStatus.Move); } protected override void onStop() { } } //-------------------------------------------------------------------------------------- protected class StatePlayerAttackTo : State { private TargetPos target; private MoveAI moveAI; private bool is_attack; public bool IsAttack { get { return is_attack; } } public bool IsDone { get { return target == null; } } public StatePlayerAttackTo(InstancePlayer unit, float tx, float ty, bool attack) : base(unit) { this.target = new TargetPos(tx, ty); this.is_attack = attack; } public override bool onBlock(State new_state) { return true; } override protected void onStart() { this.moveAI = new MoveAI(unit, true, 0); this.moveAI.IsNoWayAutoFindNear = false; ; if (target != null) { this.moveAI.FindPath(target); unit.SetActionStatus(UnitActionStatus.Move); } else { unit.SetActionStatus(UnitActionStatus.Idle); } } override protected void onUpdate() { if (target == null) { unit.doSomething(); } else { var result = this.moveAI.Update(); if (result.HasFlag(MoveResult.MOVE_RESULT_ARRIVED)) { do_stop(); } else if (result.HasFlag(MoveResult.MOVE_RESULT_MIN_STEP) && result.HasFlag(MoveResult.MOVE_RESULT_NO_WAY)) { do_stop(); } else if (result.HasFlag(MoveResult.MOVE_RESULT_BLOCK_OBJ)) { if (CMath.includeRoundPoint(unit.X, unit.Y, unit.BodyBlockSize, target.X, target.Y)) { do_stop(); } else if (result.obj != null && CMath.includeRoundPoint(result.obj.X, result.obj.Y, result.obj.BodyBlockSize, target.X, target.Y)) { do_stop(); } } } } protected override void onStop() { } private void do_stop() { target = null; unit.doSomething(); } class TargetPos : IPositionObject { public float Direction { get; set; } public float RadiusSize { get; set; } public float X { get; set; } public float Y { get; set; } public TargetPos(float tx, float ty) { this.X = tx; this.Y = ty; } } } } }