44from time import time
55
66from sqlalchemy import Table , Column , String , Integer , PrimaryKeyConstraint , desc , Boolean
7+ from sqlalchemy .exc import DatabaseError
78from sqlalchemy .sql import select
89
910from cloudbot import hook
1011from cloudbot .event import EventType
1112from cloudbot .util import database
13+ from cloudbot .util .formatting import pluralize
1214
1315duck_tail = "・゜゜・。。・゜゜"
1416duck = ["\_o< " , "\_O< " , "\_0< " , "\_\u00f6 < " , "\_\u00f8 < " , "\_\u00f3 < " ]
@@ -165,7 +167,7 @@ def stop_hunt(chan, conn):
165167
166168
167169@hook .command ("duckkick" , permissions = ["chanop" , "op" , "botcontrol" ])
168- def no_duck_kick (text , chan , conn , notice ):
170+ def no_duck_kick (text , chan , conn , notice_doc ):
169171 """<enable|disable> - If the bot has OP or half-op in the channel you can specify .duckkick enable|disable so that people are kicked for shooting or befriending a non-existent goose. Default is off."""
170172 global game_status
171173 if chan in opt_out :
@@ -177,7 +179,7 @@ def no_duck_kick(text, chan, conn, notice):
177179 game_status [conn .name ][chan ]['no_duck_kick' ] = 0
178180 return "kicking for non-existent ducks has been disabled."
179181 else :
180- notice ( no_duck_kick . __doc__ )
182+ notice_doc ( )
181183 return
182184
183185
@@ -191,7 +193,7 @@ def generate_duck():
191193 dnoise = random .choice (duck_noise )
192194 rn = random .randint (1 , len (dnoise ) - 1 )
193195 dnoise = dnoise [:rn ] + u'\u200b ' + dnoise [rn :]
194- return ( dtail , dbody , dnoise )
196+ return dtail , dbody , dnoise
195197
196198
197199@hook .periodic (11 , initial_interval = 11 )
@@ -216,11 +218,6 @@ def deploy_duck(bot):
216218 game_status [network ][chan ]['duck_time' ] = time ()
217219 dtail , dbody , dnoise = generate_duck ()
218220 conn .message (chan , "{}{}{}" .format (dtail , dbody , dnoise ))
219- # Leave this commented out for now. I haven't decided how to make ducks leave.
220- # if active == 1 and duck_status == 1 and game_status[network][chan]['flyaway'] <= int(time()):
221- # conn.message(chan, "The duck flew away.")
222- # game_status[network][chan]['duck_status'] = 2
223- # set_ducktime(chan, conn)
224221 continue
225222 continue
226223
@@ -277,127 +274,113 @@ def dbupdate(nick, chan, db, conn, shoot, friend):
277274 db .commit ()
278275
279276
280- @hook .command ("bang" , autohelp = False )
281- def bang (nick , chan , message , db , conn , notice ):
282- """- when there is a duck on the loose use this command to shoot it."""
283- global game_status , scripters
284- if chan in opt_out :
285- return
286- network = conn .name
287- out = ""
288- miss = ["WHOOSH! You missed the duck completely!" , "Your gun jammed!" , "Better luck next time." ,
289- "WTF?! Who are you, Kim Jong Un firing missiles? You missed." ]
290- if not game_status [network ][chan ]['game_on' ]:
291- return "There is no activehunt right now. Use .starthunt to start a game."
292- elif game_status [network ][chan ]['duck_status' ] != 1 :
293- if game_status [network ][chan ]['no_duck_kick' ] == 1 :
294- out = "KICK {} {} :There is no duck! What are you shooting at?" .format (chan , nick )
295- conn .send (out )
296- return
297- return "There is no duck. What are you shooting at?"
277+ def update_score (nick , chan , db , conn , shoot = 0 , friend = 0 ):
278+ score = db .execute (select ([table .c .shot , table .c .befriend ])
279+ .where (table .c .network == conn .name )
280+ .where (table .c .chan == chan .lower ())
281+ .where (table .c .name == nick .lower ())).fetchone ()
282+ if score :
283+ score = score [0 ]
284+ score += 1
285+ dbupdate (nick , chan , db , conn , score [0 ] + shoot , score [1 ] + friend )
298286 else :
299- game_status [network ][chan ]['shoot_time' ] = time ()
300- deploy = game_status [network ][chan ]['duck_time' ]
301- shoot = game_status [network ][chan ]['shoot_time' ]
302- if nick .lower () in scripters :
303- if scripters [nick .lower ()] > shoot :
304- notice ("You are in a cool down period, you can try again in {} seconds." .format (
305- str (scripters [nick .lower ()] - shoot )))
306- return
307- chance = hit_or_miss (deploy , shoot )
308- if not random .random () <= chance and chance > .05 :
309- out = random .choice (miss ) + " You can try again in 7 seconds."
310- scripters [nick .lower ()] = shoot + 7
311- return out
312- if chance == .05 :
313- out += "You pulled the trigger in {} seconds, that's mighty fast. Are you sure you aren't a script? Take a 2 hour cool down." .format (
314- str (shoot - deploy ))
315- scripters [nick .lower ()] = shoot + 7200
316- if not random .random () <= chance :
317- return random .choice (miss ) + " " + out
318- else :
319- message (out )
320- game_status [network ][chan ]['duck_status' ] = 2
321- score = db .execute (select ([table .c .shot ]) \
322- .where (table .c .network == conn .name ) \
323- .where (table .c .chan == chan .lower ()) \
324- .where (table .c .name == nick .lower ())).fetchone ()
325- if score :
326- score = score [0 ]
327- score += 1
328- dbupdate (nick , chan , db , conn , score , 0 )
329- else :
330- score = 1
331- dbadd_entry (nick , chan , db , conn , score , 0 )
332- timer = "{:.3f}" .format (shoot - deploy )
333- duck = "duck" if score == 1 else "ducks"
334- message ("{} you shot a duck in {} seconds! You have killed {} {} in {}." .format (nick , timer , score , duck , chan ))
335- set_ducktime (chan , conn .name )
287+ dbadd_entry (nick , chan , db , conn , shoot , friend )
336288
337289
338- @hook .command ("befriend" , autohelp = False )
339- def befriend (nick , chan , message , db , conn , notice ):
340- """- when there is a duck on the loose use this command to befriend it before someone else shoots it."""
290+ def attack (nick , chan , message , db , conn , notice , attack ):
341291 global game_status , scripters
342292 if chan in opt_out :
343293 return
294+
344295 network = conn .name
296+ status = game_status [network ][chan ]
297+
345298 out = ""
346- miss = ["The duck didn't want to be friends, maybe next time." ,
299+ if attack == "shoot" :
300+ miss = [
301+ "WHOOSH! You missed the duck completely!" , "Your gun jammed!" ,
302+ "Better luck next time." ,
303+ "WTF?! Who are you, Kim Jong Un firing missiles? You missed."
304+ ]
305+ no_duck = "There is no duck! What are you shooting at?"
306+ msg = "{} you shot a duck in {:.3f} seconds! You have killed {} in {}."
307+ scripter_msg = "You pulled the trigger in {:.3f} seconds, that's mighty fast. Are you sure you aren't a script? Take a 2 hour cool down."
308+ attack_type = "shoot"
309+ else :
310+ miss = [
311+ "The duck didn't want to be friends, maybe next time." ,
347312 "Well this is awkward, the duck needs to think about it." ,
348313 "The duck said no, maybe bribe it with some pizza? Ducks love pizza don't they?" ,
349- "Who knew ducks could be so picky?" ]
350- if not game_status [network ][chan ]['game_on' ]:
314+ "Who knew ducks could be so picky?"
315+ ]
316+ no_duck = "You tried befriending a non-existent duck. That's freaking creepy."
317+ msg = "{} you befriended a duck in {:.3f} seconds! You have made friends with {} in {}."
318+ scripter_msg = "You tried friending that duck in {:.3f} seconds, that's mighty fast. Are you sure you aren't a script? Take a 2 hour cool down."
319+ attack_type = "friend"
320+
321+ if not status ['game_on' ]:
351322 return "There is no hunt right now. Use .starthunt to start a game."
352- elif game_status [network ][chan ]['duck_status' ] != 1 :
353- if game_status [network ][chan ]['no_duck_kick' ] == 1 :
354- out = "KICK {} {} :You tried befriending a non-existent duck. That's fucking creepy." .format (chan , nick )
355- conn .send (out )
323+ elif status ['duck_status' ] != 1 :
324+ if status ['no_duck_kick' ] == 1 :
325+ conn .cmd ("KICK" , chan , nick , no_duck )
356326 return
357- return "You tried befriending a non-existent duck. That's freaking creepy."
327+
328+ return no_duck
358329 else :
359- game_status [ network ][ chan ] ['shoot_time' ] = time ()
360- deploy = game_status [ network ][ chan ] ['duck_time' ]
361- shoot = game_status [ network ][ chan ] ['shoot_time' ]
330+ status ['shoot_time' ] = time ()
331+ deploy = status ['duck_time' ]
332+ shoot = status ['shoot_time' ]
362333 if nick .lower () in scripters :
363334 if scripters [nick .lower ()] > shoot :
364- notice ("You are in a cool down period, you can try again in {} seconds." .format (
365- str (scripters [nick .lower ()] - shoot )))
335+ notice (
336+ "You are in a cool down period, you can try again in {:.3f} seconds." .format (
337+ scripters [nick .lower ()] - shoot
338+ )
339+ )
366340 return
341+
367342 chance = hit_or_miss (deploy , shoot )
368343 if not random .random () <= chance and chance > .05 :
369344 out = random .choice (miss ) + " You can try again in 7 seconds."
370345 scripters [nick .lower ()] = shoot + 7
371346 return out
347+
372348 if chance == .05 :
373- out += "You tried friending that duck in {} seconds, that's mighty fast. Are you sure you aren't a script? Take a 2 hour cool down." .format (
374- str (shoot - deploy ))
349+ out += scripter_msg .format (shoot - deploy )
375350 scripters [nick .lower ()] = shoot + 7200
376351 if not random .random () <= chance :
377352 return random .choice (miss ) + " " + out
378353 else :
379354 message (out )
380355
381- game_status [network ][chan ]['duck_status' ] = 2
382- score = db .execute (select ([table .c .befriend ]) \
383- .where (table .c .network == conn .name ) \
384- .where (table .c .chan == chan .lower ()) \
385- .where (table .c .name == nick .lower ())).fetchone ()
386- if score :
387- score = score [0 ]
388- score += 1
389- dbupdate (nick , chan , db , conn , 0 , score )
390- else :
356+ status ['duck_status' ] = 2
357+ try :
391358 score = 1
392- dbadd_entry (nick , chan , db , conn , 0 , score )
393- duck = "duck" if score == 1 else "ducks"
394- timer = "{:.3f}" .format (shoot - deploy )
395- message (
396- "{} you befriended a duck in {} seconds! You have made friends with {} {} in {}." .format (nick , timer , score ,
397- duck , chan ))
359+ args = {
360+ attack_type : score
361+ }
362+
363+ update_score (nick , chan , db , conn , ** args )
364+ except DatabaseError :
365+ status ['duck_status' ] = 1
366+ raise
367+
368+ message (msg .format (nick , shoot - deploy , pluralize (score , "duck" ), chan ))
398369 set_ducktime (chan , conn .name )
399370
400371
372+ @hook .command ("bang" , autohelp = False )
373+ def bang (nick , chan , message , db , conn , notice ):
374+ """- when there is a duck on the loose use this command to shoot it."""
375+ return attack (nick , chan , message , db , conn , notice , "shoot" )
376+
377+
378+ @hook .command ("befriend" , autohelp = False )
379+ def befriend (nick , chan , message , db , conn , notice ):
380+ """- when there is a duck on the loose use this command to befriend it before someone else shoots it."""
381+ return attack (nick , chan , message , db , conn , notice , "befriend" )
382+
383+
401384def smart_truncate (content , length = 320 , suffix = '...' ):
402385 if len (content ) <= length :
403386 return content
0 commit comments