using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using D2DataNew; using Mapper; using Mapper.Pathing; using Mapper.Pathing.Heuristics; using Mapper.Pathing.Interfaces; using Mapper.Pathing.Processors; namespace PindleSkill.Bots { //This class inherit from BotBase, wich means it is like an "addon" to BotBase class Pindle : BotBase { BotConfig cfg;//holds the current configuration bool CheckLife = false;//tell the program if he need to do a life check or not, usefull when you enter game (you dont want to chicken in town) GameInfo.GameObject RedTP //will find the red portal { get { return base.currentGameInfo.FindGameObject(n => n.ObjectId == GameObjectClass.PermanentTownPortal); } } /// /// Creates a new instance of Pindle class /// /// public Pindle(BotConfig cfg) : base(cfg) { this.cfg = cfg; } /// /// The bot automatically call this method when it enter game. /// The run needs to be coded in there /// /// public override bool onGameEnter() { base.ReportProgress("Game Entered"); sleep(100); //Dont really bother with that.. I have the same thing twice but I need to convert it to use pathing functions correctly GameDifficulty diff = GameDifficulty.Nightmare; switch (base.cfg.Difficulty) { case DifficultyType.Normal: diff = GameDifficulty.Normal; break; case DifficultyType.Hell: diff = GameDifficulty.Hell; break; } //if life is lower than 900, or mana lower than 300; go talk to malah to heal if (currentGameInfo.Me.Life < 900 || currentGameInfo.Me.Mana < 300) { ReportProgress("We need to heal, going to malah. life=" + currentGameInfo.Me.Life + " mana=" + currentGameInfo.Me.Mana); Console.WriteLine(currentGameInfo.Me.Life + " mana=" + currentGameInfo.Me.Mana); //go to the npc if (!base.GoToHealingNPC(Act.Five, base.myBot.seed, diff, 300, 5, 10)) throw new GameFailedException("Failed to walk to malah"); //but we need to interact with it manually, so the malah from the list of NPCs GameInfo.NPC malah = base.currentGameInfo.FindMonster(n => n.Id == NPCClass.Malah); if (malah == null) throw new GameFailedException("Failed to find malah!"); //those methdos send packets to interact with malah base.SendGS(D2PacketsNew.GameClient.GoToTownFolk.Build(UnitType.NPC, malah.UID,(uint) malah.X, (uint)malah.Y)); sleep(100); base.SendGS(D2PacketsNew.GameClient.UnitInteract.Build(UnitType.NPC, malah.UID)); sleep(100); base.SendGS(D2PacketsNew.GameClient.TownFolkInteract.Build(UnitType.NPC, malah.UID)); } ReportProgress("Leaving town"); //here we walk to the red portal if (!base.GoToRedTP(Act.Five, base.myBot.seed, diff, 300, 5, 10)) { ReportProgress("Game failed: Failed to reach red TP"); throw new GameFailedException("Game failed: Failed to reach red TP"); } //if the portal is not detected, it means that we got stuck somewhere, so run failed //note that there is a TODO here wich is to retry pathing if (RedTP == null) { ReportProgress("Game failed: could not locate red TP"); throw new GameFailedException("Game failed: could not locate red TP"); } //enable life watch CheckLife = true; //send the packets to enter the red portal base.SendGS(D2PacketsNew.GameClient.RunToLocation.Build(RedTP.X, RedTP.Y)); base.sleep(100); base.SendGS(D2PacketsNew.GameClient.RunToTarget.Build(UnitType.GameObject, RedTP.UID)); base.sleep(100); base.SendGS(D2PacketsNew.GameClient.UnitInteract.Build(UnitType.GameObject, RedTP.UID)); //this is an ugly loop to check if we left town int startTime = Environment.TickCount; while (base.currentGameInfo.Me.Y < 10000) { if (Environment.TickCount - startTime > 3000) { ReportProgress("Game failed: Failed to leave town"); throw new GameFailedException("Game failed: Failed to leave town"); } } //we get a path to teleport close to pindle LevelMap map = Map.Instance.LoadLevelMap(base.myBot.seed,AreaLevel.NihlathaksTemple,diff); List path = new AStar(map,new DiagonalShortcut(), new TeleportReducer(40)).FindPath(currentGameInfo.Me.Position,new System.Drawing.Point(10062, 13240)); //we teleport that path if (!base.Teleport(path, 3000)) { ReportProgress("Game failed: Failed to teleport to pindle"); throw new GameFailedException("Game failed: Failed to teleport to pindle"); } sleep(500); //tricky way to get pindle... Unkown part len is greater than others.. (dont bother with this) //OBSOLETE GameInfo.NPC[] pindleAndMinions = currentGameInfo.FindMonsters(NPCClass.DefiledWarrior); GameInfo.NPC pindle = null; foreach(GameInfo.NPC npc in pindleAndMinions) { if (pindle == null) { pindle = npc; continue; } if (npc.Unknown.Length > pindle.Unknown.Length) pindle = npc; } //END OBSOLETE //Will kill pindle! if (!base.KillMonstersClosest(currentGameInfo.FindMonstersUIDs(NPCClass.DefiledWarrior) ,SkillType.Blizzard,SkillType.IceBlast,1500,10000)) { ReportProgress("Game failed: Failed to kill pindle"); throw new GameFailedException("Game failed: Failed to kill pindle"); } //Pick items and run is done! Pickit(); return true; } /// /// this gets called when the game is exited, it is there to let clean some variables if we need to /// public override void onRunDoneCleanUp() { CheckLife = false; } /// /// each packets you receive is passed to that method /// You can implement your own packet-specific actions here /// /// public override void OverrideReceivePacket(D2PacketsNew.GameServer.GSPacket packet) { switch (packet.PacketType) { case D2PacketsNew.D2Packets.GameServerPacket.LifeManaChange: if (CheckLife) { D2PacketsNew.GameServer.LifeManaChange lifeManaChange = new D2PacketsNew.GameServer.LifeManaChange(packet.Data); if (lifeManaChange.Life < 400) Chicken(); else if (lifeManaChange.Life < 1000) base.myBelt.DrinkPotion(ref base.myBot); } break; } } //will just leave game.. public void Chicken() { //invoke; //find a way to t hrow an exception on another thread base.SendGS(D2PacketsNew.GameClient.ExitGame.Build()); /*System.Threading.Thread thread; throw new GameFailedException("Chicken!");*/ } } }