feat(achievements): add some achievements
This commit is contained in:
650
app/achievements/hush_hush.py
Normal file
650
app/achievements/hush_hush.py
Normal file
@@ -0,0 +1,650 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from app.database.beatmap import calculate_beatmap_attributes
|
||||
from app.database.score import Beatmap, Score
|
||||
from app.dependencies.database import get_redis
|
||||
from app.dependencies.fetcher import get_fetcher
|
||||
from app.models.achievement import Achievement, Medals
|
||||
from app.models.beatmap import BeatmapRankStatus
|
||||
from app.models.mods import get_speed_rate, mod_to_save
|
||||
from app.models.score import Rank
|
||||
|
||||
from sqlmodel.ext.asyncio.session import AsyncSession
|
||||
|
||||
|
||||
async def jackpot(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# Pass a map with a score above 100,000, where every digit of the score is
|
||||
# identical (222,222 / 7,777,777 / 99,999,999 / etc).
|
||||
return (
|
||||
score.passed
|
||||
and score.total_score > 100000
|
||||
and all(d == str(score.total_score)[0] for d in str(score.total_score))
|
||||
)
|
||||
|
||||
|
||||
async def nonstop(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# PFC any map with a drain time of 8:41 or longer (before mods).
|
||||
return (score.rank == Rank.X or score.rank == Rank.XH) and beatmap.hit_length > 521
|
||||
|
||||
|
||||
async def time_dilation(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# Pass any map that is 8 minutes or longer (after mods),
|
||||
# Using either of the specified mods: DT, NC.
|
||||
# NF is not allowed, but all other difficulty reducing mods are.
|
||||
if not score.passed:
|
||||
return False
|
||||
mods_ = mod_to_save(score.mods)
|
||||
if "NF" in mods_:
|
||||
return False
|
||||
if "DT" not in mods_ and "NC" not in mods_:
|
||||
return False
|
||||
rate = get_speed_rate(score.mods)
|
||||
return beatmap.hit_length / rate > 480
|
||||
|
||||
|
||||
async def to_the_core(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# Pass any map that contains 'Nightcore' in the title or artist name,
|
||||
# using either of the mods specified: DT, NC
|
||||
if not score.passed:
|
||||
return False
|
||||
if (
|
||||
"Nightcore" not in beatmap.beatmapset.title
|
||||
) and "Nightcore" not in beatmap.beatmapset.artist:
|
||||
return False
|
||||
mods_ = mod_to_save(score.mods)
|
||||
if "DT" not in mods_ or "NC" not in mods_:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
async def wysi(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# Pass any map by song artist "xi" with X7.27% accuracy (97.27%, 87.27%, etc.).
|
||||
if not score.passed:
|
||||
return False
|
||||
if str(round(score.accuracy, ndigits=4))[3:] != "727":
|
||||
return False
|
||||
if "xi" not in beatmap.beatmapset.artist:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
async def prepared(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# PFC any map, using the mods specified: NF
|
||||
if score.rank != Rank.X or score.rank != Rank.XH:
|
||||
return False
|
||||
mods_ = mod_to_save(score.mods)
|
||||
if "NF" not in mods_:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
async def reckless_adandon(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# PFC any map, using the mods specified: HR, SD, that is star 3+ after mods.
|
||||
if score.rank != Rank.X or score.rank != Rank.XH:
|
||||
return False
|
||||
mods_ = mod_to_save(score.mods)
|
||||
if "HR" not in mods_ or "SD" not in mods_:
|
||||
return False
|
||||
fetcher = await get_fetcher()
|
||||
redis = get_redis()
|
||||
mods_ = score.mods.copy()
|
||||
attribute = await calculate_beatmap_attributes(
|
||||
beatmap.id, score.gamemode, mods_, redis, fetcher
|
||||
)
|
||||
if attribute.star_rating < 3:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
async def lights_out(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
):
|
||||
# Pass any map, using the mods specified: FL, NC
|
||||
if not score.passed:
|
||||
return False
|
||||
mods_ = mod_to_save(score.mods)
|
||||
return "FL" in mods_ and "NC" in mods_
|
||||
|
||||
|
||||
async def camera_shy(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
):
|
||||
# PFC any map, using the mods specified: HD, NF
|
||||
if score.rank != Rank.X and score.rank != Rank.XH:
|
||||
return False
|
||||
mods_ = mod_to_save(score.mods)
|
||||
return "HD" in mods_ and "NF" in mods_
|
||||
|
||||
|
||||
async def the_sun_of_all_fears(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
):
|
||||
# "PFC" any map, but miss on the very first or very last combo.
|
||||
if not score.passed:
|
||||
return False
|
||||
return score.max_combo == (beatmap.max_combo or 0) - 1
|
||||
|
||||
|
||||
async def hour_before_the_down(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# PFC any difficulty of ginkiha - EOS.
|
||||
if score.rank != Rank.X and score.rank != Rank.XH:
|
||||
return False
|
||||
return beatmap.beatmapset.artist == "ginkiha" and beatmap.beatmapset.title == "EOS"
|
||||
|
||||
|
||||
async def slow_and_steady(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# PFC any map, using the mods specified: HT, PF, that is star 3+ after mods.
|
||||
if score.rank != Rank.X and score.rank != Rank.XH:
|
||||
return False
|
||||
mods_ = mod_to_save(score.mods)
|
||||
if "HT" not in mods_ or "PF" not in mods_:
|
||||
return False
|
||||
fetcher = await get_fetcher()
|
||||
redis = get_redis()
|
||||
mods_ = score.mods.copy()
|
||||
attribute = await calculate_beatmap_attributes(
|
||||
beatmap.id, score.gamemode, mods_, redis, fetcher
|
||||
)
|
||||
return attribute.star_rating >= 3
|
||||
|
||||
|
||||
async def no_time_to_spare(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# PFC any map, using the mods specified, that is 30 seconds or shorter (after mods).
|
||||
if score.rank != Rank.X and score.rank != Rank.XH:
|
||||
return False
|
||||
mods_ = mod_to_save(score.mods)
|
||||
if "DT" not in mods_ and "NC" not in mods_:
|
||||
return False
|
||||
rate = get_speed_rate(score.mods)
|
||||
return (beatmap.total_length / rate) <= 30
|
||||
|
||||
|
||||
async def sognare(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# Pass LeaF - Evanescent using HT (difficulty reduction allowed)
|
||||
if not score.passed:
|
||||
return False
|
||||
mods_ = mod_to_save(score.mods)
|
||||
if "HT" not in mods_:
|
||||
return False
|
||||
return (
|
||||
beatmap.beatmapset.artist == "LeaF" and beatmap.beatmapset.title == "Evanescent"
|
||||
)
|
||||
|
||||
|
||||
async def realtor_extraordinaire(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# PFC any difficulty of cYsmix - House With Legs using DT/HR (DT/NC interchangeable)
|
||||
if score.rank != Rank.X and score.rank != Rank.XH:
|
||||
return False
|
||||
mods_ = mod_to_save(score.mods)
|
||||
if not ("DT" in mods_ or "NC" in mods_) or "HR" not in mods_:
|
||||
return False
|
||||
return (
|
||||
beatmap.beatmapset.artist == "cYsmix"
|
||||
and beatmap.beatmapset.title == "House With Legs"
|
||||
)
|
||||
|
||||
|
||||
async def impeccable(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# Pass any map using the mods specified: DT, PF, that is star 4+ after mods.
|
||||
if not score.passed:
|
||||
return False
|
||||
mods_ = mod_to_save(score.mods)
|
||||
# DT and NC interchangeable
|
||||
if not ("DT" in mods_ or "NC" in mods_) or "PF" not in mods_:
|
||||
return False
|
||||
fetcher = await get_fetcher()
|
||||
redis = get_redis()
|
||||
mods_ = score.mods.copy()
|
||||
attribute = await calculate_beatmap_attributes(
|
||||
beatmap.id, score.gamemode, mods_, redis, fetcher
|
||||
)
|
||||
return attribute.star_rating >= 4
|
||||
|
||||
|
||||
async def aeon(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# PFC any map that was ranked before or during 2011,
|
||||
# using the mods specified: FL, HD, HT.
|
||||
# The map must be at least star 4+ and at least 3 minutes long after mods.
|
||||
if not score.passed:
|
||||
return False
|
||||
mods_ = mod_to_save(score.mods)
|
||||
if "FL" not in mods_ or "HD" not in mods_ or "HT" not in mods_:
|
||||
return False
|
||||
if not beatmap.beatmapset.ranked_date or beatmap.beatmapset.ranked_date > datetime(
|
||||
2012, 1, 1
|
||||
):
|
||||
return False
|
||||
if beatmap.total_length < 180:
|
||||
return False
|
||||
fetcher = await get_fetcher()
|
||||
redis = get_redis()
|
||||
mods_ = score.mods.copy()
|
||||
attribute = await calculate_beatmap_attributes(
|
||||
beatmap.id, score.gamemode, mods_, redis, fetcher
|
||||
)
|
||||
return attribute.star_rating >= 4
|
||||
|
||||
|
||||
async def quick_maths(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# Get exactly 34 misses on any difficulty of Function Phantom - Variable.
|
||||
if score.nmiss != 34:
|
||||
return False
|
||||
return (
|
||||
beatmap.beatmapset.artist == "Function Phantom"
|
||||
and beatmap.beatmapset.title == "Variable"
|
||||
)
|
||||
|
||||
|
||||
async def kaleidoscope(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# Pass The Flashbulb - DIDJ PVC [EX III] with 80% accuracy or higher,
|
||||
# using the mods specified: EZ HT
|
||||
if not score.passed:
|
||||
return False
|
||||
mods_ = mod_to_save(score.mods)
|
||||
if "EZ" not in mods_ or "HT" not in mods_:
|
||||
return False
|
||||
return beatmap.id == 2022237 and score.accuracy >= 0.8
|
||||
|
||||
|
||||
async def valediction(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# Pass a_hisa - Alexithymia | Lupinus | Tokei no Heya to Seishin Sekai
|
||||
# with 90% accuracy or higher.
|
||||
return (
|
||||
score.passed
|
||||
and beatmap.beatmapset.artist == "a_hisa"
|
||||
and beatmap.beatmapset.title
|
||||
== "Alexithymia | Lupinus | Tokei no Heya to Seishin Sekai"
|
||||
and score.accuracy >= 0.9
|
||||
)
|
||||
|
||||
|
||||
async def right_on_time(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# Submit a score on Kola Kid - timer on the first minute of any hour
|
||||
if not score.passed:
|
||||
return False
|
||||
if not (
|
||||
beatmap.beatmapset.artist == "Kola Kid" and beatmap.beatmapset.title == "timer"
|
||||
):
|
||||
return False
|
||||
return score.ended_at.minute == 0
|
||||
|
||||
|
||||
async def not_again(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# Pass ARForest - Regret. with 1x Miss and 99%+ accuracy
|
||||
if not score.passed:
|
||||
return False
|
||||
if score.nmiss != 1:
|
||||
return False
|
||||
if score.accuracy < 0.99:
|
||||
return False
|
||||
return (
|
||||
beatmap.beatmapset.artist == "ARForest" and beatmap.beatmapset.title == "Regret"
|
||||
)
|
||||
|
||||
|
||||
async def deliberation(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# PFC any ranked or loved map, with HT, that is 6+ stars after mods
|
||||
if score.rank != Rank.X and score.rank != Rank.XH:
|
||||
return False
|
||||
mods_ = mod_to_save(score.mods)
|
||||
if "HT" not in mods_:
|
||||
return False
|
||||
if (
|
||||
not beatmap.beatmap_status.has_pp()
|
||||
or beatmap.beatmap_status != BeatmapRankStatus.LOVED
|
||||
):
|
||||
return False
|
||||
|
||||
fetcher = await get_fetcher()
|
||||
redis = get_redis()
|
||||
mods_copy = score.mods.copy()
|
||||
attribute = await calculate_beatmap_attributes(
|
||||
beatmap.id, score.gamemode, mods_copy, redis, fetcher
|
||||
)
|
||||
return attribute.star_rating >= 6
|
||||
|
||||
|
||||
async def clarity(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# Pass rrtyui's mapset of Camellia vs Akira Complex - Reality Distortion
|
||||
if not score.passed:
|
||||
return False
|
||||
return beatmap.beatmapset.id == 582089
|
||||
|
||||
|
||||
async def autocreation(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# Pass any map where the artist and the host of the mapset are the same person
|
||||
if not score.passed:
|
||||
return False
|
||||
return beatmap.beatmapset.creator == beatmap.beatmapset.artist
|
||||
|
||||
|
||||
async def value_your_identity(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# Achieve a score where max combo equals the last 3 digits of User ID
|
||||
if not score.passed:
|
||||
return False
|
||||
user_id = score.user_id
|
||||
last_3_digits = user_id % 1000
|
||||
if last_3_digits == 0:
|
||||
last_3_digits = 1000
|
||||
return score.max_combo == last_3_digits
|
||||
|
||||
|
||||
async def by_the_skin_of_the_teeth(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# Set a play using Accuracy Challenge that is exactly the accuracy specified
|
||||
if not score.passed:
|
||||
return False
|
||||
|
||||
mods_ = mod_to_save(score.mods)
|
||||
if "AC" not in mods_:
|
||||
return False
|
||||
|
||||
for mod in score.mods:
|
||||
if mod.get("acronym") == "AC":
|
||||
if "settings" in mod and "minimum_accuracy" in mod["settings"]:
|
||||
target_accuracy = mod["settings"]["minimum_accuracy"]
|
||||
if isinstance(target_accuracy, int | float):
|
||||
return abs(score.accuracy - float(target_accuracy)) < 0.0001
|
||||
return False
|
||||
|
||||
|
||||
async def meticulous_mayhem(
|
||||
session: AsyncSession,
|
||||
score: Score,
|
||||
beatmap: Beatmap,
|
||||
) -> bool:
|
||||
# Pass any map with 15 or more mods enabled
|
||||
if not score.passed:
|
||||
return False
|
||||
return len(score.mods) >= 15
|
||||
|
||||
|
||||
# TODO: Quick Draw, Obsessed, Jack of All Trades, Ten To One, Persistence Is Key
|
||||
# Tribulation, Replica, All Good, Time Sink, You're Here Forever, Hospitality,
|
||||
# True North, Superfan, Resurgence, Festive Fever, Deciduous Arborist,
|
||||
# Infectious Enthusiasm, Exquisite, Mad Scientist
|
||||
MEDALS: Medals = {
|
||||
Achievement(
|
||||
id=105,
|
||||
name="Jackpot",
|
||||
desc="Lucky sevens is a mild understatement.",
|
||||
assets_id="all-secret-jackpot",
|
||||
): jackpot,
|
||||
Achievement(
|
||||
id=106,
|
||||
name="Nonstop",
|
||||
desc="Breaks? What are those?",
|
||||
assets_id="all-secret-nonstop",
|
||||
): nonstop,
|
||||
Achievement(
|
||||
id=107,
|
||||
name="Time Dilation",
|
||||
desc="Longer is shorter when all is said and done.",
|
||||
assets_id="all-secret-tidi",
|
||||
): time_dilation,
|
||||
Achievement(
|
||||
id=108,
|
||||
name="To The Core",
|
||||
desc="In for a penny, in for a pound. Pounding bass, that is.",
|
||||
assets_id="all-secret-tothecore",
|
||||
): to_the_core,
|
||||
Achievement(
|
||||
id=109,
|
||||
name="When You See It",
|
||||
desc="Three numbers which will haunt you forevermore.",
|
||||
assets_id="all-secret-when-you-see-it",
|
||||
): wysi,
|
||||
Achievement(
|
||||
id=110,
|
||||
name="Prepared",
|
||||
desc="Do it for real next time.",
|
||||
assets_id="all-secret-prepared",
|
||||
): prepared,
|
||||
Achievement(
|
||||
id=111,
|
||||
name="Reckless Abandon",
|
||||
desc="Throw it all to the wind.",
|
||||
assets_id="all-secret-reckless",
|
||||
): reckless_adandon,
|
||||
Achievement(
|
||||
id=112,
|
||||
name="Lights Out",
|
||||
desc="The party's just getting started.",
|
||||
assets_id="all-secret-lightsout",
|
||||
): lights_out,
|
||||
Achievement(
|
||||
id=113,
|
||||
name="Camera Shy",
|
||||
desc="Stop being cute.",
|
||||
assets_id="all-secret-uguushy",
|
||||
): camera_shy,
|
||||
Achievement(
|
||||
id=114,
|
||||
name="The Sun of All Fears",
|
||||
desc="Unfortunate.",
|
||||
assets_id="all-secret-nuked",
|
||||
): the_sun_of_all_fears,
|
||||
Achievement(
|
||||
id=115,
|
||||
name="Hour Before The Down",
|
||||
desc="Eleven skies of everlasting sunrise.",
|
||||
assets_id="all-secret-hourbeforethedawn",
|
||||
): hour_before_the_down,
|
||||
Achievement(
|
||||
id=116,
|
||||
name="Slow And Steady",
|
||||
desc="Win the race, or start again.",
|
||||
assets_id="all-secret-slowandsteady",
|
||||
): slow_and_steady,
|
||||
Achievement(
|
||||
id=117,
|
||||
name="No Time To Spare",
|
||||
desc="Places to be, things to do.",
|
||||
assets_id="all-secret-ntts",
|
||||
): no_time_to_spare,
|
||||
Achievement(
|
||||
id=118,
|
||||
name="Sognare",
|
||||
desc="A dream in stop-motion, soon forever gone.",
|
||||
assets_id="all-secret-sognare",
|
||||
): sognare,
|
||||
Achievement(
|
||||
id=119,
|
||||
name="Realtor Extraordinaire",
|
||||
desc="An acre-wide stride.",
|
||||
assets_id="all-secret-realtor",
|
||||
): realtor_extraordinaire,
|
||||
Achievement(
|
||||
id=120,
|
||||
name="Impeccable",
|
||||
desc="Speed matters not to the exemplary.",
|
||||
assets_id="all-secret-impeccable",
|
||||
): impeccable,
|
||||
Achievement(
|
||||
id=121,
|
||||
name="Aeon",
|
||||
desc="In the mire of thawing time, memory shall be your guide.",
|
||||
assets_id="all-secret-aeon",
|
||||
): aeon,
|
||||
Achievement(
|
||||
id=122,
|
||||
name="Quick Maths",
|
||||
desc="Beats per minute over... this isn't quick at all!",
|
||||
assets_id="all-secret-quickmaffs",
|
||||
): quick_maths,
|
||||
Achievement(
|
||||
id=123,
|
||||
name="Kaleidoscope",
|
||||
desc="So many pretty colours. Most of them red.",
|
||||
assets_id="all-secret-kaleidoscope",
|
||||
): kaleidoscope,
|
||||
Achievement(
|
||||
id=124,
|
||||
name="Valediction",
|
||||
desc="One last time.",
|
||||
assets_id="all-secret-valediction",
|
||||
): valediction,
|
||||
# Achievement(
|
||||
# id=125,
|
||||
# name="Exquisite",
|
||||
# desc="Indubitably.",
|
||||
# assets_id="all-secret-exquisite",
|
||||
# ): exquisite,
|
||||
# Achievement(
|
||||
# id=126,
|
||||
# name="Mad Scientist",
|
||||
# desc="The experiment... it's all gone!",
|
||||
# assets_id="all-secret-madscientist",
|
||||
# ): mad_scientist,
|
||||
Achievement(
|
||||
id=127,
|
||||
name="Right On Time",
|
||||
desc="The first minute is always the hardest.",
|
||||
assets_id="all-secret-rightontime",
|
||||
): right_on_time,
|
||||
Achievement(
|
||||
id=128,
|
||||
name="Not Again",
|
||||
desc="Regret everything.",
|
||||
assets_id="all-secret-notagain",
|
||||
): not_again,
|
||||
Achievement(
|
||||
id=129,
|
||||
name="Deliberation",
|
||||
desc="The challenge remains.",
|
||||
assets_id="all-secret-deliberation",
|
||||
): deliberation,
|
||||
Achievement(
|
||||
id=130,
|
||||
name="Clarity",
|
||||
desc="And yet in our memories, you remain crystal clear.",
|
||||
assets_id="all-secret-clarity",
|
||||
): clarity,
|
||||
Achievement(
|
||||
id=131,
|
||||
name="Autocreation",
|
||||
desc="Absolute rule.",
|
||||
assets_id="all-secret-autocreation",
|
||||
): autocreation,
|
||||
Achievement(
|
||||
id=132,
|
||||
name="Value Your Identity",
|
||||
desc="As perfect as you are.",
|
||||
assets_id="all-secret-identity",
|
||||
): value_your_identity,
|
||||
Achievement(
|
||||
id=133,
|
||||
name="By The Skin Of The Teeth",
|
||||
desc="You're that accurate.",
|
||||
assets_id="all-secret-skinoftheteeth",
|
||||
): by_the_skin_of_the_teeth,
|
||||
Achievement(
|
||||
id=134,
|
||||
name="Meticulous Mayhem",
|
||||
desc="How did we get here?",
|
||||
assets_id="all-secret-meticulousmayhem",
|
||||
): meticulous_mayhem,
|
||||
}
|
||||
Reference in New Issue
Block a user