I've found a small MUD-like single player game that I did with Python several years ago. Thought it would be nice to share the source. So here it is.
First of all, a live demo (type help. gone if my internet connection or home server is down.)
server down
And a "screenshot" (sorry for my bad sense of humor):
> help
welcome to mud. available commands are:
go, move, help, exit, look, say, take, drop, inventory, use
>
Unknown Command
> look
spajus sees deep green woods. There also seems to be: flower, bird
> touch bird
looks like a rainbow
> use bird
you do not have bird
> take bird
spajus puts bird in his inventory
> use bird
cuckarekoo! motherfucka!?!
> drop bird
bird was dropped..
> kill bird
Unknown Command
> look north
spajus sees shallow river. There also seems to be: object
> go north
spajus moves to shallow river
> look object
spajus sees a stinky one
> touch object
ewww...
> take object
spajus puts shit in his inventory
> use shit
you are sick, you know that?
Now, the
engine.py
- class MudObject:
- def __init__(self, name, sight, collide = 'nothing happens', usability = 'unusable'):
- self.name = name
- self.sight = sight
- self.collide = collide
- self.usability = usability
- def view(self):
- return self.sight
- def touch(self):
- return self.collide
- def use(self):
- return self.usability
- class MudPlayer:
- def __init__(self, name):
- self.inventory = {}
- self.name = name
- self.health = 100
- def move(self, area):
- return self.name + ' moves to ' + area.sight
- def take(self, obj):
- self.inventory[obj.name] = obj
- return self.name + ' puts ' + obj.name + ' in his inventory'
- def drop(self, name):
- if self.inventory.has_key(name):
- return self.inventory.pop(name)
- def say(self, what):
- return self.name + ' says: ' + what
- def use(self, what):
- if self.inventory.has_key(what):
- return self.inventory[what].use()
- else:
- return 'you do not have ' + what
- class MudArea:
- def __init__(self, sight):
- self.objects = {}
- self.panorama = {}
- self.sight = sight
- self.inverted_directions = {'north':'south', 'south':'north', 'east':'west', 'west':'east'}
- def addArea(self, direction, area):
- area.panorama[self.inverted_directions[direction]] = self
- self.panorama[direction] = area
- def relocate(self, args):
- try:
- return self.panorama[args]
- except KeyError:
- return None
- def addObject(self, name, obj):
- if obj != None:
- self.objects[name] = obj
- return name + ' was dropped..'
- def getObject(self, name):
- if self.objects.has_key(name):
- return self.objects.pop(name)
- else:
- return 'there is no ' + name + ' arround!'
- def touchObject(self, name):
- if self.objects.has_key(name):
- return self.objects[name].touch()
- else:
- return 'there is no ' + name + ' arround!'
- def view(self, args = 'arround'):
- if (args != '' and args != 'arround'):
- try:
- return self.panorama[args].view()
- except KeyError:
- try:
- return self.objects[args].view()
- except KeyError:
- return 'nothing.'
- else:
- objects = ', '.join([k for k, v in self.objects.items()])
- if (objects != ''):
- obsight = '. There also seems to be: ' + objects
- else:
- obsight = ''
- return self.sight + obsight
- import sys
- class MudCommand:
- """ welcome to mud. available commands are:
- go, move, help, exit, look, touch, say, take, drop, inventory, use """
- def __init__(self, char, area):
- self.char = char
- self.area = area
- def go(self, args):
- """ alias of move """
- return self.move(args)
- def use(self, args):
- """ uses item from inventory """
- return self.char.use(args)
- def inventory(self, args):
- """ displays inventory """
- return self.char.name + ' has: ' + ', '.join(self.char.inventory)
- def help(self, args):
- """ gives you help on a topic"""
- if args == '':
- return self.__doc__
- else:
- try:
- return getattr(self, args).__doc__
- except AttributeError:
- return 'help topic not found'
- def exit(self, args):
- """ exits game """
- print 'bye bye!'
- sys.exit()
- def look(self, args):
- """ lets you look arround """
- return self.char.name + ' sees ' + self.area.view(args)
- def take(self, args):
- """ takes item from the ground """
- try:
- return self.char.take(self.area.getObject(args))
- except AttributeError:
- return 'you cannot take ' + args
- def touch(self, args):
- """ touches item from the ground """
- return self.area.touchObject(args)
- def drop(self, args):
- """ drops item from inventory to current area """
- return self.area.addObject(args, self.char.drop(args))
- def move(self, args):
- """ moves arround """
- area = self.area.relocate(args)
- if area != None:
- self.area = area
- return self.char.move(self.area)
- else:
- return 'There seems to be nothing that way.'
- def say(self, args):
- """ makes character talk """
- return self.char.say(args)
- class MudGame:
- def __init__(self, char, area):
- self.cmd = MudCommand(char, area)
- def run(self):
- while True:
- command = raw_input('> ');
- self.parse(command)
- def parse(self, command):
- comm = command.lower().split(' ')
- try:
- cmd = comm[0]
- except IndexError:
- cmd = 'help'
- try:
- args = comm[1:]
- except IndexError:
- args = []
- try:
- result = getattr(self.cmd, cmd)(' '.join(args).strip())
- except AttributeError:
- result = 'Unknown Command'
- print result
And the main game script -
mud.py
:- from engine import *
- #objects (name, description, on touch, on use)
- rose = MudObject('rose', 'a red blossom with spikes', 'bites fingers!', 'wanna eat it or what?')
- shit = MudObject('shit', 'a stinky one', 'ewww...', 'you are sick, you know that?')
- gaidys = MudObject('bird', 'oh, a cock!', 'looks like a rainbow', 'cuckarekoo! motherfucka!?!')
- #areas
- woods = MudArea('deep green woods')
- river = MudArea('shallow river')
- hills = MudArea('orc hills')
- house = MudArea('house of all gay')
- meadow = MudArea('a green smelly meadow')
- #attaching interactive stuff to areas
- river.addObject('object', shit)
- woods.addObject('flower', rose)
- woods.addObject('bird', gaidys)
- meadow.addObject('animal', gaidys)
- #link all areas with bidirectional references
- river.addArea('south', hills)
- woods.addArea('north', river)
- woods.addArea('west', house)
- hills.addArea('east', meadow)
- meadow.addArea('north', woods)
- #create a player
- char = MudPlayer('spajus')
- #create a game with player and starting area
- game = MudGame(char, woods)
- #lets go!
- game.run()
OK, and of course, unit tests:
- import unittest
- from engine import *
- class TestMudObject(unittest.TestCase):
- def setUp(self):
- self.o = MudObject('object1', 'sight1', 'collision1', 'usage1')
- self.o2 = MudObject('object2', 'sight2')
- def test_view(self):
- self.assertEqual(self.o.view(), 'sight1')
- self.assertEqual(self.o2.view(), 'sight2')
- self.assertNotEqual(self.o.view(), 'c')
- self.assertNotEqual(self.o.view(), self.o2.view())
- def test_touch(self):
- self.assertEqual(self.o.touch(), 'collision1')
- self.assertEqual(self.o2.touch(), 'nothing happens')
- self.assertNotEqual(self.o.touch(), 'sight1')
- self.assertNotEqual(self.o.touch(), self.o2.touch())
- def test_use(self):
- self.assertEqual(self.o.use(), 'usage1')
- self.assertEqual(self.o2.use(), 'unusable')
- self.assertNotEqual(self.o.use(), 'unsuable')
- self.assertNotEqual(self.o.use(), self.o2.use())
- class TestMudPlayer(unittest.TestCase):
- def setUp(self):
- self.p1 = MudPlayer('player1')
- self.p2 = MudPlayer('player2')
- self.area1 = MudArea('area1')
- self.area2 = MudArea('area2')
- self.o = MudObject('object1', 'sight1', 'collision1', 'usage1')
- self.o2 = MudObject('object2', 'sight2')
- def test_move(self):
- f1 = self.p1.move
- f2 = self.p2.move
- a1 = self.area1
- a2 = self.area2
- self.assertEqual(f1(a1), 'player1 moves to area1')
- self.assertEqual(f2(a1), 'player2 moves to area1')
- self.assertEqual(f1(a2), 'player1 moves to area2')
- self.assertEqual(f2(a2), 'player2 moves to area2')
- self.assertNotEqual(f1(a1), 'player1 moves to area2')
- def test_take_drop(self):
- take = self.p1.take
- use = self.p1.use
- drop = self.p1.drop
- inven = self.p1.inventory
- o1 = self.o
- o2 = self.o2
- self.assertEqual(inven, {})
- self.assertEqual(take(o1), 'player1 puts object1 in his inventory')
- self.assertEqual(inven, {'object1':o1})
- self.assertEqual(take(o2), 'player1 puts object2 in his inventory')
- self.assertEqual(inven, {'object1':o1, 'object2':o2})
- self.assertEqual(drop('object1'), o1)
- #neesamo objekto dropint neina
- self.assertRaises(TypeError, drop('object1'))
- self.assertEqual(inven, {'object2':o2})
- self.assertEqual(drop('object2'), o2)
- self.assertEqual(inven, {})
- def test_use(self):
- p1 = self.p1
- o1 = self.o
- self.assertNotEqual(p1.use('object1'), 'usage1')
- self.assertEqual(p1.use('object1'), 'you do not have object1')
- p1.take(o1)
- self.assertEqual(p1.use('object1'), 'usage1')
- class TestMudArea(unittest.TestCase):
- def setUp(self):
- self.a1 = MudArea('area1')
- self.a2 = MudArea('area2')
- self.o1 = MudObject('obj1', 'sight1', 'collide1', 'use1')
- self.o2 = MudObject('obj2', 'sight2')
- def test_addArea(self):
- #assignmentas turi buti veidrodinis
- self.a1.addArea('north', self.a2)
- self.assertEqual(self.a1.panorama, {'north':self.a2})
- self.assertEqual(self.a2.panorama, {'south':self.a1})
- def test_relocate(self):
- self.a1.addArea('north', self.a2)
- self.assertEqual(self.a1.relocate('north'), self.a2)
- self.assertEqual(self.a2.relocate('north'), None)
- self.assertEqual(self.a2.relocate('south'), self.a1)
- def test_addObject(self):
- self.assertEqual(self.a1.objects, {})
- #dropped returninama todel, kad paprastai objectas zaidimo metu addinamas tada, kai playeris dropina ji.
- #kreivai biski, bet ka padarysi :)
- self.assertEqual(self.a1.addObject('something', self.o1), 'something was dropped..')
- self.assertEqual(self.a1.objects, {'something':self.o1})
- self.a1.addObject('other', self.o2)
- self.assertEqual(self.a1.objects, {'something':self.o1, 'other':self.o2})
- self.assertEqual(self.a1.addObject('something_clone', self.o1), 'something_clone was dropped..')
- self.assertEqual(self.a1.objects, {'something':self.o1, 'other':self.o2, 'something_clone':self.o1})
- def test_getObject(self):
- self.assertEqual(self.a1.objects, {})
- self.a1.addObject('something', self.o1)
- self.a1.addObject('other', self.o2)
- self.assertEqual(self.a1.getObject('something'), self.o1)
- self.assertEqual(self.a1.objects, {'other':self.o2})
- self.assertEqual(self.a1.getObject('something'), 'there is no something arround!')
- def test_touchObject(self):
- self.assertEqual(self.a1.objects, {})
- self.a1.addObject('something', self.o1)
- self.a1.addObject('other', self.o2)
- self.assertEqual(self.a1.touchObject('something'), self.o1.touch())
- self.assertNotEqual(self.a1.touchObject('obj2'), self.o2.touch())
- self.assertEqual(self.a1.touchObject('ass'), 'there is no ass arround!')
- def test_view(self):
- view = self.a1.view
- self.assertEqual(view(), 'area1')
- #unindentified object/panorama
- self.assertEqual(view('my brain'), 'nothing.')
- self.a1.addObject('my brain', self.o1)
- self.assertEqual(view('my brain'), self.o1.view())
- #padarom dar idomiau. kadangi pridejom my brain, reikia parodyti ir tai..
- self.assertNotEqual(view(), 'area1')
- self.assertEqual(view(), 'area1. There also seems to be: my brain')
- self.a1.addObject('duck', self.o2)
- self.assertEqual(view(), 'area1. There also seems to be: my brain, duck') #', '.join(self.a1.objects)
- self.assertEqual(view('north'), 'nothing.')
- self.a1.addArea('north', self.a2)
- self.assertEqual(view('north'), 'area2')
- #kadangi priskyrem area2, turejo atsispindeti ir is ten paziurejus i priesinga north krypti (south), turi matytis area1 viewas
- self.assertEqual(self.a2.view('south'), view())
- #akurat.. matosi :)
- class MudCommandTest(unittest.TestCase):
- def setUp(self):
- self.p1 = MudPlayer('player1')
- self.a1 = MudArea('area1')
- self.a2 = MudArea('area2')
- self.o1 = MudObject('obj1', 'sight1', 'collide1', 'use1')
- self.o2 = MudObject('obj2', 'sight2', 'collide2', 'use2')
- self.a2.addObject('bread', self.o1)
- self.a2.addObject('pig', self.o2)
- self.a1.addArea('east', self.a2)
- self.c = MudCommand(self.p1, self.a1)
- def test_go_move(self):
- #MudArea.go === MudArea.move
- #test wrong way
- self.assertEqual(self.c.go('somewhere'), 'There seems to be nothing that way.')
- #test walk arround
- self.assertEqual(self.c.go('east'), 'player1 moves to area2')
- self.assertEqual(self.c.go('west'), 'player1 moves to area1')
- def test_use(self):
- self.assertEqual(self.c.use('bla'), 'you do not have bla')
- #lets go east and take something to test using
- self.c.go('east')
- self.c.take('bread')
- #as bread was only the looks, we know it's actually obj1, so lets use it
- self.assertEqual(self.c.use('obj1'), self.o1.use())
- def test_inventory(self):
- self.c.go('east')
- self.c.take('bread')
- self.assertEqual(self.c.inventory(None), 'player1 has: obj1')
- def test_help(self):
- self.assertEqual(self.c.help(''), self.c.__doc__)
- self.assertEqual(self.c.help('move'), self.c.move.__doc__)
- self.assertEqual(self.c.help('blabla'), 'help topic not found')
- def test_look(self):
- self.assertEqual(self.c.look(''), 'player1 sees ' + self.a1.view())
- self.assertEqual(self.c.look('at my balls'), 'player1 sees nothing.')
- self.assertEqual(self.c.look('east'), 'player1 sees ' + self.a2.view())
- def test_take(self):
- self.c.go('east')
- self.assertEqual(self.c.take('bread'), 'player1 puts obj1 in his inventory')
- self.assertEqual(self.p1.inventory, {'obj1':self.o1})
- #already taken!
- self.assertEqual(self.c.take('bread'), 'you cannot take bread')
- def test_touch(self): #perv test.. :)
- self.assertEqual(self.c.touch('self'), 'there is no self arround!')
- self.assertNotEqual(self.c.touch('bread'), self.o1.touch())
- self.c.go('east')
- #kad paliesti reik pirma nueiti
- self.assertEqual(self.c.touch('bread'), self.o1.touch())
- def test_drop(self):
- self.assertEqual(self.c.drop('smelly thing'), None)
- self.c.go('east')
- self.c.take('bread')
- self.c.go('west')
- self.assertEqual(self.c.drop('obj1'), 'obj1 was dropped..')
- self.assertEqual(self.a1.objects, {'obj1':self.o1})
- def test_say(self):
- self.assertEqual(self.c.say('i love this game'), 'player1 says: i love this game')
- self.assertNotEqual(self.c.say('python sucks'), 'player1 says: that\'s true!')
- if __name__ == '__main__':
- unittest.main()
To run the game:
python mud.py
To run the tests:
python testengine.py
Damn, I really miss such coding activities :)
thats pretty neat.
ReplyDeleteThis is very cool! I'm trying to get my brain around Python and examples like this help me out!
ReplyDeletePretty well coded. Thanks for sharing this with us :).
ReplyDelete"small MUD-like single player game"
ReplyDeleteI think you missed the whole point with the M in MUD :)
Hey, thanks for sharing this.
ReplyDeleteIt's got me started in the right direction for classifying a mud. Good organization!
Hi I'm Kan:
ReplyDeletei follow the code, but error shows.
the program close automatic. Please help.
Thanks
I think that's why he said "MUD-like"... because it isn't a MUD. What was he supposed to say? UD game? :)
ReplyDeleteEduard K
SUD
ReplyDelete