Implement comprehensive team builder configuration system
### Major Features Added:
**Team Configuration Management:**
- Add support for 3 different team configurations per player
- Implement save/load/rename functionality for team setups
- Add prominent team configuration UI with dropdown selector
- Create quick action buttons for instant configuration loading
- Add status tracking for current editing state
**Database Enhancements:**
- Add team_configurations table with player_id, slot_number, config_name
- Implement rename_team_configuration() method for configuration management
- Add proper indexing and foreign key constraints
**Web Interface Improvements:**
- Fix team builder template visibility issue (was using wrong template)
- Add comprehensive CSS styling for configuration elements
- Implement responsive design with proper hover effects and transitions
- Add visual feedback with status indicators and progress tracking
**API Endpoints:**
- Add /teambuilder/{nickname}/config/rename/{slot} for renaming configs
- Implement proper validation and error handling for all endpoints
- Add JSON response formatting with success/error states
**JavaScript Functionality:**
- Add switchActiveConfig() for configuration switching
- Implement quickSaveConfig() for instant team saving
- Add renameConfig() with user-friendly prompts
- Create loadConfigToEdit() for seamless configuration editing
**Admin & System Improvements:**
- Enhance weather command system with simplified single-word names
- Fix \!reload command to properly handle all 12 modules
- Improve IRC connection health monitoring with better PONG detection
- Add comprehensive TODO list tracking and progress management
**UI/UX Enhancements:**
- Position team configuration section prominently for maximum visibility
- Add clear instructions: "Save up to 3 different team setups for quick switching"
- Implement intuitive workflow: save → load → edit → rename → resave
- Add visual hierarchy with proper spacing and typography
### Technical Details:
**Problem Solved:**
- Team configuration functionality existed but was hidden in unused template
- Users reported "no indication i can save multiple team configs"
- Configuration management was not visible or accessible
**Solution:**
- Identified dual template system in webserver.py (line 4160 vs 5080)
- Added complete configuration section to actively used template
- Enhanced both CSS styling and JavaScript functionality
- Implemented full backend API support with database persistence
**Files Modified:**
- webserver.py: +600 lines (template fixes, API endpoints, CSS, JavaScript)
- src/database.py: +20 lines (rename_team_configuration method)
- modules/admin.py: +150 lines (weather improvements, enhanced commands)
- TODO.md: Updated progress tracking and completed items
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
6cd25ab9b1
commit
add7731d80
7 changed files with 1434 additions and 51 deletions
153
modules/admin.py
153
modules/admin.py
|
|
@ -21,7 +21,7 @@ class Admin(BaseModule):
|
|||
"""Handles admin-only commands like reload"""
|
||||
|
||||
def get_commands(self):
|
||||
return ["reload", "rate_stats", "rate_user", "rate_unban", "rate_reset"]
|
||||
return ["reload", "rate_stats", "rate_user", "rate_unban", "rate_reset", "weather", "setweather"]
|
||||
|
||||
async def handle_command(self, channel, nickname, command, args):
|
||||
if command == "reload":
|
||||
|
|
@ -34,6 +34,10 @@ class Admin(BaseModule):
|
|||
await self.cmd_rate_unban(channel, nickname, args)
|
||||
elif command == "rate_reset":
|
||||
await self.cmd_rate_reset(channel, nickname, args)
|
||||
elif command == "weather":
|
||||
await self.cmd_weather(channel, nickname, args)
|
||||
elif command == "setweather":
|
||||
await self.cmd_setweather(channel, nickname, args)
|
||||
|
||||
async def cmd_reload(self, channel, nickname):
|
||||
"""Reload bot modules (admin only)"""
|
||||
|
|
@ -168,4 +172,149 @@ class Admin(BaseModule):
|
|||
self.send_message(channel, f"{nickname}: ℹ️ No violations found for user {target_user}.")
|
||||
|
||||
except Exception as e:
|
||||
self.send_message(channel, f"{nickname}: ❌ Error resetting violations: {str(e)}")
|
||||
self.send_message(channel, f"{nickname}: ❌ Error resetting violations: {str(e)}")
|
||||
|
||||
async def cmd_weather(self, channel, nickname, args):
|
||||
"""Check current weather in locations (admin only)"""
|
||||
if not self.is_admin(nickname):
|
||||
self.send_message(channel, f"{nickname}: Access denied. Admin command.")
|
||||
return
|
||||
|
||||
try:
|
||||
if args and args[0].lower() != "all":
|
||||
# Check weather for specific location
|
||||
location_name = " ".join(args)
|
||||
weather = await self.database.get_location_weather_by_name(location_name)
|
||||
|
||||
if weather:
|
||||
self.send_message(channel,
|
||||
f"🌤️ {nickname}: {location_name} - {weather['weather_type']} "
|
||||
f"(modifier: {weather['spawn_modifier']}x, "
|
||||
f"until: {weather['active_until'][:16]})")
|
||||
else:
|
||||
self.send_message(channel, f"❌ {nickname}: Location '{location_name}' not found or no weather data.")
|
||||
else:
|
||||
# Show weather for all locations
|
||||
all_weather = await self.database.get_all_location_weather()
|
||||
if all_weather:
|
||||
weather_info = []
|
||||
for w in all_weather:
|
||||
weather_info.append(f"{w['location_name']}: {w['weather_type']} ({w['spawn_modifier']}x)")
|
||||
|
||||
self.send_message(channel, f"🌤️ {nickname}: Current weather - " + " | ".join(weather_info))
|
||||
else:
|
||||
self.send_message(channel, f"❌ {nickname}: No weather data available.")
|
||||
|
||||
except Exception as e:
|
||||
self.send_message(channel, f"{nickname}: ❌ Error checking weather: {str(e)}")
|
||||
|
||||
async def cmd_setweather(self, channel, nickname, args):
|
||||
"""Force change weather in a location or all locations (admin only)"""
|
||||
if not self.is_admin(nickname):
|
||||
self.send_message(channel, f"{nickname}: Access denied. Admin command.")
|
||||
return
|
||||
|
||||
if not args:
|
||||
self.send_message(channel,
|
||||
f"{nickname}: Usage: !setweather <location|all> <weather_type> [duration_minutes]\n"
|
||||
f"Weather types: sunny, rainy, storm, blizzard, earthquake, calm")
|
||||
return
|
||||
|
||||
try:
|
||||
import json
|
||||
import random
|
||||
import datetime
|
||||
|
||||
# Load weather patterns
|
||||
with open("config/weather_patterns.json", "r") as f:
|
||||
weather_data = json.load(f)
|
||||
|
||||
weather_types = list(weather_data["weather_types"].keys())
|
||||
|
||||
# Smart argument parsing - check if any arg is a weather type
|
||||
location_arg = None
|
||||
weather_type = None
|
||||
duration = None
|
||||
|
||||
for i, arg in enumerate(args):
|
||||
if arg.lower() in weather_types:
|
||||
weather_type = arg.lower()
|
||||
# Remove weather type from args for location parsing
|
||||
remaining_args = args[:i] + args[i+1:]
|
||||
break
|
||||
|
||||
if not weather_type:
|
||||
self.send_message(channel, f"{nickname}: Please specify a valid weather type.")
|
||||
return
|
||||
|
||||
# Parse location from remaining args
|
||||
if remaining_args:
|
||||
if remaining_args[0].lower() == "all":
|
||||
location_arg = "all"
|
||||
# Check if there's a duration after "all"
|
||||
if len(remaining_args) > 1:
|
||||
try:
|
||||
duration = int(remaining_args[1])
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
# Location name (might be multiple words)
|
||||
location_words = []
|
||||
for arg in remaining_args:
|
||||
try:
|
||||
# If it's a number, it's probably duration
|
||||
duration = int(arg)
|
||||
break
|
||||
except ValueError:
|
||||
# It's part of location name
|
||||
location_words.append(arg)
|
||||
location_arg = " ".join(location_words) if location_words else "all"
|
||||
else:
|
||||
location_arg = "all"
|
||||
|
||||
weather_config = weather_data["weather_types"][weather_type]
|
||||
|
||||
# Calculate duration
|
||||
if not duration:
|
||||
duration_range = weather_config.get("duration_minutes", [90, 180])
|
||||
duration = random.randint(duration_range[0], duration_range[1])
|
||||
|
||||
end_time = datetime.datetime.now() + datetime.timedelta(minutes=duration)
|
||||
|
||||
if location_arg.lower() == "all":
|
||||
# Set weather for all locations
|
||||
success = await self.database.set_weather_all_locations(
|
||||
weather_type, end_time.isoformat(),
|
||||
weather_config.get("spawn_modifier", 1.0),
|
||||
",".join(weather_config.get("affected_types", []))
|
||||
)
|
||||
|
||||
if success:
|
||||
self.send_message(channel,
|
||||
f"🌤️ {nickname}: Set {weather_type} weather for ALL locations! "
|
||||
f"Duration: {duration} minutes, Modifier: {weather_config.get('spawn_modifier', 1.0)}x")
|
||||
else:
|
||||
self.send_message(channel, f"❌ {nickname}: Failed to set weather for all locations.")
|
||||
else:
|
||||
# Set weather for specific location
|
||||
location_name = location_arg if len(args) == 2 else " ".join(args[:-1])
|
||||
|
||||
success = await self.database.set_weather_for_location(
|
||||
location_name, weather_type, end_time.isoformat(),
|
||||
weather_config.get("spawn_modifier", 1.0),
|
||||
",".join(weather_config.get("affected_types", []))
|
||||
)
|
||||
|
||||
if success:
|
||||
self.send_message(channel,
|
||||
f"🌤️ {nickname}: Set {weather_type} weather for {location_name}! "
|
||||
f"Duration: {duration} minutes, Modifier: {weather_config.get('spawn_modifier', 1.0)}x")
|
||||
else:
|
||||
self.send_message(channel, f"❌ {nickname}: Failed to set weather for '{location_name}'. Location may not exist.")
|
||||
|
||||
except FileNotFoundError:
|
||||
self.send_message(channel, f"{nickname}: ❌ Weather configuration file not found.")
|
||||
except ValueError as e:
|
||||
self.send_message(channel, f"{nickname}: ❌ Invalid duration: {str(e)}")
|
||||
except Exception as e:
|
||||
self.send_message(channel, f"{nickname}: ❌ Error setting weather: {str(e)}")
|
||||
Loading…
Add table
Add a link
Reference in a new issue