diff --git a/.vs/Ledybot/v14/.suo b/.vs/Ledybot/v14/.suo
new file mode 100644
index 0000000..83ea308
Binary files /dev/null and b/.vs/Ledybot/v14/.suo differ
diff --git a/Ledybot.sln b/Ledybot.sln
new file mode 100644
index 0000000..d613d3a
--- /dev/null
+++ b/Ledybot.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25123.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ledybot", "Ledybot\Ledybot.csproj", "{3A95B46E-CD57-4F68-AB2E-29ED7BF9F8A6}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {3A95B46E-CD57-4F68-AB2E-29ED7BF9F8A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3A95B46E-CD57-4F68-AB2E-29ED7BF9F8A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3A95B46E-CD57-4F68-AB2E-29ED7BF9F8A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3A95B46E-CD57-4F68-AB2E-29ED7BF9F8A6}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Ledybot/App.config b/Ledybot/App.config
new file mode 100644
index 0000000..88fa402
--- /dev/null
+++ b/Ledybot/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Ledybot/Form1.Designer.cs b/Ledybot/Form1.Designer.cs
new file mode 100644
index 0000000..1d5221a
--- /dev/null
+++ b/Ledybot/Form1.Designer.cs
@@ -0,0 +1,311 @@
+namespace Ledybot
+{
+ partial class MainForm
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.tb_IP = new System.Windows.Forms.TextBox();
+ this.tb_Port = new System.Windows.Forms.TextBox();
+ this.l_dummy = new System.Windows.Forms.Label();
+ this.tb_PID = new System.Windows.Forms.TextBox();
+ this.lb_dummy2 = new System.Windows.Forms.Label();
+ this.btn_Connect = new System.Windows.Forms.Button();
+ this.tb_PokemonToFind = new System.Windows.Forms.TextBox();
+ this.label1 = new System.Windows.Forms.Label();
+ this.label2 = new System.Windows.Forms.Label();
+ this.tb_GiveAway = new System.Windows.Forms.TextBox();
+ this.label3 = new System.Windows.Forms.Label();
+ this.tb_Level = new System.Windows.Forms.TextBox();
+ this.label4 = new System.Windows.Forms.Label();
+ this.tb_Default = new System.Windows.Forms.TextBox();
+ this.label5 = new System.Windows.Forms.Label();
+ this.tb_Folder = new System.Windows.Forms.TextBox();
+ this.btn_Start = new System.Windows.Forms.Button();
+ this.btn_Stop = new System.Windows.Forms.Button();
+ this.lv_log = new System.Windows.Forms.ListView();
+ this.Time = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this.Trainer = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this.Ditto = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this.Country = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this.SubCountry = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
+ this.SuspendLayout();
+ //
+ // tb_IP
+ //
+ this.tb_IP.Location = new System.Drawing.Point(13, 13);
+ this.tb_IP.Name = "tb_IP";
+ this.tb_IP.Size = new System.Drawing.Size(100, 20);
+ this.tb_IP.TabIndex = 0;
+ this.tb_IP.Text = "192.168.178.48";
+ //
+ // tb_Port
+ //
+ this.tb_Port.Location = new System.Drawing.Point(135, 12);
+ this.tb_Port.Name = "tb_Port";
+ this.tb_Port.Size = new System.Drawing.Size(34, 20);
+ this.tb_Port.TabIndex = 1;
+ this.tb_Port.Text = "8000";
+ //
+ // l_dummy
+ //
+ this.l_dummy.AutoSize = true;
+ this.l_dummy.Location = new System.Drawing.Point(119, 16);
+ this.l_dummy.Name = "l_dummy";
+ this.l_dummy.Size = new System.Drawing.Size(10, 13);
+ this.l_dummy.TabIndex = 2;
+ this.l_dummy.Text = ":";
+ //
+ // tb_PID
+ //
+ this.tb_PID.Location = new System.Drawing.Point(191, 12);
+ this.tb_PID.Name = "tb_PID";
+ this.tb_PID.Size = new System.Drawing.Size(19, 20);
+ this.tb_PID.TabIndex = 3;
+ this.tb_PID.Text = "2b";
+ //
+ // lb_dummy2
+ //
+ this.lb_dummy2.AutoSize = true;
+ this.lb_dummy2.Location = new System.Drawing.Point(175, 16);
+ this.lb_dummy2.Name = "lb_dummy2";
+ this.lb_dummy2.Size = new System.Drawing.Size(10, 13);
+ this.lb_dummy2.TabIndex = 4;
+ this.lb_dummy2.Text = "-";
+ //
+ // btn_Connect
+ //
+ this.btn_Connect.Location = new System.Drawing.Point(216, 9);
+ this.btn_Connect.Name = "btn_Connect";
+ this.btn_Connect.Size = new System.Drawing.Size(75, 23);
+ this.btn_Connect.TabIndex = 5;
+ this.btn_Connect.Text = "Connect";
+ this.btn_Connect.UseVisualStyleBackColor = true;
+ this.btn_Connect.Click += new System.EventHandler(this.btn_Connect_Click);
+ //
+ // tb_PokemonToFind
+ //
+ this.tb_PokemonToFind.Location = new System.Drawing.Point(13, 70);
+ this.tb_PokemonToFind.Name = "tb_PokemonToFind";
+ this.tb_PokemonToFind.Size = new System.Drawing.Size(100, 20);
+ this.tb_PokemonToFind.TabIndex = 6;
+ this.tb_PokemonToFind.Text = "Ledyba";
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(13, 51);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(106, 13);
+ this.label1.TabIndex = 7;
+ this.label1.Text = "Deposited Pokemon:";
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.Location = new System.Drawing.Point(12, 106);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(106, 13);
+ this.label2.TabIndex = 8;
+ this.label2.Text = "GiveAway Pokemon:";
+ //
+ // tb_GiveAway
+ //
+ this.tb_GiveAway.Location = new System.Drawing.Point(12, 122);
+ this.tb_GiveAway.Name = "tb_GiveAway";
+ this.tb_GiveAway.Size = new System.Drawing.Size(100, 20);
+ this.tb_GiveAway.TabIndex = 9;
+ this.tb_GiveAway.Text = "Ditto";
+ //
+ // label3
+ //
+ this.label3.AutoSize = true;
+ this.label3.Location = new System.Drawing.Point(125, 106);
+ this.label3.Name = "label3";
+ this.label3.Size = new System.Drawing.Size(36, 13);
+ this.label3.TabIndex = 10;
+ this.label3.Text = "Level:";
+ //
+ // tb_Level
+ //
+ this.tb_Level.Location = new System.Drawing.Point(128, 122);
+ this.tb_Level.Name = "tb_Level";
+ this.tb_Level.Size = new System.Drawing.Size(33, 20);
+ this.tb_Level.TabIndex = 11;
+ this.tb_Level.Text = "91";
+ //
+ // label4
+ //
+ this.label4.AutoSize = true;
+ this.label4.Location = new System.Drawing.Point(13, 159);
+ this.label4.Name = "label4";
+ this.label4.Size = new System.Drawing.Size(68, 13);
+ this.label4.TabIndex = 12;
+ this.label4.Text = "Default .pk7:";
+ //
+ // tb_Default
+ //
+ this.tb_Default.Location = new System.Drawing.Point(12, 176);
+ this.tb_Default.Name = "tb_Default";
+ this.tb_Default.Size = new System.Drawing.Size(354, 20);
+ this.tb_Default.TabIndex = 13;
+ this.tb_Default.Text = "C:/GiveAway/6IV.pk7";
+ //
+ // label5
+ //
+ this.label5.AutoSize = true;
+ this.label5.Location = new System.Drawing.Point(16, 203);
+ this.label5.Name = "label5";
+ this.label5.Size = new System.Drawing.Size(101, 13);
+ this.label5.TabIndex = 14;
+ this.label5.Text = "Specific .pk7 folder:";
+ //
+ // tb_Folder
+ //
+ this.tb_Folder.Location = new System.Drawing.Point(12, 219);
+ this.tb_Folder.Name = "tb_Folder";
+ this.tb_Folder.Size = new System.Drawing.Size(354, 20);
+ this.tb_Folder.TabIndex = 15;
+ this.tb_Folder.Text = "C:/GiveAway/";
+ //
+ // btn_Start
+ //
+ this.btn_Start.Location = new System.Drawing.Point(167, 120);
+ this.btn_Start.Name = "btn_Start";
+ this.btn_Start.Size = new System.Drawing.Size(58, 23);
+ this.btn_Start.TabIndex = 16;
+ this.btn_Start.Text = "Start";
+ this.btn_Start.UseVisualStyleBackColor = true;
+ this.btn_Start.Click += new System.EventHandler(this.btn_Start_Click);
+ //
+ // btn_Stop
+ //
+ this.btn_Stop.Location = new System.Drawing.Point(233, 120);
+ this.btn_Stop.Name = "btn_Stop";
+ this.btn_Stop.Size = new System.Drawing.Size(58, 23);
+ this.btn_Stop.TabIndex = 17;
+ this.btn_Stop.Text = "Stop";
+ this.btn_Stop.UseVisualStyleBackColor = true;
+ this.btn_Stop.Click += new System.EventHandler(this.btn_Stop_Click);
+ //
+ // lv_log
+ //
+ this.lv_log.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
+ this.Time,
+ this.Trainer,
+ this.Ditto,
+ this.Country,
+ this.SubCountry});
+ this.lv_log.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable;
+ this.lv_log.Location = new System.Drawing.Point(13, 246);
+ this.lv_log.Name = "lv_log";
+ this.lv_log.Size = new System.Drawing.Size(353, 262);
+ this.lv_log.TabIndex = 18;
+ this.lv_log.UseCompatibleStateImageBehavior = false;
+ this.lv_log.View = System.Windows.Forms.View.Details;
+ //
+ // Time
+ //
+ this.Time.Text = "Time";
+ this.Time.Width = 40;
+ //
+ // Trainer
+ //
+ this.Trainer.Text = "Trainer";
+ //
+ // Ditto
+ //
+ this.Ditto.Text = "Ditto";
+ this.Ditto.Width = 50;
+ //
+ // Country
+ //
+ this.Country.Text = "Country";
+ //
+ // SubCountry
+ //
+ this.SubCountry.Text = "SubCountry";
+ //
+ // MainForm
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(378, 520);
+ this.Controls.Add(this.lv_log);
+ this.Controls.Add(this.btn_Stop);
+ this.Controls.Add(this.btn_Start);
+ this.Controls.Add(this.tb_Folder);
+ this.Controls.Add(this.label5);
+ this.Controls.Add(this.tb_Default);
+ this.Controls.Add(this.label4);
+ this.Controls.Add(this.tb_Level);
+ this.Controls.Add(this.label3);
+ this.Controls.Add(this.tb_GiveAway);
+ this.Controls.Add(this.label2);
+ this.Controls.Add(this.label1);
+ this.Controls.Add(this.tb_PokemonToFind);
+ this.Controls.Add(this.btn_Connect);
+ this.Controls.Add(this.lb_dummy2);
+ this.Controls.Add(this.tb_PID);
+ this.Controls.Add(this.l_dummy);
+ this.Controls.Add(this.tb_Port);
+ this.Controls.Add(this.tb_IP);
+ this.Name = "MainForm";
+ this.Text = "Ledybot v1.0";
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.TextBox tb_IP;
+ private System.Windows.Forms.TextBox tb_Port;
+ private System.Windows.Forms.Label l_dummy;
+ private System.Windows.Forms.TextBox tb_PID;
+ private System.Windows.Forms.Label lb_dummy2;
+ private System.Windows.Forms.Button btn_Connect;
+ private System.Windows.Forms.TextBox tb_PokemonToFind;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.TextBox tb_GiveAway;
+ private System.Windows.Forms.Label label3;
+ private System.Windows.Forms.TextBox tb_Level;
+ private System.Windows.Forms.Label label4;
+ private System.Windows.Forms.TextBox tb_Default;
+ private System.Windows.Forms.Label label5;
+ private System.Windows.Forms.TextBox tb_Folder;
+ private System.Windows.Forms.Button btn_Start;
+ private System.Windows.Forms.Button btn_Stop;
+ private System.Windows.Forms.ListView lv_log;
+ private System.Windows.Forms.ColumnHeader Time;
+ private System.Windows.Forms.ColumnHeader Trainer;
+ private System.Windows.Forms.ColumnHeader Ditto;
+ private System.Windows.Forms.ColumnHeader Country;
+ private System.Windows.Forms.ColumnHeader SubCountry;
+ }
+}
+
diff --git a/Ledybot/Form1.cs b/Ledybot/Form1.cs
new file mode 100644
index 0000000..4040ab8
--- /dev/null
+++ b/Ledybot/Form1.cs
@@ -0,0 +1,74 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace Ledybot
+{
+ public partial class MainForm : Form
+ {
+ public MainForm()
+ {
+ InitializeComponent();
+ }
+
+ private void btn_Connect_Click(object sender, EventArgs e)
+ {
+ string szIp = tb_IP.Text;
+ string szPort = tb_Port.Text;
+
+ int iPort = Convert.ToInt32(szPort);
+
+ if (!Program.Connected)
+ {
+ Program.Connected = Program.scriptHelper.connect(szIp, iPort);
+ }
+ }
+
+ Thread workerThread = null;
+ Worker workerObject = null;
+
+ private void btn_Start_Click(object sender, EventArgs e)
+ {
+ if (workerThread == null && workerObject == null)
+ {
+ workerObject = new Worker();
+ workerObject.setValues(tb_PokemonToFind.Text, tb_GiveAway.Text, tb_Default.Text, tb_Folder.Text, tb_Level.Text, tb_PID.Text);
+ workerThread = new Thread(workerObject.DoWork);
+ workerThread.Start();
+ }
+ }
+
+ public void AppendListViewItem(string szTrainerName, string szNickname, string szCountry, string szSubCountry)
+ {
+ if (InvokeRequired)
+ {
+ this.Invoke(new Action(AppendListViewItem), new object[] { szTrainerName, szNickname, szCountry, szSubCountry });
+ return;
+ }
+ string[] row = { DateTime.Now.ToString("h:mm:ss"), szTrainerName, szNickname, szCountry, szSubCountry };
+ var listViewItem = new ListViewItem(row);
+
+ lv_log.Items.Add(listViewItem);
+ lv_log.Items[lv_log.Items.Count - 1].EnsureVisible();
+ }
+
+ private void btn_Stop_Click(object sender, EventArgs e)
+ {
+ if(workerThread != null && workerObject != null)
+ {
+ workerObject.RequestStop();
+ workerThread.Join();
+
+ workerObject = null;
+ workerThread = null;
+ }
+ }
+ }
+}
diff --git a/Ledybot/Ledybot.csproj b/Ledybot/Ledybot.csproj
new file mode 100644
index 0000000..aa07698
--- /dev/null
+++ b/Ledybot/Ledybot.csproj
@@ -0,0 +1,91 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {3A95B46E-CD57-4F68-AB2E-29ED7BF9F8A6}
+ WinExe
+ Properties
+ Ledybot
+ Ledybot
+ v4.5.2
+ 512
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Form
+
+
+ Form1.cs
+
+
+
+
+
+
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+ Designer
+
+
+ True
+ Resources.resx
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+ True
+ Settings.settings
+ True
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Ledybot/NTRClient.cs b/Ledybot/NTRClient.cs
new file mode 100644
index 0000000..a565f04
--- /dev/null
+++ b/Ledybot/NTRClient.cs
@@ -0,0 +1,325 @@
+using System;
+using System.IO;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading;
+using System.Windows.Forms;
+
+namespace Ledybot
+{
+ public class NTRClient
+ {
+ public String host;
+ public int port;
+ public TcpClient tcp;
+ public NetworkStream netStream;
+ public Thread packetRecvThread;
+ UInt32 lastReadMemSeq;
+ string lastReadMemFileName;
+ private object syncLock = new object();
+ public object retValLock = new object();
+ int heartbeatSendable;
+ int timeout;
+ public delegate void logHandler(string msg);
+ UInt32 currentSeq;
+ public volatile int progress = -1;
+
+ public string retVal;
+ public bool retDone;
+
+
+ int readNetworkStream(NetworkStream stream, byte[] buf, int length)
+ {
+ int index = 0;
+ bool useProgress = false;
+
+ if (length > 100000)
+ {
+ useProgress = true;
+ }
+ do
+ {
+ if (useProgress)
+ {
+ progress = (int)(((double)(index) / length) * 100);
+ }
+ int len = stream.Read(buf, index, length - index);
+ if (len == 0)
+ {
+ return 0;
+ }
+ index += len;
+ } while (index < length);
+ progress = -1;
+ return length;
+ }
+
+ void packetRecvThreadStart()
+ {
+ byte[] buf = new byte[84];
+ UInt32[] args = new UInt32[16];
+ int ret;
+ NetworkStream stream = netStream;
+
+ while (true)
+ {
+ try
+ {
+ ret = readNetworkStream(stream, buf, buf.Length);
+ if (ret == 0)
+ {
+ break;
+ }
+ int t = 0;
+ UInt32 magic = BitConverter.ToUInt32(buf, t);
+ t += 4;
+ UInt32 seq = BitConverter.ToUInt32(buf, t);
+ t += 4;
+ UInt32 type = BitConverter.ToUInt32(buf, t);
+ t += 4;
+ UInt32 cmd = BitConverter.ToUInt32(buf, t);
+ for (int i = 0; i < args.Length; i++)
+ {
+ t += 4;
+ args[i] = BitConverter.ToUInt32(buf, t);
+ }
+ t += 4;
+ UInt32 dataLen = BitConverter.ToUInt32(buf, t);
+
+ if (magic != 0x12345678)
+ {
+ break;
+ }
+
+ if (cmd == 0)
+ {
+ if (dataLen != 0)
+ {
+ byte[] dataBuf = new byte[dataLen];
+ readNetworkStream(stream, dataBuf, dataBuf.Length);
+ string logMsg = Encoding.UTF8.GetString(dataBuf);
+ //Console.WriteLine(logMsg);
+ }
+ lock (syncLock)
+ {
+ heartbeatSendable = 1;
+ }
+ continue;
+ }
+ if (dataLen != 0)
+ {
+ byte[] dataBuf = new byte[dataLen];
+ readNetworkStream(stream, dataBuf, dataBuf.Length);
+ handlePacket(cmd, seq, dataBuf);
+ }
+ }
+ catch
+ {
+ break;
+ }
+ }
+ disconnect(false);
+ }
+
+ void handlePacket(UInt32 cmd, UInt32 seq, byte[] dataBuf)
+ {
+ if (cmd == 9)
+ {
+ handleReadMem(seq, dataBuf);
+ }
+ }
+
+ void handleReadMem(UInt32 seq, byte[] dataBuf)
+ {
+ if (seq != lastReadMemSeq)
+ {
+ //log("seq != lastReadMemSeq, ignored");
+ return;
+ }
+ lastReadMemSeq = 0;
+ string fileName = lastReadMemFileName;
+ if (fileName != null)
+ {
+ FileStream fs = new FileStream(fileName, FileMode.Create);
+ fs.Write(dataBuf, 0, dataBuf.Length);
+ fs.Close();
+ //log("dump saved into " + fileName + " successfully");
+
+ int i = 0;
+ string szResult = "";
+ for (i = 0; i < dataBuf.Length; i++)
+ {
+ if (i % 2 == 0)
+ {
+ if (dataBuf[i] == 0x00)
+ {
+ break;
+ }
+ else
+ {
+ //this is what it looks like when you have no clue about unicode:
+ szResult = szResult + (char)dataBuf[i];
+ }
+ }
+ }
+
+ //string szResult = Encoding.Unicode.GetString(dataBuf);
+
+ //t.BeginInvoke((MethodInvoker)delegate () { t.Text = szResult; ; });
+ lock (retValLock)
+ {
+ retVal = szResult;
+ retDone = true;
+ }
+ return;
+ }
+ //log(byteToHex(dataBuf, 0));
+
+ }
+
+ public void sendReadMemPacket(UInt32 addr, UInt32 size, UInt32 pid, string fileName)
+ {
+ sendEmptyPacket(9, pid, addr, size);
+ lastReadMemSeq = currentSeq;
+ lastReadMemFileName = fileName;
+ }
+
+ public void sendEmptyPacket(UInt32 cmd, UInt32 arg0 = 0, UInt32 arg1 = 0, UInt32 arg2 = 0, UInt32 arg3 = 0, UInt32 arg4 = 0)
+ {
+ UInt32[] args = new UInt32[16];
+
+ args[0] = arg0;
+ args[1] = arg1;
+ args[2] = arg2;
+ args[3] = arg3;
+ args[4] = arg4;
+ sendPacket(0, cmd, args, 0);
+ }
+
+ public void setServer(String serverHost, int serverPort)
+ {
+ host = serverHost;
+ port = serverPort;
+ }
+
+ public Boolean connectToServer()
+ {
+ if (tcp != null)
+ {
+ disconnect();
+ }
+ tcp = new TcpClient();
+ tcp.NoDelay = true;
+ try
+ {
+ if (tcp.ConnectAsync(host, port).Wait(1000))
+ {
+ currentSeq = 0;
+ netStream = tcp.GetStream();
+ heartbeatSendable = 1;
+ packetRecvThread = new Thread(new ThreadStart(packetRecvThreadStart));
+ packetRecvThread.Start();
+ Program.Connected = true;
+ }
+ else
+ {
+ Program.Connected = false;
+ }
+ }
+ catch
+ {
+ Program.Connected = false;
+ }
+
+ return Program.Connected;
+ }
+
+ public void disconnect(bool waitPacketThread = true)
+ {
+ try
+ {
+ if (tcp != null)
+ {
+ tcp.Close();
+ }
+ if (waitPacketThread)
+ {
+ if (packetRecvThread != null)
+ {
+ packetRecvThread.Join();
+ }
+ }
+ }
+ catch { }
+ tcp = null;
+ Program.Connected = false;
+ }
+
+ public void sendPacket(UInt32 type, UInt32 cmd, UInt32[] args, UInt32 dataLen)
+ {
+ int t = 0;
+ currentSeq += 1000;
+ byte[] buf = new byte[84];
+ BitConverter.GetBytes(0x12345678).CopyTo(buf, t);
+ t += 4;
+ BitConverter.GetBytes(currentSeq).CopyTo(buf, t);
+ t += 4;
+ BitConverter.GetBytes(type).CopyTo(buf, t);
+ t += 4;
+ BitConverter.GetBytes(cmd).CopyTo(buf, t);
+ for (int i = 0; i < 16; i++)
+ {
+ t += 4;
+ UInt32 arg = 0;
+ if (args != null)
+ {
+ arg = args[i];
+ }
+ BitConverter.GetBytes(arg).CopyTo(buf, t);
+ }
+ t += 4;
+ BitConverter.GetBytes(dataLen).CopyTo(buf, t);
+ try
+ {
+ netStream.Write(buf, 0, buf.Length);
+ }
+ catch (Exception)
+ {
+ }
+ }
+
+ public void sendWriteMemPacket(UInt32 addr, UInt32 pid, byte[] buf)
+ {
+ UInt32[] args = new UInt32[16];
+ args[0] = pid;
+ args[1] = addr;
+ args[2] = (UInt32)buf.Length;
+ sendPacket(1, 10, args, args[2]);
+ netStream.Write(buf, 0, buf.Length);
+ }
+
+ public void sendHeartbeatPacket()
+ {
+ if (Program.Connected)
+ {
+ lock (syncLock)
+ {
+ if (heartbeatSendable == 1)
+ {
+ heartbeatSendable = 0;
+ sendPacket(0, 0, null, 0);
+ }
+ else
+ {
+ timeout++;
+ if (timeout == 5)
+ {
+ disconnect(false);
+ }
+ }
+ }
+ }
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/Ledybot/PKHeX.cs b/Ledybot/PKHeX.cs
new file mode 100644
index 0000000..0ebd663
--- /dev/null
+++ b/Ledybot/PKHeX.cs
@@ -0,0 +1,145 @@
+
+/// I do not own the code in this class.
+/// All rights and credits for the code in this class belong to Kaphotics.
+/// All code within this class is taken from PKHeX https://github.com/kwsch/PKHeX
+
+
+using System;
+using System.Linq;
+using System.Text;
+
+namespace Ledybot
+{
+ public class PKHeX
+ {
+
+ public static uint LCRNG(uint seed)
+ {
+ const uint a = 0x41C64E6D;
+ const uint c = 0x00006073;
+
+ return seed * a + c;
+ }
+
+ public static uint LCRNG(ref uint seed)
+ {
+ const uint a = 0x41C64E6D;
+ const uint c = 0x00006073;
+
+ return seed = seed * a + c;
+ }
+
+ public static readonly byte[][] blockPosition =
+{
+ new byte[] {0, 0, 0, 0, 0, 0, 1, 1, 2, 3, 2, 3, 1, 1, 2, 3, 2, 3, 1, 1, 2, 3, 2, 3},
+ new byte[] {1, 1, 2, 3, 2, 3, 0, 0, 0, 0, 0, 0, 2, 3, 1, 1, 3, 2, 2, 3, 1, 1, 3, 2},
+ new byte[] {2, 3, 1, 1, 3, 2, 2, 3, 1, 1, 3, 2, 0, 0, 0, 0, 0, 0, 3, 2, 3, 2, 1, 1},
+ new byte[] {3, 2, 3, 2, 1, 1, 3, 2, 3, 2, 1, 1, 3, 2, 3, 2, 1, 1, 0, 0, 0, 0, 0, 0},
+ };
+
+ public static readonly byte[] blockPositionInvert =
+ {
+ 0, 1, 2, 4, 3, 5, 6, 7, 12, 18, 13, 19, 8, 10, 14, 20, 16, 22, 9, 11, 15, 21, 17, 23
+ };
+
+ public static byte[] shuffleArray(byte[] data, uint sv)
+ {
+ byte[] sdata = new byte[data.Length];
+ Array.Copy(data, sdata, 8); // Copy unshuffled bytes
+
+ // Shuffle Away!
+ for (int block = 0; block < 4; block++)
+ Array.Copy(data, 8 + 56 * blockPosition[block][sv], sdata, 8 + 56 * block, 56);
+
+ // Fill the Battle Stats back
+ if (data.Length > 232)
+ Array.Copy(data, 232, sdata, 232, 28);
+
+ return sdata;
+ }
+
+ public static byte[] decryptArray(byte[] ekx)
+ {
+ byte[] pkx = (byte[])ekx.Clone();
+
+ uint pv = BitConverter.ToUInt32(pkx, 0);
+ uint sv = (pv >> 0xD & 0x1F) % 24;
+
+ uint seed = pv;
+
+ // Decrypt Blocks with RNG Seed
+ for (int i = 8; i < 232; i += 2)
+ BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(pkx, i) ^ LCRNG(ref seed) >> 16)).CopyTo(pkx, i);
+
+ // Deshuffle
+ pkx = shuffleArray(pkx, sv);
+
+ // Decrypt the Party Stats
+ seed = pv;
+ if (pkx.Length <= 232) return pkx;
+ for (int i = 232; i < 260; i += 2)
+ BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(pkx, i) ^ LCRNG(ref seed) >> 16)).CopyTo(pkx, i);
+
+ return pkx;
+ }
+ public static byte[] encryptArray(byte[] pkx)
+ {
+ // Shuffle
+ uint pv = BitConverter.ToUInt32(pkx, 0);
+ uint sv = (pv >> 0xD & 0x1F) % 24;
+
+ byte[] ekx = (byte[])pkx.Clone();
+
+ ekx = shuffleArray(ekx, blockPositionInvert[sv]);
+
+ uint seed = pv;
+
+ // Encrypt Blocks with RNG Seed
+ for (int i = 8; i < 232; i += 2)
+ BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(ekx, i) ^ LCRNG(ref seed) >> 16)).CopyTo(ekx, i);
+
+ // If no party stats, return.
+ if (ekx.Length <= 232) return ekx;
+
+ // Encrypt the Party Stats
+ seed = pv;
+ for (int i = 232; i < 260; i += 2)
+ BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(ekx, i) ^ LCRNG(ref seed) >> 16)).CopyTo(ekx, i);
+
+ // Done
+ return ekx;
+ }
+
+ public static ushort getCHK(byte[] data)
+ {
+ ushort chk = 0;
+ for (int i = 8; i < 232; i += 2) // Loop through the entire PKX
+ chk += BitConverter.ToUInt16(data, i);
+
+ return chk;
+ }
+
+ public static readonly int[,] hpivs =
+ {
+ { 1, 1, 0, 0, 0, 0 }, // Fighting
+ { 0, 0, 0, 0, 0, 1 }, // Flying
+ { 1, 1, 0, 0, 0, 1 }, // Poison
+ { 1, 1, 1, 0, 0, 1 }, // Ground
+ { 1, 1, 0, 1, 0, 0 }, // Rock
+ { 1, 0, 0, 1, 0, 1 }, // Bug
+ { 1, 0, 1, 1, 0, 1 }, // Ghost
+ { 1, 1, 1, 1, 0, 1 }, // Steel
+ { 1, 0, 1, 0, 1, 0 }, // Fire
+ { 1, 0, 0, 0, 1, 1 }, // Water
+ { 1, 0, 1, 0, 1, 1 }, // Grass
+ { 1, 1, 1, 0, 1, 1 }, // Electric
+ { 1, 0, 1, 1, 1, 0 }, // Psychic
+ { 1, 0, 0, 1, 1, 1 }, // Ice
+ { 1, 0, 1, 1, 1, 1 }, // Dragon
+ { 1, 1, 1, 1, 1, 1 }, // Dark
+ };
+
+ public byte[] Data { get; set; }
+
+ }
+}
\ No newline at end of file
diff --git a/Ledybot/Program.cs b/Ledybot/Program.cs
new file mode 100644
index 0000000..6afc13e
--- /dev/null
+++ b/Ledybot/Program.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace Ledybot
+{
+ static class Program
+ {
+ public volatile static NTRClient ntrClient;
+ public volatile static ScriptHelper scriptHelper;
+ public static Boolean Connected = false;
+ public volatile static MainForm f1;
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ static void Main()
+ {
+ ntrClient = new NTRClient();
+ scriptHelper = new ScriptHelper();
+ Application.EnableVisualStyles();
+ Application.SetCompatibleTextRenderingDefault(false);
+ f1 = new MainForm();
+ Application.Run(f1);
+ }
+ }
+}
diff --git a/Ledybot/Properties/AssemblyInfo.cs b/Ledybot/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..2b17ae8
--- /dev/null
+++ b/Ledybot/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Ledybot")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Ledybot")]
+[assembly: AssemblyCopyright("Copyright © 2016")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("3a95b46e-cd57-4f68-ab2e-29ed7bf9f8a6")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/Ledybot/Properties/Resources.Designer.cs b/Ledybot/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..063c9d3
--- /dev/null
+++ b/Ledybot/Properties/Resources.Designer.cs
@@ -0,0 +1,71 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Ledybot.Properties
+{
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources
+ {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources()
+ {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager
+ {
+ get
+ {
+ if ((resourceMan == null))
+ {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Ledybot.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture
+ {
+ get
+ {
+ return resourceCulture;
+ }
+ set
+ {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/Ledybot/Properties/Resources.resx b/Ledybot/Properties/Resources.resx
new file mode 100644
index 0000000..af7dbeb
--- /dev/null
+++ b/Ledybot/Properties/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Ledybot/Properties/Settings.Designer.cs b/Ledybot/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..4881098
--- /dev/null
+++ b/Ledybot/Properties/Settings.Designer.cs
@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Ledybot.Properties
+{
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
+ {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default
+ {
+ get
+ {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/Ledybot/Properties/Settings.settings b/Ledybot/Properties/Settings.settings
new file mode 100644
index 0000000..3964565
--- /dev/null
+++ b/Ledybot/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/Ledybot/ScriptHelper.cs b/Ledybot/ScriptHelper.cs
new file mode 100644
index 0000000..489c6c1
--- /dev/null
+++ b/Ledybot/ScriptHelper.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Threading;
+
+namespace Ledybot
+{
+ public class ScriptHelper
+ {
+ public uint left = 0xFDF;
+ public uint right = 0xFEF;
+ public uint up = 0xFBF;
+ public uint down = 0xF7F;
+ public uint start = 0xFF7;
+ public uint Abtn = 0xFFE;
+ public uint Bbtn = 0xFFD;
+
+ public uint searchBtn = 0x01B618E0;
+
+ public Boolean connect(string host, int port)
+ {
+ Program.ntrClient.setServer(host, port);
+ return Program.ntrClient.connectToServer();
+ }
+
+ public void disconnect()
+ {
+ Program.ntrClient.disconnect();
+ }
+
+ public void write(uint addr, byte[] buf, int pid = -1)
+ {
+ Program.ntrClient.sendWriteMemPacket(addr, (uint)pid, buf);
+ }
+
+ public void press(uint buttons)
+ {
+ byte[] data = new byte[12];
+ uint oldbuttons = buttons;
+ uint oldtouch = 0x2000000;
+ uint oldcpad = 0x800800;
+ data[0x00] = (byte)(oldbuttons & 0xFF);
+ data[0x01] = (byte)((oldbuttons >> 0x08) & 0xFF);
+ data[0x02] = (byte)((oldbuttons >> 0x10) & 0xFF);
+ data[0x03] = (byte)((oldbuttons >> 0x18) & 0xFF);
+
+ //Touch
+ data[0x04] = (byte)(oldtouch & 0xFF);
+ data[0x05] = (byte)((oldtouch >> 0x08) & 0xFF);
+ data[0x06] = (byte)((oldtouch >> 0x10) & 0xFF);
+ data[0x07] = (byte)((oldtouch >> 0x18) & 0xFF);
+
+ //CPad
+ data[0x08] = (byte)(oldcpad & 0xFF);
+ data[0x09] = (byte)((oldcpad >> 0x08) & 0xFF);
+ data[0x0A] = (byte)((oldcpad >> 0x10) & 0xFF);
+ data[0x0B] = (byte)((oldcpad >> 0x18) & 0xFF);
+
+ Program.scriptHelper.write(0x10DF20, data, 0x10);
+ Thread.Sleep(150);
+ oldbuttons = 0xFFF;
+ data[0x00] = (byte)(oldbuttons & 0xFF);
+ data[0x01] = (byte)((oldbuttons >> 0x08) & 0xFF);
+ data[0x02] = (byte)((oldbuttons >> 0x10) & 0xFF);
+ data[0x03] = (byte)((oldbuttons >> 0x18) & 0xFF);
+
+ this.write(0x10DF20, data, 0x10);
+ }
+
+ public void touch(uint touch)
+ {
+ byte[] data = new byte[12];
+ uint oldbuttons = 0xFFF;
+ uint oldtouch = touch;
+ uint oldcpad = 0x800800;
+ data[0x00] = (byte)(oldbuttons & 0xFF);
+ data[0x01] = (byte)((oldbuttons >> 0x08) & 0xFF);
+ data[0x02] = (byte)((oldbuttons >> 0x10) & 0xFF);
+ data[0x03] = (byte)((oldbuttons >> 0x18) & 0xFF);
+
+ //Touch
+ data[0x04] = (byte)(oldtouch & 0xFF);
+ data[0x05] = (byte)((oldtouch >> 0x08) & 0xFF);
+ data[0x06] = (byte)((oldtouch >> 0x10) & 0xFF);
+ data[0x07] = (byte)((oldtouch >> 0x18) & 0xFF);
+
+ //CPad
+ data[0x08] = (byte)(oldcpad & 0xFF);
+ data[0x09] = (byte)((oldcpad >> 0x08) & 0xFF);
+ data[0x0A] = (byte)((oldcpad >> 0x10) & 0xFF);
+ data[0x0B] = (byte)((oldcpad >> 0x18) & 0xFF);
+
+ Program.scriptHelper.write(0x10DF20, data, 0x10);
+ Thread.Sleep(150);
+ oldtouch = 0x2000000;
+ data[0x04] = (byte)(oldtouch & 0xFF);
+ data[0x05] = (byte)((oldtouch >> 0x08) & 0xFF);
+ data[0x06] = (byte)((oldtouch >> 0x10) & 0xFF);
+ data[0x07] = (byte)((oldtouch >> 0x18) & 0xFF);
+
+ Program.scriptHelper.write(0x10DF20, data, 0x10);
+
+ }
+
+ public string readSafe(UInt32 addr, UInt32 byteCount, int pid)
+ {
+ lock (Program.ntrClient.retValLock)
+ {
+ Program.ntrClient.retDone = false;
+ }
+ bool waiting = true;
+ Program.ntrClient.sendReadMemPacket(addr, byteCount, (uint)pid, "C:/temp.txt");
+ string szReturn = "";
+ while (waiting)
+ {
+ Thread.Sleep(100);
+ lock (Program.ntrClient.retValLock)
+ {
+ if (Program.ntrClient.retDone)
+ {
+ waiting = false;
+ szReturn = Program.ntrClient.retVal;
+ }
+ }
+ }
+ return szReturn;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Ledybot/Worker.cs b/Ledybot/Worker.cs
new file mode 100644
index 0000000..45f5c54
--- /dev/null
+++ b/Ledybot/Worker.cs
@@ -0,0 +1,163 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace Ledybot
+{
+ public class Worker
+ {
+
+ private volatile string szPokemonToFind = "";
+ private volatile string szPokemonToGive = "";
+ private volatile string szDefaultPk7 = "";
+ private volatile string szPk7Folder = "";
+ private volatile string szLevel = "";
+ private volatile string szPID = "";
+ private volatile int iPID = 0;
+ private volatile bool _shouldStop = false;
+ public void DoWork()
+ {
+ bool bPokemonFound = false;
+ ScriptHelper h = Program.scriptHelper;
+
+ while (!_shouldStop)
+ {
+ Thread.Sleep(2000);
+ bool bSent = false;
+ if (!bPokemonFound)
+ {
+ h.press(h.Abtn);
+ Thread.Sleep(1000);
+ h.press(h.Abtn);
+ Thread.Sleep(1000);
+ h.press(h.up);
+ Thread.Sleep(1000);
+ //What Pokemon?
+ h.press(h.Abtn);
+ //black screen
+ Thread.Sleep(3000);
+
+ //"type" the name of the pokemon we want to find
+ byte[] name = new byte[this.szPokemonToFind.Length * 2];
+ for (int i = 0; i < szPokemonToFind.Length; i++)
+ {
+ name[i * 2] = (byte)szPokemonToFind[i];
+ name[i * 2 + 1] = 0x00;
+ }
+ //I like this solution so much
+ Program.scriptHelper.write(0x301118D4, name, iPID);
+ Thread.Sleep(1000);
+ h.press(h.start);
+ Thread.Sleep(1000);
+ h.press(h.Abtn);
+ //black screen
+ Thread.Sleep(4000);
+ bPokemonFound = true;
+ }
+ else
+ {
+ h.press(h.Abtn);
+ Thread.Sleep(2000);
+ }
+
+ h.touch(h.searchBtn);
+ //finding pokemon
+ Thread.Sleep(4000);
+
+ for(int i = 0; i < 25; i++)
+ {
+ string szReqPokemon = h.readSafe(0x30784ef4, 20, iPID);
+ if(szReqPokemon == this.szPokemonToGive)
+ {
+ string szLevel = h.readSafe(0x307879B4, 6, iPID);
+ szLevel = szLevel.ToLower();
+ if (szLevel.Contains(this.szLevel) || szLevel.Contains("any"))
+ {
+ string szNickname = h.readSafe(0x3077c514, 20, iPID);
+
+ string szPath = this.szDefaultPk7;
+ string szFileToFind = this.szPk7Folder + szNickname + ".pk7";
+ if (File.Exists(szFileToFind))
+ {
+ szPath = szFileToFind;
+ }
+
+ byte[] pkmEncrypted = System.IO.File.ReadAllBytes(szPath);
+ byte[] cloneshort = PKHeX.encryptArray(pkmEncrypted.Take(232).ToArray());
+ string ek7 = BitConverter.ToString(cloneshort).Replace("-", ", 0x");
+
+ //optional: grab some trainer data
+ string szTrainerName = h.readSafe(0x305F1864, 20, iPID);
+ string szCountry = h.readSafe(0x305F2A14, 20, iPID);
+ string szSubCountry = h.readSafe(0x305F76A4, 20, iPID);
+
+ Program.f1.AppendListViewItem(szTrainerName, szNickname, szCountry, szSubCountry);
+ //Inject the Pokemon to box1slot1
+ Program.scriptHelper.write(0x330d9838, cloneshort, iPID);
+ Thread.Sleep(1000);
+ h.press(h.Abtn);
+ Thread.Sleep(3000);
+ h.press(h.Abtn);
+ Thread.Sleep(1000);
+ h.press(h.Abtn);
+ Thread.Sleep(1000);
+ h.press(h.Abtn);
+ //trade starts here
+ Thread.Sleep(10000);
+ //if the pokemon has been traded we have 35 seconds to get back to the starting spot for the bot by spamming b a bit
+ h.press(h.Abtn);
+ Thread.Sleep(1000);
+ h.press(h.Bbtn);
+ Thread.Sleep(1000);
+ h.press(h.Bbtn);
+ Thread.Sleep(1000);
+ h.press(h.Bbtn);
+ Thread.Sleep(1000);
+ h.press(h.Bbtn);
+ Thread.Sleep(1000);
+ h.press(h.Bbtn);
+ //if the trade is still going on wait for it to finish
+ Thread.Sleep(30000);
+ bSent = true;
+ break;
+ }
+ }
+ h.press(h.right);
+ Thread.Sleep(500);
+ }
+ if (!bSent)
+ {
+ //no tradable pokemon in the last X pokemon, start from the front of the list again
+ h.press(h.Bbtn);
+ Thread.Sleep(1000);
+ h.press(h.Bbtn);
+ Thread.Sleep(1000);
+ }
+ }
+ }
+ public void RequestStop()
+ {
+ _shouldStop = true;
+ }
+
+ public void setValues(string szPtF, string szPtG, string szD, string szF, string szL, string szP)
+ {
+ this.szPokemonToFind = szPtF;
+ this.szPokemonToGive = szPtG;
+ this.szDefaultPk7 = szD;
+ this.szPk7Folder = szF;
+ this.szLevel = szL;
+ this.szPID = szP;
+
+
+ this.iPID = int.Parse(szPID, NumberStyles.HexNumber);
+ }
+
+ }
+}
diff --git a/README.md b/README.md
index 41c4d10..94129f3 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,34 @@
# Ledybot
A pokemon SM giveaway bot for the n3ds. Needs NTR and Input Redirection to work.
+
+Thanks to kwsch and the guys from PKHeX for their work on the .pk7 format!
+Also thanks to Kazo for his NTR Input Redirection Client as well as Stary2001 for the actual .cia!
+
+1. Boot your n3ds
+2. Start the Boot NTR selector
+3. Start the Input Redirection.cia
+4. Start Pokemon SM and connect online in the Festival Plaza
+5. Open the GTS until you see the "Seek Pokemon / Deposit Pokemon" screen
+6. Start Ledybot, fill in your n3ds ip, ntr port and pokemon pid
+7. Type in which pokemon the bot shall find in the GTS
+8. Type in which pokemon you are giving away (this is used to check if we can actually trade the deposited pokemon)
+9. Type in the lower level range of the pokemon you are trading. The bot will trade all "Any"-level pokemon as well as pokemon asking for this level+. This means if you want to trade a lvl 100 Ditto you have to put 91 in here (since the range goes 91 - 100).
+10. Select a default .pk7 file, this file will be injected and traded by the bot on default.
+11. Select a specific .pk7 folder. The bot will check the deposited Pokemons name, see if the name matches any .pk7 file in the folder and inject this one instead (if it exists).
+12. Press Start
+
+## Todo:
+
+Lots of things!
+- Comments and Documentation!
+- Unicode support
+- There may be some stability issues at times. I've had it run for 10h+ in the past but since the bot can't really restart itself when it crashes you still need to have an eye on it from time to time.
+- 1-10 level range probably won't work yet because of lazy coding (You'd have to type in "1" in the field, but I use contains() to check... and 91 also contains 1 so yeaa...)
+- Giving away different pokemon. This would need a simple change to check the requested pokemon based on the name of the deposited pokemon. Mostly a UI thing and I'm not really a fan of that, will come in the future.
+- An actual working stop button (it will stop... eventually... maybe)
+- Speed optimizations
+- Prevent the same people from requesting more than once every X min. I already have the data of who requests (at least trainer name, country and subcountry), I'd just need to add them to a list and block them for a while. This would also block people from the same region with the same name though (unless I find a better way to identify who is requesting)
+- Add an option to search from the back of the queue?
+- Add an option for several deposited pokemon (to prevent people from redepositing the same pokemon all the time)?
+- Add an option to select how many gts entries we look at max (currently hardcoded 25)
+- ... and more!
\ No newline at end of file