diff --git a/message_bus.py b/message_bus.py
new file mode 100644
index 00000000..f393ec4d
--- /dev/null
+++ b/message_bus.py
@@ -0,0 +1,54 @@
+from enum import StrEnum
+
+from ansi_tags import ansiprint
+
+
+class Message(StrEnum):
+ # These are just some basic events to start off with. I will add more as I go along.
+ START_OF_COMBAT = 'start_of_combat'
+ END_OF_COMBAT = 'end_of_combat'
+ START_OF_TURN = 'start_of_turn'
+ END_OF_TURN = 'end_of_turn'
+
+class MessageBus:
+ '''
+ This is a Pub/Sub, or Publish/Subscribe, message bus. It allows components to subscribe to messages,
+ registering a callback function that will be called when that message is published.
+ '''
+ def __init__(self, debug=True):
+ self.subscribers = dict(dict()) # noqa: C408
+ self.debug = debug
+
+ def subscribe(self, event_type: Message, callback, uid):
+ if event_type not in self.subscribers:
+ self.subscribers[event_type] = {}
+ self.subscribers[event_type][uid] = callback
+ if self.debug:
+ ansiprint(f"MESSAGEBUS: {event_type} | Subscribed {callback.__qualname__}")
+
+ def unsubscribe(self, event_type, uid):
+ if self.debug:
+ ansiprint(f"MESSAGEBUS: Unsubscribed {self.subscribers[event_type][uid].__qualname__} from {', '.join(event_type).rstrip(', ')}")
+ del self.subscribers[event_type][uid]
+
+ def publish(self, event_type: Message, data):
+ if event_type in self.subscribers:
+ for _uid, callback in self.subscribers[event_type].items():
+ if self.debug:
+ ansiprint(f"MESSAGEBUS: {event_type} | Calling {callback.__qualname__}")
+ callback(event_type, data)
+ return data
+
+class Registerable():
+ '''Convenience class so I don't have to repeat the register function in every class that needs it.'''
+ registers = []
+ def register(self):
+ for message in self.registers:
+ bus.subscribe(message, self.callback, self.uid)
+
+ def unregister(self, event_types: list[Message]=None):
+ event_types = event_types if event_types else []
+ for message in self.registers:
+ bus.unsubscribe(message, self.uid)
+
+bus = MessageBus(debug=True)