vesper-arch / Slay-the-Spire-in-Python

A text based version of Slay the Spire coded in python. Credit to slaythetext for some really early systems I used.
https://docs.google.com/document/d/1j7c3oHXeQjjF6yyuY0tOMaZeMlAHPokfzw99Azpe6fk/edit?usp=sharing
2 stars 4 forks source link

Use message bus engine system. #49

Open vesper-arch opened 8 months ago

vesper-arch commented 8 months ago

Currently being worked on on branch message_bus_engine. I am using the existing example of the engine as a reference. I am going to go insane, it took me like 2 hours just to make the common cards.

vesper-arch commented 8 months ago

@miketwo Would it be fine to make some cards register from messages? Not sure what that would do.

miketwo commented 8 months ago

Not sure what you mean. Probably fine, if you're thinking about something like "beginning of combat" messages causing the player to register cards.

vesper-arch commented 8 months ago

Like with the card Sentinel, it has a passive effect where it gives the player energy when it's Exhausted. Lots of other cards that I havent got to use passive effects like these such as Curses and Statuses. I could have these cards subscribe to certain messages and check if the card is in the player's hand in the callback function to do whatever its supposed to do. Edit: I meant to type 'for' in my previous message.

miketwo commented 8 months ago

Yeah, that's the way to do it. Subscribe to something like a "Card Exhausted" event that fires whenever any card is exhausted. Then inside the Sentinel object, check conditions for activation, and if they pass, modify the player's energy. Ditto for curses and other things.

The goal is that all the logic associated with a card is in one spot (the card object) -- so that the game engine doesn't need to be modified with each new card / relic / potion. The hard part is going to be cards that stack or interact with each other. (You may need a hidden "coordinator" object.)

vesper-arch commented 8 months ago

Update: A breaker tripped and deleted all of my changes on the devcontainer. fuck

miketwo commented 8 months ago

Damn, that sucks.

Commit and push often, my dude. Commits protect against power outtages and pushes protect against your computer getting destroyed/stolen.

vesper-arch commented 8 months ago

at least I can get make it again faster now that I know how to make it faster.

vesper-arch commented 8 months ago

probably better too

vesper-arch commented 8 months ago

How would I make it to where the player takes advantage of the message bus without causing an infinite loop? image As you can see, this would cause the player's callback function to be recursively called. Is there a way I can somehow exclude the player(or any object for that matter) from the start of combat publish?

miketwo commented 8 months ago

Why is the player publishing a message about something they're not responsible for, like when combat starts and stops?

Only publish about things you control. The player can publish about being created, gaining health, taking damage, etc. But there should be a Game or Combat object that's responsible for the flow of combat, and it decides when turns/rounds/combat start and stop.

If you're doing it right, it should be easy to swap out the enemies for a second player and make it a PvP game, or swap the player for an enemy and watch the computer play itself, because characters should not have any responsibility for the combat loop.

vesper-arch commented 8 months ago

Fair point. This is rough for me. How should the Combat class be done? So far I've just migrated the combat functions to a class but nothing else is changed and I don't know what I can do different.

miketwo commented 8 months ago

Have the Combat take in players and enemies and keep track of them, instead of global variables like player and active_enemies. (See if you can create a working combat in a test_combat.py file -- if you can make an isolated one, now you've got a mechanism for testing out different combat scenarios.)

vesper-arch commented 8 months ago

How does __init__ work as opposed to this(in example_message_bus.py)?:

class Combat():
    player: Character
    enemy: Character
    bus: MessageBus
    turn: int = 1

Is it a one time init or is it an instance sort of deal?

miketwo commented 8 months ago

It's per instance - it sets up init for you. But to use that style you have to use the @dataclass decorator. It sets up a bunch of stuff automatically. But it's more meant for classes that have few/no methods. If you've got a bunch of methods, a regular __init__ is probably better.

vesper-arch commented 5 months ago

@miketwo Update: I will be reverting to when I added the item classes because I realize there is a lot of stuff that I was going to do that was not really related to the goal of using a message bus such as removing globals. Those were changes that I made along the way but I didn't need.

vesper-arch commented 2 months ago

@miketwo I am going to go back to the original message_bus branch. I'll merge it and then continue updating it but in smaller sized pull requests. Having to rewrite something i already did is obnoxious and incredibly uninteresting and makes me not want to work on anything

vesper-arch commented 2 months ago

even if the implementation isn't ideal, I'd rather continue working it than try and optimize it by reverting a bunch