async def explosive(self, ctx: MyContext): """ Buy Explosive ammo to TRIPLE the damage you do to super ducks for 24 hours """ ITEM_COST = 25 _ = await ctx.get_translate_function() if self.bot.current_event == Events.UN_TREATY: await ctx.reply(_("❌ A UN treaty bans the use of Armor Piercing and Explosive ammo for now, " "I can't sell that to you. (`{ctx.prefix}event`)",)) return False language_code = await ctx.get_language_code() db_hunter: Player = await get_player(ctx.author, ctx.channel) self.ensure_enough_experience(db_hunter, ITEM_COST) if db_hunter.is_powerup_active("explosive_ammo"): time_delta = get_timedelta(db_hunter.active_powerups['explosive_ammo'], time.time()) await ctx.reply(_("❌ Your gun is already using explosive ammo for {time_delta}!", time_delta=format_timedelta(time_delta, locale=language_code))) return False await db_hunter.edit_experience_with_levelups(ctx, -ITEM_COST) db_hunter.active_powerups["explosive_ammo"] = int(time.time()) + DAY db_hunter.bought_items['explosive_ammo'] += 1 await db_hunter.save() await ctx.reply(_("💸 You bought some **EXPLOSIVE** ammo. Thrice the damage, that'll be bloody! [Bought: -{ITEM_COST} exp]", ITEM_COST=ITEM_COST))
async def ap(self, ctx: MyContext): """ Buy AP ammo to double the damage you do to super ducks. [15 exp/24 hrs] """ ITEM_COST = 15 _ = await ctx.get_translate_function() language_code = await ctx.get_language_code() if self.bot.current_event == Events.UN_TREATY: await ctx.reply( _( "❌ A UN treaty bans the use of Armor Piercing and Explosive ammo for now, " "I can't sell that to you. (`{ctx.prefix}event`)", )) return False db_hunter: Player = await get_player(ctx.author, ctx.channel) self.ensure_enough_experience(db_hunter, ITEM_COST) if db_hunter.is_powerup_active("ap_ammo"): time_delta = get_timedelta(db_hunter.active_powerups['ap_ammo'], time.time()) await ctx.reply( _("❌ Whoops, your gun is already using AP ammo for {time_delta}!", time_delta=format_timedelta(time_delta, locale=language_code))) return False elif db_hunter.is_powerup_active("explosive_ammo"): time_delta = get_timedelta( db_hunter.active_powerups['explosive_ammo'], time.time()) await ctx.reply( _("❌ Your gun is using some even better explosive ammo for {time_delta}!", time_delta=format_timedelta(time_delta, locale=language_code))) return False await db_hunter.edit_experience_with_levelups(ctx, -ITEM_COST) db_hunter.active_powerups["ap_ammo"] = int(time.time()) + DAY db_hunter.bought_items['ap_ammo'] += 1 await db_hunter.save() await ctx.reply( _("💸 You bought some AP ammo. Twice the damage, twice the fun! [Bought: -{ITEM_COST} exp, total {db_hunter.experience} exp]", db_hunter=db_hunter, ITEM_COST=ITEM_COST))
async def silencer(self, ctx: MyContext): """ Add a silencer to your weapon to prevent scaring ducks. [5 exp/24* hrs] """ ITEM_COST = 5 _ = await ctx.get_translate_function() db_hunter: Player = await get_player(ctx.author, ctx.channel) self.ensure_enough_experience(db_hunter, ITEM_COST) if db_hunter.is_powerup_active('silencer'): language_code = await ctx.get_language_code() time_delta = get_timedelta(db_hunter.active_powerups['silencer'], time.time()) await ctx.reply( _("❌ You already use a silencer. It's still good for {time_delta}, come back then.", time_delta=format_timedelta(time_delta, locale=language_code))) return False await db_hunter.edit_experience_with_levelups(ctx, -ITEM_COST) db_hunter.active_powerups["silencer"] = int(time.time()) + DAY if db_hunter.prestige >= 6: db_hunter.active_powerups["silencer"] += DAY db_hunter.bought_items['silencer'] += 1 await db_hunter.save() if db_hunter.prestige >= 6: await ctx.reply( _("💸 You added a military-grade silencer to your weapon. You seem to know the game well. [Bought: -{ITEM_COST} exp, total {db_hunter.experience} exp]", db_hunter=db_hunter, ITEM_COST=ITEM_COST)) else: await ctx.reply( _("💸 You added a silencer to your weapon. Ducks are still afraid of the noise, but you don't make any. [Bought: -{ITEM_COST} exp, total {db_hunter.experience} exp]", db_hunter=db_hunter, ITEM_COST=ITEM_COST))
async def clover(self, ctx: MyContext): """ Buy a 4-Leaf clover to get more exp for every duck you kill :) """ ITEM_COST = 13 _ = await ctx.get_translate_function() language_code = await ctx.get_language_code() db_hunter: Player = await get_player(ctx.author, ctx.channel) db_channel: DiscordChannel = await get_from_db(ctx.channel) self.ensure_enough_experience(db_hunter, ITEM_COST) if db_hunter.is_powerup_active('clover'): time_delta = get_timedelta(db_hunter.active_powerups['clover'], time.time()) await ctx.reply(_("❌ You already use a 4-Leaf clover. Try your luck again in {time_delta}!", time_delta=format_timedelta(time_delta, locale=language_code))) return False max_experience = db_channel.clover_max_experience if self.bot.current_event == Events.FLORIST: max_experience *= 2 clover_exp = random.randint(db_channel.clover_min_experience, max_experience) await db_hunter.edit_experience_with_levelups(ctx, -ITEM_COST) db_hunter.active_powerups["clover"] = int(time.time()) + DAY db_hunter.active_powerups["clover_exp"] = clover_exp db_hunter.bought_items['clover'] += 1 await db_hunter.save() await ctx.reply( _("🍀 You bought a 4-Leaf clover. Every time you kill a duck, you'll get {clover_exp} experience points more. [Bought: -{ITEM_COST} exp]", ITEM_COST=ITEM_COST, clover_exp=clover_exp))
async def bang(self, ctx: MyContext, target: Optional[SmartMemberConverter], *args): """ Shoot at the duck that appeared first on the channel. """ _ = await ctx.get_translate_function() if not self.bot.is_ready(): await ctx.reply( _("The bot is still starting up, please wait a minute and retry. Ducks haven't been lost." )) return False db_hunter: Player = await get_player(ctx.author, ctx.channel, giveback=True) hunter_coat_color = db_hunter.get_current_coat_color() now = int(time.time()) language_code = await ctx.get_language_code() if db_hunter.is_powerup_active("dead"): db_hunter.shooting_stats['shots_when_dead'] += 1 await db_hunter.save() await ctx.reply( _( "☠️ It's a little cold in there... Maybe because **you are DEAD**! have you tried eating BRAINS ? `{ctx.prefix}revive`...", ctx=ctx, )) return False if db_hunter.is_powerup_active('wet'): db_hunter.shooting_stats['shots_when_wet'] += 1 await db_hunter.save() td = get_timedelta(db_hunter.active_powerups['wet'], now) await ctx.reply( _("🚰 Come on! Your clothes are wet, at least dry them (for **{time_delta}**) or something, or buy new ones (`{ctx.prefix}shop clothes`)", ctx=ctx, time_delta=format_timedelta(td, locale=language_code))) return False if db_hunter.is_powerup_active("confiscated"): db_hunter.shooting_stats['shots_when_confiscated'] += 1 await db_hunter.save() await ctx.reply( _("⛔️ Oh no! Your weapon has been confiscated. Wait for freetime (`{ctx.prefix}freetime`), or buy it back in the shop (`{ctx.prefix}shop weapon`)", ctx=ctx)) return False sabotage = db_hunter.weapon_sabotaged_by if sabotage: sabotager = await db_hunter.weapon_sabotaged_by.get() member = await sabotager.member user = await member.user if target and user.discord_id == target.id and target.id != ctx.author.id: sabotager.stored_achievements['prevention'] = True await sabotager.save() db_hunter.weapon_sabotaged_by = None db_hunter.active_powerups['jammed'] = 1 db_hunter.shooting_stats['shots_when_sabotaged'] += 1 await db_hunter.save() await ctx.reply( _( "💥 Your weapon was sabotaged and exploded in your face. You can thank " "{sabotager.name}#{sabotager.discriminator} for this bad joke.", sabotager=user)) return False if db_hunter.is_powerup_active('jammed'): db_hunter.shooting_stats['shots_when_jammed'] += 1 await db_hunter.save() await ctx.reply( _("☁️ Your weapon is jammed. Reload it to clean it up ! (`{ctx.prefix}reload`)" ), view=ReloadView(self.bot), ) return False if db_hunter.bullets <= 0: level_info = db_hunter.level_info() if db_hunter.is_powerup_active('reloader'): if db_hunter.magazines > 0: db_hunter.magazines -= 1 db_hunter.bullets = level_info['bullets'] db_hunter.shooting_stats['autoreloads'] += 1 else: db_hunter.shooting_stats['failed_autoreloads'] += 1 await db_hunter.save() await ctx.reply( _( "🦉 Backpack empty ! Buy magazines | **Bullets**: 0/{max_bullets} | Magazines: 0/{max_magazines} [**Autoreload failed**]", max_bullets=level_info['bullets'], max_magazines=level_info['magazines'], )) return False else: db_hunter.shooting_stats['shots_with_empty_magazine'] += 1 await db_hunter.save() await ctx.reply(_( "🦉 Magazine empty ! Reload or buy bullets | **Bullets**: 0/{max_bullets} | Magazines: {current_magazines}/{max_magazines}", max_bullets=level_info['bullets'], max_magazines=level_info['magazines'], current_magazines=db_hunter.magazines), view=ReloadView(self.bot)) return False # Jamming level_info = db_hunter.level_info() lucky = compute_luck(level_info['reliability']) if db_hunter.is_powerup_active('grease'): lucky = lucky or compute_luck(level_info['reliability']) elif db_hunter.is_powerup_active('sand'): db_hunter.active_powerups['sand'] -= 1 lucky = lucky and compute_luck(level_info['reliability']) if not lucky: db_hunter.shooting_stats['shots_jamming_weapon'] += 1 db_hunter.active_powerups['jammed'] = 1 await db_hunter.save() await ctx.reply(_( "💥 Your weapon jammed. Reload it and consider buying grease next time." ), view=ReloadView(self.bot)) return False db_hunter.bullets -= 1 db_hunter.shooting_stats['bullets_used'] += 1 db_channel = await get_from_db(ctx.channel) homing = db_hunter.is_powerup_active('homing_bullets') if homing: db_hunter.active_powerups["homing_bullets"] -= 1 db_hunter.shooting_stats['homing_kills'] += 1 db_hunter.shooting_stats['missed'] += 1 db_hunter.shooting_stats['killed'] += 1 db_hunter.shooting_stats['murders'] += 1 db_hunter.active_powerups["dead"] += 1 await db_hunter.edit_experience_with_levelups(ctx, -2) # Missed has_kill_licence = db_hunter.is_powerup_active('kill_licence') if not has_kill_licence: await db_hunter.edit_experience_with_levelups(ctx, -15) # Kill db_hunter.active_powerups["confiscated"] = 1 await db_hunter.save() await ctx.reply( _( "✨ You take the new homing bullets outside of their packaging, place them in your weapon and shoot with your eyes closed...", )) await asyncio.sleep(2) if has_kill_licence: if db_channel.anti_trigger_wording: await ctx.reply( _( "... And the bullet flew straight into your face, killing you instantly. " "You should send your complaints to the CACAD. Your licence to kill saved your experience. [**MISSED**: -2 exp]", )) else: await ctx.reply( _( "... And the bullet flew straight into your face, killing you instantly. " "You should send your complaints to the CACAD. At least, you had a ~~kill~~ suicide licence. [**MISSED**: -2 exp]", )) else: await ctx.reply( _( "... And the bullet flew straight into your face, killing you instantly. " "You should send your complaints to the CACAD. [**WEAPON CONFISCATED**][**MISSED**: -2 exp][**MURDER**: -15 exp]", )) await ctx.send( f"http://www.tombstonebuilder.com/generate.php?top1={quote_plus(ctx.author.name)}&top2={quote_plus(_('Signed up for the CACAD.'))}&top3=&top4=&sp=" ) return False # Maybe a duck there await db_hunter.save() duck = await ctx.target_next_duck() # Missing if duck: accuracy = await duck.get_accuracy(level_info['accuracy']) if self.bot.current_event == Events.WINDY: # Gotta miss more accuracy = max(60, accuracy * 3 / 4) if db_hunter.is_powerup_active('mirror'): if hunter_coat_color == Coats.YELLOW: accuracy = int(accuracy / 1.4) db_hunter.active_powerups['mirror'] -= 1 else: accuracy = int(accuracy / 2) db_hunter.active_powerups['mirror'] -= 1 if db_hunter.is_powerup_active('sight'): accuracy += int((100 - accuracy) / 3) db_hunter.active_powerups['sight'] -= 1 else: if db_hunter.is_powerup_active('detector'): accuracy = 100 else: accuracy = 90 # 90% chance of knowing there is no duck. missed = not compute_luck(accuracy) if target and hunter_coat_color == Coats.RED: missed = False if (missed and not target) or (target and not missed): if duck: await duck.release() murder = bool(target) if missed: db_hunter.shooting_stats['missed'] += 1 await db_hunter.edit_experience_with_levelups(ctx, -2) # Killing killed_someone = target or compute_luck( db_channel.kill_on_miss_chance) if self.bot.current_event == Events.SAFETY: # Double the kills killed_someone = killed_someone or compute_luck( db_channel.kill_on_miss_chance) if killed_someone: if murder: db_target: Player = await get_player(target, ctx.channel) db_hunter.shooting_stats['murders'] += 1 else: db_target: Player = await get_random_player(db_channel) if db_target.member.user.discord_id == 138751484517941259: db_user = await get_from_db(ctx.author, as_user=True) db_user.trophys["no_more_updates"] = True await db_user.save(update_fields=["trophys"]) target_coat_color = db_target.get_current_coat_color() if db_channel.mentions_when_killed: player_name = f"<@{db_target.member.user.discord_id}>" else: player_name = db_target.member.user.name if not murder and target_coat_color == Coats.ORANGE and random.randint( 1, 100) <= 75: db_hunter.shooting_stats['near_misses'] += 1 db_target.shooting_stats['near_missed'] += 1 await ctx.reply( _( "🔫 You missed the duck... And *almost* shot {player_name} in the head, missing them by a few hairs. " "Their orange coat saved them. [**MISSED**: -2 exp]", player_name=player_name, )) await asyncio.gather(db_target.save(), db_hunter.save()) return elif hunter_coat_color == Coats.PINK and target_coat_color == Coats.PINK: if murder: db_hunter.shooting_stats[ 'murders'] -= 1 # Cancel the murder db_hunter.shooting_stats['love_avoids_murder'] += 1 db_target.shooting_stats['love_avoided_murder'] += 1 await ctx.reply( _( "🔫 You took your weapon out, aimed it towards {player_name} head, but they had a pink coat just like yours. " "Using the power of love, you missed them on purpose, and hit the love tree 🌳. [**MISSED**: -2 exp]", player_name=player_name, )) else: db_hunter.shooting_stats['love_avoids_accidents'] += 1 db_target.shooting_stats['love_avoided_accidents'] += 1 await ctx.reply( _( "🔫 You missed the duck... And you saw your bullet go towards {player_name} head, " "but they had a pink coat just like yours. Just like in the movies, " "by using the power of love, you made the bullet hit the love tree 🌳 instead. [**MISSED**: -2 exp]", player_name=player_name, )) await asyncio.gather(db_target.save(), db_hunter.save()) return has_valid_kill_licence = db_hunter.is_powerup_active( 'kill_licence') and not murder db_hunter.shooting_stats['killed'] += 1 if hunter_coat_color == Coats.RED and murder: await db_hunter.edit_experience_with_levelups(ctx, -15) elif not has_valid_kill_licence: await db_hunter.edit_experience_with_levelups(ctx, -15) db_hunter.active_powerups["confiscated"] = 1 if db_target.id == db_hunter.id: db_target = db_hunter db_hunter.shooting_stats['suicides'] += 1 db_target.shooting_stats['got_killed'] += 1 db_target.active_powerups["dead"] += 1 if db_target.id != db_hunter.id: await asyncio.gather(db_target.save(), db_hunter.save() ) # Save both at the same time else: await db_hunter.save() if murder: if hunter_coat_color != Coats.RED: if db_target.id == db_hunter.id: if db_channel.anti_trigger_wording: await ctx.reply( _( "🔫 You are now dead. [**WEAPON CONFISCATED**][**MURDER**: -15 exp]", )) else: await ctx.reply( _( "🔫 You commited suicide. [**WEAPON CONFISCATED**][**MURDER**: -15 exp]", )) else: await ctx.reply( _( "🔫 You took your weapon out, aiming it directly towards {player_name} head, and pulled the trigger. " "[**WEAPON CONFISCATED**][**MURDER**: -15 exp]", player_name=player_name, )) else: if db_target.id == db_hunter.id: if db_channel.anti_trigger_wording: await ctx.reply( _( "🔫 You are now dead. [**RED COAT**: Kept weapon][**MURDER**: -15 exp]", )) else: await ctx.reply( _( "🔫 You commited suicide. [**RED COAT**: Kept weapon][**MURDER**: -15 exp]", )) else: await ctx.reply( _( "🔫 You took your weapon out, aiming it directly towards {player_name} head, and pulled the trigger. " "[**RED COAT**: Kept weapon][**MURDER**: -15 exp]", player_name=player_name, )) else: if has_valid_kill_licence: if db_target.id == db_hunter.id: await ctx.reply( _( "🔫 You missed the duck... And shot yourself in the head. You died. " "You are legally allowed to kill ~~people~~yourself. [**MISSED**: -2 exp]", )) else: await ctx.reply( _( "🔫 You missed the duck... And shot {player_name} in the head, killing them on the spot. " "You are legally allowed to kill people. [**MISSED**: -2 exp]", player_name=player_name, )) else: if db_target.id == db_hunter.id: await ctx.reply( _( "🔫 You missed the duck... And shot yourself in the head, dying instantly. " "[**WEAPON CONFISCATED**][**MISSED**: -2 exp][**MURDER**: -15 exp]", )) else: await ctx.reply( _( "🔫 You missed the duck... And shot {player_name} in the head, killing them on the spot. " "[**WEAPON CONFISCATED**][**MISSED**: -2 exp][**MURDER**: -15 exp]", player_name=player_name, )) await ctx.send( f"http://www.tombstonebuilder.com/generate.php?top1={quote_plus(db_target.member.user.name)}&top2={quote_plus(_('Forgot to duck'))}&top3=&top4=&sp=" ) else: await db_hunter.save() await ctx.reply( _( "🌲 What did you try to aim at ? I guess you shot that tree, over here. [**MISSED**: -2 exp]", )) return False if duck: db_hunter.shooting_stats['shots_with_duck'] += 1 duck.db_target_lock_by = db_hunter # Since we have unsaved data await duck.shoot(args) elif db_hunter.is_powerup_active('detector'): db_hunter.active_powerups['detector'] -= 1 db_hunter.shooting_stats['shots_stopped_by_detector'] += 1 db_hunter.shooting_stats['bullets_used'] -= 1 db_hunter.bullets += 1 await db_hunter.save() await ctx.reply( _("🕵️ Woah there ! Calm down, there are no ducks. Your infrared detector stopped the shot." )) else: db_hunter.shooting_stats['shots_without_ducks'] += 1 await db_hunter.edit_experience_with_levelups(ctx, -2) await db_hunter.save() await ctx.reply( _("❓️ What are you trying to kill exactly ? There are no ducks here. [**MISSED**: -2 exp]" ))
async def clover(self, ctx: MyContext): """ Buy a 4-Leaf clover to get more exp for every duck you kill :). [13 exp/24 hrs] You can always buy a new clover during the florist event, but the price will be doubled if you had a clover already. """ ITEM_COST = 13 _ = await ctx.get_translate_function() language_code = await ctx.get_language_code() db_hunter: Player = await get_player(ctx.author, ctx.channel) db_channel: DiscordChannel = await get_from_db(ctx.channel) if db_hunter.is_powerup_active('clover'): if self.bot.current_event == Events.FLORIST: try: self.ensure_enough_experience(db_hunter, ITEM_COST * 2) except NotEnoughExperience: db_hunter.shooting_stats['cops_seen'] += 1 await db_hunter.save() await ctx.reply( _( "❌ You tried to throw your old clover to buy a new one at the new florist. " "Unfortunately, there is a cop around and you don't have enough exp to pay a " "littering fine of {fine} exp.", fine=ITEM_COST)) return False db_hunter.shooting_stats['thrown_clovers'] += 1 await ctx.reply( _( "🍀 You throw your old clover to buy a new one at the new florist. " "Unfortunately, a cop catches you and fines you {fine} exp for littering.", fine=ITEM_COST)) ITEM_COST *= 2 else: time_delta = get_timedelta(db_hunter.active_powerups['clover'], time.time()) await ctx.reply( _("❌ You already use a 4-Leaf clover. Try your luck again in {time_delta}!", time_delta=format_timedelta(time_delta, locale=language_code))) return False self.ensure_enough_experience(db_hunter, ITEM_COST) max_experience = db_channel.clover_max_experience if self.bot.current_event == Events.FLORIST: max_experience *= 2 clover_exp = random.randint(db_channel.clover_min_experience, max_experience) await db_hunter.edit_experience_with_levelups(ctx, -ITEM_COST) db_hunter.active_powerups["clover"] = int(time.time()) + DAY db_hunter.active_powerups["clover_exp"] = clover_exp db_hunter.bought_items['clover'] += 1 await db_hunter.save() await ctx.reply( _( "🍀 You bought a 4-Leaf clover. Every time you kill a duck, you'll get {clover_exp} more experience points." " [Bought: -{ITEM_COST} exp, total {db_hunter.experience} exp]", db_hunter=db_hunter, ITEM_COST=ITEM_COST, clover_exp=clover_exp))