#	pubobjs.py			6/01/98 JJS##	This module defines the standard PUB objects (Things).##	Use this module with:  import pubobjs##----------------------------------------------------------------------# standard modulesimport stringimport typesimport re as regeximport copy# PUB modulesimport pubfrom pubcore import *import pubverbs#----------------------------------------------------------------------# Thing -- overrides BaseThing to provide some common PreObj checks#		(couldn't do this in BaseThing, since it references pubverbs)#class Thing(BaseThing):	def __init__(self,pNames=''):		# if we've already initialized, don't do it again:		if hasattr(self,'name'): return		BaseThing.__init__(self,pNames)		if (pub.lastroom): pub.lastroom.ContainNoCheck(self)	def PreObj(self,cmd):		if cmd.verb == pubverbs.get and cmd.dirobj == self:			if not cmd.actor.CanContain(self):				cmd.Tell("You can't pick that up.")				return CANCEL			if cmd.dirobj.container == cmd.actor:				cmd.Tell("You've already got <the dirobj>.")				return CANCEL		elif cmd.verb == pubverbs.drop:			if isInstance(cmd.dirobj) and cmd.dirobj.container != cmd.actor:				cmd.Tell("You don't have <a dirobj>.")				return CANCEL		# no other verbs need special checks, so...		return OK		def PostObj(self,cmd):		if cmd.verb == pubverbs.get \		or (cmd.verb == pubverbs.put and cmd.dirobj == self):			# if we have an "initial" note or desc, delete them when we're moved			self.initialNote = ''			self.initialDesc = ''		return BaseThing.PostObj(self,cmd)#----------------------------------------------------------------------# Openable -- object which can be opened, closed, locked, & unlocked##class Openable (Thing):##	# initialization method#	def __init__(self,pNames=''):#		Thing.__init__(self,pNames)#		self.isOpen = TRUE			# currently open?#		self.isLocked = FALSE		# currently locked?#		self.key = None				# object required to unlock with#		self.autolock = FALSE		# automatically lock when closed?#		self.openFail = "It won't budge."	# open fail msg#		self.oopenFail= "<The actor> tries to open <the dirobj>, but it won't budge."#		self.unlockFail = "You don't have the key."		# unlock fail msg#		self.ounlockFail= "<The actor> tries to unlock <the dirobj>, but has no key."#		self.onOpenCode = ''		# code to execute upon opening#		self.onCloseCode= ''		# code to execute upon closing#		self.openDesc = ''			# special description when open#		self.closedDesc = ''		# special description when closed#	#	def Open(self,pByWhom=None):#		if self.isOpen: return		# (already open, do nothing)#		self.isOpen = TRUE#		if self.openDesc: self.desc = self.openDesc#		if self.onOpenCode:#			actor = pByWhom#			object = self#			exec self.onOpenCode##	def Close(self,pByWhom=None):#		if not self.isOpen: return	# (already closed, do nothing)#		self.isOpen = FALSE#		if self.closedDesc: self.desc = self.closedDesc#		if self.onCloseCode:#			actor = pByWhom#			object = self#			exec self.onOpenCode	#----------------------------------------------------------------------# class Switch -- has Activate and Deactivate (and supporting) methods#class Switch(Thing):	def __init__(self,pNames=''):		Thing.__init__(self,pNames)		self.effectOnCode = ''	# code to execute when switched on		self.effectOn = 'You activate <the dirobj>.'	# what to print on On		self.oeffectOn = '<The actor> activates <a dirobj>.'	# and to others		self.effectOffCode = ''	# code to execute when switched off		self.effectOff = 'You deactivate <the dirobj>.'	# what to print on Off		self.oeffectOff = '<The actor> deactivates <a dirobj>.'		self.isActive = FALSE	# currently active?		self.getOnOn = FALSE	# try to GET it when you activate it?		self.offOnDrop = FALSE	# turn it off when you drop it?		self.onDesc = ''		# special description when on		self.offDesc = ''		# special description when off		self.onNote = ''		# special note when on		self.offNote = ''		# special note when off		self.onListLine = ''	# special list line when on		self.offListLine = ''	# special list line when off		# define some new methods	def Activate(self,pUser=None):		self.isActive = TRUE		if self.onDesc: self.desc = self.onDesc		else: self.desc = ''		if self.onNote: self.note = self.onNote		else: self.note = ''		if self.onListLine: self.listLine = "   - " + self.onListLine		else: self.listLine = ''		if pUser: user = pUser		else: user = self		object = self		here = user.container		if self.effectOnCode: exec self.effectOnCode		self.GetRoom().ComputeTotalLight()		def Deactivate(self,pUser=None):		self.isActive = FALSE		if self.offDesc: self.desc = self.offDesc		else: self.desc = ''		if self.offNote: self.note = self.offNote		else: self.note = ''		if self.offListLine: self.listLine = "   - " + self.offListLine		else: self.listLine = ''		if pUser: user = pUser		else: user = self		object = self		here = user.container		if self.effectOffCode: exec self.effectOffCode		self.GetRoom().ComputeTotalLight()	def Use(self,pUser): return self.Activate(pUser)	# see whether the thing can be activated/deactivated	def PreObj(self,cmd):		if (cmd.verb == pubverbs.on or cmd.verb == pubverbs.use \		or cmd.verb == pubverbs.push) and cmd.dirobj == self:			if self.isActive:				cmd.Tell('<The dirobj> is already on.')				return CANCEL			if self.container != cmd.actor and self.getOnOn:				#cmd.Tell("You don't have <the dirobj>.")				cmd.actor.DoCommandString("get "+ self.name)				return OK				#return CANCEL		elif cmd.verb == pubverbs.off and cmd.dirobj == self:			if not self.isActive:				cmd.Tell('<The dirobj> is not on.')				return CANCEL		elif cmd.verb == pubverbs.drop or cmd.verb == pubverbs.give:			if self.isActive and self.offOnDrop:				self.Deactivate(cmd.actor)				cmd.Tell( self.effectOff, self.oeffectOff )		return Thing.PreObj(self,cmd)	# PostObj: perform action, give the appropriate output	def PostObj(self,cmd):		if cmd.verb == pubverbs.on or cmd.verb == pubverbs.use \		or cmd.verb == pubverbs.push:			cmd.Tell( self.effectOn, self.oeffectOn )			return CANCEL		elif cmd.verb == pubverbs.off:			self.Deactivate(cmd.actor)			cmd.Tell( self.effectOff, self.oeffectOff )			if cmd.verb == pubverbs.off: return CANCEL					return Thing.PostObj(self,cmd)#----------------------------------------------------------------------# Container -- base type of any object which can contain another#class Container (Thing):	# initialization method	def __init__(self,pNames=''):		Thing.__init__(self,pNames)		self.contents = []		self.fail = "You can't put <a dirobj> in <the inobj>."	# return true if this object can contain another	def CanContain(self,pThing):		return pThing.size < self.size;	# move the given object to the contents of this one	def ContainNoCheck(self,*pThing):		#print self(the)+" contains ",pThing		for item in pThing:			if item.container != None:				# remove from previous container				item.container.contents.remove(item)			item.container = self			self.contents.append(item)	def PreObj(self,cmd):		if cmd.verb == pubverbs.put and cmd.inobj == self:			if not self.CanContain(cmd.dirobj):				cmd.Tell(self.fail)				return CANCEL		return Thing.PreObj(self,cmd)#	def GetDesc(self):#		if not self.contents: return Thing.GetDesc(self)#		return Thing.GetDesc(self) + '\n' + self.GetContentsDesc()	def GetContentsDesc(self, pLooker=None):		out = ''		contentslist = filter(lambda x:x.salient, self.contents)		if pLooker:			contentslist = filter( lambda x,a=pLooker: a.CanSee(x), contentslist)		for item in contentslist:			out = out + '\n' + item.GetListLine()		return out	# return list of visible contents as objects (recursively)	def VisibleContents(self):		out = self.contents		for item in out:			if hasattr(item,'contents'):		# and is open or transparent...				out = out + item.VisibleContents()		return out# end of class Container#----------------------------------------------------------------------# base class of any room or locationclass Room(Container):	def __init__(self,pNames=''):		Container.__init__(self,pNames)		self.ownLight = 75		# internal light, where 0=pitch black, 100=sunlight		self.light = 75			# total light (including light sources)		self.size = 5000		if pub.universe and pub.universe != self: pub.universe.ContainNoCheck(self)		pub.lastroom = self		# note last room created	def GetDesc(self, pLooker=None):		if pLooker and not pLooker.CanSee(self):			isDark = TRUE			out = "It's too dark to see much.\n"		else:			isDark = FALSE			out = '\n' + self.GetName() + '\n'			out = out + Thing.GetDesc(self) + '\n'		for item in self.contents:			if item != pLooker and (not pLooker or pLooker.CanSee(item)) and \			(item.salient or (isDark and item.light>5)):				out = out + '\n  ' + item.GetNote()		return out + '\n'	def Tell( self, pWhat, *pExcept):		whom = filter(lambda x,n=pExcept: x.listening and x not in n, self.contents)		for i in whom: i.Tell(pWhat)	def ComputeTotalLight(self):		if self == pub.universe: return	# don't bother for universe object		self.light = self.ownLight		for item in self.VisibleContents():			self.light = self.light + item.light		return self.light# end of class Room#----------------------------------------------------------------------# Box -- a Container which can be opened, closed, locked, etc.#class Box (Container,Switch):	def __init__(self,pNames=''):		Container.__init__(self,pNames)		Switch.__init__(self,pNames)	def PreObj(self,cmd):		return Switch.PreObj(self,cmd) and Container.PreObj(self,cmd)		def PostObj(self,cmd):		return Switch.PostObj(self,cmd) and Container.PostObj(self,cmd)#----------------------------------------------------------------------# class for exits -- things which connect one room to another#class Exit(Thing):	def __init__(self,pNames=''):		Thing.__init__(self,pNames)		self.dest = None		# by default, no destination		self.salient = 0		# and not salient		self.light = 1			# but glows in the dark (i.e., usable in dark)		self.size = 300			# and as big as 3 people		self.defverb = pubverbs.go	# no verb needed to go thru		self.opostsucc = '<The actor> enters the room.'	# msg to others in destination		self.open = TRUE		# door is open by default				if 'north' in self.synonyms:			self.opostsucc = '<The actor> enters from the south.'		elif 'south' in self.synonyms:			self.opostsucc = '<The actor> enters from the north.'		elif 'east' in self.synonyms:			self.opostsucc = '<The actor> enters from the west.'		elif 'west' in self.synonyms:			self.opostsucc = '<The actor> enters from the east.'		self.note = 'You can go to the '+self()+' from here.'	# move someone through the exit, if possible	def Use(self,pWhom):		if not self.open: return		# perform the move		pWhom.MoveTo(self.dest)	# check to see whether using this exit is possible	def PreObj(self,cmd):		if cmd.verb == pubverbs.go or cmd.verb == pubverbs.use:			if not self.open:				cmd.Tell( "The door is closed." )				return CANCEL			if not self.dest:				cmd.Tell("<Dirobj> leads nowhere.")				return CANCEL			if self.size < cmd.actor.size or not self.dest.CanContain(cmd.actor):				cmd.Tell("You don't fit!")				return CANCEL			if Thing.PreObj(self,cmd):				cmd.Tell("You head <dirobj>.", "<The actor> exits to <the dirobj>.")				return OK			return CANCEL				if cmd.verb == pubverbs.push:			cmd.Tell("Pushing has no effect.")			return CANCEL					# in any other case, return inherited method		return Thing.PreObj(self,cmd)	def PostObj(self,cmd):		if cmd.verb == pubverbs.go or cmd.verb == pubverbs.use:				cmd.Tell('', self.opostsucc)			cmd.Tell(self.dest.GetDesc(cmd.actor))			return CANCEL	# so that no further output is printed		# any other condition, return OK for normal output		return OK# end of class Exit#----------------------------------------------------------------------# base class of any person, monster, or other chanacterclass Actor(Container):	def __init__(self,pNames=''):		Container.__init__(self,pNames)		self.a = ''				# no article for Actors		self.cmdList = []		# list of commands to be executed		self.size = 100			# human-sized		self.listening = 1		# wants Tell() calls		self.par = Parser()		# my very own command interpreter		self.par.me = self.synonyms[0]	# which knows my name		self.speakingTo = None	# whom we're addressing		self.busytill = 0		# busy until what time?		self.invisName = "someone"		self.followers = []		# list of actors following		self.following = None	# whom we're following		self.the = ''			# no article for Actors		self.note = self(The) + " is here."	def GetName(self,article=0,pLooker=None):		# don't use articles with Actors, unless explicitly specified		if self.the or self.a or (pLooker and not pLooker.CanSee(self)):			return Container.GetName(self,article,pLooker)		return self.name	def Act(self):		return	def Announce(self, pWhat):		if self.container:			self.container.Tell( pWhat, self )	# get list of objects within visible/reachable range	def LocalNouns(self):		# that'd be everything visible from the room...		out = self.container.VisibleContents()		# plus room's container's contents (maybe later)		return out	# given the name of a noun, return the visible object	def FindNoun(self,pName,cmd=None):		if not pName: return None		if pName == 'self' or pName == 'me': return self		if pName == 'here' or pName == 'room': return self.container		l = filter(lambda x,a=pName: x.NameMatch(a),self.LocalNouns())		if len(l) > 1 and cmd:			# multiple matches... try to resolve by context			l2 = []			if cmd.verb == pubverbs.drop or cmd.verb == pubverbs.give:				l2 = filter(lambda x,a=cmd.actor: x.container==a, l)			elif cmd.verb == pubverbs.get:				l2 = filter(lambda x,a=cmd.actor: x.container!=a, l)			elif cmd.verb == pubverbs.defverb:				l2 = filter(lambda x:x.defverb, l)			if len(l2) > 0: l = l2		if not l: return None		if len(l)==1: return l[0]		# still can't resolve?  For now, pick arbitrarily		return l[0]	# similar to above, but if it can't find the object, return the given string	def NameToObj(self,pName,cmd=None):		ans = self.FindNoun(pName,cmd)		if ans: return ans		return pName	def DoCommandString(self,cmdstr):		# check for direct address		firstword = stripPunctuation( string.split(cmdstr)[0] )		obj = self.NameToObj(firstword)		if hasattr(obj,'DoCommandString'):			# a-ha!  Direct address... make it into a SAY command			cmdstr = 'say "' + cmdstr + '"'		# build the command list from the command string		# (insert at beginning, so we can insert prerequisite commands)		self.cmdList = self.par.Parse(cmdstr) + self.cmdList		#if self == player: print "Got: ",map(str,self.cmdList)		# do the first command in the list immediately		self.DoNextCmd();		def DoNextCmd(self):		if not self.cmdList: return CANCEL		cmd = copy.copy(self.cmdList[0])		self.cmdList = self.cmdList[1:]		#if self == pub.player: print "Executing:", cmd		cmd.actor = self		if pub.verbdict.has_key(cmd.verb):			cmd.verb = pub.verbdict[cmd.verb]				# attempt to find object references for all nouns in cmd		cmd.toobj = self.NameToObj(cmd.toobj,cmd)		cmd.dirobj = self.NameToObj(cmd.dirobj,cmd)		cmd.inobj = self.NameToObj(cmd.inobj,cmd)		cmd.atobj = self.NameToObj(cmd.atobj,cmd)		cmd.withobj = self.NameToObj(cmd.withobj,cmd)				# start the command		# (the Verb object does most of the work)		if isInstance(cmd.verb):			cmd.verb.Do(cmd)			# special check: if "restoring" a game, then			# this object must bail out immediately!			if cmd.verb.__class__ == pubverbs.Restore:				print "bailing out"		else:			self.Tell('Unknown verb '+cmd.verb)		if self.busytill < pub.scheduler.minutes:			self.busytill = pub.scheduler.minutes		self.busytill = self.busytill + 1				# if there's more commands to be done, schedule an event to do it...		if self.cmdList:				pub.scheduler.AddAbsEvent( self.busytill, \						Event(self, 'object.DoNextCmd()' ) )		else:			# if not, schedule an Act() event to get more commands			pub.scheduler.AddAbsEvent( self.busytill, Event(self, 'object.Act()' ) )		return	def PreAct(self, cmd):		if cmd.verb == pubverbs.go and self.followers:			for item in self.followers:				item.DoCommandString('go '+cmd.dirobj())		return OK# end of class Actor#----------------------------------------------------------------------# class of the player -- i.e., the Actor interfaced to the terminalclass Player(Actor):	def __init__(self,pNames=''):		Actor.__init__(self,pNames)		self.linebreak = 80	def Tell(self, pWhat):		if self.linebreak:			# break lines every <linebreak> characters:			while len(pWhat) >= self.linebreak:				pos = string.rfind(pWhat[:self.linebreak],' ')				pos2 = string.rfind(pWhat[:self.linebreak],'\n')				if pos2 < pos and pos2 > -1: pos = pos2				print pWhat[:pos]				pWhat = pWhat[pos+1:]		print pWhat	def Act(self):		if pub.scheduler.HasEventFor( self ): 			# I've already got a scheduled event; no need to ask for input			pub.scheduler.Update()			return		# no scheduled events, so ask the user what to do		#cmdstr = raw_input(pub.scheduler.GetTime()+'>')		print		if self != pub.player:			print "WARNING: self != pub.player>",		cmdstr = raw_input('>')		if cmdstr: self.DoCommandString(cmdstr)		else: pub.scheduler.AddEvent( 1, Event(self, 'object.Act()') )# end of class Player#----------------------------------------------------------------------# class Monitor -- puts whatever it hears to the terminalclass Monitor(Actor):	def Tell(self,pWhat):		print '[' + self() + ' hears] ' + pWhat# end of class Monitor#----------------------------------------------------------------------# class Timer -- something that goes off after a certain amount of time on#class Timer(Switch):	def __init__(self,pNames=''):		Switch.__init__(self,pNames)		self.delay = 8			# by default, waits 8 minutes		self.dueCode = ''		self.canTurnOff = TRUE		self.failTurnOff = "You can't see any way to deactivate <the dirobj>."		self.getOnOn = FALSE		self.offOnDrop = FALSE			def Activate(self,pUser):		# upon activation, schedule a ComeDue event		pub.scheduler.AddEvent(self.delay,Event(self,'object.ComeDue()'))		Switch.Activate(self,pUser)		def ComeDue(self):		here = self.container		if self.dueCode: exec self.dueCode		Switch.Deactivate(self)		self.container.Tell( self.oeffectOff )		def PreObj(self,cmd):		if cmd.verb == pubverbs.off and cmd.dirobj == self:			if  self.isActive and not self.canTurnOff:				cmd.Tell(self.failTurnOff)				return CANCEL		return Switch.PreObj(self,cmd)#----------------------------------------------------------------------# class Garment -- something you can wear (and may have an effect)#class Garment(Switch):	def __init__(self,pNames=''):		Switch.__init__(self,pNames)		self.bodypart = ''		self.effectOn = 'You wear <the dirobj>.'		self.oeffectOn = '<The actor> dons <a dirobj>.'		self.effectOff = 'You remove <the dirobj>.'		self.oeffectOff = '<The actor> removes <a dirobj>.'		self.onListLine =  self.GetName(a) + " (worn)"	# check to see whether wearing this garment is possible	def PreObj(self,cmd):		if cmd.verb == pubverbs.on:			if self.isActive:				cmd.Tell("You're already wearing <the dirobj>.")				return CANCEL						# check for something already on that body part			for item in cmd.actor.contents:				if hasattr(item,'isActive') and item.isActive \				  and hasattr(item,'bodypart') and item.bodypart == self.bodypart:					cmd.Tell("You're already wearing something on your " \								+ self.bodypart + ".")					return CANCEL		elif cmd.verb == pubverbs.off:			if not self.isActive or self.container != cmd.actor:				cmd.Tell("You're not wearing <the dirobj>.")				return CANCEL		return Switch.PreObj(self,cmd)		def PreMove(self):		self.Deactivate()		return Thing.PreMove(self)		#----------------------------------------------------------------------# Liquid -- a Thing with some special properties#class Liquid(Thing):	def __init__(self,pNames=''):		Thing.__init__(self,pNames)		self.a = "some"			def PreObj(self,cmd):		if cmd.verb == pubverbs.get:			cmd.Tell("You'll have to put it in something.")			return CANCEL		if cmd.verb == pubverbs.put:			if not hasattr(cmd.inobj,'canContainLiquid') \			or not cmd.inobj.canContainLiquid:				cmd.Tell("<The inobj> can't hold liquids.")				return CANCEL		return Thing.PreObj(self,cmd)#----------------------------------------------------------------------# Countable -- a Thing with a quantity, can be divided and recombined#class Countable(Thing):	def __init__(self,pNames=''):		Thing.__init__(self,pNames)		self.quantity = 10		self.pluralname = self.name + 's'		for item in self.synonyms:			term = "# "+item			if term not in nouns: nouns.append(term)		self.newquantity = 0		self.prevqty = 0		def GetName(self,article=0,pLooker=None):#		return self.pluralname + ' (' + str(self.quantity) + ')'		if self.quantity == 1:			self.a = 'a'			self.the = 'the'			self.name = self.synonyms[0]		else:			self.a = str(self.quantity)			self.the = str(self.quantity)			self.name = self.pluralname		return Thing.GetName(self,article,pLooker)		def GetNote(self):		return "You see " + self.GetName(a) + " here."		def NameMatch(self,str):		# print "Trying name match of ",str," with ",self.GetName()		# name should match if it starts with a number less that self.quantity		self.newquantity = self.quantity		words = string.split(str)		if len(words) < 2 or not isInt(words[0]):			return Thing.NameMatch(self,str)		givenNum = toInt(words[0])		if givenNum > 0 and givenNum <= self.quantity:			if Thing.NameMatch(self, string.join(words[1:]) ):				self.newquantity = givenNum		# remember number used...				return TRUE			else: return FALSE		# number's invalid... no match		return FALSE	def Split(self,pQty):		# create a new object, pQty less than the current one		newobj = copy.copy(self)		# copy.copy calls the constructor, so the new object		# may get put into the last room built...		if pub.lastroom: pub.lastroom.contents.remove(newobj)		self.container.contents.append(newobj)		# split the quantities between the old and new objects		newobj.quantity = newobj.quantity - pQty		newobj.newquantity = newobj.quantity		self.quantity = pQty		self.newquantity = pQty		def Absorb(self, pOther):		# absorb the other one into this one, and delete the other		self.quantity = self.quantity + pOther.quantity		pOther.container.contents.remove(pOther)		del pOther		def PostMove(self):		self.prevqty = self.quantity		for item in self.container.contents:			if item != self and item.synonyms == self.synonyms:				self.Absorb(item)			return BaseThing.PostMove(self)	def PreObj(self,cmd):		# if we do something that would GET or DROP some items,		# but not all of them, then we need to split this object				if (cmd.verb == pubverbs.get or cmd.verb == pubverbs.drop \		or cmd.verb == pubverbs.give) \		and self.newquantity < self.quantity:			# print self.newquantity,'<',self.quantity,', so...'			self.Split(self.newquantity)			return OK		return Thing.PreObj(self,cmd)	def PostObj(self,cmd):		# here, we need to see if we can consolidate with others like us		if cmd.verb == pubverbs.get or cmd.verb == pubverbs.drop \		or cmd.verb == pubverbs.give:			# special output for when we've absorbed some other items			if self.prevqty != self.quantity:				amount = str(self.prevqty) + ' '				if self.prevqty == 1: amount = amount + self.synonyms[0]				else: amount = amount + self.pluralname				if cmd.verb == pubverbs.get:					cmd.Tell('You take ' + amount + ' (you now have '+ \							  str(self.quantity)+').', \							'<The actor> takes ' + amount + '.')				elif cmd.verb == pubverbs.drop:					cmd.Tell('You drop ' + amount + '.', \							'<The actor> drops ' + amount + '.')				elif cmd.verb == pubverbs.give:					cmd.Tell('You give ' + amount + ' to <toobj>.', \							'<The actor> gives ' + amount + ' to <toobj>.',							'<The actor> gives you ' + amount + ' (you now have '+ \							 str(self.quantity)+').', cmd.toobj )				else:					cmd.Tell('You '+cmd.verb.synonyms[0]+' '+amount+'.', \							'<The actor> '+cmd.verb.synonyms[0]+'s '+amount+'.' )				return CANCEL		return OK		#----------------------------------------------------------------------# NPC -- a Non-Player Character; an Actor with simple responses#class NPC(Actor):	def __init__(self,pNames=''):		Actor.__init__(self,pNames)		self.obedient = TRUE		self.replies = { 			'hello': [ 'Hi', 'Hello', 'Hi already!', 'Sheesh!' ],			'howdy': [ 'Howdy to you.', 'Hi' ],			'weather': [ "Yes, isn't it?", "Beautiful, just beautiful." ],			'thank': [ "You're welcome.", "No problem.", "Think nothing of it."]		}		self.replies['hi'] = self.replies['hello']		self.replies['thanks'] = self.replies['thank']		self.noReply = self.GetName() + " does not reply."		self.replyCounter = {}		# Here's the main function through which NPC's react:	# they hear something, via their Tell() method	def Tell(self, pWhat):		# if it's something we said, don't reply		if (regex.match('You say ".*"',pWhat)): return		# if it's someone else speaking, figure out who		if (regex.match('.* says, ".*"',pWhat)):			speakername = string.split(pWhat)[0]			speaker = self.FindNoun( string.lower(speakername) )			if not speaker:				self.Announce( self.GetName()+' looks around in confusion. ' \					+ '"Who said that?!?"' )				return						sezwhat = string.split(pWhat,'"')[1]			return self.HearSpeech( speaker, sezwhat )		# if it's not either, it must be some effect		self.HearEffect( pWhat )		def HearSpeech(self, pSpeaker, pSpeech):		# is the speaker speaking to me?		for word in self.synonyms:			if (string.count( string.lower(pSpeech), word )):				pSpeaker.speakingTo = self#		print pSpeaker, ' speaking to ', pSpeaker.speakingTo				# if not speaking to me, then maybe ignore it		if pSpeaker.speakingTo != self and random.randint(0,1): return				words = string.split( stripPunctuation(pSpeech) )		if not words: return		# for now, assume speaker is speaking to me		# check for keywords		for word in words:			# remove punctuation			word = stripPunctuation(word)			if self.replies.has_key(word):				# found a word!				if not self.replyCounter.has_key(word): repnum = -1				else: repnum = self.replyCounter[word]				repnum = repnum + 1				if repnum >= len(self.replies[word]): repnum = 0				self.replyCounter[word] = repnum				self.DoCommandString('say '+self.replies[word][repnum])				return				# no keywords found?  Check for a verb (or name, then verb)		w = 0		if self.NameMatch(words[w]):			# ah, my name -- definitely speaking to me!			if len(words) < 2: return			w = 1#		print "Checking for a verb: ", words[w]		if pub.verbdict.has_key(words[w]):			# looks like a command!			return self.HearCommand( pSpeaker, string.join(words[w:]) )					# no verbs either?  Give null reply (or nothing at all)		if random.randint(0,2): self.Announce( self.noReply )	def HearCommand(self, pCommander, pCmdStr ):		# if not obedient...		if not self.obedient:			pCommander.Tell( self.GetName() + " ignores you.")			return		# if obedient, then execute the command		# after converting all "me"s to commander's name		pCmdStr = replace( "me", pCommander.synonyms[0], pCmdStr )		self.DoCommandString( pCmdStr )	def HearEffect(self, pStr ):		# nothing for now...		return#----------------------------------------------------------------------## create the two required objects#pub.universe = Room("Universe")pub.player = Player("Everyman")