def use(self, item, quantity=1): """ Uses an item in the inventory Arguments: - `br`: Browser - `item`: Name of the item to use - `quantity`: number of quantity to use. -1 to use all """ name = item self.update_inventory() if type(item) is str: if item not in item_map: self.logger.write(log() + " Item not in db - " + str(item) + "\n") return None item = item_map[item] #get the item code if self.inventory[item] < quantity: self.logger.write(log() + " Item not available in sufficient quantity. item: " + str(item) + " quantity: " + str(quantity) + "\n") return None if quantity == -1: quantity = self.inventory[item] url = game_url + "Action.php?action=6&type=" + str(item) + "&IDParametre=0" while quantity > 0: #print url #for debug self.logger.write(log() + " Using item: " + str(name) + "\n") self.br.open(url, timeout=35) quantity-=1 self.refresh()
def hire(self, stat=None, wage=None, autobuy=True): """ Posts an advertisement at the townhall/calpulli. """ if self.can_hire(): if not self.prep_home_inventory(autobuy): self.char.logger.write(log() + " Don't have the necessary materials for hiring worker..QUIT HIRING\n") return False page = self.char.visit(myhome_url).read() s1 = "textePage["+str(self.number+1)+"]['Texte'] = '" s2 = "';" start = page.find(s1) + len(s1) end = page.find(s2, start) text = page[start:end] soup = BeautifulSoup(text) carac = soup.find("input", attrs={"name": "carac"})['value'] actionChamp = soup.find("input", attrs={"name": "actionChamp"})['value'] embauche = soup.find("input", attrs={"name": "embauche"})['value'] wage = self.wage_recommender() if (type(wage) is not int or not 12<=wage<=50) else wage stat = self.stat_recommender() if (type(stat) is not int or not 0<=stat<=19) else stat if wage > int(self.char.money): self.char.logger.write(log() + " Don't have enough money to hire...QUIT HIRING\n") return False url = game_url + "Action.php?action=18&champ=" + str(self.number-1) self.char.visit(url, urllib.urlencode({'actionChamp':str(actionChamp), 'carac':str(carac), 'embauche':str(embauche), 'salaire':str(wage), 'qualification':str(stat)})) self.char.logger.write(log() + " Posted a job for hiring a worker to work on field " + str(self.number) + "\n")
def login(self): """ Logs in to the game server. """ while self.is_server_under_maint(): time.sleep(120) logged_in = False while logged_in == False: try: response = self.br.open(loginform_url, data=urllib.urlencode({ 'login': self.name, 'password': self.password }), timeout=35) if response.geturl() == loginfail_url: self.logger.write(log() + "Wrong password\n") thread.exit() elif response.geturl() == game_url: #server under maint? self.logger.write(log() + " Server maybe under maintainance\n") time.sleep(120) else: logged_in = True except SystemExit, e: thread.exit() except:
def snooze_till_market_reset(char): """ Puts the caller to sleep till the market resets (all pending transactions are done). The markets reset at every 10th minute Arguments: - `char`: """ page = char.visit(market_url).read() s1 = "textePage[1]['Texte'] = '" s2 = "Sale" start = page.find(s1) + len(s1) end = page.find(s2, start) text = page[start:end].lower() if "each" in text: current_time = char.get_current_time() minutes_to_sleep = 10 - ( current_time[4] % 10) + 0.25 #to incorporate some delay for market reset char.logger.write(log() + " Waiting for items purchased from the market (" + str(minutes_to_sleep * 60) + " seconds)" + '\n') char.logout() time.sleep(minutes_to_sleep * 60) char.logger.write(log() + " Market transanctions done. Continuing.." + '\n') char.login() char.refresh()
def use(self, item, quantity=1): """ Uses an item in the inventory Arguments: - `br`: Browser - `item`: Name of the item to use - `quantity`: number of quantity to use. -1 to use all """ name = item self.update_inventory() if type(item) is str: if item not in item_map: self.logger.write(log() + " Item not in db - " + str(item) + "\n") return None item = item_map[item] #get the item code if self.inventory[item] < quantity: self.logger.write( log() + " Item not available in sufficient quantity. item: " + str(item) + " quantity: " + str(quantity) + "\n") return None if quantity == -1: quantity = self.inventory[item] url = game_url + "Action.php?action=6&type=" + str( item) + "&IDParametre=0" while quantity > 0: #print url #for debug self.logger.write(log() + " Using item: " + str(name) + "\n") self.br.open(url, timeout=35) quantity -= 1 self.refresh()
def harvester(char, rsc): """ Arguments: - `char`: The character object - `rsc`: The resource to be harvested """ if rsc not in resource.resource_list: char.logger.write(log() + " Illegal resource: " + str(rsc) + "\n") return False if char.activity != resource.get_resource_string(rsc) and char.is_working(): return False limit_Y = resource.get_max_Y_coordinate(rsc) max_yield = 0 chances = resource.get_max_moves(char, rsc) br = char.get_browser() x = 0 y = resource.set_Y_coordinate(char, rsc) max_X = x max_Y = y while chances > 1 and 0 <= y <= limit_Y: url = game_url+"Action.php?action=50&x=" + str(x) + "&y=" + str(y) try: br.open(url, timeout=35) except: char.logger.write(log() + " -ERROR OPENING URL: " + url + "\n") traceback.print_exc(file=char.logger) time.sleep(15) text = resource.get_resource_text(char) tmp = resource.get_yield(text, rsc) char.logger.write("X:" + str(x) + " Y:" + str(y) + " " + str(tmp) + "\n") if tmp > max_yield: max_yield = tmp max_X = x max_Y = y x = resource.update_X_coordinate(x, y, rsc) y = (y-1) if x == 0 else y m = re.search("(\d+)(/)(\d+)", text) chances = int(m.group(3)) - int(m.group(1)) char.visit(game_url+"Action.php?action=50&x="+str(max_X)+"&y="+str(max_Y)) max_Yield = resource.get_yield(resource.get_resource_text(char), rsc) result = char.is_working() char.logger.write(log() + " Harvest " + str(rsc) + " : " + str(result) + " (" + str(char.activity) + ")") if result: char.logger.write(" [X=" + str(max_X) + " Y=" + str(max_Y) + " " + str(max_yield) + "]") char.logger.write("\n") return result
def work_in_mine(char, duration=1, mine=None): """ Perform the activity of mining. You can set the duration of the activity as well as which mine(node number) to work in Arguments: - `mine`: the node number of the mine - `duration`: the hours to work Returns: True if got a spot for mining, False otherwise """ if char.is_working(): return False if duration not in [1,2,6,10,22]: duration = 1 s1 = "textePage[1]['Texte'] = '" s2 = "textePage[2] = new" page = char.visit(outskirts_url).read() start = page.find(s1) end = page.find(s2) end = page.rfind("'",start,end) start+=len(s1) soup = BeautifulSoup(page[start:end]) forms = soup.find_all('form') mine_list = [game_url+form['action'] for form in forms if "t=mine" in form['action']] mine_list = set(mine_list) if len(mine_list) == 0: char.logger.write(log() + " There are no mines!\n") return False else : if mine == None: for url in mine_list: res = char.visit(url, urllib.urlencode({'duree':str(duration)})).read() if "overcrowded" in res.lower(): m = re.search("(&n=)(\d+)",url,re.IGNORECASE) char.logger.write(log() + " The mine on node " + m.group(2) + " is full\n") else: for url in mine_list: if "n="+str(mine) in url: res = char.visit(url, urllib.urlencode({'duree':str(duration)})).read() if "overcrowded" in res.lower(): char.logger.write(log() + " Mine " + str(mine) + " is full\n") break result = char.is_working() char.logger.write(log() + " Mine Application: " + str(result) + " (" + str(char.activity) + ")" + '\n') return result
def hire(self, stat=None, wage=None, autobuy=True): """ Posts an advertisement at the townhall/calpulli. """ if self.can_hire(): if not self.prep_home_inventory(autobuy): self.char.logger.write( log() + " Don't have the necessary materials for hiring worker..QUIT HIRING\n" ) return False page = self.char.visit(myhome_url).read() s1 = "textePage[" + str(self.number + 1) + "]['Texte'] = '" s2 = "';" start = page.find(s1) + len(s1) end = page.find(s2, start) text = page[start:end] soup = BeautifulSoup(text) carac = soup.find("input", attrs={"name": "carac"})['value'] actionChamp = soup.find("input", attrs={"name": "actionChamp"})['value'] embauche = soup.find("input", attrs={"name": "embauche"})['value'] wage = self.wage_recommender() if ( type(wage) is not int or not 12 <= wage <= 50) else wage stat = self.stat_recommender() if ( type(stat) is not int or not 0 <= stat <= 19) else stat if wage > int(self.char.money): self.char.logger.write( log() + " Don't have enough money to hire...QUIT HIRING\n") return False url = game_url + "Action.php?action=18&champ=" + str(self.number - 1) self.char.visit( url, urllib.urlencode({ 'actionChamp': str(actionChamp), 'carac': str(carac), 'embauche': str(embauche), 'salaire': str(wage), 'qualification': str(stat) })) self.char.logger.write( log() + " Posted a job for hiring a worker to work on field " + str(self.number) + "\n")
def apply_for_imw(char, duration=1): """ Apply for IMW Arguments: - `duration`: Duration of activity in hours """ if char.is_working(): return False if duration not in [1,2,6,10,22]: duration = 1 s1 = "textePage[1]['Texte'] = '" s2 = "textePage[2] = new" page = char.visit(outskirts_url).read() start = page.find(s1) end = page.find(s2) end = page.rfind("'",start,end) start+=len(s1) soup = BeautifulSoup(page[start:end]) forms = soup.find_all('form') url_list = [game_url+form['action'] for form in forms if "t=rmi" in form['action']] url_list = set(url_list) for url in url_list: char.visit(url, urllib.urlencode({'duree':str(duration)})) result = char.is_working() char.logger.write(log() + " IMW Application: " + str(result) + " (" + str(char.activity) + ")" + "\n") return result
def refresh(self): """ Refreshes all the attributes. TEST - self.harvesting when we are harvesting are own field """ page = self.char.visit(myhome_url).read() s1 = "textePage["+str(self.number+1)+"]['Texte'] = '" s2 = "';" start = page.find(s1) + len(s1) end = page.find(s2, start) text = page[start:end] m = re.search("(\d+)(\s*/\s*)(\d+)", text) self.day = int(m.group(1)) m = re.search("(Quality\s*:\s*)(\d+)%", text, re.IGNORECASE) self.quality = int(m.group(2)) m = re.search("your\s*job\s*offer", text, re.IGNORECASE) self.hiring = True if m != None else False self.harvesting = True if "FichePersonnage.php?login="******" Interesting...we are hiring and also harvesting at the same time....ERROR\n") self.type = None
def visit(self, url, mydata=None): """ A new interface to open any of the game urls This method takes care of network issues, server maintainance and makes sure that the url is visited. Arguments: - `url`: The url to open - `mydata`: The post data Returns: The response after we visit that url """ if self.is_server_under_maint(): self.login() loaded = False while loaded == False: try: response = self.br.open(url, data=mydata, timeout=35) loaded = True except : self.logger.write(log() + " -ERROR OPENING URL: " + url + "\n") traceback.print_exc(file = self.logger) time.sleep(15) if "Bad Request" in str(sys.exc_info()[1]): #we lost the session self.login() return response
def visit(self, url, mydata=None): """ A new interface to open any of the game urls This method takes care of network issues, server maintainance and makes sure that the url is visited. Arguments: - `url`: The url to open - `mydata`: The post data Returns: The response after we visit that url """ if self.is_server_under_maint(): self.login() loaded = False while loaded == False: try: response = self.br.open(url, data=mydata, timeout=35) loaded = True except: self.logger.write(log() + " -ERROR OPENING URL: " + url + "\n") traceback.print_exc(file=self.logger) time.sleep(15) if "Bad Request" in str( sys.exc_info()[1]): #we lost the session self.login() return response
def refresh(self): """ Refreshes all the attributes. TEST - self.harvesting when we are harvesting are own field """ page = self.char.visit(myhome_url).read() s1 = "textePage[" + str(self.number + 1) + "]['Texte'] = '" s2 = "';" start = page.find(s1) + len(s1) end = page.find(s2, start) text = page[start:end] m = re.search("(\d+)(\s*/\s*)(\d+)", text) self.day = int(m.group(1)) m = re.search("(Quality\s*:\s*)(\d+)%", text, re.IGNORECASE) self.quality = int(m.group(2)) m = re.search("your\s*job\s*offer", text, re.IGNORECASE) self.hiring = True if m != None else False self.harvesting = True if "FichePersonnage.php?login="******" Interesting...we are hiring and also harvesting at the same time....ERROR\n" ) self.type = None
def apply_for_militia(char): """ Apply for militia job Arguments: - `char`: """ if char.level < 1 or char.is_working(): return False page = char.visit(townhall_url).read() m = re.search("Action.php?action=43", page, re.IGNORECASE) if m == None: char.logger.write(log() + " Militia job is not available\n") return False char.visit(game_url+"Action.php?action=43") result = char.is_working() char.logger.write(log() + " Militia Application: " + str(result) + " (" + str(char.activity) + ")\n") return result
def donate_to_province(self, money=None): """ Donates money to the province Arguments: - `self`: - `money`: """ if money == None: return old = int(self.money) money = min(min(50, money), old) res = self.visit(donate_to_province_url, urllib.urlencode({'somme':str(money)})) self.update_inventory() if old > int(self.money): self.logger.write(log() + " Donated " + str(money) + " to the province/county\n") else: self.logger.write(log() + " " + BeautifulSoup(res).find("div", {"class":"pseudopopup"}).text + "\n")
def look_for_rare_materials(char): """ Search on the node for rare materials Arguments: - `char`: The character object """ if char.is_working(): return False page = char.visit(outskirts_url).read() m = re.search("Action.php?action=275", page, re.IGNORECASE) if m == None: char.logger.write(log() + " There are no rare materials on this node\n") return False char.visit(game_url+"Action.php?action=275") result = char.is_working() char.logger.write(log() + " Look for rare materials: " + str(result) + " (" + str(char.activity) + ")" + "\n") return result
def work_at_church(char): """ Work in the church """ if char.is_working(): return False char.visit((game_url + "Action.php?action=1")) char.logger.write(log() + " Working at church" + " (" + str(char.activity) + ")" + "\n") return True
def retreat(char): """ Put the character into retreat """ if char.is_working(): return False char.visit(game_url+"Action.php?action=37") char.logger.write(log() + "Going into retreat" + " (" + str(char.activity) + ")" + "\n") return True
def sleep_till_next_event(self, hours=0, minutes=0, seconds=0): """ Makes the character sleep till next specified periord. By default the character sleeps for a period that is equal to the time needed to finish his current activity. Arguments: - `self`: - `hours`: The hours to sleep - `minutes`: The minutes to sleep - `seconds`: The seconds to sleep """ self.logout() sleep_time = hours * 3600 + minutes * 60 + seconds sleep_time = (self.activity_remaining + 2) * 60 if sleep_time <= 0 else sleep_time self.logger.write(log() + " sleeping for " + str(sleep_time) + " sec" + '\n') time.sleep(sleep_time) self.logger.write(log() + " woke up...refreshing" + '\n') self.login() self.refresh()
def equip(self, item): """ Equips a weapon. These items can be unquipped. Arguments: - `self`: - `item`: The weapon to be equipped """ name = item self.update_inventory() if type(item) is str: if item not in item_map: self.logger.write(log() + " Item not in db - " + str(item) + "\n") return None item = item_map[item] if self.inventory[item]: self.visit(game_url + "Action.php?action=154&o=" + str(item)) self.logger.write(log() + " Equipped: " + str(name) + "\n") else: self.logger.write(log() + " Unable to equip item: " + str(name) + " - not in inventory\n") self.update_tools_and_wardrobe()
def donate_to_church(self,): """ Donates 5q to the church Arguments: - `self`: """ old = self.reputation self.visit(donate_to_church_url) self.update_stats() self.logger.write(log() + " Donated 5 to the church") if old < self.reputation: self.logger.write( "..got 1 reputation point!!") self.logger.write("\n")
def donate_to_church(self, ): """ Donates 5q to the church Arguments: - `self`: """ old = self.reputation self.visit(donate_to_church_url) self.update_stats() self.logger.write(log() + " Donated 5 to the church") if old < self.reputation: self.logger.write("..got 1 reputation point!!") self.logger.write("\n")
def attend_lessons(char, subjects=[]): """ Attend a class at the university. Arguments: - `char`: The character object - `subjects`: The subjects to study. This can be a list. The subject at the beggining of the list gets more priority. If no subject is specified, then study any subject being taught. Ex: attend_lessons(char, ["empire administration", "currency"]) -- makes the character attend empire administration or currrency but empire administration is preferred if both are available. """ if char.is_working(): return False if type(subjects) is not list: subjects = [subjects] subjects = [subject.lower() for subject in subjects] all_classrooms = university.get_classrooms(char) rooms = [] if len(subjects) == 0: rooms = [room for room in all_classrooms if room.free_places > 0] else : for subject in subjects: subject_rooms = [room for room in all_classrooms if room.subject == subject and room.free_places > 0] rooms += subject_rooms for room in rooms: char.visit(game_url + "Action.php?action=79&type=3&id=" + str(room.ID), urllib.urlencode({})) if char.is_working(): char.logger.write(log() + " Attending Lesson: " + room.subject + " taught by " + room.teacher + " (" + str(char.activity) +")\n") return True char.logger.write(log() + " Could not attend lessons :(\n") return False
def donate_to_province(self, money=None): """ Donates money to the province Arguments: - `self`: - `money`: """ if money == None: return old = int(self.money) money = min(min(50, money), old) res = self.visit(donate_to_province_url, urllib.urlencode({'somme': str(money)})) self.update_inventory() if old > int(self.money): self.logger.write(log() + " Donated " + str(money) + " to the province/county\n") else: self.logger.write(log() + " " + BeautifulSoup(res).find("div", { "class": "pseudopopup" }).text + "\n")
def travel_on_road(char, dst, exclude_nodes = []): """ Makes the character travel to the given destination Arguments: - `char`: The character object. - `dst`: The node number/town to travel to. This need not be the immediate neighbour. - `exclude_nodes`: The nodes to avoid during the travel. Useful incase you know robbers or hostile armies are on the node. These must be node numbers. """ if char.is_working(): return False if char.load > char.maxload: char.logger.write(log() + " Unable to travel due to inventory overload: " + str(char.load) + "/" + str(char.maxload) + "\n") return False destination = travel.get_next_hop(char, dst, exclude_nodes) if destination == None: return False char.visit(game_url+"Action.php?action=68", urllib.urlencode({"n":str(destination)})) result = char.is_working() char.logger.write(log() + " Traveling to node " + str(destination) + " - " + str(result) + " (" + str(char.activity) + ")" + "\n") return result
def login(self): """ Logs in to the game server. """ while self.is_server_under_maint(): time.sleep(120) logged_in = False while logged_in == False: try: response = self.br.open(loginform_url, data=urllib.urlencode({'login':self.name, 'password':self.password}), timeout=35) if response.geturl() == loginfail_url: self.logger.write(log() + "Wrong password\n") thread.exit() elif response.geturl() == game_url: #server under maint? self.logger.write(log() + " Server maybe under maintainance\n") time.sleep(120) else: logged_in = True except SystemExit ,e: thread.exit() except:
def get_node_number(char, adjlist, neighbours): """ Returns the node number the character is currently at Arguments: - `char`: """ for i in range(0, len(adjlist)): if i not in neighbours and len(adjlist[i]): #exclude the neighbours and disconnected nodes assertion = True #asserting that this is the characte's node for j in adjlist[i]: if j not in neighbours: assertion = False if assertion: return i char.logger.write(log()+ "Unable to find the character's node: ") return None
def get_node_number(char, adjlist, neighbours): """ Returns the node number the character is currently at Arguments: - `char`: """ for i in range(0, len(adjlist)): if i not in neighbours and len( adjlist[i]): #exclude the neighbours and disconnected nodes assertion = True #asserting that this is the characte's node for j in adjlist[i]: if j not in neighbours: assertion = False if assertion: return i char.logger.write(log() + "Unable to find the character's node: ") return None
def harvest_resource(char, autousetool=True, autobuytool=False, price=None): """ Harvest the clan resource (Lake/Orchard/Forest) Arguments: - `char`: The character object """ rsc = resource.get_resource_type(char) if rsc in resource.resource_list: if autousetool and not resource.has_equipped_tool(char, rsc): resource.use_tool(char, rsc) if autobuytool and not resource.has_equipped_tool(char, rsc): resource.buy_tool(char, rsc) resource.use_tool(char, rsc) return harvester(char, rsc) else: char.logger.write(log() + " Harvest Resource: False (" + str(char.activity)+ ") - unknown resource - " + str(rsc) + "\n") return False
def pick_herbs(char, duration=2): """Pick medicinal herbs ARGUMENTS: -`char`: The character object -`duration`: Duration of the activity in hours RETURNS: -`True`: If the character is picking herbs -`False': Otherwise """ if char.is_working(): return False if duration not in [2,6,12,24]: duration = 2 url = game_url+"Action.php?action=338&t=rechercheComposants" char.visit(url, urllib.urlencode({'duree':str(duration)})) result = char.is_working() char.logger.write(log() + " Pick herbs: " + str(result) + " (" + str(char.activity) + ")" + "\n") return result
def show_inbox(self): """ Writes the inbox to the logger. Arguments: - `self`: """ page = self.visit(my_url).read() s1 = "textePage[2]['Texte'] = '" s2 = "';" start = page.find(s1) end = page.find(s2, start) soup = BeautifulSoup(page[start:end]) mails = soup.find_all("li") self.logger.write(log() + " Mails for " + self.name + "\n") for mail in mails: a = mail.find("a") if a != None: mail.a.extract() self.logger.write(a.text + " [" + mail.text.strip() + "]\n") else: self.logger.write(mail.text+"\n")
def apply_for_job(char, evaluator = sample_job_evaluator): """ Apply for a player posted job in the townhall Arguments: - `char`: The character object - `evaluator`: """ if char.is_working(): return False job = evaluator(townhall.get_jobs(char)) if job == None: return False char.visit(game_url+"Action.php?action=13", urllib.urlencode({"IDOffre":str(job.formcode)})) result = char.is_working() char.logger.write(log() + " Job Application: " + str(result) + " (" + str(char.activity) + ") " + '\n') return result
def show_inbox(self): """ Writes the inbox to the logger. Arguments: - `self`: """ page = self.visit(my_url).read() s1 = "textePage[2]['Texte'] = '" s2 = "';" start = page.find(s1) end = page.find(s2, start) soup = BeautifulSoup(page[start:end]) mails = soup.find_all("li") self.logger.write(log() + " Mails for " + self.name + "\n") for mail in mails: a = mail.find("a") if a != None: mail.a.extract() self.logger.write( a.text.encode('ascii', 'ignore') + " [" + mail.text.encode('ascii', 'ignore').strip() + "]\n") else: self.logger.write(mail.text.encode('ascii', 'ignore') + "\n")
def get_next_hop(char, destination, exclude_list=[]): """ Returns the next node in the shortest path the character must travel inorder to reach 'destination'. `exclude_list`: A list of nodes to avoid. Used in case you know there are enemy armies or robbers. Note: It takes care of whether or not the character is a noble (3 node coverage) or a normal traveller (2 node coverage) Arguments: -`destination`: can be a node number or the name of a town """ if type(destination) is str: destination = destination.lower() if destination not in node_map: raise ValueError("Destination not in the db. - " + str(destination)) destination = node_map[destination] if type(destination) is not str and type(destination) is not int: raise TypeError("Invalid type supplied as destination - " + str(destination)) if not 1 <= destination <= 299: char.logger.write(log() + " Invalid node number\n") return None page = char.visit(outskirts_url).read() neighbours = [] for m in re.finditer("(textePage\[0\]\[)(\d+)(\]\[\'Texte\'\] = \')", page, re.IGNORECASE): neighbours.append(int(m.group(2))) adjlist = load_world_map() src = get_node_number(char, adjlist, neighbours) if destination == src: char.logger.write(log() + " We are at the destination\n") return None #Disconnecting the excluded nodes from the graph for node in exclude_list: for i in adjlist[node]: adjlist[i].remove(node) adjlist[node] = [] depth = [-1] * len(adjlist) parents = breadth_first_visit(adjlist, depth, src) if depth[destination] == -1: char.logger.write(log() + " Destination not reachable -- " + str(destination)) return None node = destination path = [node] while node != src: path.append(parents[node]) node = parents[node] path = path[::-1] char.logger.write(log() + " Route: Our Location-> " + str(path) + " <-Destination\n") #return the farthest neighbour -- takes care of noble travelling too dst = -1 for node in neighbours: try: index = path.index(node) if index > dst: dst = index except: pass return path[dst]
def eat(self): """ Makes the character eat the minimum cost food. Returns the amount of leftover HP points that have not been eaten """ hunger = self.char.hunger if self.hunger == None else self.hunger if len(self.food) == 0 or hunger == 0: return hunger food = list() for item in self.food: if type(item) is tuple: food.append(item[0]) elif type(item) is str: food.append(item) else: raise TypeError("Invalid item specified in MinCostDiet.food Allowed types are str or tuple") for item in food: if item not in item_map: raise ValueError("Item not in db - " + str(item)) consumed = self.consume_inventory_food(food, hunger) leftover = hunger - consumed self.char.logger.write(log() + " Consumed " + str(consumed) + " hp worth food from inventory. Need to eat " + str(leftover) + " hp points more."+ "\n") while leftover > 0: # we must buy some food from the market costs = [] weight = [] quantity = [] khana = [] for item in self.food: if type(item) is tuple: sales_info = market.apply_price_filter(market.get_market_sales(self.char, item[0]),(0, item[1])) else: sales_info = market.get_market_sales(self.char, item) if sales_info == None or len(sales_info) == 0: continue food_name = r_food_map[sales_info[0][0]] qty_to_buy = int(math.ceil(float(leftover)/hp_info[food_name])) for sale in sales_info: khana.append(food_name) costs.append(sale[1]) weight.append(hp_info[food_name]) quantity.append(min(qty_to_buy, sale[2])) qty_to_buy -= min(qty_to_buy, sale[2]) if(qty_to_buy == 0): break self.char.logger.write("leftover: " + str(leftover) + "\n") for i in range(0, len(khana)): self.char.logger.write(str(khana[i]) + " " + str(costs[i]) + " " + str(quantity[i]) + " " + str(weight[i])+"\n") if len(khana) == 0: #when there is no food available to buy on the market (ex: when on the roads) return leftover buy_list, meal_cost = self.make_optimal_buy_decision(khana, costs, weight, quantity, leftover) self.char.logger.write(str(buy_list) + "\n" + "Cost: " + str(meal_cost) + "\n") khana = list(set(buy_list)) quantity = [] prev_counts = [] for var in khana: quantity.append(buy_list.count(var)) self.char.update_inventory() money = int(round(self.char.money*100,1)) for i in range(0, len(khana)): prev_counts.append(self.char.inventory[item_map[khana[i]]]) market.buy(self.char, khana[i], quantity=quantity[i], block=False) market.snooze_till_market_reset(self.char) for i in range(0, len(khana)): leftover -= (hp_info[khana[i]] * self.char.inventory[item_map[khana[i]]] - prev_counts[i]) self.char.use(khana[i], self.char.inventory[item_map[khana[i]]] - prev_counts[i]) if money < meal_cost: # we don't have enough money to buy even the min cost meal, then break out self.char.logger.write(log()+ " We don't have enough money to buy food! (money: " + str(money) + ") (cost: " + str(meal_cost) + ")\n") break return leftover
def buy(char, item, price=None, quantity=1, block=True): """Buy's an item from the market Default behaviour is to block the caller till the item to be bought is in the inventory. Arguments: - `char`: - `item`: - `price: There are 3 ways to give a price -- Specify a particular price in which case the item is bought from the market at that price -- Specify a range of the item price (2 element tuple/list) in which case the item is bought from the market in that range if its available -- Specify nothing in which case the item is bought for the lowest price available on the market - `quantity`: Set to -1 to buy the all quantity on the market - `block`: Set to False if you do not want this function to block Returns: - The number of items purchased. When used in non-blocking mode the return value is meaningless (should be ignored) """ if item not in item_map: raise ValueError("Item is not in the db - " + str(item)) item_code = item_map[item] submit_url = game_url + "Action.php?action=11" basket_url = game_url + "Action.php?action=29" poster = char.get_browser() char.update_inventory() prev_count = char.inventory[item_code] bought = 0 got_money = True block_test = True if quantity == -1: #buy all that is available on market quantity = 0 sales = get_market_sales(char, item) buy_window = apply_price_filter(sales, price) for sales in buy_window: quantity += sales[2] if len(buy_window) == 0: char.logger.write(log() + " Item not available in price range\n" + "Bought " + str(bought) + " " + str(item) + "\n") char.logger.write(log() + " Buying item: " + str(item) + " from the market\n") char.logger.write(log() + " Quantity: " + str(quantity) + '\n') #char.logger.write(log() + " prev_count: " + str(prev_count) + '\n') #debug. should be removed while bought != quantity and got_money and block_test: to_buy = quantity - bought sales = get_market_sales(char, item) if len(sales) == 0: char.logger.write(log() + " Item not available on the market\n" + "Bought " + str(bought) + " " + str(item) + "\n") return bought buy_window = apply_price_filter(sales, price) if len(buy_window) == 0: char.logger.write(log() + " Item not available in price range\n" + "Bought " + str(bought) + " " + str(item) + "\n") return bought char.update_inventory() money = int(round(char.money * 100, 1)) #char.visit(market_url) ordered = 0 #the number of items in our basket for sales in buy_window: prix = sales[1] quantite = min(to_buy, sales[2]) char.logger.write(log() + " Price:" + str(prix) + " Quantity:" + str(quantite) + " Money:" + str(money) + '\n') if (prix * quantite) > money: got_money = False quantite = int(money / prix) money -= (prix * quantite) poster.open( basket_url, urllib.urlencode({ 'IDParametre': '0', 'prix': str(prix), 'quantite': str(quantite), 'typeObjet': str(sales[0]) #bd })) to_buy -= quantite ordered += quantite if to_buy == 0 or got_money == False: break poster.open(submit_url, urllib.urlencode({})) char.logger.write(log() + " Ordered: " + str(ordered) + '\n') if block: snooze_till_market_reset(char) char.update_inventory() recent_purchase = char.inventory[item_code] - prev_count - bought if not got_money and ordered and ordered > recent_purchase: #for the case where we ran out of money and we did not get item from the market(someone else bought it) got_money = True #so we must retry again with what amount we have left bought = char.inventory[item_code] - prev_count char.logger.write(log() + " Bought: " + str(bought) + '\n') block_test = block #char.logger.write( str(bought!= quantity) + " " + str(got_money) + " " + str(block_test) + '\n') char.logger.write(log() + " Bought " + str(bought) + " " + str(item) + "\n") return bought
def eat(self): """ Makes the character eat the minimum cost food. Returns the amount of leftover HP points that have not been eaten """ hunger = self.char.hunger if self.hunger == None else self.hunger if len(self.food) == 0 or hunger == 0: return hunger food = list() for item in self.food: if type(item) is tuple: food.append(item[0]) elif type(item) is str: food.append(item) else: raise TypeError( "Invalid item specified in MinCostDiet.food Allowed types are str or tuple" ) for item in food: if item not in item_map: raise ValueError("Item not in db - " + str(item)) consumed = self.consume_inventory_food(food, hunger) leftover = hunger - consumed self.char.logger.write(log() + " Consumed " + str(consumed) + " hp worth food from inventory. Need to eat " + str(leftover) + " hp points more." + "\n") while leftover > 0: # we must buy some food from the market costs = [] weight = [] quantity = [] khana = [] for item in self.food: if type(item) is tuple: sales_info = market.apply_price_filter( market.get_market_sales(self.char, item[0]), (0, item[1])) else: sales_info = market.get_market_sales(self.char, item) if sales_info == None or len(sales_info) == 0: continue food_name = r_food_map[sales_info[0][0]] qty_to_buy = int( math.ceil(float(leftover) / hp_info[food_name])) for sale in sales_info: khana.append(food_name) costs.append(sale[1]) weight.append(hp_info[food_name]) quantity.append(min(qty_to_buy, sale[2])) qty_to_buy -= min(qty_to_buy, sale[2]) if (qty_to_buy == 0): break self.char.logger.write("leftover: " + str(leftover) + "\n") for i in range(0, len(khana)): self.char.logger.write( str(khana[i]) + " " + str(costs[i]) + " " + str(quantity[i]) + " " + str(weight[i]) + "\n") if len( khana ) == 0: #when there is no food available to buy on the market (ex: when on the roads) return leftover buy_list, meal_cost = self.make_optimal_buy_decision( khana, costs, weight, quantity, leftover) self.char.logger.write( str(buy_list) + "\n" + "Cost: " + str(meal_cost) + "\n") khana = list(set(buy_list)) quantity = [] prev_counts = [] for var in khana: quantity.append(buy_list.count(var)) self.char.update_inventory() money = int(round(self.char.money * 100, 1)) for i in range(0, len(khana)): prev_counts.append(self.char.inventory[item_map[khana[i]]]) market.buy(self.char, khana[i], quantity=quantity[i], block=False) market.snooze_till_market_reset(self.char) for i in range(0, len(khana)): leftover -= (hp_info[khana[i]] * self.char.inventory[item_map[khana[i]]] - prev_counts[i]) self.char.use( khana[i], self.char.inventory[item_map[khana[i]]] - prev_counts[i]) if money < meal_cost: # we don't have enough money to buy even the min cost meal, then break out self.char.logger.write( log() + " We don't have enough money to buy food! (money: " + str(money) + ") (cost: " + str(meal_cost) + ")\n") break return leftover
def get_next_hop(char, destination, exclude_list = []): """ Returns the next node in the shortest path the character must travel inorder to reach 'destination'. `exclude_list`: A list of nodes to avoid. Used in case you know there are enemy armies or robbers. Note: It takes care of whether or not the character is a noble (3 node coverage) or a normal traveller (2 node coverage) Arguments: -`destination`: can be a node number or the name of a town """ if type(destination) is str: destination = destination.lower() if destination not in node_map: raise ValueError("Destination not in the db. - " + str(destination)) destination = node_map[destination] if type(destination) is not str and type(destination) is not int: raise TypeError("Invalid type supplied as destination - " + str(destination)) if not 1 <= destination <= 299: char.logger.write(log() + " Invalid node number\n") return None page = char.visit(outskirts_url).read() neighbours = [] for m in re.finditer("(textePage\[0\]\[)(\d+)(\]\[\'Texte\'\] = \')", page, re.IGNORECASE): neighbours.append(int(m.group(2))) adjlist = load_world_map() src = get_node_number(char, adjlist, neighbours) if destination == src: char.logger.write(log() + " We are at the destination\n") return None #Disconnecting the excluded nodes from the graph for node in exclude_list: for i in adjlist[node]: adjlist[i].remove(node) adjlist[node] = [] depth = [-1] * len(adjlist) parents = breadth_first_visit(adjlist, depth, src) if depth[destination] == -1: char.logger.write(log() + " Destination not reachable -- " + str(destination)) return None node = destination path = [node] while node != src: path.append(parents[node]) node = parents[node] path = path[::-1] char.logger.write(log() + " Route: Our Location-> " + str(path) + " <-Destination\n") #return the farthest neighbour -- takes care of noble travelling too dst = -1 for node in neighbours: try: index = path.index(node) if index > dst: dst = index except: pass return path[dst]
while logged_in == False: try: response = self.br.open(loginform_url, data=urllib.urlencode({'login':self.name, 'password':self.password}), timeout=35) if response.geturl() == loginfail_url: self.logger.write(log() + "Wrong password\n") thread.exit() elif response.geturl() == game_url: #server under maint? self.logger.write(log() + " Server maybe under maintainance\n") time.sleep(120) else: logged_in = True except SystemExit ,e: thread.exit() except: self.logger.write(log()) time.sleep(15) traceback.print_exc(file = self.logger) def visit(self, url, mydata=None): """ A new interface to open any of the game urls This method takes care of network issues, server maintainance and makes sure that the url is visited. Arguments: - `url`: The url to open - `mydata`: The post data
}), timeout=35) if response.geturl() == loginfail_url: self.logger.write(log() + "Wrong password\n") thread.exit() elif response.geturl() == game_url: #server under maint? self.logger.write(log() + " Server maybe under maintainance\n") time.sleep(120) else: logged_in = True except SystemExit, e: thread.exit() except: self.logger.write(log()) time.sleep(15) traceback.print_exc(file=self.logger) def visit(self, url, mydata=None): """ A new interface to open any of the game urls This method takes care of network issues, server maintainance and makes sure that the url is visited. Arguments: - `url`: The url to open - `mydata`: The post data Returns: The response after we visit that url