inherit
4276
0
84
skal75
WH lvl 5 runes status : not ready
274
May 21, 2017 12:45:54 GMT
May 2017
skal75
102
Revelations 2
skal75
|
Post by skal75 on Jan 16, 2018 12:14:30 GMT
Hi guys,
I really like doing Raids in this game. Now, after 18 months of play, and 2 active accounts, finding an opponent is sooo boring and time consuming.
Do you know a macro recorder software soft that would be able to "read" an info in a zone ?
I'd really like a simple bot that keeps pressing "Change Opponent" button in Raids until opponent's Glory Points > 12000.
A class "while" loop with an end condition.
Note : I use BlueStacks.
Any help would be greatly appreciated.
SkAl
|
|
inherit
4276
0
84
skal75
WH lvl 5 runes status : not ready
274
May 21, 2017 12:45:54 GMT
May 2017
skal75
102
Revelations 2
skal75
|
Post by skal75 on Jan 16, 2018 14:32:02 GMT
The challenge relies in reading the amount of opponent's Glory Points.
Most probably need OCR ability.
Don't know if a macro recorder software exists with this ability, built in.
|
|
inherit
4420
0
Jul 21, 2021 13:22:30 GMT
82
n4k3dm1k3
626
Jul 31, 2017 15:11:26 GMT
July 2017
n4k3dm1k3
|
Post by n4k3dm1k3 on Jan 16, 2018 16:33:43 GMT
Is running on BlueStacks allowed by the ToS of this game?
|
|
inherit
4276
0
84
skal75
WH lvl 5 runes status : not ready
274
May 21, 2017 12:45:54 GMT
May 2017
skal75
102
Revelations 2
skal75
|
Post by skal75 on Jan 16, 2018 16:59:14 GMT
Well, I don't know. But my main account is on Windows Phone and my alt (and probably my future main knowing that windows phone is dying) is on Android. That's why it's on BlueStacks for the moment.
|
|
inherit
4420
0
Jul 21, 2021 13:22:30 GMT
82
n4k3dm1k3
626
Jul 31, 2017 15:11:26 GMT
July 2017
n4k3dm1k3
|
Post by n4k3dm1k3 on Jan 16, 2018 17:09:32 GMT
You should be able to move you account between OSes - or do they run on different servers?
|
|
#da2020
2361
0
339
ZanderX10
1,085
Jan 21, 2016 18:26:57 GMT
January 2016
zanderx10
|
Post by ZanderX10 on Jan 16, 2018 17:27:17 GMT
You should be able to move you account between OSes - or do they run on different servers? can't switch os. At least not from ios to android so I would assume not from windows either.
|
|
inherit
4805
0
0
xsoundstorm
2
February 2018
xsoundstorm
|
Post by xsoundstorm on Feb 12, 2018 9:54:46 GMT
Hi this is good article and thinking about some tool called SikuliX.Automation tool with imeages recognize but i dont know nothing about scripting etc if someone can try it for his own and tell us it would work.
|
|
inherit
4276
0
84
skal75
WH lvl 5 runes status : not ready
274
May 21, 2017 12:45:54 GMT
May 2017
skal75
102
Revelations 2
skal75
|
Post by skal75 on Feb 13, 2018 21:26:27 GMT
Thanks for the info !!!
I'm a C# Developer and not Python aware but within an hour I managed to : - click on the raid button - extract the amount of glory
Now I need a loop, wait between clicks and conditional end of loop.
|
|
inherit
4276
0
84
skal75
WH lvl 5 runes status : not ready
274
May 21, 2017 12:45:54 GMT
May 2017
skal75
102
Revelations 2
skal75
|
Post by skal75 on Feb 13, 2018 21:42:55 GMT
Ladies and gentlemen, thanks to xsoundstorm,
I successfully wrote my Raiding tool !
Took me 2 hours, because I don't know anything of Python.
|
|
inherit
4276
0
84
skal75
WH lvl 5 runes status : not ready
274
May 21, 2017 12:45:54 GMT
May 2017
skal75
102
Revelations 2
skal75
|
Post by skal75 on Feb 13, 2018 23:14:18 GMT
Sorry, I spoke too fast.
I still have an issue.
The glory points value that is read is not the right one.
There's a kind of wait to provoke after the click, because for the moment, I think the region that is captured is still the one holding the previous opponent. So the number of glory points is the previous one.
|
|
inherit
4805
0
0
xsoundstorm
2
February 2018
xsoundstorm
|
Post by xsoundstorm on Feb 18, 2018 7:50:50 GMT
I hope u can make it work.
|
|
inherit
1003
0
Sept 26, 2019 9:51:15 GMT
51
moonshaker
239
Jul 31, 2015 15:55:50 GMT
July 2015
moonshaker
|
Post by moonshaker on Feb 19, 2018 13:37:53 GMT
Put 1000 millisecond delay it should be fine
|
|
inherit
2227
0
Dec 25, 2018 18:50:07 GMT
29
Doomkin✪NFS
97
Dec 23, 2015 14:51:28 GMT
December 2015
doomkin
|
Post by Doomkin✪NFS on Feb 20, 2018 16:57:36 GMT
I implemented this quite awhile back using AutoIt that makes a windows call to Tesseract-OCR. AutoIt allows taking screen shots (specifically images in a certain pixel range) and then you throw that at the tesseract which spits out a text document with what it read. At that point it's just reading a text file.
When I get home I'll try and remember and post the function I made that takes two x,y pairs and returns text read from the square formed. (Edit: I forgot, lol, will try again to remember today... sucks I only think to log in here when Im at work)
|
|
nuke
Nightraider
Posts: 91
inherit
4486
0
8
nuke
91
Aug 29, 2017 21:30:09 GMT
August 2017
nuke
|
Post by nuke on Feb 21, 2018 15:43:37 GMT
Very interested in this thread
|
|
user11
ApexNFS Guild
Posts: 34
#000000
4063
0
Apr 11, 2023 11:10:53 GMT
1
user11
34
March 2017
user11
|
Post by user11 on Feb 22, 2018 8:30:09 GMT
I would like to pop up with another proposal. What about using "Ankulua"?
I don't have time to do it myself, but it is a software for android, which doesn't require root, which supports OCR, and it is easy sharable to others.
So, it would work directly on the phone (no computer needed to execute, but reccomended to write the code)
Would someone have the time to give it a try and consider it suitable?
Cheers!!
|
|
inherit
2227
0
Dec 25, 2018 18:50:07 GMT
29
Doomkin✪NFS
97
Dec 23, 2015 14:51:28 GMT
December 2015
doomkin
|
Post by Doomkin✪NFS on Feb 22, 2018 13:50:38 GMT
Below is the function I made for my AutoIt script to grab the text in a certain region on the screen. Tesseract-OCR worked better in testing the smaller the image you give and the less text present.
Func ScreenCap($x_min, $y_min, $x_max, $y_max, $deleteFiles = True)
; Create file names based on date/time for uniqueness $capture_filename = $path & StringReplacE(_NowDate(), "/", "_") & "_" & StringReplace(StringReplace(_NowTime(), ":", "_"), " ", "_") & ".jpg" $output_filename = StringLeft($capture_filename, StringLen($capture_filename)-4) $output_text_filename = $output_filename & ".txt"
; Activate Game Window in case it's not in front WinActivate($windowTitle)
; Create the image Sleep(50) $fileHandler = _ScreenCapture_Capture($capture_filename, $x_min, $y_min, $x_max, $y_max, False) ConsoleWrite("! File created: " & $capture_filename & @crlf)
; Find text in tesseract ShellExecuteWait("C:\Tesseract-OCR\tesseract.exe", $capture_filename & " " & $output_filename, "", "", @sw_HIDE)
; Read output file $content = FileRead($output_text_filename)
; Cleanup files _WinAPI_DeleteObject ($fileHandler) If $deleteFiles Then FileDelete($capture_filename) FileDelete($output_text_filename) EndIf
Return $content
EndFunc
|
|
inherit
4276
0
84
skal75
WH lvl 5 runes status : not ready
274
May 21, 2017 12:45:54 GMT
May 2017
skal75
102
Revelations 2
skal75
|
Post by skal75 on Mar 6, 2018 17:25:38 GMT
So I finally made it. Before any comment : - I'm a C# developer not a Python Developer, so all apologies if the script does not follow Python best practices ...I did my best with a few hours of reading on the net - Resize the BlueStacks window at the minimum, if you want the OCR to work nicely Prerequisites : - install Sikuli X (follow this guide Sikulix QuickStart ) - choose option 1 (with Python) and 3 (OCR) - launch the ide as explained in the guide - copy the script below in the IDE - edit the MIN_GLORY constant as you wish - start bluestacks - in bluestacks, start deck heroes - Resize the BlueStacks window at the minimum (best results for OCR) - in deck heroes, go to raids feature, in the opponent window - in sikulix ide, click on Run (say yes to save if asked) Enjoy !import re
# minimum glory you want to raid for
MIN_GLORY = 5000
class AppRegion(Region):
def __init__(self,appName): switchApp(appName); self._window=App.focusedWindow(); Region.__init__(self,self._window); self.dbg(appName);
def dbg(self,appName): Debug.user("%s - x: %d, y: %d, w: %d, h: %d",appName, self.x,self.y,self.w, self.h); return;
class RaidInfo:
def __init__(self,name, power, glory): self.name = name; self.power = power; self.glory = glory; Debug.user("Name: %s",name) Debug.user("Power: %d",power) Debug.user("Glory Points: %d",glory);
@staticmethod def fromRegion(region): t=region.text(); Debug.user("Raid Region Text : %s",t);
m=re.search("Power:[ ]*(\d+)",t); power=int(m.group(1)); m=re.search("Glory Points:[ ]*(\d+)",t); glory=int(m.group(1)); m=re.search("Name:[ ]*(\S+)",t); name= m.group(1); return RaidInfo(name, power, glory);
class RaidInfoRegion(AppRegion):
def __init__(self,appName): AppRegion.__init__(self,appName); textHeight=int((self._window.h*4.5)/100); textYPos=self.y+int((self._window.h*25.5)/100);
self.setY(textYPos); self.setH(textHeight);
AppRegion.dbg(self,"Raid Info");
class RaidNextOpponentButtonRegion(AppRegion):
def __init__(self,appName): AppRegion.__init__(self,appName);
x=int((self._window.w*67.34)/100); y=int((self._window.h*77.25)/100); h=int((self._window.h*8.12)/100); w=int((self._window.w*21.2)/100); self.setX(self._window.x+x); self.setY(self._window.y+y); self.setH(h); self.setW(w);
AppRegion.dbg(self,"Next Opponent Button");
# # main program #
def changed(event): Debug.user("something changed"); event.stopObserver();
infoRegion=RaidInfoRegion("BlueStacks"); bt=RaidNextOpponentButtonRegion("BlueStacks") infoRegion.onChange(50,changed)
while True: info=RaidInfo.fromRegion(infoRegion);
if (info.glory >= MIN_GLORY) : break;
bt.click() infoRegion.observe(5)
|
|
#000000
4265
0
Feb 25, 2019 15:23:43 GMT
15
Edayn✪NFS
88
May 15, 2017 15:24:43 GMT
May 2017
edayn
|
Post by Edayn✪NFS on Mar 6, 2018 23:20:55 GMT
Hey guys,
Really cool conversation, would love to add some value but need quickly to get back to the basics for a second. I don't get the thing with glory. If I beat level 100 or level 50, with 4 glory or 5600, the glory points won vary from 600 min to 1200+, not that much more. What did I misunderstood ?
|
|
inherit
84
0
Aug 21, 2019 23:29:12 GMT
708
asgarth1980
2,446
March 2015
asgarth1980
|
Post by asgarth1980 on Mar 7, 2018 0:50:23 GMT
Hey guys, Really cool conversation, would love to add some value but need quickly to get back to the basics for a second. I don't get the thing with glory. If I beat level 100 or level 50, with 4 glory or 5600, the glory points won vary from 600 min to 1200+, not that much more. What did I misunderstood ? think there is a formula... ~20% of (opponent's glory) + ~500 (rough estimate)
|
|
inherit
Twisted Soul
834
0
Sept 21, 2018 9:49:47 GMT
454
Jonathan
"He who speaks without modesty will find it difficult to make his words good" - Confucius
808
July 2015
jonathanro
113
Twisted Soul
-
-
Example 3
|
Post by Jonathan on Mar 7, 2018 9:32:05 GMT
So I finally made it. Before any comment : - I'm a C# developer not a Python Developer, so all apologies if the script does not follow Python best practices ...I did my best with a few hours of reading on the net - Resize the BlueStacks window at the minimum, if you want the OCR to work nicely Prerequisites : - install Sikuli X (follow this guide Sikulix QuickStart ) - choose option 1 (with Python) and 3 (OCR) - launch the ide as explained in the guide - copy the script below in the IDE - edit the MIN_GLORY constant as you wish - start bluestacks - in bluestacks, start deck heroes - Resize the BlueStacks window at the minimum (best results for OCR) - in deck heroes, go to raids feature, in the opponent window - in sikulix ide, click on Run (say yes to save if asked) Enjoy !Interesting the code but: [user (07/03/18 10.28.34)] Raid Region Text : ,,_~ ~
[error] script [ Raiding ] stopped with error at line --unknown-- [error] Error caused by: Traceback (most recent call last): File "D:\Users\LROBU\Desktop\Raiding.sikuli\Raiding.py", line 86, in <module> info=RaidInfo.fromRegion(infoRegion); File "D:\Users\LROBU\Desktop\Raiding.sikuli\Raiding.py", line 36, in fromRegion power=int(m.group(1)); AttributeError: 'NoneType' object has no attribute 'group' Zero skill on programming for myself..
|
|
inherit
4276
0
84
skal75
WH lvl 5 runes status : not ready
274
May 21, 2017 12:45:54 GMT
May 2017
skal75
102
Revelations 2
skal75
|
Post by skal75 on Mar 7, 2018 10:10:02 GMT
So, I tested a little further and had some issues with OCR (quite normal).
To reduce these issues, I changed the script a little : - I continue to observe the raid info region (a rectangle that contains name, power and glory info) to be notified of the change of player after the click on Next Opponent - ... but I created a smaller region around glory points to extract glory points only (no more name and power) because OCR seems to be working quite well reading numbers - I added a popup at the end.
It works well. I used it while watching PSG - Real Madrid yesterday (what a disappointment this game...)
import re
WINDOW_NAME = "BlueStacks";
# minimum glory you want to raid for MIN_GLORY = 10000;
class AppRegion(Region):
def __init__(self,appName): switchApp(appName); self._window=App.focusedWindow(); Region.__init__(self,self._window); self.dbg(appName);
def dbg(self,appName): Debug.user("%s - x: %d, y: %d, w: %d, h: %d",appName, self.x,self.y,self.w, self.h); return;
class RaidInfoRegion(AppRegion): def __init__(self,appName): AppRegion.__init__(self,appName); textHeight=int((self._window.h*4.5)/100); textYPos=self.y+int((self._window.h*25.5)/100); self.setY(textYPos); self.setH(textHeight); AppRegion.dbg(self,"Raid Info");
class RaidGloryRegion(AppRegion):
def __init__(self,appName): AppRegion.__init__(self,appName); textHeight=int((self._window.h*4.5)/100); y=self.y+int((self._window.h*25.3)/100); x=int((self._window.w*67.7)/100); w=int((self._window.w*21.6)/100); self.setY(y); self.setH(textHeight); self.setX(self._window.x+x); self.setW(w); #self.highlight(); AppRegion.dbg(self,"Raid Glory");
def readGlory(self): t=self.text(); Debug.user("Raid Glory Text : %s",t); m=re.search("(\d+)",t); glory=int(m.group(1)); return glory;
class RaidNextOpponentButtonRegion(AppRegion):
def __init__(self,appName): AppRegion.__init__(self,appName); x=int((self._window.w*67.34)/100); y=int((self._window.h*77.25)/100); h=int((self._window.h*8.12)/100); w=int((self._window.w*21.2)/100); self.setX(self._window.x+x); self.setY(self._window.y+y); self.setH(h); self.setW(w); AppRegion.dbg(self,"Next Opponent Button");
# # main program #
def changed(event): Debug.user("something changed"); event.stopObserver();
gloryRegion=RaidGloryRegion(WINDOW_NAME); infoRegion=RaidInfoRegion(WINDOW_NAME); bt=RaidNextOpponentButtonRegion(WINDOW_NAME); infoRegion.onChange(50,changed);
glory = 0;
while True:
glory=gloryRegion.readGlory();
if (glory >= MIN_GLORY) : break;
bt.click()
infoRegion.observe(5)
popup("Hey! I found a guy with "+ str(glory) + " glory!");
|
|
nuke
Nightraider
Posts: 91
inherit
4486
0
8
nuke
91
Aug 29, 2017 21:30:09 GMT
August 2017
nuke
|
Post by nuke on Mar 7, 2018 19:15:32 GMT
Can it work with Nox? Bluestacks will never be installed again on my PC after I logged in one time then someone in China tried to log into the same account. Luckily I had 2-factor authentication. Trust lost.
|
|
inherit
4276
0
84
skal75
WH lvl 5 runes status : not ready
274
May 21, 2017 12:45:54 GMT
May 2017
skal75
102
Revelations 2
skal75
|
Post by skal75 on Mar 7, 2018 19:20:47 GMT
nuke and others interested in this : please contact me on Line
|
|
nuke
Nightraider
Posts: 91
inherit
4486
0
8
nuke
91
Aug 29, 2017 21:30:09 GMT
August 2017
nuke
|
Post by nuke on Mar 7, 2018 19:27:21 GMT
nuke and others interested in this : please contact me on Line Will do. Thanks and sorry for the double post. Accident. Line name?
|
|
inherit
4276
0
84
skal75
WH lvl 5 runes status : not ready
274
May 21, 2017 12:45:54 GMT
May 2017
skal75
102
Revelations 2
skal75
|
Post by skal75 on Mar 8, 2018 11:25:47 GMT
This will probably be the last update concerning this raiding tool. As it works nicely, I consider it done. This post is made to help people have a chance to make it work with other emulators. PLEASE READ THIS CAREFULLY, I UPDATED THE STEPS I - Installation - install Sikuli X (follow this guide Sikulix Quickstart ) - choose option 1 (with Python) and 3 (OCR) - launch the ide as explained in the guide - go to Preferences, click on more options and check the TextSearch and OCR checkboxes (allow searching for text, allow OCR) - copy the script below in the IDE - edit the MIN_GLORY constant as you wish - if you don't use BlueStacks, edit the WINDOW_NAME constant (name of the window in which your emulator runs) II - Running the tool
- launch the Sikulix IDE - start deck heroes in your favourite emulator (I used Bluestacks) - Resize the emulator window at the minimum (best results for OCR) - in deck heroes, go to raids feature, in the opponent window - in sikulix ide, click on Run (say yes to save if asked) - WHEN THE TOOL RUNS, DO NOT OVERLAP THE EMULATOR WINDOW, THE TOOL NEEDS TO TAKE PICTURES OF THE SCREEN (OCR). ELSE IT WONT WORK. III - Make it workNormally, it works with BlueStacks. That does not mean it cant work with other emulators. As it is, when launched you will see 3 rectangles (regions being highlighted. First one should be around what I call the Raid info region (name, power, glory) Second one should be around the glory amount. Third one should be around the next opponent button. if that's not the case, it won't work. Everything you have to do is tweaking the ratios here : clipWidth=int(((self.w * 8.43)/100.0)); clipheight=int(((self.h * 7.58)/100.0));
w=self.w - (clipWidth*2); h=self.h - (clipheight*2);
yOffset=int(h/20.0); y=self.y + clipheight + yOffset; xOffset= 0 # -int(w/20.0); x=self.x + clipWidth + xOffset;
During the tweaking, just comment out these two lines of code (put a # at the start) glory = r.findOpponent(MIN_GLORY); popup("Hey! I found a guy with "+ str(glory) + " glory!");
Edit the ratios, launch it. Repeat until the regions are nicely set. ... and uncomment the code (remove the #) IV - The code import re
class RegionDebugger:
def __init__(self,region): self._region=region; pass;
def highlight(self,rows,cols, seconds): for col in xrange(0,cols): for row in xrange(0,rows): p=self._region.getCell(row,col); p.highlight(seconds);
class AppRegion(Region):
def __init__(self,appName): switchApp(appName); self._window=App.focusedWindow(); Region.__init__(self,self._window); self.dbg(appName);
def dbg(self,appName): Debug.user("%s - x: %d, y: %d, w: %d, h: %d",appName, self.x,self.y,self.w, self.h); return;
def changed(event): #Debug.user("something changed"); event.stopObserver();
class RaidsRegion(AppRegion): cols=3 rows=8
def readGlory(self): t=self.__gp.text(); Debug.user("Raid Glory Text : %s",t); m=re.search("(\d+)",t); glory=int(m.group(1)); return glory;
def changeOpponent(self): self.__bt.click();
def findOpponent(self, minGlory): self.__ir.onChange(50,changed); glory = 0; while True: glory=self.readGlory();
if (glory >= minGlory) : break;
self.changeOpponent(); self.__ir.observe(5);
return glory;
def __init__(self,appName): AppRegion.__init__(self,appName);
# the empty left and right zones to remove clipWidth=int(((self.w * 8.43)/100.0));
# the top and bottom zones around deck heroes # they correspond to bluestacks elements clipheight=int(((self.h * 7.58)/100.0));
# computing width and height w=self.w - (clipWidth*2); h=self.h - (clipheight*2); # a vertical offset to define a nice grid that will # contain cells surrounding glory amount and next opponent button yOffset=int(h/20.0); y=self.y + clipheight + yOffset; # same idea for horizontal offset xOffset= 0 # -int(w/20.0); x=self.x + clipWidth + xOffset; # define region self.setX(x); self.setW(w); self.setY(y); self.setH(h); # define grid
# works in sikulix 1.1.1 #self.setRows(self.rows); #self.setCols(1);
# works in sikulix 1.1.2 self.setRaster(self.rows, 1);
# set info region self.__ir = Region(self.getCell(1,0)); self.__ir.highlight(1); # works in sikulix 1.1.1 #self.setCols(self.cols);
# works in sikulix 1.1.2 self.setRaster(self.rows, self.cols);
# set glory amount region self.__gp = self.getCell(1,2); self.__gp.highlight(1); # set next opponent button region self.__bt = self.getCell(6,2); self.__bt.highlight(1);
# # main program #
# name of your emulator window WINDOW_NAME = "BlueStacks";
# minimum glory you want to raid for MIN_GLORY = 10000;
r=RaidsRegion(WINDOW_NAME); #RegionDebugger(r).highlight(r.rows,r.cols,1);
glory = r.findOpponent(MIN_GLORY); popup("Hey! I found a guy with "+ str(glory) + " glory!");
|
|
nuke
Nightraider
Posts: 91
inherit
4486
0
8
nuke
91
Aug 29, 2017 21:30:09 GMT
August 2017
nuke
|
Post by nuke on Mar 8, 2018 19:14:45 GMT
This will probably be the last update concerning this raiding tool. As it works nicely, I consider it done. This post is made to help people have a chance to make it work with other emulators. PLEASE READ THIS CAREFULLY, I UPDATED THE STEPS *** Steps Follow ***
Excellent. Thank you.
|
|
nuke
Nightraider
Posts: 91
inherit
4486
0
8
nuke
91
Aug 29, 2017 21:30:09 GMT
August 2017
nuke
|
Post by nuke on Mar 8, 2018 19:16:37 GMT
Couldn't find you in Line by the way. Try mine: "nukeson". I would love to keep in touch and update you on how it works
|
|
inherit
4276
0
84
skal75
WH lvl 5 runes status : not ready
274
May 21, 2017 12:45:54 GMT
May 2017
skal75
102
Revelations 2
skal75
|
Post by skal75 on Mar 9, 2018 10:48:05 GMT
1) s*** happens : an update of Sikulix it's now in 1.1.2 and the script was no longer working with it. I'll update the script accordingly
2) thanks to nuke we validated the bot for Nox too. Just replace h=self.h - (clipheight*2); by h=self.h - clipheight; because nox has no bottom row.
|
|
nuke
Nightraider
Posts: 91
inherit
4486
0
8
nuke
91
Aug 29, 2017 21:30:09 GMT
August 2017
nuke
|
Post by nuke on Mar 9, 2018 10:58:16 GMT
Works great! I set MIN_GLORY to 1000 for this test. Many thanks, skal75!
|
|
inherit
2227
0
Dec 25, 2018 18:50:07 GMT
29
Doomkin✪NFS
97
Dec 23, 2015 14:51:28 GMT
December 2015
doomkin
|
Post by Doomkin✪NFS on Mar 9, 2018 15:00:00 GMT
Warning to all - be careful of your glory settings. When I was running my tool to search for 15k+ over a year ago, I woke up once to 100million gold missing. Don't be too greedy, consider setting a specific raiding deck (if not already), maybe consider adding a timeout feature that after so many failed attempts, it waits so many minutes before continuing. Very simple to add if desired.
|
|