WWWJDIC: Fixed to match the abrupt change in result format.
[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 """Stats are {stats}, total {total}. """ \
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 total=sum(_.base_stat for _ in obj.stats),
148 link_name=link_name,
149 )
150 )
151
152 elif isinstance(obj, tables.Move):
153 reply_template = \
154 u"""{name}, {type}-type {damage_class} move. """ \
155 """{power} power; {accuracy}% accuracy; {pp} PP. """ \
156 """{effect} """ \
157 """http://veekun.com/dex/moves/{link_name}"""
158 self._reply(irc, reply_template.format(
159 name=obj.name,
160 type=obj.type.name,
161 damage_class=obj.damage_class.name,
162 power=obj.power,
163 accuracy=obj.accuracy,
164 pp=obj.pp,
165 effect=unicode(obj.short_effect.as_html),
166 link_name=urllib.quote(obj.name.lower().encode('utf8')),
167 )
168 )
169
170 elif isinstance(obj, tables.Type):
171 reply_template = u"""{name}, a type. """
172
173 reply_factors = { 200: u'2', 50: u'½', 0: u'0' }
174
175 offensive_modifiers = {}
176 for matchup in obj.damage_efficacies:
177 if matchup.damage_factor != 100:
178 offensive_modifiers.setdefault(matchup.damage_factor, []) \
179 .append(matchup.target_type.name)
180 if offensive_modifiers:
181 reply_template += u"""{offensive_modifiers}. """
182 for factor in offensive_modifiers:
183 offensive_modifiers[factor] = u'{factor}× against {types}'.format(
184 factor=reply_factors[factor],
185 types=', '.join(sorted(offensive_modifiers[factor]))
186 )
187
188 defensive_modifiers = {}
189 for matchup in obj.target_efficacies:
190 if matchup.damage_factor != 100:
191 defensive_modifiers.setdefault(matchup.damage_factor, []) \
192 .append(matchup.damage_type.name)
193 if defensive_modifiers:
194 reply_template += u"""{defensive_modifiers}. """
195 for factor in defensive_modifiers:
196 defensive_modifiers[factor] = u'{factor}× from {types}'.format(
197 factor=reply_factors[factor],
198 types=', '.join(sorted(defensive_modifiers[factor]))
199 )
200
201 reply_template += u"""http://veekun.com/dex/types/{link_name}"""
202
203 self._reply(irc, reply_template.format(
204 name=obj.name.capitalize(),
205 offensive_modifiers='; '.join(offensive_modifiers[_]
206 for _ in sorted(offensive_modifiers)),
207 defensive_modifiers='; '.join(defensive_modifiers[_]
208 for _ in sorted(defensive_modifiers)),
209 link_name=urllib.quote(obj.name.lower().encode('utf8')),
210 )
211 )
212
213 elif isinstance(obj, tables.Item):
214 reply_template = \
215 u"""{name}, an item. """ \
216 """http://veekun.com/dex/items/{link_name}"""
217 self._reply(irc, reply_template.format(
218 name=obj.name,
219 link_name=urllib.quote(obj.name.lower().encode('utf8')),
220 )
221 )
222
223 elif isinstance(obj, tables.Ability):
224 reply_template = \
225 u"""{name}, an ability. {effect} """ \
226 """http://veekun.com/dex/abilities/{link_name}"""
227 self._reply(irc, reply_template.format(
228 name=obj.name,
229 effect=obj.effect,
230 link_name=urllib.quote(obj.name.lower().encode('utf8')),
231 )
232 )
233
234 else:
235 # This can only happen if lookup.py is upgraded and we are not
236 self._reply(irc, "Uhh.. I found that, but I don't know what it is. :(")
237
238 pokedex = wrap(pokedex, [rest('something')])
239
240 def _reply(self, irc, response):
241 """Wraps irc.reply() to do some Unicode decoding."""
242 if isinstance(response, str):
243 irc.reply(response)
244 else:
245 irc.reply(response.encode('utf8'))
246
247
248 Class = Pokedex
249
250
251 # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: