diff --git a/__pycache__/monop_parser.cpython-310.pyc b/__pycache__/monop_parser.cpython-310.pyc index ee65d83..15a3eee 100644 Binary files a/__pycache__/monop_parser.cpython-310.pyc and b/__pycache__/monop_parser.cpython-310.pyc differ diff --git a/__pycache__/monop_players.cpython-310.pyc b/__pycache__/monop_players.cpython-310.pyc index 1933d65..f47e279 100644 Binary files a/__pycache__/monop_players.cpython-310.pyc and b/__pycache__/monop_players.cpython-310.pyc differ diff --git a/monop_bridge.py b/monop_bridge.py index 10a8085..58fa8c4 100644 --- a/monop_bridge.py +++ b/monop_bridge.py @@ -108,34 +108,38 @@ class IRCBridge: print(f"[bridge] {m.group(1)} joined — starting game") return + def _process_buffer(self): + """Process any complete lines in the buffer.""" + while "\r\n" in self.buffer: + line, self.buffer = self.buffer.split("\r\n", 1) + if line.startswith("PING"): + self.irc_send("PONG" + line[4:]) + continue + m = re.match(r":(\S+?)!(\S+?) PRIVMSG (\S+) :(.+)", line) + if m: + sender_nick = m.group(1) + target = m.group(3) + msg = m.group(4) + if target == CHANNEL and sender_nick != NICK: + if msg.startswith(PREFIX): + cmd = msg[len(PREFIX):] + self._feed_monop(sender_nick, cmd) + def run(self): self.connect_irc() self._wait_for_players() self.start_monop() + # Process any lines buffered during _wait_for_players + self._process_buffer() + while True: try: data = self.sock.recv(4096) if not data: break self.buffer += data.decode("utf-8", errors="replace") - while "\r\n" in self.buffer: - line, self.buffer = self.buffer.split("\r\n", 1) - if line.startswith("PING"): - self.irc_send("PONG" + line[4:]) - continue - # Parse PRIVMSG - m = re.match( - r":(\S+?)!(\S+?) PRIVMSG (\S+) :(.+)", line - ) - if m: - sender_nick = m.group(1) - target = m.group(3) - msg = m.group(4) - if target == CHANNEL and sender_nick != NICK: - if msg.startswith(PREFIX): - cmd = msg[len(PREFIX):] - self._feed_monop(sender_nick, cmd) + self._process_buffer() except Exception as e: print(f"[bridge] error: {e}") break diff --git a/monop_parser.py b/monop_parser.py index 9a610fe..a6a9f1e 100644 --- a/monop_parser.py +++ b/monop_parser.py @@ -257,6 +257,17 @@ class MonopParser: g.add_log(f"Game for {count} players", timestamp=timestamp) return + # Name registration — user sends their IRC nick as their name. + # In monop-irc, the bridge sends "nick name" to monop stdin, + # so the player name matches the IRC sender. + name = msg.strip() + if name and not name.isdigit() and name == sender: + for p in g.players: + if p.name.startswith("Player "): + p.name = name + g.add_log(f"{name} joined!", player=name, timestamp=timestamp) + return + def parse_line(self, line): """Parse a single IRC log line. Returns any events generated.""" self.line_num += 1 diff --git a/monop_players.py b/monop_players.py index 2de5acc..7a21512 100644 --- a/monop_players.py +++ b/monop_players.py @@ -117,6 +117,11 @@ class PlayerBot: time.sleep(1.0) self.log("Sending player count (in case we missed the prompt)") self.say(str(self.num_players)) + else: + # Send our name proactively in case we missed the "say me" prompt + time.sleep(1.0) + self.log(f"Sending name (in case we missed the prompt)") + self.say(self.nick) def _send(self, line): with self.lock: diff --git a/plugins/monop/monop_parser.py b/plugins/monop/monop_parser.py index 9a610fe..a6a9f1e 100644 --- a/plugins/monop/monop_parser.py +++ b/plugins/monop/monop_parser.py @@ -257,6 +257,17 @@ class MonopParser: g.add_log(f"Game for {count} players", timestamp=timestamp) return + # Name registration — user sends their IRC nick as their name. + # In monop-irc, the bridge sends "nick name" to monop stdin, + # so the player name matches the IRC sender. + name = msg.strip() + if name and not name.isdigit() and name == sender: + for p in g.players: + if p.name.startswith("Player "): + p.name = name + g.add_log(f"{name} joined!", player=name, timestamp=timestamp) + return + def parse_line(self, line): """Parse a single IRC log line. Returns any events generated.""" self.line_num += 1 diff --git a/site/game-state.json b/site/game-state.json index ad1321a..4fab5e2 100644 --- a/site/game-state.json +++ b/site/game-state.json @@ -1,27 +1,37 @@ { "players": [ { - "name": "Player 1", + "name": "alice", "number": 1, - "money": 1500, - "location": 0, + "money": 1190, + "location": 40, + "inJail": true, + "jailTurns": 1, + "doublesCount": 0, + "getOutOfJailFreeCards": 0 + }, + { + "name": "bob", + "number": 2, + "money": 1300, + "location": 11, "inJail": false, "jailTurns": 0, "doublesCount": 0, "getOutOfJailFreeCards": 0 }, { - "name": "Player 2", - "number": 2, - "money": 1500, - "location": 0, + "name": "charlie", + "number": 3, + "money": 1400, + "location": 8, "inJail": false, "jailTurns": 0, "doublesCount": 0, "getOutOfJailFreeCards": 0 } ], - "currentPlayer": null, + "currentPlayer": 3, "squares": [ { "id": 0, @@ -31,7 +41,12 @@ { "id": 1, "name": "Mediterranean ave. (P)", - "type": "property" + "type": "property", + "owner": null, + "mortgaged": false, + "group": "purple", + "cost": 60, + "houses": 0 }, { "id": 2, @@ -41,7 +56,12 @@ { "id": 3, "name": "Baltic ave. (P)", - "type": "property" + "type": "property", + "owner": 2, + "mortgaged": false, + "group": "purple", + "cost": 60, + "houses": 0 }, { "id": 4, @@ -51,12 +71,21 @@ { "id": 5, "name": "Reading RR", - "type": "railroad" + "type": "railroad", + "owner": null, + "mortgaged": false, + "group": "railroad", + "cost": 200 }, { "id": 6, "name": "Oriental ave. (L)", - "type": "property" + "type": "property", + "owner": null, + "mortgaged": false, + "group": "lightblue", + "cost": 100, + "houses": 0 }, { "id": 7, @@ -66,12 +95,22 @@ { "id": 8, "name": "Vermont ave. (L)", - "type": "property" + "type": "property", + "owner": 3, + "mortgaged": false, + "group": "lightblue", + "cost": 100, + "houses": 0 }, { "id": 9, "name": "Connecticut ave. (L)", - "type": "property" + "type": "property", + "owner": null, + "mortgaged": false, + "group": "lightblue", + "cost": 120, + "houses": 0 }, { "id": 10, @@ -81,32 +120,60 @@ { "id": 11, "name": "St. Charles pl. (V)", - "type": "property" + "type": "property", + "owner": 2, + "mortgaged": false, + "group": "violet", + "cost": 140, + "houses": 0 }, { "id": 12, "name": "Electric Co.", - "type": "utility" + "type": "utility", + "owner": null, + "mortgaged": false, + "group": "utility", + "cost": 150 }, { "id": 13, "name": "States ave. (V)", - "type": "property" + "type": "property", + "owner": null, + "mortgaged": false, + "group": "violet", + "cost": 140, + "houses": 0 }, { "id": 14, "name": "Virginia ave. (V)", - "type": "property" + "type": "property", + "owner": 1, + "mortgaged": false, + "group": "violet", + "cost": 160, + "houses": 0 }, { "id": 15, "name": "Pennsylvania RR", - "type": "railroad" + "type": "railroad", + "owner": null, + "mortgaged": false, + "group": "railroad", + "cost": 200 }, { "id": 16, "name": "St. James pl. (O)", - "type": "property" + "type": "property", + "owner": null, + "mortgaged": false, + "group": "orange", + "cost": 180, + "houses": 0 }, { "id": 17, @@ -116,12 +183,22 @@ { "id": 18, "name": "Tennessee ave. (O)", - "type": "property" + "type": "property", + "owner": null, + "mortgaged": false, + "group": "orange", + "cost": 180, + "houses": 0 }, { "id": 19, "name": "New York ave. (O)", - "type": "property" + "type": "property", + "owner": null, + "mortgaged": false, + "group": "orange", + "cost": 200, + "houses": 0 }, { "id": 20, @@ -131,7 +208,12 @@ { "id": 21, "name": "Kentucky ave. (R)", - "type": "property" + "type": "property", + "owner": null, + "mortgaged": false, + "group": "red", + "cost": 220, + "houses": 0 }, { "id": 22, @@ -141,37 +223,70 @@ { "id": 23, "name": "Indiana ave. (R)", - "type": "property" + "type": "property", + "owner": null, + "mortgaged": false, + "group": "red", + "cost": 220, + "houses": 0 }, { "id": 24, "name": "Illinois ave. (R)", - "type": "property" + "type": "property", + "owner": null, + "mortgaged": false, + "group": "red", + "cost": 240, + "houses": 0 }, { "id": 25, "name": "B&O RR", - "type": "railroad" + "type": "railroad", + "owner": null, + "mortgaged": false, + "group": "railroad", + "cost": 200 }, { "id": 26, "name": "Atlantic ave. (Y)", - "type": "property" + "type": "property", + "owner": null, + "mortgaged": false, + "group": "yellow", + "cost": 260, + "houses": 0 }, { "id": 27, "name": "Ventnor ave. (Y)", - "type": "property" + "type": "property", + "owner": null, + "mortgaged": false, + "group": "yellow", + "cost": 260, + "houses": 0 }, { "id": 28, "name": "Water Works", - "type": "utility" + "type": "utility", + "owner": null, + "mortgaged": false, + "group": "utility", + "cost": 150 }, { "id": 29, "name": "Marvin Gardens (Y)", - "type": "property" + "type": "property", + "owner": null, + "mortgaged": false, + "group": "yellow", + "cost": 280, + "houses": 0 }, { "id": 30, @@ -181,12 +296,22 @@ { "id": 31, "name": "Pacific ave. (G)", - "type": "property" + "type": "property", + "owner": null, + "mortgaged": false, + "group": "green", + "cost": 300, + "houses": 0 }, { "id": 32, "name": "N. Carolina ave. (G)", - "type": "property" + "type": "property", + "owner": null, + "mortgaged": false, + "group": "green", + "cost": 300, + "houses": 0 }, { "id": 33, @@ -196,12 +321,21 @@ { "id": 34, "name": "Pennsylvania ave. (G)", - "type": "property" + "type": "property", + "owner": null, + "mortgaged": false, + "group": "green", + "cost": 320, + "houses": 0 }, { "id": 35, "name": "Short Line RR", - "type": "railroad" + "type": "railroad", + "owner": null, + "mortgaged": false, + "group": "railroad", + "cost": 200 }, { "id": 36, @@ -211,7 +345,12 @@ { "id": 37, "name": "Park place (D)", - "type": "property" + "type": "property", + "owner": null, + "mortgaged": false, + "group": "darkblue", + "cost": 350, + "houses": 0 }, { "id": 38, @@ -221,27 +360,165 @@ { "id": 39, "name": "Boardwalk (D)", - "type": "property" + "type": "property", + "owner": null, + "mortgaged": false, + "group": "darkblue", + "cost": 400, + "houses": 0 } ], "log": [ { "text": "Game for 3 players", "player": null, - "timestamp": "2026-02-21 11:33:22" + "timestamp": "2026-02-21 11:53:09" }, { "text": "Waiting for Player 1 to register...", "player": null, - "timestamp": "2026-02-21 11:33:22" + "timestamp": "2026-02-21 11:53:09" + }, + { + "text": "alice joined!", + "player": "alice", + "timestamp": "2026-02-21 11:53:10" }, { "text": "Waiting for Player 2 to register...", "player": null, - "timestamp": "2026-02-21 11:33:23" + "timestamp": "2026-02-21 11:53:10" + }, + { + "text": "bob joined!", + "player": "bob", + "timestamp": "2026-02-21 11:53:12" + }, + { + "text": "Waiting for Player 3 to register...", + "player": null, + "timestamp": "2026-02-21 11:53:12" + }, + { + "text": "charlie joined!", + "player": "charlie", + "timestamp": "2026-02-21 11:53:15" + }, + { + "text": "Game started! alice goes first", + "player": null, + "timestamp": "2026-02-21 11:53:15" + }, + { + "text": "alice's turn \u2014 $1500 on === GO ===", + "player": "alice", + "timestamp": "2026-02-21 11:53:15" + }, + { + "text": "roll is 2, 2", + "player": "alice", + "timestamp": "2026-02-21 11:53:16" + }, + { + "text": "Landed on Income Tax", + "player": "alice", + "timestamp": "2026-02-21 11:53:17" + }, + { + "text": "alice's turn \u2014 $1350 on Income Tax", + "player": "alice", + "timestamp": "2026-02-21 11:53:19" + }, + { + "text": "roll is 5, 5", + "player": "alice", + "timestamp": "2026-02-21 11:53:20" + }, + { + "text": "Landed on Virginia ave. (V)", + "player": "alice", + "timestamp": "2026-02-21 11:53:21" + }, + { + "text": "alice's turn \u2014 $1190 on Virginia ave. (V)", + "player": "alice", + "timestamp": "2026-02-21 11:53:23" + }, + { + "text": "roll is 3, 3", + "player": "alice", + "timestamp": "2026-02-21 11:53:24" + }, + { + "text": "3 doubles \u2014 go to jail!", + "player": "alice", + "timestamp": "2026-02-21 11:53:25" + }, + { + "text": "bob's turn \u2014 $1500 on === GO ===", + "player": "bob", + "timestamp": "2026-02-21 11:53:25" + }, + { + "text": "roll is 1, 2", + "player": "bob", + "timestamp": "2026-02-21 11:53:27" + }, + { + "text": "Landed on Baltic ave. (P)", + "player": "bob", + "timestamp": "2026-02-21 11:53:27" + }, + { + "text": "charlie's turn \u2014 $1500 on === GO ===", + "player": "charlie", + "timestamp": "2026-02-21 11:53:29" + }, + { + "text": "roll is 2, 6", + "player": "charlie", + "timestamp": "2026-02-21 11:53:31" + }, + { + "text": "Landed on Vermont ave. (L)", + "player": "charlie", + "timestamp": "2026-02-21 11:53:31" + }, + { + "text": "alice's turn \u2014 $1190 on JAIL", + "player": "alice", + "timestamp": "2026-02-21 11:53:33" + }, + { + "text": "roll is 2, 6", + "player": "alice", + "timestamp": "2026-02-21 11:53:34" + }, + { + "text": "bob's turn \u2014 $1440 on Baltic ave. (P)", + "player": "bob", + "timestamp": "2026-02-21 11:53:35" + }, + { + "text": "roll is 3, 5", + "player": "bob", + "timestamp": "2026-02-21 11:53:37" + }, + { + "text": "Landed on St. Charles pl. (V)", + "player": "bob", + "timestamp": "2026-02-21 11:53:37" + }, + { + "text": "charlie's turn \u2014 $1400 on Vermont ave. (L)", + "player": "charlie", + "timestamp": "2026-02-21 11:53:39" + }, + { + "text": "roll is 3, 2", + "player": "charlie", + "timestamp": "2026-02-21 11:53:40" } ], - "phase": "setup", - "numPlayersExpected": 3, - "lastUpdated": "2026-02-21T11:33:23.055895+00:00" + "lastUpdated": "2026-02-21T11:53:40.970003+00:00" } \ No newline at end of file