mirror of
https://github.com/ethanrusz/scouter.git
synced 2025-04-20 14:06:32 -04:00
Compare commits
No commits in common. "19150301d6dd3206bb93ff7cda3cdcab10c1eb48" and "1fa40e729d6c1f77b5d752684033ffc4c49c8832" have entirely different histories.
19150301d6
...
1fa40e729d
2 changed files with 151 additions and 95 deletions
157
app.py
157
app.py
|
@ -2,6 +2,14 @@ import streamlit as st
|
||||||
import database as db
|
import database as db
|
||||||
|
|
||||||
|
|
||||||
|
class Moon:
|
||||||
|
def __init__(self, name, tier, inside_max_power, outside_max_power):
|
||||||
|
self.name = name
|
||||||
|
self.tier = tier
|
||||||
|
self.inside_max_power = inside_max_power
|
||||||
|
self.outside_max_power = outside_max_power
|
||||||
|
|
||||||
|
|
||||||
class Creature:
|
class Creature:
|
||||||
def __init__(self, name, nickname, power, max_spawns, hits_to_kill):
|
def __init__(self, name, nickname, power, max_spawns, hits_to_kill):
|
||||||
self.name = name
|
self.name = name
|
||||||
|
@ -18,22 +26,85 @@ class Run:
|
||||||
self.outside_power = moon.outside_max_power
|
self.outside_power = moon.outside_max_power
|
||||||
|
|
||||||
|
|
||||||
|
def find_spawn_list(remaining_power: int, creatures: list[Creature]) -> list[str] | None:
|
||||||
|
"""
|
||||||
|
Given a run, return all possible spawns for location.
|
||||||
|
|
||||||
|
:param creatures:
|
||||||
|
:param remaining_power: The remaining power in the current location.
|
||||||
|
:return: A list of all creatures that may still spawn or None.
|
||||||
|
"""
|
||||||
|
if remaining_power == 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
spawnable = sorted(
|
||||||
|
[creature.name for creature in creatures if creature.power <= remaining_power]
|
||||||
|
)
|
||||||
|
if spawnable:
|
||||||
|
return spawnable
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
st.set_page_config("Lethal Company Scouter", "🛰️")
|
st.set_page_config("Lethal Company Scouter", "🛰️")
|
||||||
|
|
||||||
moon_name = st.selectbox(
|
moons = [
|
||||||
|
# Tier 1
|
||||||
|
Moon("Experimentation", 1, 4, 8),
|
||||||
|
Moon("Assurance", 1, 6, 8),
|
||||||
|
Moon("Vow", 1, 7, 6),
|
||||||
|
# Tier 2
|
||||||
|
Moon("Offense", 2, 12, 12),
|
||||||
|
Moon("March", 2, 14, 12),
|
||||||
|
# Tier 3
|
||||||
|
Moon("Rend", 3, 10, 6),
|
||||||
|
Moon("Dine", 3, 15, 6),
|
||||||
|
Moon("Titan", 3, 18, 7),
|
||||||
|
]
|
||||||
|
|
||||||
|
outside_creatures = [
|
||||||
|
Creature("Baboon Hawk", None, 1, 15, 6),
|
||||||
|
Creature("Circuit Bees", None, 1, 6, None),
|
||||||
|
Creature("Eyeless Dog", None, 2, 8, 12),
|
||||||
|
Creature("Forest Keeper", "Giant", 3, 3, None),
|
||||||
|
Creature("Earth Leviathan", "Worm", 2, 3, None),
|
||||||
|
# Hybrid
|
||||||
|
Creature("Outside Ghost Girl ", None, 2, 1, None),
|
||||||
|
Creature("Outside Masked", None, 1, 10, 4),
|
||||||
|
]
|
||||||
|
|
||||||
|
inside_creatures = [
|
||||||
|
Creature("Bracken", "Freddy Fazbear", 3, 1, 6),
|
||||||
|
Creature("Bunker Spider", None, 3, 1, 6),
|
||||||
|
Creature("Coil Head", None, 1, 5, None),
|
||||||
|
Creature("Hoarding Bug", "Yippee Bug", 1, 8, 3),
|
||||||
|
Creature("Hygrodere", "Goo", 1, 2, None),
|
||||||
|
Creature("Jester", None, 3, 1, None),
|
||||||
|
Creature("Nutcracker", None, 1, 10, 5),
|
||||||
|
Creature("Snare Flea", "Head. Bug.", 1, 4, 3),
|
||||||
|
Creature("Spore Lizard", None, 1, 2, None),
|
||||||
|
Creature("Thumper", None, 2, 4, 4),
|
||||||
|
# Hybrid
|
||||||
|
Creature("Inside Ghost Girl", None, 2, 1, None),
|
||||||
|
Creature("Inside Masked", None, 1, 10, 4),
|
||||||
|
]
|
||||||
|
|
||||||
|
st.markdown("# :red[Lethal Company] Scouter")
|
||||||
|
st.markdown(":rainbow[What does the scouter say about this moon's power level?]")
|
||||||
|
|
||||||
|
moon_strings = db.get_moon_list()
|
||||||
|
|
||||||
|
moon = st.selectbox(
|
||||||
"Moon",
|
"Moon",
|
||||||
db.get_moon_list(),
|
moon_strings,
|
||||||
placeholder="Moon! Pick a moon!",
|
placeholder="Moon! Pick a moon!",
|
||||||
help="Pick your current moon.",
|
help="Pick your current moon.",
|
||||||
)
|
)
|
||||||
moon_id = db.get_moon_id_by_name(moon_name)
|
|
||||||
run = Run(db.get_moon_by_id(moon_id))
|
|
||||||
|
|
||||||
st.markdown(f"## {run.moon.name} ({run.moon.tier})")
|
run = Run(next(m for m in moons if m.name is moon))
|
||||||
|
|
||||||
st.info(f"Risk: {run.moon.risk_level} | Min scrap: {run.moon.min_scrap} "
|
st.markdown(f"## {run.moon.name} (Tier {run.moon.tier})")
|
||||||
f"| Max scrap: {run.moon.max_scrap} | Default layout: {run.moon.default_layout}")
|
|
||||||
|
|
||||||
# Begin column layout
|
# Begin column layout
|
||||||
left_column, right_column = st.columns(2)
|
left_column, right_column = st.columns(2)
|
||||||
|
@ -41,9 +112,81 @@ def main():
|
||||||
with left_column:
|
with left_column:
|
||||||
st.markdown("### Outside")
|
st.markdown("### Outside")
|
||||||
|
|
||||||
|
with st.form("outside"):
|
||||||
|
for creature in outside_creatures:
|
||||||
|
moon_max = min(
|
||||||
|
creature.max_spawns, run.moon.outside_max_power // creature.power
|
||||||
|
)
|
||||||
|
if moon_max > 0:
|
||||||
|
st.slider(
|
||||||
|
creature.name,
|
||||||
|
0,
|
||||||
|
moon_max,
|
||||||
|
key=creature.name,
|
||||||
|
help=creature.nickname,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
st.slider(
|
||||||
|
creature.name,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
key=creature.name,
|
||||||
|
help=creature.nickname,
|
||||||
|
disabled=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
run.outside_power = run.outside_power - st.session_state[creature.name]
|
||||||
|
|
||||||
|
outside_submit = st.form_submit_button("Calculate")
|
||||||
|
if outside_submit:
|
||||||
|
st.info(f"Maximum power: {run.moon.outside_max_power}")
|
||||||
|
if run.outside_power >= 0:
|
||||||
|
st.warning(f"🌳 Outside power remaining: {run.outside_power}")
|
||||||
|
st.write(find_spawn_list(run.outside_power, outside_creatures))
|
||||||
|
else:
|
||||||
|
st.error(
|
||||||
|
f"Power level exceeds maximum possible for {run.moon.name}."
|
||||||
|
)
|
||||||
|
|
||||||
with right_column:
|
with right_column:
|
||||||
st.markdown("### Inside")
|
st.markdown("### Inside")
|
||||||
|
|
||||||
|
with st.form("inside"):
|
||||||
|
for creature in inside_creatures:
|
||||||
|
moon_max = min(
|
||||||
|
creature.max_spawns, run.moon.inside_max_power // creature.power
|
||||||
|
)
|
||||||
|
if moon_max > 0:
|
||||||
|
st.slider(
|
||||||
|
creature.name,
|
||||||
|
0,
|
||||||
|
moon_max,
|
||||||
|
key=creature.name,
|
||||||
|
help=creature.nickname,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
st.slider(
|
||||||
|
creature.name,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
key=creature.name,
|
||||||
|
help=creature.nickname,
|
||||||
|
disabled=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
run.inside_power = run.inside_power - st.session_state[creature.name]
|
||||||
|
|
||||||
|
inside_submit = st.form_submit_button("Calculate")
|
||||||
|
if inside_submit:
|
||||||
|
st.info(f"Maximum power: {run.moon.inside_max_power}")
|
||||||
|
if run.inside_power >= 0:
|
||||||
|
st.warning(f"🏭 Inside power remaining: {run.inside_power}")
|
||||||
|
st.write(find_spawn_list(run.inside_power, inside_creatures))
|
||||||
|
else:
|
||||||
|
st.error(
|
||||||
|
f"Power level exceeds maximum possible for {run.moon.name}."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -2,109 +2,22 @@ import os
|
||||||
import sqlite3
|
import sqlite3
|
||||||
|
|
||||||
|
|
||||||
class Moon:
|
|
||||||
def __init__(self, moon_id, name, risk_level, cost, default_layout, map_size_multiplier, min_scrap, max_scrap,
|
|
||||||
outside_max_power, inside_max_power, tier):
|
|
||||||
self.id = moon_id
|
|
||||||
self.name = name
|
|
||||||
self.risk_level = risk_level
|
|
||||||
self.cost = cost
|
|
||||||
self.default_layout = default_layout,
|
|
||||||
self.map_size_multiplier = map_size_multiplier
|
|
||||||
self.min_scrap = min_scrap
|
|
||||||
self.max_scrap = max_scrap
|
|
||||||
self.outside_max_power = outside_max_power
|
|
||||||
self.inside_max_power = inside_max_power
|
|
||||||
self.tier = tier
|
|
||||||
|
|
||||||
|
|
||||||
def get_connection() -> sqlite3.Connection:
|
def get_connection() -> sqlite3.Connection:
|
||||||
"""Opens a connection to the SQLite3 database at the default path
|
|
||||||
or a path provided by an environment variable if one exists.
|
|
||||||
|
|
||||||
:return: A connection to the database as a sqlite3.Connection object
|
|
||||||
"""
|
|
||||||
if os.getenv("DATABASE_FILE"):
|
if os.getenv("DATABASE_FILE"):
|
||||||
return sqlite3.connect(os.getenv("DATABASE_FILE"))
|
return sqlite3.connect(os.getenv("DATABASE_FILE"))
|
||||||
else:
|
else:
|
||||||
return sqlite3.connect("./scouter.db")
|
return sqlite3.connect("./scouter.db")
|
||||||
|
|
||||||
|
|
||||||
def get_moon_id_by_name(moon_name: str) -> int | None:
|
|
||||||
"""Queries the database for a moon ID that matches the given name.
|
|
||||||
|
|
||||||
:param moon_name: Moon name as a string
|
|
||||||
:return: The moon's ID as an int or None if no moon is found
|
|
||||||
"""
|
|
||||||
with get_connection() as connection:
|
|
||||||
cursor = connection.cursor()
|
|
||||||
moon_id = cursor.execute(
|
|
||||||
"select moon_id "
|
|
||||||
"from moon "
|
|
||||||
"where moon_name = ? "
|
|
||||||
"limit 1;",
|
|
||||||
(moon_name,)
|
|
||||||
).fetchone()
|
|
||||||
|
|
||||||
if moon_id:
|
|
||||||
return moon_id[0]
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def get_moon_list() -> list[str] | None:
|
def get_moon_list() -> list[str] | None:
|
||||||
"""Provides a list of all moon names from the database.
|
|
||||||
|
|
||||||
:return: All moon names as a list of strings or None if no moons are found
|
|
||||||
"""
|
|
||||||
with get_connection() as connection:
|
with get_connection() as connection:
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
moons = cursor.execute(
|
moons = cursor.execute(
|
||||||
"select moon_name from moon order by moon_id"
|
"select moon_name from moon order by moon_id"
|
||||||
).fetchall()
|
)
|
||||||
|
|
||||||
if moons:
|
if moons:
|
||||||
moons = [moon[0] for moon in moons]
|
moons = [moon[0] for moon in moons]
|
||||||
return moons
|
return moons
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_moon_by_id(moon_id: int) -> Moon | None:
|
|
||||||
"""Queries the database to create a moon object.
|
|
||||||
|
|
||||||
:param moon_id: Moon ID as int
|
|
||||||
:return: A moon object or None if no moon is found
|
|
||||||
"""
|
|
||||||
with get_connection() as connection:
|
|
||||||
connection.text_factory = str
|
|
||||||
cursor = connection.cursor()
|
|
||||||
|
|
||||||
query = """
|
|
||||||
select m.moon_id,
|
|
||||||
m.moon_name,
|
|
||||||
rl.risk_level_name,
|
|
||||||
m.cost,
|
|
||||||
l.layout_name,
|
|
||||||
m.map_size_multiplier,
|
|
||||||
m.min_scrap,
|
|
||||||
m.max_scrap,
|
|
||||||
m.outside_max_power,
|
|
||||||
m.inside_max_power,
|
|
||||||
mt.tier_name
|
|
||||||
from moon as m
|
|
||||||
join main.risk_level rl on rl.risk_level_id = m.risk_level_id
|
|
||||||
join main.layout l on l.layout_id = m.default_layout_id
|
|
||||||
join main.moon_tier mt on mt.moon_tier_id = m.moon_tier_id
|
|
||||||
where m.moon_id = ?
|
|
||||||
limit 1;"""
|
|
||||||
|
|
||||||
moon = cursor.execute(
|
|
||||||
query,
|
|
||||||
(moon_id,)
|
|
||||||
).fetchone()
|
|
||||||
|
|
||||||
if moon:
|
|
||||||
return Moon(*moon)
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue