ExistFlag LifeNpcType2ExistFlag(LifeNPCType type, BuildNPCType bldType) { ExistFlag flag = ExistFlag.None; switch (type) { case LifeNPCType.Hero: flag = ExistFlag.Hero; break; case LifeNPCType.Build: switch (bldType) { case BuildNPCType.Tower: flag = ExistFlag.Tower; break; case BuildNPCType.Barrank: case BuildNPCType.Base: flag = ExistFlag.Building; break; } break; case LifeNPCType.Soldier: flag = ExistFlag.minion; break; case LifeNPCType.Summon: flag = ExistFlag.Summoner; break; } return(flag); }
public List <ServerNPC> GetNPCByType(LifeNPCType type, CAMP camp) { List <ServerNPC> list = null; foreach (KeyValuePair <int, ServerNPC> itor in npcDic) { if (itor.Value != null && itor.Value.data != null && itor.Value.data.configData.type == type) { if (camp == CAMP.None || camp == CAMP.All) { if (list == null) { list = new List <ServerNPC> (); } list.Add(itor.Value); } else if (itor.Value.Camp == camp) { if (list == null) { list = new List <ServerNPC> (); } list.Add(itor.Value); } } } return(list); }
ExistFlag NPCToFlag(ServerNPC npc, WarServerNpcMgr npcMgr, LifeNPCType type) { ExistFlag tar1 = ExistFlag.None; ExistFlag tar2 = ExistFlag.None; switch (type) { case LifeNPCType.Hero: tar1 = ExistFlag.Hostile_Hero; tar2 = ExistFlag.Hostile_Hero_ATK_Self_Hero; break; case LifeNPCType.Summon: tar1 = ExistFlag.Hostile_Summoner; tar2 = ExistFlag.Hostile_Summoner_ATK_Self_Hero; break; case LifeNPCType.Soldier: tar1 = ExistFlag.Hostile_Minion; tar2 = ExistFlag.Hostile_Minion_ATK_Self_Hero; break; } ExistFlag toTest = ExistFlag.None; //没有攻击过的目标 if (npc.TargetID == -1) { toTest = tar1; } else { ServerNPC targetNpc = npcMgr.GetNPCByUniqueID(npc.TargetID); if (targetNpc != null) { /// /// 发现目标是Hero,则会判定为攻击了英雄 /// NPCConfigData tarCfg = targetNpc.data.configData; if (tarCfg.type.check(LifeNPCType.Hero)) { toTest = tar2; } else { toTest = tar1; } } else { toTest = tar1; } } return(toTest); }
/// <summary> /// 选择的规则是: /// 1. 判定EffectTarget(范围) /// 2. 判定flag-剔除友军,敌军等概念, 进入战斗状态的则再最后判定(状态可能目前并不会去设定) /// 3. 判定EffectTargetType-剔除 /// 4. 每个NPC的概率 /// 5. 判定EffectTargetStatusReject-剔除 /// 6. 选择目标的数量不能超过上限 /// /// </summary> /// <param name="caster">Caster.</param> /// <param name="targets">Targets.</param> /// <param name="efCfg">Ef cfg.</param> public IEnumerable <ServerNPC> Select(ServerNPC caster, IEnumerable <ServerNPC> targets, EffectConfigData efCfg) { #if DEBUG Utils.Assert(efCfg == null, "Effect Selector can't find target unless EffectConfigData isn't null"); #endif List <ServerNPC> reTarget = null; IEnumerable <ServerNPC> itor = null; /// 1. 判定EffectTarget(范围)2. 判定flag-剔除友军,敌军等概念 reTarget = areaSelector.SelectArea(caster, targets, efCfg); /// 3. 判定EffectTargetType-剔除 建筑物 LifeNPCType lifeType = efCfg.EffectTargetType.toPositive(); itor = reTarget.Where(n => lifeType.check(n.data.configData.type)); /// 4. 每个NPC的概率 5.判定EffectTargetStatusReject itor = itor.Where(n => { ServerLifeNpc lifeTar = n as ServerLifeNpc; bool ok = random.happen(efCfg.Prob); if (lifeTar != null) { if (ok) { return(!lifeTar.curStatus.AnySame(efCfg.EffectTargetStatusReject)); } else { return(ok); } } else { return(ok); } } ); ///6. 选择的目标数量不能超过上限 if (efCfg.EffectLimit > 0) { itor = itor.Take(efCfg.EffectLimit); } else if (efCfg.EffectLimit == 0) { itor = new List <ServerNPC>().AsEnumerable <ServerNPC>(); } return(itor); }
public static LifeNPCType toPositive(this TargetSubClass flags) { bool ok = flags == TargetSubClass.AllTarget; if (ok) { return(LifeNPCType.SkTarAll); } //默认所有的都选择出来 LifeNPCType type = LifeNPCType.SkTarAll; //不要建筑物 ok = flags.check(TargetSubClass.Forbid_Building); if (ok) { type = type.clear(LifeNPCType.Build); } //不要小兵 ok = flags.check(TargetSubClass.Forbid_Unit); if (ok) { type = type.clear(LifeNPCType.Soldier); } //不要英雄 ok = flags.check(TargetSubClass.Forbid_Hero); if (ok) { type = type.clear(LifeNPCType.Hero); } //不要召唤物 ok = flags.check(TargetSubClass.Forbid_Summon); if (ok) { type = type.clear(LifeNPCType.Summon); } return(type); }
/// <summary> /// 根据LifeNPCType类型和camp得到npc /// </summary> /// <returns>The life NPC by type.</returns> /// <param name="type">Type.</param> /// <param name="camp">Camp.</param> public List <ServerLifeNpc> GetLifeNPCByType(LifeNPCType type, CAMP camp) { List <ServerLifeNpc> list = new List <ServerLifeNpc> (); foreach (KeyValuePair <int, ServerNPC> itor in npcDic) { ServerLifeNpc lifenpc = itor.Value as ServerLifeNpc; if (lifenpc != null && lifenpc.WhatTypeOf == type) { if (camp == CAMP.None) { list.Add(lifenpc); } else if (lifenpc.Camp == camp) { list.Add(lifenpc); } } } return(list); }
/// <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); }
public static LifeNPCType clear(this LifeNPCType flags, LifeNPCType totest) { return(flags & ~totest); }
public static LifeNPCType set(this LifeNPCType flags, LifeNPCType totest) { return(flags | totest); }
public static bool check(this LifeNPCType flags, LifeNPCType totest) { return((flags & totest) == totest); }
/// <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); }
/// <summary> /// Gets the npc with in range. /// </summary> /// <returns>The npc with in range.</returns> /// <param name="anchor">起点</param> /// <param name="range">范围</param> /// <param name="NpcSource">NPC 容器</param> /// <param name="capm">阵营</param> /// <param name="kind">是否是lifeNpc</param> /// <param name="type">如果是LifeNpc的时候,又是什么子类型</param> public static List <ServerNPC> GetNpcWithInRange(ServerNPC caster, float range, WarServerNpcMgr NpcSource, CAMP camp, KindOfNPC kind, LifeNPCType type = LifeNPCType.SkTarAll) { IEnumerable <ServerNPC> filter = NpcSource.getCampBnpc(camp); if (kind == KindOfNPC.Life) { filter = filter.Where(n => (n.WhatKindOf() == kind) && (type.check(((ServerLifeNpc)n).WhatTypeOf))); } else if (kind == KindOfNPC.NonLife) { filter = filter.Where(n => n.WhatKindOf() == kind); } int count = filter.Count(); if (count > 0) { Vector3 anchor = caster.transform.position; float radius = caster.data.configData.radius; filter = filter.Where(n => IsInRange(anchor, n.data.configData.radius + range + radius, n.transform)); } return(filter.ToList()); }
//可以选择单个目标,也可以是多个目标 //提供给SkillSelecotr使用 public static IEnumerable <ServerNPC> GetNPCInRange(ServerNPC caster, float range, WarServerNpcMgr NpcSource, KindOfNPC kind, TargetClass target, NpcStatus TarStatusInCfg, LifeNPCType type = LifeNPCType.SkTarAll) { List <ServerNPC> found = new List <ServerNPC>(); /// /// 枚举器,其实不用返回特定类型,返回枚举器就可以了。(在不需要Copy容器里面的数据时,就是用枚举器) /// IEnumerable <ServerNPC> Itor = found.AsEnumerable(); // 临时枚举器 IEnumerable <ServerNPC> Itor1 = null; Vector3 anchor = caster.transform.position; Transform trans = caster.transform; ServerNPC nearest = null; CAMP camp = CAMP.None; if (target.AnySame(TargetClass.Friendly)) { camp = caster.Camp; } else if (target.AnySame(TargetClass.Hostile)) { camp = caster.Camp.Hostile(); } Itor1 = NpcSource.getCampBnpc(camp); if (kind == KindOfNPC.Life) { Itor1 = Itor1.Where(n => (n.WhatKindOf() == kind) && (type.check(((ServerLifeNpc)n).WhatTypeOf))); } else if (kind == KindOfNPC.NonLife) { Itor1 = Itor1.Where(n => n.WhatKindOf() == kind); } bool any = Itor1 != null?Itor1.Any() : false; if (any) { /// /// --- 筛选出有效状态的NPC ---- /// Itor1 = Itor1.Where(n => { ServerLifeNpc lifeTar = n as ServerLifeNpc; if (lifeTar != null) { return(!lifeTar.curStatus.AnySame(TarStatusInCfg)); } else { return(true); } }); /// /// --- 再次根据距离条件筛选出NPC ---- /// float radius = caster.data.configData.radius; Itor1 = Itor1.Where(n => IsInRange(anchor, n.data.configData.radius + radius + range, n.transform)); if (target.AnySame(TargetClass.FarAwary)) { nearest = Itor1.OrderByDescending(n => GetVirtualDistance(trans, n.transform)).FirstOrDefault(); if (nearest != null) { found.Add(nearest); } } else if (target.AnySame(TargetClass.Nearest)) { nearest = Itor1.OrderBy(n => GetVirtualDistance(trans, n.transform)).FirstOrDefault(); if (nearest != null) { found.Add(nearest); } } else { Itor = Itor1; } /// /// --- 判定最大,最小生命值的NPC ----- /// if (target.AnySame(TargetClass.HpLowest)) { ServerNPC lowest = Itor1.OrderBy(n => n.data.rtData.CurHpNested).FirstOrDefault(); if (lowest != null) { found.Add(lowest); } } else if (target.AnySame(TargetClass.HpHighest)) { ServerNPC highest = Itor1.OrderByDescending(n => n.data.rtData.CurHpNested).FirstOrDefault(); if (highest != null) { found.Add(highest); } } } return(Itor); }
//此方法仅仅对单体目标有效,多目标的选择不走优先级排序逻辑 //且不能对自己生效和无优先级 //排序完了之后,按照“血量或距离”筛选出合适的NPC public static ServerNPC GetPrioritiedNpc(ServerNPC caster, TargetClass target, WarServerNpcMgr NpcSource, float range, NpcStatus TarStatusInCfg, SkTargetPriority priority, SkPriorityMgr PriorityMgr, LifeNPCType type = LifeNPCType.SkTarAll) { /// /// 获取未排好序的 /// IEnumerable <ServerNPC> unPriority = GetNPCValideStatus(caster, NpcSource, KindOfNPC.Life, target, TarStatusInCfg, type); /// /// 过滤掉超出范围的数据 /// Vector3 anchor = caster.transform.position; Transform trans = caster.transform; float radius = caster.data.configData.radius; unPriority = unPriority.Where(n => IsInRange(anchor, n.data.configData.radius + radius + range, n.transform)); /// /// 排序 /// IPrioritySelect selector = PriorityMgr.getImplement(priority); selector.SortByPriority(unPriority, NpcSource, hasPriority); /// /// 依照排好序的顺序,依次查找出一个适合的目标 /// 查找的方式为:血量和距离 /// ServerNPC theOne = null; bool Highest = target.AnySame(TargetClass.HpHighest); bool Lowest = target.AnySame(TargetClass.HpLowest); bool Farest = target.AnySame(TargetClass.FarAwary); bool Nearest = target.AnySame(TargetClass.Nearest); bool ExceptionCheck = false; int Condition = 0; if (Highest) { Condition++; } if (Lowest) { Condition++; } if (Farest) { Condition++; } if (Nearest) { Condition++; } #if DEBUG Utils.Assert(Condition >= 2, "TargetPriority shall set only one Max Or Min condition."); #endif int count = hasPriority.Count; if (Highest || Lowest) { for (int i = 0; i < count; ++i) { List <ServerNPC> line = hasPriority[i]; if (line != null) { if (Highest) { theOne = line.OrderByDescending(n => n.data.rtData.CurHpNested).FirstOrDefault(); } if (Lowest) { theOne = line.OrderBy(n => n.data.rtData.CurHpNested).FirstOrDefault(); } if (theOne != null) { break; } } } } if (Farest || Nearest) { for (int i = 0; i < count; ++i) { List <ServerNPC> line = hasPriority[i]; if (line != null) { if (Farest) { theOne = line.OrderByDescending(n => GetVirtualDistance(trans, n.transform)).FirstOrDefault(); } if (Nearest) { theOne = line.OrderBy(n => GetVirtualDistance(trans, n.transform)).FirstOrDefault(); } if (theOne != null) { break; } } } } /// /// 这种情况是没有排序的情况,只要能选出来第一个就可以 /// if (Condition == 0) { for (int i = 0; i < count; ++i) { List <ServerNPC> line = hasPriority[i]; if (line != null && line.Count > 0) { theOne = line[0]; if (theOne != null) { break; } } } } return(theOne); }
/// <summary> /// 获取特定的KindOfNPC,敌友方,有效状态的, 是建筑物还是什么的 活着的NPC /// </summary> /// <returns>ServerNPC 列表</returns> /// <param name="caster">Caster.</param> /// <param name="NpcSource">Npc source.</param> /// <param name="kind">KindOfNPC</param> /// <param name="target">TargetClass</param> /// <param name="TarStatusInCfg">NpcStatus</param> /// <param name="type">LifeNPCType.</param> public static IEnumerable <ServerNPC> GetNPCValideStatus(ServerNPC caster, WarServerNpcMgr NpcSource, KindOfNPC kind, TargetClass target, NpcStatus TarStatusInCfg, LifeNPCType type = LifeNPCType.SkTarAll) { // 临时枚举器 IEnumerable <ServerNPC> Itor1 = null; CAMP camp = CAMP.None; if (target.AnySame(TargetClass.Friendly)) { camp = caster.Camp; } else if (target.AnySame(TargetClass.Hostile)) { camp = caster.Camp.Hostile(); } else { //全阵营 camp = CAMP.All; } Itor1 = NpcSource.getCampBnpc(camp); if (kind == KindOfNPC.Life) { Itor1 = Itor1.Where(n => (n.WhatKindOf() == kind) && (type.check(((ServerLifeNpc)n).WhatTypeOf))); } else if (kind == KindOfNPC.NonLife) { Itor1 = Itor1.Where(n => n.WhatKindOf() == kind); } /// /// --- 筛选出有效状态的NPC ---- /// Itor1 = Itor1.Where(n => { ServerLifeNpc lifeTar = n as ServerLifeNpc; if (lifeTar != null) { return(!lifeTar.curStatus.AnySame(TarStatusInCfg)); } else { return(true); } }); return(Itor1); }