[Python] Runebook library

Only working scripts
Post Reply
Posts: 36
Joined: 12.02.2012 18:06

[Python] Runebook library

Post by Boydon »

Below you can find a really simple and minimalisti lib to easly handle runebooks.
For documentation please see the attached pyDoc string. To work correctly you'll need my gumps library.

Code: Select all

"""Runebook class. Minimal runebook support.

Created by Boydon
Only tested with Python 3.x"""

import datetime

import gumps
from stealth import *

class Runebook():
	"""An easy way to handle runebooks."""

	# type of the runebook as class attribute
	type = 0x22C5
	def __init__(self, runeBookID):
		"""runeBookID: the ID of the runebook we want to use """
		self.runeBookID = runeBookID
		self.runeNames = []
	def findRuneByName(self, findName):
		"""Finds a rune by a given name.
			findName: the name to look for"""
		returnRunes = []
		runeNr = 1
		runeNames = self.listRunes(update = True)
		for runeName in runeNames:
			if findName.lower() in runeName.lower():
			runeNr += 1
		return returnRunes
	def listRunes(self, update = False):
		"""Return a list with the names of all the runes.
			Results are cached in self.runeNames and only updated if update == True """
		#if results are cached we return them
		if self.runeNames and not update:
			# print('Using listRunes chache...')
			return self.runeNames
		# print('NOT using listRunes chache...')
		runeNames = []
		while not gumps.gumpFromObject(self.runeBookID, 0x059, wait=True, timeout=5000, delay=1):
		textLines = []
		gumpDict = {}
		while not textLines:
			textLines = GetGumpTextLines( gumps.lastGumpIndex() )
		while not gumpDict:
			gumpDict = gumps.toDict( gumps.lastGumpIndex() )
		# this is a little bit hard to remember: we are mapping textLines elements using the gumpDict CroppedTexts elements
		# if we are at page one and the descripion is not empty we get the corresponding element in textLines
		runeNames = [textLines[x['Text_ID']] for x in gumpDict['CroppedText'] if x['Page'] == 1 and textLines[x['Text_ID']] != 'Empty']
		self.runeNames = runeNames
		return runeNames
	def countRunes(self):
		"""Returns the number of runes in the runebook."""
		return len(self.listRunes())
	def travel(self, runeNr, method='r', tryAgain = ['fizzles', 'recover', 'reagents', 'tithing', 'mana']):
		"""	Travel using the runebook. You need to pass the following parameters:
			- runeNr with the number of the rune you want to travel to (must be between 1 and 16);
			- the method you want to use to travel:
				+ 'r' for recall;
				+ 'g' for gate;
				+ 's' for scroll;
				+ 'c' for sacred journey;
			- a list of situations in wich the function won't return the result status, but will try again (see below for return details).
			The following values are returned:
			- 'success'		if the travel was successful
			- 'fizzles'		if the spell fizzles (only for recall)
			- 'blocked'		if the destination is blocked;
			- 'recover' 	if you haven't yet recovered from former spell;
			- 'charges'		if the runebook has no more recall scrolls to use;
			- 'reagents'	if you need more reagents;
			- 'tithing'		if you need more tithing points;
			- 'mana'			if you don't have enough mana
			- 'marked'		??	
			- 'nomagic'		if you are travelling from a location where you can't use magic;
			- 'unknow'		if we couldn't recall for an unknow reason. This should never be the case.
			If you add any of thos return values to the tryAgain argument, the function wont return, but instead it will try again to travel.
			Defauld ignored return statuses are:
			- fizzles;
			- recover;
			- reagents;
			- tithing;
			- mana;
			Beware with what you do. You may end in an endless loop here.
		#check on rune number
		if runeNr not in list(range(1, 17)):
			raise Exception('The rune number for runeBookTravel must be between 1 and 16, got {0}'.format(runeNr))
		#check on recal method
		if method not in ['r', 'g', 's', 'c']:
			raise Exception('Unkwon runebook travel method: {0}'.format(method))
		#check on tryAgain arg type
		if not isinstance(tryAgain, list):
			raise TypeError('runeBookTravel is expecting a list as tryAgain argument, got a {0}'.format(type(tryAgain)))
		# translation of FoundedParamID  to be used later on
		fpTranslations = [None]*9
		fpTranslations[0] = 'fizzles'  # fizzles
		fpTranslations[1] = 'blocked'  # location is blocked
		fpTranslations[2] = 'recover'  # not yet recovered
		fpTranslations[3] = 'charges'  # no charges left
		fpTranslations[4] = 'reagents' # more reagents
		fpTranslations[5] = 'tithing'  # tithing points
		fpTranslations[6] = 'mana'     # insufficient mana
		fpTranslations[7] = 'marked'   # not marked
		fpTranslations[8] = 'nomagic'  # cannot teleport from here
		while True:
			# we save our starting position
			start = (GetX(Self()), GetY(Self()))
			# we open the rune book
			while not gumps.gumpFromObject(self.runeBookID, 0x059, wait=True, timeout=5000, delay=1):
			#TODO: add check to verify that runeNr is present in runebookId
			# button value calculated by recall method
			if method == 'r':
				button = 5 + ((runeNr - 1) * 6)
			elif method == 'g':
				button = 6 + ((runeNr - 1) * 6)
				# TODO implement movement trough the GATE
			elif method == 'c':
				button = 7 + ((runeNr - 1) * 6)
			elif method == 's':
				raise Exception('Runebook scroll traveling not implemented yet!')

			# maybe timeout should be an argument?
			now = datetime.datetime.now()
			timeout = now + datetime.timedelta(seconds=7)
			gumps.clickButton(button, -1, 0, False)
			if WaitJournalLine(now, 'fizzles|location is blocked|not yet recovered|no charges left|more reagents|tithing points|insufficient mana|not marked|cannot teleport from here', 4000):
				if fpTranslations[FoundedParamID()] not in tryAgain:
					return fpTranslations[FoundedParamID()]
				if method == 'g':
					return 'success'
				while datetime.datetime.now() < timeout:
					if (GetX(Self()), GetY(Self())) != start:
						return 'success'
		return 'unknow'
Post Reply