home · contact · privacy
Fix visibility tests on annotation, volume algorithm.
[plomrogue2] / rogue_chat_curses.py
index 33b2750788c4c9b241158c9943ff428d726c9a8e..e037e7d5943f3762ffc72f08952a4d0f20fcec67 100755 (executable)
@@ -2,6 +2,7 @@
 import curses
 import queue
 import threading
+import time
 from plomrogue.game import GameBase
 from plomrogue.parser import Parser
 from plomrogue.mapping import YX, MapGeometrySquare, MapGeometryHex
@@ -103,6 +104,10 @@ def cmd_MAP(game, geometry, size, content):
         }
 cmd_MAP.argtypes = 'string:map_geometry yx_tuple:pos string'
 
+def cmd_FOV(game, content):
+    game.fov = content
+cmd_FOV.argtypes = 'string'
+
 def cmd_MAP_CONTROL(game, content):
     game.map_control_content = content
 cmd_MAP_CONTROL.argtypes = 'string'
@@ -177,6 +182,7 @@ class Game(GameBase):
         self.register_command(cmd_GAME_ERROR)
         self.register_command(cmd_PLAY_ERROR)
         self.register_command(cmd_TASKS)
+        self.register_command(cmd_FOV)
         self.map_content = ''
         self.player_id = -1
         self.info_db = {}
@@ -257,11 +263,48 @@ class TUI:
             for k in keys_conf:
                 self.keys[k] = keys_conf[k]
         self.show_help = False
+        self.disconnected = True
+        self.force_instant_connect = True
+        self.input_lines = []
+        self.fov = ''
         curses.wrapper(self.loop)
 
     def flash(self):
         curses.flash()
 
+    def connect(self):
+
+        def handle_recv(msg):
+            if msg == 'BYE':
+                self.socket.close()
+            else:
+                self.queue.put(msg)
+
+        self.log_msg('@ attempting connect')
+        socket_client_class = PlomSocketClient
+        if self.host.startswith('ws://') or self.host.startswith('wss://'):
+            socket_client_class = WebSocketClient
+        try:
+            self.socket = socket_client_class(handle_recv, self.host)
+            self.socket_thread = threading.Thread(target=self.socket.run)
+            self.socket_thread.start()
+            self.disconnected = False
+            self.socket.send('TASKS')
+            self.switch_mode('login')
+        except ConnectionRefusedError:
+            self.log_msg('@ server connect failure')
+            self.disconnected = True
+            self.switch_mode('waiting_for_server')
+        self.do_refresh = True
+
+    def reconnect(self):
+        self.log_msg('@ attempting reconnect')
+        self.send('QUIT')
+        time.sleep(0.1)  # FIXME necessitated by some some strange SSL race
+                         # conditions with ws4py, find out what exactly
+        self.switch_mode('waiting_for_server')
+        self.connect()
+
     def send(self, msg):
         try:
             if hasattr(self.socket, 'plom_closed') and self.socket.plom_closed:
@@ -269,6 +312,8 @@ class TUI:
             self.socket.send(msg)
         except (BrokenPipeError, BrokenSocketConnection):
             self.log_msg('@ server disconnected :(')
+            self.disconnected = True
+            self.force_instant_connect = True
             self.do_refresh = True
 
     def log_msg(self, msg):
@@ -310,7 +355,6 @@ class TUI:
         self.restore_input_values()
 
     def loop(self, stdscr):
-        import time
         import datetime
 
         def safe_addstr(y, x, line):
@@ -324,38 +368,6 @@ class TUI:
                 stdscr.insstr(y, self.size.x - 2, ' ')
                 stdscr.addstr(y, x, cut)
 
-        def connect():
-
-            def handle_recv(msg):
-                if msg == 'BYE':
-                    self.socket.close()
-                else:
-                    self.queue.put(msg)
-
-            socket_client_class = PlomSocketClient
-            if self.host.startswith('ws://') or self.host.startswith('wss://'):
-                socket_client_class = WebSocketClient
-            while True:
-                try:
-                    self.socket = socket_client_class(handle_recv, self.host)
-                    self.socket_thread = threading.Thread(target=self.socket.run)
-                    self.socket_thread.start()
-                    self.socket.send('TASKS')
-                    self.switch_mode('login')
-                    return
-                except ConnectionRefusedError:
-                    self.log_msg('@ server connect failure, trying again …')
-                    draw_screen()
-                    stdscr.refresh()
-                    time.sleep(1)
-
-        def reconnect():
-            self.send('QUIT')
-            time.sleep(0.1)  # FIXME necessitated by some some strange SSL race
-                             # conditions with ws4py, find out what exactly
-            self.switch_mode('waiting_for_server')
-            connect()
-
         def handle_input(msg):
             command, args = self.parser.parse(msg)
             command(*args)
@@ -412,18 +424,20 @@ class TUI:
             if not self.game.turn_complete:
                 return
             pos_i = self.explorer.y * self.game.map_geometry.size.x + self.explorer.x
-            info = 'TERRAIN: %s\n' % self.game.map_content[pos_i]
-            for t in self.game.things:
-                if t.position == self.explorer:
-                    info += 'PLAYER @: %s\n' % t.name
-            if self.explorer in self.game.portals:
-                info += 'PORTAL: ' + self.game.portals[self.explorer] + '\n'
-            else:
-                info += 'PORTAL: (none)\n'
-            if self.explorer in self.game.info_db:
-                info += 'ANNOTATION: ' + self.game.info_db[self.explorer]
-            else:
-                info += 'ANNOTATION: waiting …'
+            info = 'outside field of view'
+            if self.game.fov[pos_i] == '.':
+                info = 'TERRAIN: %s\n' % self.game.map_content[pos_i]
+                for t in self.game.things:
+                    if t.position == self.explorer:
+                        info += 'PLAYER @: %s\n' % t.name
+                if self.explorer in self.game.portals:
+                    info += 'PORTAL: ' + self.game.portals[self.explorer] + '\n'
+                else:
+                    info += 'PORTAL: (none)\n'
+                if self.explorer in self.game.info_db:
+                    info += 'ANNOTATION: ' + self.game.info_db[self.explorer]
+                else:
+                    info += 'ANNOTATION: waiting …'
             lines = msg_into_lines_of_width(info, self.window_width)
             height_header = 2
             for i in range(len(lines)):
@@ -559,13 +573,18 @@ class TUI:
         self.explorer = YX(0, 0)
         self.input_ = ''
         input_prompt = '> '
-        connect()
-        last_ping = datetime.datetime.now()
-        interval = datetime.timedelta(seconds=30)
+        interval = datetime.timedelta(seconds=5)
+        last_ping = datetime.datetime.now() - interval
         while True:
+            if self.disconnected and self.force_instant_connect:
+                self.force_instant_connect = False
+                self.connect()
             now = datetime.datetime.now()
             if now - last_ping > interval:
-                self.send('PING')
+                if self.disconnected:
+                    self.connect()
+                else:
+                    self.send('PING')
                 last_ping = now
             if self.do_refresh:
                 draw_screen()
@@ -608,13 +627,11 @@ class TUI:
                 self.input_ = ""
                 self.switch_mode('play')
             elif self.mode == self.mode_chat and key == '\n':
-                if self.input_[0] == '/':
+                if self.input_[0] == '/':  # FIXME fails on empty input
                     if self.input_ in {'/' + self.keys['switch_to_play'], '/play'}:
                         self.switch_mode('play')
                     elif self.input_ in {'/' + self.keys['switch_to_study'], '/study'}:
                         self.switch_mode('study')
-                    elif self.input_ == '/reconnect':
-                        reconnect()
                     elif self.input_.startswith('/nick'):
                         tokens = self.input_.split(maxsplit=1)
                         if len(tokens) == 2:
@@ -650,7 +667,7 @@ class TUI:
             elif self.mode == self.mode_teleport and key == '\n':
                 if self.input_ == 'YES!':
                     self.host = self.teleport_target_host
-                    reconnect()
+                    self.reconnect()
                 else:
                     self.log_msg('@ teleport aborted')
                     self.switch_mode('play')