|
|
|
"""
|
|
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!")
|
|
|
|
|
|
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")
|
|
|
|
|
|
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}!")
|
|
|
|
|
|
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}")
|
|
|
|
|
|
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")
|
|
|
|
|
|
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:
|
|
|
|
categories = ["general", "character", "copyright", "meta", "rating", "artist", "year"]
|
|
category = st.selectbox("Category:", categories)
|
|
|
|
if st.button("Add Tag", key="add_specific_tag"):
|
|
|
|
is_new = tag_name not in st.session_state.collected_tags
|
|
|
|
|
|
st.session_state.collected_tags[tag_name] = {
|
|
"count": 1,
|
|
"rarity": rarity,
|
|
"category": category,
|
|
"discovery_time": time.strftime("%Y-%m-%d %H:%M:%S")
|
|
}
|
|
|
|
|
|
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}'")
|
|
|
|
|
|
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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
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
|
|
|
|
|
|
if advanced and total == 100:
|
|
|
|
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:
|
|
|
|
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
|
|
}
|
|
|
|
|
|
for i in range(num_tags):
|
|
|
|
tag_name = f"random_tag_{int(time.time() % 10000)}_{i}"
|
|
|
|
|
|
rarity = random.choices(
|
|
list(rarity_weights.keys()),
|
|
weights=list(rarity_weights.values()),
|
|
k=1
|
|
)[0]
|
|
|
|
|
|
categories = list(TAG_CATEGORIES.keys())
|
|
category = random.choice(categories)
|
|
|
|
|
|
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
|
|
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:
|
|
|
|
st.session_state.collected_tags[tag_name]["count"] += 1
|
|
|
|
|
|
st.success(f"Generated {generated_count} new random tags!")
|
|
|
|
def display_progression_tools():
|
|
"""Display tools for managing progression"""
|
|
st.subheader("Progression System Tools")
|
|
|
|
|
|
with st.expander("Unlock Categories", expanded=True):
|
|
st.write("Select categories to unlock:")
|
|
|
|
|
|
unlocked = []
|
|
if hasattr(st.session_state, 'unlocked_tag_categories'):
|
|
unlocked = st.session_state.unlocked_tag_categories
|
|
|
|
|
|
category_checkboxes = {}
|
|
for category, info in TAG_CATEGORIES.items():
|
|
|
|
if info["unlocked_by_default"]:
|
|
continue
|
|
|
|
|
|
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}"
|
|
)
|
|
|
|
|
|
if st.button("Apply Category Changes", key="apply_categories"):
|
|
|
|
if not hasattr(st.session_state, 'unlocked_tag_categories'):
|
|
st.session_state.unlocked_tag_categories = []
|
|
|
|
|
|
for cat, info in TAG_CATEGORIES.items():
|
|
if info["unlocked_by_default"]:
|
|
st.session_state.unlocked_tag_categories.append(cat)
|
|
|
|
|
|
for category, checked in category_checkboxes.items():
|
|
|
|
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']}!")
|
|
|
|
|
|
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']}")
|
|
|
|
|
|
with st.expander("Set Detector Level", expanded=False):
|
|
|
|
current_level = 0
|
|
if hasattr(st.session_state, 'detector_level'):
|
|
current_level = st.session_state.detector_level
|
|
|
|
|
|
new_level = st.slider(
|
|
"Detector Level:",
|
|
min_value=0,
|
|
max_value=len(TAG_DETECTOR_UPGRADES) - 1,
|
|
value=current_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)")
|
|
|
|
|
|
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']})")
|
|
|
|
|
|
with st.expander("Manage Achievements", expanded=False):
|
|
|
|
all_achievements = {**ACHIEVEMENTS, **PROGRESSION_ACHIEVEMENTS}
|
|
|
|
|
|
if not hasattr(st.session_state, 'achievements'):
|
|
st.session_state.achievements = set()
|
|
|
|
|
|
unlocked_tab, locked_tab = st.tabs(["Unlocked", "Locked"])
|
|
|
|
with unlocked_tab:
|
|
st.write("Currently unlocked achievements:")
|
|
|
|
|
|
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:")
|
|
|
|
|
|
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)
|
|
|
|
|
|
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")
|
|
|
|
|
|
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
|
|
|
|
|
|
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
|
|
)
|
|
|
|
|
|
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:
|
|
|
|
mosaic = st.session_state.tag_mosaic
|
|
|
|
|
|
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)
|
|
|
|
|
|
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
|
|
|
|
|
|
added_count = 0
|
|
added_tags = {}
|
|
|
|
|
|
all_positions = [(x, y) for x in range(mosaic.grid_width) for y in range(mosaic.grid_height)]
|
|
|
|
available_positions = [pos for pos in all_positions if pos not in mosaic.filled_cells]
|
|
|
|
|
|
cells_to_add = min(cells_to_add, len(available_positions))
|
|
|
|
|
|
selected_positions = random.sample(available_positions, cells_to_add)
|
|
|
|
|
|
for pos in selected_positions:
|
|
x, y = pos
|
|
|
|
|
|
tag_name = f"mosaic_fill_{x}_{y}_{int(time.time() % 10000)}"
|
|
|
|
|
|
rarity = random.choice(active_rarities)
|
|
|
|
|
|
added_tags[tag_name] = {
|
|
"count": 1,
|
|
"rarity": rarity,
|
|
"category": "general"
|
|
}
|
|
|
|
added_count += 1
|
|
|
|
|
|
if added_count > 0:
|
|
mosaic.update_with_tags(added_tags)
|
|
st.success(f"Added {added_count} random cells to the mosaic!")
|
|
|
|
|
|
stats = mosaic.get_stats()
|
|
st.write(f"New completion: {stats['completion_percentage']:.2f}%")
|
|
st.write(f"Emerging pattern: {stats['completion_pattern']}")
|
|
|
|
|
|
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.")
|
|
|
|
|
|
with st.expander("Reset Mosaic", expanded=False):
|
|
if st.button("Reset Mosaic", key="reset_mosaic"):
|
|
|
|
confirm = st.checkbox("I understand this will clear the mosaic visualization (not your collection)")
|
|
|
|
if confirm:
|
|
|
|
mosaic = st.session_state.tag_mosaic
|
|
|
|
|
|
from tag_mosaic import TagMosaic
|
|
st.session_state.tag_mosaic = TagMosaic()
|
|
|
|
|
|
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!")
|
|
|
|
|
|
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}")
|
|
|
|
|
|
with st.expander("Reset Collection", expanded=False):
|
|
st.write("This will remove all collected tags or specific 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 = st.checkbox("I understand this will delete collected tags")
|
|
|
|
if confirm:
|
|
|
|
rarities_to_keep = [r for r, checked in keep_rarities.items() if checked]
|
|
|
|
|
|
if rarities_to_keep:
|
|
|
|
kept_tags = {}
|
|
for tag, info in st.session_state.collected_tags.items():
|
|
if info.get("rarity") in rarities_to_keep:
|
|
kept_tags[tag] = info
|
|
|
|
|
|
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:
|
|
|
|
removed_count = len(st.session_state.collected_tags)
|
|
st.session_state.collected_tags = {}
|
|
st.success(f"Removed all {removed_count} tags from your collection")
|
|
|
|
|
|
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"):
|
|
|
|
confirm1 = st.checkbox("I understand ALL progress will be lost")
|
|
confirm2 = st.checkbox("This cannot be undone")
|
|
|
|
if confirm1 and confirm2:
|
|
|
|
st.session_state.threshold = 0.25
|
|
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
|
|
}
|
|
|
|
|
|
if hasattr(st.session_state, 'unlocked_tag_categories'):
|
|
st.session_state.unlocked_tag_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
|
|
|
|
|
|
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") |