c576bd68e5658758eef53b575a2e2473f17615f5
[zzz-dywypi.git] / plugins / Pokedex / plugin.py
1 # encoding: utf8
2 ###
3 # Copyright (c) 2010, Alex Munroe
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions are met:
8 #
9 # * Redistributions of source code must retain the above copyright notice,
10 # this list of conditions, and the following disclaimer.
11 # * Redistributions in binary form must reproduce the above copyright notice,
12 # this list of conditions, and the following disclaimer in the
13 # documentation and/or other materials provided with the distribution.
14 # * Neither the name of the author of this software nor the name of
15 # contributors to this software may be used to endorse or promote products
16 # derived from this software without specific prior written consent.
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 # POSSIBILITY OF SUCH DAMAGE.
29
30 ###
31
32 import supybot.conf as conf
33 import supybot.utils as utils
34 from supybot.commands import *
35 import supybot.plugins as plugins
36 import supybot.ircutils as ircutils
37 import supybot.callbacks as callbacks
38
39 import pokedex.db
40 import pokedex.db.tables as tables
41 import pokedex.lookup
42
43 import urllib
44
45 class Pokedex(callbacks.Plugin):
46 """Add the help for "@plugin help Pokedex" here
47 This should describe *how* to use this plugin."""
48 def __init__(self, irc):
49 self.__parent = super(Pokedex, self)
50 self.__parent.__init__(irc)
51 self.db = pokedex.db.connect(self.registryValue('databaseURL'))
52 self.indices = pokedex.lookup.open_index(
53 directory=conf.supybot.directories.data.dirize('pokedex-index'),
54 session=self.db,
55 )
56
57 def pokedex(self, irc, msg, args, thing):
58 """<thing...>
59
60 Looks up <thing> in the veekun Pokédex."""
61
62 # Fix encoding. Sigh.
63 if not isinstance(thing, unicode):
64 ascii_thing = thing
65 try:
66 thing = ascii_thing.decode('utf8')
67 except UnicodeDecodeError:
68 thing = ascii_thing.decode('latin1')
69
70 # Similar logic to the site, here.
71 results = pokedex.lookup.lookup(thing, session=self.db,
72 indices=self.indices)
73
74 # Nothing found
75 if len(results) == 0:
76 self._reply(irc, "I don't know what that is.")
77 return
78
79 # Multiple matches; propose them all
80 if len(results) > 1:
81 if results[0].exact:
82 reply = "Are you looking for"
83 else:
84 reply = "Did you mean"
85
86 # For exact name matches with multiple results, use type prefixes
87 # (item:Metronome). For anything else, omit them
88 use_prefixes = (results[0].exact
89 and '*' not in thing
90 and '?' not in thing)
91
92 result_strings = []
93 for result in results:
94 result_string = result.object.name
95
96 # Prepend, e.g., pokemon: if necessary
97 if use_prefixes:
98 # Table classes know their singular names
99 prefix = result.object.__singlename__
100 result_string = prefix + ':' + result_string
101
102 # Identify foreign language names
103 if result.language:
104 result_string += u""" ({0}: {1})""".format(
105 result.iso3166, result.name)
106
107 result_strings.append(result_string)
108
109 self._reply(irc, u"{0}: {1}?".format(reply, '; '.join(result_strings)))
110 return
111
112 # If we got here, there's an exact match; hurrah!
113 result = results[0]
114 obj = result.object
115 if isinstance(obj, tables.Pokemon):
116 reply_template = \
117 u"""#{id} {name}, {type}-type Pokémon. Has {abilities}. """ \
118 """Is {stats}. """ \
119 """http://veekun.com/dex/pokemon/{link_name}"""
120
121 if obj.forme_name:
122 name = '{form} {name}'.format(
123 form=obj.forme_name.title(),
124 name=obj.name
125 )
126 else:
127 name = obj.name
128
129 if obj.forme_base_pokemon:
130 # Can't use urllib.quote() on the whole thing or it'll
131 # catch "?" and "=" where it shouldn't.
132 # XXX Also we need to pass urllib.quote() things explicitly
133 # encoded as utf8 or else we get a UnicodeEncodeError.
134 link_name = '{name}?form={form}'.format(
135 name=urllib.quote(obj.name.lower().encode('utf8')),
136 form=urllib.quote(obj.forme_name.lower().encode('utf8')),
137 )
138 else:
139 link_name = urllib.quote(obj.name.lower().encode('utf8'))
140
141 self._reply(irc, reply_template.format(
142 id=obj.national_id,
143 name=name,
144 type='/'.join(_.name for _ in obj.types),
145 abilities=' or '.join(_.name for _ in obj.abilities),
146 stats='/'.join(str(_.base_stat) for _ in obj.stats),
147 link_name=link_name,
148 )
149 )
150
151 elif isinstance(obj, tables.Move):
152 reply_template = \
153 u"""{name}, {type}-type {damage_class} move. """ \
154 """{power} power; {accuracy}% accuracy; {pp} PP. """ \
155 """{effect} """ \
156 """http://veekun.com/dex/moves/{link_name}"""
157 self._reply(irc, reply_template.format(
158 name=obj.name,
159 type=obj.type.name,
160 damage_class=obj.damage_class.name,
161 power=obj.power,
162 accuracy=obj.accuracy,
163 pp=obj.pp,
164 effect=unicode(obj.short_effect.as_html),
165 link_name=urllib.quote(obj.name.lower().encode('utf8')),
166 )
167 )
168
169 elif isinstance(obj, tables.Type):
170 reply_template = u"""{name}, a type. """
171
172 reply_factors = { 200: u'2', 50: u'½', 0: u'0' }
173
174 offensive_modifiers = {}
175 for matchup in obj.damage_efficacies:
176 if matchup.damage_factor != 100:
177 offensive_modifiers.setdefault(matchup.damage_factor, []) \
178 .append(matchup.target_type.name)
179 if offensive_modifiers:
180 reply_template += u"""{offensive_modifiers}. """
181 for factor in offensive_modifiers:
182 offensive_modifiers[factor] = u'{factor}× against {types}'.format(
183 factor=reply_factors[factor],
184 types=', '.join(sorted(offensive_modifiers[factor]))
185 )
186
187 defensive_modifiers = {}
188 for matchup in obj.target_efficacies:
189 if matchup.damage_factor != 100:
190 defensive_modifiers.setdefault(matchup.damage_factor, []) \
191 .append(matchup.damage_type.name)
192 if defensive_modifiers:
193 reply_template += u"""{defensive_modifiers}. """
194 for factor in defensive_modifiers:
195 defensive_modifiers[factor] = u'{factor}× from {types}'.format(
196 factor=reply_factors[factor],
197 types=', '.join(sorted(defensive_modifiers[factor]))
198 )
199
200 reply_template += u"""http://veekun.com/dex/types/{link_name}"""
201
202 self._reply(irc, reply_template.format(
203 name=obj.name.capitalize(),
204 offensive_modifiers='; '.join(offensive_modifiers[_]
205 for _ in sorted(offensive_modifiers)),
206 defensive_modifiers='; '.join(defensive_modifiers[_]
207 for _ in sorted(defensive_modifiers)),
208 link_name=urllib.quote(obj.name.lower().encode('utf8')),
209 )
210 )
211
212 elif isinstance(obj, tables.Item):
213 reply_template = \
214 u"""{name}, an item. """ \
215 """http://veekun.com/dex/items/{link_name}"""
216 self._reply(irc, reply_template.format(
217 name=obj.name,
218 link_name=urllib.quote(obj.name.lower().encode('utf8')),
219 )
220 )
221
222 elif isinstance(obj, tables.Ability):
223 reply_template = \
224 u"""{name}, an ability. {effect} """ \
225 """http://veekun.com/dex/abilities/{link_name}"""
226 self._reply(irc, reply_template.format(
227 name=obj.name,
228 effect=obj.effect,
229 link_name=urllib.quote(obj.name.lower().encode('utf8')),
230 )
231 )
232
233 else:
234 # This can only happen if lookup.py is upgraded and we are not
235 self._reply(irc, "Uhh.. I found that, but I don't know what it is. :(")
236
237 pokedex = wrap(pokedex, [rest('something')])
238
239 def _reply(self, irc, response):
240 """Wraps irc.reply() to do some Unicode decoding."""
241 if isinstance(response, str):
242 irc.reply(response)
243 else:
244 irc.reply(response.encode('utf8'))
245
246
247 Class = Pokedex
248
249
250 # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: