/// /// 释放技能, pos的第几个技能 /// public void Cast(ServerNPC caster, short pos, Action <MsgParam> Report) { #if DEBUG Utils.Assert(caster == null, "Caster is null when cast skill."); #endif ServerLifeNpc src = caster as ServerLifeNpc; if (src.IsAlive == false) { return; } RtSkData rtSk = src.runSkMd.getRuntimeSkill(pos); /// /// 冷却时间好了吗, 死亡了吗 /// if (rtSk != null && rtSk.canCast) { //进入Skill释放的状态 src.curStatus = src.curStatus.set(NpcStatus.InSkill); IEnumerable <ServerNPC> targets = SelectS.Select(caster, rtSk, Sight.NearSight); EfCastor.Cast(caster, targets, rtSk, Report); } }
void castBuff_Skill(RtBufData rtbf, BuffPhase phase) { container.Clear(); RtSkData skill = null; switch (phase) { case BuffPhase.Start: skill = rtbf.OnStartSkill; break; case BuffPhase.End: skill = rtbf.OnEndSkill; break; case BuffPhase.Cycle: skill = rtbf.onCycleskill; break; } if (skill != null) { ServerNPC castor = BFSelector.locateCastor(rtbf); ServerNPC target = BFSelector.locateTarget(rtbf); List <ServerNPC> Targets = new List <ServerNPC>(); Targets.Add(target); IEnumerable <ServerNPC> itor = Targets.AsEnumerable <ServerNPC>(); EfCastor.Cast(castor, itor, skill, container, false); dispatchMsg(container, skill); } }
/// <summary> /// 挑出TimeOut的判定 /// </summary> /// <returns>The up.</returns> /// <param name="sk">Sk.</param> ConditionConfigure pickUp(RtSkData sk) { ConditionConfigure ConCfg = null; //获取激活的判定规则ID列表 int[] IncideCon = sk.skillCfg.Incite; if (IncideCon != null && IncideCon.Length > 0) { int len = IncideCon.Length; for (int i = 0; i < len; ++i) { //获取激活的判定规则ID int CondiId = IncideCon[i]; if (CondiId > 0) { ConCfg = ConModel.get(CondiId); if (ConCfg.ConditionType == SkConditionType.TimeOut) { break; } } } } return(ConCfg); }
public void EnterIncite(RtSkData sk, EffectConfigData efCfg, ServerNPC caster, IEnumerable <ServerNPC> targets) { bool canEnter = CheckIncite(sk, efCfg); if (canEnter) { bool injured = CheckBeHead(sk); if (injured) { float Delay = 0.6F; /// /// 检测伤害类的还需要至少延迟了两个FixedUpdate,因为承受伤害的逻辑,还没开始执行 /// 所以,目标血量的判定还不能开始 /// DelayedSkData data = new DelayedSkData() { caster = caster, chosen = targets, rtsk = sk, }; SkAsyncRunner.AysncRun(EnterIncite, Delay, data); } else { EnterIncite(sk, caster, targets); } } }
/// <summary> /// 检测有没有斩首的逻辑,如果有伤害逻辑,就得要延迟执行 /// </summary> /// <returns><c>true</c>, if be head was checked, <c>false</c> otherwise.</returns> /// <param name="sk">Sk.</param> bool CheckBeHead(RtSkData sk) { bool hasInjury = false; ConditionConfigure ConCfg = null; //获取激活的判定规则ID列表 int[] IncideCon = sk.skillCfg.Incite; if (IncideCon != null && IncideCon.Length > 0) { int len = IncideCon.Length; for (int i = 0; i < len; ++i) { //获取激活的判定规则ID int CondiId = IncideCon[i]; if (CondiId > 0) { ConCfg = ConModel.get(CondiId); if (ConCfg.ConditionType == SkConditionType.BeHead || ConCfg.ConditionType == SkConditionType.BeHead2 || ConCfg.ConditionType == SkConditionType.BeHeadReset || ConCfg.ConditionType == SkConditionType.BeHead2Reset) { hasInjury = true; break; } } } } return(hasInjury); }
void EnterIncite(RtSkData sk, ServerNPC caster, IEnumerable <ServerNPC> targets) { ConditionConfigure ConCfg = null; //获取激活的判定规则ID列表 int[] IncideCon = sk.skillCfg.Incite; if (IncideCon != null && IncideCon.Length > 0) { int len = IncideCon.Length; for (int i = 0; i < len; ++i) { //获取激活的判定规则ID int CondiId = IncideCon[i]; if (CondiId > 0) { ConCfg = ConModel.get(CondiId); Utils.Assert(ConCfg == null, "Can't find Condition Configure. Condition ID = " + ConCfg); //判定器--- 如果成功就跳出 ICondition decider = Mgr.getImplement(ConCfg.ConditionType); bool suc = decider.check(sk, ConCfg, caster, targets); if (suc) { ServerLifeNpc life = caster as ServerLifeNpc; bool isReset = ConCfg.ConditionClass == SkConditionClass.ResetSkill; life.runSkMd.switchToSkill(sk.pos, ConCfg.TargetSkID, isReset); break; } } } } }
/// <summary> /// pos 普通攻击的第几步 /// </summary> public List <MsgParam> NormalAttack(ServerNPC caster, short pos) { container.Clear(); #if DEBUG Utils.Assert(caster == null, "Caster is null when cast skill."); #endif ServerLifeNpc src = caster as ServerLifeNpc; if (src.IsAlive == false) { return(container); } RtSkData rtSk = src.runSkMd.getAttack(pos); if (rtSk != null) { IEnumerable <ServerNPC> targets = SelectS.Select(caster, rtSk, Sight.NearSight); EfCastor.Cast(caster, targets, rtSk, container); } int cnt = container.Count; if (cnt > 0) { for (int i = 0; i < cnt; ++i) { ((WarMsgParam)container[i]).cmdType = WarMsg_Type.Attack; } } return(container); }
/// <summary> /// 检测是否符合逻辑 /// </summary> /// <param name="sk">技能</param> /// <param name="cfg">条件配置技能</param> /// <param name="caster">施法者忽略</param> /// <param name="targets">目标者们忽略</param> public bool check(RtSkData sk, ConditionConfigure cfg, ServerNPC caster, IEnumerable <ServerNPC> targets) { #if DEBUG Utils.Assert(sk == null, "Skill is null in TimeoutCondition."); Utils.Assert(cfg == null, "ConditionConfigure is null in TimeoutCondition."); #endif bool Condi = false; /// /// 1. 判定是否符合关心的BeHead类型 /// var self = this.GetType(); var classAttribute = (ConditionAttribute)Attribute.GetCustomAttribute(self, typeof(ConditionAttribute)); if (cfg.ConditionType == classAttribute.Con) { RtFakeSkData fakeSk = sk as RtFakeSkData; if (fakeSk != null) { float TimeOut = cfg.Param1 * Consts.OneThousand; /// ///2.判定是否超时 /// Condi = fakeSk.aliveDur >= TimeOut; ///3.判定概率 if (Condi) { Condi = PseudoRandom.getInstance().happen(cfg.Prop); } } } return(Condi); }
public void Cast(ServerNPC caster, IEnumerable <ServerNPC> chosen, RtSkData rtSk, List <MsgParam> MsgContainer, bool skDirecHurt) { #if DEBUG Utils.Assert(caster == null, "Effect Castor"); Utils.Assert(rtSk == null, "Effect Castor"); #endif List <EffectConfigData> effCfg = new List <EffectConfigData>(); foreach (EffectConfigData cfg in rtSk.effectCfgDic.Values) { effCfg.Add(cfg); } ICastEffect[] castor = effMgr.getImplements(effCfg.ToArray(), rtSk.skillCfg); if (castor != null) { int len = castor.Length; for (int i = 0; i < len; ++i) { IEnumerable <ServerNPC> reTarget = selector.Select(caster, chosen, effCfg[i]); castor[i].Cast(caster, chosen, reTarget, skDirecHurt, MsgContainer); effMgr.Recycle(effCfg[i], castor[i]); } } castor = null; }
/// <summary> /// 数据的初始化 /// </summary> /// <param name="go">Go.</param> /// <param name="num">Number.</param> /// <param name="id">Identifier.</param> /// <param name="camp">Camp.</param> void DynamicDataInit(ServerNPC curHero, NPCConfigData econfig, CAMP camp) { /// /// 填充阵营 /// curHero.Camp = camp; /// /// 填充NPC数据 /// NPCData dynamicData = new NPCData(); dynamicData.rtData = new NPCRuntimeData(econfig); dynamicData.configData = econfig; dynamicData.btData = new NPCBattleData(); curHero.data = dynamicData; /// /// 向WarManager注册 /// serNpcMgr.SignID(curHero); WarServerManager warMgr = WarServerManager.Instance; /// /// 填充技能数据 /// RtNpcSkillModel skMd = new RtNpcSkillModel(econfig.ID, curHero.UniqueID); ServerLifeNpc life = curHero as ServerLifeNpc; if (life != null) { life.runSkMd = skMd; } /// /// 填充默认的buff /// for (short i = 0; i < Consts.MAX_SKILL_COUNT; ++i) { RtSkData sk = skMd.getRuntimeSkill(i); if (sk != null) { int passive = sk.skillCfg.PassiveBuff; if (passive > 0) { BuffCtorParam ctor = new BuffCtorParam() { bufNum = passive, fromNpcId = curHero.UniqueID, toNpcId = curHero.UniqueID, origin = OriginOfBuff.BornWithSkill, initLayer = 1, duration = Consts.USE_BUFF_CONFIG_DURATION, }; warMgr.bufMgr.createBuff(ctor); } } } }
bool CheckIncite(RtSkData sk, EffectConfigData efCfg) { #if DEBUG Utils.Assert(sk == null, "RtSkData is null in CheckIncite."); Utils.Assert(efCfg == null, "EffectConfigData is null in CheckIncite."); #endif return(sk.skillCfg.InciteEffectID == efCfg.ID); }
/// <summary> /// 检测回复技能 /// /// 检测逻辑和上面的并不太一致 /// 判定顺序是: /// 0. 判定技能的类型 /// 1. 判定施法者的状态 /// 2. 选在施法的距离(特定范围)内血最少的 英雄 NPC /// </summary> /// <returns><c>true</c>, if cast was caned, <c>false</c> otherwise.</returns> /// <param name="caster">Caster.</param> public bool canCast(ServerNPC caster, RtSkData rtOne) { bool can = true; #if DEBUG Utils.Assert(caster == null, "Can't know whether can cast skill unless caster isn't null."); Utils.Assert(rtOne == null, "Can't know whether can cast skill unless runtime skill isn't null"); #endif SkillConfigData skillCfg = rtOne.skillCfg; /// 0. 判定技能的类型 can = skillCfg.DamageType == 1; if (can == false) { return(can); } /// 1.判定施法者的状态 //只有LifeNPC才检查施法者的状态 ServerLifeNpc castlife = caster as ServerLifeNpc; if (castlife != null) { if (skillCfg.CasterStatusReject.AnySame(castlife.curStatus)) { //不可施法 can = false; } } if (can == false) { return(can); } /// 2. 选在施法的距离(特定范围)内血最少的 英雄 NPC List <ServerNPC> friendlyArmy = SelectorTools.GetNpcWithInRange(caster, skillCfg.Distance, NpcMgr, caster.Camp, KindOfNPC.Life, LifeNPCType.Hero); if (friendlyArmy != null && friendlyArmy.Count > 0) { //选择血最少的 ServerNPC friend = friendlyArmy.OrderBy(npc => (npc.data.rtData.curHp * 1.0f / npc.data.rtData.totalHp)).FirstOrDefault(); if (friend != null) { NPCRuntimeData npcRtdt = friend.data.rtData; float factor = npcRtdt.curHp * 1.0f / npcRtdt.totalHp; //低于20%的 if (factor > 0.2f) { can = false; } } } return(can); }
/// <summary> /// 检测是否符合逻辑 /// </summary> /// <param name="sk">技能忽略</param> /// <param name="cfg">条件配置技能忽略</param> /// <param name="caster">施法者忽略</param> /// <param name="targets">目标者们忽略</param> public bool check(RtSkData sk, ConditionConfigure cfg, ServerNPC caster, IEnumerable <ServerNPC> targets) { #if DEBUG Utils.Assert(cfg == null, "ConditionConfigure is null in PropCondition."); #endif ///1.判定概率 bool Condi = PseudoRandom.getInstance().happen(cfg.Prop); return(Condi); }
/// <summary> /// 这个是给技能使用的,可能不会立即有结果 /// </summary> /// <param name="caster">Caster.</param> /// <param name="chosen">Chosen.</param> /// <param name="rtSk">技能</param> /// <param name="pos">技能的索引</param> /// <param name="Report">Report.</param> public void Cast(ServerNPC Caster, IEnumerable <ServerNPC> Chosen, RtSkData RtSk, Action <MsgParam> ReportFunc) { #if DEBUG Utils.Assert(Caster == null, "Effect Castor"); Utils.Assert(RtSk == null, "Effect Castor"); #endif List <EffectConfigData> effCfg = new List <EffectConfigData>(); foreach (EffectConfigData cfg in RtSk.effectCfgDic.Values) { effCfg.Add(cfg); } //虚假的Buff桩对象 EffectConfigData stub = ctorStubEffCfg(RtSk); if (stub != null) { effCfg.Add(stub); } ICastEffect[] castor = effMgr.getImplements(effCfg.ToArray(), RtSk.skillCfg); if (castor != null) { int len = castor.Length; for (int i = 0; i < len; ++i) { if (castor[i] == null) { ConsoleEx.DebugLog("ICastEffect Not Implement. ID = " + effCfg[i].ID, ConsoleEx.YELLOW); } else { float Delay = RtSk.skillCfg.EffectDelayTime[i]; if (Delay > 0) { DelayedSkData data = new DelayedSkData() { caster = Caster, chosen = Chosen, castor = castor[i], cfg = effCfg[i], Report = ReportFunc, rtsk = RtSk, }; SkAsyncRunner.AysncRun(DelayCast, Delay, data); } else { DelayCast(Caster, Chosen, castor[i], effCfg[i], RtSk, ReportFunc); } } } } castor = null; }
public void cast(ServerNPC castor, IEnumerable <ServerNPC> targets, TriggerConfigData triCfg) { #if DEBUG Utils.Assert(castor == null, "TriggerCastor can't cask if castor is null."); Utils.Assert(targets == null, "TriggerCastor can't cask if target is null."); Utils.Assert(triCfg == null, "TriggerCastor can't cask if TriggerConfigData is null."); #endif RtSkData skill = new RtSkData(triCfg.SkillID, -1); targets = filtor(targets, triCfg); container.Clear(); EfCastor.Cast(castor, targets, skill, container, false); dispatchMsg(container, skill); }
/// <summary> /// 返回可以释放的技能, 这个要一直检测 /// 这个只检查4个技能,不检查普通攻击 /// </summary> /// <returns>The cast.</returns> /// <param name="caster">Caster.</param> /// <param name="target">Target.</param> public List <short> canCast(ServerNPC caster, ServerNPC target) { List <short> skNumList = new List <short>(); #if DEBUG Utils.Assert(caster == null, "Caster is null when check whether can cast skill."); Utils.Assert(target == null, "Target is null when check whether can cast skill."); #endif ServerLifeNpc castLife = caster as ServerLifeNpc; if (castLife.IsAlive == false) { return(skNumList); } short pos = 0; for ( ; pos < Consts.MAX_SKILL_COUNT; ++pos) { RtSkData rtsk = castLife.runSkMd.getRuntimeSkill(pos); if (rtsk != null) { bool can = false; /// /// 冷却时间好了吗 /// can = rtsk.canCast; SkillConfigData skCfg = rtsk.skillCfg; if (skCfg.DamageType == (short)1) { can = can & CanCast.canCast(caster, rtsk); } else if (skCfg.DamageType == (short)0) { can = can & CanCast.canCast(caster, target, rtsk); } //如果可以则加入可释放列表 if (can) { skNumList.Add(pos); } } } return(skNumList); }
/// <summary> /// 检测是否符合逻辑 /// </summary> /// <param name="sk">技能,忽略</param> /// <param name="caster">施法者,忽略</param> /// <param name="targets">目标者们</param> public bool check(RtSkData sk, ConditionConfigure cfg, ServerNPC caster, IEnumerable <ServerNPC> targets) { #if DEBUG Utils.Assert(cfg == null, "ConditionConfigure is null in BeHeadCondition."); Utils.Assert(targets == null, "Targets are null in BeHeadCondition."); #endif bool Condi = false; /// /// 1. 判定是否符合关心的BeHead类型 /// var self = this.GetType(); var classAttribute = (ConditionAttribute)Attribute.GetCustomAttribute(self, typeof(ConditionAttribute)); if (cfg.ConditionType == classAttribute.Con) { //血线 float hpLineFactor = cfg.Param1 * Consts.OneThousand; //满足的个数 int Count = cfg.Param2; int curCnt = 0; foreach (ServerNPC npc in targets) { float hpLine = (int)hpLineFactor * npc.data.rtData.totalHp; if (npc.data.rtData.curHp <= hpLine) { curCnt++; } } if (curCnt >= Count) { Condi = true; } //判定概率 if (Condi) { Condi = PseudoRandom.getInstance().happen(cfg.Prop); } } return(Condi); }
//判断target是否是skData的一个有效技能使用目标(不包括cd和距离,值判断能否对target使用) public bool IsValidTarget(ServerNPC caster, ServerNPC target, RtSkData rtsk) { bool isValid = false; ServerLifeNpc castLife = caster as ServerLifeNpc; if (castLife.IsAlive == false) { return(isValid); } if (rtsk != null) { isValid = CanCast.canCast(caster, target, rtsk, true); } return(isValid); }
public override void OnStart() { for (short i = 0; i < 4; i++) { RtSkData sk = myHero.runSkMd.getRuntimeSkill(i); if (sk != null && sk.skillCfg.ID == curSkill.Value.skillCfg.ID) { skillIdx = i; break; } } if (skillIdx == -1) { ConsoleEx.DebugError(myHero.name + " not find skill idx :: " + curSkill.Value.skillCfg.Name); } }
//不检查CD,不检查距离 public bool isVaild(ServerNPC caster, ServerNPC target, short pos) { bool isValid = false; ServerLifeNpc castLife = caster as ServerLifeNpc; if (castLife.IsAlive == false) { return(isValid); } RtSkData rtsk = castLife.runSkMd.getRuntimeSkill(pos); if (rtsk != null) { isValid = CanCast.canCast(caster, target, rtsk, true); } return(isValid); }
/// <summary> /// 检测是否符合逻辑 /// </summary> /// <param name="sk">技能</param> /// <param name="cfg">条件配置技能, 忽略</param> /// <param name="caster">施法者, 忽略</param> /// <param name="targets">目标者们, 忽略</param> public bool check(RtSkData sk, ConditionConfigure cfg, ServerNPC caster, IEnumerable <ServerNPC> targets) { #if DEBUG Utils.Assert(sk == null, "Skill is null in CountingCondition."); Utils.Assert(cfg == null, "ConditionConfigure is null in CountingCondition."); #endif bool Condi = false; /// /// 1. 判定是否符合关心的Counting类型 /// var self = this.GetType(); var classAttribute = (ConditionAttribute)Attribute.GetCustomAttribute(self, typeof(ConditionAttribute)); if (cfg.ConditionType == classAttribute.Con) { /// /// 2. 只有RtFakeSkData才有计算功能 /// RtFakeSkData fakeSk = sk as RtFakeSkData; if (fakeSk != null) { /// /// 3. 判定计数 /// if (fakeSk.curCounting >= cfg.Param1) { Condi = true; } ///4.判定概率 if (Condi) { Condi = PseudoRandom.getInstance().happen(cfg.Prop); } } } return(Condi); }
/// /// 引导Buff是可以被打断的 /// 创建假的Effect的配置(桩对象) /// EffectConfigData ctorStubEffCfg(RtSkData RtSk) { EffectConfigData stub = null; if (RtSk.ChannelBuff != null) { stub = new EffectConfigData() { ID = -1, Flags = EffectFlag.None, EffectClass = SkillTypeClass.Magical, EffectTarget = EffectTargetClass.SkillTarget, EffectTargetType = TargetSubClass.AllTarget, EffectTargetStatusReject = NpcStatus.None, EffectType = EffectOp.DotHot, Param1 = RtSk.ChannelBuff.ID, Prob = 1000, EffectLimit = -1, }; } return(stub); }
/// <summary> /// 搜索攻击目标 /// </summary> /// <returns>The atk targets.</returns> public IEnumerable <ServerNPC> FindAtkTargets(ServerNPC caster, short pos, Sight sight) { #if DEBUG Utils.Assert(caster == null, "Caster is null when cast skill."); #endif ServerLifeNpc src = caster as ServerLifeNpc; if (src.IsAlive == false) { return(null); } RtSkData rtSk = src.runSkMd.getAttack(pos); if (rtSk != null) { IEnumerable <ServerNPC> targets = SelectS.Select(caster, rtSk, sight); return(targets); } else { return(null); } }
/// <summary> /// // 判断skData能否对target使用 /// </summary> /// <returns><c>true</c>, if cast was caned, <c>false</c> otherwise.</returns> /// <param name="caster">施法者.</param> /// <param name="target">技能使用目标.</param> /// <param name="skData">使用的技能.</param> public bool canCast(ServerNPC caster, ServerNPC target, RtSkData rtsk) { if (rtsk != null) { bool can = false; /// /// 冷却时间好了吗 /// can = rtsk.canCast; SkillConfigData skCfg = rtsk.skillCfg; if (skCfg.DamageType == (short)1) { can = can & CanCast.canCast(caster, rtsk); } else if (skCfg.DamageType == (short)0) { can = can & CanCast.canCast(caster, target, rtsk); } return(can); } return(false); }
/// <summary> /// 派发出去消息 /// </summary> /// <param name="outMsg">Out message.</param> void dispatchMsg(List <MsgParam> outMsg, RtSkData skill) { if (outMsg != null && outMsg.Count > 0) { int count = outMsg.Count; for (int i = 0; i < count; ++i) { MsgParam msg = outMsg[i]; WarAnimParam warMsg = msg as WarAnimParam; warMsg.cmdType = WarMsg_Type.UseBuff; warMsg.SkillId = skill == null ? -1 : skill.Num; if (warMsg != null && warMsg.described != null) { SelfDescribed des = warMsg.described; #if DEBUG ConsoleEx.DebugLog("Buff Msg is going out : " + fastJSON.JSON.Instance.ToJSON(des), ConsoleEx.YELLOW); #endif msgMgr.SendMessageAsync(des.src, des.target, warMsg); } } } }
/// <summary> /// 检测伤害技能能否释放, /// 回血,恢复之类的技能不做检测 /// /// 判定顺序是: /// 0. 判定技能的类型 /// 1. 判定是否是相同的阵营 /// 2. 判定施法者的状态 /// 3. 判定目标是什么类型的NPC(比如建筑物,英雄。。。) /// 3. 判定施法的距离 /// 5. 目标的状态 /// /// </summary> /// <returns><c>true</c>, if cast was caned, <c>false</c> otherwise.</returns> public bool canCast(ServerNPC caster, ServerNPC target, RtSkData rtOne, bool ignoreDis = false) { bool can = true; #if DEBUG Utils.Assert(caster == null, "Can't know whether can cast skill unless caster isn't null."); Utils.Assert(target == null, "Can't know whether can cast skill unless target isn't null."); Utils.Assert(rtOne == null, "Can't know whether can cast skill unless runtime skill isn't null"); #endif SkillConfigData skillCfg = rtOne.skillCfg; /// 0. 判定技能的类型 can = skillCfg.DamageType == 0; if (can == false) { return(can); } /// 1.判定是否是相同的阵营 can = caster.Camp != target.Camp; if (can == false) { return(can); } /// 2. 判定施法者的状态 //只有LifeNPC才检查施法者的状态 ServerLifeNpc castlife = caster as ServerLifeNpc; if (castlife != null) { if (skillCfg.CasterStatusReject.AnySame(castlife.curStatus)) { //不可施法 can = false; } } if (can == false) { return(can); } /// 3. 判定目标是什么类型的NPC LifeNPCType type = skillCfg.TargetType.toPositive(); can = type.check(target.data.configData.type); if (can == false) { return(can); } /// 4. 判定施法的距离 if (ignoreDis == false) { can = AITools.IsInRange(caster.transform.position, skillCfg.Distance, target.transform); if (can == false) { return(can); } } /// 5. 目标的状态 ServerLifeNpc targetLife = target as ServerLifeNpc; if (targetLife != null) { if (targetLife.curStatus.AnySame(skillCfg.TargetStatusReject)) { //不可施法 can = false; } } return(can); }
public override void SetValue(object value) { mValue = (RtSkData)value; }
/// <summary> /// 选择的规则是: /// 多目标判定规则 /// 1. 判定施法者的状态 /// 2. 判定施法者的上次目标,如果目标在攻击范围内,则选择为最优先目标 /// 3. 判定施法的范围类型 /// 4. 目标的状态 /// 5. 根据施法的距离选择出目标 /// 6. 根据血量选择出目标 /// 7. 目标的优先级 /// 8. 单体攻击敌方,并且有最高优先级的目标 /// /// /// 单目标判定规则 /// /// /// /// </summary> /// <returns><c>true</c>, if cast was caned, <c>false</c> otherwise.</returns> public IEnumerable <ServerNPC> Select(ServerNPC caster, RtSkData rtOne, Sight sight) { //枚举器 IEnumerable <ServerNPC> itor = null, itor1 = null; #if DEBUG Utils.Assert(caster == null, "Can't find target unless caster isn't null"); Utils.Assert(rtOne == null, "Can't find target unless runtime skill isn't null"); #endif SkillConfigData skillCfg = rtOne.skillCfg; /// 视野范围 -- 决定索敌范围 float CheckDistance = 0F; if (sight == Sight.NearSight) { CheckDistance = skillCfg.Distance; } else { CheckDistance = caster.data.rtData.seekRange; } bool castcan = true; //只有LifeNPC才检查施法者的状态 //1. 判定施法者的状态 ServerLifeNpc castlife = caster as ServerLifeNpc; if (castlife != null) { if (castlife.curStatus.AnySame(skillCfg.CasterStatusReject)) { //不可施法 castcan = false; } } if (castcan == false) { return(new List <ServerNPC>().AsEnumerable <ServerNPC>()); } //能进入CD rtOne.EnterCD(); /// /// 3. 判定施法的范围类型 . /// 单体和AOE都需要在技能配置里选择出目标 , 再次到Effect里面选择目标。 -- 叫做前置判定 /// 方向性则不需要选择目标,该类型的技能可对空地释放,再次到EffectTarget的目标是skill的目标 -- 叫做后置判定 /// TargetClass rtTargetCls = skillCfg.SkillTarget; if (skillCfg.RangeType == RangeClass.Direction) { //后置判定 return(new List <ServerNPC>().AsEnumerable <ServerNPC>()); } bool isMultiTarget = skillCfg.RangeType != RangeClass.SingleTarget; bool isNoPriority = skillCfg.TargetPriority == SkTargetPriority.NonePriority; bool isTargetSelf = rtTargetCls.AnySame(TargetClass.Self); //单目标 ServerNPC singlePriority = null; LifeNPCType type = skillCfg.TargetType.toPositive(); /// /// 是否为多目标的战斗, 或者是没有优先级的单目标 /// if (isMultiTarget || isNoPriority || isTargetSelf) { /// /// 4. 目标的状态 /// if (rtTargetCls.AnySame(TargetClass.Friendly)) { //友方 itor1 = SelectorTools.GetNPCValideStatus(caster, npcMgr, KindOfNPC.Life, rtTargetCls, NpcStatus.None, type); } else if (rtTargetCls.AnySame(TargetClass.Hostile)) { //敌方 itor1 = SelectorTools.GetNPCValideStatus(caster, npcMgr, KindOfNPC.Life, rtTargetCls, skillCfg.TargetStatusReject, type); } else if (rtTargetCls.AnySame(TargetClass.Self)) { //自己 List <ServerNPC> targets = new List <ServerNPC>(); targets.Add(caster); itor = targets.AsEnumerable <ServerNPC>(); return(targets); } else { itor1 = SelectorTools.GetNPCValideStatus(caster, npcMgr, KindOfNPC.Life, rtTargetCls, skillCfg.TargetStatusReject, type); ConsoleEx.DebugLog("Warning : We should have a Camp. But sometimes, it's Ok.", ConsoleEx.RED); } /// /// 5. 根据施法的距离选择出目标 /// itor1 = SelectorTools.GetNPCInRadius(caster, CheckDistance, rtTargetCls, itor1); /// /// 6. 根据血量选择出目标 /// itor1 = SelectorTools.GetNPCByHp(caster, rtTargetCls, itor1); if (isNoPriority) { singlePriority = itor1.FirstOrDefault(); } } else { /// /// 获取单目标 /// singlePriority = SelectorTools.GetPrioritiedNpc(caster, rtTargetCls, npcMgr, CheckDistance, skillCfg.TargetStatusReject, skillCfg.TargetPriority, priorityMgr, type); //单目标的友方,有可能选择到自己(但并不属于 TargetClass 64.就针对自己) if (!rtTargetCls.AnySame(TargetClass.Hostile)) { List <ServerNPC> broker = new List <ServerNPC>(); if (singlePriority != null) { broker.Add(singlePriority); } itor1 = broker.AsEnumerable <ServerNPC>(); } } if (isMultiTarget == false) { /// /// 9. 单体攻击敌方,只有打敌方单体的时候,TargetID才会被重新设定 /// if (rtTargetCls.AnySame(TargetClass.Hostile)) { ServerLifeNpc HighestPriority = null; /// /// 检测嘲讽 /// int tarId = caster.getHighestHatred; if (tarId != -1) { //有被嘲讽的目标 HighestPriority = npcMgr.GetNPCByUniqueID(tarId) as ServerLifeNpc; } else { //没有被嘲讽的目标 /// /// 判定施法者的上次目标,则选择为最优先目标 /// 此逻辑,能保证追击残血逃跑的 /// if (caster.TargetID != -1) { HighestPriority = npcMgr.GetNPCByUniqueID(caster.TargetID) as ServerLifeNpc; if (HighestPriority != null) { /// /// 如果单一目标的是英雄, /// if (singlePriority != null && singlePriority.data.configData.type == LifeNPCType.Hero && HighestPriority.data.configData.type != LifeNPCType.Hero) { HighestPriority = null; caster.TargetID = -1; } else { bool validate1 = true, validate2 = true, validate3 = true; /// 生命判定 if (HighestPriority.data.rtData.curHp <= 0) { validate1 = false; } /// 距离判定 float distance = SelectorTools.GetDistance(HighestPriority.transform.position, caster.transform.position); distance = distance - HighestPriority.data.configData.radius - caster.data.configData.radius; /// 视野范围 if (distance > CheckDistance) { validate2 = false; } ///如果有相同的状态,则不让释放技能 validate3 = !HighestPriority.curStatus.AnySame(skillCfg.TargetStatusReject); /// 失败的判定 bool validate = validate1 & validate2 & validate3; if (!validate) { HighestPriority = null; caster.TargetID = -1; } else { caster.RstTimeout(); } } } else { caster.TargetID = -1; } } } //找到普通选择出的目标 if (HighestPriority == null) { ServerNPC target = singlePriority; caster.TargetID = target != null ? target.UniqueID : -1; HighestPriority = target as ServerLifeNpc; } List <ServerNPC> high = new List <ServerNPC>(); if (HighestPriority != null) { high.Add(HighestPriority); } itor1 = high.AsEnumerable <ServerNPC>(); } else { /// /// 10.单体友方 /// if (itor1.Any()) { itor1 = itor1.Take(1); } } } itor = itor1; return(itor); }
void DelayCast(ServerNPC caster, IEnumerable <ServerNPC> chosen, ICastEffect castor, EffectConfigData cfg, RtSkData RtSk, Action <MsgParam> Report) { bool skDirecHurt = true; List <MsgParam> MsgContainer = new List <MsgParam>(); IEnumerable <ServerNPC> reTarget = selector.Select(caster, chosen, cfg); castor.Cast(caster, chosen, reTarget, skDirecHurt, MsgContainer); effMgr.Recycle(cfg, castor); /// /// ---- 进入激活判定器 ---- /// conDicder.EnterIncite(RtSk, cfg, caster, chosen); short pos = RtSk.pos; /// /// 回报数据,区分一条数据和多条数据 /// HowToReport(MsgContainer, pos, Report); }
/// <summary> /// Cast the specified caster, chosen, rtSk and MsgContainer. /// 这个是给普通攻击使用的,其实就是立即有结果的模式 /// 没有激活判定器 /// </summary> /// <param name="caster">Caster.</param> /// <param name="chosen">Chosen.可以为空</param> /// <param name="rtSk">Rt sk.</param> /// <param name="MsgContainer">Message container.</param> public void Cast(ServerNPC caster, IEnumerable <ServerNPC> chosen, RtSkData rtSk, List <MsgParam> MsgContainer) { bool skDirectlyHurt = true; Cast(caster, chosen, rtSk, MsgContainer, skDirectlyHurt); }