using System; using System.Collections.Generic; using System.Text; using CommonLang; using CommonAI.Zone.Helper; using CommonAI.Zone.Formula; using CommonAI.Zone.UnitTriggers; using CommonAI.Zone.Attributes; using CommonLang.Property; using CommonAI.RTS; using CommonLang.Vector; using CommonAI.ZoneClient; using CommonAI.data; using static CommonAI.Zone.LaunchSpell; using CommonAI.Data; namespace CommonAI.Zone.Instance { public delegate int ReadBuffDelegate(InstanceUnit.BuffState buffState); /// /// 所有常态状态(Buff,技能,被动系) /// partial class InstanceUnit { //-------------------------------------------------------------------------------------------------------------- #region _时效性效果_ //-------------------------------------------------------------------------------------------------------------- /// /// 是否可被发现 /// virtual public bool IsVisible { get { return !mInvisibleTimeMS.Enable;/* && !DeadHide; */} } /// /// 是否无敌 /// virtual public bool IsInvincible { get { return mInvincibleTimeMS.Enable; } } /// /// 此单位是否霸体 /// virtual public bool IsNoneBlock { get { return mNoneBlockTimeMS.Enable; } } /// /// 是否为眩晕 /// virtual public bool IsStun { get { return mStunTimeMS.Enable; } } /// /// 是否沉默 /// virtual public bool IsSilent { get { return mSilentTimeMS.Enable; } } /// /// 是否免控 /// virtual public bool IsIgnoreControl { get { return mIgnoreControl.Enable; } } /** 是否不允许移动 */ public bool MarkCannotMove = false; virtual public bool IsCannotMove { get { return mCannotMoveTimeMS.Enable; } } //死亡隐藏 private bool mDeadHide = false; public bool DeadHide{ get { return mDeadHide; } set { mDeadHide = value; } } public bool IsInPVP() { return this.Virtual.IsInPVP(); } public bool IsInPVE() { return this.Virtual.IsInPVE(); } virtual public string PlayerUUID { get { return ""; } } //-------------------------------------------------------------------------------------------------------------- private List mMultiTimeLineGroup = new List(); private UnitSyncMultiTimeLine mMultiTimeLineSync; /// /// 注册自定义MultiTimeLine /// /// /// public MultiTimeLine RegistMultiTimeLine(out int index) { index = mMultiTimeLineGroup.Count; var timeline = new MultiTimeLine(MultiTimeLineRefresh); mMultiTimeLineGroup.Add(timeline); return timeline; } ///// ///// 获取指定ID TimeLine ///// ///// ///// //public MultiTimeLine GetTimeLine(int index) //{ // return mMultiTimeLineGroup[index]; //} public bool IsMoveAble() { return this.Info.IsMoveable && this.Info.MoveSpeedSEC > 0; } /// /// 指定TimeLine是否还有任务 /// /// /// public bool IsTimeLineEnable(int index) { return mMultiTimeLineGroup[index].Enable; } /// /// 获取指定 TimeLine 的 ID /// /// /// public int GetTimeLineIndex(MultiTimeLine timeline) { return mMultiTimeLineGroup.IndexOf(timeline); } //是否跟随队长 public virtual bool IsFollowMaster() { return false; } /// /// 添加TimeLine任务 /// /// /// /// public TimeExpire AddTimeLineTask(int index, int timeMS) { return mMultiTimeLineGroup[index].Add(timeMS); } /// /// 强制移除TimeLine任务 /// /// /// /// public bool RemoveTimeLineTask(int index, TimeExpire task) { return mMultiTimeLineGroup[index].Remove(task); } //-------------------------------------------------------------------------------------------------------------- /// /// 被击中后不会被中断(霸体),是一个叠加值 /// private MultiTimeLine mNoneBlockTimeMS; /// /// 眩晕,移动限制状态,是一个叠加值 /// private MultiTimeLine mStunTimeMS; /// /// 隐形,是一个叠加值 /// private MultiTimeLine mInvisibleTimeMS; /// /// 无敌时间,是个叠加值 /// private MultiTimeLine mInvincibleTimeMS; /// /// 沉默时间,是个叠加值 /// private MultiTimeLine mSilentTimeMS; /// /// 沉默时间,是个叠加值 /// private MultiTimeLine mCannotMoveTimeMS; /// /// 免控时间 /// private MultiTimeLine mIgnoreControl; //是否刷新标记 private bool mNeedUpdate = false; public bool IsCanLaunchSkill(int skillID) { if (this.IsStun || (this.IsSilent == true && skillID != this.Virtual.GetBaseSkillID())) { return false; } return true; } private void InitTimeLines() { int index; mNoneBlockTimeMS = RegistMultiTimeLine(out index); mStunTimeMS = RegistMultiTimeLine(out index); mInvisibleTimeMS = RegistMultiTimeLine(out index); mInvincibleTimeMS = RegistMultiTimeLine(out index); mSilentTimeMS = RegistMultiTimeLine(out index); mCannotMoveTimeMS = RegistMultiTimeLine(out index); mIgnoreControl = RegistMultiTimeLine(out index); mMultiTimeLineSync = new UnitSyncMultiTimeLine(this.ID); } private void UpdateTimeLines(int intervalMS) { if(mMultiTimeLineGroup == null || !mNeedUpdate) { return; } bool hasUpdate = false; for (int i = mMultiTimeLineGroup.Count - 1; i >= 0; --i) { if (mMultiTimeLineGroup[i].Update(intervalMS)) { hasUpdate = true; } } // 全部timer都没有,不刷新 if (!hasUpdate) { mNeedUpdate = false; } //不能移动单独刷新,此状态需要通知客户端 if(this.MarkCannotMove && !this.IsCannotMove) { this.MarkCannotMove = false; this.RemoveActionSubState(UnitActionSubStatus.CanNotMove); } if (mMultiTimeLineSync.Update(mMultiTimeLineGroup)) { queueEvent(mMultiTimeLineSync); } } public void MultiTimeLineRefresh(bool isAdd) { this.mNeedUpdate = true; } /// /// 设置霸体时间,如果当前已霸体,则取最大值 /// /// public TimeExpire SetNoneBlockTimeMS(int timeMS) { return mNoneBlockTimeMS.Add(timeMS); } /// /// 设置眩晕时间,如果当前已眩晕,则取最大值 /// /// public TimeExpire SetStunTimeMS(int timeMS) { TimeExpire ret = mStunTimeMS.Add(timeMS); if (!IsStateDead) { changeState(new StateStun(this)); } return ret; } /// /// 设置隐身时间,如果当前已隐身,则取最大值 /// /// public TimeExpire SetInvisibleTimeMS(int timeMS) { return mInvisibleTimeMS.Add(timeMS); } /// /// 设置无敌时间,如果当前已无敌,则取最大值 /// /// public TimeExpire SetInvincibleTimeMS(int timeMS) { return mInvincibleTimeMS.Add(timeMS); } /// /// 设置沉默时间 /// /// public TimeExpire SetSilentTimeMS(int timeMS) { return mSilentTimeMS.Add(timeMS); } /** 设置无法移动时间 */ public TimeExpire SetCannotMoveTimeMS(int timeMS) { this.MarkCannotMove = true; this.AddActionSubState(UnitActionSubStatus.CanNotMove); return mCannotMoveTimeMS.Add(timeMS); } /// /// 设置免控时间 /// /// public TimeExpire SetIgnoreControlTimeMS(int timeMS) { return mIgnoreControl.Add(timeMS); } public bool RemoveNoneBlock(TimeExpire task) { return mNoneBlockTimeMS.Remove(task); } public bool RemoveStun(TimeExpire task) { return mStunTimeMS.Remove(task); } public bool RemoveInvisible(TimeExpire task) { return mInvisibleTimeMS.Remove(task); } public bool RemoveInvincible(TimeExpire task) { return mInvincibleTimeMS.Remove(task); } public bool RemoveSilent(TimeExpire task) { return mSilentTimeMS.Remove(task); } public bool RemoveCannotMove(TimeExpire task) { return mCannotMoveTimeMS.Remove(task); } public bool RemoveIgnoreControl(TimeExpire task) { return mIgnoreControl.Remove(task); } public void ClearNoneBlock() { mNoneBlockTimeMS.Clear(); } public void ClearStun() { mStunTimeMS.Clear(); } public void ClearInvisible() { mInvisibleTimeMS.Clear(); } public void ClearInvincible() { mInvincibleTimeMS.Clear(); } public void ClearSilent() { mSilentTimeMS.Clear(); } public void ClearCannotMove() { mCannotMoveTimeMS.Clear(); } public void ClearIgnoreControl() { mIgnoreControl.Clear(); } #endregion //-----------------------------------------------------------------------------------------------------// //----------------------------------------------------------------------------------------------- #region _技能状态类_ public PlayerSkillChangedEvent GetSkillEvent() { PlayerSkillChangedEvent evt = new PlayerSkillChangedEvent(ID); evt.unitFastCastRate = this.mFastCastRate; if (mDefaultSkill != null) { evt.baseSkill = mDefaultSkill.Data; } foreach (SkillState sk in mSkillStatus.Skills) { if (sk.GetSkillType() != XmdsSkillType.cardSkill && (evt.baseSkill == null || sk.Data.TemplateID != evt.baseSkill.ID)) { sk.Data.CurUseTimes = (short)sk.OveryLayer; evt.skills.Add(sk.Data); } } return evt; } public ClientStruct.UnitSkillStatus[] GetCurrentSkillStatus() { ClientStruct.UnitSkillStatus[] ret = new ClientStruct.UnitSkillStatus[mSkillStatus.Count]; int i = 0; foreach (SkillState sk in mSkillStatus.Skills) { ret[i].SkillTemplateID = (sk.Data.TemplateID); ret[i].PassTime = (sk.PassTime); ret[i].useTimes = sk.OveryLayer; i++; } return ret; } /// /// 初始化技能可用性 /// public PlayerSkillActiveChangedEvent GetSyncSkillActives() { PlayerSkillActiveChangedEvent mSyncSkillActives = new PlayerSkillActiveChangedEvent(this.ID, mSkillStatus.Count); foreach (SkillState st in mSkillStatus.Skills) { PlayerSkillActiveChangedEvent.State sat = new PlayerSkillActiveChangedEvent.State(); sat.SkillTemplateID = st.ID; sat.ST = st.ActiveState; mSyncSkillActives.Skills.Add(sat); } return mSyncSkillActives; } private SkillMap mSkillStatus = new SkillMap(); private SkillState mDefaultSkill; private List mAllSkills = new List(); private bool mSyncSkillActivesChanged = false; private void updateSyncSkillActives() { if (mSyncSkillActivesChanged) { mSyncSkillActivesChanged = false; queueEvent(GetSyncSkillActives()); } } protected bool DoTryAddSkill(ref SkillTemplate sk) { bool ret = true; if (mOnTryAddSkill != null) { foreach (TryAddSkill tryadd in mOnTryAddSkill.GetInvocationList()) { if (!tryadd.Invoke(this, ref sk)) { ret = false; } } } return ret; } /// /// 重置当前单位技能,当前单位技能重置为单位模板指定技能 /// public void ResetSkills() { if (mFormula.TryResetSkill(this)) { InitSkills(mInfo.BaseSkillID, mInfo.Skills.ToArray()); } } /// /// 设置当前单位技能 /// /// /// public virtual void InitSkills(LaunchSkill baseSkill, LaunchSkill[] skills) { List exist = new List(mSkillStatus.Skills); mSyncSkillActivesChanged = true; mDefaultSkill = null; mSkillStatus.Clear(); mAllSkills.Clear(); foreach (SkillState st in exist) { if (mOnSkillRemoved != null) { mOnSkillRemoved.Invoke(this, st); } } if (baseSkill != null) { SkillTemplate st = Templates.getSkill(baseSkill.SkillID); if (DoTryAddSkill(ref st)) { if (st != null && !mSkillStatus.ContainsKey(baseSkill.SkillID)) { mDefaultSkill = new SkillState(st, baseSkill, this); mAllSkills.Add(st); mSkillStatus.Add(mDefaultSkill); if (mOnSkillAdded != null) { mOnSkillAdded.Invoke(this, mDefaultSkill); } } } } foreach (LaunchSkill lsk in skills) { SkillTemplate stt = Templates.getSkill(lsk.SkillID); if (DoTryAddSkill(ref stt)) { if (stt != null && !mSkillStatus.ContainsKey(lsk.SkillID)) { SkillState sk = new SkillState(stt, lsk, this); mAllSkills.Add(stt); mSkillStatus.Add(sk); if (mOnSkillAdded != null) { mOnSkillAdded.Invoke(this, sk); } } } } if (IsInZone) { Parent.queueObjectEvent(this, GetSkillEvent()); } if (mOnSkillChanged != null) { mOnSkillChanged.Invoke(this, mDefaultSkill, mSkillStatus.SkillsArray); } } /// /// 设置当前单位技能 /// /// /// public void InitSkills(SkillTemplate baseSkill, SkillTemplate[] skills) { List exist = new List(mSkillStatus.Skills); mSyncSkillActivesChanged = true; mDefaultSkill = null; mSkillStatus.Clear(); mAllSkills.Clear(); foreach (SkillState st in exist) { if (mOnSkillRemoved != null) { mOnSkillRemoved.Invoke(this, st); } } if (baseSkill != null) { if (DoTryAddSkill(ref baseSkill)) { if (baseSkill != null && !mSkillStatus.ContainsKey(baseSkill.ID)) { mDefaultSkill = new SkillState(baseSkill, new LaunchSkill(baseSkill.ID), this); mAllSkills.Add(baseSkill); mSkillStatus.Add(mDefaultSkill); if (mOnSkillAdded != null) { mOnSkillAdded.Invoke(this, mDefaultSkill); } } } } foreach (SkillTemplate ssk in skills) { SkillTemplate stt = ssk; if (DoTryAddSkill(ref stt)) { if (stt != null && !mSkillStatus.ContainsKey(stt.ID)) { LaunchSkill lsk = null; foreach(LaunchSkill _lsk in mInfo.Skills) { if (_lsk.SkillID == stt.ID) { lsk = _lsk; break; } } if (lsk == null) lsk = new LaunchSkill(stt.ID); SkillState state = new SkillState(stt, lsk, this); mAllSkills.Add(stt); mSkillStatus.Add(state); if (mOnSkillAdded != null) { mOnSkillAdded.Invoke(this, state); } } } } if (IsInZone) { Parent.queueObjectEvent(this, GetSkillEvent()); } if (mOnSkillChanged != null) { mOnSkillChanged.Invoke(this, mDefaultSkill, mSkillStatus.SkillsArray); } } public SkillState AddSkill(SkillTemplate st, bool autoLaunch, bool is_default = false) { if (DoTryAddSkill(ref st)) { if (st != null && !mSkillStatus.ContainsKey(st.ID)) { mSyncSkillActivesChanged = true; SkillState state = new SkillState(st, new LaunchSkill(st.ID, autoLaunch), this); mAllSkills.Add(st); mSkillStatus.Add(state); if (is_default) { mDefaultSkill = state; } if (IsInZone) { st.CurUseTimes = (short)state.OveryLayer; Parent.queueObjectEvent(this, new PlayerSkillAddedEvent(ID, st, is_default)); } if (mOnSkillAdded != null) { mOnSkillAdded.Invoke(this, state); } if (mOnSkillChanged != null) { mOnSkillChanged.Invoke(this, mDefaultSkill, mSkillStatus.SkillsArray); } return state; } } return null; } public SkillState RemoveSkill(int skillTemplateID) { SkillState state = mSkillStatus.RemoveByKey(skillTemplateID); if (state != null) { mSyncSkillActivesChanged = true; mAllSkills.RemoveAll((t) => { return (t.TemplateID == skillTemplateID); }); if (state == mDefaultSkill) { mDefaultSkill = null; } if (IsInZone) { Parent.queueObjectEvent(this, new PlayerSkillRemovedEvent(ID, skillTemplateID)); } if (mOnSkillRemoved != null) { mOnSkillRemoved.Invoke(this, state); } if (mOnSkillChanged != null) { mOnSkillChanged.Invoke(this, mDefaultSkill, mSkillStatus.SkillsArray); } } return state; } public SkillTemplate DefaultSkill { get { if (mDefaultSkill != null) { return mDefaultSkill.Data; } return null; } } public SkillState DefaultSkillStatus() { return mDefaultSkill; } public IEnumerable SkillStatus { get { return mSkillStatus.Skills; } } public SkillTemplate getSkill(int skillID) { SkillState st = mSkillStatus.Get(skillID); if (st != null) { return st.Data; } return null; } public SkillState getSkillState(int skillID) { SkillState st = mSkillStatus.Get(skillID); if (st != null) { return st; } return null; } public void onSkillHitTarget() { if (mOnSkillHitTarger != null) mOnSkillHitTarger.Invoke(); } /// /// 获得当前随机可释放的技能 /// /// /// public virtual SkillState getRandomLaunchableExpectSkill(SkillTemplate.CastTarget expectTarget) { int rand = RandomN.Next(0, mAllSkills.Count); for (int si = mAllSkills.Count - 1; si >= 0; --si) { SkillTemplate st = mAllSkills[CMath.cycNum(rand, si, mAllSkills.Count)]; if (st.ExpectTarget == expectTarget) { SkillState sst = mSkillStatus.Get(st.GetID()); if (sst.LaunchSkill.AutoLaunch && sst.TryLaunch() && sst.CanAutoLaunch()) { return sst; } } } return null; } /// /// 获得当前随机可释放的技能 /// /// /// /// /// /// public virtual SkillState getRandomLaunchableExpectSkill(InstanceUnit target, SkillTemplate.CastTarget expectTarget, AttackReason reason = AttackReason.Tracing, bool checkRange = false) { int rand = RandomN.Next(0, mAllSkills.Count); for (int si = mAllSkills.Count - 1; si >= 0; --si) { SkillTemplate st = mAllSkills[CMath.cycNum(rand, si, mAllSkills.Count)]; if (st.ExpectTarget == expectTarget) { SkillState sst = mSkillStatus.Get(st.GetID()); if (sst.LaunchSkill.AutoLaunch && sst.TryLaunch() && Parent.IsAttackable(this, target, expectTarget, reason, st)) { if (!checkRange || sst.checkTargetRange(target)) { return sst; } } } } return null; } /// /// 获得当前随机可释放的技能 /// /// public virtual SkillState getRandomLaunchableSkill() { int rand = RandomN.Next(0, mAllSkills.Count); for (int si = mAllSkills.Count - 1; si >= 0; --si) { SkillTemplate st = mAllSkills[CMath.cycNum(rand, si, mAllSkills.Count)]; SkillState sst = mSkillStatus.Get(st.GetID()); if (sst.TryLaunch()) { return sst; } } return null; } public void getKeepSkills(List keeps, List ret) { foreach (SkillState st in mSkillStatus.Skills) { if (keeps.Contains(st.ID)) { ret.Add(st.LaunchSkill); } } } private void updateSkills() { //int intervalMS = Parent.UpdateIntervalMS; //for (int i = 0; i < mSkillStatus.Count; i++) //{ // SkillState st = mSkillStatus.GetAt(i); // st.Update(intervalMS); //} mSkillStatus.update(Parent.UpdateIntervalMS); } protected virtual void clearSkills() { this.mSkillStatus.Clear(); } // Skills class SkillMap { private HashMap Map = new HashMap(); private List For = new List(); public int Count { get { return For.Count; } } public IEnumerable Skills { get { return For; } } public SkillState[] SkillsArray { get { return For.ToArray(); } } public SkillState GetAt(int i) { return For[i]; } public SkillState Get(int id) { return Map.Get(id); } public void Add(SkillState state) { if (!Map.ContainsKey(state.ID)) { Map.Put(state.ID, state); For.Add(state); } } public SkillState RemoveByKey(int id) { SkillState ret = Map.RemoveByKey(id); if (ret != null) { For.Remove(ret); } return ret; } public bool ContainsKey(int id) { return Map.ContainsKey(id); } public void Clear() { Map.Clear(); For.Clear(); } public void update(int intervalMS) { foreach (SkillState st in this.For) { st.Update(intervalMS); } } } public delegate void ISkillCDStatusChange(SkillState skill, bool iscd); public class SkillState { // 技能CD状态更改监听 readonly private List mSkillCDStatusChange = new List(); readonly public SkillTemplate Data; readonly public LaunchSkill LaunchSkill; readonly public InstanceUnit Owner; private SkillActiveState current_state = SkillActiveState.Active; private int total_cd_time; private int decrease_total_timems; private int trigger_decrease_times; //机制触发,减少CD // 叠层 private int overLayer = -1; /// /// 从技能开始时的逝去时间 /// private int pass_time; /// /// 最后CD完成时间 /// private int stop_time; /// /// 如果是多段攻击,记录段数 /// private int action_step = -1; private int lockActionStep = -1; //锁定执行序列号 // 是否是多段式技能 private bool mCanStoreTimes = false; /// /// 多段攻击自动下段 /// private bool auto_increase_action_step = true; /// /// 当前是否在冷却 /// private bool is_cd = false; /// /// 当前是否在多段攻击允许时间内 /// private bool is_in_mutil_time = true; /// /// 当前释放技能时的状态机 /// private StateSkill state; private float action_speed; public int ID { get { return Data.ID; } } /// /// 当前技能是否在转CD /// public bool IsCD { get { return is_cd; } } public SkillActiveState ActiveState { get { return current_state; } } public bool IsActive { get { return current_state == SkillActiveState.Active || current_state == SkillActiveState.ActiveAndHide; } } public bool IsPauseOnDeactive { get { return current_state == SkillActiveState.DeactiveAndPause; } } public XmdsSkillType GetSkillType() { return this.Data.Properties.GetSkillType(); } //是否是多段式技能 private byte mMaxMutilStep = 0; //代码逻辑控制cd private bool mCodeControl_HasNext; /// /// 当前技能是否放完 /// public bool IsDone { get { if (Data.IsCoolDownWithAction) { if (state == null) return true; if (state.IsDone) return true; if (state.IsCancelableBySkill) return true; return false; } else if (this.IsMutilAction() && this.IsHasNext())//多段式攻击 { if (is_in_mutil_time) { return true; } } return !is_cd; } } public bool CanAutoLaunch() { return this.stop_time == 0 || this.GetSkillType() == XmdsSkillType.normalAtk || this.stop_time + 2000 < this.pass_time || this.IsInMutilTime; } public bool IsCodeConttrolCD() { return this.mCodeControl_HasNext; } /// /// CD 需要的总时间 /// public int TotalCDTime { get { return total_cd_time - this.trigger_decrease_times; } set { total_cd_time = value; } } /// /// CD 需要的总时间 /// public bool IsInMutilTime { get { return is_in_mutil_time; } set { is_in_mutil_time = value; } } public void ResetTotalTime() { this.total_cd_time = Data.ToUnitSkillTotalTime(Owner.mFastCastRate) - decrease_total_timems; this.total_cd_time = Math.Max(0, this.total_cd_time); } public int PassTime { get { return pass_time; } } public int OveryLayer { get { return this.overLayer; } } public void ResetPassTime() { this.pass_time = 0; } public void SetCDStates(bool cdStatus) { this.is_cd = cdStatus; for (int i = 0; i < mSkillCDStatusChange.Count; i++) { mSkillCDStatusChange[i].Invoke(this, this.is_cd); } } public void ResgistSkillCDChangeListen(ISkillCDStatusChange listen) { if(listen != null) { this.mSkillCDStatusChange.Add(listen); } } public bool IsMutilAction() { return Data.IsSingleAction && (Data.ActionQueue.Count > 1); } public bool IsHasNext() { bool isHasNext = this.ActionIndex < this.mMaxMutilStep; if(!isHasNext && this.Data.ActionQueue.Count > this.ActionIndex && this.Data.ActionQueue[this.ActionIndex].IsCancelBySkillNext) { isHasNext = true; } return isHasNext; } public byte GetMaxMutilStep() { return this.mMaxMutilStep; } public int GetMaxSteps() { return this.mMaxMutilStep > 0 ? Math.Min(this.mMaxMutilStep, this.Data.ActionQueue.Count-1) : (this.Data.ActionQueue.Count-1); } public UnitActionData GetNextAction() { if(this.ActionIndex + 1 >= this.Data.ActionQueue.Count) { return null; } return this.Data.ActionQueue[this.ActionIndex + 1]; } public UnitActionData GetCurAction() { if (this.ActionIndex < 0 || this.ActionIndex >= this.Data.ActionQueue.Count) { return null; } return this.Data.ActionQueue[this.ActionIndex]; } public float ActionSpeed { get { return action_speed; } } public int ActionIndex { get { return action_step; }} public int LockActionStep { get { return lockActionStep; } set { lockActionStep = value; } } public object Tag { get; set; } public bool CanStoreTimes { get { return this.mCanStoreTimes; }} internal SkillState(SkillTemplate data, LaunchSkill skill, InstanceUnit owner) { this.Owner = owner; this.Data = data; this.mCanStoreTimes = (this.Data.Properties.GetSkillUseTimes() > 1 && this.Data.Properties.GetSkillAddTimeInterval() > 0); //默认有最大层数 if (this.mCanStoreTimes) { this.overLayer = this.Data.Properties.GetSkillUseTimes(); } this.LaunchSkill = skill; this.total_cd_time = Data.ToUnitSkillTotalTime(Owner.mFastCastRate) - decrease_total_timems; this.pass_time = int.MaxValue / 2; this.action_speed = data.ActionSpeedRate + Owner.__mSkillActionSpeedRate; // 多段式技能,但是只能释放一段 if(Data.IsSingleAction && (Data.ActionQueue.Count > 1)) { for (int i = 0; i < Data.ActionQueue.Count; i++) { this.mMaxMutilStep = (byte)i; if (Data.ActionQueue[i].SigleActionType == ActionEnum.forbidNext || Data.ActionQueue[i].SigleActionType == ActionEnum.forbidNext_lock || Data.ActionQueue[i].SigleActionType == ActionEnum.forbidNext_showTime) { break; } } } } //设置自动释放 public void setAutoLaunch(bool AutoLaunch) { this.LaunchSkill.AutoLaunch = AutoLaunch; } public void setMaxMutilStep(int vlaue) { this.mMaxMutilStep = (byte)vlaue; } public void SetActionIndex(int index) { this.action_step = index; } // 设置机制冷却缩减时间 public void setTriggerDecreaseTime(int time, bool notify = false) { this.trigger_decrease_times = time; // time==0是开始释放时的重置 if(notify) { PlayerCDEvent evt = new PlayerCDEvent(this.Owner.ID); evt.is_decrease_time = true; evt.is_all = false; evt.decrease_timeMS = time; evt.skill_template_id = this.LaunchSkill.SkillID; this.Owner.Parent.queueObjectEvent(this.Owner, evt); } } /// /// 检测目标距离 /// /// public bool checkTargetRange(InstanceUnit targetUnit) { if (Data.AttackMustBeInRange && Data.AttackAngle == 0) { if (targetUnit != null) { float rg = Owner.GetSkillAttackRange(this.Data, targetUnit); if (Collider.Object_HitBody_TouchRound(targetUnit, Owner.X, Owner.Y, rg)) { return true; } } return false; } return true; } /// /// 检测目标距离 /// /// public bool checkTargetInAttackRange(InstanceUnit targetUnit, LaunchSkillParam param) { //只处理怪物的自动战斗,玩家控制不了 if (this.Owner.IsMonster && this.Data.AttackKeepRange > 0) { targetUnit = targetUnit == null ? this.Owner.Parent.getUnit(param.TargetUnitID) : targetUnit; if (targetUnit != null && CMath.getDistance(targetUnit.X, targetUnit.Y, this.Owner.X, this.Owner.Y) < Data.AttackKeepRange) { return false; } } if (this.Data.AttackRange > 0) { targetUnit = targetUnit == null ? this.Owner.Parent.getUnit(param.TargetUnitID) : targetUnit; if (targetUnit != null && CMath.getDistance(targetUnit.X, targetUnit.Y, this.Owner.X, this.Owner.Y) > (Owner.GetSkillAttackRange(this.Data) + targetUnit.BodyBlockSize)) { return false; } } return true; } public void SetDecreaseTotalTimeMS(int timeMS) { this.decrease_total_timems = timeMS; } public void AddDecreaseTotalTimeMS(int timeMS) { this.decrease_total_timems += timeMS; } public int GetDecreaseTotalTimeMS() { return this.decrease_total_timems; } /// /// 指定技能动作 /// /// public void Reset(bool init = false) { this.action_step = -1; if (!init) { this.IsInMutilTime = false; } } /// /// 设置是否自动控制多段攻击(如果要手动指定播放技能,则设置为False) /// /// public void SetAutoIncreaseActionIndex(bool at) { this.auto_increase_action_step = at; } internal void Launch(StateSkill s, LaunchSkillParam param) { this.NextAction(); this.total_cd_time = this.GetDefTotalCDTime(); this.pass_time = 0; this.state = s; this.SetCDStates(true); } private int GetDefTotalCDTime() { int cd_time = 0; cd_time = Data.ToUnitSkillTotalTime(Owner.mFastCastRate) - decrease_total_timems; if(this.GetSkillType() == XmdsSkillType.normalAtk) { cd_time = (int)(cd_time / (Owner.GetAttackSpeed() * 0.0001f)); } else { cd_time = (int)((1.0f - Math.Min(XmdsConstConfig.SKILL_CD_REDUCE_MAX, Owner.SkillCdReduce) * 0.0001f) * cd_time); } cd_time = Math.Max(0, cd_time); return cd_time; } public void updateOverLayer(int value) { this.overLayer = value; //通知叠层 var queData = new PlayerSkillUseTimeChangedEvent(this.Owner.ID, this.Data.ID, (byte)this.overLayer); queData.hasNext = (byte)((this.OveryLayer >= this.Data.Properties.GetSkillUseTimes()) ? 0 : 1); this.Owner.queueEvent(queData); } public void StartCD(int total_time = 0) { if (total_time > 0) { this.total_cd_time = Math.Max(0, total_time - decrease_total_timems); } else { //this.total_cd_time = Data.ToUnitSkillTotalTime(Owner.mFastCastRate) - decrease_total_timems; //this.total_cd_time = Math.Max(0, this.total_cd_time); this.total_cd_time = this.GetDefTotalCDTime(); } this.pass_time = 0; this.SetCDStates(true); Owner.queueEvent(new PlayerSkillTimeChangedEvent(Owner.ID, ID, this.pass_time, this.TotalCDTime)); } public void LogicToCD() { this.mCodeControl_HasNext = true; this.StartCD(); } public void SetCodeControlNext() { this.mCodeControl_HasNext = false; } public void ForceIntoCD() { this.is_in_mutil_time = false; this.action_step = -1; this.StartCD(); } internal void Stop(StateSkill s) { this.state = null; // CD 依靠动作结束 if (Data.IsCoolDownWithAction) { this.SetCDStates(false); this.stop_time = this.pass_time; } } internal void Update(int intervalMS) { if (!IsActive && IsPauseOnDeactive) { return; } this.pass_time += intervalMS; if(this.CanStoreTimes) { if(this.overLayer < Data.Properties.GetSkillUseTimes() && this.pass_time >= Data.Properties.GetSkillAddTimeInterval()) { this.pass_time = 0; this.updateOverLayer(this.overLayer + 1); } } else if (is_cd && !Data.IsCoolDownWithAction) { // 技能 CD if (this.pass_time >= TotalCDTime) { if(this.IsMutilAction() && (this.is_in_mutil_time || (this.action_step >= Data.ActionQueue.Count))) { if(this.action_step < Data.ActionQueue.Count && this.action_step > 0 && (Data.ActionQueue[this.action_step].SigleActionType == ActionEnum.chargeAtk || Data.ActionQueue[this.action_step].SigleActionType == ActionEnum.IsAutoNext)) { pass_time = 0; return; } else { this.Reset(); this.StartCD(); } } else { this.is_in_mutil_time = true; this.SetCDStates(false); this.stop_time = this.pass_time; //Console.WriteLine("out cd : " + TimeUtil.GetTimestampMS()); } } } } public bool TryLaunch() { if (!IsActive) { return false; } if (!this.Owner.IsCanLaunchSkill(Data.TemplateID)) { return false; } //if (Owner.__mCurrentHP.Value >= Data.CostHP) { return IsDone; } //return false; } public int NextAction() { if (Data.IsSingleAction && auto_increase_action_step) { int action_time = this.TotalCDTime; // 是放技能时,处于多段攻击连击冷却时间范围 //if (pass_time - stop_time < Data.SingleActionCoolDownMS || pass_time < (action_time + Data.SingleActionCoolDownMS)) if (this.action_step < 0) { this.action_step = 0; } else { if (Data.IsCoolDownWithAction) { action_time = Data.ActionQueue[action_step % Data.ActionQueue.Count].TotalTimeMS; } if (this.IsMutilAction()) { if (this.IsInMutilTime || (this.Data.IsCoolDownWithAction && this.IsDone) || (!this.IsDone && this.action_step < this.mMaxMutilStep)) { this.action_step += 1; this.action_step = (byte)(action_step % Data.ActionQueue.Count); //if (this.action_step >= Data.ActionQueue.Count || !IsCanLaunchNextStepByPlayer(Data.ActionQueue[this.action_step])) //{ // this.action_step = 0; // this.is_in_mutil_time = false; //} } } } } return action_step; } public bool IsCanLaunchNextStepByPlayer(UnitActionData actionData) { // = this.Data.ActionQueue[this.ActionIndex]; if (actionData.SigleActionType == ActionEnum.forbidNext || actionData.SigleActionType == ActionEnum.forbidNext_lock) { return false; } return true; } internal void ClearCD() { this.pass_time = TotalCDTime; } internal void DecreaseSkillCD(int timeMS) { if (!Data.IsCoolDownWithAction) { this.pass_time += timeMS; } } internal void DecreaseSkillCD_Pct(float percent) { if (!Data.IsCoolDownWithAction) { this.pass_time += (int)(TotalCDTime * percent); } } internal void SetPassTime(int passtime) { if (!Data.IsCoolDownWithAction) { if (passtime != this.pass_time) { this.pass_time = passtime; Owner.queueEvent(new PlayerSkillTimeChangedEvent(Owner.ID, ID, this.pass_time, this.total_cd_time)); if (pass_time < TotalCDTime) { this.SetCDStates(true); } } } } internal bool TrySetActive(SkillActiveState state) { if (state != current_state) { this.current_state = state; this.Owner.mSyncSkillActivesChanged = true; return true; } return false; } } /// /// 设置技能可用性 /// /// /// /// public void SetSkillActive(int skillTemplateID, bool active, bool pause_on_deactive = false) { SkillState st = getSkillState(skillTemplateID); if (st != null) { if (active) st.TrySetActive(SkillActiveState.Active); else if (pause_on_deactive) st.TrySetActive(SkillActiveState.DeactiveAndPause); else st.TrySetActive(SkillActiveState.Deactive); } //标记冻结 this.Virtual.SetSkillActive(skillTemplateID, active, pause_on_deactive); } public void SetSkillActive(int skillTemplateID, SkillActiveState state) { SkillState st = getSkillState(skillTemplateID); if (st != null) { st.TrySetActive(state); } } /// /// 清除技能CD /// /// public void ClearSkillCD(int skillTemplateID) { SkillState ss = getSkillState(skillTemplateID); if (ss != null) { ss.ClearCD(); PlayerCDEvent evt = new PlayerCDEvent(ID); evt.is_clear = true; evt.is_all = false; evt.skill_template_id = skillTemplateID; Parent.queueObjectEvent(this, evt); } } /// /// 清除所有技能CD /// public void ClearAllSkillCD() { foreach (SkillState ss in mSkillStatus.Skills) { ss.ClearCD(); } PlayerCDEvent evt = new PlayerCDEvent(ID); evt.is_clear = true; evt.is_all = true; Parent.queueObjectEvent(this, evt); } /// /// 减少当前CD固定时间 /// /// /// public void DecreaseSkillCD(int skillTemplateID, int updateTimeMS) { SkillState ss = getSkillState(skillTemplateID); if (ss != null) { ss.DecreaseSkillCD(updateTimeMS); PlayerCDEvent evt = new PlayerCDEvent(ID); evt.is_decrease_time = true; evt.is_all = false; evt.decrease_timeMS = updateTimeMS; evt.skill_template_id = skillTemplateID; Parent.queueObjectEvent(this, evt); } } /// /// 减少当前CD固定时间 /// /// public void DecreaseAllSkillCD(int updateTimeMS) { foreach (SkillState ss in mSkillStatus.Skills) { ss.DecreaseSkillCD(updateTimeMS); } PlayerCDEvent evt = new PlayerCDEvent(ID); evt.is_decrease_time = true; evt.is_all = true; evt.decrease_timeMS = updateTimeMS; Parent.queueObjectEvent(this, evt); } public void DecreaseSkillCD_Pct(int skillTemplateID, float percent) { SkillState ss = getSkillState(skillTemplateID); if (ss != null) { ss.DecreaseSkillCD_Pct(percent); PlayerCDEvent evt = new PlayerCDEvent(ID); evt.is_decrease_pct = true; evt.is_all = false; evt.decrease_pct = percent; evt.skill_template_id = skillTemplateID; Parent.queueObjectEvent(this, evt); } } public void DecreaseAllSkillCD_Pct(float percent) { foreach (SkillState ss in mSkillStatus.Skills) { ss.DecreaseSkillCD_Pct(percent); } PlayerCDEvent evt = new PlayerCDEvent(ID); evt.is_decrease_pct = true; evt.is_all = true; evt.decrease_pct = percent; Parent.queueObjectEvent(this, evt); } public void SetSkillPassTime(int skillID, int passTimeMS) { SkillState ss = this.getSkillState(skillID); if (ss != null) { ss.SetPassTime(passTimeMS); } } public void StartSkillCD(int skillID, int totalTimeMS = 0) { SkillState ss = this.getSkillState(skillID); if (ss != null) { ss.StartCD(totalTimeMS); } } #endregion //----------------------------------------------------------------------------------------------- #region _BUFF状态类_ public ClientStruct.UnitBuffStatus[] GetCurrentBuffStatus() { List ret = new List(mBuffs.Count); mBuffs.ForEachRead((buff) => { if (buff.Data.ClientVisible) { ClientStruct.UnitBuffStatus bf = new ClientStruct.UnitBuffStatus(); bf.BuffTemplateID = (buff.Data.TemplateID); bf.SenderID = buff.SenderID; bf.IsEquip = buff.IsEquip; bf.TotalTime = buff.Data.LifeTimeMS; bf.PassTime = (buff.PassTimeMS); bf.OverlayLevel = buff.OverlayLevel; bf.ext = buff.BuffExtData; ret.Add(bf); } return false; }); return ret.ToArray(); } public bool IshasControlBuff(Predicate cb) { bool hasControlBuff = false; mBuffs.ForEachReadTrueReturn((buff) => { if (cb(buff.Data)) { hasControlBuff = true; return true; } return false; }); return hasControlBuff; } public void GetAllBuffStatus(List ret) { mBuffs.ForEachRead((bf) => { ret.Add(bf); return false; }); } private class BuffMap { class BuffList : IEnumerable { readonly public BuffTemplate bufft; private HashMap list; private InstanceUnit.BuffState last; public BuffList(BuffTemplate bufft) { this.bufft = bufft; this.list = new HashMap(1); } public void Add(InstanceUnit.BuffState bs) { if (bs.Data.IsDuplicating) { list.Add(bs.SenderID, bs); } else { list.Add(0, bs); } last = bs; } public InstanceUnit.BuffState Remove(uint unit_id) { if (bufft.IsDuplicating) { InstanceUnit.BuffState bs = list.RemoveByKey(unit_id); if (bs != null && bs == last) { if (list.Count > 0) { foreach (InstanceUnit.BuffState bf in list.Values) { last = bf; break; } } else { last = null; } } return bs; } else { last = null; return list.RemoveByKey(0); } } public void Clear(List cleared) { last = null; cleared.AddRange(list.Values); list.Clear(); } public InstanceUnit.BuffState Get(uint unit_id) { return list.Get(unit_id); } public int Count { get { return list.Count; } } public InstanceUnit.BuffState Last { get { return last; } } IEnumerator IEnumerable.GetEnumerator() { return list.Values.GetEnumerator(); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return list.Values.GetEnumerator(); } } private HashMap mObjects = new HashMap(); private List mObjectsList = new List(); private bool dirty = true; public int Count { get { return mObjects.Count; } } //----------------------------------------------------------------------- // read //----------------------------------------------------------------------- public InstanceUnit.BuffState GetObject(int id) { BuffList list; if (mObjects.TryGetValue(id, out list)) { return list.Last; } return null; } public void GetObjects(int id, List ret) { BuffList list; if (mObjects.TryGetValue(id, out list)) { ret.AddRange(list); } } public InstanceUnit.BuffState GetObject(int buff_id, uint unit_id) { BuffList list; if (mObjects.TryGetValue(buff_id, out list)) { return list.Get(unit_id); } return null; } //----------------------------------------------------------------------- // write //----------------------------------------------------------------------- public bool RemoveObject(InstanceUnit.BuffState bs) { BuffList list; if (mObjects.TryGetValue(bs.ID, out list)) { dirty = true; return list.Remove(bs.SenderID) != null; } return false; } public InstanceUnit.BuffState RemoveObject(int buffID, uint unit_id) { BuffList list; if (mObjects.TryGetValue(buffID, out list)) { dirty = true; return list.Remove(unit_id); } return null; } public void RemoveObjects(int buffID, List removed) { BuffList list; if (mObjects.TryGetValue(buffID, out list)) { dirty = true; list.Clear(removed); } } public void AddObject(InstanceUnit.BuffState obj) { BuffList list = mObjects.Get(obj.ID); if (list == null) { list = new BuffList(obj.Data); mObjects.Add(obj.ID, list); } list.Add(obj); dirty = true; } private IList Refresh() { if (dirty) { dirty = false; mObjectsList.Clear(); foreach (BuffList list in mObjects.Values) { foreach (InstanceUnit.BuffState buff in list) { mObjectsList.Add(buff); } } } return mObjectsList; } private void ToList(List ret) { foreach (BuffList list in mObjects.Values) { foreach (InstanceUnit.BuffState buff in list) { ret.Add(buff); } } } //----------------------------------------------------------------------- // //----------------------------------------------------------------------- /// /// /// /// 返回true终止迭代! public void ForEachRead(Predicate action) { foreach (BuffList list in mObjects.Values) { foreach (InstanceUnit.BuffState buff in list) { if (action(buff)) { return; } } } } public bool ForEachReadTrueReturn(Predicate action) { foreach (BuffList list in mObjects.Values) { foreach (InstanceUnit.BuffState buff in list) { if (action(buff)) { return true; } } } return false; } /// /// /// /// 返回true终止迭代! public void ForEachWrite(Predicate action) { using (var list = ListObjectPool.AllocAutoRelease()) { ToList(list); for (int i = 0; i < list.Count; i++) { if (action(list[i])) { return; } } } } public void Update(InstanceZone parent) { IList list = Refresh(); for (int i = 0; i < list.Count; i++) { BuffState bs = list[i]; bs.OnUpdate(parent); if (bs.IsEnd() && !bs.MarkRemove) { this.RemoveObject(bs); bs.OnEnd(BuffState.EndResult_ByTimeUp); } } } } public class BuffState { public const string EndResult_ByTimeUp = "time_up"; public const string EndResult_ByReplaced = "replaced"; public const string EndResult_ByClientRemoved = "client_removed"; public const string EndResult_ByCatgoryExclusive = "catgory_exclusive"; public const string EndResult_ByCode = "code"; public const string ENDResult_HuDunBreak = "HuDunBreak"; readonly private BuffTemplate mData; readonly private InstanceUnit mOwner; readonly private InstanceUnit sender; private TimeExpire st_stun; private TimeExpire st_invisible; private TimeExpire st_invincible; private TimeExpire st_silent; private TimeExpire st_canmove; private TimeExpire st_ignoreControl; private int mBuffExtData; //buff扩展字段 private TimeInterval interval; private PopupKeyFrames keyframes; private int total_time; private int passtime; private byte overlay_level; public BuffTemplate Data { get { return mData; } } public int ID { get { return mData.ID; } } public byte OverlayLevel { get { return overlay_level; }} public int PassTimeMS { get { return passtime; } } public int LifeTimeMS { get { return total_time; } } public bool IsEquip { get; private set; } public uint SenderID { get { return sender.ID; } } public int BuffExtData { get { return mBuffExtData; } set { mBuffExtData = value; } } public InstanceZone Zone { get { return mOwner.Parent; } } public InstanceUnit Owner { get { return mOwner; } } public InstanceUnit Sender { get { return sender; } } public object Tag { get; set; } //释放时位置信息 private Vector2 mHitPos = new Vector2(); public bool MarkRemove { get; set; } //set和get放在一起虽然爽,但是可读性真一般 public void SetLayerLevel(byte value) { this.overlay_level = value; } internal BuffState(BuffTemplate data, InstanceUnit unit, InstanceUnit sender, byte overlay_level, bool forever, bool isControlBuf) { this.mData = data; this.mOwner = unit; this.sender = sender; this.IsEquip = forever; this.overlay_level = overlay_level; this.passtime = 0; this.MarkRemove = false; this.interval = new TimeInterval(data.HitIntervalMS); this.interval.FirstTimeEnable = data.FirstTimeEnable; this.interval.Tag = data.HitKeyFrame; this.keyframes = new PopupKeyFrames(); this.keyframes.AddRange(data.KeyFrames); this.total_time = data.LifeTimeMS; //控制增幅 if (sender.__mControledTimeAdd != 0 && (mData.IsSilent || mData.MakeStun || isControlBuf)) { this.total_time = (int)(Math.Max(0.0f, 1.0f + unit.__mControledTimeAdd * 0.0001f) * this.total_time); } //韧性,控制减 if (unit.ControledTimeReduce != 0 && (mData.IsSilent || mData.MakeStun || isControlBuf)) { this.total_time = (int)(Math.Max(0.0f, 1.0f - unit.ControledTimeReduce * 0.0001f) * this.total_time); } } internal void OnStart() { mHitPos.SetX(mOwner.X); mHitPos.SetY(mOwner.Y); mOwner.mFormula.OnBuffBegin(mOwner, this, sender); if (mData.MakeStun) { this.st_stun = mOwner.SetStunTimeMS(total_time); } if (mData.IsInvisible) { this.st_invisible = mOwner.SetInvisibleTimeMS(total_time); } if (mData.IsInvincible) { this.st_invincible = mOwner.SetInvincibleTimeMS(total_time); } if (mData.IsSilent) { this.st_silent = mOwner.SetSilentTimeMS(total_time); } if(!mData.IsCanMove) { this.st_canmove = mOwner.SetCannotMoveTimeMS(total_time); } // 免疫控制 if(mData.IgnoreControl) { this.st_ignoreControl = mOwner.SetIgnoreControlTimeMS(total_time); } if (mData.UnitTrigger != null) { mOwner.addTrigger(mData.UnitTrigger.TriggerTemplateID); } if (mData.UnitChangeSkills) { if (mData.UnitKeepSkillsID != null && mData.UnitKeepSkillsID.Count > 0) { using (var keeps = ListObjectPool.AllocAutoRelease()) { mOwner.getKeepSkills(mData.UnitKeepSkillsID, keeps); keeps.AddRange(mData.UnitSkills); mOwner.InitSkills(mData.UnitBaseSkillID, keeps.ToArray()); } } else { mOwner.InitSkills(mData.UnitBaseSkillID, mData.UnitSkills.ToArray()); } } mOwner.doGotBuff(this); if (mData.ClientVisible) { //Console.WriteLine("获得剑影 - " + this.BuffExtData); mOwner.queueEvent(new UnitLaunchBuffEvent(mOwner.ID, this.ID, this.SenderID, this.LifeTimeMS, this.IsEquip, overlay_level, this.BuffExtData)); } } internal void OnEnd(string result, bool replace = false) { this.passtime = total_time; this.MarkRemove = true; mOwner.doLostBuff(this); if (this.st_stun != null) { mOwner.mStunTimeMS.Remove(st_stun); } if (this.st_invisible != null) { mOwner.mInvisibleTimeMS.Remove(st_invisible); } if (this.st_invincible != null) { mOwner.mInvisibleTimeMS.Remove(st_invincible); } if (this.st_silent != null) { mOwner.mSilentTimeMS.Remove(st_silent); } if(this.st_canmove != null) { mOwner.mCannotMoveTimeMS.Remove(st_canmove); } if(this.st_ignoreControl != null) { mOwner.mIgnoreControl.Remove(st_ignoreControl); } if (mData.UnitTrigger != null) { mOwner.removeTrigger(mData.UnitTrigger.TriggerTemplateID); } if (mData.UnitChangeSkills) { mOwner.ResetSkills(); } if (mData.EndKeyFrame != null) { doKeyFrame(mData.EndKeyFrame); } mOwner.mFormula.OnBuffEnd(mOwner, this, result, replace); if (this.Data.ClientVisible) { if (!replace) { mOwner.queueEvent(new UnitStopBuffEvent(mOwner.ID, this.ID, SenderID)); } } } internal void OnUpdate(InstanceZone zone) { using (var kfs = ListObjectPool.AllocAutoRelease()) { if (keyframes.PopKeyFrames(passtime, kfs) > 0) { foreach (BuffTemplate.KeyFrame kf in kfs) { doKeyFrame(kf); } } } if (interval.Update(zone.UpdateIntervalMS)) { doKeyFrame(mData.HitKeyFrame); mOwner.mFormula.OnBuffUpdate(mOwner, this, interval.TotalTickCount); } passtime += zone.UpdateIntervalMS; } private void doKeyFrame(BuffTemplate.KeyFrame kf) { if (kf != null) { if (kf.Attack != null) { mOwner.doHitAttack(sender, new AttackSource(this, kf.Attack)); } if (kf.Spell != null) { if(kf.Spell.SenderUnit == LaunchSpllSenderUnit.AttackerUnit) { this.sender.Parent.unitLaunchSpell(XmdsSkillType.none, sender, kf.Spell, this.sender.X, this.sender.Y, mOwner.ID, null); } else { mOwner.Parent.unitLaunchSpell(XmdsSkillType.none, sender, kf.Spell, mOwner.X, mOwner.Y, mOwner.ID, null); } } if (kf.Item != null) { mOwner.UseItem(kf.Item.ItemTemplateID); } if(kf.addItem != null) { this.BuffAddItem(kf.addItem); } } } /** buff生成道具 */ private void BuffAddItem(BuffAddItem addItem) { var itemInfo = Zone.Templates.getItem(addItem.ItemTemplateID); if(itemInfo == null) { log.Warn("BuffAddItem找不到指定道具: " + addItem.ItemTemplateID); return; } if(addItem.posType == CommonAI.Zone.BuffAddItem.PosType.HitBuffPos) { this.mOwner.Parent.AddItem(itemInfo, null, this.mHitPos.X, this.mHitPos.Y, 0, this.mOwner.Force, null, this.Owner); } else if(addItem.posType == CommonAI.Zone.BuffAddItem.PosType.BindUnitPos) { this.mOwner.Parent.AddItem(itemInfo, null, this.Owner.X, this.Owner.Y, 0, this.mOwner.Force, null, this.Owner); } else if(addItem.posType == CommonAI.Zone.BuffAddItem.PosType.PointPos) { this.mOwner.Parent.AddItem(itemInfo, null, addItem.pointX, addItem.pointY, 0, this.mOwner.Force, null, this.Owner); } } public bool IsEnd() { if (Data.IsRemoveOnSenderRemoved) { if (!sender.Enable || sender.IsDead()) { return true; } } if(Data.IsRemoveOnDead && this.mOwner.IsDead()) { return true; } if (IsEquip) return false; return (passtime >= total_time); } public void AddLifeTimeMS(int timeMS) { this.total_time += timeMS; } //public void RefrushToMaxOverlayer() //{ // this.overlay_level = this.mData.MaxOverlay; //} } private BuffMap mBuffs = new BuffMap(); /// /// 是否存在技能变身BUFF /// public bool IsBuffChangeSkills { get { return GetChangeSkillBuff() != null; } } /// /// 获得技能变身BUFF /// public BuffState GetChangeSkillBuff() { BuffState ret = null; mBuffs.ForEachRead((bs) => { if (bs.Data.UnitChangeSkills && !bs.IsEnd()) { ret = bs; return true; } return false; }); return ret; } public BuffState GetBuffByID(int buffTemplateID) { return mBuffs.GetObject(buffTemplateID); } public BuffState GetBuffByIDAndSender(int buffTemplateID, uint senderUnitID) { return mBuffs.GetObject(buffTemplateID, senderUnitID); } public BuffState AddBuff(int buffID, int pointMaxOverLayer = 0, bool forever = false, bool bMaxOverlayer = false, bool bMaxReset = false) { BuffTemplate buff = Templates.getBuff(buffID); if (buff != null) { return this.AddBuff(buff, this, pointMaxOverLayer, forever, bMaxOverlayer, 0, false, bMaxReset); } return null; } public BuffState AddBuff(int buffID, InstanceUnit sender, int pointMaxOverLayer = 0, bool forever = false, bool bMaxOverlayer = false, bool bMaxReset = false, int buffExt = 0, int addLyers = 0) { BuffTemplate buff = Templates.getBuff(buffID); if (buff != null) { return this.AddBuff(buff, sender, pointMaxOverLayer, forever, bMaxOverlayer, buffExt, false, bMaxReset, addLyers); } return null; } /** 编辑器直接编写增加buff接口 */ public BuffState AddBuff(LaunchBuff buff, InstanceUnit sender, bool forever = false) { //如果绑定了事件id,就表示去触发事件 if (buff.BuffID == 0 && buff.BindEventID > 0) { BattleFunction.GetInstance().TriggrBattleFunction(buff.BindEventID, this.Virtual, sender == null ? null : sender.Virtual); return null; } return this.AddBuff(buff.BuffID, sender, 0, forever); } /// /// 增加Buff /// /// 如果为True,则表示Buff不受时间CD控制 public virtual BuffState AddBuff(BuffTemplate buff, InstanceUnit sender, int pointMaxOverLayer = 0, bool forever = false, bool bMaxOverlayer = false, int buffExt = 0, bool isControlBuf = false, bool maxReset = false, int addLayers = 0) { object tag = null; if (mFormula.TryAddBuff(this, sender, ref buff, out tag)) { if (!forever && buff.LifeTimeMS <= 0) { return null; } //凌驾于一切之上的免控 if(isControlBuf && this.IsIgnoreControl) { return null; } if (!removeBuffByCatgory(buff.ID, buff.ExclusiveCatgory, buff.ExclusivePriority)) { return null; } int finalMaxOverLay = (pointMaxOverLayer <= 0) ? buff.MaxOverlay : pointMaxOverLayer; int overlay_level = bMaxOverlayer ? (finalMaxOverLay - 1) : 0; BuffState bs = mBuffs.RemoveObject(buff.ID, sender.ID); if (bs != null) { if (buff.IsOverlay) { int finalAddLayer = Math.Max(1, addLayers); if(bs.OverlayLevel + finalAddLayer >= finalMaxOverLay && maxReset) { overlay_level = 0; } else { overlay_level = bMaxOverlayer ? (finalMaxOverLay - 1) : (Math.Min(bs.OverlayLevel + finalAddLayer, finalMaxOverLay - 1)); } } bs.OnEnd(BuffState.EndResult_ByReplaced, true); } else if(addLayers > 0 && buff.MaxOverlay > 0) { overlay_level = Math.Max(0, Math.Min(buff.MaxOverlay - 1, addLayers-1)); } BuffState newbs = new BuffState(buff, this, sender, (byte)overlay_level, forever, isControlBuf); newbs.Tag = tag; newbs.BuffExtData = (bs == null) ? buffExt : bs.BuffExtData; mBuffs.AddObject(newbs); newbs.OnStart(); //System.Console.WriteLine("AddBuf - " + newbs.Data.ID + ", " + newbs.OverlayLevel); mFormula.SendAddBuffEvent(this, sender, buff); return newbs; } return null; } /// /// 移除互斥技能,根据优先级 /// /// /// /// private bool removeBuffByCatgory(int buffID, int catgory, int priority) { if (catgory != 0) { // 检测当时有更高优先级 // { BuffState greater_buff = null; mBuffs.ForEachRead((bs) => { if ((bs.ID != buffID) && (bs.Data.ExclusiveCatgory == catgory) && (bs.Data.ExclusivePriority > priority)) { greater_buff = bs; return true; } return false; }); if (greater_buff != null) { return false; } } // 移除低优先级 // mBuffs.ForEachWrite((bs) => { if ((bs.ID != buffID) && (bs.Data.ExclusiveCatgory == catgory)) { mBuffs.RemoveObject(bs); bs.OnEnd(BuffState.EndResult_ByCatgoryExclusive); } return false; }); } return true; } public void removeBuff(int buffID, string result = BuffState.EndResult_ByCode) { using (var bss = ListObjectPool.AllocAutoRelease()) { mBuffs.RemoveObjects(buffID, bss); if (bss.Count > 0) { foreach (BuffState bs in bss) { bs.OnEnd(result); } } } } public void removeBuffBySender(int buffID, uint senderUnitID, string result = BuffState.EndResult_ByCode) { BuffState bs = mBuffs.RemoveObject(buffID, senderUnitID); if (bs != null) { bs.OnEnd(result); } } public void clearBuffs(string result = BuffState.EndResult_ByCode) { mBuffs.ForEachWrite((bs) => { if (!bs.Data.IsPassive && !bs.IsEquip) { mBuffs.RemoveObject(bs); bs.OnEnd(result); } return false; }); } private void updateBuffs() { mBuffs.Update(Parent); } #endregion //--------------------------------------------------------------------------------------------------------------- #region _被动系触发类_ private readonly List mTriggerStatus = new List(); private readonly UnitTriggerHelper mTriggerHelper; /// /// 保存被动状态 /// public class TriggerState { readonly internal UnitTriggerTemplate mData; readonly internal InstanceUnit mOwner; public bool IsDamageTrigger { get; private set; } public bool IsAttackTrigger { get; private set; } public UnitTriggerTemplate Data { get { return mData; } } public object Tag { get; set; } private long launch_time; internal TriggerState(UnitTriggerTemplate data, InstanceUnit unit) { this.mData = data; this.mOwner = unit; this.IsDamageTrigger = false; this.IsAttackTrigger = false; this.launch_time = -mData.CoolDownTimeMS; foreach (BaseTriggerEvent evt in data.Triggers) { UnitTriggerEventTypeAttribute ut = PropertyUtil.GetAttribute(evt.GetType()); foreach (Type dtype in ut.DelegateTypes) { if (dtype == typeof(DamageHandler)) { this.IsDamageTrigger = true; } else if (dtype == typeof(AttackHandler)) { this.IsAttackTrigger = true; } } } } internal void Start(InstanceUnit target) { if (IsActive) { this.launch_time = mOwner.Parent.PassTimeMS; uint targetID = 0; Vector2 targetPos = new Vector2(mOwner.X, mOwner.Y); if (target != null) { targetPos.SetX(target.X); targetPos.SetY(target.Y); targetID = target.ID; } // 如果关键帧绑定特效 if (mData.DoEffect != null) { mOwner.queueEvent(new UnitEffectEvent(mOwner.ID, mData.DoEffect)); } // 如果关键帧绑定释放法术 if (mData.DoSpell != null) { mOwner.Parent.unitLaunchSpell(XmdsSkillType.none, mOwner, mData.DoSpell, mOwner.X, mOwner.Y, 0, targetPos); } // 如果关键帧绑定自己释放BUFF if (mData.DoBuff != null) { mOwner.AddBuff(mData.DoBuff, mOwner); } // 如果关键帧绑定单位位移 if (mData.DoSkill != null) { mOwner.launchSkill(mData.DoSkill.SkillID, new InstanceUnit.LaunchSkillParam(targetID, targetPos)); } //召唤 if (mData.DoSummon != null) { mOwner.Parent.unitSummonUnit(mOwner, mData.DoSummon); } mOwner.mFormula.OnTriggerStart(mOwner, this, target); } } public bool Test(AttackSource source) { if (IsActive) { foreach (BaseTriggerEvent evt in mData.Triggers) { if (!mOwner.mFormula.TryLaunchTrigger(mOwner, mData, evt, source) || !evt.Test(mOwner, source)) { return false; } } return true; } return false; } /// /// 是否处于冷却状态 /// public bool IsActive { get { return (launch_time + mData.CoolDownTimeMS) < mOwner.Parent.PassTimeMS; } } } private void updateTriggers(bool slowRefresh) { this.mFormula.OnUpdateTriggerSkill(this, Parent.UpdateIntervalMS, slowRefresh); } public void addTriggers(ICollection triggers) { foreach (LaunchTrigger launch in triggers) { addTrigger(launch.TriggerTemplateID); } } public bool containsTrigger(int tgID) { for (int i = mTriggerStatus.Count - 1; i >= 0; --i) { if (mTriggerStatus[i].mData.ID == tgID) { return true; } } return false; } public TriggerState findTrigger(int tgID) { for (int i = mTriggerStatus.Count - 1; i >= 0; --i) { if (mTriggerStatus[i].mData.ID == tgID) { return mTriggerStatus[i]; } } return null; } public bool addTrigger(UnitTriggerTemplate trigger) { if (!containsTrigger(trigger.ID)) { TriggerState ts = new TriggerState(trigger, this); mTriggerStatus.Add(ts); } return false; } public bool addTrigger(int triggerID) { if (!containsTrigger(triggerID)) { UnitTriggerTemplate tg = Templates.getUnitTrigger(triggerID); if (tg != null) { TriggerState ts = new TriggerState(tg, this); mTriggerStatus.Add(ts); } } return false; } public void removeTrigger(int tgID) { TriggerState bs = findTrigger(tgID); if (bs != null) { mTriggerStatus.Remove(bs); } } public bool startTrigger(int tgID, InstanceUnit target) { TriggerState bs = findTrigger(tgID); if (bs != null && bs.IsActive) { bs.Start(target); return true; } return false; } public void clearTriggers() { mTriggerStatus.Clear(); } /// /// 如果被攻击,尝试启动单位触发器 /// /// /// public void TryStartDamageTriggers(InstanceUnit attacker, AttackSource source) { foreach (TriggerState ts in this.mTriggerStatus) { if (ts.IsDamageTrigger && ts.Test(source)) { ts.Start(attacker); } } } /// /// 如果攻击别人,尝试启动触发器 /// /// /// public void TryStartAttackTriggers(InstanceUnit target, AttackSource source) { foreach (TriggerState ts in this.mTriggerStatus) { if (ts.IsAttackTrigger && ts.Test(source)) { ts.Start(target); } } } public class UnitTriggerHelper { private readonly InstanceUnit unit; public UnitTriggerHelper(InstanceUnit unit) { this.unit = unit; unit.OnDamage += this.onUnitDamage; unit.OnAttack += this.onUnitAttack; } public void onUnitDamage(InstanceUnit obj, InstanceUnit attacker, int hp, AttackSource source) { unit.TryStartDamageTriggers(attacker, source); } public void onUnitAttack(InstanceUnit obj, InstanceUnit target, int hp, AttackSource source) { unit.TryStartAttackTriggers(target, source); } } #endregion //--------------------------------------------------------------------------------------------------------------- #region _背包和道具_ public ClientStruct.UnitItemStatus[] GetCurrentItemStatus() { ClientStruct.UnitItemStatus[] ret = new ClientStruct.UnitItemStatus[mInventorySlots.Count]; int i = 0; foreach (InventorySlot item in mInventorySlots) { ret[i].ItemTemplateID = item.ItemTemplateID; ret[i].Count = item.Count; i++; } return ret; } public class InventorySlot { readonly public int Index; readonly public InstanceUnit Owner; public InventorySlot(int index, InstanceUnit owner) { this.Index = index; this.Owner = owner; } public bool IsEmpty { get { return (Item == null); } } public int ItemTemplateID { get { if (Item != null) return Item.TemplateID; return 0; } } public ItemTemplate Item { get; private set; } public int Count { get; private set; } internal int AddItem(ItemTemplate item, int count) { if (item == null) return 0; if (count <= 0) return 0; if (this.IsEmpty) { // 背包为空 // this.Item = item; this.Count = Math.Min(this.Item.MaxStackCount, count); this.Owner.doGotInventoryItem(this, item, Index, count); return this.Count; } else if (item.TemplateID == this.ItemTemplateID) { int oldcount = this.Count; // 道具类型一致, 堆叠 // this.Count = Math.Min(this.Item.MaxStackCount, this.Count + count); if (oldcount != this.Count) { this.Owner.doGotInventoryItem(this, item, Index, count); return this.Count - oldcount; } return 0; } return 0; } internal int TryUse(int count) { if (IsEmpty) return 0; if (!Item.IsInventoryUseable) return 0; if (Owner.tryUseItem(Item, Owner)) { return Math.Min(count, this.Count); } return 0; } internal int Use(int count) { if (IsEmpty) return 0; if (!Item.IsInventoryUseable) return 0; if (Owner.tryUseItem(Item, Owner)) { int used = 0; count = Math.Min(count, this.Count); for (int i = 0; i < count; i++) { Owner.UseItem(Item); this.Count--; used++; if (Count == 0) { break; } } this.Owner.doLostInventoryItem(this, Item, Index, count); if (Count == 0) { this.Item = null; } return used; } return 0; } internal int Drop(int count) { if (IsEmpty) return 0; count = Math.Min(count, this.Count); this.Count -= count; if (this.Count <= 0) { this.Count = 0; } this.Owner.doLostInventoryItem(this, Item, Index, count); if (this.Count == 0) { this.Item = null; } return count; } internal int Clean() { return Drop(this.Count); } } private List mInventorySlots = new List(); private HashMap> mCoolDownItems = new HashMap>(); private List> mRemoved = new List>(); private void InitBagSlots() { for (int i = 0; i < mInfo.InventorySize; i++) { mInventorySlots.Add(new InventorySlot(i, this)); } } private bool tryUseItem(ItemTemplate item, InstanceUnit item_creater) { if (mFormula.TryUseItem(this, item, item_creater)) { if (item.UseCoolDownTimeMS > 0) { if (IsItemCoolDown(item.ID)) { return false; } return true; } return true; } return false; } private void beginUseItem(ItemTemplate item) { if (item.UseCoolDownTimeMS > 0) { mCoolDownItems.Put(item.ID, new TimeExpire(item, item.UseCoolDownTimeMS)); } } private void updateItems() { int intervalMS = Parent.UpdateIntervalMS; /* using (var removed = ListObjectPool>.AllocAutoRelease()) { foreach (TimeExpire expire in mCoolDownItems.Values) { if (expire.Update(intervalMS)) { removed.Add(expire); } } if (removed.Count > 0) { foreach (TimeExpire expire in removed) { if (expire.IsEnd) { mCoolDownItems.RemoveByKey(expire.Tag.ID); } } } }*/ if(mCoolDownItems.Count <= 0) { return; } //换一个写法 mRemoved.Clear(); foreach (TimeExpire expire in mCoolDownItems.Values) { if (expire.Update(intervalMS)) { mRemoved.Add(expire); } } if (mRemoved.Count > 0) { foreach (TimeExpire expire in mRemoved) { if (expire.IsEnd) { mCoolDownItems.RemoveByKey(expire.Tag.ID); } } mRemoved.Clear(); } } protected virtual void clearItemSlots() { foreach (var slot in mInventorySlots) { slot.Clean(); } mInventorySlots.Clear(); mCoolDownItems.Clear(); } /// /// 检测此道具是否在CD /// /// /// public bool IsItemCoolDown(int itemTemplateID) { if (mCoolDownItems.ContainsKey(itemTemplateID)) { return true; } return false; } /// /// 添加道具到白空的背包 /// /// /// /// public int AddItemToEmptyInventory(ItemTemplate item, int count = 1) { if (item == null) return 0; if (count <= 0) return 0; if (!item.IsDuplicateInventory || item.HoldingLimit > 0) { int holding = GetItemCountInInventory(item.ID); if (!item.IsDuplicateInventory) { if (holding > 0) { return 0; } count = 1; } if (item.HoldingLimit > 0) { if (holding >= item.HoldingLimit) { return 0; } if (holding + count > item.HoldingLimit) { count = item.HoldingLimit - holding; } if (count <= 0) return 0; } } int added = 0; //优先堆叠// for (int i = 0; i < mInventorySlots.Count; i++) { InventorySlot slot = mInventorySlots[i]; if (slot.ItemTemplateID == item.ID) { added += slot.AddItem(item, count - added); if (added >= count) { break; } } } //使用空闲格子// for (int i = 0; i < mInventorySlots.Count; i++) { InventorySlot slot = mInventorySlots[i]; added += slot.AddItem(item, count - added); if (added >= count) { break; } } return added; } /// /// 添加道具到指定背包 /// /// /// /// /// public int AddItemToInventory(ItemTemplate item, int index, int count = 1) { if (item == null) return 0; if (count <= 0) return 0; if (!item.IsDuplicateInventory || item.HoldingLimit > 0) { int holding = GetItemCountInInventory(item.ID); if (!item.IsDuplicateInventory) { if (holding > 0) { return 0; } count = 1; } if (item.HoldingLimit > 0) { if (holding >= item.HoldingLimit) { return 0; } if (holding + count > item.HoldingLimit) { count = item.HoldingLimit - holding; } if (count <= 0) return 0; } } if (index >= 0 && index < mInventorySlots.Count) { InventorySlot slot = mInventorySlots[index]; return slot.AddItem(item, count); } return 0; } /// /// 添加道具到指定背包 /// /// /// /// /// public int AddItemToInventory(int itemTemplateID, int index, int count = 1) { if (count <= 0) return 0; return AddItemToInventory(Templates.getItem(itemTemplateID), index, count); } private int UseItemInternal(InventorySlot slot, int count) { if (slot.Item != null) { if (slot.Item.UseInProgressTimeMS > 0) { count = slot.TryUse(count); if (count > 0) { this.startPickProgressSelf(slot.Item.UseInProgressTimeMS, (s, p) => { slot.Use(count); }); } return count; } else { return slot.Use(count); } } return 0; } /// /// 使用背包的道具 /// /// /// /// public int UseInventoryItem(int index, int count = 1) { if (count <= 0) return 0; if (index >= 0 && index < mInventorySlots.Count) { InventorySlot slot = mInventorySlots[index]; return UseItemInternal(slot, count); } return 0; } public int UseInventoryItemByType(int itemTemplateID, int count = 1) { if (count <= 0) return 0; for (int i = 0; i < mInventorySlots.Count; i++) { InventorySlot slot = mInventorySlots[i]; if (slot.ItemTemplateID == itemTemplateID) { return UseItemInternal(slot, count); } } return 0; } public int DropInventoryItemByIndex(int index, int count = 1) { if (count <= 0) return 0; if (index >= 0 && index < mInventorySlots.Count) { InventorySlot slot = mInventorySlots[index]; return slot.Drop(count); } return 0; } public int DropInventoryItemByType(int itemTemplateID, int count = 1) { if (count <= 0) return 0; int droped = 0; for (int i = 0; i < mInventorySlots.Count; i++) { InventorySlot slot = mInventorySlots[i]; if (slot.ItemTemplateID == itemTemplateID) { droped += slot.Drop(count); if (droped >= count) { break; } } } return droped; } public int ClearInventoryItemByIndex(int index) { if (index >= 0 && index < mInventorySlots.Count) { InventorySlot slot = mInventorySlots[index]; return slot.Clean(); } return 0; } public int ClearInventoryItemByType(int itemTemplateID) { int droped = 0; for (int i = 0; i < mInventorySlots.Count; i++) { InventorySlot slot = mInventorySlots[i]; if (slot.ItemTemplateID == itemTemplateID) { droped += slot.Clean(); } } return droped; } /// /// 背包内是否有此道具 /// /// /// public bool ContainsItemInInventory(int itemTemplateID) { for (int i = 0; i < mInventorySlots.Count; i++) { InventorySlot slot = mInventorySlots[i]; if (slot.ItemTemplateID == itemTemplateID) { return true; } } return false; } public int GetItemCountInInventory(int itemTemplateID) { int ret = 0; for (int i = 0; i < mInventorySlots.Count; i++) { InventorySlot slot = mInventorySlots[i]; if (slot.ItemTemplateID == itemTemplateID) { ret += slot.Count; } } return ret; } #endregion //--------------------------------------------------------------------------------------------------------------- #region _物理运动_ public bool IsFallingDown { get { if (mCurrentFallingDown != null) return !mCurrentFallingDown.IsEnd; return false; } } public bool IsDamageFallingDown { get { StateDamage damage = (this.CurrentState as StateDamage); if (damage != null) { return damage.IsFallingDown; } return false; } } public bool IsPhysicalMove { get { if (mCurrentStartMove != null) return !mCurrentStartMove.IsEnd; return false; } } private FallingDown mCurrentFallingDown; private HitMoveSpeed mCurrentStartMove; private void updatePhysical() { if (mCurrentFallingDown != null && mCurrentFallingDown.Update(Parent.UpdateIntervalMS)) { mCurrentFallingDown = null; } if (mCurrentStartMove != null && mCurrentStartMove.Update(Parent.UpdateIntervalMS)) { mCurrentStartMove = null; } } /// /// 开始自由落体 /// /// /// /// /// /// public virtual FallingDown StartFly(object launcher, float speedZ, float gravity, float zlimit) { mCurrentFallingDown = new FallingDown(this, speedZ, gravity, zlimit); return mCurrentFallingDown; } /// /// 开始复杂移动 /// /// /// /// /// /// /// /// /// public virtual HitMoveSpeed StartHitMove( object launcher, float direction, float rotateSpeedSEC, int expectlTimeMS, float moveSpeedSEC, float moveSpeedAdd, float moveSpeedAcc, bool isNoneTouch) { if (mCurrentStartMove != null) { mCurrentStartMove.Stop(); } HitMoveSpeed move = new HitMoveSpeed( this, direction, rotateSpeedSEC, expectlTimeMS, moveSpeedSEC, moveSpeedAdd, moveSpeedAcc, isNoneTouch); mCurrentStartMove = move; return move; } /// /// 落体运动 /// public class FallingDown { private readonly InstanceUnit unit; private readonly float gravity; private readonly float z_limit; private float z_speed; public FallingDown(InstanceUnit unit, float zspeed, float zgravity, float zlimit) { this.unit = unit; this.z_limit = zlimit; this.z_speed = zspeed; this.gravity = zgravity == 0 ? unit.Templates.CFG.GLOBAL_GRAVITY : zgravity; this.ExpectTimeMS = MoveHelper.CalculateFlyTimeMS(unit.Z, zspeed, zlimit, gravity, 10); this.IsEnd = false; } public bool Update(int intervalMS) { //向上受到ZLimit限制// unit.Z += MoveHelper.GetDistance(intervalMS, z_speed); unit.Z = Math.Max(0, unit.Z); this.IsEnd = unit.Z <= 0; //骤停// if (z_limit != 0 && z_speed > 0 && unit.Z > z_limit) { z_speed = 0; } this.z_speed -= MoveHelper.GetDistance(intervalMS, gravity); return IsEnd; } public bool IsEnd { get; private set; } public int ExpectTimeMS { get; private set; } public float ZSpeedSEC { get { return z_speed; } } public float ZLimit { get { return z_limit; } } } public class HitMoveSpeed { private readonly InstanceUnit mOwner; private readonly float mStartDirection; private readonly float mMoveSpeedAdd; private readonly float mMoveSpeedAcc; private readonly float mRotateSpeedSEC; private float moveSpeedSEC; private TimeExpire hitMoveTime; private FallingDown hasFly; private IPositionObject moveTarget; private bool moveTargetBody; private bool isNoneTouch = false; public HitMoveSpeed( InstanceUnit owner, float direction, float rotateSpeedSEC, int expectlTimeMS, float moveSpeedSEC, float moveSpeedAdd, float moveSpeedAccPct, bool isNoneTouch) { this.mOwner = owner; this.mStartDirection = direction; this.moveSpeedSEC = moveSpeedSEC; this.mMoveSpeedAdd = moveSpeedAdd; this.mMoveSpeedAcc = moveSpeedAccPct / 100f; this.mRotateSpeedSEC = rotateSpeedSEC; this.isNoneTouch = isNoneTouch; this.TotalTimeMS = expectlTimeMS; this.hitMoveTime = new TimeExpire(TotalTimeMS); this.IsEnd = false; this.PrevX = owner.X; this.PrevY = owner.Y; } public void SetFly(object launcher, float moveZSpeed, float gravity, float zlimit) { if (moveZSpeed != 0) { this.hasFly = mOwner.StartFly(launcher, moveZSpeed, gravity, zlimit); this.TotalTimeMS = hasFly.ExpectTimeMS; this.hitMoveTime = new TimeExpire(TotalTimeMS); } } public void SetMoveTarget(IPositionObject target, bool targetBodyBlock) { moveTarget = target; moveTargetBody = targetBodyBlock; } public void Stop() { this.IsEnd = true; } public bool Update(int intervalMS) { int intervalMS_move = intervalMS; if (hitMoveTime.PassTimeMS + intervalMS >= hitMoveTime.TotalTimeMS) { intervalMS_move = hitMoveTime.TotalTimeMS - hitMoveTime.PassTimeMS; } if (mRotateSpeedSEC != 0) { mOwner.turn(MoveHelper.GetDistance(intervalMS_move, mRotateSpeedSEC)); } this.PrevX = mOwner.X; this.PrevY = mOwner.Y; // 移动 // if (moveTarget != null) { move(intervalMS_move, moveTarget); } else { move(intervalMS_move, mStartDirection); } // 递增 // { //每秒递减速度绝对值// MoveHelper.UpdateSpeed(intervalMS_move, ref moveSpeedSEC, mMoveSpeedAdd, mMoveSpeedAcc); } if (hitMoveTime.PassTimeMS + intervalMS >= hitMoveTime.TotalTimeMS || hitMoveTime.Update(intervalMS)) { IsEnd = true; } return IsEnd; } private void move(int intervalMS, IPositionObject target) { if (moveTargetBody) { float distance = MoveHelper.GetDistance(intervalMS, moveSpeedSEC); if (CMath.includeRoundPoint(mOwner.X, mOwner.Y, target.RadiusSize + mOwner.RadiusSize + distance, target.X, target.Y)) { return; } } if (hasFly != null) { mOwner.jumpToTarget(target.X, target.Y, moveSpeedSEC, intervalMS, IsNoneTouch); } else { if (IsNoneTouch) { mOwner.jumpToTarget(target.X, target.Y, moveSpeedSEC, intervalMS, IsNoneTouch); } else if (mMoveSpeedAdd != 0 || mMoveSpeedAcc != 0) { mOwner.moveImpactTo(target.X, target.Y, moveSpeedSEC, intervalMS); } else { mOwner.moveBlockTo(target.X, target.Y, moveSpeedSEC, intervalMS); } } } private void move(int intervalMS, float direction) { if (hasFly != null) { mOwner.jumpTo(direction, moveSpeedSEC, intervalMS, IsNoneTouch); } else { if (IsNoneTouch) { mOwner.jumpTo(direction, moveSpeedSEC, intervalMS, IsNoneTouch); } else if (mMoveSpeedAdd != 0 || mMoveSpeedAcc != 0) { mOwner.moveImpact(direction, moveSpeedSEC, intervalMS); } else { mOwner.moveBlockTo(direction, moveSpeedSEC, intervalMS); } } } public float PrevX { get; private set; } public float PrevY { get; private set; } public bool IsFly { get { return hasFly != null; } } public int TotalTimeMS { get; private set; } public bool IsEnd { get; private set; } public bool IsNoneTouch { get { return isNoneTouch; } set { this.isNoneTouch = value; } } public float ZSpeedSEC { get { if (hasFly != null) return hasFly.ZSpeedSEC; return 0; } } } #endregion //--------------------------------------------------------------------------------------------------------------- } }