public void rotateLines() { //-Here we rotate towers and locking for nearest threat int i = ownTowers.Count; if (i < 1) { return; } List <attackDef> attackersList = new List <attackDef>(); List <attackDef> tmp; attackDef near = new attackDef(); foreach (BoardObj t in this.ownTowers) { tmp = t.getImmediateAttackers(this); if (tmp.Count > 0 && (near.empty || near.time > tmp[0].time)) { near = tmp[0]; } } if (!near.empty) { Playfield p = new Playfield(this, near.time); BoardObj myObj = near.attacker.own ? near.attacker : near.target; opposite opp = KnowledgeBase.Instance.getOppositeToAll(p, myObj); if (opp != null) { if (opp.hc != null) { int callTime = near.time - opp.hc.card.DeployTime; if (callTime < 0) { callTime = 0; } p = new Playfield(p, callTime); VectorAI position = new VectorAI(0, 0); //VectorAI position = p.getDeployPosition(opp); //TODO: this decision takes a behavior or a time machine bestCast = new Cast(opp.hc.name, position, opp.hc); } else if (opp.bo != null) { if (opp.bo.TargetType == targetType.GROUND) { //TODO } } else { //TODO automatic creation opposite list in getOppositeToAll or do something else } } } }
private VectorAI getDeployPosition(opposite opp) { VectorAI retval = new VectorAI(0, 0); //TODO: /* * 1.Исходя из Радиуса атаки высчитываем точку его призыва. * а)учесть, он дамагер или отвлекатель * если дамагер - то так что бы сразу был на линии своей атаки * если отвлекатель - то так чтобы башни или другие минионы дамажили как можно дольше + подальше от других вражеских * distractor * */ if (noEnemiesOnMySide()) { return(getBackPosition(opp.hc)); } BoardObj enemy = opp.target; bool enemyMelee = (opp.target.Range < 1000) ? true : false; //TODO: set real value bool defenderMelee = (opp.target.attacker.Range < 1000) ? true : false; //TODO: set real value bool attackerMelee = (opp.hc.card.MaxRange < 3) ? true : false; //TODO: set real value VectorAI centerPos = new VectorAI(0, 0); int kingLine = 0; foreach (BoardObj tower in this.ownTowers) { if (tower.Tower < 10) { continue; } kingLine = tower.Line; centerPos = tower.Position; break; } if (enemyMelee) { if (attackerMelee) { if (enemy.attacked) { if (defenderMelee) { retval = enemy.Position; } else { //0.TODO: ставить так что бы сагрился именно на оппозит + максимально увести вбок под башни //или других юнитов с радиусом атаки и не вывести из под текущего дефендера(того кто ща атакует) retval = centerPos; } } else if (enemy.attacking) { retval = enemy.Position; } else { //1.TODO: выбрать: //а)если на линии есть R атакер - то поближе к нему //б)прям на врага //с)если отвлекатель - то увести вбок меж башен retval = enemy.Position; } } else { if (enemy.attacked) { if (defenderMelee) { //2.TODO: max R + под башни если не сдержит или поближе (но не слишком близко на случай аое) и //в бок паралельно 1 башне что бы она доставала если сдержит (что бы потом войска настакались) retval = centerPos; } else { //3.TODO: выбрать кто ценнее - дефендер или атакер и поставить на max R + под башни //если не сдержит или в бок паралельно 1 башне что бы она доставала если сдержит //что бы потом войска настакались но небыли слишком близко на случай аое retval = centerPos; } } else if (enemy.attacking) { //2.TODO: max R + под башни если не сдержит или в бок паралельно 1 башне что бы она доставала если сдержит //что бы потом войска настакались но небыли слишком близко на случай аое retval = centerPos; } else { //6.TODO: выбрать: //а)если есть рэндж атакер на поле который сможет его атаковать - выбрать кто ценнее и поставить //так что бы сагрился на менее ценного (не забываем уводить под башни и max R) //б) //2. retval = centerPos; } } } else { if (attackerMelee) { if (enemy.attacked) { retval = enemy.Position; } else if (enemy.attacking) { retval = enemy.Position; } else { //4.TODO: выбрать: //а)если есть рэндж атакер на поле который сможет его атаковать и сам не будет атакован //то выбать что лучше подставить под дефендера и позволить врагу атаковать юнитов пока они //топают к нему (отвлекатель, нельзя дамагера) или поставить сразу на врага (дамагер или отвлекатель) //б)поставить сразу на врага retval = enemy.Position; } } else { if (enemy.attacked) { if (defenderMelee) { //2.TODO: max R + под башни если не сдержит или в бок паралельно 1 башне что бы она доставала если сдержит //что бы потом войска настакались но небыли слишком близко на случай аое retval = centerPos; } else { //3.TODO: выбрать кто ценнее - дефендер или атакер и поставить на max R + под башни //если не сдержит или в бок паралельно 1 башне что бы она доставала если сдержит //что бы потом войска настакались но небыли слишком близко на случай аое retval = centerPos; } } else if (enemy.attacking) { //2.TODO: max R + под башни если не сдержит или в бок паралельно 1 башне что бы она доставала если сдержит //что бы потом войска настакались но небыли слишком близко на случай аое retval = centerPos; } else { //5.TODO: выбрать: //а)если ток башня - выбрать кто ценнее и поставить на max R //б) //2. retval = centerPos; } } } return(retval); }
public opposite getOppositeToAll(Playfield p, BoardObj defender, int canWaitMissingMana = 3) { opposite bestOpposite = null; List <attackDef> attackersList = defender.getPossibleAttackers(p); if (attackersList.Count < 1) { return(bestOpposite); } List <attackDef> defendersList; CardDB.cardName aName; CardDB.cardName dName; Dictionary <CardDB.cardName, int> aopp; Dictionary <CardDB.cardName, opposite> allOpposite = new Dictionary <CardDB.cardName, opposite>(); foreach (attackDef ad in attackersList) { if (OppositeDB.ContainsKey(ad.attacker.Name)) { aopp = OppositeDB[ad.attacker.Name]; //-1.Get all obj on board defendersList = ad.attacker.getPossibleAttackers(p); foreach (var def in defendersList) { dName = def.attacker.Name; if (aopp.ContainsKey(dName)) { if (!allOpposite.ContainsKey(dName)) { allOpposite.Add(dName, new opposite(dName, aopp[dName], def.attacker, ad.attacker)); } else { allOpposite[dName].value += aopp[dName]; } } } //-2.Get all cards //TODO - enemy have opposite - it depends on his mana if (defender.own) { foreach (Handcard hc in p.ownHandCards) { dName = hc.card.name; if (canWaitMissingMana >= hc.manacost - p.ownMana && aopp.ContainsKey(dName)) { hc.missingMana = hc.manacost - p.ownMana; if (!allOpposite.ContainsKey(dName)) { allOpposite.Add(dName, new opposite(dName, aopp[dName], hc, ad.attacker)); } else { allOpposite[dName].value += aopp[dName]; } } } } } else { Handcard tmp = null; int count = p.ownHandCards.Count; //TODO automatic creation opposite list if (ad.attacker.Transport == transportType.AIR) { foreach (Handcard hc in p.ownHandCards) { if (canWaitMissingMana >= hc.manacost - p.ownMana) { if (hc.card.TargetType == targetType.ALL) { if (ad.attacker.card.DamageRadius > 1000) { if (hc.card.MaxHP > ad.attacker.Atk) { if (tmp == null || tmp.card.MaxHP < hc.card.MaxHP) { tmp = hc; } } } else { if (hc.card.MaxHP > ad.attacker.Atk * 4 || hc.card.SpawnNumber > 3 || hc.card.SummonNumber > 3) { tmp = hc; break; } } } } } } else { if (ad.attacker.TargetType == targetType.ALL) { foreach (Handcard hc in p.ownHandCards) { if (canWaitMissingMana >= hc.manacost - p.ownMana) { if (ad.attacker.card.DamageRadius > 1000 && hc.card.MaxHP > ad.attacker.Atk) { if (tmp == null || tmp.card.MaxHP < hc.card.MaxHP) { tmp = hc; } } else { if (hc.card.MaxHP > ad.attacker.Atk * 4 || hc.card.SpawnNumber > 3 || hc.card.SummonNumber > 3) { tmp = hc; break; } } } } } else if (ad.attacker.TargetType == targetType.BUILDINGS) { foreach (Handcard hc in p.ownHandCards) { if (canWaitMissingMana >= hc.manacost - p.ownMana) { if (hc.card.Atk > ad.attacker.HP * 5 || hc.card.SpawnNumber > 3) { tmp = hc; break; } } } } else { foreach (Handcard hc in p.ownHandCards) { if (canWaitMissingMana >= hc.manacost - p.ownMana) { if (hc.card.Transport == transportType.AIR) { if (tmp == null || tmp.card.SpawnNumber < hc.card.SpawnNumber || tmp.card.SummonNumber < hc.card.SummonNumber) { tmp = hc; } } } } if (tmp == null) { foreach (Handcard hc in p.ownHandCards) { if (canWaitMissingMana >= hc.manacost - p.ownMana) { if (ad.attacker.card.DamageRadius > 1000) { if (hc.card.MaxHP > ad.attacker.Atk) { if (tmp == null || tmp.card.MaxHP < hc.card.MaxHP) { tmp = hc; } } } else { if (hc.card.MaxHP > ad.attacker.Atk * 4 || hc.card.SpawnNumber > 3 || hc.card.SummonNumber > 3) { tmp = hc; break; } } } } } } } if (tmp == null) { foreach (Handcard hc in p.ownHandCards) { if (hc.card.type == boardObjType.PROJECTILE) { if (tmp == null || tmp.card.Atk < hc.card.Atk) { tmp = hc; } } } } if (tmp == null && p.ownMana >= 9) { tmp = p.getCheapestCard(boardObjType.NONE, targetType.NONE); } if (tmp != null && !allOpposite.ContainsKey(tmp.card.name)) { tmp.missingMana = tmp.manacost - p.ownMana; allOpposite.Add(tmp.card.name, new opposite(tmp.card.name, 10, tmp, ad.attacker)); } } } int oppCount = allOpposite.Count; if (oppCount > 0) { foreach (opposite opp in allOpposite.Values) { if (OppositeDB.ContainsKey(opp.name)) { aopp = OppositeDB[opp.name]; foreach (attackDef ad in attackersList) { aName = ad.attacker.Name; if (aopp.ContainsKey(aName)) { opp.value -= aopp[aName]; //TODO: test - repeat for each or break; } } } else { Logger.Debug("!OppositeDB.ContainsKey"); } if (bestOpposite != null) { if (bestOpposite.value < opp.value) { bestOpposite = opp; } } else { bestOpposite = opp; } } if (bestOpposite != null && bestOpposite.target != null && bestOpposite.hc != null && bestOpposite.hc.card != null) { bestOpposite.target.attacker = new BoardObj(bestOpposite.hc.card.name, bestOpposite.hc.lvl); } } return(bestOpposite); }