-
Notifications
You must be signed in to change notification settings - Fork 5
/
models.py
198 lines (171 loc) · 5.26 KB
/
models.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
import logging
import os
import dfrotz
class Story:
"""
The Story class acts as a model for
collecting metadata about the story files.
The class is always keeping track
of its instances.
"""
instances = []
def __init__(self, name, abbrev, filename):
"""
Every Story instance is created by being
supplied with a name (the full game title),
an abbreviation (so the user may select it
quickly) and a filename, respectively.
"""
self.__class__.instances.append(self)
self.name = name
self.abbrev = abbrev
self.path = os.path.join('stories', filename)
@classmethod
def get_instance_by_abbrev(self, abbrev):
"""
Returns a Story instance for the associated
abbreviation - or None.
"""
for story in self.instances:
if story.abbrev == abbrev:
return story
return None
def __repr__(self):
return '<Story: %s [%s]>' % (self.abbrev, self.path)
class Chat:
"""
The Chat class acts as a model for
keeping track of a Telegram (group) chat
involving the bot.
In addition, the class is always keeping track
of its instances.
"""
instances = []
def __init__(self, id):
"""
Every Chat instance is created by being
supplied with an ID (usually just Telegram's
chat id).
"""
self.__class__.instances.append(self)
self.frotz = None
self.id = id
self.savedir = None
self.story = None
#self.stage =
@classmethod
def get_instance_or_create(self, id):
"""
Returns a Chat instance for the given
Telegram chat id - or creates an instance,
if it's not existing.
"""
if len(self.instances) > 0:
for chat in self.instances:
if chat.id == id:
logging.debug('Using existing Chat instance: %r' % chat)
return chat
# no instance found / not existing
chat = Chat(id)
logging.debug('Created new Chat instance: %r' % chat)
return chat
def has_story(self):
"""
Returns True if a Story instance is
linked to the Chat instance via
self.set_story.
"""
return self.story is not None
def set_story(self, story):
"""
Links a Story instance to the calling
Chat instance. Implicitly runs the
Frotz interpreter for the linked Story's
game file.
"""
self.story = story
self.frotz = dfrotz.DFrotz(Z5Bot.interpreter, self.story.path)
def __repr__(self):
if self.story is not None:
return '<Chat: %d, playing %r>' % (self.id, self.story.name)
return '<Chat: %d>' % self.id
class Z5Bot:
"""
The Z5Bot class keeps track of
linked Chat instances and provides
various methods for communicating
with the game.
"""
instances = []
interpreter = os.path.join('tools', 'dfrotz')
def __init__(self):
"""
No arguments are needed for creating
a Z5Bot instance.
"""
self.__class__.instances.append(self)
self.broadcasted = False
self.chats = []
self.parser = None
self.cwd = None
@classmethod
def get_instance_or_create(self):
"""
Returns a Z5Bot instance if there's already
an active one. Else, the class will create
one.
"""
if len(self.instances) > 0:
instance = self.instances[0]
logging.debug('Using %r!' % instance)
else:
instance = Z5Bot()
logging.debug('Created new Z5Bot instance!')
return instance
def add_parser(self, parser):
"""
Links a parser.Parser instance
to the calling Z5Bot instance.
"""
self.parser = parser
def add_chat(self, new_chat):
"""
Links a Chat instance to the calling
Z5Bot instance.
"""
# Create the Chat's save directory if it doesn't exist
new_chat.savedir = self.cwd.joinpath("saves/%d/" % new_chat.id)
os.makedirs(new_chat.savedir, exist_ok=True)
# Remove an already existing Chat instance before adding the new one
for chat in self.chats:
if chat.id == new_chat.id:
self.chats.remove(chat)
self.chats.append(new_chat)
def get_chat_by_id(self, id):
"""
Returns a Chat instance for the given
Telegram chat id - or None if there
is no matching Chat instance.
"""
for chat in self.chats:
if chat.id == id:
return chat
else:
return None
def process(self, id, command):
"""
Takes user input and redirects it
to the Frotz interpreter.
"""
self.chat = self.get_chat_by_id(id)
self.chat.frotz.send('%s\r\n' % command)
def receive(self, id):
"""
Returns Frotz' buffered output.
"""
self.chat = self.get_chat_by_id(id)
return self.chat.frotz.get()
def set_cwd(self, cwd):
self.cwd = cwd
def __repr__(self):
return '<Z5Bot, %d chats>' % len(self.chats)