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
extern crate dcss_api;

use dcss_api::Webtile;
use dcss_api::{BlockingError, Error as APIError};
use serde_json::Value;
use std::process;

fn main() {
    // Connect to DCSS Webtile
    let mut webtile =
        Webtile::connect("ws://localhost:8080/socket", 100, "0.29").expect("Failed to connect");

    // Log in (to a user called "Username", with a password "Password")
    let gameid = webtile
        .login_with_credentials("Username", "Password")
        .expect("Failed to login");

    // Empty message queue;
    while webtile.get_message().is_some() {}

    // Start a random game on 'dcss-web-trunk', for Minotaur berserker with a mace.
    webtile
        .start_game_seeded(&gameid[0], "1", false, "b", "i", "b")
        .expect("Failed to start game");

    // Process the messages
    while let Some(message) = webtile.get_message() {
        processor(&message);
    }

    // Depending on what is found in the "map" data, a move up may make sense (up to the
    // bot to decide this) -- note this may if a north wall exists (no bot intelligence here).
    write_key_bot(&mut webtile, "key_dir_n", "player").expect("Failed");
    write_key_bot(&mut webtile, "key_dir_s", "player").expect("Failed");

    // Quit game (same as dying)
    webtile.quit_game().expect("Failed to quit");

    // Disconnect from webtile
    webtile.disconnect().expect("Failed to disconnect");
}

fn write_key_bot(webtile: &mut Webtile, to_send: &str, to_receive: &str) -> Result<(), APIError> {
    println!("SEND: {}", to_send);

    webtile.write_key(to_send)?;

    // Make sure you verify for blocking errors;
    if let Err(e) = webtile.read_until(to_receive, None, None) {
        match e {
            APIError::Blocking(BlockingError::More) => webtile.write_key(" ")?,
            APIError::Blocking(BlockingError::TextInput) => {
                println!("ERROR: Likely level up choice");
            }
            APIError::Blocking(BlockingError::Pickup) => println!("ERROR: Pickup"),
            APIError::Blocking(BlockingError::Acquirement) => println!("ERROR: Acquirement"),
            APIError::Blocking(BlockingError::Identify) => println!("ERROR: Identify"),
            APIError::Blocking(BlockingError::EnchantWeapon) => println!("ERROR: EnchantWeapon"),
            APIError::Blocking(BlockingError::EnchantItem) => println!("ERROR: EnchantItem"),
            APIError::Blocking(BlockingError::BrandWeapon) => println!("ERROR: BrandWeapon"),
            APIError::Blocking(BlockingError::Died) => {
                println!("ERROR: Died");
                process::exit(0);
            }
            _ => Err(e)?,
        }
    }

    // Process the data based on what was done (e.g. new map revealed, health of player...)
    while let Some(message) = webtile.get_message() {
        processor(&message);
    }

    Ok(())
}

fn processor(message: &Value) {
    let msg = message["msg"].as_str().unwrap();

    match msg {
        // Ignore
        "ping" => (),
        "lobby_clear" => (),
        "go_lobby" => (),
        "html" => (),
        "set_game_links" => (),
        "game_client" => (),
        "chat" => (),
        "version" => (),
        "options" => (),
        "layout" => (),
        "ui-state-sync" => (),
        "text_cursor" => (),
        "cursor" => (),
        "ui_state" => (),
        "flash" => (),
        "ui-stack" => (),
        "ui-state" => (),
        "update_menu_items" => (),
        "close_all_menus" => (),
        "delay" => (),
        "menu_scroll" => (),
        "ui-scroller-scroll" => (),
        "ui_cutoff" => (),
        "lobby_complete" => (),
        "login_success" => (),
        "game_started" => (),

        // Input & blocking
        "input_mode" => println!("PROCESS: input_mode"),

        // Messages
        "msgs" => println!("PROCESS: game log"),

        // Lobby
        "update_spectators" => println!("PROCESS: number of spectators"),

        // Player
        "player" => println!("PROCESS: player data"),

        // Dungeon
        "map" => println!("PROCESS: map data"),

        // Menu
        "menu" => println!("PROCESS: menu data"),
        "update_menu" => println!("PROCESS: menu data"),
        "close_menu" => println!("PROCESS: menu data"),
        "ui-push" => println!("PROCESS: menu data"),
        "ui-pop" => println!("PROCESS: menu data"),

        _ => {
            unreachable!();
        }
    };
}