player.py 4.92 KB
Newer Older
1
from util import *
Ralf's avatar
Ralf committed
2 3
from thing import Thing
from labyrinth import directions as directionOffsets
Constantin's avatar
SOKOBAN  
Constantin committed
4
from labyrinth import directions_inv as directions_t
5

Ralf's avatar
Ralf committed
6 7
goVerbs = ['go', 'walk', 'run']
sayVerbs = ['say', 'talk', 'scream', 'whisper']
Ralf's avatar
Ralf committed
8
announceVerbs = ['announce']
9
leaveVerbs = ['leave', 'quit', 'exit', 'suicide']
Ralf's avatar
Ralf committed
10

Ralf's avatar
Ralf committed
11 12
playerUID = 0

Ralf's avatar
Ralf committed
13
class Player(Thing):
Ralf's avatar
Ralf committed
14
	def __init__(self, game, conn):
Ralf's avatar
Ralf committed
15
		global playerUID
Constantin's avatar
Constantin committed
16
		super().__init__()
Ralf's avatar
Ralf committed
17 18 19
		self.buffer = b""
		self.game = game
		self.conn = conn
Ralf's avatar
Ralf committed
20 21 22
		self.uid = playerUID
		playerUID += 1
		log_stdout("New player: {0}".format(self.uid))
Ralf's avatar
Ralf committed
23 24
	
	# low-level functions
25
	def send(self, data, end='\n'):
Ralf's avatar
Ralf committed
26
		assert type(data) == str
27
		send_async(self.conn, (data+end).encode('utf-8'))
Ralf's avatar
Ralf committed
28 29 30
	
	def close(self): # only to be called by Game - it has to remove us from its list
		self.conn.close()
Ralf's avatar
Ralf committed
31
		log_stdout("Player left: {0}".format(self.uid))
32
		return self.conn
Ralf's avatar
Ralf committed
33 34 35 36 37 38 39
	
	def read(self, conn, mask):
		assert self.conn == conn, "The player's connection changed?"
		data = conn.recv(1024)  # Should be ready
		if data:
			self.buffer += data
			pos = self.buffer.find(b'\n')
Ralf's avatar
Ralf committed
40
			while pos >= 0:
Ralf's avatar
Ralf committed
41 42
				cmd = self.buffer[:pos]
				self.buffer = self.buffer[pos+1:]
43 44 45 46
				try:
					self.readCmd(cmd.decode('utf-8'))
				except UnicodeDecodeError:
					self.send("These are bad bytes...")
Ralf's avatar
Ralf committed
47 48
				# maybe we got several lines?
				pos = self.buffer.find(b'\n')
Ralf's avatar
Ralf committed
49 50 51
		else:
			self.game.removePlayer(self)
	
Ralf's avatar
Ralf committed
52
	def __str__(self):
Constantin's avatar
Constantin committed
53 54
		return "another player"
	
55 56
	def pushAway(self,pusher,direction):
		dy,dx = directionOffsets[direction]
Constantin's avatar
SOKOBAN  
Constantin committed
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
		pushTarget = self.field.neighbor(dx=dx,dy=dy)
		travelDistance = 1
		while pushTarget is not None and not pushTarget.isWalkable():
			travelDistance+=1
			pushTarget = pushTarget.neighbor(dx=dx,dy=dy)
		if pushTarget is None:
			self.send("Another player pushed you out of the playing field.\nYou are dead.\nGood Bye.")
			self.game.removePlayer(self)
		else:
			assert travelDistance >= 1
			if travelDistance == 1:
				self.send("Another player pushed you to the "+directions_t[(dy,dx)]+".")
			elif travelDistance == 2:
				self.send("Another player pushed you SO HARD to the "+directions_t[(dy,dx)]+", that you flew right THROUGH A WALL!\nThis must have been a very rare occurence of quantum tunneling!\nYou feel a bit dizzy.")
			else:
				self.send("Another player pushed you SO HARD to the "+directions_t[(dy,dx)]+", that you flew through a very thick, gamma-ray proof wall.\nYou are unsure about how you survived this, but quickly remember that you are in a completely virtual world with arbitrary phsyics. This makes you feel comfortable.")
			playerToPush = None
			for thing in pushTarget.things:
				if thing != self and isinstance(thing, Player):
76
					playerToPush = thing
Constantin's avatar
SOKOBAN  
Constantin committed
77
					self.send("After coming out of the wall with incredible speed, you hit another player, who is in turn pushed away by your momentum. Poor bastard...")
Ralf's avatar
Ralf committed
78
			self.game.labyrinth.moveThing(self,pushTarget,(lambda:playerToPush.pushAway(self,direction)) if playerToPush else None)
Constantin's avatar
SOKOBAN  
Constantin committed
79
	
Ralf's avatar
Ralf committed
80 81
	# high(er)-level functions
	def readCmd(self, cmd):
Ralf's avatar
Ralf committed
82
		self.game.log("Someone [{1}] wrote '{0}'".format(cmd, self.uid))
Ralf's avatar
Ralf committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
		words = cmd.lower().split()
		if not words:
			self.send("What did you mean?")
			return
		verb = words[0]
		if verb in goVerbs:
			if len(words) >= 3 and words[1:3] == ["to", "the"]:
				direction = words[3:]
			else:
				direction = words[1:]
			if len(direction) != 1 or direction[0] not in directionOffsets:
				self.send("Where do you want to go?")
				return
			dy, dx = directionOffsets.get(direction[0])
			target = self.field.neighbor(dy=dy, dx=dx)
			if target is None or not target.isWalkable():
				self.send("Sorry, you cannot go there")
				return
Constantin's avatar
SOKOBAN  
Constantin committed
101 102 103 104
			playerToPush = None
			for thing in target.things:
				if thing != self and isinstance(thing, Player):
					playerToPush = thing
105
					self.send("By moving to the "+direction[0]+" you pushed another player away.")
Constantin's avatar
SOKOBAN  
Constantin committed
106
			
Ralf's avatar
Ralf committed
107
			self.game.labyrinth.moveThing(self, target, (lambda:playerToPush.pushAway(self,direction[0])) if playerToPush else None)
Constantin's avatar
SOKOBAN  
Constantin committed
108
			
Ralf's avatar
Ralf committed
109 110
		elif verb in sayVerbs:
			msg = " ".join(words[1:])
Ralf's avatar
Ralf committed
111
			for dx, dy in directionOffsets.values():
Ralf's avatar
Ralf committed
112
				for thing in self.field.neighbor(dx=dx, dy=dy).things:
Ralf's avatar
Ralf committed
113 114
					if isinstance(thing, Player) and thing != self:
						thing.send("You hear someone saying: "+msg)
Ralf's avatar
Ralf committed
115 116
			for admin in self.game.admins:
				admin.send("{0} says: {1}".format(self.uid, msg))
Ralf's avatar
Ralf committed
117
			self.send("You say: "+msg)
118 119 120
		elif verb in leaveVerbs:
			self.send("Good Bye!")
			self.game.removePlayer(self)
Ralf's avatar
Ralf committed
121 122 123 124 125 126 127 128 129 130
		elif verb == self.game.adminPW:
			self.send("Welcome to the vault, my son")
			self.game.makeAdmin(self)
		elif verb in announceVerbs:
			if self.game.isAdmin(self):
				msg = " ".join(words[1:])
				for player in self.game.players:
					player.send("Though Hearest A Voice Sayin': "+msg)
			else:
				self.send("Who Do Though Think Though Are?")
131 132
		else:
			self.send("I don't know what you are talking about")
Ralf's avatar
Ralf committed
133
	
Constantin's avatar
Constantin committed
134
	def afterMove(self, oldField):
Ralf's avatar
Ralf committed
135
		desc = self.game.labyrinth.getDescription(self)
136
		self.send(desc, end="")
Ralf's avatar
Ralf committed
137
	
Ralf's avatar
Ralf committed
138
	def __repr__(self):
Ralf's avatar
Ralf committed
139
		return "P"