test
This commit is contained in:
@@ -1217,6 +1217,13 @@ class SimpleIRCBot:
|
|||||||
await self.handle_use(nick, channel, item_id, user, target_nick)
|
await self.handle_use(nick, channel, item_id, user, target_nick)
|
||||||
else:
|
else:
|
||||||
self.send_message(channel, f"{nick} > Usage: !use <item_id> [target_nick]")
|
self.send_message(channel, f"{nick} > Usage: !use <item_id> [target_nick]")
|
||||||
|
elif full_cmd.startswith('!give '):
|
||||||
|
parts = full_cmd[6:].split()
|
||||||
|
if len(parts) >= 2:
|
||||||
|
target_nick, item_id = parts[0], parts[1]
|
||||||
|
await self.handle_give(nick, channel, user, target_nick, item_id)
|
||||||
|
else:
|
||||||
|
self.send_message(channel, f"{nick} > Usage: !give <nick> <item_id>")
|
||||||
elif full_cmd.startswith('!sell '):
|
elif full_cmd.startswith('!sell '):
|
||||||
item_id = full_cmd[6:].strip()
|
item_id = full_cmd[6:].strip()
|
||||||
await self.handle_sell(nick, channel, item_id, user)
|
await self.handle_sell(nick, channel, item_id, user)
|
||||||
@@ -1607,9 +1614,8 @@ class SimpleIRCBot:
|
|||||||
async def handle_help(self, nick, channel):
|
async def handle_help(self, nick, channel):
|
||||||
help_lines = [
|
help_lines = [
|
||||||
f"{nick} > {self.colors['cyan']}🦆 DUCKHUNT COMMANDS 🦆{self.colors['reset']}",
|
f"{nick} > {self.colors['cyan']}🦆 DUCKHUNT COMMANDS 🦆{self.colors['reset']}",
|
||||||
f"{nick} > {self.colors['green']}Game:{self.colors['reset']} !bang !bef !reload !duckstats !topduck !shop !buy <id> !inventory !nextduck",
|
f"{nick} > {self.colors['green']}Game:{self.colors['reset']} !bang !bef !reload !duckstats !topduck !shop !buy <id> !use <id> !give <nick> <id> !nextduck",
|
||||||
f"{nick} > {self.colors['blue']}Settings:{self.colors['reset']} !output <PUBLIC|NOTICE|PRIVMSG>",
|
f"{nick} > {self.colors['blue']}Settings:{self.colors['reset']} !output <PUBLIC|NOTICE|PRIVMSG>"
|
||||||
f"{nick} > {self.colors['yellow']}Info:{self.colors['reset']} Golden ducks: 50 XP | Gun jamming & ricochets ON | Timeout: {self.duck_timeout_min}-{self.duck_timeout_max}s"
|
|
||||||
]
|
]
|
||||||
if self.is_admin(f"{nick}!*@*"): # Check if admin
|
if self.is_admin(f"{nick}!*@*"): # Check if admin
|
||||||
help_lines.append(f"{nick} > {self.colors['red']}Admin:{self.colors['reset']} !duck !golden !ban !reset !resetdb !rearm !giveitem !givexp !ignore !unignore | /msg {self.config['nick']} restart|quit")
|
help_lines.append(f"{nick} > {self.colors['red']}Admin:{self.colors['reset']} !duck !golden !ban !reset !resetdb !rearm !giveitem !givexp !ignore !unignore | /msg {self.config['nick']} restart|quit")
|
||||||
@@ -1852,11 +1858,17 @@ class SimpleIRCBot:
|
|||||||
|
|
||||||
# Check for bread channel limit
|
# Check for bread channel limit
|
||||||
if item == '21': # Bread
|
if item == '21': # Bread
|
||||||
# Count existing bread in channel
|
# Initialize and clean up old bread
|
||||||
channel_bread_count = 0
|
if channel not in self.channel_bread:
|
||||||
if hasattr(self, 'channel_bread') and channel in self.channel_bread:
|
self.channel_bread[channel] = []
|
||||||
channel_bread_count = len(self.channel_bread[channel])
|
|
||||||
|
|
||||||
|
# Clean up expired bread (30 minutes)
|
||||||
|
import time
|
||||||
|
current_time = time.time()
|
||||||
|
self.channel_bread[channel] = [b for b in self.channel_bread[channel] if current_time - b['time'] < 1800]
|
||||||
|
|
||||||
|
# Check limit after cleanup
|
||||||
|
channel_bread_count = len(self.channel_bread[channel])
|
||||||
if channel_bread_count >= 3:
|
if channel_bread_count >= 3:
|
||||||
self.send_message(channel, f"{nick} > Maximum 3 bread items allowed in channel! Current: {channel_bread_count}")
|
self.send_message(channel, f"{nick} > Maximum 3 bread items allowed in channel! Current: {channel_bread_count}")
|
||||||
return
|
return
|
||||||
@@ -2047,6 +2059,30 @@ class SimpleIRCBot:
|
|||||||
self.send_message(channel, f"{nick} > *POCKET SAND!* You threw sand in {target_nick}'s eyes! Their accuracy reduced by 20%!")
|
self.send_message(channel, f"{nick} > *POCKET SAND!* You threw sand in {target_nick}'s eyes! Their accuracy reduced by 20%!")
|
||||||
else:
|
else:
|
||||||
self.send_message(channel, f"{nick} > You threw sand in your own eyes... brilliant strategy!")
|
self.send_message(channel, f"{nick} > You threw sand in your own eyes... brilliant strategy!")
|
||||||
|
elif effect == 'bread':
|
||||||
|
# Bread - deploy in channel to attract ducks faster
|
||||||
|
if using_on_other:
|
||||||
|
self.send_message(channel, f"{nick} > You can't use bread on other players! Deploy it in the channel.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Initialize channel bread if needed
|
||||||
|
if channel not in self.channel_bread:
|
||||||
|
self.channel_bread[channel] = []
|
||||||
|
|
||||||
|
# Check limit (should have been checked in buy, but double-check)
|
||||||
|
if len(self.channel_bread[channel]) >= 3:
|
||||||
|
self.send_message(channel, f"{nick} > Maximum 3 bread items already deployed in this channel!")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Deploy bread
|
||||||
|
import time
|
||||||
|
bread_info = {
|
||||||
|
'time': time.time(),
|
||||||
|
'owner': nick
|
||||||
|
}
|
||||||
|
self.channel_bread[channel].append(bread_info)
|
||||||
|
|
||||||
|
self.send_message(channel, f"{nick} > *CRUMBLE CRUMBLE* You scattered bread crumbs around the channel! Ducks will be attracted faster. ({len(self.channel_bread[channel])}/3 bread deployed)")
|
||||||
# Add more effects as needed...
|
# Add more effects as needed...
|
||||||
else:
|
else:
|
||||||
# Default effects for other items
|
# Default effects for other items
|
||||||
@@ -2059,6 +2095,84 @@ class SimpleIRCBot:
|
|||||||
target_user = f"{target_nick.lower()}!user@host" # Simplified - would need real user data
|
target_user = f"{target_nick.lower()}!user@host" # Simplified - would need real user data
|
||||||
self.save_database()
|
self.save_database()
|
||||||
|
|
||||||
|
async def handle_give(self, nick, channel, user, target_nick, item_id):
|
||||||
|
"""Give an item from inventory to another player"""
|
||||||
|
# Get giver's player data
|
||||||
|
player = self.get_player(user)
|
||||||
|
if not player:
|
||||||
|
self.send_message(channel, f"{nick} > Player data not found!")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check if giver has the item
|
||||||
|
if item_id not in player['inventory'] or player['inventory'][item_id] <= 0:
|
||||||
|
self.send_message(channel, f"{nick} > You don't have that item! Check !duckstats to see your inventory.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Find target player
|
||||||
|
target_nick_lower = target_nick.lower()
|
||||||
|
if target_nick_lower not in self.players:
|
||||||
|
self.send_message(channel, f"{nick} > Player {target_nick} not found!")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Can't give to yourself
|
||||||
|
if target_nick_lower == nick.lower():
|
||||||
|
self.send_message(channel, f"{nick} > You can't give items to yourself!")
|
||||||
|
return
|
||||||
|
|
||||||
|
target_player = self.players[target_nick_lower]
|
||||||
|
|
||||||
|
# Get shop item data for reference
|
||||||
|
shop_items = {
|
||||||
|
'1': {'name': 'Extra bullet', 'effect': 'ammo'},
|
||||||
|
'2': {'name': 'Extra clip', 'effect': 'max_ammo'},
|
||||||
|
'3': {'name': 'AP ammo', 'effect': 'accuracy'},
|
||||||
|
'4': {'name': 'Explosive ammo', 'effect': 'explosive'},
|
||||||
|
'5': {'name': 'Repurchase confiscated gun', 'effect': 'gun'},
|
||||||
|
'6': {'name': 'Grease', 'effect': 'reliability'},
|
||||||
|
'7': {'name': 'Sight', 'effect': 'accuracy'},
|
||||||
|
'8': {'name': 'Infrared detector', 'effect': 'detector'},
|
||||||
|
'9': {'name': 'Silencer', 'effect': 'silencer'},
|
||||||
|
'10': {'name': 'Four-leaf clover', 'effect': 'luck'},
|
||||||
|
'11': {'name': 'Shotgun', 'effect': 'shotgun'},
|
||||||
|
'12': {'name': 'Assault rifle', 'effect': 'rifle'},
|
||||||
|
'13': {'name': 'Sniper rifle', 'effect': 'sniper'},
|
||||||
|
'14': {'name': 'Automatic shotgun', 'effect': 'auto_shotgun'},
|
||||||
|
'15': {'name': 'Handful of sand', 'effect': 'sand'},
|
||||||
|
'16': {'name': 'Water bucket', 'effect': 'water'},
|
||||||
|
'17': {'name': 'Sabotage', 'effect': 'sabotage'},
|
||||||
|
'18': {'name': 'Life insurance', 'effect': 'life_insurance'},
|
||||||
|
'19': {'name': 'Liability insurance', 'effect': 'liability'},
|
||||||
|
'20': {'name': 'Decoy', 'effect': 'decoy'},
|
||||||
|
'21': {'name': 'Piece of bread', 'effect': 'bread'},
|
||||||
|
'22': {'name': 'Ducks detector', 'effect': 'duck_detector'},
|
||||||
|
'23': {'name': 'Mechanical duck', 'effect': 'mechanical'}
|
||||||
|
}
|
||||||
|
|
||||||
|
if item_id not in shop_items:
|
||||||
|
self.send_message(channel, f"{nick} > Invalid item ID! Use shop numbers 1-23.")
|
||||||
|
return
|
||||||
|
|
||||||
|
shop_item = shop_items[item_id]
|
||||||
|
|
||||||
|
# Remove item from giver
|
||||||
|
player['inventory'][item_id] -= 1
|
||||||
|
if player['inventory'][item_id] <= 0:
|
||||||
|
del player['inventory'][item_id]
|
||||||
|
|
||||||
|
# Add item to target player
|
||||||
|
if 'inventory' not in target_player:
|
||||||
|
target_player['inventory'] = {}
|
||||||
|
if item_id not in target_player['inventory']:
|
||||||
|
target_player['inventory'][item_id] = 0
|
||||||
|
target_player['inventory'][item_id] += 1
|
||||||
|
|
||||||
|
# Announce the gift
|
||||||
|
self.send_message(channel, f"{nick} > Gave {shop_item['name']} to {target_nick}!")
|
||||||
|
|
||||||
|
# Save both players
|
||||||
|
self.save_player(user)
|
||||||
|
self.save_database()
|
||||||
|
|
||||||
async def handle_trade(self, nick, channel, user, target_nick, item, amount):
|
async def handle_trade(self, nick, channel, user, target_nick, item, amount):
|
||||||
"""Trade items with other players"""
|
"""Trade items with other players"""
|
||||||
player = self.get_player(user)
|
player = self.get_player(user)
|
||||||
@@ -2396,6 +2510,11 @@ class SimpleIRCBot:
|
|||||||
# Add duck to channel
|
# Add duck to channel
|
||||||
self.ducks[channel].append(duck)
|
self.ducks[channel].append(duck)
|
||||||
|
|
||||||
|
# Consume bread when duck spawns (bread gets eaten!)
|
||||||
|
if channel in self.channel_bread and self.channel_bread[channel]:
|
||||||
|
consumed_bread = self.channel_bread[channel].pop(0) # Remove oldest bread
|
||||||
|
self.logger.info(f"Duck consumed bread from {consumed_bread['owner']} in {channel}")
|
||||||
|
|
||||||
# Send spawn message
|
# Send spawn message
|
||||||
self.send_message(channel, duck_info['msg'])
|
self.send_message(channel, duck_info['msg'])
|
||||||
self.logger.info(f"Admin spawned {duck_info['type']} duck {duck_id} in {channel}")
|
self.logger.info(f"Admin spawned {duck_info['type']} duck {duck_id} in {channel}")
|
||||||
@@ -2413,6 +2532,22 @@ class SimpleIRCBot:
|
|||||||
|
|
||||||
while not self.shutdown_requested:
|
while not self.shutdown_requested:
|
||||||
wait_time = random.randint(self.duck_spawn_min, self.duck_spawn_max)
|
wait_time = random.randint(self.duck_spawn_min, self.duck_spawn_max)
|
||||||
|
|
||||||
|
# Apply bread effects - reduce spawn time
|
||||||
|
for channel in self.channels_joined:
|
||||||
|
if channel in self.channel_bread and self.channel_bread[channel]:
|
||||||
|
# Clean up old bread (expires after 30 minutes)
|
||||||
|
current_time = time.time()
|
||||||
|
self.channel_bread[channel] = [b for b in self.channel_bread[channel] if current_time - b['time'] < 1800]
|
||||||
|
|
||||||
|
if self.channel_bread[channel]: # If any bread remains after cleanup
|
||||||
|
# Each bread reduces spawn time by 20%, max 60% reduction
|
||||||
|
bread_count = len(self.channel_bread[channel])
|
||||||
|
reduction = min(0.6, bread_count * 0.2) # Max 60% reduction
|
||||||
|
wait_time = int(wait_time * (1 - reduction))
|
||||||
|
self.logger.info(f"Bread effect: {bread_count} bread in {channel}, {reduction*100:.0f}% spawn time reduction")
|
||||||
|
break # Apply effect based on first channel with bread
|
||||||
|
|
||||||
self.logger.info(f"Waiting {wait_time//60}m {wait_time%60}s for next duck")
|
self.logger.info(f"Waiting {wait_time//60}m {wait_time%60}s for next duck")
|
||||||
|
|
||||||
# Set next spawn time for all channels
|
# Set next spawn time for all channels
|
||||||
@@ -2427,7 +2562,7 @@ class SimpleIRCBot:
|
|||||||
return
|
return
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
# Spawn only one duck per channel if no alive ducks exist
|
# Check each channel for possible duck spawning
|
||||||
for channel in self.channels_joined:
|
for channel in self.channels_joined:
|
||||||
if self.shutdown_requested:
|
if self.shutdown_requested:
|
||||||
return
|
return
|
||||||
@@ -2436,10 +2571,28 @@ class SimpleIRCBot:
|
|||||||
channel_ducks = self.ducks.get(channel, [])
|
channel_ducks = self.ducks.get(channel, [])
|
||||||
alive_ducks = [duck for duck in channel_ducks if duck.get('alive')]
|
alive_ducks = [duck for duck in channel_ducks if duck.get('alive')]
|
||||||
|
|
||||||
# Only spawn if no ducks are alive (one duck at a time naturally)
|
# Only consider spawning if no ducks are alive
|
||||||
if not alive_ducks:
|
if not alive_ducks:
|
||||||
await self.spawn_duck_now(channel)
|
# Calculate spawn chance based on bread
|
||||||
break # Only spawn in the first available channel
|
base_chance = 0.3 # 30% base chance per spawn cycle
|
||||||
|
bread_count = 0
|
||||||
|
|
||||||
|
# Count and clean up bread
|
||||||
|
if channel in self.channel_bread and self.channel_bread[channel]:
|
||||||
|
current_time = time.time()
|
||||||
|
self.channel_bread[channel] = [b for b in self.channel_bread[channel] if current_time - b['time'] < 1800]
|
||||||
|
bread_count = len(self.channel_bread[channel])
|
||||||
|
|
||||||
|
# Each bread adds 25% spawn chance
|
||||||
|
spawn_chance = base_chance + (bread_count * 0.25)
|
||||||
|
spawn_chance = min(0.95, spawn_chance) # Cap at 95%
|
||||||
|
|
||||||
|
# Roll for spawn
|
||||||
|
if random.random() < spawn_chance:
|
||||||
|
await self.spawn_duck_now(channel)
|
||||||
|
bread_msg = f" (bread boosted: {bread_count} bread = {spawn_chance*100:.0f}% chance)" if bread_count > 0 else ""
|
||||||
|
self.logger.info(f"Duck spawned in {channel}{bread_msg}")
|
||||||
|
break # Only spawn in one channel per cycle
|
||||||
|
|
||||||
async def duck_timeout_checker(self):
|
async def duck_timeout_checker(self):
|
||||||
"""Remove ducks that have been around too long"""
|
"""Remove ducks that have been around too long"""
|
||||||
|
|||||||
Reference in New Issue
Block a user