1 /** 2 * @file 3 * @brief Webtiles implementation of the tiles interface 4 **/ 5 6 #pragma once 7 8 #ifdef USE_TILE_WEB 9 10 #include <bitset> 11 #include <map> 12 #include <vector> 13 14 #include <sys/un.h> 15 16 #include "cursor-type.h" 17 #include "equipment-type.h" 18 #include "map-cell.h" 19 #include "map-knowledge.h" 20 #include "status.h" 21 #include "text-tag-type.h" 22 #include "tiledoll.h" 23 #include "tilemcache.h" 24 #include "tileweb-text.h" 25 #include "viewgeom.h" 26 27 using std::vector; 28 29 class Menu; 30 31 enum WebtilesUIState 32 { 33 UI_INIT = -1, 34 UI_NORMAL, 35 UI_CRT, 36 UI_VIEW_MAP, 37 }; 38 39 struct player_info 40 { 41 player_info(); 42 bool _state_ever_synced; 43 44 string name; 45 string job_title; 46 bool wizard; 47 string species; 48 string god; 49 bool under_penance; 50 uint8_t piety_rank; 51 52 uint8_t form; 53 54 int hp, hp_max, real_hp_max, poison_survival; 55 int mp, mp_max, dd_real_mp_max; 56 int contam; 57 int noise; 58 int adjusted_noise; 59 60 int armour_class; 61 int evasion; 62 int shield_class; 63 64 int8_t strength, strength_max; 65 int8_t intel, intel_max; 66 int8_t dex, dex_max; 67 68 int experience_level; 69 int8_t exp_progress; 70 int gold; 71 int zot_points; 72 int elapsed_time; 73 int num_turns; 74 int lives, deaths; 75 76 string place; 77 int depth; 78 coord_def position; 79 80 vector<status_info> status; 81 82 FixedVector<item_def, ENDOFPACK> inv; 83 FixedVector<int8_t, NUM_EQUIP> equip; 84 int8_t quiver_item; 85 int8_t launcher_item; 86 string quiver_desc; 87 string unarmed_attack; 88 uint8_t unarmed_attack_colour; 89 bool quiver_available; 90 }; 91 92 class TilesFramework 93 { 94 public: 95 TilesFramework(); 96 virtual ~TilesFramework(); 97 98 bool initialise(); 99 void shutdown(); 100 void load_dungeon(const crawl_view_buffer &vbuf, const coord_def &gc); 101 void load_dungeon(const coord_def &gc); 102 int getch_ck(); 103 void resize(); 104 void clrscr(); 105 void layout_reset(); 106 107 void cgotoxy(int x, int y, GotoRegion region = GOTO_CRT); 108 109 void update_minimap(const coord_def &gc); 110 void clear_minimap(); 111 void update_minimap_bounds(); 112 void update_tabs(); 113 114 void mark_for_redraw(const coord_def& gc); 115 void set_need_redraw(unsigned int min_tick_delay = 0); 116 bool need_redraw() const; 117 void redraw(); 118 119 void place_cursor(cursor_type type, const coord_def &gc); 120 void clear_text_tags(text_tag_type type); 121 void add_text_tag(text_tag_type type, const string &tag, 122 const coord_def &gc); 123 void add_text_tag(text_tag_type type, const monster_info& mon); 124 125 const coord_def &get_cursor() const; 126 127 void draw_doll_edit(); 128 129 // Webtiles-specific 130 void textcolour(int col); 131 void textbackground(int col); 132 void put_ucs_string(char32_t *str); 133 void clear_to_end_of_line(); 134 135 void push_menu(Menu* m); 136 void push_crt_menu(string tag); 137 bool is_in_crt_menu(); 138 bool is_in_menu(Menu* m); 139 void pop_menu(); 140 void push_ui_layout(const string& type, unsigned num_state_slots); 141 void pop_ui_layout(); 142 void pop_all_ui_layouts(); 143 void ui_state_change(const string& type, unsigned state_slot); 144 void push_ui_cutoff(); 145 void pop_ui_cutoff(); 146 147 void send_exit_reason(const string& type, const string& message = ""); 148 void send_dump_info(const string& type, const string& filename); 149 150 string get_message(); 151 void write_message(PRINTF(1, )); 152 void finish_message(); 153 void send_message(PRINTF(1, )); 154 void flush_messages(); 155 has_receivers()156 bool has_receivers() { return !m_dest_addrs.empty(); } is_controlled_from_web()157 bool is_controlled_from_web() { return m_controlled_from_web; } 158 159 /* Webtiles can receive input both via stdin, and on the 160 socket. Also, while waiting for input, it should be 161 able to handle other control messages (for example, 162 requests to re-send data when a new spectator joins). 163 164 This function waits until input is available either via 165 stdin or from a control message. If the input came from 166 a control message, it will be written into c; otherwise, 167 it still has to be read from stdin. 168 169 If block is false, await_input will immediately return, 170 even if no input is available. The return value indicates 171 whether input can be read from stdin; c will be non-zero 172 if input came via a control message. 173 */ 174 bool await_input(wint_t& c, bool block); 175 176 void check_for_control_messages(); 177 178 // Helper functions for writing JSON 179 void write_message_escaped(const string& s); 180 void json_open_object(const string& name = ""); 181 void json_close_object(bool erase_if_empty = false); 182 void json_open_array(const string& name = ""); 183 void json_close_array(bool erase_if_empty = false); 184 void json_write_comma(); 185 void json_write_name(const string& name); 186 void json_write_int(int value); 187 void json_write_int(const string& name, int value); 188 void json_write_bool(bool value); 189 void json_write_bool(const string& name, bool value); 190 void json_write_null(); 191 void json_write_null(const string& name); 192 void json_write_string(const string& value); 193 void json_write_string(const string& name, const string& value); 194 /* Causes the current object/array to be erased if it is closed 195 with erase_if_empty without writing any other content after 196 this call */ 197 void json_treat_as_empty(); 198 void json_treat_as_nonempty(); 199 bool json_is_empty(); 200 201 string m_sock_name; 202 bool m_await_connection; 203 204 void set_text_cursor(bool enabled); 205 void set_ui_state(WebtilesUIState state); get_ui_state()206 WebtilesUIState get_ui_state() { return m_ui_state; } 207 208 void dump(); 209 void update_input_mode(mouse_mode mode, bool force=false); 210 211 void send_mcache(mcache_entry *entry, bool submerged, 212 bool send = true); 213 void write_tileidx(tileidx_t t); 214 215 void zoom_dungeon(bool in); 216 217 void send_doll(const dolls_data &doll, bool submerged, bool ghost); 218 219 protected: 220 int m_sock; 221 int m_max_msg_size; 222 string m_msg_buf; 223 vector<sockaddr_un> m_dest_addrs; 224 225 bool m_controlled_from_web; 226 bool m_need_flush; 227 228 bool _send_lock; // not thread safe 229 230 void _await_connection(); 231 wint_t _handle_control_message(sockaddr_un addr, string data); 232 wint_t _receive_control_message(); 233 234 struct JsonFrame 235 { 236 int start; 237 int prefix_end; 238 char type; // '}' or ']' 239 }; 240 vector<JsonFrame> m_json_stack; 241 242 void json_open(const string& name, char opener, char type); 243 void json_close(bool erase_if_empty, char type); 244 245 struct UIStackFrame 246 { 247 enum { MENU, CRT, UI, } type; 248 Menu* menu; 249 string crt_tag; 250 vector<string> ui_json; 251 bool centred; 252 }; 253 vector<UIStackFrame> m_menu_stack; 254 255 WebtilesUIState m_ui_state; 256 WebtilesUIState m_last_ui_state; 257 vector<int> m_ui_cutoff_stack; 258 259 unsigned int m_last_tick_redraw; 260 bool m_need_redraw; 261 bool m_layout_reset; 262 263 coord_def m_origin; 264 265 bool m_view_loaded; 266 bool m_player_on_level; 267 268 crawl_view_buffer m_current_view; 269 coord_def m_current_gc; 270 271 crawl_view_buffer m_next_view; 272 coord_def m_next_gc; 273 coord_def m_next_view_tl; 274 coord_def m_next_view_br; 275 276 bitset<GXM * GYM> m_dirty_cells; 277 bitset<GXM * GYM> m_cells_needing_redraw; 278 void mark_dirty(const coord_def& gc); 279 void mark_clean(const coord_def& gc); 280 bool is_dirty(const coord_def& gc); 281 bool cell_needs_redraw(const coord_def& gc); 282 283 int m_current_flash_colour; 284 int m_next_flash_colour; 285 286 FixedArray<map_cell, GXM, GYM> m_current_map_knowledge; 287 map<uint32_t, coord_def> m_monster_locs; 288 bool m_need_full_map; 289 290 coord_def m_cursor[CURSOR_MAX]; 291 coord_def m_last_clicked_grid; 292 bool m_text_cursor; 293 bool m_last_text_cursor; 294 295 bool m_has_overlays; 296 297 WebTextArea m_text_menu; 298 299 GotoRegion m_cursor_region; 300 301 WebTextArea *m_print_area; 302 int m_print_x, m_print_y; 303 int m_print_fg, m_print_bg; 304 305 dolls_data last_player_doll; 306 307 player_info m_current_player_info; 308 309 void _send_version(); 310 void _send_options(); 311 void _send_layout(); 312 313 void _send_everything(); 314 315 bool m_mcache_ref_done; 316 void _mcache_ref(bool inc); 317 318 void _send_cursor(cursor_type type); 319 void _send_map(bool force_full = false); 320 void _send_cell(const coord_def &gc, 321 const screen_cell_t ¤t_sc, const screen_cell_t &next_sc, 322 const map_cell ¤t_mc, const map_cell &next_mc, 323 map<uint32_t, coord_def>& new_monster_locs, 324 bool force_full); 325 void _send_monster(const coord_def &gc, const monster_info* m, 326 map<uint32_t, coord_def>& new_monster_locs, 327 bool force_full); 328 void _send_player(bool force_full = false); 329 void _send_item(item_def& current, const item_def& next, 330 bool force_full); 331 void _send_messages(); 332 }; 333 334 // Main interface for tiles functions 335 extern TilesFramework tiles; 336 337 class tiles_crt_popup 338 { 339 public: 340 tiles_crt_popup(string tag = "") 341 { 342 tiles.push_crt_menu(tag); 343 } 344 ~tiles_crt_popup()345 ~tiles_crt_popup() 346 { 347 tiles.pop_menu(); 348 } 349 }; 350 351 class tiles_ui_control 352 { 353 public: tiles_ui_control(WebtilesUIState state)354 tiles_ui_control(WebtilesUIState state) 355 : m_new_state(state), m_old_state(tiles.get_ui_state()) 356 { 357 tiles.set_ui_state(state); 358 } 359 ~tiles_ui_control()360 ~tiles_ui_control() 361 { 362 if (tiles.get_ui_state() == m_new_state) 363 tiles.set_ui_state(m_old_state); 364 } 365 366 private: 367 WebtilesUIState m_new_state; 368 WebtilesUIState m_old_state; 369 }; 370 371 #endif 372