QQ连连看外挂制作

论坛 期权论坛 编程之家     
选择匿名的用户   2021-5-22 18:13   42   0

这几天做了个外挂,主要是想学习下相关技术,

参考的是郁金香老师的视频

核心算法是我自己实现的

我在判断3条线路连通性时,用了4个辅助点,纵向pa和pb,横向pc和pd

让其中2个点与我们棋盘上的棋子形成一个矩形,

然后遍历它们组成这个矩形的所有行和所有列
把所有的情况都考虑成3条路径,因为它们都在一个矩形上
其中有的点重合的话那就是2条或1条路径
只要保证2个参考点p1和p2不重叠就行了
纵向时的pa与pb 可以和参考点p1或p2重叠
横向时的pc与pd 可以和参考点p1或p2重叠





xp_sp2

vc6的MFC程序

在框架代码中调用下面的方法就可以了

//llk_wg.h
const PCHAR gameCaption="QQ游戏 - 连连看角色版"; //程序窗口标题
const LPARAM lpStartMenu= (568<<16)+655; //开始按钮坐标
HWND hGame=::FindWindow(NULL,gameCaption); //获取游戏窗口句柄
DWORD dwProcessId;       //进程的pid
HANDLE hProcess;       //进程句柄
LPCVOID lpBaseAddress;      //基地址
byte arrChessData[11][19];     //棋盘数据存放
DWORD rDwLen;        //实际读取的字节数
LPDWORD lpNumberOfBytesRead=&rDwLen;  //实际读取的字节数指针
BOOL readFlag=false;      //读取数据标志失败

BOOL ReadData(LPCVOID lpBaseAddress,LPVOID lpRead,DWORD nsize);//读数据
void LeftClick(POINT pp);     //模拟鼠标单击
BOOL ReadChessData();      //读棋盘数组数据
BOOL CheckChess(POINT p1,POINT p2);   //检测棋子是否可清除
BOOL CheckLine2p(POINT pi,POINT pj) ;  //检测2点是否直通(无障碍)
BOOL Click2p(POINT p1,POINT p2);   //模拟点击消息
void ClearPairOfChess(BOOL b) ;   //消除棋子主过程
void KillAll();        //秒杀
void AutoStart();       //自动开局

BOOL CheckLine2p(POINT pi,POINT pj)//检测同行或同列的2点是否连通(无障碍)
{ //关键算法之一
 POINT pUp;
 POINT pDown;
 POINT pLeft;
 POINT pRight;
 if ((pi.x==pj.x)&&(pi.y==pj.y))  //棋子重叠可连通
 {
  return true;
 }

 if (pi.x==pj.x)     //同列时(x相等,y不等)
 {
  if (pi.y<pj.y)
  {
   pUp=pi;
   pDown=pj;
  }
  else
  {
   pUp=pj;
   pDown=pi;
  }

  if ( 1==(pDown.y-pUp.y) ) //相邻棋子可连通
  {
   return true;
  }
  else      //不相邻时
  {
   for (int lineNum=pUp.y+1; lineNum<pDown.y; lineNum++) 
   {
    if (arrChessData[lineNum][pUp.x]!=0)
    {
     return false; //有障碍
    }
   }
  }
 }//

 if (pi.y==pj.y)     //同行时(x不等,y相等)
 {
  if (pi.x<pj.x)
  {
   pLeft=pi;
   pRight=pj;
  }
  else
  {
   pLeft=pj;
   pRight=pi;
  }

  if ( 1==(pRight.x-pLeft.x) ) //相邻棋子可连通
  {
   return true;    
  }
  else
  {
   for (int columnNum=pLeft.x+1; columnNum<pRight.x; columnNum++)
   {
    if (arrChessData[pLeft.y][columnNum]!=0)
    {
     return false;  //有障碍
    }
   }
  }
 }//
 return true; 
}

BOOL CheckChess(POINT p1,POINT p2)  //检测棋子可否消除
{ //关键算法之一
 bool checkFlag=false;
 POINT pa,pb;//pa的x坐标与p1相等,pb的x坐标与p2相等
 pa.x=p1.x;
 pb.x=p2.x;

 POINT pc,pd;//pc的y坐标与p1相等,pd的y坐标与p2相等
 pc.y=p1.y;
 pd.y=p2.y;

 for (int lineNum=0;lineNum<11;lineNum++)
 {
  pa.y=lineNum;
  pb.y=lineNum;
  if( CheckLine2p(p1,pa)&&CheckLine2p(pa,pb)&&CheckLine2p(pb,p2) )
  {
   //Click2p(p1,p2);  //执行消除
   checkFlag=true;
  }
 }

 for (int columnNum=0;columnNum<19;columnNum++)
 {
  pc.x=columnNum;
  pd.x=columnNum;
  if ( CheckLine2p(p1,pc)&&CheckLine2p(pc,pd)&&CheckLine2p(pd,p2) )
  {
   //Click2p(p1,p2);  //执行消除
   checkFlag=true;
  }
 }
 return checkFlag;
}

BOOL Click2p(POINT p1,POINT p2) //模拟单击事件
{ //棋子宽度31,高度35  
 //int x=25,y=195;   //第一个棋子坐标
 LeftClick(p1);
 LeftClick(p2);
 ReadChessData();
 if (arrChessData[p1.y][p1.x]==0)
 {
  return true;  //成功消除一对棋子
 }
 return false;
}

void KillAll()    //秒杀
{
 for (int a=0;a<10;a++)
 {
  ClearPairOfChess(true); //一般5次循环内就完成秒杀
 }
}

void ClearPairOfChess(BOOL b) //清除一对棋子的主过程
{ 
 ReadChessData();   //更新一下棋盘数据
 
 //遍历棋盘,找出成对的棋子
 POINT p1,p2;
 int x1,y1;
 int x2,y2;
 for (y1=0;y1<11;y1++)  //遍历行数y
 {
  for (x1=0;x1<19;x1++)   //遍历列数x
  {
   if (arrChessData[y1][x1]!=0) //不为空子时,此子设为p1
   {
    for (y2=y1;y2<11;y2++)
    {   
     for (x2=0;x2<19;x2++)
     {
      if ((arrChessData[y1][x1]==arrChessData[y2][x2])&&
       (!((x1==x2)&&(y1==y2)))
         )
      {   //存在p2时
       p1.x=x1;
       p1.y=y1;
       p2.x=x2;
       p2.y=y2;
       if (CheckChess(p1,p2)) //检测是否可清除
       {
        if (Click2p(p1,p2))//消除
        { 
         if (!b)  //不秒杀
         {
          return;
         }
        }
       } 
      }
     }
    }
   }
  }
 } 
}

void LeftClick(POINT pp)      //模拟鼠标单击
{
 if (hGame)
 {
  LPARAM lParam = ((195+pp.y*35)<<16)+(25+pp.x*31);
  SendMessage(hGame,WM_LBUTTONDOWN,0,lParam);
  SendMessage(hGame,WM_LBUTTONUP,0,lParam);
 }
}

void AutoStart()  //自动开始按钮
{ 
 hGame=::FindWindow(NULL,gameCaption);  //获取游戏窗口句柄 
 if (hGame)
 { 
  LPARAM lParam = lpStartMenu;   //(568<<16)+655
  PostMessage(hGame,WM_LBUTTONDOWN,MK_LBUTTON,lParam);
  PostMessage(hGame,WM_LBUTTONUP,0,lParam); 
 }
}




BOOL ReadData(LPCVOID lpBaseAddress,LPVOID lpRead,DWORD nsize) //读数据
{ //3个参数分别是,基址,读取数据存放的缓冲区指针,要读取的数据大小
 hGame=::FindWindow(NULL,gameCaption);//获取游戏窗口句柄
 if (hGame==NULL)
 { 
  //AfxMessageBox(gameErr); 
  return readFlag;  
 }
 
 ::GetWindowThreadProcessId(hGame,&dwProcessId); //获取进程id
 hProcess=::OpenProcess(PROCESS_ALL_ACCESS,false,dwProcessId); //打开
 readFlag=::ReadProcessMemory(hProcess,lpBaseAddress,
      lpRead,nsize,lpNumberOfBytesRead); //读一个字节
 return readFlag;
}


BOOL ReadChessData()       //读棋盘数组数据
{
 lpBaseAddress= (LPCVOID)0x0012A480;   //棋盘数组基址
 ReadData(lpBaseAddress,arrChessData,sizeof(byte)*11*19);
 return readFlag;
}

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP