Skip to content

Commit

Permalink
Add Event enum to help avoid mistakes
Browse files Browse the repository at this point in the history
  • Loading branch information
Typhi committed Nov 17, 2024
1 parent f7754cd commit 7397014
Show file tree
Hide file tree
Showing 5 changed files with 1,348 additions and 61 deletions.
126 changes: 65 additions & 61 deletions rs/ai/_example/handlers/event_handler.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from typing import List

from presentation_config import presentation_mode, p_delay, p_delay_s, slow_events
from rs.ai._example.config import CARD_REMOVAL_PRIORITY_LIST, DESIRED_CARDS_FOR_DECK
from rs.game.event import Event
from rs.game.screen_type import ScreenType
from rs.helper.logger import log_missing_event
from rs.machine.command import Command
Expand All @@ -22,25 +21,26 @@ def handle(self, state: GameState) -> HandlerAction:
return HandlerAction(commands=[p_delay, "choose 0", "wait 30"])
return HandlerAction(commands=["choose 0", "wait 30"])

if self.find_event_choice(state): # Otherwise figure out what to do below!
if find_event_choice(state): # Otherwise figure out what to do below!
if presentation_mode or slow_events:
return HandlerAction(commands=[p_delay, self.find_event_choice(state), p_delay_s])
return HandlerAction(commands=[self.find_event_choice(state), "wait 30"])
return HandlerAction(commands=[p_delay, find_event_choice(state), p_delay_s])
return HandlerAction(commands=[find_event_choice(state), "wait 30"])


def find_event_choice(self, state: GameState) -> str:
hp_per = state.get_player_health_percentage() * 100
event_name = state.game_state()['screen_state']['event_name']
def find_event_choice(state: GameState) -> str:
hp_per = state.get_player_health_percentage() * 100
event = state.get_event()

# ACT 1
match event:

if event_name == "Big Fish":
case Event.BIG_FISH:
if hp_per <= 30:
return "choose 0" # heal
if state.get_relic_counter("Omamori") >= 1:
return "choose 2" # relic and curse
return "choose 1" # max health up

if event_name == "The Cleric":
case Event.THE_CLERIC:
if hp_per <= 65 and 'heal' in state.get_choice_list():
return "choose heal"
if 'purify' in state.get_choice_list():
Expand All @@ -49,10 +49,10 @@ def find_event_choice(self, state: GameState) -> str:
return "choose leave" # Heal not worth the money and can't purify apparently
return "choose 0"

if event_name == "Dead Adventurer":
case Event.DEAD_ADVENTURER:
return "choose 1" # Escape. Could do: Add logic for sometimes taking the fight.

if event_name == "Golden Idol":
case Event.GOLDEN_IDOL:
if state.has_relic("Ectoplasm"):
return "choose 1" # Leave!
if len(state.get_choice_list()) == 2:
Expand All @@ -64,149 +64,152 @@ def find_event_choice(self, state: GameState) -> str:
return "choose 1" # 25% (35%) damage
return "choose 2" # max hp loss

if event_name == "Mushrooms":
case Event.HYPNOTIZING_MUSHROOMS:
if hp_per >= 40:
return "choose 0" # Get 'em!
return "choose 1" # Take the heal and curse

if event_name == "Living Wall":
case Event.LIVING_WALL:
return "choose 2" # Upgrade

if event_name == "Scrap Ooze":
case Event.SCRAP_OOZE:
return "choose 0" # Yolo. We'll probably get it after a few tries? If not, we don't deserve to live!!

if event_name == "Shining Light":
case Event.SHINING_LIGHT:
if hp_per >= 70:
return "choose 0" # Take the 2 random upgrades.
return "choose 1" # Leave.

if event_name == "The Ssssserpent":
case Event.THE_SSSSSERPENT:
if state.get_relic_counter("Omamori") >= 1 and not state.has_relic("Ectoplasm"):
return "choose 0" # Money in exchange for a curse
return "choose 1" # Leave

if event_name == "World of Goop":
case Event.WORLD_OF_GOOP:
if hp_per >= 80 and not state.has_relic("Ectoplasm"):
return "choose 0" # Take the money and lose a little HP.
return "choose 1" # Leave

if event_name == "Wing Statue":
case Event.WING_STATUE:
if hp_per >= 70:
return "choose 0" # Purge at cost of 7 HP
return "choose 1" # Money or leave

# ACT 1, 2

if event_name == "Face Trader":
case Event.FACE_TRADER:
if hp_per >= 75 and not state.has_relic("Ectoplasm"):
return "choose 0"
return "choose 2" # Leave.

# ACT 1, 2, 3

if event_name == "A Note For Yourself":
case Event.A_NOTE_FOR_YOURSELF:
return "choose 1" # Ignore.

if event_name == "Bonfire Spirits":
case Event.BONFIRE_SPIRITS:
return "choose 0" # Purge

if event_name == "The Divine Fountain":
case Event.THE_DIVINE_FOUNTAIN:
return "choose 0" # Remove curses!

if event_name == "Duplicator":
case Event.DUPLICATOR:
return "choose 1" # Needs some duplication logic, would be better, but for now leave.

if event_name == "Golden Shrine":
case Event.GOLDEN_SHRINE:
if state.get_relic_counter("Omamori") >= 1 and not state.has_relic("Ectoplasm"):
return "choose 1" # More free money!
return "choose 0" # Free money

if event_name == "Lab":
case Event.LAB:
return "choose 0" # Free potions

if event_name == "Match and Keep":
case Event.MATCH_AND_KEEP:
return "choose 0" # Just keep clicking

if event_name == "Ominous Forge":
case Event.OMINOUS_FORGE:
if state.get_relic_counter("Omamori") >= 1:
return "choose 1" # Warped tongs!
if state.floor() >= 30:
return "choose 0" # Might not be able to reasonably get rid of the curse anymore
return "choose 1" # I love the Warped Tongs relic.

if event_name == "Purifier":
case Event.PURIFIER:
return "choose 0" # Purge

if event_name == "Transmogrifier":
case Event.TRANSMOGRIFIER:
return "choose 1" # Ignore the transform since we don't know all cards (depending on character)

if event_name == "Upgrade Shrine":
case Event.UPGRADE_SHRINE:
return "choose 0" # Free upgrade

# if event_name == "We Meet Again!"
case Event.WE_MEET_AGAIN:
return "choose 0" # Todo

if event_name == "The Woman in Blue":
case Event.THE_WOMAN_IN_BLUE:
return "choose 0" # Grab 1 potion, or if we don't have enough money, leave.

# ACT 2

if event_name == "Ancient Writing":
case Event.ANCIENT_WRITING:
return "choose 1" # Upgrade all strikes and defends always because we currently can't tell the difference between card selection and purging in a grid event.

if event_name == "Augmenter":
case Event.AUGMENTER:
return "choose 2" # Take the Mutagenic Strength relic.

# if event_name == "The Colosseum"
case Event.THE_COLOSSEUM:
return "choose 0" # todo

if event_name == "Council of Ghosts":
case Event.COUNCIL_OF_GHOSTS:
if state.has_relic("Snecko Eye") or state.deck.contains_cards(["Bite"]): # Not amazing combos:
return "choose refuse"
return "choose accept" # Become a spooky ghost!

if event_name == "Cursed Tome":
case Event.CURSED_TOME:
return "choose 1" # Leave, we don't currently make good use of the possible relics.

# if event_name == "Forgotten Altar"
case Event.FORGOTTEN_ALTAR:
return "choose 0" # todo

if event_name == "The Joust":
case Event.THE_JOUST:
return "choose 0" # Be conservative

if event_name == "Knowing Skull":
case Event.KNOWING_SKULL:
return "choose 3" # Leave

if event_name == "The Library":
case Event.THE_LIBRARY:
return "choose sleep" # Heal, because we currently can't tell the difference between card selection and purging in a grid event.

if event_name == "Masked Bandits":
case Event.MASKED_BANDITS:
if hp_per >= 65:
return "choose 1" # Get 'em!
return "choose 0" # Give up all money and leave.

if event_name == "The Mausoleum":
case Event.THE_MAUSOLEUM:
if state.get_relic_counter("Omamori") >= 1:
return "choose 0"
return "choose 1" # Leave, we don't like curses.

if event_name == "The Nest":
case Event.THE_NEST:
if hp_per >= 50:
return "choose 1" # Ritual Dagger and a little damage.
return "choose 0" # Free money

if event_name == "N'loth":
case Event.NLOTH:
return "choose 2" # Leave, hard to statically make a good choice here.

if event_name == "Old Beggar":
case Event.OLD_BEGGAR:
return "choose 0" # Cheap purge.

if event_name == "Pleading Vagrant":
case Event.PLEADING_VAGRANT:
if state.get_relic_counter("Omamori") >= 1:
return "choose rob" # Get curse and relic
elif "offer gold" in state.get_choice_list():
return "choose offer gold" # 85 gold for random relic
else:
return "choose leave"

if event_name == "Vampires(?)":
case Event.VAMPIRES:
if state.deck.contains_cards(["Apparition"]):
return "choose refuse"
if state.has_relic("Strike Dummy"):
Expand All @@ -220,12 +223,12 @@ def find_event_choice(self, state: GameState) -> str:

# Act 2, 3

if event_name == "Designer In-Spire":
case Event.DESIGNER_IN_SPIRE:
return "choose 0" # It'll do reasonable things like upgrading and removing.

# Act 3

if event_name == "Falling":
case Event.FALLING:
options = state.get_falling_event_options()

# check for stuff we want to purge
Expand All @@ -250,36 +253,37 @@ def find_event_choice(self, state: GameState) -> str:
if card == least_desired:
return "choose " + str(idx)

if event_name == "Mind Bloom":
case Event.MIND_BLOOM:
return "choose 0" # Fight an Act 1 boss for a relic.

if event_name == "The Moai Head":
case Event.MIND_BLOOM:
return "choose 1" # Get a bunch of money or leave

if event_name == "Mysterious Sphere":
case Event.MYSTERIOUS_SPHERE:
if hp_per >= 70:
return "choose 0" # Get 'em!
else:
return "choose 1" # Leave

if event_name == "Secret Portal":
case Event.SECRET_PORTAL:
return "choose 1" # Nope - we want the rest of Act 3 to not screw up our stats.

if event_name == "Sensory Stone":
case Event.SENSORY_STONE:
return "choose 0" # Get a free colorless obtain

if event_name == "Tomb of Lord Red Mask":
case Event.TOMB_OF_LORD_RED_MASK:
if state.has_relic("Red Mask") or state.game_state()['gold'] <= 130:
return "choose 0" # Either free money or cheap.
else:
return "choose 1" # Leave

if event_name == "Winding Halls":
case Event.WINDING_HALLS:
if state.get_relic_counter("Omamori") >= 1 and hp_per < 75:
return "choose 1" # Take the curse and heal
if hp_per <= 10:
return "choose 1" # Take the curse and heal
return "choose 2" # Lose Max HP

log_missing_event(event_name)
return "choose 0"
case _:
log_missing_event(str(event))
return "choose 0"
58 changes: 58 additions & 0 deletions rs/game/event.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from enum import Enum


class Event(Enum):
UNKNOWN = "unknown"

ANCIENT_WRITING = "Ancient Writing"
AUGMENTER = "Augmenter"
A_NOTE_FOR_YOURSELF = "A Note For Yourself"
BIG_FISH = "Big Fish"
BONFIRE_SPIRITS = "Bonfire Spirits"
COUNCIL_OF_GHOSTS = "Council of Ghosts"
CURSED_TOME = "Cursed Tome"
DEAD_ADVENTURER = "Dead Adventurer"
DESIGNER_IN_SPIRE = "Designer In-Spire"
DUPLICATOR = "Duplicator"
FACE_TRADER = "Face Trader"
FALLING = "Falling"
FORGOTTEN_ALTAR = "Forgotten Altar"
GOLDEN_IDOL = "Golden Idol"
GOLDEN_SHRINE = "Golden Shrine"
HYPNOTIZING_MUSHROOMS = "Mushrooms" # Adding 'hypnotizing' because that word is included on the wiki
KNOWING_SKULL = "Knowing Skull"
LAB = "Lab"
LIVING_WALL = "Living Wall"
MASKED_BANDITS = "Masked Bandits"
MATCH_AND_KEEP = "Match and Keep"
MIND_BLOOM = "Mind Bloom"
MYSTERIOUS_SPHERE = "Mysterious Sphere"
NLOTH = "N'loth"
OLD_BEGGAR = "Old Beggar"
OMINOUS_FORGE = "Ominous Forge"
PLEADING_VAGRANT = "Pleading Vagrant"
PURIFIER = "Purifier"
SCRAP_OOZE = "Scrap Ooze"
SECRET_PORTAL = "Secret Portal"
SENSORY_STONE = "Sensory Stone"
SHINING_LIGHT = "Shining Light"
THE_CLERIC = "The Cleric"
THE_COLOSSEUM = "The Colosseum"
THE_DIVINE_FOUNTAIN = "The Divine Fountain"
THE_JOUST = "The Joust"
THE_LIBRARY = "The Library"
THE_MAUSOLEUM = "The Mausoleum"
THE_MOAI_HEAD = "The Moai Head"
THE_NEST = "The Nest"
THE_SSSSSERPENT = "The Ssssserpent"
THE_WOMAN_IN_BLUE = "The Woman in Blue"
TOMB_OF_LORD_RED_MASK = "Tomb of Lord Red Mask"
TRANSMOGRIFIER = "Transmogrifier"
UPGRADE_SHRINE = "Upgrade Shrine"
VAMPIRES = "Vampires(?)"
WE_MEET_AGAIN = "We Meet Again!"
WHEEL_OF_CHANGE = "Wheel of Change"
WINDING_HALLS = "Winding Halls"
WING_STATUE = "Wing Statue"
WORLD_OF_GOOP = "World of Goop"

9 changes: 9 additions & 0 deletions rs/machine/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from rs.calculator.interfaces.memory_items import MemoryItem
from rs.game.deck import Deck
from rs.game.event import Event
from rs.machine.command import Command
from rs.machine.orb import Orb
from rs.machine.the_bots_memory_book import TheBotsMemoryBook
Expand Down Expand Up @@ -200,3 +201,11 @@ def extract_card_from_text(text):
for idx, choice in enumerate(options):
options[idx] = choice.replace("+", "")
return options

def get_event(self) -> Event:
event_name = self.game_state()['screen_state']['event_name']
possible_events = set(item.value for item in Event)

if event_name not in possible_events:
return event_name
return Event(event_name)
Loading

0 comments on commit 7397014

Please sign in to comment.