def com_evolve(client, arguments=None): """ Dispatches a thread to: Evolves all of current char's enhancer cards """ # Are we currently active? if client.robin["char"] is None: client.send("You need to activate a character first.\n") return # No arguments if arguments is None: """ t = MenuStr() t.add("Possible options are:") t.add(" ^cevolve start^~ - Start evolving all feeders") t.add(" ^cevolve cancel^~ - Cancel evolutions in progress") client.send_cc(t.get()) return """ arguments = "start" # Parse arg1: either 'start' or 'cancel' arg1list = ["start", "cancel"] candidates = expand(arguments, arg1list)[0] if len(candidates) == 0 or len(candidates) > 1: t = MenuStr() t.add("Possible options are:") t.add(" ^cevolve start^~ - Start evolving all feeders") t.add(" ^cevolve cancel^~ - Cancel evolutions in progress") client.send_cc(t.get()) return arg1 = candidates[0] if arg1 == "start": # Make sure we aren't already running a dispatcher if "dispatcher" in client.robin: if client.robin["dispatcher"].is_alive(): client.send_cc(MenuStr("You need to ^ccancel^~ any running commands first.").get()) return client.send_cc("\n[Evolving feeders]\n") # DispatcherThread config # Preamble strings pre_console = "[{}] Evolving feeders...".format(client.robin["char"].name) # Worker thread work_target = client.robin["char"].evolve work_extra_args = () name = "[{}] Evolve".format(client.robin["char"].name) client.robin["dispatcher"] = DispatcherThread(client, pre_console, work_target, work_extra_args, name) client.robin["dispatcher"].start() elif arg1 == "cancel": client.robin["dispatcher"].queue.put("CANCEL") client.send("Cancelling...") return
def com_update(client, arguments=None): """ Update the active character """ # Are we currently active? if client.robin["char"] is None: t = MenuStr() t.add("You need to activate a character to use this command.") t.add("To update a non-active character, use the ^cchar update^~ command.") client.send_cc(t.get()) return client.robin["char"].update() client.send("Stats updated.\n")
def loadchars(self): ''' Loads characters from file Characters loaded are automatically scheduled for an update between 0.5 and 10mins later ''' console = ConsoleEngine() y = console.logtask("Loading character sessions from file...") t = MenuStr() with self.filelock: try: f = open(Config.charsave, 'r') tempchars = pickle.load(f) f.close() except IOError: console.logstatus(y, "[FAILED]") console.log("File '{}' not available for reading.".format(Config.charsave)) return except: console.logstatus(y, "[FAILED]") console.log("Error reading '{}'".format(Config.charsave)) return for x in tempchars.keys(): tchar = tempchars[x] # Check last update time - we don't want anything too old currtime = datetime.datetime.now() sinceupdate = currtime - tchar.lastupdatetime maxage = Config.maxloadage if (maxage > 150): maxage = 150 smaxage = maxage * 60 if (sinceupdate.seconds > smaxage): # Too old console.log("Load: Skipped [{}] - Session too stale".format(tchar.name)) t.add("Skipping [{}]: Session too stale.".format(tchar.name)) continue # Check if same as existing character if (tchar.name in self.chars): # If so, see which has a fresher logon tsl = currtime - tchar.logontime sl = currtime - self.chars[tchar.name].logontime if (tsl < sl): console.log("Load: Overrode [{}] - Fresher logon".format(tchar.name)) t.add("Overriding [{}]: Fresher logon.".format(tchar.name)) else: console.log("Load: Skipped [{}] - Not fresher than existing logon".format(tchar.name)) t.add("Skipping [{}]: Not fresher than existing logon.".format(tchar.name)) continue else: # New character console.log("Load: Added [{}]".format(tchar.name)) t.add("Adding [{}]".format(tchar.name)) # If we haven't continued by now, it's a valid character self.chars[tchar.name] = tchar self.chars[tchar.name].lock = threading.Lock() # Done. Let the other threads have at it self.chars[tchar.name].nextupdate = datetime.timedelta(seconds=(random.randint(30, 600))) console.logstatus(y, "[OK]") return t.get()
def sell(self, outqueue, inqueue): ''' Sell rupie cards Return output to user using queue @keyword outqueue: Queue to buffer output in. Sending "END" signals completion @keyword inqueue: Queue to listen for input. Receiving "CANCEL" signals cancellation. ''' conn = ROBConn() # Emulate sale list presses t = MenuStr("\n\nEmulating sale list presses...") outqueue.put(t.get()) conn.geturl('card_list', self.conn_session, send_session=self.session, send_viewer=self.viewer) # Scrape initial sales page soup = conn.geturl('card_sale/index', self.conn_session, send_viewer=self.viewer) # Check to see if 'All' is selected if (soup.find("div", "tabArea").find("a", href=re.compile("http://bahamut-n.cygames.jp/bahamut_n/card_sale/index/0"))): url = soup.find("div", "tabArea").find("a", href=re.compile("http://bahamut-n.cygames.jp/bahamut_n/card_sale/index/0"))['href'] url = re.match("http://bahamut-n.cygames.jp/bahamut_n/(.*)", url).group(1) # Add viewer ourselves to avoid confusing ROBConn if '?' not in url: raise RuntimeError url = url + "&viewer_id=" + self.viewer outqueue.put(MenuStr("Setting display filter to 'All'...").get()) soup = conn.geturl(url, self.conn_session) # Now check to see if sort order is 'last obtained' orderform = soup.find("form") if (orderform.find("option", selected=True).get_text() != 'Last Obtained'): # Prepare to make it so vals = [] vals.append(('sort_type', orderform.find(text=re.compile("Last Obtained")).find_parent("option")['value'])) for x in orderform.find_all("input"): if (x["type"] == 'submit'): continue vals.append((x["name"], x["value"])) query = urllib.urlencode(vals) headers = {'Cache-Control': 'max-age=0', 'Origin': 'http://bahamut-n.cygames.jp', 'Referer': conn.getreferer(self.viewer)} url = re.match("http://bahamut-n.cygames.jp/bahamut_n/(.*)", orderform['action']).group(1) outqueue.put(MenuStr("Setting sort order to 'last obtained'...").get()) soup = conn.geturl(url, self.conn_session, postdata=query, extra_headers=headers) # Ready to scrape sell_list, form = self._sell_scrape(soup) # Prepare pagelist pagelist = soup.find_all("a", "a_link") pagelist = pagelist = [re.match("http://bahamut-n.cygames.jp/bahamut_n/(.*)", y['href']).group(1) for y in pagelist] noDupes = [] [noDupes.append(i) for i in pagelist if not noDupes.count(i)] pagelist = noDupes # If there is only the one page and we have no suitable sale candidates: if (len(pagelist) == 0 and len(sell_list) == 0): outqueue.put("\nNo more cards to sell.\n") outqueue.put("END") return # If we're still here, recurse over pagelist looking for sales pagecount = 0 while (len(sell_list) == 0): if ((pagecount + 1) > len(pagelist)): # We reached the end of the pagelist outqueue.put("\nNo more cards to sell.\n") outqueue.put("END") return soup = conn.geturl(pagelist[pagecount], self.conn_session, send_viewer=self.viewer) sell_list, form = self._sell_scrape(soup) pagecount += 1 # If we're still here, we found sale candidates. t = MenuStr() t.add("\nSelling:") t.add(pprint.pformat(sell_list)) t.add() outqueue.put(t.get()) # Get sale confirmation form vallist = [] for x in sell_list: vallist.append(('sleeve[]', x[0])) vallist = urllib.urlencode(vallist) eurl = re.match("http://bahamut-n.cygames.jp/bahamut_n/(.*)", form['action']).group(1) ehead = {'Cache-Control': 'max-age=0', 'Origin': 'http://bahamut-n.cygames.jp', 'Referer': conn.getreferer(self.viewer)} # Go or no go? try: if (inqueue.get(False) == "CANCEL"): outqueue.put(MenuStr("Cancelled.").get()) outqueue.put("END") return except Queue.Empty: pass # Getting soup = conn.geturl(eurl, self.conn_session, postdata=vallist, extra_headers=ehead) # Scrape the received confirmation form eform = soup.find("form") eurl = re.match("http://bahamut-n.cygames.jp/bahamut_n/(.*)", eform['action']).group(1) ehead = {'Cache-Control': 'max-age=0', 'Origin': 'http://bahamut-n.cygames.jp', 'Referer': conn.getreferer(self.viewer)} # Duplicate all form data evals = eform.find_all("input") equery = [] for x in evals[:]: if (x["type"] == 'submit'): continue equery.append((x["name"], x["value"])) equery = urllib.urlencode(equery) # Last chance to cancel try: if (inqueue.get(False) == "CANCEL"): outqueue.put(MenuStr("Cancelled.").get()) outqueue.put("END") return except Queue.Empty: pass # Push button soup = conn.geturl(eurl, self.conn_session, postdata=equery, extra_headers=ehead) # Done. Give a status update self.update() t = "Sold. [C:{}/{} S:{}/{} R:{}]".format(self.cards, self.maxcards, self.stamina, self.maxstamina, self.rupies) outqueue.put(t) # Recurse? As long as this is the final call self.sell(outqueue, inqueue)
def evolve(self, outqueue, inqueue): ''' Evolve feeders in inventory as much as possible Return output to user using queue @keyword outqueue: Queue to buffer output in. Sending "END" signals completion @keyword inqueue: Queue to listen for input. Receiving "CANCEL" signals cancellation. ''' # Start by checking current rupies self.update() if (int(self.rupies) < 575): t = MenuStr("\n\n^RInsufficient Rupies.^~ [C:{}/{} S:{}/{} R:{}]".format(self.cards, self.maxcards, self.stamina, self.maxstamina, self.rupies)) outqueue.put(t.get()) outqueue.put("END") return conn = ROBConn() anti_infinite = [] # 1. Scrape current evolve menu soup = conn.geturl('card_union', self.conn_session, send_session=self.session, send_viewer=self.viewer) if re.search('card_union/union_card', conn.getreferer(self.viewer)): # We were redirected to new base page # Send along cached new base data t = self._evo_newbase(soup) if not t: outqueue.put(MenuStr("\n\nNo available bases.").get()) outqueue.put("END") return else: anti_infinite.append(t[0]) soup = t[1] # Find card id tuple for current base base = soup.find(text=re.compile("Change card to evolve")).find_parent("div").div.get_text() base = [str.strip(str(x)) for x in base.split("\n")] while '' in base: base.remove('') base = tuple(base) # Make sure current base is in EvolveTable if base not in EvolveTable: t = self._evo_newbase() if not t: outqueue.put(MenuStr("\n\nNo available bases.").get()) outqueue.put("END") return else: anti_infinite.append(t[0]) soup = t[1] # Determine new base base = soup.find(text=re.compile("Change card to evolve")).find_parent("div").div.get_text() base = [str.strip(str(x)) for x in base.split("\n")] while '' in base: base.remove('') base = tuple(base) t = MenuStr() basestr = pprint.pformat(base) t.add("\n\nUsing base: {}".format(basestr)) outqueue.put(t.get()) # Search for level 1 material in material list level1 = EvolveTable[base]['Material'] matlink = self._evo_newmatlink(soup, level1) # Until we get a link to a proper level1 for a base, we'll keep recursing. while not matlink: outqueue.put(MenuStr("Could not find level 1 materials. Looking for new base...").get()) t = self._evo_newbase() if not t: outqueue.put(MenuStr("\n\nNo available bases.").get()) outqueue.put("END") return else: if t[0] in anti_infinite: y = MenuStr("\n\n** Infinite loop detected! **") y.add("This probably means you have two or more feeder cards of the same kind that are higher than level 1.") y.add("Please manually evolve your feeders so that for each card-type there is only one high level card and the rest are all level 1.") outqueue.put(y.get()) outqueue.put("END") return anti_infinite.append(t[0]) soup = t[1] # Do we abort after finding the new base? try: if (inqueue.get(False) == "CANCEL"): outqueue.put(MenuStr("Cancelled.").get()) outqueue.put("END") return except Queue.Empty: pass # Find card id tuple for current base base = soup.find(text=re.compile("Change card to evolve")).find_parent("div").div.get_text() base = [str.strip(str(x)) for x in base.split("\n")] while '' in base: base.remove('') base = tuple(base) t = MenuStr() basestr = pprint.pformat(base) t.add("\n\nUsing base: {}".format(basestr)) outqueue.put(t.get()) # Search for level 1 material in material list level1 = EvolveTable[base]['Material'] matlink = self._evo_newmatlink(soup, level1) outqueue.put(MenuStr("Evolving using {}...".format(pprint.pformat(level1))).get()) # Go or no go? try: if (inqueue.get(False) == "CANCEL"): outqueue.put(MenuStr("Cancelled.").get()) outqueue.put("END") return except Queue.Empty: pass # Evolve button form soup = conn.geturl(matlink, self.conn_session, send_viewer=self.viewer) eform = soup.find("form") eurl = re.match("http://bahamut-n.cygames.jp/bahamut_n/(.*)", eform['action']).group(1) evals = eform.find_all("input") equery = [] # Copy all form values, make sure the submit button is there submitfound = False for x in evals[:]: if (x["type"] == 'submit'): submitfound = True else: equery.append((x["name"], x["value"])) if (not submitfound) or (re.match("(?i)Insufficient rupies", soup.encode(formatter=None))): t = MenuStr("\n^RInsufficient Rupies.^~ [C:{}/{} S:{}/{} R:{}]".format(self.cards, self.maxcards, self.stamina, self.maxstamina, self.rupies)) outqueue.put(t.get()) outqueue.put("END") return equery = urllib.urlencode(equery) ehead = {'Cache-Control': 'max-age=0', 'Origin': 'http://bahamut-n.cygames.jp', 'Referer': conn.getreferer(self.viewer)} # Last chance to cancel try: if (inqueue.get(False) == "CANCEL"): outqueue.put(MenuStr("Cancelled.").get()) outqueue.put("END") return except Queue.Empty: pass # Submit form and touch flash soup = conn.geturl(eurl, self.conn_session, postdata=equery, extra_headers=ehead) furl = re.findall(r"(?<=\"http://bahamut-n.cygames.jp/bahamut_n/)card_union.*?(?=\")", soup.encode(formatter=None))[0] #furl = re.match("http://bahamut-n.cygames.jp/bahamut_n/(.*)", form['action']).group(1) conn.geturl(furl, self.conn_session, extra_headers={'Referer': conn.getreferer(self.viewer)}, flash=True, spammy=True) # Done one evolution self.update() t = "^GEvolved^~. [C:{}/{} S:{}/{} R:{}]".format(self.cards, self.maxcards, self.stamina, self.maxstamina, self.rupies) outqueue.put(t) # Recurse? As long as this is the final call self.evolve(outqueue, inqueue)
def fillcards(self, outqueue, inqueue, quest, minstamina): ''' Given quest parameters, fill card storage with cards Return output to user using queue @keyword quest: String of the form "<chapter>/<quest>" @keyword minstamina: Minimum stamina at which to attempt quest @keyword outqueue: Queue to buffer output in. Sending "END" signals completion @keyword inqueue: Queue to listen for input. Receiving "CANCEL" signals cancellation. ''' # Start by checking current cards/stamina self.update() if (self.cards == self.maxcards) or (int(self.stamina) < minstamina): t = MenuStr("\n\nNothing to do here. [C:{}/{} S:{}/{} R:{}]".format(self.cards, self.maxcards, self.stamina, self.maxstamina, self.rupies)) outqueue.put(t.get()) outqueue.put("END") return False conn = ROBConn() # soup = conn.geturl('mypage', self.conn_session, send_session=self.session, send_viewer=self.viewer) # Emulate quest list presses t = MenuStr("\n\nEmulating quest list presses...") outqueue.put(t.get()) conn.geturl('quest', self.conn_session, send_session=self.session, send_viewer=self.viewer) conn.geturl('quest/quest_list', self.conn_session, send_viewer=self.viewer) conn.geturl('quest/mission_list/{}'.format(quest.split('/')[0]), self.conn_session, send_viewer=self.viewer) # Grab peripherals only the first time (emulating browser back presses) first = True while (self.cards != self.maxcards) and (int(self.stamina) >= minstamina): # Before hitting the server for the flash, check for cancel signal try: if (inqueue.get(False) == "CANCEL"): outqueue.put(MenuStr("Cancelled.").get()) outqueue.put("END") return False except Queue.Empty: pass # Force a post soup = conn.geturl('smart_phone_flash/questConvert/{}'.format(quest), self.conn_session, get_peripherals=first, postdata='') first = False # No Stamina (safety; should not get called) if re.match('http://bahamut-n.cygames.jp/bahamut_n/quest/life_empty', conn.getreferer(self.viewer)): t = MenuStr("") t.add("No more stamina.") outqueue.put(t.get()) outqueue.put("END") return False # Touch the quest flash url = re.findall(r"quest/play/{}\?flashParam=[0-9]*".format(quest), soup.encode(formatter=None))[0] conn.geturl(url, self.conn_session, extra_headers={'Referer': conn.getreferer(self.viewer)}, flash=True, spammy=True) self.update() t = MenuStr("^GQuest run^~. [C:{}/{} S:{}/{} R:{}]".format(self.cards, self.maxcards, self.stamina, self.maxstamina, self.rupies)) outqueue.put(t.get()) # Done t = MenuStr("") if (int(self.stamina) < minstamina): t.add("No more stamina.") elif (self.cards == self.maxcards): t.add("Card list full.") outqueue.put(t.get()) outqueue.put("END") return True
def com_char(client, arguments=None): engine = ROBEngine() # No arguments - show available characters if arguments is None: t = MenuStr() t.add(" Currently Available Characters:") t.add(" -------------------------------") chars = engine.getchars() if len(chars) == 0: t.add(" None") t.add() else: for x in chars: char = engine.getchar(x) if char.updating: updating = "[Updating]" else: updating = "" t.add(" ^G{:15}^~ ^R[^C{}^R]^~".format(char.name, char.agent)) t.add( " ^gC:{:8} S:{:10} R:{:10}^~ ^r{}^~".format( "{}/{}".format(char.cards, char.maxcards), "{}/{}".format(char.stamina, char.maxstamina), char.rupies, updating, ) ) t.add(" ^K?session_id={}&viewer_id={}^~".format(char.session, char.viewer)) currtime = datetime.datetime.now() sincelogon = currtime - char.logontime slmin, slsec = divmod(sincelogon.seconds, 60) slhr, slmin = divmod(slmin, 60) slhr += sincelogon.days * 24 slstr = "Logon: {:02d}:{:02d}:{:02d} ago".format(slhr, slmin, slsec) sinceupdate = currtime - char.lastupdatetime sumin, susec = divmod(sinceupdate.seconds, 60) suhr, sumin = divmod(sumin, 60) suhr += sinceupdate.days * 24 sustr = "Updated: {:02d}:{:02d}:{:02d} ago".format(suhr, sumin, susec) t.add(" {:29}{}".format(slstr, sustr)) numin, nusec = divmod(char.nextupdate.seconds, 60) nustr = "Auto-refresh in: {:02d}:{:02d}".format(numin, nusec) t.add(" {:29}".format(nustr)) t.add() t.add(" ^cchar add [adb|<sessionstring>] [sensation|desire]^~ to add characters") t.add(" ^cchar delete <name>^~ to remove characters") t.add(" ^cchar update [all|<name>]^~ to update character stats") t.add(" ^cchar use <name>^~ to take control of a character") t.add(" ^cchar [save|load]^~ to save or load characters to/from disk") client.send_cc(t.get()) return # Arguments passed. Expand # e.g. 'char add sensation adb' # 'char': command; 'add': arg1; 'sensation': arg2; etc. arg1list = ["add", "delete", "update", "use", "save", "load"] candidates, rawarg2 = expand(arguments, arg1list) if len(candidates) == 0: t = MenuStr() t.add("Possible options are:") t.add() t.add(" ^cchar add [adb|<sessionstring>] [sensation|desire]^~ to add characters") t.add(" ^cchar delete <name>^~ to remove characters") t.add(" ^cchar update [all|<name>]^~ to update character stats") t.add(" ^cchar use <name>^~ to take control of a character") t.add(" ^cchar [save|load]^~ to save or load characters to/from disk") client.send_cc(t.get()) return elif len(candidates) > 1: t = MenuStr() t.add("The command ^cchar {}^~ was not specific enough. Did you mean:".format(arguments.split(None, 1)[0])) for x in candidates: t.add(" ^cchar {}^~".format(x)) client.send_cc(t.get()) return elif len(candidates) == 1: arg1 = candidates[0] # Got arg1 # Add if arg1 == "add": # Need to parse for arg2(method) and arg3(device) # arg2 is taken without modification: it either matches 'adb' exactly, or is treated as a session string if rawarg2 is None: # No arg2 passed t = MenuStr() t.add("Possible options are:") t.add() t.add(" ^cchar add adb [sensation|desire]^~") t.add(" Look for recent sessions over ADB, use [sensation|desire] headers.") t.add() t.add(" ^cchar add <sessionstring> [sensation|desire]^~") t.add(" Add a character using <sessionstring>, use [sensation|desire] headers.") t.add(" (?session_id=<session>&viewer_id=<viewer>)") t.add() t.add("You must ensure the headers chosen match the device used to start the session.") client.send_cc(t.get()) return rawarg2 = rawarg2.split(None, 1) arg2 = rawarg2[0] # Parse rawarg3 if len(rawarg2) == 1: # No arg3 passed t = MenuStr() t.add("Possible options are:") t.add() if arg2 == "adb": t.add(" ^cchar add adb [sensation|desire]^~") t.add(" Look for recent sessions over ADB, use [sensation|desire] headers.") else: t.add(" ^cchar add <sessionstring> [sensation|desire]^~") t.add(" Add a character using <sessionstring>, use [sensation|desire] headers.") t.add(" (^K?session_id=<session>&viewer_id=<viewer>^~)") t.add() t.add("You must ensure the headers chosen match the device used to start the session.") client.send_cc(t.get()) return rawarg3 = rawarg2[1] arg3list = ["sensation", "desire"] candidates = expand(rawarg3, arg3list)[0] if len(candidates) == 0 or len(candidates) > 1: t = MenuStr() t.add("Possible options are:") t.add() if arg2 == "adb": t.add(" ^cchar add adb [sensation|desire]^~") t.add(" Look for recent sessions over ADB, use [sensation|desire] headers.") else: t.add(" ^cchar add <sessionstring> [sensation|desire]^~") t.add(" Add a character using <sessionstring>, use [sensation|desire] headers.") t.add(" (^K?session_id=<session>&viewer_id=<viewer>^~)") t.add() t.add("You must ensure the headers chosen match the device used to start the session.") client.send_cc(t.get()) return else: arg3 = candidates[0] # If we're still here, add a character using the options given t = engine.addchar(arg2, arg3) if t == "CANCELLED": client.send("Character add cancelled by server.\n") elif t == "FAILED": client.send("No recent sessions found over ADB.\n") elif t == "MAINTENANCE": client.send("ROB Servers undergoing maintenance.\n") else: client.send_cc("Successfully added [^G{}^~] with ^R[^C{}^R]^~ headers\n".format(t, arg3)) return # Delete char if arg1 == "delete": if rawarg2 is None: # No arg2 t = MenuStr() t.add("Possible options are:") t.add(" ^cchar delete <name>^~ - Remove a character from the character list") t.add() t.add("Available characters:") for x in engine.getchars(): t.add(" ^G{}^~".format(x)) client.send_cc(t.get()) return # Parse arg2: a character name arg2list = [] for x in engine.getchars(): arg2list.append(x) candidates = expand(rawarg2, arg2list)[0] if len(candidates) == 0: t = MenuStr() t.add("No such character. Choices are:") for x in arg2list: t.add(" ^G{}^~".format(x)) client.send_cc(t.get()) return else: arg2 = candidates[0] char = engine.getchar(arg2) if client.robin["char"] == char: client.robin["char"] = None engine.delchar(arg2) client.send_cc("Removed ^G{}^~ from character list.\n".format(char.name)) return if arg1 == "update": # Parse arg2: either 'all' or a character name if rawarg2 is None: # No arg2 t = MenuStr() t.add("Possible options are:") t.add(" ^cchar update all^~ - Manually update all characters (SLOW)") t.add(" ^cchar update <name>^~ - Manually update a character") t.add() t.add("Available characters:") for x in engine.getchars(): t.add(" ^G{}^~".format(x)) client.send_cc(t.get()) return arg2list = ["all"] for x in engine.getchars(): arg2list.append(x) candidates = expand(rawarg2, arg2list)[0] if len(candidates) == 0: t = MenuStr() """ t.add("Possible options are:") t.add(" ^cchar update all^~ - Manually update all characters (SLOW)") t.add(" ^cchar update <name>^~ - Manually update a character") """ t.add("No such character. Choices are:") t.add(" ^call^~") for x in engine.getchars(): t.add(" ^G{}^~".format(x)) client.send_cc(t.get()) return elif len(candidates) > 1: t = MenuStr() t.add( "The command ^cchar update {}^~ was not specific enough. Did you mean:".format( rawarg2.split(None, 1)[0] ) ) for x in candidates: t.add(" ^cchar update {}^~".format(x)) client.send_cc(t.get()) return else: arg2 = candidates[0] if arg2 == "all": client.send("Not implemented. Please specify a character name.\n") return else: char = engine.getchar(arg2) char.update() client.send("Stats updated.\n") return if arg1 == "use": if rawarg2 is None: # No arg2 t = MenuStr() t.add("Possible options are:") t.add(" ^cchar use <name>^~ - Take control of a character") t.add() t.add("Available characters:") for x in engine.getchars(): t.add(" ^G{}^~".format(x)) client.send_cc(t.get()) return # Parse arg2: a character name arg2list = [] for x in engine.getchars(): arg2list.append(x) candidates = expand(rawarg2, arg2list)[0] if len(candidates) == 0: t = MenuStr() t.add("No such character. Choices are:") for x in arg2list: t.add(" ^G{}^~".format(x)) client.send_cc(t.get()) return else: arg2 = candidates[0] char = engine.getchar(arg2) client.robin["char"] = char client.send_cc("Now controlling ^G{}^~.\n".format(char.name)) return # Save/Load if arg1 == "save": engine.savechars() client.send("Characters saved.\n") return if arg1 == "load": t = engine.loadchars() client.send_cc(t) return
def com_use(client, arguments=None): # No arguments if arguments is None: t = MenuStr() t.add("Possible options are:") t.add(" ^cuse <name>^~ - Take control of a character") client.send_cc(t.get()) return # Parse arg1: a character name engine = ROBEngine() arg1list = [] for x in engine.getchars(): arg1list.append(x) candidates = expand(arguments, arg1list)[0] if len(candidates) == 0: t = MenuStr() t.add("No such character. Choices are:") for x in arg1list: t.add(" ^G{}^~".format(x)) client.send_cc(t.get()) return else: arg1 = candidates[0] char = engine.getchar(arg1) client.robin["char"] = char client.send_cc("Now controlling ^G{}^~.\n".format(char.name)) return
def com_sell(client, arguments=None): """ Dispatches a thread to: Sell all farmed rupie cards """ # Are we currently active? if client.robin["char"] is None: client.send("You need to activate a character first.\n") return # No arguments if arguments is None: """ t = MenuStr() t.add("Possible options are:") t.add(" ^csell start^~ - Start selling all rupie cards") t.add(" ^csell cancel^~ - Cancel current sale operation") client.send_cc(t.get()) return """ arguments = "start" # Parse arg1: either 'start' or 'cancel' arg1list = ["start", "cancel", "loop"] candidates = expand(arguments, arg1list)[0] if len(candidates) == 0 or len(candidates) > 1: t = MenuStr() t.add("Possible options are:") t.add(" ^csell start^~ - Start selling all rupie cards") t.add(" ^csell cancel^~ - Cancel current sale operation") t.add(" ^csell loop^~ - Start Fill-Sell loop") client.send_cc(t.get()) return arg1 = candidates[0] if arg1 == "start": # Make sure we aren't already running a dispatcher if "dispatcher" in client.robin: if client.robin["dispatcher"].is_alive(): client.send_cc(MenuStr("You need to ^ccancel^~ any running commands first.").get()) return client.send_cc("\n[Selling cards]\n") # DispatcherThread config # Preamble strings pre_console = "[{}] Selling cards...".format(client.robin["char"].name) # Worker thread work_target = client.robin["char"].sell work_extra_args = () name = "[{}] Sell".format(client.robin["char"].name) client.robin["dispatcher"] = DispatcherThread(client, pre_console, work_target, work_extra_args, name) client.robin["dispatcher"].start() elif arg1 == "cancel": client.robin["dispatcher"].queue.put("CANCEL") client.send("Cancelling...") elif arg1 == "loop": # Make sure we aren't already running a dispatcher if "dispatcher" in client.robin: if client.robin["dispatcher"].is_alive(): client.send_cc(MenuStr("You need to ^ccancel^~ any running commands first.").get()) return client.send_cc("\n[Starting Fill-Sell Loop]\n") # DispatcherThread config # Preamble strings pre_console = "[{}] Fill-Sell loop...".format(client.robin["char"].name) # Worker thread work_target = client.robin["char"].loop_sell work_extra_args = () name = "[{}] Fill-Sell".format(client.robin["char"].name) client.robin["dispatcher"] = DispatcherThread(client, pre_console, work_target, work_extra_args, name) client.robin["dispatcher"].start() return
def com_score(client, arguments=None): char = client.robin["char"] # Prepare segments # Note that caret codes are counted as characters for format strings namestr = "[^G{}^~]".format(char.name) cardstr = "^C{}^~/^C{}^~".format(char.cards, char.maxcards) staminastr = "^R{}^~/^R{}^~".format(char.stamina, char.maxstamina) rupiesstr = "^Y{}^~".format(char.rupies) currtime = datetime.datetime.now() sincelogon = currtime - char.logontime slmin, slsec = divmod(sincelogon.seconds, 60) slhr, slmin = divmod(slmin, 60) slstr = "^K{:02d}^~:^K{:02d}^~:^K{:02d}^~ ago".format(slhr, slmin, slsec) sinceupdate = currtime - char.lastupdatetime sumin, susec = divmod(sinceupdate.seconds, 60) suhr, sumin = divmod(sumin, 60) sustr = "^K{:02d}^~:^K{:02d}^~:^K{:02d}^~ ago".format(suhr, sumin, susec) numin, nusec = divmod(char.nextupdate.seconds, 60) nustr = " ^K{:02d}^~:^K{:02d}^~ min".format(numin, nusec) t = MenuStr() t.add("=" * 70) t.add() t.add(" [^KLv. {:>3}^~] ".format(char.level)) t.add(" {:24} Device: ^R[^C{}^R]^~".format(namestr, char.agent)) t.add(" ^c?session_id={}&viewer_id={}^~".format(char.session, char.viewer)) t.add() t.add("=" * 70) t.add() t.add(" Cards: {:18} First logged on: {}".format(cardstr, slstr)) t.add(" Stamina: {:18} Last updated: {}".format(staminastr, sustr)) t.add(" Rupies: {:14} Auto-refresh in: {}".format(rupiesstr, nustr)) t.add() t.add("=" * 70) t.add() t.add(" ^GInbox^~:") t.add() for x in char.inbox: t.add(" {}".format(x[1])) t.add(" ^c{}^~".format(x[0])) t.add() client.send_cc(t.get())
def com_look(client, arguments=None): t = MenuStr() t.add("[^CThe Core^~]") t.add() t.add("You are standing in a large, white room, empty save for a") t.add("small computer terminal that flickers to life as you approach,") t.add("as if beckoning you to give it a command.") client.send_cc(t.get()) return
def com_fill(client, arguments=None): """ Dispatches a thread to: Fill current char's card storage with feeders, either rupies or enhancers """ # Are we currently active? if client.robin["char"] is None: client.send("You need to activate a character first.\n") return # No arguments if arguments is None: t = MenuStr() t.add("Possible options are:") t.add(" ^cfill enhancers^~ - Fill with cards from quest 2-5 (Best for enhancing)") t.add(" ^cfill rupies^~ - Fill with cards from quest 2-2 (Best for rupie farming)") t.add(" ^cfill cancel^~ - Cancel a fill in progress") client.send_cc(t.get()) return # Parse arg1: either 'enhancers' or 'rupies' or 'cancel' arg1list = ["enhancers", "rupies", "cancel"] candidates = expand(arguments, arg1list)[0] if len(candidates) == 0 or len(candidates) > 1: t = MenuStr() t.add("Possible options are:") t.add(" ^cfill enhancers^~ - Fill with cards from quest 2-5 (Best for enhancing)") t.add(" ^cfill rupies^~ - Fill with cards from quest 2-2 (Best for rupie farming)") client.send_cc(t.get()) return arg1 = candidates[0] if (arg1 == "enhancers") or (arg1 == "rupies"): if arg1 == "enhancers": quest = "2/5" minstamina = 3 elif arg1 == "rupies": quest = "2/2" minstamina = 3 # Make sure we aren't already running a dispatcher if "dispatcher" in client.robin: if client.robin["dispatcher"].is_alive(): client.send_cc(MenuStr("You need to ^ccancel^~ any running commands first.").get()) return client.send_cc("\n[Farming quest {}]\n".format(quest)) # DispatcherThread config # Preamble strings pre_console = "[{}] Filling with {}...".format(client.robin["char"].name, quest) # Worker thread work_target = client.robin["char"].fillcards work_extra_args = (quest, minstamina) name = "[{}] Fill {}".format(client.robin["char"].name, quest) client.robin["dispatcher"] = DispatcherThread(client, pre_console, work_target, work_extra_args, name) client.robin["dispatcher"].start() elif arg1 == "cancel": client.robin["dispatcher"].queue.put("CANCEL") client.send("Cancelling...") return
def com_colour(client, arguments=None): """ Send sample colour table to client """ t = MenuStr() t.add("Colours:") t.add(" ^^k = ^kblack^~") t.add(" ^^K = ^Kbold black (grey)^~") t.add(" ^^r = ^rred^~") t.add(" ^^R = ^Rbold red^~") t.add(" ^^g = ^ggreen^~") t.add(" ^^G = ^Gbold green^~") t.add(" ^^y = ^yyellow^~") t.add(" ^^Y = ^Ybold yellow^~") t.add(" ^^b = ^bblue^~") t.add(" ^^B = ^Bbold blue^~") t.add(" ^^m = ^mmagenta^~") t.add(" ^^M = ^Mbold magenta^~") t.add(" ^^c = ^ccyan^~") t.add(" ^^C = ^Cbold cyan^~") t.add(" ^^w = ^wwhite^~") t.add(" ^^W = ^Wbold white^~") t.add(" ^^! = ^!bold on (use within a block of non-bright text)^~") t.add(" ^^. = ^.bold off^~") t.add(" ^^d = ^ddefault text colors, varies by client^~") t.add(" ^^0 = ^0black background^~") t.add(" ^^1 = ^1red background^~") t.add(" ^^2 = ^2green background^~") t.add(" ^^3 = ^3yellow background^~") t.add(" ^^4 = ^4blue background^~") t.add(" ^^5 = ^5magenta background^~") t.add(" ^^6 = ^6cyan background^~") t.add(" ^^I = ^Iinverse text on^~") t.add(" ^^i = ^iinverse text off^~") t.add(" ^^~ = ^~reset all^~") t.add(" ^^U = ^Uunderline on^~") t.add(" ^^u = ^uunderline off^~") t.add(" ^^^^ = escape a caret, ^^^^r = ^^r^~") client.send_cc(t.get()) return