home · contact · privacy
Client: More refactoring.
[plomrogue] / roguelike-client
1 #!/usr/bin/python3
2
3 import curses
4 import os
5 import signal
6 import time
7
8
9 from client.config.world_data import world_data
10 from client.config.io import io
11 from client.config.commands import commands
12 from client.window_management import redraw_windows, set_window_geometries, \
13                                      stdscr, draw_screen
14 from client.query_mapcell import query_mapcell
15
16
17 message_queue = {
18     "open_end": False,
19     "messages": []
20 }
21
22
23 def read_worldstate():
24     global redraw_windows
25     if not os.access(io["path_worldstate"], os.F_OK):
26         msg = "No world state file found at " + io["path_worldstate"] + "."
27         raise SystemExit(msg)
28     read_anew = False
29     worldstate_file = open(io["path_worldstate"], "r")
30     turn_string = worldstate_file.readline()
31     if int(turn_string) != world_data["turn"]:
32         read_anew = True
33     if not read_anew: # In rare cases, world may change, but not turn number.
34         mtime = os.stat(io["path_worldstate"])
35         if mtime != read_worldstate.last_checked_mtime:
36             read_worldstate.last_checked_mtime = mtime
37             read_anew = True
38     if read_anew:
39         redraw_windows = True
40         world_data["turn"] = int(turn_string)
41         world_data["lifepoints"] = int(worldstate_file.readline())
42         world_data["satiation"] = int(worldstate_file.readline())
43         world_data["inventory"] = []
44         while True:
45             line = worldstate_file.readline().replace("\n", "")
46             if line == '%':
47                 break
48             world_data["inventory"] += [line]
49         world_data["avatar_position"][0] = int(worldstate_file.readline())
50         world_data["avatar_position"][1] = int(worldstate_file.readline())
51         if not world_data["look_mode"]:
52             world_data["map_center"][0] = world_data["avatar_position"][0]
53             world_data["map_center"][1] = world_data["avatar_position"][1]
54         world_data["map_size"] = int(worldstate_file.readline())
55         world_data["fov_map"] = ""
56         for i in range(world_data["map_size"]):
57             line = worldstate_file.readline().replace("\n", "")
58             world_data["fov_map"] += line
59         world_data["mem_map"] = ""
60         for i in range(world_data["map_size"]):
61             line = worldstate_file.readline().replace("\n", "")
62             world_data["mem_map"] += line
63     worldstate_file.close()
64 read_worldstate.last_checked_mtime = -1
65
66
67 def read_message_queue():
68     global redraw_windows
69     while (len(message_queue["messages"]) > 1
70         or (len(message_queue["messages"]) == 1
71             and not message_queue["open_end"])):
72         message = message_queue["messages"].pop(0)
73         if message == "THINGS_HERE START":
74             read_message_queue.parse_thingshere = True
75             world_data["look"] = []
76         elif message == "THINGS_HERE END":
77             read_message_queue.parse_thingshere = False
78             if world_data["look"] == []:
79                 world_data["look"] = ["(none known)"]
80             redraw_windows = True
81         elif read_message_queue.parse_thingshere:
82             world_data["look"] += [message]
83         elif message[0:4] == "LOG ":
84             world_data["log"] += [message[4:]]
85             redraw_windows = True
86         elif message == "WORLD_UPDATED":
87             query_mapcell()
88 read_message_queue.parse_thingshere = False
89
90
91 def cursed_main(stdscr):
92     global redraw_windows
93
94     def ping_test():
95         half_wait_time = 5
96         if len(new_data_from_server) > 0:
97             ping_test.sent = False
98         elif ping_test.wait_start + half_wait_time < time.time():
99             if not ping_test.sent:
100                 io["file_out"].write("PING\n")
101                 io["file_out"].flush()
102                 ping_test.sent = True
103                 ping_test.wait_start = time.time()
104             elif ping_test.sent:
105                 raise SystemExit("Server not answering anymore.")
106     ping_test.wait_start = 0
107
108     def read_into_message_queue():
109         if new_data_from_server == "":
110             return
111         new_open_end = False
112         if new_data_from_server[-1] is not "\n":
113             new_open_end = True
114         new_messages = new_data_from_server.splitlines()
115         if message_queue["open_end"]:
116             message_queue["messages"][-1] += new_messages[0]
117             del new_messages[0]
118         message_queue["messages"] += new_messages
119         if new_open_end:
120             message_queue["open_end"] = True
121
122     curses.noecho()
123     curses.curs_set(False)
124     signal.signal(signal.SIGWINCH,
125         lambda ignore_1, ignore_2: set_window_geometries())
126     set_window_geometries()
127     delay = 1
128     while True:
129         stdscr.timeout(int(delay))
130         delay = delay * 1.1 if delay < 1000 else delay
131         if redraw_windows:
132             delay = 1
133             draw_screen()
134             redraw_windows = False
135         char = stdscr.getch()
136         if char >= 0:
137             char = chr(char)
138             if char in commands:
139                 if len(commands[char]) == 1 or not world_data["look_mode"]:
140                     commands[char][0]()
141                     redraw_windows = True
142                 else:
143                     commands[char][1]()
144                     redraw_windows = True
145         new_data_from_server = io["file_in"].read()
146         ping_test()
147         read_into_message_queue()
148         read_worldstate()
149         read_message_queue()
150
151
152 try:
153     if (not os.access(io["path_out"], os.F_OK)):
154         msg = "No server input file found at " + io["path_out"] + "."
155         raise SystemExit(msg)
156     io["file_out"] = open(io["path_out"], "a")
157     io["file_in"] = open(io["path_in"], "r")
158     curses.wrapper(cursed_main)
159 except SystemExit as exit:
160     print("ABORTING: " + exit.args[0])
161 except:
162     print("SOMETHING WENT WRONG IN UNEXPECTED WAYS")
163     raise
164 finally:
165     if "file_out" in io:
166         io["file_out"].close()
167     if "file_in" in io:
168         io["file_in"].close()