private void ProcessFeedbackStringFromWebClient(object sender, DownloadStringCompletedEventArgs e) { COMPACT_LOGGER.Debug(".. Received feedback .."); this.pagesLoaded++; if (!this.running) { COMPACT_LOGGER.Warn("Received feedback after shutdown."); return; } if (e.Error != null) { COMPACT_LOGGER.Error(e.Error, "Error during web request."); return; } switch (ParseGameStatus(e.Result)) { case EventType.NORMAL: break; case EventType.DEATH: COMPACT_LOGGER.Info("Restarting..."); PrintStatistics(); ResetAfterDeath(); return; case EventType.REGEX_FAIL: COMPACT_LOGGER.Error("Aborting run."); PrintStatistics(); return; default: COMPACT_LOGGER.Error("Unknown game state. Aborting."); return; } DetermineCurrentPosition(); // currently standing next to the stairs if (this.directions.Contains(DirectionType.DOWN)) { this.stairPositionX = this.playerPosX; this.stairPositionY = this.playerPosY; COMPACT_LOGGER.Info("Found stairs at: " + this.stairPositionX + ":" + this.stairPositionY); } // need to fight? if (this.fightRound > 0) { // use best BUFF potion for boss fight if ((this.fightRound == 1) && this.bossFight && this.playerPotions.Any(x => x.type == PotionType.WEAPON_BUFF)) { Potion buffPotion = this.playerPotions.Where(x => x.type == PotionType.WEAPON_BUFF).OrderBy(x => x.level).Last(x => x.type == PotionType.WEAPON_BUFF); this.webClient.DownloadStringAsync(new Uri(dungeonUrl + "&potion=" + buffPotion.invIndex)); COMPACT_LOGGER.Info("Using BUFF potion (in boss fight). Level:" + buffPotion.level + " InvIndex:" + buffPotion.invIndex); return; } // got more than one BUFF potion and the fight is starting? (last one is for the boss fight) if ((this.fightRound == 1) && !this.bossFight && this.playerPotions.Count(x => x.type == PotionType.WEAPON_BUFF) > 1) { Potion buffPotion = this.playerPotions.Where(x => x.type == PotionType.WEAPON_BUFF).OrderBy(x => x.level).First(x => x.type == PotionType.WEAPON_BUFF); this.webClient.DownloadStringAsync(new Uri(dungeonUrl + "&potion=" + buffPotion.invIndex)); COMPACT_LOGGER.Info("Using BUFF potion (in normal fight). Level:" + buffPotion.level + " InvIndex:" + buffPotion.invIndex); return; } // only got a shitty BUFF potion? if ((this.fightRound == 1) && !this.bossFight && this.playerPotions.Count(x => (x.type == PotionType.WEAPON_BUFF) && (x.level < 4)) > 0) { Potion buffPotion = this.playerPotions.Where(x => (x.type == PotionType.WEAPON_BUFF) && (x.level < 4)).OrderBy(x => x.level).First(x => x.type == PotionType.WEAPON_BUFF); this.webClient.DownloadStringAsync(new Uri(dungeonUrl + "&potion=" + buffPotion.invIndex)); COMPACT_LOGGER.Info("Using shitty BUFF potion (in normal fight). Level:" + buffPotion.level + " InvIndex:" + buffPotion.invIndex); return; } // got a SHIELD potion and the fight is starting? if ((this.fightRound == 1) && this.playerPotions.Any(x => x.type == PotionType.SHIELD)) { Potion shieldPotion = this.playerPotions.Where(x => x.type == PotionType.SHIELD).OrderBy(x => x.level).First(x => x.type == PotionType.SHIELD); this.webClient.DownloadStringAsync(new Uri(dungeonUrl + "&potion=" + shieldPotion.invIndex)); COMPACT_LOGGER.Info("Using SHIELD potion. Level:" + shieldPotion.level + " InvIndex:" + shieldPotion.invIndex); return; } // got a DAMAGE potion? if (this.playerPotions.Any(x => x.type == PotionType.DAMAGE)) { Potion damagePotion = this.playerPotions.Where(x => x.type == PotionType.DAMAGE).OrderBy(x => x.level).First(x => x.type == PotionType.DAMAGE); this.webClient.DownloadStringAsync(new Uri(dungeonUrl + "&potion=" + damagePotion.invIndex)); COMPACT_LOGGER.Info("Using DMG potion. Level:" + damagePotion.level + " InvIndex:" + damagePotion.invIndex); return; } // low HP in boss fight if (((float)this.playerHitPoints / this.playerMaxHp < 0.3f) && this.bossFight && this.playerPotions.Any(x => x.type == PotionType.HEALING)) { Potion healPotion = this.playerPotions.Where(x => x.type == PotionType.HEALING).OrderBy(x => x.level).Last(x => x.type == PotionType.HEALING); this.webClient.DownloadStringAsync(new Uri(dungeonUrl + "&potion=" + healPotion.invIndex)); COMPACT_LOGGER.Info("Using HEAL potion (in boss fight). Level:" + healPotion.level + " InvIndex:" + healPotion.invIndex); return; } // low HP, HEAL potion available & not close to boss if (((float)this.playerHitPoints / this.playerMaxHp < 0.3f) && !this.bossFight && (this.dungeonLevel < 23) && this.playerPotions.Any(x => x.type == PotionType.HEALING)) { Potion healPotion = this.playerPotions.Where(x => x.type == PotionType.HEALING).OrderBy(x => x.level).Last(x => x.type == PotionType.HEALING); this.webClient.DownloadStringAsync(new Uri(dungeonUrl + "&potion=" + healPotion.invIndex)); COMPACT_LOGGER.Info("Using HEAL potion (in upper levels). Level:" + healPotion.level + " InvIndex:" + healPotion.invIndex); return; } // low HP and many potions in normal fight if (((float)this.playerHitPoints / this.playerMaxHp < 0.3f) && !this.bossFight && this.playerPotions.Count(x => x.type == PotionType.HEALING) > 1) { Potion healPotion = this.playerPotions.Where(x => x.type == PotionType.HEALING).OrderBy(x => x.level).First(x => x.type == PotionType.HEALING); this.webClient.DownloadStringAsync(new Uri(dungeonUrl + "&potion=" + healPotion.invIndex)); COMPACT_LOGGER.Info("Using HEAL potion (because we got 1+). Level:" + healPotion.level + " InvIndex:" + healPotion.invIndex); return; } this.webClient.DownloadStringAsync(new Uri(dungeonUrl + "&attack=1")); COMPACT_LOGGER.Info("Attacking!"); return; } // loot?! if (this.looting) { if (this.lootPotion.level > -1) { if (this.playerPotions.Any(x => x.type == PotionType.NONE)) { this.webClient.DownloadStringAsync(new Uri(dungeonUrl + "&tres=1")); COMPACT_LOGGER.Info("Looting potion. Type:" + lootPotion.type + " Level:" + lootPotion.level); this.playerPotionsLooted++; this.lootPotion = new Potion(); return; } else { COMPACT_LOGGER.Info("Ignoring potion. Type:" + lootPotion.type + " Level:" + lootPotion.level); this.lootPotion = new Potion(); } } if (this.lootWeapon.level > -1) { if ((this.playerWeapon.level + this.playerWeapon.bonus < this.lootWeapon.level + this.lootWeapon.bonus)) { this.webClient.DownloadStringAsync(new Uri(dungeonUrl + "&tres=1")); COMPACT_LOGGER.Info("Looting weapon. OldLevel:" + this.playerWeapon.level + " OldBonus:" + this.playerWeapon.bonus + " NewLevel:" + this.lootWeapon.level + " NewBonus:" + this.lootWeapon.bonus); this.playerWeaponsLooted++; this.lootWeapon = new Weapon(); return; } else { COMPACT_LOGGER.Info("Ignoring weapon. OldLevel:" + this.playerWeapon.level + " OldBonus:" + this.playerWeapon.bonus + " NewLevel:" + this.lootWeapon.level + " NewBonus:" + this.lootWeapon.bonus); this.lootWeapon = new Weapon(); } } } // no plan & completed if ((this.plannedPath == string.Empty) && this.levelCompleted) { this.plannedPath = PlanPathToStairs(); COMPACT_LOGGER.Info("Done with this level. Heading for stairs: " + this.plannedPath); } // no plan .. not complete if ((this.plannedPath == string.Empty) && !this.levelCompleted) { this.plannedPath = defaultPaths[this.playerPosX + (3 * this.playerPosY)]; COMPACT_LOGGER.Info("New to this level. Making plan: " + this.plannedPath); } string nextStep = string.Empty; // still the plan is empty and the level is done? if ((this.plannedPath == string.Empty) && this.levelCompleted) { // need more levels? take random step away from stairs bool upperLevels = (this.dungeonLevel <= 17) && (this.playerLevel <= this.dungeonLevel + 2); bool middleLevels = (this.dungeonLevel <= 22) && (this.playerLevel <= this.dungeonLevel + 1); bool lowerLevels = (this.dungeonLevel <= 24) && (this.playerLevel <= this.dungeonLevel); bool stillNeedLevels = upperLevels || middleLevels || lowerLevels; if (stillNeedLevels) { switch (this.directions.First(x => x != DirectionType.DOWN)) { case DirectionType.EAST: nextStep = "e"; break; case DirectionType.NORTH: nextStep = "n"; break; case DirectionType.SOUTH: nextStep = "s"; break; case DirectionType.WEST: nextStep = "w"; break; } } else { nextStep = "d"; this.levelCompleted = false; this.stairPositionX = -1; this.stairPositionY = -1; COMPACT_LOGGER.Info("Been there, done that. Going downstairs."); } } // follow the path else { nextStep = this.plannedPath.Substring(0, 1); this.plannedPath = this.plannedPath.Substring(1, this.plannedPath.Length - 1); if (this.plannedPath == string.Empty) { this.levelCompleted = true; } COMPACT_LOGGER.Info("Taking another step to '" + nextStep + "'. That leaves '" + this.plannedPath + "' as future path." + (this.levelCompleted ? " This level is therefore done." : "")); } this.webClient.DownloadStringAsync(new Uri(dungeonUrl + "&m=" + nextStep)); }
private EventType ParseGameStatus(string webResponse) { RAW_LOGGER.Info(webResponse); if (Regex.IsMatch(webResponse, "you have died", RegexOptions.IgnoreCase)) { COMPACT_LOGGER.Warn("********************"); COMPACT_LOGGER.Warn("* You have died :/ *"); COMPACT_LOGGER.Warn("********************"); this.webClient.DownloadStringAsync(new Uri(dungeonUrl)); return(EventType.DEATH); } Match match = regexParseRoom.Match(webResponse); if (!match.Success) { COMPACT_LOGGER.Error("WARNING! Could not parse server response. Regex broken :/ Output was:" + Environment.NewLine + webResponse); return(EventType.REGEX_FAIL); } // dungeon level : 1 this.dungeonLevel = int.Parse(match.Groups[1].Value); // player level : 2 this.playerLevel = int.Parse(match.Groups[2].Value); // player hitpoints : 3 this.playerHitPoints = int.Parse(match.Groups[3].Value); this.playerMaxHp = Math.Max(this.playerHitPoints, this.playerMaxHp); // player xp : 4 this.playerExperience = int.Parse(match.Groups[4].Value); // weapon : 5 + 6 this.playerWeapon = ParseWeapon(match.Groups[5].Value, match.Groups[6].Value); // inventory (potions) : 7 - 12 for (int potionIndex = 0; potionIndex < 3; potionIndex++) { if (string.IsNullOrEmpty(match.Groups[7 + (2 * potionIndex)].Value)) { this.playerPotions[potionIndex] = new Potion(PotionType.NONE, 0, potionIndex); } else { this.playerPotions[potionIndex] = ParsePotion(match.Groups[7 + (2 * potionIndex)].Value, match.Groups[8 + (2 * potionIndex)].Value, potionIndex); } } // movement (empty room) : 13 - 17 for (int directionIndex = 0; directionIndex < 5; directionIndex++) { string directionString = match.Groups[13 + directionIndex].Value; // no further directions found if (string.IsNullOrEmpty(directionString)) { break; } // first direction found if (directionIndex == 0) { this.directions.Clear(); } this.directions.Add(ParseDirection(directionString)); } // "attack" (monster in room) : 18 if (!string.IsNullOrEmpty(match.Groups[18].Value)) { this.fightRound++; if (!webResponse.Contains("big monster", StringComparison.OrdinalIgnoreCase)) { COMPACT_LOGGER.Warn("***************"); COMPACT_LOGGER.Info("* BOSS FIGTH! *"); COMPACT_LOGGER.Warn("***************"); this.bossFight = true; } } else { this.fightRound = 0; } // "treasure" (monster defeated) : 19 if (!string.IsNullOrEmpty(match.Groups[19].Value)) { this.looting = true; // potion to loot (type + bonus) : 20 + 21 if (!string.IsNullOrEmpty(match.Groups[20].Value)) { this.lootPotion = ParsePotion(match.Groups[20].Value, match.Groups[21].Value, -1); this.playerPotionsFound.Add(this.lootPotion); } // weapon to loot (level + bonus) : 22 + 23 if (!string.IsNullOrEmpty(match.Groups[22].Value)) { this.lootWeapon = ParseWeapon(match.Groups[22].Value, match.Groups[23].Value); this.playerWeaponsFound.Add(this.lootWeapon); } } // movement after loot : 24 - 28 for (int directionIndex = 0; directionIndex < 5; directionIndex++) { string directionString = match.Groups[24 + directionIndex].Value; // no further directions found if (string.IsNullOrEmpty(directionString)) { break; } // first direction found if (directionIndex == 0) { this.directions.Clear(); } this.directions.Add(ParseDirection(directionString)); } // log COMPACT_LOGGER.Info("Dungeon:" + this.dungeonLevel + " Fight:" + this.fightRound + " Stairs:" + this.stairPositionX + ":" + this.stairPositionY + " Position:" + this.playerPosX + ":" + this.playerPosY); COMPACT_LOGGER.Info("Player:" + this.playerLevel + " Hitpoints:" + this.playerHitPoints + "/" + this.playerMaxHp + " XP:" + this.playerExperience + " Weapon:" + this.playerWeapon.level + "+" + this.playerWeapon.bonus); COMPACT_LOGGER.Info("Inventory:" + this.playerPotions[0].type + "+" + this.playerPotions[0].level + "," + this.playerPotions[1].type + "+" + this.playerPotions[1].level + "," + this.playerPotions[2].type + "+" + this.playerPotions[2].level); // stats if (webResponse.Contains("you killed the monster", StringComparison.OrdinalIgnoreCase)) { this.playerMonstersKilled++; } if (webResponse.Contains("you hit the monster", StringComparison.OrdinalIgnoreCase)) { this.playerAttacksHit++; } if (webResponse.Contains("you miss", StringComparison.OrdinalIgnoreCase)) { this.playerAttacksMissed++; } if (webResponse.Contains("the monster hits you", StringComparison.OrdinalIgnoreCase)) { this.monsterAttacksHit++; } if (webResponse.Contains("the monster misses", StringComparison.OrdinalIgnoreCase)) { this.monsterAttacksMissed++; } return(EventType.NORMAL); }