public opposite(CardDB.cardName name, int value, BoardObj bo, BoardObj target) { this.name = name; this.value = value; this.bo = bo; this.target = target; }
public opposite(CardDB.cardName name, int value, Handcard hc, BoardObj target) { this.name = name; this.value = value; this.hc = hc; this.target = target; }
public Handcard getOppositeCard(Playfield p, BoardObj attacker, int canWaitMissingMana = 3) { Handcard bestCard = null; if (OppositeDB.ContainsKey(attacker.Name)) { Dictionary <CardDB.cardName, int> tmp = OppositeDB[attacker.Name]; int bestCardVal = -1; CardDB.cardName name; foreach (Handcard hc in p.ownHandCards) { name = hc.card.name; if (canWaitMissingMana >= hc.manacost - p.ownMana) { if (tmp.ContainsKey(name)) { if (tmp[name] > bestCardVal) { bestCardVal = tmp[name]; bestCard = hc; bestCard.val = bestCardVal; bestCard.missingMana = hc.manacost - p.ownMana; } if (bestCardVal == 100) { break; } } } } } return(bestCard); }
public void setKingsLine(bool own) { BoardObj tower = own ? this.ownKingsTower : this.enemyKingsTower; List <BoardObj> list = own ? this.ownTowers : this.enemyTowers; int i = 0; foreach (BoardObj t in list) { if (t.Tower < 10) { i += t.Line; } } tower.Line = 0; switch (i) { case 0: tower.Line = 3; break; case 1: tower.Line = 2; break; case 2: tower.Line = 1; break; } foreach (BoardObj t in list) { if (t.Tower > 9) { t.Line = tower.Line; } } }
public Playfield(Playfield p, int timeShift = 0) { //this.pID = prozis.getPid(); this.ownerIndex = p.ownerIndex; this.BattleTime = p.BattleTime; this.home = p.home; this.ownMana = p.ownMana; this.enemyMana = p.enemyMana; copyCards(p.ownHandCards, p.nextCard); copyBoardObj(p.ownMinions, this.ownMinions); copyBoardObj(p.enemyMinions, this.enemyMinions); copyBoardObj(p.ownAreaEffects, this.ownAreaEffects); copyBoardObj(p.enemyAreaEffects, this.enemyAreaEffects); copyBoardObj(p.ownBuildings, this.ownBuildings); copyBoardObj(p.enemyBuildings, this.enemyBuildings); copyBoardObj(p.ownTowers, this.ownTowers); copyBoardObj(p.enemyTowers, this.enemyTowers); this.ownKingsTower = new BoardObj(p.ownKingsTower); this.ownPrincessTower1 = new BoardObj(p.ownPrincessTower1); this.ownPrincessTower2 = new BoardObj(p.ownPrincessTower2); this.enemyKingsTower = new BoardObj(p.enemyKingsTower); this.enemyPrincessTower1 = new BoardObj(p.enemyPrincessTower1); this.enemyPrincessTower2 = new BoardObj(p.enemyPrincessTower2); initTowers(); this.ownDeck = p.ownDeck; this.enemyDeck = p.enemyDeck; this.ownGroup = p.ownGroup; this.enemyGroup = p.enemyGroup; //enemyHandCards = prozis.enemyHandCards; if (p.needPrint) { this.needPrint = true; this.pIdHistory.AddRange(p.pIdHistory); this.pIdHistory.Add(pID); } this.nextEntity = p.nextEntity; this.evaluatePenality = p.evaluatePenality; this.ruleWeight = p.ruleWeight; this.rulesUsed = p.rulesUsed; this.playactions.AddRange(p.playactions); if (timeShift != 0) { TimeMachine.Instance.setTimeShift(this, timeShift); } }
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 } } } }
public bool aheadOf(BoardObj bo, bool home) { if ((this.Position.Y > bo.Position.Y) == home) { return(true); } else { return(false); } }
public VectorAI getDeployPosition(BoardObj bo, deployDirectionRelative relativeDirection = deployDirectionRelative.none, int deployDistance = 0) //for deployDistance you can use hc.card.DamageRadius { if (bo == null) { Logger.Debug("!!![getDeployPosition]Error:BoardObj == NULL"); return(new VectorAI(0, 0)); } else { return(getDeployPosition(bo.Position, relativeDirection, deployDistance)); } }
//TODO allCharsInAreaGetDamage private void LogBoardObject(BoardObj bo) { Logger.Information("{type} {ownerIndex} {Name} {GId} {Position} {level} {Atk} {HP} {Shield}", bo.type, bo.ownerIndex, bo.Name, bo.GId, bo.Position, bo.level, bo.Atk, bo.HP, bo.Shield); if (bo.frozen) { Logger.Information("frozen: {startFrozen}", bo.startFrozen); } if (bo.LifeTime > 0) { Logger.Information("LifeTime: {LifeTime}", bo.LifeTime); } }
public BoardObj getFrontMob() //TODO: perhaps add for enemy minions { BoardObj retval = null; int count = ownMinions.Count; if (count > 0) { retval = ownMinions[0]; for (int i = 1; i < count; i++) { if (!retval.aheadOf(ownMinions[i], home)) { retval = ownMinions[i]; } } } return(retval); }
public Handcard getPatnerForMobInPeace(BoardObj bo) { if (bo == null) { return(null); } Handcard retval = null; List <Handcard> air = new List <Handcard>(); List <Handcard> troops = new List <Handcard>(); bool needDamager = false; bool needAir = false; if (bo.HP > 600) { needDamager = true; } if (bo.TargetType != targetType.ALL) { needAir = true; } foreach (Handcard hc in ownHandCards) { if (hc.card.type != boardObjType.MOB) { continue; } troops.Add(hc); if (hc.card.Transport == transportType.AIR) { air.Add(hc); } } if (needAir) { retval = getMobCardByCondition(air, needDamager); } if ((needAir && retval == null) || !needAir) { retval = getMobCardByCondition(troops, needDamager); } return(retval); }
private BoardObj getBOfromHeader(string[] line, int ownerIndex) { BoardObj bo = new BoardObj(CardDB.Instance.cardNamestringToEnum(line[2])); bo.ownerIndex = Convert.ToInt32(line[1]); bo.own = bo.ownerIndex == ownerIndex ? true : false; bo.GId = Convert.ToUInt32(line[3]); bo.Position = new VectorAI(line[4]); bo.Line = bo.Position.X > 8700 ? 1 : 2; bo.level = Convert.ToInt32(line[5]); bo.Atk = Convert.ToInt32(line[6]); bo.HP = Convert.ToInt32(line[7]); bo.Shield = Convert.ToInt32(line[8]); int len = line.Length; if (len > 9) { for (int i = 9; i < len; i++) { string[] ss = line[i].Split(':'); switch (ss[0]) { case "frozen": bo.frozen = true; bo.startFrozen = Convert.ToInt32(ss[1]); continue; case "LifeTime": bo.LifeTime = Convert.ToInt32(ss[1]); continue; case "extraData": bo.extraData = ss[1]; continue; } } } //this.attacking = c.attacking; //this.attacked = c.attacked; //this.attacker = c.attacker; //this.target = c.target; return(bo); }
public BoardObj(BoardObj bo) { this.Name = bo.Name; this.card = bo.card; this.type = bo.type; this.Transport = bo.Transport; this.affectOn = bo.affectOn; this.Position = bo.Position; this.own = bo.own; this.pID = bo.pID; //-???????? this.Line = bo.Line; this.GId = bo.GId; this.cost = bo.cost; this.DeployTime = bo.DeployTime; this.DamageRadius = bo.DamageRadius; this.MaxHP = bo.MaxHP; this.HP = bo.HP; this.Atk = bo.Atk; this.Shield = bo.Shield; this.Speed = bo.Speed; this.HitSpeed = bo.HitSpeed; this.MinRange = bo.MinRange; this.Range = bo.Range; this.SightRange = bo.SightRange; this.TargetType = bo.TargetType; this.MaxTargets = bo.MaxTargets; this.attacking = bo.attacking; this.attacked = bo.attacked; this.LifeTime = bo.LifeTime; this.SpawnNumber = bo.SpawnNumber; this.SpawnInterval = bo.SpawnInterval; this.SpawnTime = bo.SpawnTime; this.SpawnCharacterLevel = bo.SpawnCharacterLevel; this.frozen = bo.frozen; this.clone = bo.clone; this.startFrozen = bo.startFrozen; this.attacker = bo.attacker; this.target = bo.target; this.DeathEffect = bo.DeathEffect; this.Tower = bo.Tower; this.extraData = bo.extraData; }
private void addTower(BoardObj tower) { //maybe add duplicate check (todo) - depending on the performance if (tower.own) { ownTowers.Add(tower); if (tower.Tower < 9) { ownPrincessTowers.Add(tower); } } else { enemyTowers.Add(tower); if (tower.Tower < 9) { enemyPrincessTowers.Add(tower); } } }
public void collectCardInfo(BoardObj bo) { if (cardNameToCardList.ContainsKey(bo.Name)) { Card c = cardNameToCardList[bo.Name]; if (c.needUpdate) { c.type = bo.type; c.Transport = bo.Transport; c.TargetType = bo.TargetType; c.affectType = bo.affectOn; c.cost = bo.cost; c.DeployTime = bo.DeployTime; c.DamageRadius = bo.DamageRadius; c.MaxHP = bo.MaxHP; c.Atk = bo.Atk; c.Shield = bo.Shield; c.Speed = bo.Speed; c.HitSpeed = bo.HitSpeed; c.MinRange = bo.MinRange; c.MaxRange = bo.Range; c.SightRange = bo.SightRange; c.MultipleTargets = bo.MaxTargets; c.DeathEffect = bo.DeathEffect; c.Level = bo.level; c.LifeTime = bo.LifeTime; c.SpawnNumber = bo.SpawnNumber; c.SpawnPause = bo.SpawnTime; c.SpawnInterval = bo.SpawnInterval; c.SpawnCharacterLevel = bo.SpawnCharacterLevel; c.needUpdate = false; } } else { //numDuplicates = 0; //numDifferences = 0; } }
public sealed override CastRequest GetNextCast() { Logger.Debug(""); if (statNumSuccessfulEntrances > 0) { statTimeOutsideRoutine = DateTime.Now - statTimerRoutine; } statTimerRoutine = DateTime.Now; List <BoardObj> ownMinions = new List <BoardObj>(); List <BoardObj> enemyMinions = new List <BoardObj>(); List <BoardObj> ownAreaEffects = new List <BoardObj>(); List <BoardObj> enemyAreaEffects = new List <BoardObj>(); List <BoardObj> ownBuildings = new List <BoardObj>(); List <BoardObj> enemyBuildings = new List <BoardObj>(); BoardObj ownKingsTower = new BoardObj(); BoardObj ownPrincessTower1 = new BoardObj(); BoardObj ownPrincessTower2 = new BoardObj(); BoardObj enemyKingsTower = new BoardObj(); BoardObj enemyPrincessTower1 = new BoardObj(); BoardObj enemyPrincessTower2 = new BoardObj(); List <Handcard> ownHandCards = new List <Handcard>(); Handcard prevHandCard = new Handcard(); Logger.Debug("#####Stats##### Inint BO {0}", (statTimerRoutine - DateTime.Now).TotalSeconds); var battle = ClashEngine.Instance.Battle; if (battle == null || !battle.IsValid) { return(null); } var om = ClashEngine.Instance.ObjectManager; if (om == null) { return(null); } var lp = ClashEngine.Instance.LocalPlayer; if (lp == null || !lp.IsValid) { return(null); } var spellButtons = ClashEngine.Instance.AvailableSpellButtons; if (spellButtons == null) { return(null); } var spells = ClashEngine.Instance.AvailableSpells; if (spells == null) { return(null); } if (ownKingsTowerPos.Y == -1) { List <Tuple <int, int> > towersIndY = new List <Tuple <int, int> >(); bool needFriendlyIndex = false; var chars = om.OfType <Clash.Engine.NativeObjects.Logic.GameObjects.Character>(); foreach (var @char in chars) { if ([email protected]) { continue; } var data = @char.LogicGameObjectData; if (data == null || !data.IsValid) { continue; } var name = data.Name; if ((MemPtr)name == MemPtr.Zero) { continue; } switch (CardDB.Instance.cardNamestringToEnum(name.Value.ToString(), "0")) { case CardDB.cardName.kingtower: int OwnerIndex = (int)@char.OwnerIndex; int charY = @char.StartPosition.Y; towersIndY.Add(new Tuple <int, int>(OwnerIndex, charY)); if (OwnerIndex == lp.OwnerIndex) { ownKingsTowerPos.Y = charY; } break; case CardDB.cardName.kingtowermiddle: ownKingsTowerPos.X = @char.StartPosition.X; needFriendlyIndex = true; break; } } if (needFriendlyIndex) { foreach (var t in towersIndY) { if (ownKingsTowerPos.Y == t.Item2 && lp.OwnerIndex != t.Item1) { friendlyOwnerIndex = t.Item1; } } } } Logger.Debug("#####Stats##### Inint BO+engine {0}", (statTimerRoutine - DateTime.Now).TotalSeconds); using (new PerformanceTimer("GetNextCast entrance")) { Handcard Mirror = null; Dictionary <string, int> AvailableSpells = new Dictionary <string, int>(); foreach (var spell in spells) { if (spell == null || !spell.IsValid) { continue; } var name = spell.Name; if ((MemPtr)name == MemPtr.Zero) { continue; } AvailableSpells.Add(name.Value.ToString(), 0); } foreach (var spellBtn in spellButtons) { if (spellBtn == null || !spellBtn.IsValid) { continue; } if (spellBtn.SpellDeckSpell == null || !spellBtn.SpellDeckSpell.IsValid) { continue; } if (spellBtn.SpellDeckSpell.Spell == null || !spellBtn.SpellDeckSpell.Spell.IsValid) { continue; } var name = spellBtn.SpellDeckSpell.Spell.Name; if ((MemPtr)name == MemPtr.Zero) { continue; } if (!AvailableSpells.ContainsKey(name.Value.ToString())) { continue; } int lvl = spellBtn.SpellDeckSpell.LevelIndex; Handcard hc = new Handcard(name.Value.ToString(), lvl); if (hc.card.name == CardDB.cardName.unknown) { CardDB.Instance.collectNewCards(spellBtn); } hc.manacost = spellBtn.SpellDeckSpell.Spell.ManaCost; if (hc.card.name == CardDB.cardName.mirror) { Mirror = hc; } //if (hc.card.needUpdate) CardDB.Instance.cardsAdjustment(spell); ownHandCards.Add(hc); } if (ownHandCards.Count == 4) { if (prevHandCards.Count != 4) { prevHandCards = new List <Handcard>(ownHandCards); } else { for (int i = 0; i < 4; i++) { if (ownHandCards[i].card.name == prevHandCards[i].card.name) { continue; } if (ownHandCards[i].card.name == CardDB.cardName.unknown) { continue; } prevHandCard = prevHandCards[i]; if (Mirror != null) { Mirror.transformTo(prevHandCard); Mirror.mirror = true; } break; } } } var qSpells = ClashEngine.Instance.QueuedSpells; if (qSpells != null) { if (qSpells.Count() == 0) { if (CastRequestDB.Count != 0) { CastRequestDB.Clear(); } } else { if (CastRequest != null && !CastRequestDB.ContainsKey(CastRequest.SpellName)) { CastRequestDB.Add(CastRequest.SpellName, CastRequest); } if (CastRequestDBtmp.Count != 0) { CastRequestDBtmp.Clear(); } foreach (var qs in qSpells) { if (qs == null || !qs.IsValid) { continue; } string name = qs.Name.Value.ToString(); if (!CastRequestDBtmp.ContainsKey(name)) { CastRequestDBtmp.Add(name, 0); } if (CastRequestDB.ContainsKey(name)) { //add to pf //TODO: real lvl BoardObj bo = new BoardObj(CardDB.Instance.cardNamestringToEnum(name, "21"), 6); bo.Position = new VectorAI(CastRequestDB[name].Position); bo.ownerIndex = (int)lp.OwnerIndex; bo.frozen = true; bo.GId = getNextGId(); switch (bo.type) { case boardObjType.MOB: int nums = bo.card.SummonNumber; if (nums == 0) { nums = 1; } else { if (bo.card.SpawnCharacter != "") { bo = new BoardObj(CardDB.Instance.cardNamestringToEnum(bo.card.SpawnCharacter, "22"), 6); bo.Position = new VectorAI(CastRequestDB[name].Position); bo.ownerIndex = (int)lp.OwnerIndex; bo.frozen = true; bo.GId = getNextGId(); } } for (int i = 0; i < nums; i++) { ownMinions.Add(bo); if (nums > 1) { bo = new BoardObj(bo); bo.GId = getNextGId(); } } break; case boardObjType.BUILDING: ownBuildings.Add(bo); break; case boardObjType.AOE: break; } } } foreach (var kvp in CastRequestDB.ToArray()) { if (!CastRequestDBtmp.ContainsKey(kvp.Key)) { CastRequestDB.Remove(kvp.Key); } } } } //var projs = om.OfType<Clash.Engine.NativeObjects.Logic.GameObjects.Projectile>(); //foreach (var proj in projs) //{ // if (proj != null && proj.IsValid) // { // //TODO: get static data for all objects // //Here we get dynamic data only // CardDB.Instance.collectNewCards(proj); // } //} var aoes = om.OfType <Clash.Engine.NativeObjects.Logic.GameObjects.AreaEffectObject>(); foreach (var aoe in aoes) { if (!aoe.IsValid) { continue; } var data = aoe.LogicGameObjectData; if (data == null || !data.IsValid) { continue; } var name = data.Name; if ((MemPtr)name == MemPtr.Zero) { continue; } BoardObj bo = new BoardObj(CardDB.Instance.cardNamestringToEnum(name.Value.ToString(), "1")); //if (bo.card.needUpdate) CardDB.Instance.cardsAdjustment(aoe); if (bo.card.name == CardDB.cardName.unknown) { CardDB.Instance.collectNewCards(aoe); } bo.GId = aoe.GlobalId; bo.Position = new VectorAI(aoe.StartPosition); bo.Line = bo.Position.X > 8700 ? 2 : 1; //bo.level = TODO real value //bo.Atk = TODO real value bo.LifeTime = aoe.HealthComponent.RemainingTime; //bo.extraData = data.Field10.ToString();//!!TEST bo.ownerIndex = (int)aoe.OwnerIndex; bool own = bo.ownerIndex == lp.OwnerIndex ? true : (bo.ownerIndex == friendlyOwnerIndex ? true : false); bo.own = own; if (own) { ownAreaEffects.Add(bo); } else { enemyAreaEffects.Add(bo); } } var chars = om.OfType <Clash.Engine.NativeObjects.Logic.GameObjects.Character>(); foreach (var @char in chars) { if ([email protected]) { continue; } var data = @char.LogicGameObjectData; if (data == null || !data.IsValid) { continue; } var name = data.Name; if ((MemPtr)name == MemPtr.Zero) { continue; } BoardObj bo = new BoardObj(CardDB.Instance.cardNamestringToEnum(name.Value.ToString(), "2"), (int)@char.TowerLevel); bo.ownerIndex = (int)@char.OwnerIndex; bool own = bo.ownerIndex == lp.OwnerIndex ? true : (bo.ownerIndex == friendlyOwnerIndex ? true : false); bo.own = own; if (bo.card.name == CardDB.cardName.unknown) { CardDB.Instance.collectNewCards(@char); } else if (bo.ownerIndex == lp.OwnerIndex && bo.card.needUpdate) { CardDB.Instance.cardsAdjustment(@char); } bo.GId = @char.GlobalId; bo.Position = new VectorAI(@char.StartPosition); bo.Line = bo.Position.X > 8700 ? 2 : 1; bo.level = 1 + (int)@char.TowerLevel; //this.frozen = TODO //this.startFrozen = TODO bo.HP = @char.HealthComponent.CurrentHealth; bo.Shield = @char.HealthComponent.CurrentShieldHealth; bo.LifeTime = @char.HealthComponent.LifeTime - @char.HealthComponent.RemainingTime; //TODO: - find real value for battle stage int tower = 0; switch (bo.Name) { case CardDB.cardName.princesstower: CardDB.Instance.setPrincessTowerMaxHP(bo); tower = bo.Line; if (bo.own) { if (tower == 1) { ownPrincessTower1 = bo; } else { ownPrincessTower2 = bo; } } else { if (tower == 1) { enemyPrincessTower1 = bo; } else { enemyPrincessTower2 = bo; } } break; case CardDB.cardName.kingtower: CardDB.Instance.setKingsTowerMaxHP(bo); tower = 10 + bo.Line; if (bo.own) { if (ownKingsTower.HP == 0) { ownKingsTower = bo; } else if (bo.HP < ownKingsTower.HP) { ownKingsTower = bo; } if (ownKingsTowerPos.X != -1) { ownKingsTower.Position.X = ownKingsTowerPos.X; } ownKingsTower.ownerIndex = (int)lp.OwnerIndex; } else { if (enemyKingsTower.HP == 0) { enemyKingsTower = bo; } else if (bo.HP < enemyKingsTower.HP) { enemyKingsTower = bo; } if (ownKingsTowerPos.X != -1) { enemyKingsTower.Position.X = ownKingsTowerPos.X; } } break; case CardDB.cardName.kingtowermiddle: tower = 100; break; default: bo.Atk = (int)(bo.card.Atk * lvlToCoef[bo.level]); //TODO: need value from core if (own) { switch (bo.type) { case boardObjType.MOB: ownMinions.Add(bo); break; case boardObjType.BUILDING: ownBuildings.Add(bo); break; } } else { switch (bo.type) { case boardObjType.MOB: enemyMinions.Add(bo); break; case boardObjType.BUILDING: enemyBuildings.Add(bo); break; } } break; } } } Playfield p; Logger.Debug("#####Stats##### before Initialize playfield {0}", (statTimerRoutine - DateTime.Now).TotalSeconds); using (new PerformanceTimer("Initialize playfield.")) { Logger.Debug("################################Routine v.0.8.6 Behavior:{Name:l} v.{Version:l}", Name, Version); p = new Playfield { BattleTime = battle.BattleTime, suddenDeath = battle.BattleTime.TotalSeconds > 180, ownerIndex = (int)lp.OwnerIndex, ownMana = (int)(lp.Mana - lp.ReservedMana), ownHandCards = ownHandCards, ownAreaEffects = ownAreaEffects, ownMinions = ownMinions, ownBuildings = ownBuildings, ownKingsTower = ownKingsTower, ownPrincessTower1 = ownPrincessTower1, ownPrincessTower2 = ownPrincessTower2, enemyAreaEffects = enemyAreaEffects, enemyMinions = enemyMinions, enemyBuildings = enemyBuildings, enemyKingsTower = enemyKingsTower, enemyPrincessTower1 = enemyPrincessTower1, enemyPrincessTower2 = enemyPrincessTower2, prevCard = prevHandCard, //nextCard = //TODO: Add next card }; p.home = p.ownKingsTower.Position.Y < 15250 ? true : false; if (p.ownPrincessTower1.Position == null) { p.ownPrincessTower1.Position = p.getDeployPosition(deployDirectionAbsolute.ownPrincessTowerLine1); } if (p.ownPrincessTower2.Position == null) { p.ownPrincessTower2.Position = p.getDeployPosition(deployDirectionAbsolute.ownPrincessTowerLine2); } if (p.enemyPrincessTower1.Position == null) { p.enemyPrincessTower1.Position = p.getDeployPosition(deployDirectionAbsolute.enemyPrincessTowerLine1); } if (p.enemyPrincessTower2.Position == null) { p.enemyPrincessTower2.Position = p.getDeployPosition(deployDirectionAbsolute.enemyPrincessTowerLine2); } p.initTowers(); p.print(); battleLogs.Add(p); } Logger.Debug("#####Stats##### after Initialize playfield {0}", (statTimerRoutine - DateTime.Now).TotalSeconds); statTimeInitPlayfield = DateTime.Now - statTimerRoutine; statTimerRoutine = DateTime.Now; Cast bc; using (new PerformanceTimer("GetBestCast")) { //DateTime statBehaviorCalcStart = DateTime.Now; bc = this.GetBestCast(p); CastRequest = null; if (bc != null && bc.Position != null) { if (p.ownMana + 1 >= bc.hc.manacost) { CastRequest = new CastRequest(bc.SpellName, bc.Position.ToVector2f(true)); } Logger.Debug("CastRequest {SpellName:l} {Position:l}", bc.SpellName, CastRequest == null ? bc.Position?.ToString() : CastRequest.Position.ToString()); } else { Logger.Debug("Waiting for cast, maybe next tick..."); } statTimeInsideBehavior = DateTime.Now - statTimerRoutine; //stat info statSumTimeOutsideRoutine += statTimeOutsideRoutine; statSumTimeInitPlayfield += statTimeInitPlayfield; statSumTimeInsideBehavior += statTimeInsideBehavior; statNumSuccessfulEntrances++; int objsCount = ownAreaEffects.Count + enemyAreaEffects.Count + ownMinions.Count + enemyMinions.Count + ownBuildings.Count + enemyBuildings.Count; //without HandCards if (objsCount == 0) { objsCount = 2; } Logger.Debug("Hint: ne:NumberEntrances CT:CalculationTime aCT:AverageCalculationTimePer1Game tpo:TimePer1Object ToR:TimeOutsideRoutine"); Logger.Debug("#####Stats### ne:{NumberEntrances} Behavior(CT/aCT/tpo):{BehaviorCalcTime}/{averageBCT}/{timePer1Object} Playfield(CT/aCT/tpo):{PlayfieldCreationTime}/{averagePCT}/{timePer1Object} outsideRoutine(ToR/aToR/tpo):{timeOutsideRoutine}/{averageToR}/{timePer1Object}", statNumSuccessfulEntrances, statTimeInsideBehavior.TotalSeconds, (statSumTimeInsideBehavior / statNumSuccessfulEntrances).TotalSeconds, (statTimeInsideBehavior / objsCount).TotalSeconds, statTimeInitPlayfield.TotalSeconds, (statSumTimeInitPlayfield / statNumSuccessfulEntrances).TotalSeconds, (statTimeInitPlayfield / objsCount).TotalSeconds, statTimeOutsideRoutine.TotalSeconds, (statSumTimeOutsideRoutine / (statNumSuccessfulEntrances > 1 ? statNumSuccessfulEntrances - 1 : 1)).TotalSeconds, (statTimeOutsideRoutine / objsCount).TotalSeconds); statTimerRoutine = DateTime.Now; return(CastRequest); } }
public abstract int GetBoValue(BoardObj bo, Playfield p);
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 sealed override CastRequest GetNextCast() { List <BoardObj> ownMinions = new List <BoardObj>(); List <BoardObj> enemyMinions = new List <BoardObj>(); List <BoardObj> ownAreaEffects = new List <BoardObj>(); List <BoardObj> enemyAreaEffects = new List <BoardObj>(); List <BoardObj> ownBuildings = new List <BoardObj>(); List <BoardObj> enemyBuildings = new List <BoardObj>(); BoardObj ownKingsTower = new BoardObj(); BoardObj ownPrincessTower1 = new BoardObj(); BoardObj ownPrincessTower2 = new BoardObj(); BoardObj enemyKingsTower = new BoardObj(); BoardObj enemyPrincessTower1 = new BoardObj(); BoardObj enemyPrincessTower2 = new BoardObj(); List <Handcard> ownHandCards = new List <Handcard>(); var battle = ClashEngine.Instance.Battle; if (battle == null || !battle.IsValid) { return(null); } var om = ClashEngine.Instance.ObjectManager; if (om == null) { return(null); } var lp = ClashEngine.Instance.LocalPlayer; if (lp == null || !lp.IsValid) { return(null); } var spells = ClashEngine.Instance.AvailableSpells; if (spells == null) { return(null); } StringBuilder sb = new StringBuilder(); using (new PerformanceTimer("GetNextCast entrance")) { foreach (var spell in spells) { if (spell != null && spell.IsValid) { int lvl = 1; Handcard hc = new Handcard(spell.Name.Value, lvl); //hc.lvl = ??? TODO hc.manacost = spell.ManaCost; //hc.position = ??? TODO //TODO:for all objects - if (new name) get actual params ownHandCards.Add(hc); } } var aoes = om.OfType <Clash.Engine.NativeObjects.Logic.GameObjects.AreaEffectObject>(); foreach (var aoe in aoes) { if (aoe != null && aoe.IsValid) { //TODO: get static data for all objects //Here we get dynamic data only BoardObj bo = new BoardObj(CardDB.Instance.cardNamestringToEnum(aoe.LogicGameObjectData.Name.Value)); bo.GId = aoe.GlobalId; bo.Position = new VectorAI(aoe.StartPosition); bo.Line = bo.Position.X > 8700 ? 1 : 2; //bo.level = TODO real value //bo.Atk = TODO real value bo.LifeTime = aoe.HealthComponent.RemainingTime; //TODO check this value bo.ownerIndex = (int)aoe.OwnerIndex; bool own = bo.ownerIndex == lp.OwnerIndex ? true : false; //TODO: replace it on Friendly (for 2x2 mode) bo.own = own; if (own) { ownAreaEffects.Add(bo); } else { enemyAreaEffects.Add(bo); } //hc.position = ??? TODO } } var chars = om.OfType <Clash.Engine.NativeObjects.Logic.GameObjects.Character>(); foreach (var @char in chars) { //sb.Clear(); //i++; //BoardObj bo = new BoardObj(); var data = @char.LogicGameObjectData; if (data != null && data.IsValid) { //TODO: get static data for all objects //Here we get dynamic data only BoardObj bo = new BoardObj(CardDB.Instance.cardNamestringToEnum(data.Name.Value)); bo.GId = @char.GlobalId; bo.Position = new VectorAI(@char.StartPosition); bo.Line = bo.Position.X > 8700 ? 1 : 2; //bo.level = TODO real value //bo.Atk = TODO real value //this.frozen = TODO //this.startFrozen = TODO bo.HP = @char.HealthComponent.CurrentHealth; //TODO: check it bo.Shield = @char.HealthComponent.CurrentShieldHealth; //TODO: check it bo.LifeTime = @char.HealthComponent.LifeTime - @char.HealthComponent.RemainingTime; //TODO: check it of data.LifeTime, - find real value for battle stage bo.ownerIndex = (int)@char.OwnerIndex; bool own = bo.ownerIndex == lp.OwnerIndex ? true : false; //TODO: replace it on Friendly (for 2x2 mode) int tower = 0; switch (bo.Name) { case CardDB.cardName.princesstower: tower = bo.Line; if (bo.own) { if (tower == 1) { ownPrincessTower1 = bo; } else { ownPrincessTower2 = bo; } } else { if (tower == 1) { enemyPrincessTower1 = bo; } else { enemyPrincessTower2 = bo; } } break; case CardDB.cardName.kingtower: tower = 10 + bo.Line; if (bo.own) { if (lp.OwnerIndex == bo.ownerIndex) { ownKingsTower = bo; } } else { enemyKingsTower = bo; } break; case CardDB.cardName.kingtowermiddle: tower = 100; break; } if (tower == 0) { if (bo.own) { ownBuildings.Add(bo); } else { enemyBuildings.Add(bo); } } bo.own = own; if (own) { switch (bo.type) { case boardObjType.MOB: ownMinions.Add(bo); break; case boardObjType.BUILDING: if (bo.Tower > 0) { if (bo.Tower > 9 && bo.ownerIndex == lp.OwnerIndex) { ownKingsTower = bo; } } else { ownBuildings.Add(bo); } break; } } else { switch (bo.type) { case boardObjType.MOB: enemyMinions.Add(bo); continue; case boardObjType.BUILDING: if (bo.Tower == 0) { if (bo.Tower > 9) { enemyKingsTower = bo; } } else { enemyBuildings.Add(bo); } break; } } } } } Playfield p; using (new PerformanceTimer("Initialize playfield.")) { p = new Playfield { BattleTime = ClashEngine.Instance.Battle.BattleTime, ownerIndex = (int)lp.OwnerIndex, ownMana = (int)lp.Mana, ownHandCards = ownHandCards, ownAreaEffects = ownAreaEffects, ownMinions = ownMinions, ownBuildings = ownBuildings, ownKingsTower = ownKingsTower, ownPrincessTower1 = ownPrincessTower1, ownPrincessTower2 = ownPrincessTower2, enemyAreaEffects = enemyAreaEffects, enemyMinions = enemyMinions, enemyBuildings = enemyBuildings, enemyKingsTower = enemyKingsTower, enemyPrincessTower1 = enemyPrincessTower1, enemyPrincessTower2 = enemyPrincessTower2, //TODO: Add next card //nextCard = }; p.home = p.ownKingsTower.Position.Y < 15250 ? true : false; p.initTowers(); int i = 0; foreach (BoardObj t in p.ownTowers) { if (t.Tower < 10) { i += t.Line; } } int kingsLine = 0; switch (i) { case 0: kingsLine = 3; break; case 1: kingsLine = 2; break; case 2: kingsLine = 1; break; } foreach (BoardObj t in p.ownTowers) { if (t.Tower > 9) { t.Line = kingsLine; } } p.print(); } Cast bc; using (new PerformanceTimer("GetBestCast")) { bc = this.GetBestCast(p); CastRequest retval = null; if (bc != null && bc.Position != null) { Logger.Information("Cast {bc}", bc.ToString()); retval = new CastRequest(bc.SpellName, bc.Position.ToVector2()); } else { Logger.Information("Waiting for cast, maybe next tick..."); } 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); }
//TODO allCharsInAreaGetDamage private void LogBoardObject(BoardObj bo) { string extrainfo = (bo.frozen ? " frozen:" + bo.startFrozen : "") + (bo.LifeTime > 0 ? " LifeTime:" + bo.LifeTime : "") + (bo.extraData != "" ? " ed:" + bo.extraData : ""); Logger.Debug("{type} {own:l} {ownerIndex} {Name} {GId} {Position:l} {level} {Atk} {HP} {Shield}{extrainfo:l}", bo.type, bo.own ? "o" : "e", bo.ownerIndex, bo.Name, bo.GId, bo.Position, bo.level, bo.Atk, bo.HP, bo.Shield, extrainfo); }
public attackDef(BoardObj att, BoardObj tgt) { if (att.Line != tgt.Line && tgt.Tower < 10) { return; } if (att.Atk == 0) { return; } switch (att.TargetType) { case targetType.GROUND: if (tgt.Transport == transportType.AIR) { return; } break; case targetType.NONE: return; } this.attacker = att; this.target = tgt; this.empty = false; //TODO: here we calc attackPos based on range and collision radius and speed both bo - просто добавить учёт радиуса коллизий if (att.type == boardObjType.BUILDING || att.frozen) { att.Speed = 0; } if (tgt.type == boardObjType.BUILDING || tgt.frozen) { tgt.Speed = 0; } //TODO: find how to calc it without Math int fullDistance = (int)Math.Sqrt((att.Position.X - tgt.Position.X) * (att.Position.X - tgt.Position.X) + (att.Position.Y - tgt.Position.Y) * (att.Position.Y - tgt.Position.Y)); int attackDistance = fullDistance - att.Range; if (attackDistance <= 0) { this.time = 0; } else { //TODO: get real direction //-TODO: переделать с учётом того что цель может двигаться а может и нет и вообще у неё тоже есть радиус атаки и она может остановиться... //-тут мы учли обе скорости, но это не правильно if (att.Speed + tgt.Speed == 0) { this.empty = true; return; } this.time = attackDistance / (att.Speed + tgt.Speed); } int distanceAtt = att.Speed * this.time; int distanceTgt = tgt.Speed * this.time; this.attPos = new VectorAI(att.Position); this.tgtPos = new VectorAI(tgt.Position); if (this.time > 0) { if (att.Speed > 0) { this.attPos.X = ((fullDistance - distanceAtt) * att.Position.X + distanceAtt * tgt.Position.X) / fullDistance; this.attPos.Y = ((fullDistance - distanceAtt) * att.Position.Y + distanceAtt * tgt.Position.Y) / fullDistance; } if (tgt.Speed > 0) { this.tgtPos.X = ((fullDistance - distanceTgt) * tgt.Position.X + distanceTgt * att.Position.X) / fullDistance; this.tgtPos.Y = ((fullDistance - distanceTgt) * tgt.Position.Y + distanceTgt * att.Position.Y) / fullDistance; //-переделать под реальные радиусы и учесть точку останова для радиусных } } }