player.py 4.9 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']
sayVerbs = ['say', 'talk', 'scream']
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)) 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
135
	def afterMove(self, oldField):
		desc = self.game.labyrinth.getDescription(self.field)
136
		self.send(desc, end="")
Ralf's avatar
Ralf committed
137
138
139
	
	def asChar(self):
		return "P"