player.py 4.98 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"
	
Constantin's avatar
SOKOBAN    
Constantin committed
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
	def isMovedBy(self,pusher):
		dx = self.field.column - pusher.field.column
		dy = self.field.row    - pusher.field.row
		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):
					playerToPush = thing # yes, this may have higher speeds than one *grin*
					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...")
			self.game.labyrinth.moveThing(self,pushTarget,(lambda:playerToPush.isMovedBy(self) if playerToPush else None))
	
Ralf's avatar
Ralf committed
81
82
	# high(er)-level functions
	def readCmd(self, cmd):
Ralf's avatar
Ralf committed
83
		self.game.log("Someone [{1}] wrote '{0}'".format(cmd, self.uid))
Ralf's avatar
Ralf committed
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
		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
102
103
104
105
			playerToPush = None
			for thing in target.things:
				if thing != self and isinstance(thing, Player):
					playerToPush = thing
Ralf's avatar
Ralf committed
106
					self.send("By moving to the "+direction[0]+" you pushed another player away.")
Constantin's avatar
SOKOBAN    
Constantin committed
107
108
109
			
			self.game.labyrinth.moveThing(self, target, (lambda:playerToPush.isMovedBy(self) if playerToPush else None))
			
Ralf's avatar
Ralf committed
110
111
		elif verb in sayVerbs:
			msg = " ".join(words[1:])
Ralf's avatar
Ralf committed
112
			for dx, dy in directionOffsets.values():
Ralf's avatar
Ralf committed
113
				for thing in self.field.neighbor(dx=dx, dy=dy).things:
Ralf's avatar
Ralf committed
114
115
					if isinstance(thing, Player) and thing != self:
						thing.send("You hear someone saying: "+msg)
Ralf's avatar
Ralf committed
116
117
			for admin in self.game.admins:
				admin.send("{0} says: {1}".format(self.uid, msg))
Ralf's avatar
Ralf committed
118
			self.send("You say: "+msg)
119
120
121
		elif verb in leaveVerbs:
			self.send("Good Bye!")
			self.game.removePlayer(self)
Ralf's avatar
Ralf committed
122
123
124
125
126
127
128
129
130
131
		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?")
132
133
		else:
			self.send("I don't know what you are talking about")
Ralf's avatar
Ralf committed
134
	
Constantin's avatar
Constantin committed
135
136
	def afterMove(self, oldField):
		desc = self.game.labyrinth.getDescription(self.field)
137
		self.send(desc, end="")
Ralf's avatar
Ralf committed
138
139
140
	
	def asChar(self):
		return "P"