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