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);
}
}
/// <summary>
/// Creates a new instance of Pindle class
/// </summary>
/// <param name="cfg"></param>
public Pindle(BotConfig cfg)
: base(cfg)
{
this.cfg = cfg;
}
/// <summary>
/// The bot automatically call this method when it enter game.
/// The run needs to be coded in there
/// </summary>
/// <returns></returns>
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<AStarNode> 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;
}
/// <summary>
/// this gets called when the game is exited, it is there to let clean some variables if we need to
/// </summary>
public override void onRunDoneCleanUp()
{
CheckLife = false;
}
/// <summary>
/// each packets you receive is passed to that method
/// You can implement your own packet-specific actions here
/// </summary>
/// <param name="packet"></param>
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!");*/
}
}
}