研究天龍八部(網遊), 寫了個輔助自動打怪、答題提示的輔助工具
阿新 • • 發佈:2019-01-19
最近玩了玩天龍八部,玩這個遊戲簡直就是遭罪,升級非常慢,而且殺怪也很累,純手工,我都不知道為什麼還有那麼多人玩。玩到40多級了,實在是受不了,遊戲的顏色搭配也是非常的傷眼睛,於是我就想寫一個自動打怪的輔助工具得了。
接下來我就花了1天多的時間寫了程式。有自動尋怪、自動加血、自動加藍、自動釋放技能、防外掛答題報警(利用Fetion傳送簡訊到手機)。有了這個工具後我就可以掛上,關掉電腦,需要答題的時候就來答一下題。
附上主要程式碼(有需要程式碼郵件和我聯絡吧:[email protected]):
- unit BackMainFrm;
- interface
- uses
- Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
- Dialogs, ExtCtrls, Menus, GlobalDefs, StdCtrls;
- type
- TNumItem = record
- StartCol: Byte;
- EndCol: Byte;
- end;
- TNumItemAry = arrayof TNumItem;
- TBackMainForm = class(TForm)
- MainTray: TTrayIcon;
- TrayMenu: TPopupMenu;
- SysSetMenuItem: TMenuItem;
- ExitSysMenuItem: TMenuItem;
- N4: TMenuItem;
- TimerFinder: TTimer;
- procedure ExitSysMenuItemClick(Sender: TObject);
- procedure SysSetMenuItemClick(Sender: TObject);
- procedure FormCreate(Sender: TObject);
- procedure TimerFinderTimer(Sender: TObject);
- procedure FormDestroy(Sender: TObject);
- procedure MainTrayClick(Sender: TObject);
- private
- FSCBitMap: TBitmap;
- FNumBitMapAry: array[0..9] of TBitmap;
- FCurGamePos: TPoint;
- FFightUnixTick: Cardinal;
- FIsFighting: Boolean;
- FIsNeedAnswerQT: Boolean;
- FLastCalcAnswerUnixTick: Cardinal;
- FLifeCurrent: Integer;
- FMagicCurrent: Integer;
- FBBLifeCurrent: Integer;
- FPressF1UnixTick: Cardinal;
- FPressF2UnixTick: Cardinal;
- FPressF3UnixTick: Cardinal;
- FPressF4UnixTick: Cardinal;
- procedure CreateNumBitmapAry;
- procedure LoadNumBitmapAry(const DirPath: string);
- procedure DestroyNumBitmapAry;
- private
- procedure WMHotKey(var Message: TMessage); message WM_HOTKEY;
- procedure RegisterHotKeys;
- procedure InitializeLifeAndMagicColor;
- procedure CalcCurrentPos;
- procedure CalcFightState;
- procedure CalcLifeAndMagic;
- procedure CalcQuestionState;
- procedure AutoPressMagicKeys;
- function TranslateWinHotKeyToLocal(HotKeyValue: Cardinal): Word;
- procedure AnalyseNum(ABitmap: TBitmap; NumAry: TNumItemAry; List: TStringList);
- procedure GetNumList(BitMap: TBitmap; var NumAry: TNumItemAry);
- public
- end;
- TBeepThread = class(TThread)
- private
- FBeepSecs: Integer;
- procedure SyncSendFetionMsg;
- protected
- procedure Execute; override;
- public
- constructor Create(BeepSecs: Integer);
- end;
- procedure SendFetionMsg(const Msg: string);
- var
- BackMainForm: TBackMainForm;
- implementation
- uses SystemSetFrm, BcConfigMgr, PisConfig, VirtualKeys, FetchWindow, Math,
- DateUtils;
- {$R *.dfm}
- var
- BeepThread: TBeepThread = nil;
- procedure SendFetionMsg(const Msg: string);
- begin
- if FetionWindowHandle <> 0then
- begin
- ShowWindow(FetionWindowHandle, SW_NORMAL);
- SetForegroundWindow(FetionWindowHandle);
- SendMessage(FetionInputHandle, WM_SETTEXT, 0, Integer(PChar(Msg)));
- Sleep(20);
- SendMessage(FetionSendBtnHandle, WM_LBUTTONDOWN, MK_LBUTTON, 0);
- Sleep(10);
- SendMessage(FetionSendBtnHandle, WM_LBUTTONUP, 0, 0);
- ShowWindow(FetionWindowHandle, SW_HIDE);
- end;
- end;
- procedure TBackMainForm.GetNumList(BitMap: TBitmap; var NumAry: TNumItemAry);
- procedure FetchStartCol(var LoopVar: Integer; BackColor: Integer);
- var
- J: Integer;
- begin
- while (LoopVar < BitMap.Width) do
- begin
- for J := 0to BitMap.Height - 1do
- begin
- //如果不是背景
- if (BitMap.Canvas.Pixels[LoopVar, J] xor BackColor) <> 0then
- begin
- Break;
- end;
- end;
- //如果不是背景,則找到字元
- if J < BitMap.Height then
- Break;
- Inc(LoopVar);
- end;
- end;
- procedure FetchEndCol(var LoopVar: Integer; BackColor: Integer);
- var
- J: Integer;
- begin
- while (LoopVar < BitMap.Width) do
- begin
- for J := 0to BitMap.Height - 1do
- begin
- //如果是字元
- if (BitMap.Canvas.Pixels[LoopVar, J] xor BackColor) <> 0then
- begin
- Break;
- end;
- end;
- //如果不是字元,則找到背景
- if J >= BitMap.Height then
- Break;
- Inc(LoopVar);
- end;
- end;
- var
- I: Integer;
- BackColor: Integer;
- StartCol, EndCol: Byte;
- begin
- BackColor := BitMap.Canvas.Pixels[0, 0];
- I := 0;
- while I < BitMap.Width do
- begin
- FetchStartCol(I, BackColor);
- if I >= BitMap.Width then
- Break;
- StartCol := I;
- FetchEndCol(I, BackColor);
- if I >= BitMap.Width then
- Break;
- EndCol := I - 1;
- SetLength(NumAry, Length(NumAry) + 1);
- NumAry[High(NumAry)].StartCol := StartCol;
- NumAry[High(NumAry)].EndCol := EndCol;
- end;
- end;
- procedure TBackMainForm.InitializeLifeAndMagicColor;
- begin
- if LifeColor = 0then
- LifeColor := FSCBitMap.Canvas.Pixels[LifeX, LifeY];
- if MagicColor = 0then
- MagicColor := FSCBitMap.Canvas.Pixels[MagicX, MagicY];
- BBLifeColor := LifeColor;
- MonsterLifeColor := LifeColor;
- end;
- procedure TBackMainForm.AnalyseNum(ABitmap: TBitmap; NumAry: TNumItemAry;
- List: TStringList);
- function SameNum(const NumItem: TNumItem; Num: Integer): Boolean;
- var
- J, K: Integer;
- RealWidth: Integer;
- RefIsBgColor, IsBgColor: Boolean;
- LRefBgColor, LBgColor: Integer;
- begin
- Result := True;
- RealWidth := NumItem.EndCol - NumItem.StartCol + 1;
- if RealWidth > FNumBitMapAry[Num].Width then
- RealWidth := FNumBitMapAry[Num].Width;
- LRefBgColor := FNumBitMapAry[0].Canvas.Pixels[0, 0];
- LBgColor := ABitmap.Canvas.Pixels[0,0];
- for J := 0to RealWidth - 1do
- begin
- for K := 0to7do
- begin
- RefIsBgColor := FNumBitMapAry[Num].Canvas.Pixels[J, K] = LRefBgColor;
- IsBgColor := ABitmap.Canvas.Pixels[J + NumItem.StartCol, K] = LBgColor;
- // 不相同退出
- if RefIsBgColor xor IsBgColor = True then
- begin
- Result := False;
- Exit;
- end;
- end;
- end;
- end;
- function GetStringNum(const NumItem: TNumItem): string;
- var
- I: Integer;
- begin
- Result := '';
- for I := 0to9do
- begin
- if SameNum(NumItem, I) then
- begin
- Result := IntToStr(I);
- Break;
- end;
- end;
- end;
- var
- I: Integer;
- LNumStr, TmpStr: string;
- begin
- LNumStr := '';
- for I := 0to High(NumAry) do
- begin
- TmpStr := GetStringNum(NumAry[I]);
- if TmpStr <> ''then
- begin
- LNumStr := LNumStr + TmpStr;
- end;
- if I < High(NumAry) then
- begin
- if (NumAry[I+1].StartCol - NumAry[I].EndCol) > 8then
- begin
- List.Add(LNumStr);
- LNumStr := '';
- end;
- end;
- end;
- List.Add(LNumStr);
- end;
- procedure TBackMainForm.AutoPressMagicKeys;
- begin
- if PressKeyF1Secs <> 0then
- begin
- if (DateTimeToUnix(Now) - FPressF1UnixTick) > PressKeyF1Secs then
- begin
- MonitorKeyPress([], VK_F1);
- FPressF1UnixTick := DateTimeToUnix(Now);
- Sleep(10);
- end;
- end;
- if PressKeyF2Secs <> 0then
- begin
- if (DateTimeToUnix(Now) - FPressF2UnixTick) > PressKeyF2Secs then
- begin
- MonitorKeyPress([], VK_F2);
- FPressF2UnixTick := DateTimeToUnix(Now);
- Sleep(10);
- end;
- end;
- if PressKeyF3Secs <> 0then
- begin
- if (DateTimeToUnix(Now) - FPressF3UnixTick) > PressKeyF3Secs then
- begin
- MonitorKeyPress([], VK_F3);
- FPressF3UnixTick := DateTimeToUnix(Now);
- Sleep(10);
- end;
- end;
- if PressKeyF4Secs <> 0then
- begin
- if (DateTimeToUnix(Now) - FPressF4UnixTick) > PressKeyF4Secs then
- begin
- MonitorKeyPress([], VK_F4);
- FPressF4UnixTick := DateTimeToUnix(Now);
- Sleep(10);
- end;
- end;
- end;
- procedure TBackMainForm.CalcCurrentPos;
- var
- LBitMap: TBitmap;
- NumAry: TNumItemAry;
- StrList: TStringList;
- begin
- LBitMap := TBitmap.Create;
- StrList := TStringList.Create;
- try
- LBitMap.PixelFormat := pf24bit;
- LBitMap.Width := 80;
- LBitMap.Height := 8;
- LBitMap.Canvas.CopyRect(Rect(0, 0, 80, 8), FSCBitMap.Canvas,
- Rect(FSCBitMap.Width-110, 29, FSCBitMap.Width-30, 37));
- GetNumList(LBitMap, NumAry);
- if Length(NumAry) <= 0then
- Exit;
- AnalyseNum(LBitMap, NumAry, StrList);
- FCurGamePos.X := StrToInt(StrList[0]);
- FCurGamePos.Y := StrToInt(StrList[1]);
- finally
- StrList.Free;
- LBitMap.Free;
- end;
- end;
- procedure TBackMainForm.CalcFightState;
- begin
- FIsFighting :=
- FSCBitMap.Canvas.Pixels[MonsterLifeX, MonsterLifeY] = MonsterLifeColor;
- end;
- procedure TBackMainForm.CalcLifeAndMagic;
- var
- I: Integer;
- begin
- // 初始化資料
- InitializeLifeAndMagicColor;
- // 計算生命
- I := 0;
- FLifeCurrent := 0;
- while True do
- begin
- if GetRValue(FSCBitMap.Canvas.Pixels[LifeX+I, LifeY]) <> GetRValue(LifeColor) then
- Break;
- Inc(I);
- Inc(FLifeCurrent);
- end;
- // 計算魔法
- I := 0;
- FMagicCurrent := 0;
- while True do
- begin
- if GetBValue(FSCBitMap.Canvas.Pixels[MagicX+I, MagicY]) <> GetBValue(MagicColor) then
- Break;
- Inc(I);
- Inc(FMagicCurrent);
- end;
- // 計算寶寶生命
- I := 0;
- FBBLifeCurrent := 0;
- while True do
- begin
- if GetRValue(FSCBitMap.Canvas.Pixels[BBLifeX+I, BBLifeY]) <> GetRValue(BBLifeColor) then
- Break;
- Inc(I);
- Inc(FBBLifeCurrent);
- end;
- end;
- procedure TBackMainForm.CalcQuestionState;
- // 判斷顏色是否有效
- function IsValidPoint(X, Y: Integer): Boolean;
- var
- AColor: TColor;
- begin
- AColor := FSCBitMap.Canvas.Pixels[X, Y];
- Result := True;
- Result := Result and (GetRValue(AColor) >= GetRValue(QT_MIN_COLOR));
- Result := Result and (GetGValue(AColor) >= GetGValue(QT_MIN_COLOR));
- Result := Result and (GetBValue(AColor) >= GetBValue(QT_MIN_COLOR));
- end;
- // 判斷是否是問題視窗
- function IsValidQuestion(X, Y: Integer): Boolean;
- begin
- Result := True;
- Result := Result and IsValidPoint(X+QT_WIDTH, Y);
- Result := Result and IsValidPoint(X, Y+QT_HEIGHT);
- Result := Result and IsValidPoint(X+QT_WIDTH, Y+QT_HEIGHT);
- end;
- var
- I, J: Integer;
- begin
- if (DateTimeToUnix(Now) - FLastCalcAnswerUnixTick) < 5then
- Exit;
- // 記錄最後計算時間
- FLastCalcAnswerUnixTick := DateTimeToUnix(Now);
- FIsNeedAnswerQT := False;
- for I := 0to (FSCBitMap.Width div2) - 1do
- begin
- for J := 0to (FSCBitMap.Height div2) - 1do
- begin
- if IsValidPoint(I, J) then
- begin
- if IsValidQuestion(I, J) then
- begin
- FIsNeedAnswerQT := True;
- Exit;
- end;
- end;
- end;
- end;
- end;
- procedure TBackMainForm.CreateNumBitmapAry;
- var
- I: Integer;
- begin
- for I := 0to9do
- begin
- FNumBitMapAry[I] := TBitmap.Create;
- FNumBitMapAry[I].PixelFormat := pf24bit;
- end;
- end;
- procedure TBackMainForm.DestroyNumBitmapAry;
- var
- I: Integer;
- begin
- for I := 0to9do
- begin
- FNumBitMapAry[I].Free;
- end;
- end;
- procedure TBackMainForm.ExitSysMenuItemClick(Sender: TObject);
- begin
- if Application.MessageBox('確實要退出?', '提示資訊',
- MB_YESNO + MB_ICONQUESTION) = mrYes then
- begin
- Application.Terminate;
- end;
- end;
- procedure TBackMainForm.FormCreate(Sender: TObject);
- procedure LoadConfig;
- begin
- FetionWindowIncText := ConfigMgr.FetionWindowText;
- FetionWindowHandle := ConfigMgr.FetionWindowHandle;
- FetionInputHandle := ConfigMgr.FetionInputWindowHandle;
- FetionSendBtnHandle := ConfigMgr.FetionSendBtnWindowHandle;
- end;
- begin
- FSCBitMap := TBitmap.Create;
- FFightUnixTick := 0;
- Randomize;
- MainTray.Hint := '天龍八部自助打怪 1.0';
- LoadConfig;
- CreateNumBitmapAry;
- LoadNumBitmapAry('./DigitalImages/');
- RegisterHotKeys;
- FCurGamePos.X := 0;
- FCurGamePos.Y := 0;
- TimerFinder.Interval := FinderTimerMSec;
- end;
- procedure TBackMainForm.FormDestroy(Sender: TObject);
- begin
- FSCBitMap.Free;
- DestroyNumBitmapAry;
- end;
- procedure TBackMainForm.LoadNumBitmapAry(const DirPath: string);
- var
- I: Integer;
- begin
- for I := 0to9do
- begin
- FNumBitMapAry[I].LoadFromFile(Format('%s%d.bmp', [DirPath, I]));
- end;
- end;
- procedure TBackMainForm.MainTrayClick(Sender: TObject);
- begin
- BackMainForm.Show;
- end;
- procedure TBackMainForm.RegisterHotKeys;
- var
- GlobalId: Word;
- AModifiers: Cardinal;
- begin
- AModifiers := MOD_CONTROL + MOD_ALT;;
- // 開關 CTRL + ALT + F10
- GlobalId := GlobalAddAtom(PChar('HotKey_TLBBHelperF10'));
- RegisterHotKey(Self.Handle, GlobalId, AModifiers, VK_F10);
- // 設定原點 CTRL + ALT + F11
- GlobalId := GlobalAddAtom(PChar('HotKey_TLBBHelperF11'));
- RegisterHotKey(Self.Handle, GlobalId, AModifiers, VK_F11);
- // 調出設定對話方塊 CTRL + ALT + F12
- GlobalId := GlobalAddAtom(PChar('HotKey_TLBBHelperF12'));
- RegisterHotKey(Self.Handle, GlobalId, AModifiers, VK_F12);
- // 終止傳送報警訊息執行緒 CTRL + ALT + F1
- GlobalId := GlobalAddAtom(PChar('HotKey_TLBBHelperF1'));
- RegisterHotKey(Self.Handle, GlobalId, AModifiers, VK_F1);
- // 傳送Fetion測試包 CTRL + ALT + F1
- GlobalId := GlobalAddAtom(PChar('HotKey_TLBBHelperF2'));
- RegisterHotKey(Self.Handle, GlobalId, AModifiers, VK_F2);
- end;
- procedure TBackMainForm.SysSetMenuItemClick(Sender: TObject);
- var
- OldState: Boolean;
- begin
- if TSystemSetForm.IsExist then Exit;
- OldState := TimerFinder.Enabled;
- TimerFinder.Enabled := False;
- with TSystemSetForm.Create(Self) do
- try
- if ShowModal = mrOk then
- begin
- TimerFinder.Interval := FinderTimerMSec;
- end;
- finally
- Free;
- end;
- TimerFinder.Enabled := OldState;
- end;
- procedure TBackMainForm.TimerFinderTimer(Sender: TObject);
- procedure RandomFinderMonster;
- var
- X, Y: Integer;
- begin
- if FCurGamePos.X < CenterPosX then
- X := RandomRange(FinderMinX, FinderMaxX)
- else
- X := RandomRange(-FinderMaxX, -FinderMinX);
- if FCurGamePos.Y < CenterPosY then
- Y := RandomRange(FinderMinY, FinderMaxY)
- else
- Y := RandomRange(-FinderMaxY, -FinderMinY);
- X := Screen.Width div2 + X;
- Y := Screen.Height div2 + Y;
- MonitorMouseMove(X, Y);
- Sleep(10);
- end;
- procedure FindMonster;
- begin
- // 尋找怪物
- ifnot FIsFighting then
- begin
- FFightUnixTick := 0;
- RandomFinderMonster;
- MonitorMouseClick(1);
- endelse
- begin
- if FFightUnixTick = 0then
- FFightUnixTick := DateTimeToUnix(Now)
- else
- begin
- // 如果找怪超時,則重新尋找
- if DateTimeToUnix(Now) - FFightUnixTick > 15then
- begin
- // 隨機移動位置(必須執行此操作,否則會死鎖)
- MonitorMouseMove(RandomRange(0, Screen.Width div2),
- RandomRange(0, Screen.Height div2));
- Sleep(10);
- MonitorMouseClick(2);
- endelse
- begin
- // 釋放魔法
- AutoPressMagicKeys;
- end;
- end;
- end;
- end;
- procedure FillLifeAndMagic;
- begin
- // 補人物血
- if ((FLifeCurrent*100) div LIFE_MAX) <= LifeMin then
- begin
- MonitorKeyPress([], KeyLifeAdd);
- end;
- Sleep(20);
- // 補寶寶血
- if ((FBBLifeCurrent*100) div BB_LIFE_MAX) <= BBLifeMin then
- begin
- MonitorKeyPress([], KeyBBLifeAdd);
- end;
- Sleep(20);
- // 補任務魔法
- if ((FMagicCurrent*100) div MAGIC_MAX) <= MagicMin then
- begin
- MonitorKeyPress([], KeyMagicAdd);
- end;
- end;
- procedure PickGoods;
- begin
- // 一定要在沒有打怪狀態
- ifnot FIsFighting then
- begin
- RandomFinderMonster;
- MonitorMouseClick(2);
- Sleep(10);
- end;
- end;
- begin
- try
- FetchWindowImage(FSCBitMap);
- CalcFightState;
- CalcCurrentPos;
- CalcQuestionState;
- CalcLifeAndMagic;
- //PickGoods;(暫時不開啟,有問題)
- FindMonster;
- Sleep(20);
- FillLifeAndMagic;
- // 啟動報警程式
- if FIsNeedAnswerQT and (BeepThread = nil) then
- TBeepThread.Create(50).Resume;
- except
- end;
- end;
- function TBackMainForm.TranslateWinHotKeyToLocal(
- HotKeyValue: Cardinal): Word;
- var
- ALWord, AHWord: Word;
- begin
- Result := 0;
- AHWord := HiWord(HotKeyValue);
- ALWord := HotKeyValue and$FFFF;
- if ALWord and MOD_SHIFT <> 0then
- Result := Result + scShift;
- if ALWord and MOD_ALT <> 0then
- Result := Result + scAlt;
- if ALWord and MOD_CONTROL <> 0then
- Result := Result + scCtrl;
- Result := Result + AHWord;
- end;
- procedure TBackMainForm.WMHotKey(var Message: TMessage);
- var
- LocalKey: Word;
- begin
- LocalKey := TranslateWinHotKeyToLocal(Message.LParam);
- if LocalKey = scCtrl + scAlt + VK_F10 then
- begin
- // 系統開關
- TimerFinder.Enabled := not TimerFinder.Enabled;
- Windows.Beep(3000, 100);
- endelseif LocalKey = scCtrl + scAlt + VK_F11 then
- begin
- // 設定原點
- FetchWindowImage(FSCBitMap);
- CalcCurrentPos;
- CenterPosX := FCurGamePos.X;
- CenterPosY := FCurGamePos.Y;
- Windows.Beep(2000, 100);
- Windows.Beep(2500, 100);
- endelseif LocalKey = scCtrl + scAlt + VK_F12 then
- begin
- // 調出設定框
- SysSetMenuItemClick(nil);
- endelseif LocalKey = scCtrl + scAlt + VK_F1 then
- begin
- // 關閉執行緒
- try
- if Assigned(BeepThread) then
- begin
- BeepThread.Terminate;
- end;
- except
- end;
- endelseif LocalKey = scCtrl + scAlt + VK_F2 then
- begin
- SendFetionMsg('天龍八部助手測試!');
- end;
- end;
- { TBeepThread }
- constructor TBeepThread.Create(BeepSecs: Integer);
- begin
- inherited Create(True);
- FreeOnTerminate := True;
- FBeepSecs := BeepSecs;
- // 記錄自己
- BeepThread := Self;
- end;
- procedure TBeepThread.Execute;
- var
- StartUnixTick: Cardinal;
- begin
- StartUnixTick := DateTimeToUnix(Now);
- SyncSendFetionMsg;
- whilenot Terminated do
- begin
- if DateTimeToUnix(now) - StartUnixTick > FBeepSecs then
- Break;
- Windows.Beep(4000, 300);
- Sleep(700);
- end;
- BeepThread := nil;
- end;
- procedure TBeepThread.SyncSendFetionMsg;
- begin
- SendFetionMsg('TLBBHelper: 需要輸入驗證碼!');
- end;
- end.
- unit GlobalDefs;
- interface
- uses
- Windows;
- { 相關配置引數 }
- const
- LIFE_MAX = 124;
- MAGIC_MAX = 124;
- BB_LIFE_MAX = 96;
- QT_MIN_COLOR = $FAFAFA;
- QT_WIDTH = 237;
- QT_HEIGHT = 298;
- var
- FinderTimerMSec: Integer = 200; // 系統Timer執行時間
- LifeX: Integer = 64; // 人物生命值X座標
- LifeY: Integer = 32; // 人物生命值Y座標
- LifeColor: Integer = 0; // 人物生命值取樣顏色(載入時初始化)
- LifeMin: Integer = 50; // 人物生命最小百分比
- MagicX: Integer = 64; // 人物魔法值X座標
- MagicY: Integer = 38; // 人物魔法值Y座標
- MagicColor: Integer = 0; // 人物魔法值取樣顏色(載入時初始化)
- MagicMin: Integer = 50; // 人物魔法最小百分比
- BBLifeX: Integer = 91; // 寶寶生命值X座標
- BBLifeY: Integer = 71; // 寶寶生命值Y座標
- BBLifeColor: Integer = 0; // 寶寶生命值取樣顏色(載入時初始化)
- BBLifeMin: Integer = 30; // 寶寶生命