- Quan trọng nhất là tìm được cái ma trận để lưu các con pokemon.
- Mà cần đủ thời gian tìm thì mình phải xử lý cái thời gian của trò chơi trước đã.
- Lấy được ma trận game rồi thì làm thế nào để xác định được 2 con pokemon hợp lệ.
- Làm thế nào để tự động click được lên game.
- Cheate Engine
- Knowledge about C# Programing Language :)) (vì C/C++ khó quá mình không học nổi với lại C# làm form dễ)
- Một cái đầu lạnh :V
1. Tìm kiếm địa chỉ lưu biến thời gian
Bật CE lên để search thôi, vì không rõ con số cụ thể nên sẽ phải để Scan type là Unkown initial value, Value type thì để all vì cũng chả biết nó sẽ thuộc kiểu dữ liệu gì.
Ban đầu thì cứ nghĩ là thời gian sẽ giảm về 0 nên mình search ở
những giá trị tiếp theo là Decreased Value mà nó cứ không ra, mãi lúc sau mới
nhảy số để lại thành Increased Value thì tìm thấy vài giá trị, mình nghi ngờ
cái biến kiểu float nên về set giá trị cho nó về 0, thế là thời gian được
reset lại. vậy là tìm được địa chỉ
0x004b6084 là địa chỉ chứa giá trị thời
gian.
2. Tìm kiếm ma trận của trò chơi
Cái này tìm gian nan hơn, vì mình không biết giá trị của các con pokemon, cũng may với cái kinh nghiệm từ trước mình có tìm cái ma trận của game Minesweeper nên cuối cùng cũng tìm ra được, rồi sau đó nhanh chóng tìm Pointer cho nó vì chẳng may tắt game rồi tìm lại ốm chết luôn :((. kết quả của pointer là "pikachu.exe"+000B6044 offset 76
Sau đó chọn Browse this memory region để xem memory
Thấy như sau
Cấu trúc của con pokemon đầu tiên là FF FF 0A 00 0A 00, và tất cả các con tiếp theo cũng có dạng đó gồm 6 bytes:
- 2 bytes đầu tiên FF FF là con pokmon còn hiển thị, nếu ăn mất rồi thì nó sẽ là 00 00
- 2 bytes tiếp theo 0A 0A là hình ảnh hiển thị của con pokemon đó.
- 2 bytes cuối cùng 0A 0A là mã id của con pokemon, nếu cùng mã thì ăn được kể cả khác hiển thị
Mình đã lấy máy tính ra để tính toán 1 chút như thế này, từ địa con pokemon đầu tiên + 0x6 sẽ ra con pokemon tiếp theo
Pokemon row 1 | Offset | Add | Next Pokemon Offset |
---|---|---|---|
Con đầu tiên | 72 | 6 | 78 |
Con thứ 2 | 78 | 6 | 7E |
Con thứ 3 | 7E | 6 | 84 |
Con thứ n | ... | 6 | ... |
Con thứ 15 | C6 | 6 | CC |
Con thứ 16 | CC | 6 | D2 |
Đến đây tưởng là D2 sẽ là Offset của còn đầu tiên của row2 ư? Không hề! Ban đầu mình cũng hý hửng tưởng là vậy mà chỉnh thử ở memory để cho FF FF về 00 00 nhưng mà không có gì thay đổi, mặc dù vẫn đúng cái cấu trúc 6 bytes như thế. Mình phải cộng thêm tận 2 lần nữa thì mới ra con pokemon đầu tiên ở row 2.
Pokemon | Offset | Add | Next Pokemon Offset |
---|---|---|---|
Con thứ 16 | CC | 6 | D2 |
Con thứ 17 | D2 | 6 | D8 |
Con thứ 18 | D8 | 6 | DE |
Con thứ 1 ở row 2 | DE |
Có vẻ như là game này không đơn giản chỉ là ma trận 9x16 mà phải là 9x18 cũng nên;
Lấy giá trị 0xDE - 0x72 = 0x6C. Vậy là để di chuyển đến row N thì dùng công thức 0x72 + 0x6c * N, mình dùng cái công thức này để lúc viết code sử dụng vòng lặp kết hợp với công thức để đọc hết cái ma trận của game;
3. Thuật toán để tìm kiếm 2 con pokemon hợp lệ
Mình cũng có search để tìm kiếm thuật toán được sử dụng trong ma trận, kết quả là sử dụng BFS, nên mình cũng có thử viết code trước bằng Typescript trước xem sao;
interface Point { row: number; col: number; } interface IQueue { point: Point; redirect: number; prevDirection: Point | null; } const directions: Point[] = [ { row: -1, col: 0 }, // Di chuyển lên { row: 1, col: 0 }, // Di chuyển xuống { row: 0, col: -1 }, // Di chuyển trái { row: 0, col: 1 }, // Di chuyển phải ]; function isValidMove( matrix: number[][], newRow: number, newCol: number, ): boolean { const numRows = matrix.length; const numCols = matrix[0].length; return ( newRow >= 0 && newRow < numRows && newCol >= 0 && newCol < numCols && matrix[newRow][newCol] === 0 ); } function isValidConnect(matrix: number[][], start: Point, end: Point): boolean { const numRows = matrix.length; const numCols = matrix[0].length; const visited: boolean[][] = Array.from({ length: numRows }, () => Array(numCols).fill(false), ); visited[start.row][start.col] = true; const queue: IQueue[] = [{ point: start, redirect: 0, prevDirection: null }]; while (queue.length > 0) { const { point, redirect, prevDirection } = queue.shift()!; if (redirect > 3) continue; if (point.row === end.row && point.col === end.col) { return true; } for (const direction of directions) { const newRow = point.row + direction.row; const newCol = point.col + direction.col; if (isValidMove(matrix, newRow, newCol) && !visited[newRow][newCol]) { visited[newRow][newCol] = true; let newRedirect = redirect; if ( prevDirection === null || prevDirection.row !== direction.row || prevDirection.col !== direction.col ) { newRedirect++; // Nếu có chuyển hướng thì tăng biến redirect } queue.push({ point: { row: newRow, col: newCol }, redirect: newRedirect, prevDirection: direction, }); } } } return false; // Không tìm thấy đường đi } const matrix: number[][] = [ [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 0], [1, 0, 1, 0], [0, 0, 0, 0], ]; const start: Point = { row: 0, col: 0 }; const end: Point = { row: 3, col: 3 }; const redirections = isValidConnect(matrix, start, end); console.log(redirections ? 'Valid' : 'invalid');
Code minh hoạ đi từ điểm 0,0 đến 3,3, khi đi từ start đến end mà số lần chuyển hướng không quá 3 thì là hợp lệ, chạy code lên thì cũng khá là oke, nên sau đó mình sẽ chuyển sang C# để áp dụng với game sau.
Đến đây là hết phần chuẩn bị thông tin rồi, phần sau sẽ là dựa vào những cái này để code.
0 Nhận xét