camie-tagger / game /dev_tools.py
Camais03's picture
V1.5
29b445b verified
raw
history blame
24.9 kB
#!/usr/bin/env python3
"""
Developer Tools for Tag Collector Game
A hidden panel with tools for testing and debugging game features.
"""
import streamlit as st
import random
import time
from game_constants import (
TAG_CURRENCY_NAME,
RARITY_LEVELS,
ACHIEVEMENTS,
)
from tag_categories import (
TAG_CATEGORIES,
TAG_DETECTOR_UPGRADES,
PROGRESSION_ACHIEVEMENTS
)
def display_dev_tools():
"""
Display the developer tools interface
This should be hidden in production builds or behind a developer toggle
"""
st.title("🛠️ Developer Tools")
st.warning("These tools are for testing and debugging only. They can break game balance!")
# Create tabs for different tool categories
resource_tab, tag_tab, progression_tab, mosaic_tab, reset_tab = st.tabs([
"Resources", "Tag Management", "Progression", "Mosaic Tools", "Reset Tools"
])
with resource_tab:
display_resource_tools()
with tag_tab:
display_tag_tools()
with progression_tab:
display_progression_tools()
with mosaic_tab:
display_mosaic_tools()
with reset_tab:
display_reset_tools()
def display_resource_tools():
"""Display tools for managing game resources"""
st.subheader("Currency and Resources")
# Add TagCoins
col1, col2 = st.columns([3, 1])
with col1:
amount = st.number_input("Amount of TagCoins to add:", min_value=0, max_value=1000000, value=1000, step=100)
with col2:
if st.button("Add TagCoins", key="add_currency"):
st.session_state.tag_currency += amount
st.session_state.game_stats["total_currency_earned"] += amount
st.success(f"Added {amount} {TAG_CURRENCY_NAME}!")
# Set threshold directly
col1, col2 = st.columns([3, 1])
with col1:
threshold = st.slider("Set threshold value:", min_value=0.0, max_value=1.0, value=st.session_state.threshold, step=0.01)
with col2:
if st.button("Set Threshold", key="set_threshold"):
st.session_state.threshold = threshold
st.success(f"Set threshold to {threshold:.2f}")
# Add tag power bonuses
col1, col2 = st.columns([3, 1])
with col1:
power = st.number_input("Add tag power bonus:", min_value=0.0, max_value=0.1, value=0.01, step=0.001, format="%.3f")
with col2:
if st.button("Add Power", key="add_power"):
if not hasattr(st.session_state, 'tag_power_bonus'):
st.session_state.tag_power_bonus = 0
st.session_state.tag_power_bonus += power
st.success(f"Added {power:.3f} tag power!")
def display_tag_tools():
"""Display tools for managing tags"""
st.subheader("Tag Management")
# Add specific tag
with st.expander("Add Specific Tag", expanded=True):
col1, col2, col3 = st.columns([4, 2, 1])
with col1:
tag_name = st.text_input("Tag name:", value="custom_tag")
with col2:
rarities = list(RARITY_LEVELS.keys())
rarity = st.selectbox("Rarity:", rarities)
with col3:
# Get categories from session state or fallback to general
categories = ["general", "character", "copyright", "meta", "rating", "artist", "year"]
category = st.selectbox("Category:", categories)
if st.button("Add Tag", key="add_specific_tag"):
# Check if tag already exists
is_new = tag_name not in st.session_state.collected_tags
# Add tag to collection
st.session_state.collected_tags[tag_name] = {
"count": 1,
"rarity": rarity,
"category": category,
"discovery_time": time.strftime("%Y-%m-%d %H:%M:%S")
}
# Show confirmation
if is_new:
st.success(f"Added new tag '{tag_name}' ({rarity}, {category})")
else:
st.session_state.collected_tags[tag_name]["count"] += 1
st.info(f"Incremented count for existing tag '{tag_name}'")
# Generate random tags
with st.expander("Generate Random Tags", expanded=False):
col1, col2 = st.columns([3, 1])
with col1:
num_tags = st.number_input("Number of random tags to generate:", min_value=1, max_value=1000, value=10)
# Options for distribution
advanced = st.checkbox("Advanced options")
if advanced:
st.write("Rarity distribution:")
common_pct = st.slider("Common tags %:", 0, 100, 70)
uncommon_pct = st.slider("Uncommon tags %:", 0, 100, 20)
rare_pct = st.slider("Rare tags %:", 0, 100, 8)
super_rare_pct = st.slider("Super rare tags %:", 0, 100, 2)
# Ensure total is 100%
total = common_pct + uncommon_pct + rare_pct + super_rare_pct
if total != 100:
st.warning(f"Distribution totals {total}%, should be 100%")
with col2:
generate_button = st.button("Generate", key="generate_random_tags")
if generate_button:
generated_count = 0
# Determine distribution of rarities
if advanced and total == 100:
# Custom distribution
rarity_weights = {
"Whispered Word": common_pct / 100,
"Common Canard": uncommon_pct / 100 * 0.6,
"Urban Footnote": uncommon_pct / 100 * 0.4,
"Urban Myth": rare_pct / 100 * 0.5,
"Urban Legend": rare_pct / 100 * 0.5,
"Urban Nightmare": super_rare_pct / 100 * 0.8,
"Impuritas Civitas": super_rare_pct / 100 * 0.2
}
else:
# Default distribution
rarity_weights = {
"Whispered Word": 0.70,
"Common Canard": 0.15,
"Urban Footnote": 0.08,
"Urban Myth": 0.04,
"Urban Legend": 0.02,
"Urban Nightmare": 0.008,
"Impuritas Civitas": 0.002
}
# Generate the tags
for i in range(num_tags):
# Create a random tag name if we don't have metadata
tag_name = f"random_tag_{int(time.time() % 10000)}_{i}"
# Determine rarity
rarity = random.choices(
list(rarity_weights.keys()),
weights=list(rarity_weights.values()),
k=1
)[0]
# Determine category
categories = list(TAG_CATEGORIES.keys())
category = random.choice(categories)
# Add to collection
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
# Check if this is a new tag
is_new = tag_name not in st.session_state.collected_tags
if is_new:
st.session_state.collected_tags[tag_name] = {
"count": 1,
"rarity": rarity,
"category": category,
"discovery_time": timestamp
}
generated_count += 1
else:
# Increment count if already exists
st.session_state.collected_tags[tag_name]["count"] += 1
# Show confirmation
st.success(f"Generated {generated_count} new random tags!")
def display_progression_tools():
"""Display tools for managing progression"""
st.subheader("Progression System Tools")
# Unlock categories
with st.expander("Unlock Categories", expanded=True):
st.write("Select categories to unlock:")
# Get currently unlocked categories
unlocked = []
if hasattr(st.session_state, 'unlocked_tag_categories'):
unlocked = st.session_state.unlocked_tag_categories
# Display each category with a checkbox
category_checkboxes = {}
for category, info in TAG_CATEGORIES.items():
# Skip default unlocked
if info["unlocked_by_default"]:
continue
# Check if already unlocked
is_unlocked = category in unlocked
category_checkboxes[category] = st.checkbox(
f"{info['name']} ({info['cost']} {TAG_CURRENCY_NAME})",
value=is_unlocked,
key=f"cat_{category}"
)
# Button to apply changes
if st.button("Apply Category Changes", key="apply_categories"):
# Initialize if needed
if not hasattr(st.session_state, 'unlocked_tag_categories'):
st.session_state.unlocked_tag_categories = []
# Add default unlocked
for cat, info in TAG_CATEGORIES.items():
if info["unlocked_by_default"]:
st.session_state.unlocked_tag_categories.append(cat)
# Update unlocked categories
for category, checked in category_checkboxes.items():
# If checked but not unlocked, add it
if checked and category not in st.session_state.unlocked_tag_categories:
st.session_state.unlocked_tag_categories.append(category)
st.success(f"Unlocked {TAG_CATEGORIES[category]['name']}!")
# If unchecked but unlocked, remove it
elif not checked and category in st.session_state.unlocked_tag_categories:
st.session_state.unlocked_tag_categories.remove(category)
st.info(f"Locked {TAG_CATEGORIES[category]['name']}")
# Upgrade detector level
with st.expander("Set Detector Level", expanded=False):
# Get current level
current_level = 0
if hasattr(st.session_state, 'detector_level'):
current_level = st.session_state.detector_level
# Display slider for detector level
new_level = st.slider(
"Detector Level:",
min_value=0,
max_value=len(TAG_DETECTOR_UPGRADES) - 1,
value=current_level
)
# Show info about selected level
upgrade = TAG_DETECTOR_UPGRADES[new_level]
max_tags = upgrade["max_tags"]
if max_tags == 0:
st.write(f"Selected: {upgrade['name']} (Unlimited tags)")
else:
st.write(f"Selected: {upgrade['name']} ({max_tags} tags)")
# Button to apply changes
if st.button("Set Detector Level", key="set_detector_level"):
st.session_state.detector_level = new_level
st.success(f"Set detector level to {new_level} ({upgrade['name']})")
# Unlock achievements
with st.expander("Manage Achievements", expanded=False):
# Combine standard and progression achievements
all_achievements = {**ACHIEVEMENTS, **PROGRESSION_ACHIEVEMENTS}
# Initialize achievements if needed
if not hasattr(st.session_state, 'achievements'):
st.session_state.achievements = set()
# Create tabs for unlocked and locked
unlocked_tab, locked_tab = st.tabs(["Unlocked", "Locked"])
with unlocked_tab:
st.write("Currently unlocked achievements:")
# Show unlocked achievements with option to remove
for achievement_id in sorted(st.session_state.achievements):
if achievement_id in all_achievements:
col1, col2 = st.columns([3, 1])
with col1:
achievement = all_achievements[achievement_id]
st.write(f"**{achievement['name']}**: {achievement['description']}")
with col2:
if st.button("Remove", key=f"remove_{achievement_id}"):
st.session_state.achievements.remove(achievement_id)
st.info(f"Removed achievement: {achievement['name']}")
st.rerun()
with locked_tab:
st.write("Currently locked achievements:")
# Show locked achievements with option to add
locked_achievements = [a for a in all_achievements if a not in st.session_state.achievements]
for achievement_id in sorted(locked_achievements):
col1, col2 = st.columns([3, 1])
with col1:
achievement = all_achievements[achievement_id]
st.write(f"**{achievement['name']}**: {achievement['description']}")
with col2:
if st.button("Unlock", key=f"unlock_{achievement_id}"):
st.session_state.achievements.add(achievement_id)
# Apply rewards if applicable
if "reward" in achievement:
from scan_handler import apply_achievement_reward
apply_achievement_reward(achievement_id, achievement["reward"])
st.success(f"Unlocked achievement: {achievement['name']}")
st.rerun()
def display_mosaic_tools():
"""Display tools for managing the tag mosaic"""
st.subheader("Tag Mosaic Tools")
# Check if mosaic exists
has_mosaic = hasattr(st.session_state, 'tag_mosaic')
if not has_mosaic:
st.warning("Tag Mosaic not initialized yet. Visit the Tag Collection tab first.")
return
# Fill random portions of the mosaic
with st.expander("Fill Random Portions", expanded=True):
col1, col2 = st.columns([3, 1])
with col1:
fill_percentage = st.slider(
"Percentage to fill:",
min_value=0,
max_value=100,
value=10,
step=1
)
# Options for distribution
st.write("Fill with tags of rarity:")
fill_rarities = {}
for rarity in RARITY_LEVELS:
fill_rarities[rarity] = st.checkbox(rarity, value=True, key=f"fill_{rarity}")
with col2:
fill_button = st.button("Fill Mosaic", key="fill_mosaic")
if fill_button:
# Get the mosaic from session state
mosaic = st.session_state.tag_mosaic
# Calculate how many cells to fill
total_cells = mosaic.total_cells
existing_filled = len(mosaic.filled_cells)
target_filled = int(total_cells * fill_percentage / 100)
cells_to_add = max(0, target_filled - existing_filled)
# Get active rarities
active_rarities = [r for r, checked in fill_rarities.items() if checked]
if not active_rarities:
st.error("Select at least one rarity to fill with")
return
# Create artificial tags and add them
added_count = 0
added_tags = {}
# Generate random positions
all_positions = [(x, y) for x in range(mosaic.grid_width) for y in range(mosaic.grid_height)]
# Remove already filled positions
available_positions = [pos for pos in all_positions if pos not in mosaic.filled_cells]
# If we need more than available, just use what's available
cells_to_add = min(cells_to_add, len(available_positions))
# Randomly select positions
selected_positions = random.sample(available_positions, cells_to_add)
# Create tags for each position
for pos in selected_positions:
x, y = pos
# Create a tag name
tag_name = f"mosaic_fill_{x}_{y}_{int(time.time() % 10000)}"
# Select a random rarity from active rarities
rarity = random.choice(active_rarities)
# Add to tags dictionary (this won't be saved to session_state)
added_tags[tag_name] = {
"count": 1,
"rarity": rarity,
"category": "general"
}
added_count += 1
# Update the mosaic (this does save to disk)
if added_count > 0:
mosaic.update_with_tags(added_tags)
st.success(f"Added {added_count} random cells to the mosaic!")
# Show updated stats
stats = mosaic.get_stats()
st.write(f"New completion: {stats['completion_percentage']:.2f}%")
st.write(f"Emerging pattern: {stats['completion_pattern']}")
# Show image
mosaic_img = mosaic.get_image(show_highlights=True)
st.image(mosaic_img, caption="Updated Mosaic", width=400)
else:
st.info("No new cells added. Mosaic may already be filled to the requested level.")
# Reset mosaic without affecting collection
with st.expander("Reset Mosaic", expanded=False):
if st.button("Reset Mosaic", key="reset_mosaic"):
# Confirm
confirm = st.checkbox("I understand this will clear the mosaic visualization (not your collection)")
if confirm:
# Get the mosaic from session state
mosaic = st.session_state.tag_mosaic
# Reset the mosaic by creating a new one
from tag_mosaic import TagMosaic
st.session_state.tag_mosaic = TagMosaic()
# Delete the mosaic save file
import os
if os.path.exists("tag_mosaic.png"):
try:
os.remove("tag_mosaic.png")
except Exception as e:
st.error(f"Error removing mosaic file: {e}")
st.success("Mosaic has been reset!")
def display_reset_tools():
"""Display tools for resetting the game"""
st.subheader("Reset Tools")
st.warning("These tools will reset parts of your game progress. Use with caution!")
# Reset currency
with st.expander("Reset Currency", expanded=False):
col1, col2 = st.columns([3, 1])
with col1:
new_amount = st.number_input("Set currency to:", min_value=0, value=0)
with col2:
if st.button("Reset Currency", key="reset_currency"):
st.session_state.tag_currency = new_amount
st.success(f"Reset currency to {new_amount} {TAG_CURRENCY_NAME}")
# Reset collection
with st.expander("Reset Collection", expanded=False):
st.write("This will remove all collected tags or specific rarities.")
# Options to keep certain rarities
st.write("Keep tags with these rarities:")
keep_rarities = {}
for rarity in RARITY_LEVELS:
keep_rarities[rarity] = st.checkbox(rarity, value=False, key=f"keep_{rarity}")
if st.button("Reset Collection", key="reset_collection"):
# Confirm
confirm = st.checkbox("I understand this will delete collected tags")
if confirm:
# Get rarities to keep
rarities_to_keep = [r for r, checked in keep_rarities.items() if checked]
# If keeping some rarities, filter the collection
if rarities_to_keep:
# Create a new collection with only the kept rarities
kept_tags = {}
for tag, info in st.session_state.collected_tags.items():
if info.get("rarity") in rarities_to_keep:
kept_tags[tag] = info
# Replace the collection
removed_count = len(st.session_state.collected_tags) - len(kept_tags)
st.session_state.collected_tags = kept_tags
st.success(f"Removed {removed_count} tags. Kept {len(kept_tags)} tags with rarities: {', '.join(rarities_to_keep)}")
else:
# Remove all tags
removed_count = len(st.session_state.collected_tags)
st.session_state.collected_tags = {}
st.success(f"Removed all {removed_count} tags from your collection")
# Reset complete game
with st.expander("Reset ENTIRE Game", expanded=False):
st.error("This will reset ALL game progress including collection, currency, achievements, and upgrades.")
if st.button("Reset EVERYTHING", key="reset_everything"):
# Double confirm
confirm1 = st.checkbox("I understand ALL progress will be lost")
confirm2 = st.checkbox("This cannot be undone")
if confirm1 and confirm2:
# Reset everything
st.session_state.threshold = 0.25 # Default starting threshold
st.session_state.tag_currency = 0
st.session_state.collected_tags = {}
st.session_state.purchased_upgrades = []
st.session_state.achievements = set()
st.session_state.tag_history = []
st.session_state.current_scan = None
st.session_state.game_stats = {
"images_processed": 0,
"total_tags_found": 0,
"total_currency_earned": 0,
"currency_spent": 0
}
# Reset progression
if hasattr(st.session_state, 'unlocked_tag_categories'):
st.session_state.unlocked_tag_categories = []
# Add default unlocked categories
for cat, info in TAG_CATEGORIES.items():
if info["unlocked_by_default"]:
st.session_state.unlocked_tag_categories.append(cat)
if hasattr(st.session_state, 'detector_level'):
st.session_state.detector_level = 0
if hasattr(st.session_state, 'tag_power_bonus'):
st.session_state.tag_power_bonus = 0
if hasattr(st.session_state, 'coin_multiplier'):
st.session_state.coin_multiplier = 1.0
if hasattr(st.session_state, 'essence_generator_count'):
st.session_state.essence_generator_count = 0
# Reset mosaic
import os
if os.path.exists("tag_mosaic.png"):
try:
os.remove("tag_mosaic.png")
except Exception as e:
st.error(f"Error removing mosaic file: {e}")
if hasattr(st.session_state, 'tag_mosaic'):
from tag_mosaic import TagMosaic
st.session_state.tag_mosaic = TagMosaic()
st.success("Game completely reset to initial state!")
st.info("Refresh the page to see changes take effect")