using CommonAI.Zone; using CommonAI.Zone.Helper; using CommonAI.Zone.Instance; using CommonLang; using XmdsCommon.Plugin; using CommonLang.Vector; using XmdsCommonServer.Plugin.Scene; using System.Collections.Generic; using System; using CommonAI.Zone.Formula; using static XmdsCommonServer.Plugin.XmdsVirtual; using static CommonAI.Zone.AttackProp; using XmdsCommon.Message; using CommonAI.Data; using CommonAI; namespace XmdsCommonServer.Plugin.Units { public class XmdsInstanceMonster : InstanceGuard { /// /// 储存真正的单位ID. /// private int mMonsterID = 0; /// /// 获取怪物真正的ID. /// /// public int MonsterID { set { mMonsterID = value; } get { return mMonsterID; } } private float mGuardRangeLimit; private float mGuardRange; private TimeExpire mIdleMoveHoldTime; private WanderConfig mWanderConfig = null; public XmdsInstanceMonster(InstanceZone zone, UnitInfo info, string name, int force, int level) : base(zone, info, name, force, level) { mGuardRangeLimit = info.GuardRangeLimit; mGuardRange = info.GuardRange; if (((zone as XmdsServerScene).Data != null)) { XmdsServerSceneData data = ((zone as XmdsServerScene).Data.Properties as XmdsSceneProperties).ServerSceneData; //只有野外地图生效. if (data.SceneHard == XmdsServerSceneData.NORMAL_MAP) { mWanderConfig = (info.Properties as XmdsUnitProperties).WanderConfigData; if (mWanderConfig == null) { //编辑器未配置时走默认. mWanderConfig = new WanderConfig(); mWanderConfig.MaxHoldTimeMS = XmdsConfig.Instance.MAX_HOLD_TIMEMS; mWanderConfig.MinHoldTimeMS = XmdsConfig.Instance.MIN_HOLD_TIMEMS; mWanderConfig.MaxMoveTimeMS = XmdsConfig.Instance.MAX_MOVE_TIMEMS; mWanderConfig.MinMoveTimeMS = XmdsConfig.Instance.MIN_MOVE_TIMEMS; mWanderConfig.WanderRange = XmdsConfig.Instance.WANDE_RRANGE; } if (mWanderConfig.MaxHoldTimeMS > 0) { mIdleMoveHoldTime = new TimeExpire(Parent.RandomN.Next(mWanderConfig.MinHoldTimeMS, mWanderConfig.MaxHoldTimeMS)); } } } } protected override void onUpdate(bool slowRefresh) { base.onUpdate(slowRefresh); this.updateIdle(); } public HateSystem getHateSystem() { return this.mHateSystem; } protected override void OnBackToOrgin() { //DoUnitStateReset(); base.OnBackToOrgin(); } public void AddEnemy(InstanceUnit target) { base.onAddEnemy(target, false, AttackReason.Look); } public override void doSomething() { base.doSomething(); } public override bool IsMonster { get { return true; } } protected override void updateBackToOrgin() { if (mBackToPosition != null) { if (mBackToPosition.IsDone) { mBackToPosition = null; } } if (mGuardRangeLimit > mGuardRange) { //if (mCheckInGuardLimit.Update(Parent.UpdateIntervalMS)) if (mNextCheckGuardLimit != null && mNextCheckGuardLimit.IsTrigger()) { //怪物会原地警戒 float mGuardRangeLimitTemp = mGuardRangeLimit + 1.5f; if (!CMath.includeRoundPoint(X, Y, mGuardRangeLimitTemp, mOrginPosition.X, mOrginPosition.Y)) { mHateSystem.forceRemoveAtkTraget(); //Console.WriteLine(" - - backToOrgin - 1 " + this.Info.Name); //在自己的攻击范围内,找仇恨,目标 if(mHateSystem.updateHateList(mGuardRangeLimit, mOrginPosition) <= 0) { backToOrgin(); } else { //boss寻找下一个攻击目标 mTracingTarget = null; InstanceUnit unit = mHateSystem.GetHated(); if (unit is InstancePlayer) { } followAndAttack(mHateSystem.GetHated(), AttackReason.Look); } //mHateSystem.print(); } else if (mTracingTarget != null) { if (!mTracingTarget.IsActive || !CMath.intersectRound( X, Y, mGuardRangeLimit, mTracingTarget.TargetUnit.X, mTracingTarget.TargetUnit.Y, mTracingTarget.TargetUnit.BodyHitSize)) { //Console.WriteLine(" - - backToOrgin - 2 " + this.Info.Name); mHateSystem.Remove(mTracingTarget.TargetUnit); if(mHateSystem.getHateSize() <= 0) { backToOrgin(); }else { //boss寻找下一个攻击目标 mTracingTarget = null; followAndAttack(mHateSystem.GetHated(), AttackReason.Look); } return; } } } } } protected virtual void updateIdle() { //不能移动单位,也不游荡 if (CurrentActionStatus == UnitActionStatus.Idle && this.Moveable && (this.Virtual as XmdsVirtual).CombatState == BattleStatus.None) { if (mIdleMoveHoldTime != null && mIdleMoveHoldTime.Update(Parent.UpdateIntervalMS)) { //发呆时间. mIdleMoveHoldTime.Reset(Parent.RandomN.Next(mWanderConfig.MinHoldTimeMS, mWanderConfig.MaxHoldTimeMS)); //游荡时间、游荡范围. idleMove(Parent.RandomN.Next(mWanderConfig.MinMoveTimeMS, mWanderConfig.MaxMoveTimeMS), mWanderConfig.WanderRange); } } } public override void guardInPosition(Vector2 pos) { if (this.IsDead() == false) { DoUnitStateReset(); } if (CurrentState is StateIdleMove && pos == mOrginPosition) { // 浪切换到发呆,别回原点 // base.guardInPosition(new Vector2(X, Y)); } else { base.guardInPosition(pos); } } //怪物返回原点时,状态重置. private void DoUnitStateReset() { var v = this.Virtual as XmdsVirtual_Monster; if (v != null) { v.DoUnitStateReset(); } } public void SetGuardRange(float r) { if (mViewTrigger is ViewTriggerRoundBody) { mGuardRange = r; (mViewTrigger as ViewTriggerRoundBody).SetLookRange(r); } } protected override void onNewStateBeginChange(State old_state, ref State new_state) { if (new_state is StateBackToPosition) { if(this.Info.Attributes != null && this.Info.Attributes.Length > 0) { //特殊的怪物不回血, 如要特殊处理,初始化就弄 // String par = this.Info.Attributes[0]; // if (par.Equals("noRecover")) { this.clearBuffs(); } } else { //回血. this.AddHP(this.MaxHP, null); this.AddMP(this.MaxMP, null); this.Virtual.StartRecoverMP(true); //去BUFF. this.clearBuffs(); } } base.onNewStateBeginChange(old_state, ref new_state); } public override BuffState AddBuff(BuffTemplate buff, InstanceUnit sender, int pointMaxOverLayer = 0, bool forever = false, bool bMaxOverlayer = false, int buffExt = 0, bool isControlBuf = false, bool bMaxRest = false, int addLayers = 0) { if (!buff.forceAdd && this.Virtual.IsBoss() && XmdsInstanceUtils.IsControlBuff_Monster(buff))//BOSS不吃控制 { return null; } return base.AddBuff(buff, sender, pointMaxOverLayer, forever, bMaxOverlayer, buffExt, isControlBuf, bMaxRest, addLayers); } public override void InitSkills(LaunchSkill baseSkill, params LaunchSkill[] skills) { if (this.Virtual == null || (this.Virtual as XmdsVirtual).IsFinishSkillInit() == false) { return; } base.InitSkills(baseSkill, skills); } protected SkillState GetAvailableSkillExceptDefaultSkill() { SkillState ret = null; List list = SkillStatus as List; for (int si = list.Count - 1; si >= 0; --si) { SkillState sst = list[si]; if (DefaultSkill != null && sst.Data.ID != DefaultSkill.ID) { if (!sst.IsCD && sst.IsActive && sst.IsDone) { ret = sst; break; } } } return ret; } public override void guard() { if (IsNoneSkill) { mTracingTarget = null; base.startIdle(); return; } if (this.Info.GuardRange > 0) { InstanceUnit min = null; float min_len = float.MaxValue; bool isSpecial = false; bool iamSpecial = Info.Properties is XmdsUnitProperties myprop && myprop.GameStatusType > XmdsUnitProperties.StatusType.Normal; float guardRangSqua = mGuardRange * mGuardRange; Parent.ForEachNearObjects(this.X, this.Y, this.Info.GuardRange, (InstanceUnit u, ref bool cancel) => { float len = MathVector.getDistanceSquare(u.X, u.Y, this.X, this.Y); if (len > guardRangSqua) { return; } if (!Parent.IsAttackable(this, u, SkillTemplate.CastTarget.Enemy, AttackReason.Look, Info)) { return; } if (iamSpecial && u.Info.Properties is XmdsUnitProperties prop && prop.GameStatusType > XmdsUnitProperties.StatusType.Normal) { if (isSpecial) { if (len < min_len) { min = u; min_len = len; } } else { min = u; min_len = len; isSpecial = true; } } else if (!isSpecial && min_len > len) { min_len = len; min = u; } }); if (min != null) { changeState(new StateFollowAndAttack(this, min, SkillTemplate.CastTarget.Enemy)); return; } } base.guard(); } public override bool tryLaunchRandomSkillAndCancelCurrentSkill(InstanceUnit target, bool autoFocusNearTarget = false) { //自动战斗不允许中断当前技能施放. return false; } protected override void onResetAI() { mTracingTarget = null; doSomething(); } protected override void Disposing() { mIdleMoveHoldTime = null; mWanderConfig = null; base.Disposing(); } protected override void doHitAttack(InstanceUnit attacker, AttackSource source) { base.doHitAttack(attacker, source); if (IsDead() && source.OutClientState == (int)UnitHitEventState.Crit && this.Weight < XmdsConstConfig.DEFAULT_WEIGHT && source.Attack.killHitMove!=null && source.Attack.killHitMove.enable) { HitMoveType moveType = source.Attack.killHitMove.moveType; changeState(new StateDeadFuckFuck(this, source, attacker, moveType), true); } } protected override void onBack2PositionStart() { (this.Virtual as XmdsVirtual_Monster).changeRunSpeed4back(); } protected override void onBack2PositionEnd() { (this.Virtual as XmdsVirtual_Monster).onBack2PositionEnd(); } protected override void onAddEnemy(InstanceUnit target, bool group, AttackReason reason) { var state = CurrentState; InstanceUnit nowTarget = null; if (state is StateFollowAndAttack attackstate) { nowTarget = attackstate.TargetUnit; } else if(state is StateSkill skillstate) { nowTarget = skillstate.TargetUnit; } //当前正在追踪/攻击一个价值更高的目标时,不理会小啰啰的攻击 if (nowTarget != null && nowTarget.Info.Properties is XmdsUnitProperties prop && prop.GameStatusType > XmdsUnitProperties.StatusType.Normal) { if(target.Info.Properties is XmdsUnitProperties propnew && propnew.GameStatusType > prop.GameStatusType) { } else { return; } } base.onAddEnemy(target, group, reason); } } }