`

QQ连连看外挂制作

    博客分类:
  • vc
阅读更多

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

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

核心算法是我自己实现的

 

我在判断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;
}

 

  • 大小: 28.5 KB
  • 大小: 36 KB
分享到:
评论
5 楼 xouou_53320 2012-05-02  
//支持xp和win7
void CheckOsVersion()
{
OSVERSIONINFO ovi;
ovi.dwOSVersionInfoSize=sizeof(ovi);
GetVersionEx(&ovi);
if (ovi.dwMajorVersion == 5 && ovi.dwMinorVersion == 1) //WinXP
{
//MessageBox(NULL,"xp系统","提示",MB_OK);
lpBaseAddress = (LPCVOID)0x0012A480; //基址

}
else if (ovi.dwMajorVersion == 6 && ovi.dwMinorVersion == 1) //Win7
{
lpBaseAddress = (LPCVOID)0x0012A444;
}else
{
MessageBox(NULL,"版本不支持!","提示",MB_OK);
ExitProcess(0);
}
}
4 楼 xouou_53320 2012-04-08  
genime 写道
已经搞定了- -

3 楼 genime 2012-04-07  
已经搞定了- -
2 楼 genime 2012-04-07  
请教一下,为什么我查找的基址是一样的,读出来的都是00 呢? 座位号读的倒是对的
1 楼 genime 2012-04-07  
请教一下,为什么我读的棋盘数据都是00呢

相关推荐

Global site tag (gtag.js) - Google Analytics