using CommonAI.RTS; using CommonLang.Vector; using CommonAI.Zone.Helper; using CommonLang; using System; using System.Collections.Generic; using System.Linq; using System.Text; using CommonAI.Zone.Instance.Helper; using CommonAI.Data; namespace CommonAI.Zone.Instance { public class InstancePet : InstanceUnit, ISummonedUnit { protected InstanceUnit mMaster; protected StateFollowMaster mFollowMaster; public InstanceUnit Owner { get { return this; } } public InstancePet(InstanceZone zone, UnitInfo info, string name, int force, int level) : base(zone, info, name, force, level) { s_mFollowDistance = Templates.CFG.PET_FOLLOW_DISTANCE_MIN + (Templates.CFG.PET_FOLLOW_DISTANCE_MAX - Templates.CFG.PET_FOLLOW_DISTANCE_MIN) / 2; } public override bool IntersectMap { get { return Info.BodySize > 0; } } public override bool IntersectObj { get { return false; } } public override bool IsActive { get { return false; } } public override bool IsAttackable { get { return false; } } /// /// 获取主人 /// public virtual InstanceUnit Master { get { return mMaster; } set { this.mMaster = value; this.mFollowMaster = new StateFollowMaster(this, mMaster); } } public virtual InstanceUnit SummonerUnit { get { return Master; } set { Master = value; } } /// /// IAO标记 /// public override ObjectAoiStatus AoiStatus { get { return this.Master == null ? base.AoiStatus : this.Master.AoiStatus; } } // 跟随最大最小距离的中间值 public static float s_mFollowDistance = 0; protected override void onUpdate(bool slowRefresh) { base.onUpdate(slowRefresh); OnPetUpdate(); } protected virtual void OnPetUpdate() { if (mMaster != null) { if (mMaster.IsDead() || !mMaster.Enable) { this.kill(this); } else if (!CMath.includeRoundPoint(X, Y, Templates.CFG.PET_FOLLOW_DISTANCE_LIMIT, mMaster.X, mMaster.Y)) { this.transportToMaster(); } else if (!CMath.includeRoundPoint(X, Y, Templates.CFG.PET_FOLLOW_DISTANCE_MAX, mMaster.X, mMaster.Y)) { this.followMaster(); } } if (CurrentState is StateIdle) { doSomething2(); } } protected void transportToMaster() { float dx, dy; CMath.RandomPosInRound(Parent.RandomN, mMaster.X, mMaster.Y, Templates.CFG.PET_FOLLOW_DISTANCE_MAX, out dx, out dy); if (IntersectMap && Parent.TryTouchMap(this, dx, dy)) { dx = Master.X; dy = Master.Y; } this.Virtual.SetCombatState(BattleStatus.None); this.transport(dx, dy); this.followMaster(); } protected void followMaster() { StateSkill skillState = this.CurrentState as StateSkill; if (skillState != null && skillState.Skill != null && !skillState.IsCancelableByMove) { return; } else if(CurrentState == mFollowMaster) { return; } //float distanceTemp = MathVector.getDistance(this.X, this.Y, this.Master.X, this.Master.Y); float speedChag = 1.01f;// (distanceTemp < s_mFollowDistance) ? 1.01f : 1.1f; this.followMasterChangeSpeed(speedChag); changeState(mFollowMaster); //System.Console.WriteLine("---followMaster: " + TimeUtil.GetTimestampMS() + speedChag); } protected virtual void followMasterChangeSpeed(float speedChag) { // 随从使用主人的速度 if (this.Master != null) { this.SetMoveSpeed(this.Master.MoveSpeedSEC * speedChag); } } protected void doSomething2() { if (!IsNoneSkill) { using (var list = ListObjectPool.AllocAutoRelease()) { //随机找个目标施法// Parent.getObjectsRoundRange(Collider.Object_Pos_IncludeInRound, X, Y, Info.GuardRange, list, this.AoiStatus); DoAndRemoveCollection.UpdateAndRemove(list, (InstanceUnit u) => { return !u.IsActive; }); CUtils.RandomList(Parent.RandomN, list); foreach (SkillState skill in SkillStatus) { if (skill.LaunchSkill.AutoLaunch && skill.TryLaunch()) { foreach (InstanceUnit u in list) { if (Parent.IsAttackable(this, u, skill.Data.ExpectTarget, AttackReason.Look, skill.Data)) { //检测是否有可释放技能// if (tryAutoLaunch(skill, u)) { return; } } } } } } } } protected virtual bool tryAutoLaunch(SkillState st, InstanceUnit target) { if (st != null && st.LaunchSkill.AutoLaunch) { changeState(new StateFollowAndAttack(this, target, st.Data.ExpectTarget)); return true; } return false; } protected override void Disposing() { mMaster = null; mFollowMaster = null; base.Disposing(); } //---------------------------------------------------------------------------------------------------------- protected override IUnitStatistic CreateUnitStatistic() { return new PetUnitStatistic(this); //return base.CreateUnitStatistic(); } public class PetUnitStatistic : UnitStatistic { private InstancePet owner; public PetUnitStatistic(InstancePet owner) : base(owner) { this.owner = owner; } public override void onAttack(InstanceUnit target, int reduceHP) { //伤害统计重定向到主人// if (owner.Master != null) { owner.Master.Statistic.onAttack(target, reduceHP); } else { base.onAttack(target, reduceHP); } } public override void onKill(InstanceUnit target) { //击杀统计重定向到主人// if (owner.Master != null) { owner.Master.Statistic.onKill(target); } else { base.onKill(target); } } } //---------------------------------------------------------------------------------------------------------- /// /// 移动状态 /// public class StateFollowMaster : State { // 被追目标 readonly private InstanceZoneObject master; private MoveAI move; public StateFollowMaster(InstancePet unit, InstanceZoneObject target) : base(unit) { this.master = target; this.move = new MoveAI(unit); } override public bool onBlock(State new_state) { if (new_state is StateDead) { return true; } if (new_state is StateFollowMaster) { return true; } float r = Math.Max(zone.Templates.CFG.PET_FOLLOW_DISTANCE_MIN, master.BodyBlockSize + unit.BodyBlockSize); if (CMath.includeRoundPoint(unit.X, unit.Y, r, master.X, master.Y)) { unit.SetActionStatus(UnitActionStatus.Idle); return true; } StateSkill stateSkill = new_state as StateSkill; if(stateSkill != null && !stateSkill.IsCancelableByMove) { return true; } return false; } override protected void onStart() { unit.SetActionStatus(UnitActionStatus.Move); this.move.FindPath(master); } override protected void onUpdate() { float r = Math.Max(zone.Templates.CFG.PET_FOLLOW_DISTANCE_MIN, master.BodyBlockSize + unit.BodyBlockSize); if (CMath.includeRoundPoint(unit.X, unit.Y, r, master.X, master.Y)) { unit.SetActionStatus(UnitActionStatus.Idle); unit.doSomething(); } else { move.Update(); if (move.IsNoWay) { (unit as InstancePet).transportToMaster(); } } } override protected void onStop() { unit.SetActionStatus(UnitActionStatus.Idle); } } } }