Skip to content

Commit

Permalink
awards: add new awards
Browse files Browse the repository at this point in the history
  • Loading branch information
rr- committed Sep 8, 2023
1 parent 428b42c commit d934d93
Show file tree
Hide file tree
Showing 38 changed files with 827 additions and 8 deletions.
72 changes: 65 additions & 7 deletions backend/trcustoms/awards/requirements/impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,26 @@ def check_eligible(self, user: User) -> bool:
)


class AuthoredLevelsFarApartRequirement(BaseAwardRequirement):
def __init__(self, min_time_apart: timedelta) -> None:
self.min_time_apart = min_time_apart

def check_eligible(self, user: User) -> bool:
# User has released two approved levels that are more than
# min_time_apart
good_level_creation_times = sorted(
user.authored_levels.filter(
is_approved=True,
).values_list("created", flat=True)
)
return any(
time2 - time1 >= self.min_time_apart
for time1, time2 in zip(
good_level_creation_times, good_level_creation_times[1:]
)
)


class AuthoredWalkthroughsAwardRequirement(BaseAwardRequirement):
def __init__(
self,
Expand Down Expand Up @@ -207,17 +227,23 @@ def check_eligible(self, user: User) -> bool:


class AuthoredReviewsPositionAwardRequirement(BaseAwardRequirement):
def __init__(self, max_position: int, min_reviews: int) -> None:
def __init__(
self,
min_reviews: int,
min_position: int | None = None,
max_position: int | None = None,
) -> None:
self.min_position = min_position
self.max_position = max_position
self.min_reviews = min_reviews

def check_eligible(self, user: User) -> bool:
return (
user.reviewed_levels.filter(
position__lte=self.max_position
).count()
>= self.min_reviews
)
queryset = user.reviewed_levels
if self.min_position is not None:
queryset = queryset.filter(position__gte=self.min_position)
if self.max_position is not None:
queryset = queryset.filter(position__lte=self.max_position)
return queryset.count() >= self.min_reviews


class AuthoredReviewsSameBuilderAwardRequirement(BaseAwardRequirement):
Expand All @@ -231,3 +257,35 @@ def check_eligible(self, user: User) -> bool:
.filter(total__gte=self.min_reviews)
.exists()
)


class PlayedLevelsAwardRequirement(BaseAwardRequirement):
def __init__(self, min_levels: int) -> None:
self.min_levels = min_levels

def check_eligible(self, user: User) -> bool:
return user.playlist_items.finished().count() >= self.min_levels


class PlayedLevelsWithRatingAwardRequirement(BaseAwardRequirement):
def __init__(
self,
min_levels: int,
min_rating: int | None = None,
max_rating: int | None = None,
) -> None:
self.min_levels = min_levels
self.min_rating = min_rating
self.max_rating = max_rating

def check_eligible(self, user: User) -> bool:
queryset = user.playlist_items.played()
if self.max_rating is not None:
queryset = queryset.filter(
level__rating_class__position__lte=self.max_rating
)
if self.min_rating is not None:
queryset = queryset.filter(
level__rating_class__position__gte=self.min_rating
)
return queryset.count() >= self.min_levels
30 changes: 29 additions & 1 deletion backend/trcustoms/awards/specs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,23 @@
from .base import AwardSpec
from .bestiary import bestiary
from .bone_dust import bone_dust
from .chirugai import chirugai
from .demons_heart import demons_heart, spear_of_destiny
from .dragon_statue import dragon_statue
from .dual_pistols import dual_pistols
from .gate_key import gate_key
from .iris import iris
from .magic_stones import magic_stones
from .nightmare_stone import nightmare_stone
from .obscura_paintings import obscura_paintings
from .philosophers_stone import philosophers_stone
from .playlist_artefacts import playlist_artefacts
from .sanglyph import sanglyph
from .scion import scion
from .seraph import seraph
from .smugglers_key import smugglers_key
from .werners_broken_glasses import werners_broken_glasses
from .werners_notebook import werners_notebook

ALL_AWARD_SPECS = [
*dragon_statue(),
Expand All @@ -23,20 +32,39 @@
*werners_broken_glasses(),
*bone_dust(),
*sanglyph(),
*gate_key(),
*smugglers_key(),
*werners_notebook(),
*nightmare_stone(),
*magic_stones(),
*playlist_artefacts(),
*demons_heart(),
*spear_of_destiny(),
*chirugai(),
*obscura_paintings(),
]


__all__ = [
"amulet_of_horus",
"AwardSpec",
"amulet_of_horus",
"bestiary",
"bone_dust",
"chirugai",
"demons_heart",
"dragon_statue",
"dual_pistols",
"gate_key",
"iris",
"magic_stones",
"nightmare_stone",
"philosophers_stone",
"sanglyph",
"scion",
"seraph",
"smugglers_key",
"spear_of_destiny",
"werners_broken_glasses",
"werners_notebook",
"obscura_paintings",
]
20 changes: 20 additions & 0 deletions backend/trcustoms/awards/specs/chirugai.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from collections.abc import Iterable
from datetime import timedelta

from trcustoms.awards.requirements.impl import (
AuthoredLevelsFarApartRequirement,
)
from trcustoms.awards.specs import AwardSpec


def chirugai() -> Iterable[AwardSpec]:
min_time_apart = timedelta(days=10 * 365)

yield AwardSpec(
code="Chirugai",
title="Chirugai",
description="You have returned after years of inactivity.",
requirement=AuthoredLevelsFarApartRequirement(
min_time_apart=min_time_apart
),
)
38 changes: 38 additions & 0 deletions backend/trcustoms/awards/specs/demons_heart.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from collections.abc import Iterable

from trcustoms.awards.requirements.impl import (
PlayedLevelsWithRatingAwardRequirement,
)
from trcustoms.awards.specs.base import AwardSpec


def demons_heart() -> Iterable[AwardSpec]:
min_levels = 50

yield AwardSpec(
code="demons_heart",
title="Demon's Heart",
description=(
f"You finished {min_levels} levels with a negative rating."
),
requirement=PlayedLevelsWithRatingAwardRequirement(
min_levels=min_levels,
max_rating=-1,
),
)


def spear_of_destiny() -> Iterable[AwardSpec]:
min_levels = 50

yield AwardSpec(
code="spear_of_destiny",
title="Spear of Destiny",
description=(
f"You finished {min_levels} levels with a positive rating."
),
requirement=PlayedLevelsWithRatingAwardRequirement(
min_levels=min_levels,
min_rating=1,
),
)
23 changes: 23 additions & 0 deletions backend/trcustoms/awards/specs/gate_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from collections.abc import Iterable

from trcustoms.awards.requirements.impl import (
AuthoredLevelPlayersAwardRequirement,
)
from trcustoms.awards.specs.base import AwardSpec


def gate_key() -> Iterable[AwardSpec]:
min_players = 50

yield AwardSpec(
code="gate_key",
title="Gate Key",
description=(
f"{min_players} users have added one of your levels "
"to their playlist."
),
can_be_removed=True,
requirement=AuthoredLevelPlayersAwardRequirement(
min_players=min_players
),
)
24 changes: 24 additions & 0 deletions backend/trcustoms/awards/specs/magic_stones.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from collections.abc import Iterable

from django.conf import settings

from trcustoms.awards.requirements.impl import (
AuthoredLevelsTagCountRequirement,
)
from trcustoms.awards.specs.base import AwardSpec


def magic_stones() -> Iterable[AwardSpec]:
min_levels = 3
min_tags = settings.MAX_TAGS

yield AwardSpec(
code="magic_stones",
title="Magic Stones",
description="You topped up {min_levels} of your levels with tags!",
can_be_removed=True,
requirement=AuthoredLevelsTagCountRequirement(
min_levels=min_levels,
min_tags=min_tags,
),
)
24 changes: 24 additions & 0 deletions backend/trcustoms/awards/specs/nightmare_stone.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from collections.abc import Iterable

from trcustoms.awards.requirements.impl import (
AuthoredLevelsTagCountRequirement,
)
from trcustoms.awards.specs.base import AwardSpec


def nightmare_stone() -> Iterable[AwardSpec]:
min_levels = 3
min_tags = 1

yield AwardSpec(
code="nightmare_stone",
title="Nightmare Stone",
description=(
f"{min_levels} of your levels have " f"at least {min_tags} tag."
),
can_be_removed=True,
requirement=AuthoredLevelsTagCountRequirement(
min_levels=min_levels,
min_tags=min_tags,
),
)
33 changes: 33 additions & 0 deletions backend/trcustoms/awards/specs/obscura_paintings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from collections.abc import Iterable

from trcustoms.awards.requirements.impl import (
AuthoredReviewsPositionAwardRequirement,
)
from trcustoms.awards.specs import AwardSpec


def obscura_paintings() -> Iterable[AwardSpec]:
positions: list[tuple[int, int]] = [
(20, 1, 5, "First Obscura Painting"),
(20, 6, 10, "Second Obscura Painting"),
(20, 11, 15, "Thrid Obscura Painting"),
(20, 16, 20, "Fourth Obscura Painting"),
(20, 21, 25, "Fifth Obscura Painting"),
]

for tier, (min_reviews, min_position, max_position, title) in enumerate(
positions, 1
):
yield AwardSpec(
code=f"obscura_painting_{tier}",
title=title,
description=(
f"You reviewed {min_reviews} levels with a review amount "
f"between {min_position} and {max_position}!"
),
requirement=AuthoredReviewsPositionAwardRequirement(
min_reviews=min_reviews,
min_position=min_position,
max_position=max_position,
),
)
30 changes: 30 additions & 0 deletions backend/trcustoms/awards/specs/playlist_artefacts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from collections.abc import Iterable

from trcustoms.awards.requirements.impl import PlayedLevelsAwardRequirement
from trcustoms.awards.specs.base import AwardSpec


def playlist_artefacts() -> Iterable[AwardSpec]:
yield AwardSpec(
code="wraith_stone",
title="Wraith Stone",
description="You completed 20 levels in your playlist.",
requirement=PlayedLevelsAwardRequirement(min_levels=20),
can_be_removed=True,
)

yield AwardSpec(
code="excalibur",
title="Excalibur",
description="You completed 100 levels in your playlist.",
requirement=PlayedLevelsAwardRequirement(min_levels=100),
can_be_removed=True,
)

yield AwardSpec(
code="mjolnir",
title="Mjölnir",
description="You completed 250 levels in your playlist.",
requirement=PlayedLevelsAwardRequirement(min_levels=250),
can_be_removed=True,
)
25 changes: 25 additions & 0 deletions backend/trcustoms/awards/specs/smugglers_key.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from collections.abc import Iterable
from datetime import timedelta

from trcustoms.awards.requirements.impl import (
AuthoredReviewsTimingAwardRequirement,
)
from trcustoms.awards.specs.base import AwardSpec


def smugglers_key() -> Iterable[AwardSpec]:
min_levels = 50
max_review_age = timedelta(hours=24)

yield AwardSpec(
code="smugglers_key",
title="Smuggler's Key",
description=(
f"You reviewed {min_levels} levels on the same "
"or next day of release."
),
requirement=AuthoredReviewsTimingAwardRequirement(
min_levels=min_levels,
max_review_age=max_review_age,
),
)
Loading

0 comments on commit d934d93

Please sign in to comment.