diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index a1c20c3..b4a7243 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -25,11 +25,11 @@ jobs: - uses: actions/setup-python@v5 with: python-version: | - 3.9 3.10 3.11 3.12 3.13 + 3.14 - name: Install libssl-dev run: sudo apt-get install -y libssl-dev openssl pkg-config - name: Build wheels @@ -79,11 +79,11 @@ jobs: - uses: actions/setup-python@v5 with: python-version: | - 3.9 3.10 3.11 3.12 3.13 + 3.14 - name: Build wheels uses: PyO3/maturin-action@v1 with: @@ -111,11 +111,11 @@ jobs: - uses: actions/setup-python@v5 with: python-version: | - 3.9 3.10 3.11 3.12 3.13 + 3.14 architecture: ${{ matrix.platform.target }} - name: Build wheels uses: PyO3/maturin-action@v1 @@ -143,11 +143,11 @@ jobs: - uses: actions/setup-python@v5 with: python-version: | - 3.9 3.10 3.11 3.12 3.13 + 3.14 - name: Build wheels uses: PyO3/maturin-action@v1 with: diff --git a/Justfile b/Justfile index 1ec069b..8d00e30 100644 --- a/Justfile +++ b/Justfile @@ -24,8 +24,13 @@ setup-dcss-server: git -C ./crawl/dcss-0.32 checkout stone_soup-0.32 make -C ./crawl/dcss-0.32/crawl-ref/source WEBTILES=y + mkdir ./crawl/dcss-0.33 + cp -r ./crawl/main/crawl/. ./crawl/dcss-0.33 + git -C ./crawl/dcss-0.33 checkout stone_soup-0.33 + make -C ./crawl/dcss-0.33/crawl-ref/source WEBTILES=y + mkdir ./crawl/server - cp -r ./crawl/dcss-0.32/crawl-ref/source/webserver/. ./crawl/server + cp -r ./crawl/dcss-0.33/crawl-ref/source/webserver/. ./crawl/server sed -i -e 's/subprocess.signal/signal_module/g' ./crawl/server/webtiles/process_handler.py sed -i -e 's/import subprocess/import signal as signal_module/g' ./crawl/server/webtiles/process_handler.py cp ./crawl-config/config.py ./crawl/server/config.py @@ -34,9 +39,26 @@ setup-dcss-server: echo save_dir = ./crawl/server/saves-0.30 > ./crawl/server/init-0.30.txt echo save_dir = ./crawl/server/saves-0.31 > ./crawl/server/init-0.31.txt echo save_dir = ./crawl/server/saves-0.32 > ./crawl/server/init-0.32.txt + echo save_dir = ./crawl/server/saves-0.33 > ./crawl/server/init-0.33.txt rm -rf ./crawl/main +update-dcss-server: + git -C ./crawl/dcss-0.29 pull + make -C ./crawl/dcss-0.29/crawl-ref/source WEBTILES=y + + git -C ./crawl/dcss-0.30 pull + make -C ./crawl/dcss-0.30/crawl-ref/source WEBTILES=y + + git -C ./crawl/dcss-0.31 pull + make -C ./crawl/dcss-0.31/crawl-ref/source WEBTILES=y + + git -C ./crawl/dcss-0.32 pull + make -C ./crawl/dcss-0.32/crawl-ref/source WEBTILES=y + + git -C ./crawl/dcss-0.33 pull + make -C ./crawl/dcss-0.33/crawl-ref/source WEBTILES=y + dcss-run: python3 crawl/server/server.py @@ -57,21 +79,28 @@ dcss-clear: dcss-enable-logging: sed -i -e 's/# type: (str, Any) -> bool/print("SENT FROM DCSS: ", msg, data)/g' ./crawl/server/webtiles/ws_handler.py + sed -i -e 's/# stdout data is only used for compatibility to wrapper/print("SENT FROM DCSS: ", msg)/g' ./crawl/server/webtiles/process_handler.py dcss-disable-logging: sed -i -e 's/print("SENT FROM DCSS: ", msg, data)/# type: (str, Any) -> bool/g' ./crawl/server/webtiles/ws_handler.py + sed -i -e 's/print("SENT FROM DCSS: ", msg)/# stdout data is only used for compatibility to wrapper/g' ./crawl/server/webtiles/process_handler.py test-api: cd ./dcss-api && GAME_ID=dcss-0.29 cargo test cd ./dcss-api && GAME_ID=dcss-0.30 cargo test cd ./dcss-api && GAME_ID=dcss-0.31 cargo test cd ./dcss-api && GAME_ID=dcss-0.32 cargo test + cd ./dcss-api && GAME_ID=dcss-0.33 cargo test + +test-data: + cd ./dcss-data && GAME_ID=dcss-0.33 cargo test test-scenario: cd ./dcss-scenario-builder && GAME_ID=dcss-0.29 cargo test cd ./dcss-scenario-builder && GAME_ID=dcss-0.30 cargo test cd ./dcss-scenario-builder && GAME_ID=dcss-0.31 cargo test cd ./dcss-scenario-builder && GAME_ID=dcss-0.32 cargo test + cd ./dcss-scenario-builder && GAME_ID=dcss-0.33 cargo test setup-python: rm -rf ./dcss-api-python/pyo3 @@ -85,6 +114,7 @@ test-python: . ./dcss-api-python/pyo3/bin/activate && GAME_ID=dcss-0.30 pytest ./dcss-api-python/tests . ./dcss-api-python/pyo3/bin/activate && GAME_ID=dcss-0.31 pytest ./dcss-api-python/tests . ./dcss-api-python/pyo3/bin/activate && GAME_ID=dcss-0.32 pytest ./dcss-api-python/tests + . ./dcss-api-python/pyo3/bin/activate && GAME_ID=dcss-0.33 pytest ./dcss-api-python/tests cargo-update: cd ./dcss-api && cargo update @@ -93,7 +123,7 @@ cargo-update: cd ./dcss-data && cargo update cargo-outdated: - cd ./dcss-api && cargo outdated - cd ./dcss-scenario-builder && cargo outdated - cd ./dcss-api-python && cargo outdated - cd ./dcss-data && cargo outdated \ No newline at end of file + cd ./dcss-api && cargo outdated -d 1 + cd ./dcss-scenario-builder && cargo outdated -d 1 + cd ./dcss-api-python && cargo outdated -d 1 + cd ./dcss-data && cargo outdated -d 1 \ No newline at end of file diff --git a/README.md b/README.md index b928c39..2389ba1 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,15 @@ This repo contains a series of libraries in Rust and Python to work with [Dungeo ### [dcss-api](https://github.com/EricFecteau/dcss-api/blob/main/dcss-api/) [![Crates.io Version](https://img.shields.io/crates/v/dcss-api)](https://crates.io/crates/dcss-api) [![docs.rs](https://img.shields.io/docsrs/dcss-api)](https://docs.rs/dcss-api/latest/dcss_api/) -`dcss-api` is an easy to use Rust wrapper for DCSS Webtile websocket API. It works with version `0.29`, `0.30`, `0.31` or `0.32` of DCSS. +`dcss-api` is an easy to use Rust wrapper for DCSS Webtile websocket API. It works with version `0.29`, `0.30`, `0.31`, `0.32` and `0.33` of DCSS. ### [dcss-scenario-builder](https://github.com/EricFecteau/dcss-api/blob/main/dcss-api/) [![Crates.io Version](https://img.shields.io/crates/v/dcss-scenario-builder)](https://crates.io/crates/dcss-scenario-builder) [![docs.rs](https://img.shields.io/docsrs/dcss-scenario-builder)](https://docs.rs/dcss-scenario-builder/latest/dcss_scenario_builder/) -`dcss-scenario-builder` is a crate to build scenarios in DCSS (wizmode) from a yaml file by providing features, items and monsters and mapping them on a tile map. This is great for testing other crates in this repository. +`dcss-scenario-builder` is a crate to build scenarios in DCSS (wizmode) from a yaml file by providing features, items and monsters and mapping them on a tile map. This is great for testing other crates in this repository. It works with version `0.29`, `0.30`, `0.31`, `0.32` and `0.33` of DCSS. ### [dcss-api-python](https://github.com/EricFecteau/dcss-api/tree/main/dcss-api-python) [![PyPI - Version](https://img.shields.io/pypi/v/dcss-api)](https://pypi.org/project/dcss-api/) -`dcss-api` is an easy to use Python wrapper for DCSS Webtile websocket API, that includes the `dcss-scenario-builder` functionalities. It works with version `0.29`, `0.30`, `0.31` or `0.32` of DCSS. +`dcss-api` is an easy to use Python wrapper for DCSS Webtile websocket API, that includes the `dcss-scenario-builder` functionalities. It works with version `0.29`, `0.30`, `0.31`, `0.32` and `0.33` of DCSS. ### [dcss-data](https://github.com/EricFecteau/dcss-api/tree/main/dcss-data) (experimental) diff --git a/crawl-config/config.py b/crawl-config/config.py index 6ef4f4f..44dfe6a 100644 --- a/crawl-config/config.py +++ b/crawl-config/config.py @@ -88,6 +88,22 @@ allowed_with_hold = True, options = ["-seed"], )), + ("dcss-0.33", dict( + version = "0.33", + name = "Play 0.33", + crawl_binary = "./crawl/dcss-0.33/crawl-ref/source/crawl", + rcfile_path = "./crawl/server/rcs-0.33/", + macro_path = "./crawl/server/rcs-0.33/", + morgue_path = "./crawl/server/rcs-0.33/%n", + inprogress_path = "./crawl/server/rcs-0.33/running", + ttyrec_path = "./crawl/server/rcs-0.33/ttyrecs/%n", + socket_path = "./crawl/server/rcs-0.33/", + client_path = "./crawl/dcss-0.33/crawl-ref/source/webserver/game_data/", + morgue_url = None, + show_save_info = True, + allowed_with_hold = True, + options = ["-seed"], + )), ]) dgl_status_file = "./crawl/server/status" diff --git a/crawl-config/init-player.sh b/crawl-config/init-player.sh index b134810..911a234 100755 --- a/crawl-config/init-player.sh +++ b/crawl-config/init-player.sh @@ -55,3 +55,17 @@ mkdir -p $TTYRECDIR if [ ! -f ${RCDIR}/${PLAYERNAME}.rc ]; then cp ${DEFAULT_RC} ${RCDIR}/${PLAYERNAME}.rc fi + +RCDIR=./crawl/server/rcs-0.33/ +INPROGRESSDIR=./crawl/server/rcs-0.33/running +TTYRECDIR=./crawl/server/rcs-0.33/ttyrecs/$1 +DEFAULT_RC=./crawl/server/init-0.33.txt +PLAYERNAME=$1 + +mkdir -p $RCDIR +mkdir -p $INPROGRESSDIR +mkdir -p $TTYRECDIR + +if [ ! -f ${RCDIR}/${PLAYERNAME}.rc ]; then + cp ${DEFAULT_RC} ${RCDIR}/${PLAYERNAME}.rc +fi diff --git a/dcss-api-python/Cargo.lock b/dcss-api-python/Cargo.lock index 257ec71..a59f896 100644 --- a/dcss-api-python/Cargo.lock +++ b/dcss-api-python/Cargo.lock @@ -4,21 +4,21 @@ version = 4 [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "block-buffer" @@ -37,18 +37,19 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" -version = "1.2.16" +version = "1.2.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" dependencies = [ + "find-msvc-tools", "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "core-foundation" @@ -77,9 +78,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] @@ -96,15 +97,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] name = "dcss-api" -version = "0.2.1" +version = "0.4.0" dependencies = [ - "dcss-api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dcss-api 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "dcss-scenario-builder", "pyo3", "serde_json", @@ -112,9 +113,9 @@ dependencies = [ [[package]] name = "dcss-api" -version = "0.2.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc93b44b2084b09f5d319197738860dbad7de0f8bf30080dcbb4f8656c845e62" +checksum = "1aba1fba55c01f3a9def4ef09d68ed1557c20bf7d19163b54676b8ef7d5b9800" dependencies = [ "flate2", "serde_json", @@ -124,11 +125,11 @@ dependencies = [ [[package]] name = "dcss-scenario-builder" -version = "0.2.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eeeda5b5ce8794031f39e0b527763eedb935f8863503c3786170ee15ebd9430" +checksum = "10e374b025e1e4d2eabebbbed24d3521f2b852f1215ab74f813c4fc4610a663f" dependencies = [ - "dcss-api 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "dcss-api 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "itertools", "rustc-hash", "serde_yaml", @@ -159,9 +160,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", "windows-sys", @@ -173,11 +174,17 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "find-msvc-tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" + [[package]] name = "flate2" -version = "1.1.0" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" dependencies = [ "crc32fast", "libz-sys", @@ -217,21 +224,21 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", + "r-efi", "wasi", - "windows-targets", ] [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "heck" @@ -241,9 +248,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "http" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", @@ -258,9 +265,9 @@ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "indexmap" -version = "2.7.1" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", "hashbrown", @@ -289,15 +296,15 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "libc" -version = "0.2.170" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libz-sys" -version = "1.1.21" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" dependencies = [ "cc", "pkg-config", @@ -306,21 +313,21 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.9.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "log" -version = "0.4.26" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memoffset" @@ -333,11 +340,12 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.5" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -359,15 +367,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "openssl" -version = "0.10.71" +version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ "bitflags", "cfg-if", @@ -397,18 +405,18 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-src" -version = "300.4.2+3.4.1" +version = "300.5.3+3.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168ce4e058f975fe43e89d9ccf78ca668601887ae736090aacc23ae353c298e2" +checksum = "dc6bad8cd0233b63971e232cc9c5e83039375b8586d2312f31fda85db8f888c2" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.106" +version = "0.9.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" dependencies = [ "cc", "libc", @@ -425,9 +433,9 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "portable-atomic" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "ppv-lite86" @@ -440,20 +448,19 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] [[package]] name = "pyo3" -version = "0.24.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f1c6c3591120564d64db2261bec5f910ae454f01def849b9c22835a84695e86" +checksum = "7ba0117f4212101ee6544044dae45abe1083d30ce7b29c4b5cbdfa2354e07383" dependencies = [ - "cfg-if", "indoc", "libc", "memoffset", @@ -467,19 +474,18 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.24.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9b6c2b34cf71427ea37c7001aefbaeb85886a074795e35f161f5aecc7620a7a" +checksum = "4fc6ddaf24947d12a9aa31ac65431fb1b851b8f4365426e182901eabfb87df5f" dependencies = [ - "once_cell", "target-lexicon", ] [[package]] name = "pyo3-ffi" -version = "0.24.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5507651906a46432cdda02cd02dd0319f6064f1374c9147c45b978621d2c3a9c" +checksum = "025474d3928738efb38ac36d4744a74a400c901c7596199e20e45d98eb194105" dependencies = [ "libc", "pyo3-build-config", @@ -487,9 +493,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.24.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0d394b5b4fd8d97d48336bb0dd2aebabad39f1d294edd6bcd2cccf2eefe6f42" +checksum = "2e64eb489f22fe1c95911b77c44cc41e7c19f3082fc81cce90f657cdc42ffded" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -499,9 +505,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.24.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd72da09cfa943b1080f621f024d2ef7e2773df7badd51aa30a2be1f8caa7c8e" +checksum = "100246c0ecf400b475341b8455a9213344569af29a3c841d29270e53102e0fcf" dependencies = [ "heck", "proc-macro2", @@ -512,22 +518,27 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.39" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha", "rand_core", - "zerocopy", ] [[package]] @@ -557,9 +568,9 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustix" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ "bitflags", "errno", @@ -576,9 +587,9 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ "windows-sys", ] @@ -598,9 +609,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -608,18 +619,27 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -628,14 +648,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] @@ -668,11 +689,17 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "syn" -version = "2.0.100" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -681,17 +708,16 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" +checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c" [[package]] name = "tempfile" -version = "3.18.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c317e0a526ee6120d8dabad239c8dadca62b24b6f168914bbbc8e2fb1f0e567" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ - "cfg-if", "fastrand", "getrandom", "once_cell", @@ -701,18 +727,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -721,9 +747,9 @@ dependencies = [ [[package]] name = "tungstenite" -version = "0.26.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" dependencies = [ "bytes", "data-encoding", @@ -739,15 +765,15 @@ dependencies = [ [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unindent" @@ -781,109 +807,57 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.7+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" dependencies = [ - "wit-bindgen-rt", + "wasip2", ] [[package]] -name = "windows-sys" -version = "0.59.0" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "windows-targets", + "wit-bindgen", ] [[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] [[package]] -name = "wit-bindgen-rt" -version = "0.33.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" -dependencies = [ - "bitflags", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "zerocopy" -version = "0.8.23" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.23" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", diff --git a/dcss-api-python/Cargo.toml b/dcss-api-python/Cargo.toml index 3f213bd..bb6efb3 100644 --- a/dcss-api-python/Cargo.toml +++ b/dcss-api-python/Cargo.toml @@ -1,8 +1,8 @@ [package] authors = ["Eric Fecteau "] name = "dcss-api" -version = "0.2.1" -edition = "2021" +version = "0.4.0" +edition = "2024" license = "MPL-2.0" description = "A DCSS Webtile API for Python." repository = "https://github.com/EricFecteau/dcss-api/" @@ -14,7 +14,7 @@ crate-type = ["cdylib"] doctest = false [dependencies] -dcss-api = "0.2" -dcss-scenario-builder = "0.2" -pyo3 = { version = "0.24", features = ["extension-module"] } +dcss-api = "0.4" +dcss-scenario-builder = "0.4" +pyo3 = { version = "0.26", features = ["extension-module"] } serde_json = "1.0" \ No newline at end of file diff --git a/dcss-api-python/README.md b/dcss-api-python/README.md index c28b9a5..7f49f51 100644 --- a/dcss-api-python/README.md +++ b/dcss-api-python/README.md @@ -12,7 +12,7 @@ This example connects to DCSS on `localhost:8080`, logs in as `Username`, starts ```Python # Connect to DCSS Webtile -webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 100, "0.32") +webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 100) # Empty message queue while (message := webtile.get_message()) != None: @@ -28,7 +28,7 @@ print(gameid) while (message := webtile.get_message()) != None: pass -# Start a random game on 'dcss-0.32', for Minotaur berserker with a mace. +# Start a random game for Minotaur berserker with a mace. webtile.start_game(gameid[0], "b", "f", "b") # Print the messages you get upon starting the game (should be processed) @@ -108,7 +108,7 @@ levels: ```Python # Connect to DCSS Webtile -webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 100, "0.32") +webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 100) # Empty message queue while (message := webtile.get_message()) != None: @@ -122,7 +122,7 @@ while (message := webtile.get_message()) != None: pass # Create scenario -webtile.start_game_with_scenario("dcss-0.32", "b", "f", "b", "./examples/scenarios/readme.yaml") +webtile.start_game_with_scenario("dcss-0.33", "b", "f", "b", "./examples/scenarios/readme.yaml") # Empty message queue while (message := webtile.get_message()) != None: diff --git a/dcss-api-python/examples/0_setup.py b/dcss-api-python/examples/0_setup.py index 44617e8..9c73256 100644 --- a/dcss-api-python/examples/0_setup.py +++ b/dcss-api-python/examples/0_setup.py @@ -2,7 +2,7 @@ def main(): # Connect to DCSS Webtile - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 100, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 100) # Empty message queue while (message := webtile.get_message()) != None: diff --git a/dcss-api-python/examples/1_basic.py b/dcss-api-python/examples/1_basic.py index 936d9a1..24ae807 100644 --- a/dcss-api-python/examples/1_basic.py +++ b/dcss-api-python/examples/1_basic.py @@ -2,7 +2,7 @@ def main(): # Connect to DCSS Webtile - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 100, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 100) # Empty message queue while (message := webtile.get_message()) != None: @@ -18,7 +18,7 @@ def main(): while (message := webtile.get_message()) != None: pass - # Start a random game on 'dcss-0.32', for Minotaur berserker with a mace. + # Start a random game for Minotaur berserker with a mace. webtile.start_game(gameid[0], "b", "f", "b") # Print the messages you get upon starting the game (should be processed) diff --git a/dcss-api-python/examples/2_rc_file.py b/dcss-api-python/examples/2_rc_file.py index 47c4ec0..31dbbc0 100644 --- a/dcss-api-python/examples/2_rc_file.py +++ b/dcss-api-python/examples/2_rc_file.py @@ -2,7 +2,7 @@ def main(): # Connect to DCSS Webtile - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 100, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 100) # Empty message queue while (message := webtile.get_message()) != None: @@ -16,14 +16,14 @@ def main(): pass # Write RC File - webtile.set_rc_file("dcss-0.32", "show_more = false\nrest_delay = -1") + webtile.set_rc_file("dcss-0.33", "show_more = false\nrest_delay = -1") # Empty message queue while (message := webtile.get_message()) != None: pass # Read RC File - rc_file = webtile.get_rc_file("dcss-0.32") + rc_file = webtile.get_rc_file("dcss-0.33") print("RC FILE: \n\n", rc_file, "\n\n") diff --git a/dcss-api-python/examples/3_cookies.py b/dcss-api-python/examples/3_cookies.py index 366a909..e18d78e 100644 --- a/dcss-api-python/examples/3_cookies.py +++ b/dcss-api-python/examples/3_cookies.py @@ -2,7 +2,7 @@ def main(): # Connect to DCSS Webtile - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 100, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 100) # Empty message queue while (message := webtile.get_message()) != None: @@ -28,7 +28,7 @@ def main(): webtile.disconnect() # Connect to DCSS Webtile - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 100, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 100) # Empty message queue while (message := webtile.get_message()) != None: diff --git a/dcss-api-python/examples/4_blocking_error.py b/dcss-api-python/examples/4_blocking_error.py index 876197a..9999e09 100644 --- a/dcss-api-python/examples/4_blocking_error.py +++ b/dcss-api-python/examples/4_blocking_error.py @@ -3,7 +3,7 @@ def main(): # Connect to DCSS Webtile - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 100, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 100) # Empty message queue while (message := webtile.get_message()) != None: @@ -16,8 +16,8 @@ def main(): while (message := webtile.get_message()) != None: pass - # Start a random game on 'dcss-0.32', for Minotaur berserker with a mace. - webtile.start_game("dcss-0.32", "b", "f", "b") + # Start a random game for Minotaur berserker with a mace. + webtile.start_game("dcss-0.33", "b", "f", "b") # Print the messages you get upon starting the game (should be processed) while (message := webtile.get_message()) != None: diff --git a/dcss-api-python/examples/5_bot_core.py b/dcss-api-python/examples/5_bot_core.py index a1e0814..b4b1d81 100644 --- a/dcss-api-python/examples/5_bot_core.py +++ b/dcss-api-python/examples/5_bot_core.py @@ -5,7 +5,7 @@ def main(): # Connect to DCSS Webtile - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 100, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 100) # Empty message queue while (message := webtile.get_message()) != None: @@ -18,7 +18,7 @@ def main(): while (message := webtile.get_message()) != None: pass - # Start a random game on 'dcss-0.29', for Minotaur berserker with a mace. + # Start a random game for Minotaur berserker with a mace. webtile.start_game(gameid[0], "b", "f", "b") # Print the messages you get upon starting the game (should be processed) diff --git a/dcss-api-python/examples/6_scenario.py b/dcss-api-python/examples/6_scenario.py index d47ccad..1afb715 100644 --- a/dcss-api-python/examples/6_scenario.py +++ b/dcss-api-python/examples/6_scenario.py @@ -2,7 +2,7 @@ def main(): # Connect to DCSS Webtile - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 100, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 100) # Empty message queue while (message := webtile.get_message()) != None: @@ -16,7 +16,7 @@ def main(): pass # Create scenario - webtile.start_game_with_scenario("dcss-0.32", "b", "f", "b", "./examples/scenarios/readme.yaml") + webtile.start_game_with_scenario("dcss-0.33", "b", "f", "b", "./examples/scenarios/readme.yaml") # Empty message queue while (message := webtile.get_message()) != None: diff --git a/dcss-api-python/src/lib.rs b/dcss-api-python/src/lib.rs index 8f9f11a..cea9a3a 100644 --- a/dcss-api-python/src/lib.rs +++ b/dcss-api-python/src/lib.rs @@ -20,7 +20,7 @@ use pyo3::prelude::*; /// the future. /// /// Example: -/// webtile = Webtile::connect("ws://localhost:8080/socket", 100, "0.29") +/// webtile = Webtile::connect("ws://localhost:8080/socket", 100) /// pub struct WebtilePy { webtile: Webtile, @@ -33,8 +33,8 @@ pyo3::create_exception!(mymodule, ScenarioErr, PyException); #[pymethods] impl WebtilePy { #[new] - fn connect(url: &str, speed_ms: u32, version: &str) -> PyResult { - let webtile = Webtile::connect(url, speed_ms, version); + fn connect(url: &str, speed_ms: u32) -> PyResult { + let webtile = Webtile::connect(url, speed_ms); match webtile { Ok(t) => Ok(Self { webtile: t }), @@ -84,7 +84,7 @@ impl WebtilePy { match result { Ok(t) => Ok(t), - Err(e) => match e { + Err(e) => match *e { Error::Blocking(BlockingError::Pickup) => { Err(PyErr::new::("Pickup")) } @@ -318,7 +318,7 @@ impl WebtilePy { /// Example: /// # Start a scenario game, for a Minotaur (b), Berserker (f), with a mace (b) using the /// # branches.yaml scenario. - /// webtile.start_game_with_scenario("dcss-0.32", true, "b", "f", "b", "./scenarios/branches.yaml") + /// webtile.start_game_with_scenario("dcss-0.33", true, "b", "f", "b", "./scenarios/branches.yaml") fn start_game_with_scenario( &mut self, game_id: &str, diff --git a/dcss-api-python/tests/connect_test.py b/dcss-api-python/tests/connect_test.py index d5fb739..5ecc476 100644 --- a/dcss-api-python/tests/connect_test.py +++ b/dcss-api-python/tests/connect_test.py @@ -5,7 +5,7 @@ def test_successful_connect(): # Connect to DCSS Webtile - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) assert '{"msg":"ping"}' == webtile.get_message() assert '{"msg":"lobby_clear"}' == webtile.get_message() @@ -16,7 +16,7 @@ def test_successful_connect(): def test_failed_connect(): try: - webtile = dcss_api.WebtilePy("ws://localhost:XXXX/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:XXXX/socket", 0) assert False except APIErr as e: if "Tungstenite error" in e.args[0]: @@ -25,7 +25,7 @@ def test_failed_connect(): assert False try: - webtile = dcss_api.WebtilePy("ws://localhost:0000/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:0000/socket", 0) assert False except APIErr as e: if "Tungstenite error" in e.args[0]: diff --git a/dcss-api-python/tests/login_test.py b/dcss-api-python/tests/login_test.py index ccbc322..df1e957 100644 --- a/dcss-api-python/tests/login_test.py +++ b/dcss-api-python/tests/login_test.py @@ -6,7 +6,7 @@ def test_successful_credential_login(): # Connect to DCSS Webtile - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -24,7 +24,7 @@ def test_successful_credential_login(): def test_multiple_login_same_user(): - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -57,7 +57,7 @@ def test_multiple_login_same_user(): def test_multiple_login_diff_user(): - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -92,7 +92,7 @@ def test_multiple_login_diff_user(): def test_failed_credential_login(): - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -110,7 +110,7 @@ def test_failed_credential_login(): def test_failed_credential_login_and_retry(): - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -138,7 +138,7 @@ def test_failed_credential_login_and_retry(): def test_get_cookie_and_login(): - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -158,7 +158,7 @@ def test_get_cookie_and_login(): webtile.disconnect() - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -176,7 +176,7 @@ def test_get_cookie_and_login(): def test_failed_cookie_login(): - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -192,7 +192,7 @@ def test_failed_cookie_login(): def test_using_old_cookie_login(): - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -212,7 +212,7 @@ def test_using_old_cookie_login(): webtile.disconnect() - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -232,7 +232,7 @@ def test_using_old_cookie_login(): webtile.disconnect() - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -250,7 +250,7 @@ def test_using_old_cookie_login(): def test_credential_login_gameid(): - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -262,13 +262,14 @@ def test_credential_login_gameid(): "dcss-0.30", "dcss-0.31", "dcss-0.32", + "dcss-0.33", ] webtile.disconnect() def test_cookie_login_gameid(): - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -280,6 +281,7 @@ def test_cookie_login_gameid(): "dcss-0.30", "dcss-0.31", "dcss-0.32", + "dcss-0.33", ] cookie = webtile.request_cookie() @@ -288,7 +290,7 @@ def test_cookie_login_gameid(): webtile.disconnect() - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -300,6 +302,7 @@ def test_cookie_login_gameid(): "dcss-0.30", "dcss-0.31", "dcss-0.32", + "dcss-0.33", ] webtile.disconnect() diff --git a/dcss-api-python/tests/rc_file_test.py b/dcss-api-python/tests/rc_file_test.py index d18ab25..7ec828f 100644 --- a/dcss-api-python/tests/rc_file_test.py +++ b/dcss-api-python/tests/rc_file_test.py @@ -8,7 +8,7 @@ def test_write_read_rc(): game_id = os.environ['GAME_ID'] # Connect to DCSS Webtile - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -40,7 +40,7 @@ def test_blank_rc_file(): game_id = os.environ['GAME_ID'] # Connect to DCSS Webtile - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass diff --git a/dcss-api-python/tests/scenario_test.py b/dcss-api-python/tests/scenario_test.py index 31c7960..2459cf1 100644 --- a/dcss-api-python/tests/scenario_test.py +++ b/dcss-api-python/tests/scenario_test.py @@ -7,7 +7,7 @@ def reset_test(username, game_id): # Connect to DCSS Webtile - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -34,7 +34,7 @@ def test_wizmode(): reset_test("Username", game_id) - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -69,7 +69,7 @@ def test_no_character(): reset_test("Username", game_id) - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -95,7 +95,7 @@ def test_too_wide(): reset_test("Username", game_id) - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -121,7 +121,7 @@ def test_too_long(): reset_test("Username", game_id) - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass diff --git a/dcss-api-python/tests/start_game_test.py b/dcss-api-python/tests/start_game_test.py index 4925532..d228650 100644 --- a/dcss-api-python/tests/start_game_test.py +++ b/dcss-api-python/tests/start_game_test.py @@ -7,7 +7,7 @@ def reset_test(username, game_id): # Connect to DCSS Webtile - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -36,7 +36,7 @@ def test_start_game_seeded(): reset_test("Username", game_id) # Connect to DCSS Webtile - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -70,7 +70,7 @@ def test_start_game_seeded(): webtile.disconnect() - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -111,7 +111,7 @@ def test_start_game(): reset_test("Username", game_id) # Connect to DCSS Webtile - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -147,7 +147,7 @@ def test_start_game(): reset_test("Username", game_id) # Connect to DCSS Webtile - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -191,7 +191,7 @@ def test_start_game_two_accounts(): reset_test("Username", game_id) - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -230,7 +230,7 @@ def test_start_game_two_accounts(): reset_test("Username2", game_id) - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass @@ -274,8 +274,8 @@ def test_start_game_two_accounts_combined(): reset_test("Username", game_id) reset_test("Username2", game_id) - webtile1 = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") - webtile2 = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile1 = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) + webtile2 = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile1.get_message()) != None: pass @@ -347,7 +347,7 @@ def test_real_blocking_error(): reset_test("Username", game_id) - webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0, "0.32") + webtile = dcss_api.WebtilePy("ws://localhost:8080/socket", 0) while (message := webtile.get_message()) != None: pass diff --git a/dcss-api/Cargo.lock b/dcss-api/Cargo.lock index 0d3f2c5..315914b 100644 --- a/dcss-api/Cargo.lock +++ b/dcss-api/Cargo.lock @@ -4,15 +4,15 @@ version = 4 [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "block-buffer" @@ -31,18 +31,19 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" -version = "1.2.16" +version = "1.2.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" dependencies = [ + "find-msvc-tools", "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "core-foundation" @@ -71,9 +72,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] @@ -90,13 +91,13 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] name = "dcss-api" -version = "0.2.1" +version = "0.4.0" dependencies = [ "flate2", "serde_json", @@ -116,9 +117,9 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.10" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", "windows-sys", @@ -130,11 +131,17 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "find-msvc-tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" + [[package]] name = "flate2" -version = "1.1.0" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" dependencies = [ "crc32fast", "libz-sys", @@ -174,21 +181,21 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", + "r-efi", "wasi", - "windows-targets", ] [[package]] name = "http" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", @@ -209,15 +216,15 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "libc" -version = "0.2.170" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libz-sys" -version = "1.1.21" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" dependencies = [ "cc", "pkg-config", @@ -226,29 +233,30 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.9.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "log" -version = "0.4.26" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "miniz_oxide" -version = "0.8.5" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -270,15 +278,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "openssl" -version = "0.10.71" +version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ "bitflags", "cfg-if", @@ -308,18 +316,18 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-src" -version = "300.4.2+3.4.1" +version = "300.5.3+3.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168ce4e058f975fe43e89d9ccf78ca668601887ae736090aacc23ae353c298e2" +checksum = "dc6bad8cd0233b63971e232cc9c5e83039375b8586d2312f31fda85db8f888c2" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.106" +version = "0.9.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" dependencies = [ "cc", "libc", @@ -345,31 +353,36 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.39" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha", "rand_core", - "zerocopy", ] [[package]] @@ -393,9 +406,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ "bitflags", "errno", @@ -412,9 +425,9 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ "windows-sys", ] @@ -434,9 +447,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -444,18 +457,27 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -464,14 +486,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] @@ -491,11 +514,17 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "syn" -version = "2.0.100" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -504,11 +533,10 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.18.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c317e0a526ee6120d8dabad239c8dadca62b24b6f168914bbbc8e2fb1f0e567" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ - "cfg-if", "fastrand", "getrandom", "once_cell", @@ -518,18 +546,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -538,9 +566,9 @@ dependencies = [ [[package]] name = "tungstenite" -version = "0.26.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" dependencies = [ "bytes", "data-encoding", @@ -556,15 +584,15 @@ dependencies = [ [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "utf-8" @@ -586,109 +614,57 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.7+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" dependencies = [ - "wit-bindgen-rt", + "wasip2", ] [[package]] -name = "windows-sys" -version = "0.59.0" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "windows-targets", + "wit-bindgen", ] [[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] [[package]] -name = "wit-bindgen-rt" -version = "0.33.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" -dependencies = [ - "bitflags", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "zerocopy" -version = "0.8.23" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.23" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", diff --git a/dcss-api/Cargo.toml b/dcss-api/Cargo.toml index f8d61ad..4a4e617 100644 --- a/dcss-api/Cargo.toml +++ b/dcss-api/Cargo.toml @@ -1,8 +1,8 @@ [package] authors = ["Eric Fecteau "] name = "dcss-api" -version = "0.2.1" -edition = "2021" +version = "0.4.0" +edition = "2024" license = "MPL-2.0" description = "A DCSS Webtile API for Rust." repository = "https://github.com/EricFecteau/dcss-api/" @@ -13,6 +13,6 @@ doctest = false [dependencies] flate2 = { version = "1.0", features = ["zlib"], default-features = false } -tungstenite = { version = "0.26", features = ["native-tls-vendored"] } +tungstenite = { version = "0.28", features = ["native-tls-vendored"] } serde_json = "1.0" thiserror = "2.0" \ No newline at end of file diff --git a/dcss-api/README.md b/dcss-api/README.md index 0770b41..3f3c682 100644 --- a/dcss-api/README.md +++ b/dcss-api/README.md @@ -1,6 +1,6 @@ # dcss-api -`dcss-api` is an easy to use Rust wrapper for [Dungeon Crawl Stone Soup's (DCSS) Webtile](https://crawl.develz.org/) websocket API. It supports logging in, starting a game and sending commands during game play. It works for DCSS `0.29`, `0.30`, `0.31` and `0.32`. +`dcss-api` is an easy to use Rust wrapper for [Dungeon Crawl Stone Soup's (DCSS) Webtile](https://crawl.develz.org/) websocket API. It supports logging in, starting a game and sending commands during game play. It works for DCSS `0.29`, `0.30`, `0.31`, `0.32` and `0.33`. ## Documentation @@ -12,7 +12,7 @@ This example connects to DCSS on `localhost:8080`, logs in as `Username`, starts ```Rust // Connect to DCSS Webtile -let mut webtile = Webtile::connect("ws://localhost:8080/socket", 100, "0.32")?; +let mut webtile = Webtile::connect("ws://localhost:8080/socket", 100)?; // Empty message queue; while webtile.get_message().is_some() {} @@ -26,7 +26,7 @@ println!("{:?}", gameid); // Empty message queue; while webtile.get_message().is_some() {} -// Start a random game (seed `0`) on 'dcss-0.32', for Minotaur berserker with a mace. +// Start a random game (seed `0`) for Minotaur berserker with a mace. webtile.start_game_seeded(&gameid[0], "0", false, "b", "f", "b")?; // Print the messages you get upon starting the game (should be processed) diff --git a/dcss-api/examples/0_setup.rs b/dcss-api/examples/0_setup.rs index 01238e4..d3559f0 100644 --- a/dcss-api/examples/0_setup.rs +++ b/dcss-api/examples/0_setup.rs @@ -5,7 +5,7 @@ use dcss_api::Webtile; fn main() { // Connect to DCSS Webtile let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 100, "0.32").expect("Failed to connect"); + Webtile::connect("ws://localhost:8080/socket", 100).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} @@ -14,15 +14,39 @@ fn main() { webtile .register_account("Username", "Password", None) .expect("Failed to register"); - webtile - .register_account("Username2", "Password", None) - .expect("Failed to register"); - webtile - .register_account("Username3", "Password", None) - .expect("Failed to register"); - webtile - .register_account("Username4", "Password", None) - .expect("Failed to register"); + println!("User 'Username' created"); + + // For "log in" test + for i in 1..4 { + webtile + .register_account(format!("Username{i}").as_str(), "Password", None) + .expect("Failed to register"); + println!("User 'Username{i}' created"); + } + + // For "tiles" test + for i in 1..4 { + webtile + .register_account(format!("Tiles{i}").as_str(), "Password", None) + .expect("Failed to register"); + println!("User 'Tiles{i}' created"); + } + + // For "monsters" test + for i in 1..25 { + webtile + .register_account(format!("Monsters{i}").as_str(), "Password", None) + .expect("Failed to register"); + println!("User 'Monsters{i}' created"); + } + + // For "player" test + for i in 1..25 { + webtile + .register_account(format!("Player{i}").as_str(), "Password", None) + .expect("Failed to register"); + println!("User 'Player{i}' created"); + } // Disconnect from webtile webtile.disconnect().expect("Failed to disconnect"); diff --git a/dcss-api/examples/1_basic.rs b/dcss-api/examples/1_basic.rs index 9765f03..cc0aa31 100644 --- a/dcss-api/examples/1_basic.rs +++ b/dcss-api/examples/1_basic.rs @@ -5,7 +5,7 @@ use dcss_api::Webtile; fn main() { // Connect to DCSS Webtile let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 100, "0.32").expect("Failed to connect"); + Webtile::connect("ws://localhost:8080/socket", 100).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} @@ -16,19 +16,19 @@ fn main() { .expect("Failed to login"); // Print the game id's that can be started - println!("{:?}", gameid); + println!("{gameid:?}"); // Empty message queue; while webtile.get_message().is_some() {} - // Start a random game (seed `0`) on 'dcss-0.32', for Minotaur berserker with a mace. + // Start a random game (seed `0`) for Minotaur berserker with a mace. webtile .start_game_seeded(&gameid[0], "0", false, "b", "f", "b") .expect("Failed to start game"); // Print the messages you get upon starting the game (should be processed) while let Some(message) = webtile.get_message() { - println!("{:?}", message) + println!("{message:?}") } // Move up and back @@ -37,7 +37,7 @@ fn main() { // Print the messages you while moving (should be processed) while let Some(message) = webtile.get_message() { - println!("{:?}", message) + println!("{message:?}") } // Quit game (same as dying) @@ -45,7 +45,7 @@ fn main() { // Print the messages after you quit game while let Some(message) = webtile.get_message() { - println!("{:?}", message) + println!("{message:?}") } // Disconnect from webtile diff --git a/dcss-api/examples/2_rc_file.rs b/dcss-api/examples/2_rc_file.rs index 1d1c581..1642af0 100644 --- a/dcss-api/examples/2_rc_file.rs +++ b/dcss-api/examples/2_rc_file.rs @@ -5,7 +5,7 @@ use dcss_api::Webtile; fn main() { // Connect to DCSS Webtile let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 100, "0.32").expect("Failed to connect"); + Webtile::connect("ws://localhost:8080/socket", 100).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} @@ -20,7 +20,7 @@ fn main() { // Write RC File webtile - .set_rc_file("dcss-0.32", "show_more = false\nrest_delay = -1") + .set_rc_file("dcss-0.33", "show_more = false\nrest_delay = -1") .expect("Failed to set RC file."); // Empty message queue; @@ -28,10 +28,10 @@ fn main() { // Read RC File let rc_file = webtile - .get_rc_file("dcss-0.32") + .get_rc_file("dcss-0.33") .expect("Failed to get RC file."); - print!("RC FILE: \n\n {}\n\n", rc_file); + print!("RC FILE: \n\n {rc_file}\n\n"); // Empty message queue; while webtile.get_message().is_some() {} diff --git a/dcss-api/examples/3_cookies.rs b/dcss-api/examples/3_cookies.rs index 168ebb3..a66d79a 100644 --- a/dcss-api/examples/3_cookies.rs +++ b/dcss-api/examples/3_cookies.rs @@ -5,7 +5,7 @@ use dcss_api::Webtile; fn main() { // Connect to DCSS Webtile let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 100, "0.32").expect("Failed to connect"); + Webtile::connect("ws://localhost:8080/socket", 100).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} @@ -21,7 +21,7 @@ fn main() { // Get cookie from the game let cookie = webtile.request_cookie().unwrap(); - println!("{}", cookie); + println!("{cookie}"); // Empty message queue; while webtile.get_message().is_some() {} @@ -31,7 +31,7 @@ fn main() { // Connect (again) to DCSS Webtile let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 100, "0.32").expect("Failed to connect"); + Webtile::connect("ws://localhost:8080/socket", 100).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} diff --git a/dcss-api/examples/4_blocking_error.rs b/dcss-api/examples/4_blocking_error.rs index 7e6342a..9bfe522 100644 --- a/dcss-api/examples/4_blocking_error.rs +++ b/dcss-api/examples/4_blocking_error.rs @@ -6,7 +6,7 @@ use dcss_api::{BlockingError, Error}; fn main() { // Connect to DCSS Webtile let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 100, "0.32").expect("Failed to connect"); + Webtile::connect("ws://localhost:8080/socket", 100).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} @@ -70,7 +70,7 @@ fn main() { // a BlockingError). match webtile.read_until("input_mode", Some("mode"), Some(1)) { Ok(_) => (), - Err(e) => match e { + Err(e) => match *e { Error::Blocking(BlockingError::Pickup) => { println!("Pickup menu pop-up -- decide what to do"); webtile.write_key("key_esc").expect(""); // Esc to ignore it diff --git a/dcss-api/examples/5_bot_core.rs b/dcss-api/examples/5_bot_core.rs index 1caa595..c7804c2 100644 --- a/dcss-api/examples/5_bot_core.rs +++ b/dcss-api/examples/5_bot_core.rs @@ -8,7 +8,7 @@ use std::process; fn main() { // Connect to DCSS Webtile let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 100, "0.32").expect("Failed to connect"); + Webtile::connect("ws://localhost:8080/socket", 100).expect("Failed to connect"); // Log in (to a user called "Username", with a password "Password") let gameid = webtile @@ -40,14 +40,18 @@ fn main() { webtile.disconnect().expect("Failed to disconnect"); } -fn write_key_bot(webtile: &mut Webtile, to_send: &str, to_receive: &str) -> Result<(), APIError> { +fn write_key_bot( + webtile: &mut Webtile, + to_send: &str, + to_receive: &str, +) -> Result<(), Box> { 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 { + match *e { APIError::Blocking(BlockingError::More) => webtile.write_key(" ")?, APIError::Blocking(BlockingError::TextInput) => { println!("ERROR: Likely level up choice"); diff --git a/dcss-api/src/api_errors.rs b/dcss-api/src/api_errors.rs index fd6908c..4fed485 100644 --- a/dcss-api/src/api_errors.rs +++ b/dcss-api/src/api_errors.rs @@ -76,38 +76,40 @@ pub enum BlockingError { /// /// * `message` - The message (as a [serde_json::Value]) received by the /// DCSS webtile. -pub(crate) fn blocking_messages(message: &Value) -> Result<(), Error> { +pub(crate) fn blocking_messages(message: &Value) -> Result<(), Box> { let msg = message["msg"].as_str().unwrap(); match msg { "input_mode" => { if message["mode"].as_u64().unwrap() == 5 { - Err(Error::Blocking(BlockingError::More)) + Err(Box::new(Error::Blocking(BlockingError::More))) } else if message["mode"].as_u64().unwrap() == 7 { - Err(Error::Blocking(BlockingError::TextInput)) + Err(Box::new(Error::Blocking(BlockingError::TextInput))) } else { Ok(()) } } "menu" => { if message["tag"] == "pickup" { - Err(Error::Blocking(BlockingError::Pickup)) + Err(Box::new(Error::Blocking(BlockingError::Pickup))) } else if message["tag"] == "acquirement" { - Err(Error::Blocking(BlockingError::Acquirement(message.clone()))) + Err(Box::new(Error::Blocking(BlockingError::Acquirement( + message.clone(), + )))) } else if message["tag"] == "use_item" { match message["title"]["text"].as_str().unwrap() { - x if x.contains("Identify which item?") => { - Err(Error::Blocking(BlockingError::Identify(message.clone()))) - } - x if x.contains("Enchant which weapon?") => Err(Error::Blocking( + x if x.contains("Identify which item?") => Err(Box::new(Error::Blocking( + BlockingError::Identify(message.clone()), + ))), + x if x.contains("Enchant which weapon?") => Err(Box::new(Error::Blocking( BlockingError::EnchantWeapon(message.clone()), - )), - x if x.contains("Enchant which item?") => { - Err(Error::Blocking(BlockingError::EnchantItem(message.clone()))) - } - x if x.contains("Brand which weapon?") => { - Err(Error::Blocking(BlockingError::BrandWeapon(message.clone()))) - } + ))), + x if x.contains("Enchant which item?") => Err(Box::new(Error::Blocking( + BlockingError::EnchantItem(message.clone()), + ))), + x if x.contains("Brand which weapon?") => Err(Box::new(Error::Blocking( + BlockingError::BrandWeapon(message.clone()), + ))), _ => Ok(()), } } else { @@ -124,7 +126,7 @@ pub(crate) fn blocking_messages(message: &Value) -> Result<(), Error> { .to_owned() .contains("Select the skills to train") { - return Err(Error::Blocking(BlockingError::Skill)); + return Err(Box::new(Error::Blocking(BlockingError::Skill))); } Ok(()) @@ -137,38 +139,38 @@ pub(crate) fn blocking_messages(message: &Value) -> Result<(), Error> { let text = text_obj["text"].as_str().unwrap(); if text.contains("You die...") { - return Err(Error::Blocking(BlockingError::Died)); + return Err(Box::new(Error::Blocking(BlockingError::Died))); } if text.contains("Blink to where?") { - return Err(Error::Blocking(BlockingError::Blink)); + return Err(Box::new(Error::Blocking(BlockingError::Blink))); } if text.contains("Really read the scroll of noise?") { - return Err(Error::Blocking(BlockingError::Noise)); + return Err(Box::new(Error::Blocking(BlockingError::Noise))); } if text.contains("Keep equipping yourself?") { - return Err(Error::Blocking(BlockingError::Equipping)); + return Err(Box::new(Error::Blocking(BlockingError::Equipping))); } if text.contains("Keep disrobing?") { - return Err(Error::Blocking(BlockingError::Disrobing)); + return Err(Box::new(Error::Blocking(BlockingError::Disrobing))); } } Ok(()) } } - "login_fail" => Err(Error::LoginFailed), - "register_fail" => Err(Error::RegisterFailed), + "login_fail" => Err(Box::new(Error::LoginFailed)), + "register_fail" => Err(Box::new(Error::RegisterFailed)), "ui-push" => { if !message.as_object().unwrap().contains_key("type") { Ok(()) } else { if message["type"] == "seed-selection" { - return Err(Error::Blocking(BlockingError::SeedSelection)); + return Err(Box::new(Error::Blocking(BlockingError::SeedSelection))); } else if message["type"] == "newgame-choice" { - return Err(Error::Blocking(BlockingError::NewGameChoice)); + return Err(Box::new(Error::Blocking(BlockingError::NewGameChoice))); } Ok(()) } diff --git a/dcss-api/src/common.rs b/dcss-api/src/common.rs index ecbba7b..4647a82 100644 --- a/dcss-api/src/common.rs +++ b/dcss-api/src/common.rs @@ -71,7 +71,7 @@ pub(crate) fn keys(key: &str) -> Value { pub(crate) fn deflate_to_json( decompressor: &mut Decompress, compressed_msg: &mut Vec, -) -> Result { +) -> Result> { // DCSS Removes 4 bytes that have to be re-added compressed_msg.append(&mut vec![0u8, 0, 255, 255]); diff --git a/dcss-api/src/lib.rs b/dcss-api/src/lib.rs index 84020c9..ca70beb 100644 --- a/dcss-api/src/lib.rs +++ b/dcss-api/src/lib.rs @@ -25,18 +25,26 @@ pub struct Webtile { /// Websocket (using [tungstenite::WebSocket]) to send and receive data from /// [DCSS Webtile](http://crawl.develz.org/wordpress/howto). socket: WebSocket>, + /// A [flate2::Decompress] decompression object (Deflate) to decompress data received /// by [DCSS Webtile](http://crawl.develz.org/wordpress/howto). decompressor: Decompress, + /// [SystemTime] of the last sent message. Used to limit the rate for /// running the bot on someone else's server. last_send: SystemTime, + /// A [bool] of if the searched for data (in the websocket) has been found. message_found: bool, + /// Speed limit in milliseconds between each command sent to DCSS Webtiles. speed_ms: u32, + /// [VecDeque] of messages received from DCSS. received_messages: VecDeque, + + /// The version ("0.33") of the DCSS game, if one was started. + version: Option, } impl Webtile { @@ -48,15 +56,13 @@ impl Webtile { /// * `url` - A [&str] that holds the `ws://` or `wss://` URL /// * `speed_ms` - A [u32] that depicts the speed limit in milliseconds between /// each command sent to DCSS Webtiles. - /// * `_version` - Currently a placeholder for the version number of DCSS, in case - /// the API changes in the future. /// /// # Example /// /// ```no_run - /// let mut webtile = Webtile::connect("ws://localhost:8080/socket", 100, "0.29")?; + /// let mut webtile = Webtile::connect("ws://localhost:8080/socket", 100)?; /// ``` - pub fn connect(url: &str, speed_ms: u32, _version: &str) -> Result { + pub fn connect(url: &str, speed_ms: u32) -> Result> { // Open connection let (socket, _response) = tungstenite::connect(url).map_err(Error::Websocket)?; @@ -72,6 +78,7 @@ impl Webtile { speed_ms, message_found: false, received_messages: VecDeque::new(), + version: None, }; // Wait until the "lobby_complete" message is received -- meaning a @@ -88,7 +95,7 @@ impl Webtile { /// ```no_run /// webtile.disconnect()?; /// ``` - pub fn disconnect(&mut self) -> Result<(), Error> { + pub fn disconnect(&mut self) -> Result<(), Box> { self.socket.close(None).map_err(Error::Websocket)?; Ok(()) @@ -123,7 +130,7 @@ impl Webtile { msg: &str, key: Option<&str>, value: Option, - ) -> Result<(), Error> { + ) -> Result<(), Box> { // loop until break (found expected results or found a blocking type) // use self variable in order to retain the info when there is a blocking error while !self.message_found { @@ -148,7 +155,7 @@ impl Webtile { // Pre-process the data to identify blocking if let Err(e) = blocking_messages(message) { - match e { + match *e { Error::Blocking(BlockingError::Died) => return Err(e), // Automatic return when death _ => blocking = Err(e), } @@ -197,7 +204,7 @@ impl Webtile { /// "password": "Password", /// }))?; /// ``` - pub fn write_json(&mut self, json_val: Value) -> Result<(), Error> { + pub fn write_json(&mut self, json_val: Value) -> Result<(), Box> { // Pause while min time not met while SystemTime::now() .duration_since(self.last_send) @@ -244,7 +251,7 @@ impl Webtile { /// // Send a string of keys that will move left, open a menu and drop an item (slot a) /// webtile.write_key("6iad") /// ``` - pub fn write_key(&mut self, key: &str) -> Result<(), Error> { + pub fn write_key(&mut self, key: &str) -> Result<(), Box> { // Pause while min time not met while SystemTime::now() .duration_since(self.last_send) diff --git a/dcss-api/src/lobby.rs b/dcss-api/src/lobby.rs index 90bd095..4c4690c 100644 --- a/dcss-api/src/lobby.rs +++ b/dcss-api/src/lobby.rs @@ -21,7 +21,7 @@ impl Webtile { &mut self, username: &str, password: &str, - ) -> Result, Error> { + ) -> Result, Box> { self.write_json(json!({ "msg": "login", "username": username, @@ -51,7 +51,7 @@ impl Webtile { /// // Login under the user "Username", with a cookie /// webtile.login_with_cookie("Username%123456789123456789123456789")?; /// ``` - pub fn login_with_cookie(&mut self, cookie: &str) -> Result, Error> { + pub fn login_with_cookie(&mut self, cookie: &str) -> Result, Box> { self.write_json(json!({"msg": "token_login", "cookie": cookie}))?; self.read_until("login_success", None, None)?; @@ -85,13 +85,13 @@ impl Webtile { username: &str, password: &str, email: Option<&str>, - ) -> Result, Error> { + ) -> Result, Box> { self.write_json( json!({"msg": "register", "username": username, "password": password, "email": email.unwrap_or("")}), )?; if let Err(e) = self.read_until("login_success", None, None) { - match e { + match *e { Error::RegisterFailed => self.login_with_credentials(username, password)?, _ => Err(e)?, }; @@ -112,7 +112,7 @@ impl Webtile { /// ```no_run /// webtile.request_cookie()?; /// ``` - pub fn request_cookie(&mut self) -> Result { + pub fn request_cookie(&mut self) -> Result> { self.write_json(json!({"msg": "set_login_cookie"}))?; self.read_until("login_cookie", None, None)?; @@ -138,7 +138,7 @@ impl Webtile { /// ```no_run /// webtile.get_rc_file("dcss-web-trunk")?; /// ``` - pub fn get_rc_file(&mut self, game_id: &str) -> Result { + pub fn get_rc_file(&mut self, game_id: &str) -> Result> { self.write_json(json!({"msg": "get_rc", "game_id": game_id}))?; self.read_until("rcfile_contents", None, None)?; @@ -165,7 +165,7 @@ impl Webtile { /// ```no_run /// webtile.set_rc_file("dcss-web-trunk", "show_more = false\nrest_delay = -1")?; /// ``` - pub fn set_rc_file(&mut self, game_id: &str, content: &str) -> Result<(), Error> { + pub fn set_rc_file(&mut self, game_id: &str, content: &str) -> Result<(), Box> { self.write_json(json!({"msg": "set_rc", "game_id": game_id, "contents": content}))?; Ok(()) diff --git a/dcss-api/src/play.rs b/dcss-api/src/play.rs index cfd4fb0..51724b8 100644 --- a/dcss-api/src/play.rs +++ b/dcss-api/src/play.rs @@ -1,6 +1,6 @@ -use crate::api_errors::BlockingError; use crate::Error; use crate::Webtile; +use crate::api_errors::BlockingError; use serde_json::json; impl Webtile { @@ -26,7 +26,7 @@ impl Webtile { species: &str, background: &str, weapon: &str, - ) -> Result<(), Error> { + ) -> Result<(), Box> { self.start_game_seeded(game_id, "0", false, species, background, weapon) } @@ -42,7 +42,7 @@ impl Webtile { /// // Continue a game on "dcss-web-trunk" /// webtile.continue_game("dcss-web-trunk")?; /// ``` - pub fn continue_game(&mut self, game_id: &str) -> Result<(), Error> { + pub fn continue_game(&mut self, game_id: &str) -> Result<(), Box> { self.start_game_seeded(game_id, "", false, "", "", "") } @@ -73,14 +73,29 @@ impl Webtile { species: &str, background: &str, weapon: &str, - ) -> Result<(), Error> { + ) -> Result<(), Box> { self.write_json(json!({"msg": "play", "game_id": game_id}))?; let mut newgame_count = 0; loop { match self.read_until("map", None, None) { - Ok(_) => return Ok(()), - Err(e) => match e { + Ok(_) => { + // Get version of game (for API differences) + if self.version.is_none() { + for message in self.read_only_messages() { + let message_obj = message.as_object().unwrap(); + if message_obj["msg"] == "version" { + let text = message_obj["text"].as_str().unwrap(); + let long_version = text.split(" ").collect::>()[4]; + let version = + long_version.split(".").collect::>()[0..2].join("."); + self.version = Some(version); + } + } + } + return Ok(()); + } + Err(e) => match *e { Error::Blocking(BlockingError::SeedSelection) => { self.write_key("-")?; self.read_until("ui-state-sync", None, None)?; @@ -107,6 +122,18 @@ impl Webtile { } } + /// Get version of the DCSS game (e.g. "0.33"). Will return `None` if + /// the game has not been started. + /// + /// # Example + /// + /// ```no_run + /// webtile.game_version()?; + /// ``` + pub fn game_version(&self) -> Option { + self.version.clone() + } + /// Save a game by sending the `CTRL + S` command. /// /// # Example @@ -114,7 +141,7 @@ impl Webtile { /// ```no_run /// webtile.save_game()?; /// ``` - pub fn save_game(&mut self) -> Result<(), Error> { + pub fn save_game(&mut self) -> Result<(), Box> { self.write_key("key_ctrl_s")?; self.read_until("go_lobby", None, None)?; @@ -130,14 +157,18 @@ impl Webtile { /// ```no_run /// webtile.quit_game()?; /// ``` - pub fn quit_game(&mut self) -> Result<(), Error> { + pub fn quit_game(&mut self) -> Result<(), Box> { self.write_key("key_ctrl_q")?; match self.read_until("input_mode", Some("mode"), Some(7)) { Ok(_) => (), - Err(e) => match e { + Err(e) => match *e { Error::Blocking(BlockingError::TextInput) => { - self.write_key("yes")?; + if self.version == Some("0.33".to_string()) { + self.write_key("quit")?; + } else { + self.write_key("yes")?; + } self.write_key("key_enter")?; self.message_found = false; // Otherwise close_input will be skipped } @@ -147,7 +178,7 @@ impl Webtile { match self.read_until("close_input", None, None) { Ok(_) => (), - Err(e) => match e { + Err(e) => match *e { Error::Blocking(BlockingError::More) => self.write_key("key_esc")?, _ => return Err(e), }, @@ -157,7 +188,7 @@ impl Webtile { self.write_key("key_esc")?; match self.read_until("go_lobby", None, None) { Ok(_) => return Ok(()), - Err(e) => match e { + Err(e) => match *e { Error::Blocking(BlockingError::More) => (), _ => return Err(e), }, diff --git a/dcss-api/tests/common.rs b/dcss-api/tests/common.rs index e346f72..82301d6 100644 --- a/dcss-api/tests/common.rs +++ b/dcss-api/tests/common.rs @@ -4,8 +4,7 @@ use dcss_api::Webtile; pub(crate) fn reset_test(username: &str, game_id: &str) { // Connect to DCSS Webtile - let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect"); + let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} diff --git a/dcss-api/tests/connect_test.rs b/dcss-api/tests/connect_test.rs index 0c3606b..fd8cd16 100644 --- a/dcss-api/tests/connect_test.rs +++ b/dcss-api/tests/connect_test.rs @@ -1,10 +1,10 @@ use dcss_api::{Error, Webtile}; -use serde_json::{from_str, Value}; +use serde_json::{Value, from_str}; #[test] fn successful_connect() { let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect."); + Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect."); let json: Value = from_str("{\"msg\":\"ping\"}").unwrap(); assert_eq!(Some(json), webtile.get_message()); @@ -19,9 +19,10 @@ fn successful_connect() { #[test] fn failed_connect() { - let webtile = Webtile::connect("ws://localhost:XXXX/socket", 0, "0.32"); - assert!(matches!(webtile, Err(Error::Websocket(_)))); + let webtile = Webtile::connect("ws://localhost:XXXX/socket", 0); + assert!(matches!(*webtile.err().unwrap(), Error::Websocket(_))); - let webtile = Webtile::connect("ws://localhost:0000/socket", 0, "0.32"); - assert!(matches!(webtile, Err(Error::Websocket(_)))); + let webtile = Webtile::connect("ws://localhost:0000/socket", 0); + + assert!(matches!(*webtile.err().unwrap(), Error::Websocket(_))); } diff --git a/dcss-api/tests/login_test.rs b/dcss-api/tests/login_test.rs index 2459579..9da0f23 100644 --- a/dcss-api/tests/login_test.rs +++ b/dcss-api/tests/login_test.rs @@ -1,10 +1,10 @@ use dcss_api::{Error, Webtile}; -use serde_json::{from_str, Value}; +use serde_json::{Value, from_str}; #[test] fn successful_credential_login() { let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect."); + Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect."); // Empty message queue; while webtile.get_message().is_some() {} @@ -26,7 +26,7 @@ fn successful_credential_login() { #[test] fn multiple_login_same_user() { let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect."); + Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect."); // Empty message queue; while webtile.get_message().is_some() {} @@ -71,19 +71,19 @@ fn multiple_login_same_user() { #[test] fn multiple_login_diff_user() { let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect."); + Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect."); // Empty message queue; while webtile.get_message().is_some() {} let _ = webtile - .login_with_credentials("Username", "Password") + .login_with_credentials("Username1", "Password") .expect("Login failed."); let _ = webtile.get_message(); let json: Value = - from_str("{\"admin\": false, \"msg\": \"login_success\", \"username\": \"Username\"}") + from_str("{\"admin\": false, \"msg\": \"login_success\", \"username\": \"Username1\"}") .unwrap(); assert_eq!(Some(json), webtile.get_message()); @@ -116,14 +116,14 @@ fn multiple_login_diff_user() { #[test] fn failed_credential_login() { let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect."); + Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect."); // Empty message queue; while webtile.get_message().is_some() {} let result = webtile.login_with_credentials("XXXXXXX", "XXXXXXX"); - assert!(matches!(result, Err(Error::LoginFailed))); + assert!(matches!(*result.err().unwrap(), Error::LoginFailed)); webtile.disconnect().expect("Failed to disconnect"); } @@ -131,13 +131,13 @@ fn failed_credential_login() { #[test] fn failed_credential_login_and_retry() { let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect."); + Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect."); // Empty message queue; while webtile.get_message().is_some() {} let result = webtile.login_with_credentials("XXXXXXX", "XXXXXXX"); - assert!(matches!(result, Err(Error::LoginFailed))); + assert!(matches!(*result.err().unwrap(), Error::LoginFailed)); while webtile.get_message().is_some() {} @@ -156,8 +156,7 @@ fn failed_credential_login_and_retry() { #[test] fn get_cookie_and_login() { // Connect to DCSS Webtile - let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect"); + let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} @@ -183,8 +182,7 @@ fn get_cookie_and_login() { webtile.disconnect().expect("Failed to disconnect."); // Connect (again) to DCSS Webtile - let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect"); + let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} @@ -207,15 +205,14 @@ fn get_cookie_and_login() { #[test] fn failed_cookie_login() { // Connect to DCSS Webtile - let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect"); + let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} // Login with cookie let result = webtile.login_with_cookie("Username%123456789123456789123456789"); - assert!(matches!(result, Err(Error::LoginFailed))); + assert!(matches!(*result.err().unwrap(), Error::LoginFailed)); webtile.disconnect().expect("Failed to disconnect"); } @@ -223,8 +220,7 @@ fn failed_cookie_login() { #[test] fn using_old_cookie_login() { // Connect to DCSS Webtile - let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect"); + let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} @@ -250,8 +246,7 @@ fn using_old_cookie_login() { webtile.disconnect().expect("Failed to disconnect."); // Connect to DCSS Webtile - let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect"); + let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} @@ -277,8 +272,7 @@ fn using_old_cookie_login() { webtile.disconnect().expect("Failed to disconnect."); // Connect to DCSS Webtile - let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect"); + let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} @@ -286,7 +280,7 @@ fn using_old_cookie_login() { // Login with cookie let result = webtile.login_with_cookie(first_cookie.as_str()); - assert!(matches!(result, Err(Error::LoginFailed))); + assert!(matches!(*result.err().unwrap(), Error::LoginFailed)); webtile.disconnect().expect("Failed to disconnect"); } @@ -294,7 +288,7 @@ fn using_old_cookie_login() { #[test] fn credential_login_gameid() { let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect."); + Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect."); // Empty message queue; while webtile.get_message().is_some() {} @@ -308,6 +302,7 @@ fn credential_login_gameid() { "dcss-0.30".to_owned(), "dcss-0.31".to_owned(), "dcss-0.32".to_owned(), + "dcss-0.33".to_owned(), ]; assert_eq!(gameid, test_gameid); @@ -317,7 +312,7 @@ fn credential_login_gameid() { #[test] fn cookie_login_gameid() { let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect."); + Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect."); // Empty message queue; while webtile.get_message().is_some() {} @@ -331,6 +326,7 @@ fn cookie_login_gameid() { "dcss-0.30".to_owned(), "dcss-0.31".to_owned(), "dcss-0.32".to_owned(), + "dcss-0.33".to_owned(), ]; assert_eq!(gameid, test_gameid); @@ -343,8 +339,7 @@ fn cookie_login_gameid() { webtile.disconnect().expect("Failed to disconnect."); // Connect (again) to DCSS Webtile - let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect"); + let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} @@ -359,6 +354,7 @@ fn cookie_login_gameid() { "dcss-0.30".to_owned(), "dcss-0.31".to_owned(), "dcss-0.32".to_owned(), + "dcss-0.33".to_owned(), ]; assert_eq!(gameid, test_gameid); diff --git a/dcss-api/tests/rc_file_test.rs b/dcss-api/tests/rc_file_test.rs index d0d1283..e6cb5ba 100644 --- a/dcss-api/tests/rc_file_test.rs +++ b/dcss-api/tests/rc_file_test.rs @@ -2,10 +2,10 @@ use dcss_api::Webtile; #[test] fn write_read_rc() { - let game_id = std::env::var("GAME_ID").unwrap(); + let game_id = std::env::var("GAME_ID").unwrap_or("dcss-0.33".to_owned()); let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect."); + Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect."); // Empty message queue; while webtile.get_message().is_some() {} @@ -45,10 +45,10 @@ fn write_read_rc() { #[test] fn blank_rc_file() { - let game_id = std::env::var("GAME_ID").unwrap(); + let game_id = std::env::var("GAME_ID").unwrap_or("dcss-0.33".to_owned()); let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect."); + Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect."); // Empty message queue; while webtile.get_message().is_some() {} diff --git a/dcss-api/tests/start_game_test.rs b/dcss-api/tests/start_game_test.rs index 8229a5f..009b89f 100644 --- a/dcss-api/tests/start_game_test.rs +++ b/dcss-api/tests/start_game_test.rs @@ -5,14 +5,13 @@ use serde_json::from_str; #[test] fn start_game_seeded() { - let game_id = std::env::var("GAME_ID").unwrap(); + let game_id = std::env::var("GAME_ID").unwrap_or("dcss-0.33".to_owned()); // Safe test -- login start game, quit, and then test common::reset_test("Username", game_id.as_str()); // Connect to DCSS Webtile - let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect"); + let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} @@ -38,17 +37,18 @@ fn start_game_seeded() { } } - assert!(msgs["messages"] - .to_string() - .contains("Game seed: 1 (custom seed)")); + assert!( + msgs["messages"] + .to_string() + .contains("Game seed: 1 (custom seed)") + ); webtile.quit_game().expect("Failed to quit game"); webtile.disconnect().expect("Failed to disconnect"); // Connect to DCSS Webtile - let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect"); + let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} @@ -74,9 +74,11 @@ fn start_game_seeded() { } } - assert!(msgs["messages"] - .to_string() - .contains("Game seed: 158985 (custom seed)")); + assert!( + msgs["messages"] + .to_string() + .contains("Game seed: 158985 (custom seed)") + ); webtile.quit_game().expect("Failed to quit game"); @@ -85,14 +87,13 @@ fn start_game_seeded() { #[test] fn start_game() { - let game_id = std::env::var("GAME_ID").unwrap(); + let game_id = std::env::var("GAME_ID").unwrap_or("dcss-0.33".to_owned()); // Safe test -- login start game, quit, and then test common::reset_test("Username", game_id.as_str()); // Connect to DCSS Webtile - let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect"); + let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} @@ -134,14 +135,13 @@ fn start_game() { #[test] fn save_game_continue() { - let game_id = std::env::var("GAME_ID").unwrap(); + let game_id = std::env::var("GAME_ID").unwrap_or("dcss-0.33".to_owned()); // Safe test -- login start game, quit, and then test common::reset_test("Username", game_id.as_str()); // Connect to DCSS Webtile - let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect"); + let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} @@ -195,14 +195,13 @@ fn save_game_continue() { #[test] fn start_game_two_accounts() { - let game_id = std::env::var("GAME_ID").unwrap(); + let game_id = std::env::var("GAME_ID").unwrap_or("dcss-0.33".to_owned()); // Safe test -- login start game, quit, and then test common::reset_test("Username", game_id.as_str()); // Connect to DCSS Webtile - let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect"); + let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} @@ -245,8 +244,7 @@ fn start_game_two_accounts() { common::reset_test("Username2", game_id.as_str()); // Connect to DCSS Webtile - let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect"); + let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} @@ -288,7 +286,7 @@ fn start_game_two_accounts() { #[test] fn start_game_two_accounts_combined() { - let game_id = std::env::var("GAME_ID").unwrap(); + let game_id = std::env::var("GAME_ID").unwrap_or("dcss-0.33".to_owned()); // Safe test -- login start game, quit, and then test common::reset_test("Username", game_id.as_str()); @@ -296,9 +294,9 @@ fn start_game_two_accounts_combined() { // Connect to DCSS Webtile let mut webtile1 = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect"); + Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect"); let mut webtile2 = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect"); + Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect"); // Empty message queue; while webtile1.get_message().is_some() {} @@ -368,14 +366,13 @@ fn start_game_two_accounts_combined() { #[test] fn real_blocking_error() { - let game_id = std::env::var("GAME_ID").unwrap(); + let game_id = std::env::var("GAME_ID").unwrap_or("dcss-0.33".to_owned()); // Safe test -- login start game, quit, and then test common::reset_test("Username", game_id.as_str()); // Connect to DCSS Webtile - let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect"); + let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} @@ -423,8 +420,8 @@ fn real_blocking_error() { let result = webtile.read_until("whatever", None, None); assert!(matches!( - result, - Err(Error::Blocking(BlockingError::Pickup)) + *result.err().unwrap(), + Error::Blocking(BlockingError::Pickup) )); // Ignore the menu after all diff --git a/dcss-data/.cargo/config.toml b/dcss-data/.cargo/config.toml deleted file mode 100644 index d500958..0000000 --- a/dcss-data/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[env] -RUST_TEST_THREADS = "1" \ No newline at end of file diff --git a/dcss-data/Cargo.lock b/dcss-data/Cargo.lock index 7fa0e20..f04921a 100644 --- a/dcss-data/Cargo.lock +++ b/dcss-data/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aho-corasick" @@ -19,9 +19,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "block-buffer" @@ -40,18 +40,19 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" -version = "1.2.16" +version = "1.2.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" dependencies = [ + "find-msvc-tools", "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "core-foundation" @@ -80,9 +81,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] @@ -99,15 +100,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] name = "dcss-api" -version = "0.2.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc93b44b2084b09f5d319197738860dbad7de0f8bf30080dcbb4f8656c845e62" +checksum = "1aba1fba55c01f3a9def4ef09d68ed1557c20bf7d19163b54676b8ef7d5b9800" dependencies = [ "flate2", "serde_json", @@ -117,7 +118,7 @@ dependencies = [ [[package]] name = "dcss-data" -version = "0.1.0" +version = "0.4.0" dependencies = [ "dcss-api", "dcss-scenario-builder", @@ -128,9 +129,9 @@ dependencies = [ [[package]] name = "dcss-scenario-builder" -version = "0.2.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eeeda5b5ce8794031f39e0b527763eedb935f8863503c3786170ee15ebd9430" +checksum = "10e374b025e1e4d2eabebbbed24d3521f2b852f1215ab74f813c4fc4610a663f" dependencies = [ "dcss-api", "itertools", @@ -163,9 +164,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", "windows-sys", @@ -177,11 +178,17 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "find-msvc-tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" + [[package]] name = "flate2" -version = "1.1.0" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" dependencies = [ "crc32fast", "libz-sys", @@ -221,27 +228,27 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", + "r-efi", "wasi", - "windows-targets", ] [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "http" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", @@ -256,9 +263,9 @@ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "indexmap" -version = "2.7.1" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", "hashbrown", @@ -281,15 +288,15 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "libc" -version = "0.2.170" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libz-sys" -version = "1.1.21" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" dependencies = [ "cc", "pkg-config", @@ -298,29 +305,30 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.9.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "log" -version = "0.4.26" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "miniz_oxide" -version = "0.8.5" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -342,15 +350,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "openssl" -version = "0.10.71" +version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ "bitflags", "cfg-if", @@ -380,18 +388,18 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-src" -version = "300.4.2+3.4.1" +version = "300.5.3+3.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168ce4e058f975fe43e89d9ccf78ca668601887ae736090aacc23ae353c298e2" +checksum = "dc6bad8cd0233b63971e232cc9c5e83039375b8586d2312f31fda85db8f888c2" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.106" +version = "0.9.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" dependencies = [ "cc", "libc", @@ -417,31 +425,36 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.39" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha", "rand_core", - "zerocopy", ] [[package]] @@ -465,9 +478,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.1" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "4a52d8d02cacdb176ef4678de6c052efb4b3da14b78e4db683a4252762be5433" dependencies = [ "aho-corasick", "memchr", @@ -477,9 +490,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "722166aa0d7438abbaa4d5cc2c649dac844e8c56d82fb3d33e9c34b5cd268fc6" dependencies = [ "aho-corasick", "memchr", @@ -488,9 +501,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "c3160422bbd54dd5ecfdca71e5fd59b7b8fe2b1697ab2baf64f6d05dcc66d298" [[package]] name = "rustc-hash" @@ -500,9 +513,9 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustix" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ "bitflags", "errno", @@ -519,9 +532,9 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ "windows-sys", ] @@ -541,9 +554,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -551,18 +564,27 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -571,14 +593,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] @@ -611,11 +634,17 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "syn" -version = "2.0.100" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -624,11 +653,10 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.18.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c317e0a526ee6120d8dabad239c8dadca62b24b6f168914bbbc8e2fb1f0e567" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ - "cfg-if", "fastrand", "getrandom", "once_cell", @@ -638,18 +666,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -658,9 +686,9 @@ dependencies = [ [[package]] name = "tungstenite" -version = "0.26.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" dependencies = [ "bytes", "data-encoding", @@ -676,15 +704,15 @@ dependencies = [ [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unsafe-libyaml" @@ -712,109 +740,57 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" +version = "0.14.7+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" dependencies = [ - "wit-bindgen-rt", + "wasip2", ] [[package]] -name = "windows-sys" -version = "0.59.0" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "windows-targets", + "wit-bindgen", ] [[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] [[package]] -name = "wit-bindgen-rt" -version = "0.33.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" -dependencies = [ - "bitflags", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "zerocopy" -version = "0.8.23" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.23" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", diff --git a/dcss-data/Cargo.toml b/dcss-data/Cargo.toml index faecc03..1b655be 100644 --- a/dcss-data/Cargo.toml +++ b/dcss-data/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "dcss-data" -version = "0.1.0" -edition = "2021" +version = "0.4.0" +edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -16,5 +16,5 @@ rustc-hash = "2.0" regex = "1.10" [dev-dependencies] -dcss-api = "0.2" -dcss-scenario-builder = "0.2" \ No newline at end of file +dcss-api = "0.4" +dcss-scenario-builder = "0.4" \ No newline at end of file diff --git a/dcss-data/src/abilities.rs b/dcss-data/src/abilities.rs index 786a083..cc15d47 100644 --- a/dcss-data/src/abilities.rs +++ b/dcss-data/src/abilities.rs @@ -1,8 +1,11 @@ use rustc_hash::FxHashMap; use serde_json::Value; +use crate::CrawlData; + #[derive(Debug)] pub(crate) struct Abilities { + pub(crate) stale: bool, pub(crate) abilities: FxHashMap, } @@ -16,6 +19,7 @@ pub(crate) struct Ability { impl Abilities { pub(crate) fn new() -> Self { Self { + stale: false, abilities: FxHashMap::default(), } } @@ -39,6 +43,16 @@ impl Abilities { } } } + + // For when abilities are used, piety will go down, and some may no longer + // be available to use. Need to re-check. + pub(crate) fn make_abilities_stale(&mut self) { + self.stale = true; + } + + pub(crate) fn make_abilities_current(&mut self) { + self.stale = false; + } } impl Ability { @@ -50,3 +64,21 @@ impl Ability { } } } + +impl CrawlData { + pub fn process_ability_menu(&mut self, menu_items: Value) { + self.abilities.process_ability_menu(menu_items); + } + + pub fn has_ability(&self, ability: &str) -> bool { + self.abilities.abilities.contains_key(ability) + } + + pub fn key_of_ability(&self, ability: &str) -> String { + self.abilities.abilities[ability].key.to_owned() + } + + pub fn abilities_stale(&self) -> bool { + self.abilities.stale + } +} diff --git a/dcss-data/src/common.rs b/dcss-data/src/common.rs index aa0e3f0..f3eda85 100644 --- a/dcss-data/src/common.rs +++ b/dcss-data/src/common.rs @@ -5,8 +5,8 @@ use crate::tiles::Tile; use std::collections::VecDeque; // Type used in the data, stands for (x, y) on a 2d grid -pub type Coord = (usize, usize); -pub type CoordVec = Vec<(usize, usize)>; +pub type AbsCoord = (usize, usize); +pub type RelCoord = (i32, i32); /// Add a [i32] (including negative) to an [usize]. Returns a [usize]. /// @@ -109,10 +109,10 @@ pub(crate) fn extract_param( let mut end_index: usize = 1_000_000; for end in extract_until { let temp = searchable[start_index..].find(*end); - if let Some(value) = temp { - if value < end_index { - end_index = value; - } + if let Some(value) = temp + && value < end_index + { + end_index = value; }; } if end_index == 1_000_000 { @@ -164,6 +164,49 @@ pub(crate) fn structured_table(table: Value) -> FxHashMap) -> Vec { + // Each step is relative to the previous step (the first one relative + // to the player) + + let mut relative_coords = vec![]; + let mut cum_change = (0, 0); + + let mut coords = coords; + coords.reverse(); + + for coord in coords { + let relative_coord = ( + (coord.0 as i32 - cum_change.0 - pos.0 as i32), + (coord.1 as i32 - cum_change.1 - pos.1 as i32), + ); + + cum_change = ( + cum_change.0 + relative_coord.0, + cum_change.1 + relative_coord.1, + ); + + relative_coords.push(relative_coord); + } + + relative_coords.reverse(); + + relative_coords +} + +pub(crate) fn convert_coord_to_absolute(pos: AbsCoord, coord: RelCoord) -> AbsCoord { + ( + add_i32_to_usize(coord.0, pos.0), + add_i32_to_usize(coord.1, pos.1), + ) +} + +pub(crate) fn convert_coord_to_relative(pos: AbsCoord, coord: AbsCoord) -> RelCoord { + ( + (coord.0 as i32 - pos.0 as i32), + (coord.1 as i32 - pos.1 as i32), + ) +} + #[derive(Debug)] /// Struct for each node for the A* algorithm. struct Node { @@ -174,9 +217,9 @@ struct Node { /// Number of estimated moves necessary to get to goal. moves_to_goal: u64, /// Coordinates (x, y) of the node in the &Vec> object. - location: Coord, + location: AbsCoord, /// Coordinates (x, y) of the node that is being searched in the &Vec> object. - end_goal: Option, + end_goal: Option, /// The location in the list of nodes (explored) that the parent node is found. parent_node: Option, /// Extra key to make ordering deterministic @@ -213,20 +256,20 @@ impl Node { /// * `max_path` - maximum path steps (made to speed up when looking dozens of time per action). pub(crate) fn pathfinding( tiles: &[Vec], - start_location: Coord, - end_location: Option, + start_location: AbsCoord, + end_location: Option, end_search_mf: Option, end_search_type: Option<&'static str>, max_path: u64, ignore_blocked: bool, -) -> Vec { +) -> Vec { // Create a list of all nodes let mut explored: Vec = vec![]; // Has the final_path been found let mut final_path = None; - // open is a list of Nodes not yet checked by A*. + // Open is a list of Nodes not yet checked by A*. let mut open: VecDeque = VecDeque::new(); // Extra key to make ordering deterministic @@ -246,8 +289,8 @@ pub(crate) fn pathfinding( open.push_back(first_node); key_break += 1; - // Create a closed set of Nodes already checked by A*.\ - let mut closed: Vec = Vec::new(); + // Create a closed set of Nodes already checked by A*. + let mut closed: Vec = Vec::new(); closed.push(start_location); let dir_list = [ @@ -284,20 +327,23 @@ pub(crate) fn pathfinding( closed.push((curr_x, curr_y)); // Has the end been found (all types) - if let Some(end_type) = end_search_mf { - if tiles[curr_x][curr_y].mf == end_type { - end_found = true; - } + if let Some(end_type) = end_search_mf + && tiles[curr_x][curr_y].mf == end_type + { + end_found = true; } - if let Some(end_type) = end_search_type { - if end_type == "unexplored" && !tiles[curr_x][curr_y].explored { - end_found = true; - } + + if let Some(end_type) = end_search_type + && end_type == "unexplored" + && !tiles[curr_x][curr_y].explored + { + end_found = true; } - if let Some(end_type) = end_location { - if (curr_x, curr_y) == end_type { - end_found = true; - } + + if let Some(end_type) = end_location + && (curr_x, curr_y) == end_type + { + end_found = true; } let walkable = if ignore_blocked { diff --git a/dcss-data/src/inventory.rs b/dcss-data/src/inventory.rs index bec3c87..58974a7 100644 --- a/dcss-data/src/inventory.rs +++ b/dcss-data/src/inventory.rs @@ -1,14 +1,14 @@ use rustc_hash::FxHashMap; use serde_json::Value; +use crate::CrawlData; use crate::common::{char_to_index, extract_param}; use crate::items::Item; -use crate::CrawlData; use crate::items::armours::Armour; use crate::items::jewellery::Jewellery; use crate::items::missiles::Missile; -use crate::items::potions::{type_of_potion, Potion}; +use crate::items::potions::{Potion, type_of_potion}; use crate::items::scrolls::Scroll; use crate::items::staves::Staff; use crate::items::wands::Wand; @@ -148,7 +148,7 @@ impl Inventory { } } - pub(crate) fn description(&mut self, description: Value) { + pub(crate) fn description(&mut self, description: &Value) { let key = &description["title"].to_string()[1..2]; match &mut self.items[char_to_index(key)] { Item::None => (), diff --git a/dcss-data/src/items.rs b/dcss-data/src/items.rs index ec973d9..d73c360 100644 --- a/dcss-data/src/items.rs +++ b/dcss-data/src/items.rs @@ -33,21 +33,6 @@ pub(crate) enum Item { Staff(Staff), } -#[derive(Clone, Debug)] -pub(crate) enum WearSlots { - Weapon, - Cloak, - Helmet, - Gloves, - Boots, - Shield, - Body, - _RingLeft, - _RingRight, - Amulet, - _Unknown4, -} - impl Item { pub(crate) fn is_none(&self) -> bool { matches!(self, Self::None) diff --git a/dcss-data/src/items/armours.rs b/dcss-data/src/items/armours.rs index 0deeda3..09d4534 100644 --- a/dcss-data/src/items/armours.rs +++ b/dcss-data/src/items/armours.rs @@ -34,7 +34,7 @@ impl Armour { } } - pub(crate) fn update_armour(&mut self, armour_desc: Value) { + pub(crate) fn update_armour(&mut self, armour_desc: &Value) { self.data_collected = true; let body = armour_desc["body"].to_string(); diff --git a/dcss-data/src/items/jewellery.rs b/dcss-data/src/items/jewellery.rs index 1c15240..76501a0 100644 --- a/dcss-data/src/items/jewellery.rs +++ b/dcss-data/src/items/jewellery.rs @@ -62,7 +62,7 @@ impl Jewellery { } } - pub(crate) fn update_jewellery(&mut self, jewellery_desc: Value) { + pub(crate) fn update_jewellery(&mut self, jewellery_desc: &Value) { self.data_collected = true; let title = jewellery_desc["title"].to_string(); diff --git a/dcss-data/src/items/potions.rs b/dcss-data/src/items/potions.rs index c4dd454..22ec196 100644 --- a/dcss-data/src/items/potions.rs +++ b/dcss-data/src/items/potions.rs @@ -39,7 +39,7 @@ impl Potion { } } - pub(crate) fn update_potion(&mut self, description: Value) { + pub(crate) fn update_potion(&mut self, description: &Value) { self.data_collected = true; if description["body"] diff --git a/dcss-data/src/items/scrolls.rs b/dcss-data/src/items/scrolls.rs index 891b8a1..ac37365 100644 --- a/dcss-data/src/items/scrolls.rs +++ b/dcss-data/src/items/scrolls.rs @@ -42,7 +42,7 @@ impl Scroll { } } - pub(crate) fn update_scroll(&mut self, description: Value) { + pub(crate) fn update_scroll(&mut self, description: &Value) { self.data_collected = true; if description["body"] diff --git a/dcss-data/src/items/weapons.rs b/dcss-data/src/items/weapons.rs index 17c0b6a..6206c5b 100644 --- a/dcss-data/src/items/weapons.rs +++ b/dcss-data/src/items/weapons.rs @@ -39,7 +39,7 @@ impl Weapon { } } - pub(crate) fn update_weapon(&mut self, weapon_desc: Value) { + pub(crate) fn update_weapon(&mut self, weapon_desc: &Value) { self.data_collected = true; let body = weapon_desc["body"].to_string(); diff --git a/dcss-data/src/lib.rs b/dcss-data/src/lib.rs index 391ca3b..206e346 100644 --- a/dcss-data/src/lib.rs +++ b/dcss-data/src/lib.rs @@ -12,15 +12,15 @@ mod player; mod skills; mod tiles; -pub use crate::common::Coord; +pub use crate::common::RelCoord; use crate::abilities::Abilities; -use crate::common::{pathfinding, structured_table}; +use crate::common::{convert_coords_to_relative, pathfinding, structured_table}; use crate::inventory::Inventory; +use crate::items::Item; use crate::items::armours::ArmourType; use crate::items::jewellery::AmuletType; use crate::items::scrolls::ScrollType; -use crate::items::{Item, WearSlots}; use crate::log::Log; use crate::menus::Menus; use crate::monsters::Monsters; @@ -30,8 +30,13 @@ use crate::skills::Skills; use crate::tiles::Tiles; use std::error::Error; +use common::convert_coord_to_absolute; +use common::convert_coord_to_relative; use serde_json::Value; +/// Max floor size +const MAX_FLOOR_SIZE: usize = 500; + #[derive(Debug)] pub struct CrawlData { /// Field of view (FOV) of the character for item pickup, battle mechanics, @@ -60,7 +65,7 @@ pub struct CrawlData { } impl CrawlData { - pub fn init(fov: u32, _version: &str) -> Self { + pub fn init(fov: u32) -> Self { Self { fov, spectators: 0, @@ -83,6 +88,8 @@ impl CrawlData { // Ignore "ping" => (), "lobby_clear" => (), + "lobby_entry" => (), + "lobby_remove" => (), "go_lobby" => (), "html" => (), "set_game_links" => (), @@ -193,7 +200,7 @@ impl CrawlData { "newgame-choice" => (), "describe-item" => { self.identify_menu_as_opened(); - self.inventory_description(message.clone()); + self.item_description(message.clone()); } "describe-monster" => { if self.monsters.examine_loc.is_none() { @@ -201,7 +208,8 @@ impl CrawlData { } self.identify_menu_as_opened(); - self.monster_description(message.clone(), self.monsters.examine_loc.unwrap()); + self.monsters + .description(self.monsters.examine_loc.unwrap(), message.clone()); self.monsters.examine_loc = None; } _ => (), @@ -244,11 +252,11 @@ impl CrawlData { self.pickup.update(ground_item_coord); } - for invis_coord in extra_data.2 .0 { + for invis_coord in extra_data.2.0 { self.monsters.invisible_monster(invis_coord) } - for invis_rm_coord in extra_data.2 .1 { + for invis_rm_coord in extra_data.2.1 { self.monsters.invisible_removed(invis_rm_coord) } @@ -263,10 +271,6 @@ impl CrawlData { .update_pos(message["pos"]["x"].clone(), message["pos"]["y"].clone()); }; - if message_obj.contains_key("equip") { - self.player.update_equipped(message["equip"].clone()) - } - if message_obj.contains_key("status") { self.player.update_status(message["status"].clone()); } @@ -288,14 +292,14 @@ impl CrawlData { pub fn index_of_equipped(&self, wear_type: &str) -> i32 { match wear_type { - "Weapon" => self.player.equipped[WearSlots::Weapon as usize], - "Amulet" => self.player.equipped[WearSlots::Amulet as usize], - "Body" => self.player.equipped[WearSlots::Body as usize], - "Boots" => self.player.equipped[WearSlots::Boots as usize], - "Cloak" => self.player.equipped[WearSlots::Cloak as usize], - "Helmet" => self.player.equipped[WearSlots::Helmet as usize], - "Shield" => self.player.equipped[WearSlots::Shield as usize], - "Gloves" => self.player.equipped[WearSlots::Gloves as usize], + "Weapon" => self.player.equipped.weapon, + "Amulet" => self.player.equipped.amulet, + "Body" => self.player.equipped.body, + "Boots" => self.player.equipped.boots, + "Cloak" => self.player.equipped.cloak, + "Helmet" => self.player.equipped.helmet, + "Shield" => self.player.equipped.shield, + "Gloves" => self.player.equipped.gloves, _ => unimplemented!("TODO"), } } @@ -385,30 +389,17 @@ impl CrawlData { self.inventory.process_known_item_menu(known_item_menu); } - pub fn inventory_description(&mut self, description: Value) { - self.inventory.description(description); - } - - pub fn monster_description(&mut self, description: Value, pos: Coord) { - self.monsters.description(description, pos); - } - - pub fn process_ability_menu(&mut self, menu_items: Value) { - self.abilities.process_ability_menu(menu_items); - } + pub fn item_description(&mut self, description: Value) { + self.inventory.description(&description); - pub fn has_ability(&self, ability: &str) -> bool { - self.abilities.abilities.contains_key(ability) + self.player + .equipped_from_description(&self.inventory, &description); } pub fn has_status(&self, status: &str) -> bool { self.player.status.contains(&String::from(status)) } - pub fn key_of_ability(&self, ability: &str) -> String { - self.abilities.abilities[ability].key.to_owned() - } - pub fn unknown_item(&self, item_type: &str) -> Option { let mut item = None; @@ -426,10 +417,6 @@ impl CrawlData { item } - pub fn player_pos(&self) -> Coord { - self.player.pos - } - pub fn player_hp(&self) -> i32 { self.player.health.hp } @@ -454,53 +441,33 @@ impl CrawlData { self.fov } - pub fn tile_explored(&mut self, x_pos: usize, y_pos: usize) -> bool { - self.tiles.tiles[x_pos][y_pos].explored - } - - pub fn tile_walkable(&mut self, x_pos: usize, y_pos: usize) -> bool { - self.tiles.tiles[x_pos][y_pos].walkable && !self.tiles.tiles[x_pos][y_pos].blocked - } - - pub fn tile_walkable_ignore_blocked(&mut self, x_pos: usize, y_pos: usize) -> bool { - self.tiles.tiles[x_pos][y_pos].walkable - } - - pub fn tile_mf(&mut self, x_pos: usize, y_pos: usize) -> usize { - self.tiles.tiles[x_pos][y_pos].mf - } - pub fn unknown_item_curr_loc(&mut self) -> bool { - let pos = self.player_pos(); + let pos = self.player.pos; self.pickup.unknown_item_loc(pos) } pub fn remove_item_curr_loc(&mut self) { - let pos = self.player_pos(); + let pos = self.player.pos; self.pickup.remove_item_loc(pos); } pub fn new_ignore_item_curr_loc(&mut self) { - let pos = self.player_pos(); + let pos = self.player.pos; self.pickup.new_ignore_item_loc(pos); } - pub fn nearest_item_path(&mut self) -> Option> { - let pos = self.player_pos(); + pub fn nearest_item_path(&mut self) -> Option> { + let pos = self.player.pos; let nearest = self.pickup.nearest(&self.tiles.tiles, pos, self.fov); if !nearest.is_empty() { - return Some(nearest); + let coords = convert_coords_to_relative(pos, nearest); + return Some(coords); } None } - pub fn examine_monsters(&mut self) -> Option { - let pos = self.player_pos(); - self.monsters.pos_unexamined_monster(pos, self.fov) - } - pub fn new_floor(&mut self) { self.tiles = Tiles::init(); self.monsters = Monsters::init(); @@ -513,8 +480,8 @@ impl CrawlData { /// /// * `player_pos` - A [Coord] containing the player's position within /// the [Tiles].tiles vector. - pub fn path_to_unexplored(&mut self) -> Vec { - pathfinding( + pub fn path_to_unexplored(&mut self) -> Vec { + let coords = pathfinding( &self.tiles.tiles, self.player.pos, None, @@ -522,7 +489,9 @@ impl CrawlData { Some("unexplored"), 10_000, false, - ) + ); + + convert_coords_to_relative(self.player.pos, coords) } /// Set path to an down stair in the [Tiles] object. @@ -531,8 +500,8 @@ impl CrawlData { /// /// * `player_pos` - A ([Coord]) containing the player's position within /// the [Tiles].tiles vector. - pub fn path_to_down_stairs(&mut self) -> Vec { - pathfinding( + pub fn path_to_down_stairs(&mut self) -> Vec { + let coords = pathfinding( &self.tiles.tiles, self.player.pos, None, @@ -540,11 +509,15 @@ impl CrawlData { None, 10_000, false, - ) + ); + + convert_coords_to_relative(self.player.pos, coords) } - pub fn path_to_location(&mut self, cell_loc: Coord) -> Vec { - pathfinding( + pub fn path_to_location(&mut self, cell_loc: RelCoord) -> Vec { + let cell_loc = convert_coord_to_absolute(self.player.pos, cell_loc); + + let coords = pathfinding( &self.tiles.tiles, self.player.pos, Some(cell_loc), @@ -552,6 +525,8 @@ impl CrawlData { None, 10_000, false, - ) + ); + + convert_coords_to_relative(self.player.pos, coords) } } diff --git a/dcss-data/src/menus.rs b/dcss-data/src/menus.rs index 6cb12d1..5600dea 100644 --- a/dcss-data/src/menus.rs +++ b/dcss-data/src/menus.rs @@ -1,6 +1,6 @@ use rustc_hash::FxHashMap; -use crate::CrawlData; +use crate::{CrawlData, common::char_to_index}; /// Meta menu struct, stores the main menu that creates a menu hierarchy #[derive(Debug)] @@ -47,8 +47,8 @@ impl Menus { /// # Arguments /// /// * `hierarchy` - A [Vec] of [&str] that takes the "open_menu" key to - /// identify where in the menu hierarchy the new menu - /// should be placed. + /// identify where in the menu hierarchy the new menu + /// should be placed. /// * `open_menu` - A [&str] for the character used to open that menu /// * `close_menu` - A [&str] for the character used to close that menu /// * `requested` - A [bool] for if the menu was requested @@ -56,9 +56,9 @@ impl Menus { /// * `closed` - A [bool] for if the menu was closed /// * `high_priority` - A [bool] for if the menu is of high priority /// * `open_message` - A [String] message to wait for from the API to - /// confirm the menu is opened + /// confirm the menu is opened /// * `close_message` - A [String] message to wait for from the API to - /// confirm the menu is closed + /// confirm the menu is closed #[allow(clippy::too_many_arguments)] pub(crate) fn add_menu( &mut self, @@ -259,6 +259,8 @@ impl CrawlData { "menu", "close_menu", ); + + self.abilities.make_abilities_current(); } /// Open the description menu of a specific item @@ -355,6 +357,9 @@ impl CrawlData { "ui-push", "player", ); + + self.player + .update_equipped(char_to_index(item_key), &self.inventory); } pub fn queue_put_on(&mut self, item_key: &str) { @@ -398,7 +403,7 @@ impl CrawlData { false, false, "menu_scroll", - "player", + "input_mode", ); } @@ -426,8 +431,10 @@ impl CrawlData { false, false, "menu", - "player", + "input_mode", ); + + self.abilities.make_abilities_stale(); } pub fn queue_collect_known_item_data(&mut self) { @@ -472,6 +479,7 @@ impl CrawlData { ); } + // pub fn look_at_monster_menu(&mut self) { self.menus.add_menu( vec![""], diff --git a/dcss-data/src/monsters.rs b/dcss-data/src/monsters.rs index e6b4dd8..1026880 100644 --- a/dcss-data/src/monsters.rs +++ b/dcss-data/src/monsters.rs @@ -1,46 +1,121 @@ use std::cmp; -use crate::common::{pathfinding, CoordVec}; +use crate::common::{AbsCoord, pathfinding}; use crate::tiles::Tile; -use crate::CrawlData; +use crate::{ + CrawlData, RelCoord, convert_coord_to_absolute, convert_coord_to_relative, + convert_coords_to_relative, +}; use regex::Regex; use rustc_hash::FxHashMap; use serde_json::Value; -use crate::common::Coord; - #[derive(Debug)] +/// Object containing the monster hashmap and the location of the +/// next monster to examine. pub(crate) struct Monsters { - pub(crate) examine_loc: Option, + pub(crate) examine_loc: Option, pub(crate) monsters: FxHashMap, } #[derive(Debug)] +/// Object containing all the characteristics of a monster. pub(crate) struct Monster { + /// Name of the monster pub(crate) name: String, + + /// Threat level + /// "Friendly" / "Harmless" => -1 + /// "Minor" => 1 + /// "Low" => 2 + /// "High" => 4 + /// "Lethal" => 5 pub(crate) threat: i32, - pub(crate) pos: Option, + + /// Absolute coordinates of the monster + pub(crate) pos: Option, + + /// Has `dcss-data` received detailed info about the monster pub(crate) examined: bool, + + /// Is incapacitated (e.g. asleep) -- impacts %s + pub(crate) incapacitated: bool, + + /// Max monster range + /// "Touching" => 1 + /// "Polearm" => 2 + /// "Ranged" => 3 + pub(crate) range: Option, + + /// Maximum HP pub(crate) max_hp: Option, + + /// Will pub(crate) will: Option, + + /// AC pub(crate) ac: Option, + + /// EV pub(crate) ev: Option, + + /// Fire resistance pub(crate) fire: Option, + + /// Cold resistance pub(crate) cold: Option, + + /// Poison resistance pub(crate) poison: Option, + + /// Negative resistance pub(crate) negative: Option, + + /// Electric resistance pub(crate) electric: Option, + + /// Monster class + /// "Natural" => 1 + /// "Undead" => 2 + /// "Demonic" => 3 + /// "Nonliv." => 4 + /// "Plant" => 5 + /// "Holy" => 6 pub(crate) class: Option, + + /// Monster size + /// "Tiny" => 1 + /// "V. Small" => 2 + /// "Small" => 3 + /// "Medium" => 4 + /// "Large" => 5 + /// "Giant" => 6 pub(crate) size: Option, + + /// Monster intelligence + /// "Mindless" => 1 + /// "Animal" => 2 + /// "Human" => 3 pub(crate) int: Option, + + /// Monster speed (%) pub(crate) speed: Option, + + /// Monster regeneration pub(crate) regen: Option, + + /// Chance to hit monster (%) pub(crate) player_hit_monster_chance: Option, + + /// Chance the monster hits the player (%) pub(crate) monster_hit_player_chance: Option, + + /// Max damage the monster can do to the player pub(crate) max_damage: Option, } impl Monsters { + /// Create the [Monsters] object pub(crate) fn init() -> Self { Self { examine_loc: None, @@ -48,7 +123,15 @@ impl Monsters { } } - pub(crate) fn update(&mut self, mon_pos: Coord, monster: Value) { + /// Update the `monsters` field based on the value for the monster, received + /// from the tiles object. + /// + /// # Arguments + /// + /// * `mon_pos` - an [AbsCoord] of the monster's position + /// * `monster` - A [serde_json::Value] received by DCSS Webtiles, from the + /// tiles data. + pub(crate) fn update(&mut self, mon_pos: AbsCoord, monster: Value) { // If monster is "None", and monster still at that position in memory, // remove it from that location if monster.is_null() { @@ -149,7 +232,7 @@ impl Monsters { if !self.monsters.is_empty() { if !found { - // Assume that it's just the same as the last one (unsafe?) + // Assume that it's just the same as the last one (sound assumption?) let last_mon_id = self.monsters.keys().max().unwrap(); self.monsters.insert( @@ -169,10 +252,23 @@ impl Monsters { } } - pub(crate) fn description(&mut self, description: Value, pos: Coord) { + /// Update the `monsters` field based on the value for the monster, received + /// from inspecting the monster through tile examination (e.g. `click_cell`). + /// + /// # Arguments + /// + /// * `mon_pos` - an [AbsCoord] of the monster's position + /// * `description` - A [serde_json::Value] received by DCSS Webtiles, from a + /// ui_type popup after a tile examination. + pub(crate) fn description(&mut self, pos: AbsCoord, description: Value) { let mut desc_body = description["body"].as_str().unwrap().to_owned(); + + // Needed for uniform decoding desc_body.push_str("\n\n"); + // Incapacitated + let incapacitated = desc_body.contains("incapacitated"); + // Max HP let re: Regex = Regex::new(r"(?:Max HP: ~|Max HP: )\s*([^<\n]*)").unwrap(); let cap = re.captures(&desc_body).unwrap(); @@ -231,7 +327,7 @@ impl Monsters { // Threat let re: Regex = Regex::new(r"Threat:\s*([^<\n]*)").unwrap(); let cap: &str = &re.captures(&desc_body).unwrap()[1]; - let threat = match cap.trim() { + let mut threat = match cap.trim() { "Minor" => 1, "Low" => 2, "High" => 4, @@ -239,6 +335,11 @@ impl Monsters { _ => unimplemented!("Missing level"), }; + // Ignore friendlies + if desc_body.contains("If angered it will immediately vanish, yielding no experience or items") { + threat = -1; + } + // Class let re: Regex = Regex::new(r"Class:\s*([^<\n]*)").unwrap(); let cap: &str = &re.captures(&desc_body).unwrap()[1]; @@ -248,6 +349,7 @@ impl Monsters { "Demonic" => 3, "Nonliv." => 4, "Plant" => 5, + "Holy" => 6, _ => unimplemented!("Missing class"), }; @@ -300,7 +402,7 @@ impl Monsters { 0 }; - // hance the monster hits the player + // Chance the monster hits the player let re: Regex = Regex::new(r"(?:He|She|It|They) (?:has|have) about \s*([^%]*)").unwrap(); let monster_hit_player_chance: i32 = if let Some(cap) = re.captures(&desc_body) { cap[1].parse::().unwrap_or(0) @@ -315,6 +417,9 @@ impl Monsters { let re: Regex = Regex::new(r"\n\n").unwrap(); let end_pos = re.find(&desc_body[start_pos..]).unwrap().start(); + // TODO: Some weaspons (like trishula) have this formula for damage: `13 + 19 (holy)`. + // Currently this would only count as 13!! + // Capture the 2x (for example) and the max damage let re_num_x = Regex::new(r"(\d+)x").unwrap(); let re_max_damage = Regex::new(r"\s(\d+)(\s|$)").unwrap(); @@ -336,6 +441,34 @@ impl Monsters { 0 }; + // Range max + let re: Regex = Regex::new(r"(?:Attacks|Attack) \s*([^\n]*)").unwrap(); + let range = if let Some(found) = re.find(&desc_body) { + let start_pos = found.end() + 1; + let re: Regex = Regex::new(r"\n\n").unwrap(); + let end_pos = re.find(&desc_body[start_pos..]).unwrap().start(); + + if desc_body[start_pos..][..end_pos].contains("Shoot") + || desc_body[start_pos..][..end_pos].contains("Throw") + { + 100 + } else if desc_body[start_pos..][..end_pos].contains("spear") + || desc_body[start_pos..][..end_pos].contains("trident") + || desc_body[start_pos..][..end_pos].contains("trishula") + || desc_body[start_pos..][..end_pos].contains("halberd") + || desc_body[start_pos..][..end_pos].contains("scythe") + || desc_body[start_pos..][..end_pos].contains("partisan") + || desc_body[start_pos..][..end_pos].contains("glaive") + || desc_body[start_pos..][..end_pos].contains("bardiche") + { + 2 + } else { + 1 + } + } else { + 0 + }; + // TODO parse immunities and abilities (e.g. it is immune to acid, it can see invisible) // TODO: Get spells @@ -347,6 +480,7 @@ impl Monsters { } mon.examined = true; + mon.incapacitated = incapacitated; mon.threat = threat; mon.max_hp = Some(max_hp); mon.will = Some(will); @@ -365,20 +499,45 @@ impl Monsters { mon.player_hit_monster_chance = Some(player_hit_monster_chance); mon.monster_hit_player_chance = Some(monster_hit_player_chance); mon.max_damage = Some(max_damage); + mon.range = Some(range); } } - pub(crate) fn count_path(&mut self, tiles: &[Vec], player_pos: Coord, fov: u32) -> u32 { + /// Counts the number of paths to monsters within the field of view (FOV). + /// Generally used to count monsters that are potentially accessible by the + /// player (e.g. not in a glass box). Returns a [u32]. + /// + /// # Arguments + /// + /// * `tiles` - The 2d vector of Tiles. + /// * `player_pos` - The [AbsCoord] of the player's position. + /// * `fov` - The maximum field of view for the pathing. + pub(crate) fn count_path( + &mut self, + tiles: &[Vec], + player_pos: AbsCoord, + fov: u32, + ) -> u32 { self.path_to_all_mons(tiles, player_pos, fov, true).len() as u32 } + /// Runs pathing to all the monsters within the field of view (FOV). Returns + /// a vector of paths (i.e., [Vec>]). + /// + /// # Arguments + /// + /// * `tiles` - The 2d vector of Tiles. + /// * `player_pos` - The [AbsCoord] of the player's position. + /// * `fov` - The maximum field of view for the pathing. + /// * `ignore_blocked` - A [bool] on if the pathing should ignore temporary + /// blocks. fn path_to_all_mons( &self, tiles: &[Vec], - player_pos: Coord, + player_pos: AbsCoord, fov: u32, ignore_blocked: bool, // Ignore blocking paths, better counts - ) -> Vec { + ) -> Vec> { let mut path_of_monsters = vec![]; // How far is monster from char (max = fov) @@ -400,6 +559,7 @@ impl Monsters { continue; } + // If within FOV, path it let path = pathfinding( tiles, player_pos, @@ -410,6 +570,7 @@ impl Monsters { ignore_blocked, ); + // May be within FOV, but not accessible, skip those if !path.is_empty() { path_of_monsters.push(path) } @@ -418,10 +579,13 @@ impl Monsters { path_of_monsters } - /// Return monsters that are withing FOV, regardless of path (since some monster - /// can block the path to other monsters) - pub(crate) fn monsters_in_fov(&self, player_pos: Coord, fov: u32) -> Vec<&Monster> { - // TODO Deal with Plants (threat = -1) + /// Return monsters that are withing FOV, regardless of path. + /// + /// # Arguments + /// + /// * `player_pos` - The [AbsCoord] of the player's position. + /// * `fov` - The maximum field of view for the pathing. + pub(crate) fn monsters_in_fov(&self, player_pos: AbsCoord, fov: u32) -> Vec<&Monster> { self.monsters .iter() @@ -437,16 +601,57 @@ impl Monsters { .collect::>() } + /// Returns a vector of all the characteristics of each monster in the + /// battle. + /// + /// # Arguments + /// + /// * `player_pos` - The [AbsCoord] of the player's position. + /// * `fov` - The maximum field of view for the pathing. + /// * `can_hit` - Include only those who could hit from their current position. + /// + /// # Info + /// + /// * `threat` = threat level ("Minor" => 1 | "Low" => 2 | "High" => 4 | "Lethal" => 5) + /// * `max_hp` = maximum hp + /// * `will` = will + /// * `ac` = ac + /// * `ev` = ev + /// * `fire` = fire resistance + /// * `cold` = cold resistance + /// * `poison` = poison resistance + /// * `negative` = negative resistance + /// * `electric` = electric resistance + /// * `class` = monster class ("Natural" => 1 | "Undead" => 2 | "Demonic" => 3 | "Nonliv." => 4 | "Plant" => 5 | "Holy" => 6) + /// * `size` = monster size ("Tiny" => 1 | "V. Small" => 2 | "Small" => 3 | "Medium" => 4 | "Large" => 5 | "Giant" => 6) + /// * `int` = monster intelligence ("Mindless" => 1 | "Animal" => 2 | "Human" => 3) + /// * `speed` = monster speed (% compared to player) + /// * `regen` = monster regeneration + /// * `player_hit_monster_chance` = chance to hit monster (%) + /// * `monster_hit_player_chance` = chance the monster hits the player (%) + /// * `max_damage` = max damage the monster can do to the player pub(crate) fn monster_in_battle( &self, - player_pos: Coord, + player_pos: AbsCoord, fov: u32, + can_hit: bool, ) -> Vec> { let monsters = self.monsters_in_fov(player_pos, fov); monsters .iter() .filter(|mon| mon.name != "invisible") + .filter(|mon| { + if !mon.examined { + panic!("You must examine the monster before collecting their info. Use `ready_examine_monster(coord)` and `look_at_monster_menu()`."); + } + + !can_hit || + cmp::max( + (player_pos.0 as i32 - mon.pos.unwrap().0 as i32).abs(), + (player_pos.1 as i32 - mon.pos.unwrap().1 as i32).abs(), + ) <= mon.range.unwrap() + }) .map(|mon| { let mut hash = FxHashMap::default(); @@ -480,7 +685,17 @@ impl Monsters { .collect() } - pub(crate) fn pos_unexamined_monster(&self, player_pos: Coord, fov: u32) -> Option { + /// Returns the [AbsCoord] of an unexamined monster. + /// + /// # Arguments + /// + /// * `player_pos` - The [AbsCoord] of the player's position. + /// * `fov` - The maximum field of view for the pathing. + pub(crate) fn pos_unexamined_monster( + &self, + player_pos: AbsCoord, + fov: u32, + ) -> Option { let mons = self .monsters .iter() @@ -504,7 +719,53 @@ impl Monsters { None } - pub(crate) fn nearest(&mut self, tiles: &[Vec], player_pos: Coord, fov: u32) -> CoordVec { + /// Returns the [AbsCoord] of an incapacitated monster. + /// + /// # Arguments + /// + /// * `player_pos` - The [AbsCoord] of the player's position. + /// * `fov` - The maximum field of view for the pathing. + pub(crate) fn pos_incapacitated_monster( + &self, + player_pos: AbsCoord, + fov: u32, + ) -> Option { + let mons = self + .monsters + .iter() + .map(|mon| mon.1) + .filter(|mon| mon.pos.is_some()) + .filter(|mon| mon.threat >= 0) + .filter(|mon| mon.incapacitated) + .filter(|mon| mon.name != "invisible") + .filter(|mon| { + cmp::max( + (player_pos.0 as i32 - mon.pos.unwrap().0 as i32).abs(), + (player_pos.1 as i32 - mon.pos.unwrap().1 as i32).abs(), + ) <= fov as i32 + }) + .collect::>(); + + if !mons.is_empty() { + return mons[0].pos; + } + + None + } + + /// Returns the [AbsCoord] of the nearest monster (according to pathing). + /// + /// # Arguments + /// + /// * `tiles` - The 2d vector of tiles. + /// * `player_pos` - The [AbsCoord] of the player's position. + /// * `fov` - The maximum field of view for the pathing. + pub(crate) fn nearest( + &mut self, + tiles: &[Vec], + player_pos: AbsCoord, + fov: u32, + ) -> Vec { let mut shortest_path = vec![]; for path in self.path_to_all_mons(tiles, player_pos, fov, false) { @@ -519,12 +780,24 @@ impl Monsters { shortest_path } - pub(crate) fn invisible_monster(&mut self, mon_pos: Coord) { + /// A function to add an invisible monster to the list of monsters. Invisible monsters + /// don't generate the same information in the tiles object as other monsters. + /// + /// # Arguments + /// + /// * `mon_pos` - The [AbsCoord] of the invisible monster's position. + pub(crate) fn invisible_monster(&mut self, mon_pos: AbsCoord) { + // TODO: Can only have one invisible monster self.monsters .insert(9999, Monster::new("invisible".to_owned(), 0, Some(mon_pos))); } - pub(crate) fn invisible_removed(&mut self, mon_pos: Coord) { + /// A function to remove an invisible monster from the list of monsters. + /// + /// # Arguments + /// + /// * `mon_pos` - The [AbsCoord] of the invisible monster's position. + pub(crate) fn invisible_removed(&mut self, mon_pos: AbsCoord) { if self.monsters.contains_key(&9999) && self.monsters[&9999].pos == Some(mon_pos) { self.monsters.remove(&9999); } @@ -532,12 +805,20 @@ impl Monsters { } impl Monster { - fn new(name: String, threat: i32, pos: Option) -> Self { + /// Generate new monster. + /// + /// # Arguments + /// + /// * `name` - The name of the monster. + /// * `threat` - The threat level of the monster (received from the tiles object). + /// * `pos` - The [AbsCoord] of the monster's position. + fn new(name: String, threat: i32, pos: Option) -> Self { Self { name, threat, pos, examined: false, + incapacitated: false, max_hp: None, will: None, ac: None, @@ -555,62 +836,164 @@ impl Monster { player_hit_monster_chance: None, monster_hit_player_chance: None, max_damage: None, + range: None, } } - fn update_pos(&mut self, pos: Option) { + /// Update the position of the monster. + /// + /// # Arguments + /// + /// * `pos` - The [AbsCoord] of the monster's new position. + fn update_pos(&mut self, pos: Option) { self.pos = pos; } } impl CrawlData { - pub fn ready_examine_monster(&mut self, coord: Coord) { - self.monsters.examine_loc = Some(coord); - } - + /// Count the number of monsters that can be reached through pathing, + /// within field of view (fov). pub fn monster_count_path(&mut self) -> u32 { - let pos: Coord = self.player_pos(); + let pos: AbsCoord = self.player.pos; self.monsters.count_path(&self.tiles.tiles, pos, self.fov) } + /// Count the number of monsters that can be seen, within field of + /// view (regardless of path). pub fn monster_count_fov(&mut self) -> u32 { - let pos: Coord = self.player_pos(); + let pos: AbsCoord = self.player.pos; self.monsters.monsters_in_fov(pos, self.fov).len() as u32 } - pub fn monster_touching(&mut self) -> bool { - let pos: Coord = self.player_pos(); - self.monsters.monsters_in_fov(pos, 1).is_empty() - } + /// Get the path ([Vec]) to the nearest monster, according to + /// pathing (shortest path). + pub fn nearest_monster_path(&mut self) -> Vec { + let pos = self.player.pos; + let coords = self.monsters.nearest(&self.tiles.tiles, pos, self.fov); - pub fn nearest_monster_path(&mut self) -> Vec { - let pos = self.player_pos(); - self.monsters.nearest(&self.tiles.tiles, pos, self.fov) + convert_coords_to_relative(self.player.pos, coords) } - pub fn get_battle_monster_info(&self) -> Vec> { - let pos = self.player_pos(); - let fov = self.fov; + /// Get the coordinates ([RelCoord]) of the nearest monster, according to + /// pathing (shortest path). + pub fn coord_nearest_monster(&mut self) -> Option { + let pos = self.player.pos; + let coords = self.monsters.nearest(&self.tiles.tiles, pos, self.fov); - self.monsters.monster_in_battle(pos, fov) - } + if coords.is_empty() { + return None; + } - pub fn get_attacking_monster_info(&self) -> Vec> { - let pos = self.player_pos(); + Some(convert_coord_to_relative(self.player.pos, coords[0])) + } - self.monsters.monster_in_battle(pos, 1) + /// Get a bool if a monster is touching (within one tile) the character. + pub fn monster_touching(&mut self) -> bool { + let pos: AbsCoord = self.player.pos; + !self.monsters.monsters_in_fov(pos, 1).is_empty() } + /// Get a vector of "threat" for all monster in field of view (regardless + /// of path). Good way to get a very quick "vibe check" of the battle. pub fn get_monster_threat_vec(&mut self) -> Vec { - let pos = self.player_pos(); + let pos = self.player.pos; self.monsters .monsters_in_fov(pos, self.fov) .iter() .map(|mon| mon.threat) .collect::>() } + + /// Returns a vector of all the characteristics of each monster in the battle. + /// + /// # Info + /// + /// * `threat` = threat level ("Minor" => 1 | "Low" => 2 | "High" => 4 | "Lethal" => 5) + /// * `max_hp` = maximum hp + /// * `will` = will + /// * `ac` = ac + /// * `ev` = ev + /// * `fire` = fire resistance + /// * `cold` = cold resistance + /// * `poison` = poison resistance + /// * `negative` = negative resistance + /// * `electric` = electric resistance + /// * `class` = monster class ("Natural" => 1 | "Undead" => 2 | "Demonic" => 3 | "Nonliv." => 4 | "Plant" => 5 | "Holy" => 6) + /// * `size` = monster size ("Tiny" => 1 | "V. Small" => 2 | "Small" => 3 | "Medium" => 4 | "Large" => 5 | "Giant" => 6) + /// * `int` = monster intelligence ("Mindless" => 1 | "Animal" => 2 | "Human" => 3) + /// * `speed` = monster speed (% compared to player) + /// * `regen` = monster regeneration + /// * `player_hit_monster_chance` = chance to hit monster (%) + /// * `monster_hit_player_chance` = chance the monster hits the player (%) + /// * `max_damage` = max damage the monster can do to the player + pub fn get_battle_monster_info(&self) -> Vec> { + let pos = self.player.pos; + let fov = self.fov; + + self.monsters.monster_in_battle(pos, fov, false) + } + + /// Returns a vector of all the characteristics of each monster touching the character. + /// + /// # Info + /// + /// * `threat` = threat level ("Minor" => 1 | "Low" => 2 | "High" => 4 | "Lethal" => 5) + /// * `max_hp` = maximum hp + /// * `will` = will + /// * `ac` = ac + /// * `ev` = ev + /// * `fire` = fire resistance + /// * `cold` = cold resistance + /// * `poison` = poison resistance + /// * `negative` = negative resistance + /// * `electric` = electric resistance + /// * `class` = monster class ("Natural" => 1 | "Undead" => 2 | "Demonic" => 3 | "Nonliv." => 4 | "Plant" => 5 | "Holy" => 6) + /// * `size` = monster size ("Tiny" => 1 | "V. Small" => 2 | "Small" => 3 | "Medium" => 4 | "Large" => 5 | "Giant" => 6) + /// * `int` = monster intelligence ("Mindless" => 1 | "Animal" => 2 | "Human" => 3) + /// * `speed` = monster speed (% compared to player) + /// * `regen` = monster regeneration + /// * `player_hit_monster_chance` = chance to hit monster (%) + /// * `monster_hit_player_chance` = chance the monster hits the player (%) + /// * `max_damage` = max damage the monster can do to the player + pub fn get_attacking_monster_info(&self) -> Vec> { + let pos = self.player.pos; + let fov = self.fov; + + self.monsters.monster_in_battle(pos, fov, true) + } + + /// Set the position of the next monster to inspect in more detail. + /// + /// # Arguments + /// + /// * `coord` - The [RelCoord] of the monster's position. + pub fn ready_examine_monster(&mut self, coord: RelCoord) { + self.monsters.examine_loc = Some(convert_coord_to_absolute(self.player.pos, coord)); + } + + /// Get position of unexamined monster + pub fn get_pos_of_unexamined_monster(&mut self) -> Option { + let pos = self.player.pos; + let coord = self.monsters.pos_unexamined_monster(pos, self.fov); + + coord.map(|coord| convert_coord_to_relative(pos, coord)) + } + + /// Get position of previously incapacitated monster + pub fn get_pos_of_incapacitated_monster(&mut self) -> Option { + let pos = self.player.pos; + let coord = self.monsters.pos_incapacitated_monster(pos, self.fov); + + coord.map(|coord| convert_coord_to_relative(pos, coord)) + } } +/// Convert resistance values (e.g. `xx`) to numeric. +/// +/// # Arguments +/// +/// * `re` - A regex expression to capture the value +/// * `text` - Text to process fn decode_resistance(re: Regex, text: &str) -> i32 { if let Some(cap) = &re.captures(text) { if cap[1].starts_with('∞') { diff --git a/dcss-data/src/pickup.rs b/dcss-data/src/pickup.rs index b465eaa..c79838f 100644 --- a/dcss-data/src/pickup.rs +++ b/dcss-data/src/pickup.rs @@ -1,12 +1,12 @@ use crate::common::pathfinding; -use crate::common::Coord; +use crate::common::AbsCoord; use crate::tiles::Tile; use std::cmp; #[derive(Debug)] pub(crate) struct Pickup { - pub(crate) unknown: Vec, - pub(crate) ignore: Vec, + pub(crate) unknown: Vec, + pub(crate) ignore: Vec, } impl Pickup { @@ -17,20 +17,20 @@ impl Pickup { } } - pub(crate) fn update(&mut self, item_coord: Coord) { - let already_listed = self.unknown.iter().any(|x: &Coord| *x == item_coord); + pub(crate) fn update(&mut self, item_coord: AbsCoord) { + let already_listed = self.unknown.contains(&item_coord); - let ignore = self.ignore.iter().any(|x: &Coord| *x == item_coord); + let ignore = self.ignore.contains(&item_coord); if !already_listed && !ignore { self.unknown.push(item_coord); } } - pub(crate) fn unknown_item_loc(&self, player_coord: Coord) -> bool { - let in_list = self.unknown.iter().any(|x: &Coord| *x == player_coord); + pub(crate) fn unknown_item_loc(&self, player_coord: AbsCoord) -> bool { + let in_list = self.unknown.contains(&player_coord); - let ignore = self.ignore.iter().any(|x: &Coord| *x == player_coord); + let ignore = self.ignore.contains(&player_coord); if in_list && !ignore { return true; @@ -39,7 +39,7 @@ impl Pickup { false } - pub(crate) fn remove_item_loc(&mut self, player_coord: Coord) { + pub(crate) fn remove_item_loc(&mut self, player_coord: AbsCoord) { let index = self.unknown.iter().position(|x| *x == player_coord); if let Some(i) = index { @@ -47,10 +47,10 @@ impl Pickup { } } - pub(crate) fn new_ignore_item_loc(&mut self, player_coord: Coord) { + pub(crate) fn new_ignore_item_loc(&mut self, player_coord: AbsCoord) { self.remove_item_loc(player_coord); - let ignore = self.ignore.iter().any(|x: &Coord| *x == player_coord); + let ignore = self.ignore.contains(&player_coord); if !ignore { self.ignore.push(player_coord); @@ -60,9 +60,9 @@ impl Pickup { fn path_to_all_items( &self, tiles: &[Vec], - player_coord: Coord, + player_coord: AbsCoord, fov: u32, - ) -> Vec> { + ) -> Vec> { let mut path_of_items = vec![]; // How far is monster from char (max = fov) @@ -95,9 +95,9 @@ impl Pickup { pub(crate) fn nearest( &mut self, tiles: &[Vec], - player_coord: Coord, + player_coord: AbsCoord, fov: u32, - ) -> Vec { + ) -> Vec { let mut shortest_path = vec![]; for path in self.path_to_all_items(tiles, player_coord, fov) { diff --git a/dcss-data/src/player.rs b/dcss-data/src/player.rs index d8fa912..ffb9b8b 100644 --- a/dcss-data/src/player.rs +++ b/dcss-data/src/player.rs @@ -1,9 +1,13 @@ -use crate::common::add_i32_to_usize; -use crate::common::Coord; use crate::CrawlData; +use crate::common::AbsCoord; +use crate::common::add_i32_to_usize; +use crate::common::char_to_index; +use crate::inventory::Inventory; +use crate::items::Item; +use crate::items::armours::ArmourType; use serde_json::Value; -const MAX_FLOOR_SIZE: usize = 500; +use crate::MAX_FLOOR_SIZE; #[derive(Debug)] pub(crate) struct Health { @@ -27,12 +31,28 @@ pub(crate) struct Defense { } #[derive(Debug)] +pub(crate) struct Equipped { + pub(crate) weapon: i32, + pub(crate) quiver: i32, + pub(crate) amulet: i32, + pub(crate) body: i32, + pub(crate) boots: i32, + pub(crate) cloak: i32, + pub(crate) helmet: i32, + pub(crate) shield: i32, + pub(crate) gloves: i32, + pub(crate) _ring_left: i32, // TODO: Add 8 rings for octopods + pub(crate) _ring_right: i32, +} + +#[derive(Debug)] +/// Stores the character's information pub(crate) struct Player { - pub(crate) pos: Coord, + pub(crate) pos: AbsCoord, pub(crate) health: Health, pub(crate) stats: Stats, pub(crate) defense: Defense, - pub(crate) equipped: Vec, + pub(crate) equipped: Equipped, pub(crate) status: Vec, } @@ -66,14 +86,32 @@ impl Defense { } } +impl Equipped { + pub(crate) fn new() -> Self { + Self { + weapon: -1, + quiver: -1, + amulet: -1, + body: -1, + boots: -1, + cloak: -1, + helmet: -1, + shield: -1, + gloves: -1, + _ring_left: -1, + _ring_right: -1, + } + } +} + impl Player { pub(crate) fn init() -> Self { Self { - pos: (0, 0), + pos: (MAX_FLOOR_SIZE / 2, MAX_FLOOR_SIZE / 2), health: Health::new(), stats: Stats::new(), defense: Defense::new(), - equipped: vec![-1; 21], + equipped: Equipped::new(), status: vec![], } } @@ -85,13 +123,6 @@ impl Player { self.pos.1 = add_i32_to_usize(y.as_i64().unwrap() as i32, offset); } - pub(crate) fn update_equipped(&mut self, equipped: Value) { - for (equip_index, item_index) in equipped.as_object().unwrap() { - self.equipped[equip_index.parse::().unwrap()] = - item_index.as_i64().unwrap() as i32; - } - } - pub(crate) fn update_health(&mut self, message: &Value) { let message_obj = message.as_object().unwrap(); @@ -158,6 +189,41 @@ impl Player { } } } + + pub(crate) fn update_equipped(&mut self, item_index: usize, inventory: &Inventory) { + match &inventory.items[item_index] { + Item::None => unreachable!("None-type can not be equipped."), + Item::Weapon(_) => self.equipped.weapon = item_index as i32, + Item::Missile(_) => self.equipped.quiver = item_index as i32, + Item::Armour(armour) => match &armour.armour_type { + ArmourType::None => unreachable!("None-type can not be equipped."), + ArmourType::Body => self.equipped.body = item_index as i32, + ArmourType::Boots => self.equipped.boots = item_index as i32, + ArmourType::Cloak => self.equipped.cloak = item_index as i32, + ArmourType::Helmet => self.equipped.helmet = item_index as i32, + ArmourType::Shield => self.equipped.shield = item_index as i32, + ArmourType::Gloves => self.equipped.gloves = item_index as i32, + }, + Item::Wand(_) => unimplemented!(), + Item::_Unknown4 => unimplemented!(), + Item::Scroll(_) => unreachable!("Can't equip a scroll"), + Item::Jewellery(_) => unimplemented!(), + Item::Potion(_) => unreachable!("Can't equip a potion"), + Item::_Unknown8 => unimplemented!(), + Item::Staff(_) => unimplemented!(), + } + } + + pub(crate) fn equipped_from_description(&mut self, inventory: &Inventory, description: &Value) { + if !description["body"].to_string().contains("equipped") { + return; + } + + let key = &description["title"].to_string()[1..2]; + let item_index = char_to_index(key); + + self.update_equipped(item_index, inventory); + } } impl CrawlData { diff --git a/dcss-data/src/tiles.rs b/dcss-data/src/tiles.rs index c5b51b4..7d321f6 100644 --- a/dcss-data/src/tiles.rs +++ b/dcss-data/src/tiles.rs @@ -1,12 +1,10 @@ -use crate::common::{Coord, CoordVec}; +use crate::{CrawlData, common::AbsCoord, convert_coord_to_absolute}; use serde_json::Value; use std::error::Error; +use crate::MAX_FLOOR_SIZE; use crate::common::add_i32_to_usize; -/// Max floor size -const MAX_FLOOR_SIZE: usize = 500; - /// Map Features (MF) received by the game (e.g. floor, wall). /// /// # Data @@ -68,13 +66,13 @@ pub(crate) struct Tile { /// The number for the map feature. pub(crate) mf: usize, - /// Bool on if the tile is walkable or not. + /// Bool on if the tile is walkable. pub(crate) walkable: bool, - /// Temp blocked + /// Bool on if the tile is temporarily blocked. pub(crate) blocked: bool, - /// Bool on if the tile is explored or not. + /// Bool on if the tile is explored. pub(crate) explored: bool, } @@ -103,7 +101,14 @@ impl Tiles { pub(crate) fn update( &mut self, cells: &Value, - ) -> Result<(Vec<(Coord, Value)>, CoordVec, (CoordVec, CoordVec)), Box> { + ) -> Result< + ( + Vec<(AbsCoord, Value)>, + Vec, + (Vec, Vec), + ), + Box, + > { // x = moving left and right through a row // y = moving up and down in a column @@ -116,12 +121,12 @@ impl Tiles { let mut coord = (0, 0); // Monster list, to be returned to be processed by the monsters module - let mut monsters: Vec<(Coord, serde_json::Value)> = Vec::new(); - let mut invisible_monsters: CoordVec = Vec::new(); - let mut remove_invisible_monsters: CoordVec = Vec::new(); + let mut monsters: Vec<(AbsCoord, serde_json::Value)> = Vec::new(); + let mut invisible_monsters: Vec = Vec::new(); + let mut remove_invisible_monsters: Vec = Vec::new(); // List of items on the ground - let mut itemlist: CoordVec = Vec::new(); + let mut itemlist: Vec = Vec::new(); for tile in cells.as_array().unwrap() { let tile_object = tile.as_object().unwrap(); @@ -177,18 +182,21 @@ impl Tiles { // Tiles have the "{" glyph when invisible monsters are on them (for a period of time) if tile_object["g"] == "{" { invisible_monsters.push((x_pos, y_pos)); + self.tiles[x_pos][y_pos].unblock(); // Make it walkable again } else if tile_object["g"] == "@" { // If character on monster tile, delete invisible (means no longer there) remove_invisible_monsters.push((x_pos, y_pos)); - } else if tile_object["g"] == "§" + } + + if tile_object["g"] == "§" || tile_object["g"] == "☼" || tile_object["g"] == "○" || tile_object["g"] == "°" // Cloud (unsure if this will cause an issue for non-toxic clouds) { self.tiles[x_pos][y_pos].block(); - } else { - self.tiles[x_pos][y_pos].unblock(); + } else if !tile_object.contains_key("mon") { + self.tiles[x_pos][y_pos].unblock(); // Remove if previously cloud } } } @@ -238,3 +246,194 @@ impl Tile { self.blocked = false } } + +impl CrawlData { + /// Is the tile at `x_pos` and `y_pos` (relative to the player's position) + /// explored. Returns a [bool]. + /// + ///
+    /// Tiles [x, y]
+    ///        -y
+    ///       ↖ ↑ ↗
+    ///   -x  ← · → +x
+    ///       ↙ ↓ ↘
+    ///        +y
+    /// 
+ /// + /// # Arguments + /// + /// * `x_pos` - A [i32] containing `x` position of the tile. + /// * `y_pos` - A [i32] containing `y` position of the tile. + /// + /// # Example + /// + /// ```ignore + /// let explored = tile_explored(3, -5); + /// ``` + pub fn tile_explored(&mut self, x_pos: i32, y_pos: i32) -> bool { + let pos = self.player.pos; + + let x_adj = add_i32_to_usize(x_pos, pos.0); + let y_adj = add_i32_to_usize(y_pos, pos.1); + + self.tiles.tiles[x_adj][y_adj].explored + } + + /// Is the tile at `x_pos` and `y_pos` (relative to the player's position) + /// walkable. Returns false if the tile is temporarily blocked (e.g. has a + /// monster on the tile). Returns a [bool]. + /// + ///
+    /// Tiles [x, y]
+    ///        -y
+    ///       ↖ ↑ ↗
+    ///   -x  ← · → +x
+    ///       ↙ ↓ ↘
+    ///        +y
+    /// 
+ /// + /// # Arguments + /// + /// * `x_pos` - A [i32] containing `x` position of the tile. + /// * `y_pos` - A [i32] containing `y` position of the tile. + /// + /// # Example + /// + /// ```ignore + /// let walkable = tile_walkable(3, -5); + /// ``` + pub fn tile_walkable(&mut self, x_pos: i32, y_pos: i32) -> bool { + let pos = self.player.pos; + + let x_adj = add_i32_to_usize(x_pos, pos.0); + let y_adj = add_i32_to_usize(y_pos, pos.1); + + self.tiles.tiles[x_adj][y_adj].walkable && !self.tiles.tiles[x_adj][y_adj].blocked + } + + /// Is the tile at `x_pos` and `y_pos` (relative to the player's position) + /// walkable. Returns true even if the tile is temporarily blocked (e.g. has a + /// monster on the tile). Returns a [bool]. + /// + ///
+    /// Tiles [x, y]
+    ///        -y
+    ///       ↖ ↑ ↗
+    ///   -x  ← · → +x
+    ///       ↙ ↓ ↘
+    ///        +y
+    /// 
+ /// + /// # Arguments + /// + /// * `x_pos` - A [i32] containing `x` position of the tile. + /// * `y_pos` - A [i32] containing `y` position of the tile. + /// + /// # Example + /// + /// ```ignore + /// let walkable = tile_walkable_ignore_blocked(3, -5); + /// ``` + pub fn tile_walkable_ignore_blocked(&mut self, x_pos: i32, y_pos: i32) -> bool { + let pos = self.player.pos; + + let x_adj = add_i32_to_usize(x_pos, pos.0); + let y_adj = add_i32_to_usize(y_pos, pos.1); + + self.tiles.tiles[x_adj][y_adj].walkable + } + + /// What is the Map Feature (MF) of the tile at `x_pos` and `y_pos` + /// (relative to the player's position). This is generally used for + /// debugging. Returns a [usize]. + /// + ///
+    /// Tiles [x, y]
+    ///        -y
+    ///       ↖ ↑ ↗
+    ///   -x  ← · → +x
+    ///       ↙ ↓ ↘
+    ///        +y
+    /// 
+ /// + /// These are the possible MFs. Some are never uses in the game: + /// * 0: unexplored + /// * 1: floor + /// * 2: wall + /// * 3: magic mapping floor + /// * 4: magic mapping wall + /// * 5: door + /// * 6: item + /// * 7: MF_MONS_FRIENDLY + /// * 8: MF_MONS_PEACEFUL + /// * 9: MF_MONS_NEUTRAL + /// * 10: MF_MONS_HOSTILE + /// * 11: plant (MF_MONS_NO_EXP) + /// * 12: up stairs + /// * 13: down stairs + /// * 14: stair branch (e.g. temple) + /// * 15: feature (e.g. altar) + /// * 16: shallow water + /// * 17: lava + /// * 18: trap + /// * 19: MF_EXCL_ROOT + /// * 20: MF_EXCL + /// * 21: MF_PLAYER + /// * 22: deep water + /// * 23: portal (sewer entrance) + /// * 24: portal (up or down) + /// * 25: portal (up or down) + /// * 26: unexplored + /// + /// # Arguments + /// + /// * `x_pos` - A [i32] containing `x` position of the tile. + /// * `y_pos` - A [i32] containing `y` position of the tile. + /// + /// # Example + /// + /// ```ignore + /// let explored = tile_mf(3, -5); + /// ``` + pub fn tile_mf(&mut self, x_pos: i32, y_pos: i32) -> usize { + let pos = self.player.pos; + + let x_adj = add_i32_to_usize(x_pos, pos.0); + let y_adj = add_i32_to_usize(y_pos, pos.1); + + self.tiles.tiles[x_adj][y_adj].mf + } + + /// Get the position according to DCSS (from game start or stairs) + /// from a relative position (from the player). Necessary for a + /// few functions, such as the "click_cell" function. Returns an + /// (i32, i32). + /// + ///
+    /// Tiles [x, y]
+    ///        -y
+    ///       ↖ ↑ ↗
+    ///   -x  ← · → +x
+    ///       ↙ ↓ ↘
+    ///        +y
+    /// 
+ /// + /// # Arguments + /// + /// * `x_pos` - A [i32] containing `x` position of the tile. + /// * `y_pos` - A [i32] containing `y` position of the tile. + /// + /// # Example + /// + /// ```ignore + /// let explored = tile_mf(3, -5); + /// ``` + pub fn get_dcss_coord(&mut self, x_pos: i32, y_pos: i32) -> (i32, i32) { + let coord = convert_coord_to_absolute(self.player.pos, (x_pos, y_pos)); + + ( + coord.0 as i32 - (MAX_FLOOR_SIZE / 2) as i32, + coord.1 as i32 - (MAX_FLOOR_SIZE / 2) as i32, + ) + } +} diff --git a/dcss-data/tests/common.rs b/dcss-data/tests/common.rs index 008876d..b24b617 100644 --- a/dcss-data/tests/common.rs +++ b/dcss-data/tests/common.rs @@ -1,11 +1,13 @@ #![allow(dead_code)] use dcss_api::Webtile; +use dcss_data::CrawlData; +use dcss_scenario_builder::start_game_with_scenario; +use serde_json::json; -fn reset_test(username: &str) { +pub(crate) fn reset_test(username: &str, game_id: &str) { // Connect to DCSS Webtile - let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect"); + let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} @@ -19,7 +21,7 @@ fn reset_test(username: &str) { while webtile.get_message().is_some() {} webtile - .start_game("dcss-0.32", "b", "f", "b") + .start_game(game_id, "b", "f", "b") .expect("Failed to start game"); // Empty message queue; @@ -32,3 +34,87 @@ fn reset_test(username: &str) { webtile.disconnect().expect("Failed to disconnect"); } + +pub(crate) fn setup_webtile(username: &str, scenario_file: &str) -> Webtile { + let game_id = std::env::var("GAME_ID").unwrap_or("dcss-0.33".to_owned()); + reset_test(username, game_id.as_str()); + + // Connect to DCSS Webtile + let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0).unwrap(); + + // Empty message queue; + while webtile.get_message().is_some() {} + + // Log in (to a user called "Username", with a password "Password") + let _ = webtile + .login_with_credentials(username, "Password") + .unwrap(); + + // Start game with simple scenario. + start_game_with_scenario(&mut webtile, game_id.as_str(), "b", "f", "b", scenario_file).unwrap(); + + // Wait for Ready + webtile + .read_until("input_mode", Some("mode"), Some(1)) + .unwrap(); + + webtile +} + +pub(crate) fn setup_data(webtile: &mut Webtile) -> CrawlData { + // Setup data object + let mut data = CrawlData::init(9); + + // Process the data + while let Some(message) = webtile.get_message() { + println!("RECEIVED: {}", &message); + data.process_json(&message).unwrap() + } + + data +} + +/// Does the basic processing and menu management to look at a monster +pub(crate) fn examine_monster(coord: (i32, i32), webtile: &mut Webtile, data: &mut CrawlData) { + // Send right click to Webtile + let abs_coord = data.get_dcss_coord(coord.0, coord.1); + + let json = json!({ + "x":abs_coord.0,"y":abs_coord.1,"button":3,"msg":"click_cell" + }); + + webtile.write_json(json).unwrap(); + + // Let `data` know you queried the monster + data.ready_examine_monster(coord); + + // Read the menu that pops up about the monster + data.look_at_monster_menu(); + webtile.read_until("ui-push", None, None).unwrap(); + manage_menu(webtile, data); + + // Process the data + while let Some(message) = webtile.get_message() { + data.process_json(&message).unwrap() + } +} + +/// Manage the menus stored in DCSS Data (opening, closing, etc) by +/// taking the key necessary for the next action, sending it to the +/// API and collecting API returned values until they expected +/// message is returned. +pub(crate) fn manage_menu(webtile: &mut Webtile, data: &mut CrawlData) { + while data.menu_to_process() { + // Collect the current menu, according to the menu order rules + // and select the next action (opening, closing, etc) and what + // the API should return if the action is correct. + let (key, message) = data.interact_with_menu(); + if !key.is_empty() { + webtile.write_key(&key[..]).unwrap(); + } + if !message.is_empty() { + webtile.read_until(&message[..], None, None).unwrap(); + } + data.remove_closed_menus(); + } +} diff --git a/dcss-data/tests/scenarios/monsters/glass_box.yaml b/dcss-data/tests/scenarios/monsters/glass_box.yaml new file mode 100644 index 0000000..37a04af --- /dev/null +++ b/dcss-data/tests/scenarios/monsters/glass_box.yaml @@ -0,0 +1,21 @@ +options: + default_feature: "floor" + +levels: + - level: + name: D:1 + features: + - '# = metal_wall' + - '+ = clear_rock_wall' + - '. = floor' + monsters: + - 'x = kobold' + map: |- + ########## + #........# + #......@.# + #.+++....# + #.+x+....# + #.+++..x.# + #........# + ########## \ No newline at end of file diff --git a/dcss-data/tests/scenarios/monsters/kobold.yaml b/dcss-data/tests/scenarios/monsters/kobold.yaml new file mode 100644 index 0000000..9f23d39 --- /dev/null +++ b/dcss-data/tests/scenarios/monsters/kobold.yaml @@ -0,0 +1,20 @@ +options: + default_feature: "floor" + +levels: + - level: + name: D:1 + features: + - '# = metal_wall' + - '. = floor' + monsters: + - 'x = kobold' + map: |- + ########## + #........# + #.@......# + #........# + #........# + #......x.# + #........# + ########## \ No newline at end of file diff --git a/dcss-data/tests/scenarios/monsters/kobold_polearm.yaml b/dcss-data/tests/scenarios/monsters/kobold_polearm.yaml new file mode 100644 index 0000000..beaa9b6 --- /dev/null +++ b/dcss-data/tests/scenarios/monsters/kobold_polearm.yaml @@ -0,0 +1,20 @@ +options: + default_feature: "floor" + +levels: + - level: + name: D:1 + features: + - '# = metal_wall' + - '. = floor' + monsters: + - 'x = kobold generate_awake ; spear' + map: |- + ########## + #........# + #.@xxx...# + #........# + #........# + #........# + #........# + ########## \ No newline at end of file diff --git a/dcss-data/tests/scenarios/monsters/kobold_ranged.yaml b/dcss-data/tests/scenarios/monsters/kobold_ranged.yaml new file mode 100644 index 0000000..6f5af40 --- /dev/null +++ b/dcss-data/tests/scenarios/monsters/kobold_ranged.yaml @@ -0,0 +1,20 @@ +options: + default_feature: "floor" + +levels: + - level: + name: D:1 + features: + - '# = metal_wall' + - '. = floor' + monsters: + - 'x = kobold generate_awake ; sling' + map: |- + ########## + #........# + #.@......# + #........# + #........# + #......x.# + #........# + ########## \ No newline at end of file diff --git a/dcss-data/tests/scenarios/monsters/kobold_spell.yaml b/dcss-data/tests/scenarios/monsters/kobold_spell.yaml new file mode 100644 index 0000000..b332e75 --- /dev/null +++ b/dcss-data/tests/scenarios/monsters/kobold_spell.yaml @@ -0,0 +1,20 @@ +options: + default_feature: "floor" + +levels: + - level: + name: D:1 + features: + - '# = metal_wall' + - '. = floor' + monsters: + - 'x = kobold generate_awake spells:throw_flame;rebounding_chill' # Kobolt with spells + map: |- + ########## + #........# + #.@......# + #........# + #........# + #......x.# + #........# + ########## \ No newline at end of file diff --git a/dcss-data/tests/scenarios/monsters/kobold_strong.yaml b/dcss-data/tests/scenarios/monsters/kobold_strong.yaml new file mode 100644 index 0000000..9343750 --- /dev/null +++ b/dcss-data/tests/scenarios/monsters/kobold_strong.yaml @@ -0,0 +1,20 @@ +options: + default_feature: "floor" + +levels: + - level: + name: D:1 + features: + - '# = metal_wall' + - '. = floor' + monsters: + - 'x = kobold generate_awake hp:20 ; battleaxe . chain mail' # With 20 hp, a battleaxe and a chain mail + map: |- + ########## + #........# + #.@......# + #........# + #........# + #......x.# + #........# + ########## \ No newline at end of file diff --git a/dcss-data/tests/scenarios/monsters/kobold_two_hits.yaml b/dcss-data/tests/scenarios/monsters/kobold_two_hits.yaml new file mode 100644 index 0000000..36d7b0b --- /dev/null +++ b/dcss-data/tests/scenarios/monsters/kobold_two_hits.yaml @@ -0,0 +1,20 @@ +options: + default_feature: "floor" + +levels: + - level: + name: D:1 + features: + - '# = metal_wall' + - '. = floor' + monsters: + - 'x = kobold generate_awake ; quick blade' + map: |- + ########## + #........# + #.@......# + #........# + #........# + #......x.# + #........# + ########## \ No newline at end of file diff --git a/dcss-data/tests/scenarios/monsters/size.yaml b/dcss-data/tests/scenarios/monsters/size.yaml new file mode 100644 index 0000000..cc72da3 --- /dev/null +++ b/dcss-data/tests/scenarios/monsters/size.yaml @@ -0,0 +1,25 @@ +options: + default_feature: "floor" + +levels: + - level: + name: D:1 + features: + - '# = metal_wall' + - '. = floor' + monsters: + - 'a = hornet generate_awake' + - 'b = endoplasm generate_awake' + - 'c = kobold generate_awake' + - 'd = angel generate_awake' + - 'e = hellwing generate_awake' + - 'f = ettin generate_awake' + map: |- + ########## + #........# + #.@......# + #........# + #........# + #.abcdef.# + #........# + ########## \ No newline at end of file diff --git a/dcss-data/tests/scenarios/monsters/touching.yaml b/dcss-data/tests/scenarios/monsters/touching.yaml new file mode 100644 index 0000000..65bbb89 --- /dev/null +++ b/dcss-data/tests/scenarios/monsters/touching.yaml @@ -0,0 +1,20 @@ +options: + default_feature: "floor" + +levels: + - level: + name: D:1 + features: + - '# = metal_wall' + - '. = floor' + monsters: + - 'x = kobold' + map: |- + ########## + #........# + #.@x.....# + #........# + #........# + #........# + #........# + ########## \ No newline at end of file diff --git a/dcss-data/tests/scenarios/tiles/box_7x7.yaml b/dcss-data/tests/scenarios/tiles/box_7x7.yaml new file mode 100644 index 0000000..d9d9d5d --- /dev/null +++ b/dcss-data/tests/scenarios/tiles/box_7x7.yaml @@ -0,0 +1,20 @@ +options: + default_feature: "floor" + +levels: + - level: + name: D:1 + features: + - '# = metal_wall' + - '. = floor' + + map: |- + ######### + #.......# + #.......# + #.......# + #...@...# + #.......# + #.......# + #.......# + ######### \ No newline at end of file diff --git a/dcss-data/tests/scenarios/tiles/box_7x7_monster.yaml b/dcss-data/tests/scenarios/tiles/box_7x7_monster.yaml new file mode 100644 index 0000000..8107d28 --- /dev/null +++ b/dcss-data/tests/scenarios/tiles/box_7x7_monster.yaml @@ -0,0 +1,22 @@ +options: + default_feature: "floor" + +levels: + - level: + name: D:1 + features: + - '# = metal_wall' + - '. = floor' + monsters: + - 'M = Kobold' + + map: |- + ######### + #.......# + #.......# + #.......# + #...@...# + #.......# + #...M...# + #.......# + ######### \ No newline at end of file diff --git a/dcss-data/tests/scenarios/tiles/feature.yaml b/dcss-data/tests/scenarios/tiles/feature.yaml new file mode 100644 index 0000000..0a5a51a --- /dev/null +++ b/dcss-data/tests/scenarios/tiles/feature.yaml @@ -0,0 +1,21 @@ +options: + default_feature: "floor" + +levels: + - level: + name: D:1 + features: + - '# = metal_wall' + - '. = floor' + - 'X = lava' + + map: |- + ######### + #.......# + #.......# + #.......# + #...@...# + #.......# + #...X...# + #.......# + ######### \ No newline at end of file diff --git a/dcss-data/tests/test-monsters.rs b/dcss-data/tests/test-monsters.rs new file mode 100644 index 0000000..fecf5fe --- /dev/null +++ b/dcss-data/tests/test-monsters.rs @@ -0,0 +1,349 @@ +mod common; + +#[test] +fn no_monster() { + let mut webtile = common::setup_webtile("Monsters1", "./tests/scenarios/tiles/box_7x7.yaml"); + let mut data = common::setup_data(&mut webtile); + + // Number of monsters that can be reached + assert!(data.monster_count_path() == 0); + + // Number of monsters that can be seen + assert!(data.monster_count_fov() == 0); + + // Test nearest_monster_path + assert!(data.nearest_monster_path().is_empty()); + + // Test coord_nearest_monster + let coord = None; + assert!(data.coord_nearest_monster() == coord); + + // Touching a monster + assert!(!data.monster_touching()); + + // Get threat vector + assert!(data.get_monster_threat_vec().is_empty()); + + // No monster to care about their info + assert!(data.get_battle_monster_info().is_empty()); + assert!(data.get_attacking_monster_info().is_empty()); + + webtile.quit_game().unwrap(); + + webtile.disconnect().unwrap(); +} + +#[test] +fn monster_from_tiles() { + let mut webtile = common::setup_webtile("Monsters2", "./tests/scenarios/monsters/kobold.yaml"); + let mut data = common::setup_data(&mut webtile); + + // Number of monsters that can be reached + assert!(data.monster_count_path() == 1); + + // Number of monsters that can be seen + assert!(data.monster_count_fov() == 1); + + // Test nearest_monster_path + let path = [(1, 1), (1, 1), (1, 1), (1, 0), (1, 0)]; + assert!(data.nearest_monster_path() == path.to_vec()); + + // Test coord_nearest_monster + let coord = (5, 3); + assert!(data.coord_nearest_monster() == Some(coord)); + + // Touching a monster + assert!(!data.monster_touching()); + + // Touching a monster + assert!(!data.monster_touching()); + + // Get threat vector + assert!(data.get_monster_threat_vec() == [1]); + + webtile.quit_game().unwrap(); + + webtile.disconnect().unwrap(); +} + +#[test] +fn glass_box() { + let mut webtile = + common::setup_webtile("Monsters3", "./tests/scenarios/monsters/glass_box.yaml"); + let mut data = common::setup_data(&mut webtile); + + // Number of monsters that can be reached + assert!(data.monster_count_path() == 1); + + // Number of monsters that can be seen + assert!(data.monster_count_fov() == 2); + + // Test nearest_monster_path + let path = [(0, 1), (0, 1), (0, 1)]; + assert!(data.nearest_monster_path() == path.to_vec()); + + // Test coord_nearest_monster + let coord = (0, 3); + assert!(data.coord_nearest_monster() == Some(coord)); + + // Touching a monster + assert!(!data.monster_touching()); + + // Get threat vector + assert!(data.get_monster_threat_vec() == [1, 1]); + + webtile.quit_game().unwrap(); + + webtile.disconnect().unwrap(); +} + +#[test] +fn touching() { + let mut webtile = + common::setup_webtile("Monsters4", "./tests/scenarios/monsters/touching.yaml"); + let mut data = common::setup_data(&mut webtile); + + // Number of monsters that can be reached + assert!(data.monster_count_path() == 1); + + // Number of monsters that can be seen + assert!(data.monster_count_fov() == 1); + + // Test nearest_monster_path + let path = [(1, 0)]; + assert!(data.nearest_monster_path() == path.to_vec()); + + // Test coord_nearest_monster + let coord = (1, 0); + assert!(data.coord_nearest_monster() == Some(coord)); + + // Touching a monster + assert!(data.monster_touching()); + + // Get threat vector + assert!(data.get_monster_threat_vec() == [1]); + + webtile.quit_game().unwrap(); + + webtile.disconnect().unwrap(); +} + +#[test] +fn kobold_info() { + let mut webtile = common::setup_webtile("Monsters5", "./tests/scenarios/monsters/kobold.yaml"); + let mut data = common::setup_data(&mut webtile); + + // Sleepy monster + assert!(data.get_pos_of_incapacitated_monster().is_none()); + + // Look at monster to get more info + common::examine_monster( + data.coord_nearest_monster().unwrap(), + &mut webtile, + &mut data, + ); + + // Sleepy monster + assert!(data.get_pos_of_incapacitated_monster() == Some((5, 3))); + + // Note, this moster is asleep + let mon_data = &data.get_battle_monster_info()[0]; + + // * `threat` = threat level ("Minor" => 1 | "Low" => 2 | "High" => 4 | "Lethal" => 5) + assert!(mon_data["threat"] == 2); + + // * `max_hp` = maximum hp + assert!(mon_data["max_hp"] == 3); + + // * `will` = will + assert!(mon_data["will"] == 0); + + // * `ac` = ac + assert!(mon_data["ac"] == 1); + + // * `ev` = ev + assert!(mon_data["ev"] == 3); + + // * `fire` = fire resistance + assert!(mon_data["fire"] == 0); + + // * `cold` = cold resistance + assert!(mon_data["cold"] == 0); + + // * `poison` = poison resistance + assert!(mon_data["poison"] == 0); + + // * `negative` = negative resistance + assert!(mon_data["negative"] == 0); + + // * `electric` = electric resistance + assert!(mon_data["electric"] == 0); + + // * `class` = monster class ("Natural" => 1 | "Undead" => 2 | "Demonic" => 3 | "Nonliv." => 4 | "Plant" => 5) + assert!(mon_data["class"] == 1); + + // * `size` = monster size ("Tiny" => 1 | "V. Small" => 2 | "Small" => 3 | "Medium" => 4 | "Large" => 5 | "Giant" => 6) + assert!(mon_data["size"] == 3); + + // * `int` = monster intelligence ("Mindless" => 1 | "Animal" => 2 | "Human" => 3) + assert!(mon_data["int"] == 3); + + // * `speed` = monster speed (% compared to player) + assert!(mon_data["speed"] == 100); + + // * `regen` = monster regeneration + assert!(mon_data["regen"] == 0); + + // * `player_hit_monster_chance` = chance to hit monster (%) + assert!(mon_data["player_hit_monster_chance"] == 98); + + // * `monster_hit_player_chance` = chance the monster hits the player (%) + assert!(mon_data["monster_hit_player_chance"] == 57); + + // * `max_damage` = max damage the monster can do to the player + assert!(mon_data["max_damage"] == 5); + + // Add test if new ones are added + assert!(mon_data.len() == 18); + + webtile.quit_game().unwrap(); + + webtile.disconnect().unwrap(); +} + +#[test] +fn kobold_strong_info() { + let mut webtile = + common::setup_webtile("Monsters6", "./tests/scenarios/monsters/kobold_strong.yaml"); + let mut data = common::setup_data(&mut webtile); + + // Look at monster to get more info + common::examine_monster( + data.coord_nearest_monster().unwrap(), + &mut webtile, + &mut data, + ); + + let mon_data = &data.get_battle_monster_info()[0]; + + // * `max_hp` = maximum hp + assert!(mon_data["max_hp"] == 20); + + // * `ac` = ac + assert!(mon_data["ac"] == 2); + + // * `player_hit_monster_chance` = chance to hit monster (%) + assert!(mon_data["player_hit_monster_chance"] == 58); + + // * `monster_hit_player_chance` = chance the monster hits the player (%) + assert!(mon_data["monster_hit_player_chance"] == 38); + + // * `max_damage` = max damage the monster can do to the player + assert!(mon_data["max_damage"] == 15); + + webtile.quit_game().unwrap(); + + webtile.disconnect().unwrap(); +} + +#[test] +fn kobold_two_hits_info() { + let mut webtile = common::setup_webtile( + "Monsters7", + "./tests/scenarios/monsters/kobold_two_hits.yaml", + ); + let mut data = common::setup_data(&mut webtile); + + // Look at monster to get more info + common::examine_monster( + data.coord_nearest_monster().unwrap(), + &mut webtile, + &mut data, + ); + + let mon_data = &data.get_battle_monster_info()[0]; + + // * `max_damage` = max damage the monster can do to the player + assert!(mon_data["max_damage"] == 8); + + webtile.quit_game().unwrap(); + + webtile.disconnect().unwrap(); +} + +#[test] +fn kobold_ranged_info() { + let mut webtile = + common::setup_webtile("Monsters8", "./tests/scenarios/monsters/kobold_ranged.yaml"); + let mut data = common::setup_data(&mut webtile); + + // Look at monster to get more info + common::examine_monster( + data.coord_nearest_monster().unwrap(), + &mut webtile, + &mut data, + ); + + let mon_data = &data.get_battle_monster_info()[0]; + + // * `max_damage` = max damage the monster can do to the player + assert!(mon_data["max_damage"] == 7); + + let mon_data = &data.get_attacking_monster_info()[0]; + + // * `max_damage` = max damage the monster can do to the player + assert!(mon_data["max_damage"] == 7); + + webtile.quit_game().unwrap(); + + webtile.disconnect().unwrap(); +} + +#[test] +fn kobold_polearm_info() { + let mut webtile = common::setup_webtile( + "Monsters9", + "./tests/scenarios/monsters/kobold_polearm.yaml", + ); + let mut data = common::setup_data(&mut webtile); + + // Look at monster to get more info + while let Some(coord) = data.get_pos_of_unexamined_monster() { + common::examine_monster(coord, &mut webtile, &mut data); + } + + let mon_data = &data.get_battle_monster_info(); + + assert!(mon_data.len() == 3); + + let mon_data = &data.get_attacking_monster_info(); + + assert!(mon_data.len() == 2); + + webtile.quit_game().unwrap(); + + webtile.disconnect().unwrap(); +} + +#[test] +fn size_info() { + let mut webtile = common::setup_webtile("Monsters10", "./tests/scenarios/monsters/size.yaml"); + let mut data = common::setup_data(&mut webtile); + + // Look at monster to get more info + while let Some(coord) = data.get_pos_of_unexamined_monster() { + common::examine_monster(coord, &mut webtile, &mut data); + } + + // * `size` = monster size ("Tiny" => 1 | "V. Small" => 2 | "Small" => 3 | "Medium" => 4 | "Large" => 5 | "Giant" => 6) + let mon_data = &data.get_battle_monster_info(); + + let mut sizes = mon_data.iter().map(|m| m["size"]).collect::>(); + sizes.sort(); + + assert!(sizes == vec![1, 2, 3, 4, 5, 6]); + + webtile.quit_game().unwrap(); + + webtile.disconnect().unwrap(); +} diff --git a/dcss-data/tests/test-player.rs b/dcss-data/tests/test-player.rs new file mode 100644 index 0000000..d41f49b --- /dev/null +++ b/dcss-data/tests/test-player.rs @@ -0,0 +1,13 @@ +// mod common; + +// #[test] +// fn basic_wearing_basic() { +// let mut webtile = common::setup_webtile("Player1", "./tests/scenarios/tiles/box_7x7.yaml"); +// let mut data = common::setup_data(&mut webtile); + +// panic!(); + +// // webtile.quit_game().unwrap(); + +// // webtile.disconnect().unwrap(); +// } diff --git a/dcss-data/tests/test-tiles.rs b/dcss-data/tests/test-tiles.rs index 95151a4..4a1a1bb 100644 --- a/dcss-data/tests/test-tiles.rs +++ b/dcss-data/tests/test-tiles.rs @@ -1,50 +1,159 @@ -// mod common; - -// use dcss_api::Webtile; -// use dcss_scenario_builder::start_game_with_scenario; - -// #[test] -// fn verify_wizmode() -> Result<(), Error> { -// // Safe test -- login start game, quit, and then test -// reset_test("Username"); - -// // Connect to DCSS Webtile -// let mut webtile = -// Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect."); - -// // Empty message queue; -// while webtile.get_message().is_some() {} - -// // Log in (to a user called "Username", with a password "Password") -// let _gameid = webtile -// .login_with_credentials("Username", "Password") -// .expect("Failed to login."); - -// // Start game with simple scenario. -// start_game_with_scenario( -// &mut webtile, -// "dcss-0.32", -// "b", -// "i", -// "c", -// "./tests/test_scenarios/simple_map.yaml", -// ) -// .expect("Failed to start game with scenario."); - -// webtile.save_game().expect("Failed to save game."); - -// webtile.continue_game("dcss-0.32")?; - -// while let Some(message) = webtile.get_message() { -// if message["msg"].as_str().unwrap() == "player" -// && message.as_object().unwrap().contains_key("wizard") -// && message["wizard"].as_u64().unwrap() == 1 -// { -// // webtile.quit_game()?; -// webtile.disconnect().expect("Failed"); -// return Ok(()); -// } -// } - -// unreachable!(); -// } +mod common; + +#[test] +fn box_7x7() { + let mut webtile = common::setup_webtile("Tiles1", "./tests/scenarios/tiles/box_7x7.yaml"); + let mut data = common::setup_data(&mut webtile); + + // Tiles [x, y] + // [-y] + // ↖ ↑ ↗ + // [-x] ← · → [+x] + // ↙ ↓ ↘ + // [+y] + + // Verify area is explored + for x in -5..5 { + for y in -5..5 { + if (-4..=4).contains(&x) && (-4..=4).contains(&y) { + assert!(data.tile_explored(x, y)); + } else { + assert!(!data.tile_explored(x, y)); + } + } + } + + // Verify area is walkable + for x in -5..5 { + for y in -5..5 { + if (-3..=3).contains(&x) && (-3..=3).contains(&y) { + assert!(data.tile_walkable(x, y)); + } else { + assert!(!data.tile_walkable(x, y)); + } + } + } + + webtile.quit_game().unwrap(); + + webtile.disconnect().unwrap(); +} + +#[test] +fn box_7x7_monster() { + let mut webtile = + common::setup_webtile("Tiles2", "./tests/scenarios/tiles/box_7x7_monster.yaml"); + let mut data = common::setup_data(&mut webtile); + + // Tiles [x, y] + // [-y] + // ↖ ↑ ↗ + // [-x] ← · → [+x] + // ↙ ↓ ↘ + // [+y] + + // Verify area is explored + for x in -5..5 { + for y in -5..5 { + if (-4..=4).contains(&x) && (-4..=4).contains(&y) { + assert!(data.tile_explored(x, y)); + } else { + assert!(!data.tile_explored(x, y)); + } + } + } + + // Verify area is walkable (except monster) + for x in -5..5 { + for y in -5..5 { + if (-3..=3).contains(&x) && (-3..=3).contains(&y) { + if x == 0 && y == 2 { + // Monster + assert!(!data.tile_walkable(x, y)); + } else { + assert!(data.tile_walkable(x, y)); + } + } else { + assert!(!data.tile_walkable(x, y)); + } + } + } + + // Verify area is walkable (in spite of monster) + for x in -5..5 { + for y in -5..5 { + if (-3..=3).contains(&x) && (-3..=3).contains(&y) { + assert!(data.tile_walkable_ignore_blocked(x, y)); + } else { + assert!(!data.tile_walkable_ignore_blocked(x, y)); + } + } + } + + webtile.quit_game().unwrap(); + + webtile.disconnect().unwrap(); +} + +#[test] +fn feature() { + let mut webtile = common::setup_webtile("Tiles3", "./tests/scenarios/tiles/feature.yaml"); + let mut data = common::setup_data(&mut webtile); + + // Tiles [x, y] + // [-y] + // ↖ ↑ ↗ + // [-x] ← · → [+x] + // ↙ ↓ ↘ + // [+y] + + // Verify area is explored + for x in -5..5 { + for y in -5..5 { + if (-4..=4).contains(&x) && (-4..=4).contains(&y) { + assert!(data.tile_explored(x, y)); + } else { + assert!(!data.tile_explored(x, y)); + } + } + } + + // Verify area is walkable (except monster) + for x in -5..5 { + for y in -5..5 { + if (-3..=3).contains(&x) && (-3..=3).contains(&y) { + if x == 0 && y == 2 { + // Lava + assert!(!data.tile_walkable(x, y)); + } else { + assert!(data.tile_walkable(x, y)); + } + } else { + assert!(!data.tile_walkable(x, y)); + } + } + } + + // Verify mf type + for x in -5..5 { + for y in -5..5 { + if x == 5 || x == -5 || y == 5 || y == -5 { + assert!(data.tile_mf(x, y) == 0); // unexplored + } else if x == 4 || x == -4 || y == 4 || y == -4 { + assert!(data.tile_mf(x, y) == 2); // wall + } else if (-3..=3).contains(&x) && (-3..=3).contains(&y) { + if x == 0 && y == 2 { + assert!(data.tile_mf(x, y) == 17); // lava + } else { + assert!(data.tile_mf(x, y) == 1); // floor + } + } else { + panic!(); + } + } + } + + webtile.quit_game().unwrap(); + + webtile.disconnect().unwrap(); +} diff --git a/dcss-scenario-builder/Cargo.lock b/dcss-scenario-builder/Cargo.lock index 531c825..7972d01 100644 --- a/dcss-scenario-builder/Cargo.lock +++ b/dcss-scenario-builder/Cargo.lock @@ -4,15 +4,15 @@ version = 4 [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "block-buffer" @@ -31,18 +31,19 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" -version = "1.2.16" +version = "1.2.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" dependencies = [ + "find-msvc-tools", "shlex", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "core-foundation" @@ -71,9 +72,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] @@ -90,15 +91,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" +checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" [[package]] name = "dcss-api" -version = "0.2.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc93b44b2084b09f5d319197738860dbad7de0f8bf30080dcbb4f8656c845e62" +checksum = "1aba1fba55c01f3a9def4ef09d68ed1557c20bf7d19163b54676b8ef7d5b9800" dependencies = [ "flate2", "serde_json", @@ -108,7 +109,7 @@ dependencies = [ [[package]] name = "dcss-scenario-builder" -version = "0.2.2" +version = "0.4.0" dependencies = [ "dcss-api", "itertools", @@ -141,9 +142,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.10" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", "windows-sys", @@ -155,11 +156,17 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "find-msvc-tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" + [[package]] name = "flate2" -version = "1.1.0" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" dependencies = [ "crc32fast", "libz-sys", @@ -199,27 +206,27 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "libc", + "r-efi", "wasi", - "windows-targets", ] [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "http" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" dependencies = [ "bytes", "fnv", @@ -234,9 +241,9 @@ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "indexmap" -version = "2.7.1" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", "hashbrown", @@ -259,15 +266,15 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "libc" -version = "0.2.170" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libz-sys" -version = "1.1.21" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa" +checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" dependencies = [ "cc", "pkg-config", @@ -276,29 +283,30 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.9.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9c683daf087dc577b7506e9695b3d556a9f3849903fa28186283afd6809e9" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "log" -version = "0.4.26" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "miniz_oxide" -version = "0.8.5" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -320,15 +328,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "openssl" -version = "0.10.71" +version = "0.10.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" +checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" dependencies = [ "bitflags", "cfg-if", @@ -358,18 +366,18 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-src" -version = "300.4.2+3.4.1" +version = "300.5.3+3.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168ce4e058f975fe43e89d9ccf78ca668601887ae736090aacc23ae353c298e2" +checksum = "dc6bad8cd0233b63971e232cc9c5e83039375b8586d2312f31fda85db8f888c2" dependencies = [ "cc", ] [[package]] name = "openssl-sys" -version = "0.9.106" +version = "0.9.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" dependencies = [ "cc", "libc", @@ -395,31 +403,36 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.39" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha", "rand_core", - "zerocopy", ] [[package]] @@ -449,9 +462,9 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustix" -version = "1.0.2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ "bitflags", "errno", @@ -468,9 +481,9 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ "windows-sys", ] @@ -490,9 +503,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -500,18 +513,27 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -520,14 +542,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] @@ -560,11 +583,17 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "syn" -version = "2.0.100" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -573,11 +602,10 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.18.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c317e0a526ee6120d8dabad239c8dadca62b24b6f168914bbbc8e2fb1f0e567" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ - "cfg-if", "fastrand", "getrandom", "once_cell", @@ -587,18 +615,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -607,9 +635,9 @@ dependencies = [ [[package]] name = "tungstenite" -version = "0.26.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" dependencies = [ "bytes", "data-encoding", @@ -625,15 +653,15 @@ dependencies = [ [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unsafe-libyaml" @@ -661,109 +689,57 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" -version = "0.13.3+wasi-0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" -dependencies = [ - "wit-bindgen-rt", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" +version = "0.14.7+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c" dependencies = [ - "windows-targets", + "wasip2", ] [[package]] -name = "windows-targets" -version = "0.52.6" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "wit-bindgen", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] [[package]] -name = "wit-bindgen-rt" -version = "0.33.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" -dependencies = [ - "bitflags", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "zerocopy" -version = "0.8.23" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.23" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", diff --git a/dcss-scenario-builder/Cargo.toml b/dcss-scenario-builder/Cargo.toml index 4064f43..16cbb49 100644 --- a/dcss-scenario-builder/Cargo.toml +++ b/dcss-scenario-builder/Cargo.toml @@ -1,8 +1,8 @@ [package] authors = ["Eric Fecteau "] name = "dcss-scenario-builder" -version = "0.2.2" -edition = "2021" +version = "0.4.0" +edition = "2024" license = "MPL-2.0" description = "A scenario builder for DCSS Webtile." repository = "https://github.com/EricFecteau/dcss-api/" @@ -12,7 +12,7 @@ readme = "README.md" doctest = false [dependencies] -dcss-api = "0.2" +dcss-api = "0.4" rustc-hash = "2" serde_yaml = "0.9" itertools = "0.14" diff --git a/dcss-scenario-builder/README.md b/dcss-scenario-builder/README.md index 062883b..49abc24 100644 --- a/dcss-scenario-builder/README.md +++ b/dcss-scenario-builder/README.md @@ -1,6 +1,6 @@ # dcss-scenario-builder -`dcss-scenario-builder` creates scenarios in [Dungeon Crawl Stone Soup's (DCSS) Webtile](https://crawl.develz.org/) using [dcss-api](https://docs.rs/dcss-api/latest/dcss_api/index.html) in `wizmode` from a yaml file. It can create any floor layout, from any feature, and add any item or monster. +`dcss-scenario-builder` creates scenarios in [Dungeon Crawl Stone Soup's (DCSS) Webtile](https://crawl.develz.org/) using [dcss-api](https://docs.rs/dcss-api/latest/dcss_api/index.html) in `wizmode` from a yaml file. It can create any floor layout, from any feature, and add any item or monster. The `yaml` generally works with the [Vault Design Reference Guide](https://crawl.develz.org/wiki/doku.php?id=dcss:help:maps). ## Example @@ -56,7 +56,7 @@ levels: ```Rust // Connect to DCSS Webtile -let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0, "0.30")?; +let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0)?; // Empty message queue; while webtile.get_message().is_some() {} @@ -67,7 +67,7 @@ let _gameid = webtile.login_with_credentials("Username", "Password")?; // Create scenario start_game_with_scenario( &mut webtile, - "dcss-0.32", + "dcss-0.33", "b", "i", "c", diff --git a/dcss-scenario-builder/examples/1_basic.rs b/dcss-scenario-builder/examples/1_basic.rs index 84745a0..0d70a0a 100644 --- a/dcss-scenario-builder/examples/1_basic.rs +++ b/dcss-scenario-builder/examples/1_basic.rs @@ -1,9 +1,9 @@ use dcss_api::Webtile; -use dcss_scenario_builder::{start_game_with_scenario, Error}; +use dcss_scenario_builder::{Error, start_game_with_scenario}; fn main() -> Result<(), Error> { // Connect to DCSS Webtile - let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0, "0.30")?; + let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0)?; // Empty message queue; while webtile.get_message().is_some() {} @@ -14,11 +14,11 @@ fn main() -> Result<(), Error> { // Start game start_game_with_scenario( &mut webtile, - "dcss-0.32", + "dcss-0.33", "b", "i", "c", - "./scenarios/branches.yaml", + "./scenarios/monsters.yaml", )?; // dcss_scenario_builder::print_lua("./scenarios/features.yaml").expect("Failed"); diff --git a/dcss-scenario-builder/examples/2_readme.rs b/dcss-scenario-builder/examples/2_readme.rs index 26e848f..668a701 100644 --- a/dcss-scenario-builder/examples/2_readme.rs +++ b/dcss-scenario-builder/examples/2_readme.rs @@ -1,9 +1,9 @@ use dcss_api::Webtile; -use dcss_scenario_builder::{start_game_with_scenario, Error}; +use dcss_scenario_builder::{Error, start_game_with_scenario}; fn main() -> Result<(), Error> { // Connect to DCSS Webtile - let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0, "0.30")?; + let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0)?; // Empty message queue; while webtile.get_message().is_some() {} @@ -14,7 +14,7 @@ fn main() -> Result<(), Error> { // Start game start_game_with_scenario( &mut webtile, - "dcss-0.32", + "dcss-0.33", "b", "i", "c", diff --git a/dcss-scenario-builder/scenarios/monsters.yaml b/dcss-scenario-builder/scenarios/monsters.yaml new file mode 100644 index 0000000..2642f45 --- /dev/null +++ b/dcss-scenario-builder/scenarios/monsters.yaml @@ -0,0 +1,37 @@ +options: + default_feature: "floor" + +# https://crawl.develz.org/wiki/doku.php?id=dcss:help:maps:syntax:monster_info + +levels: + - level: + name: D:1 + features: + - '# = metal_wall' + - '. = floor' + monsters: + - 'a = kobold' # Simple + - 'b = kobold hp:20' # With specific HP + - 'c = kobold hd:5' # With high hp (decided by hit dice (hd)) + - 'd = kobold att:friendly' # Friendly + - 'e = kobold name:Bob' # Named + - 'f = kobold spells:throw_flame' # With spell + - 'g = random' # Random monster + - 'h = random place:Slime:5' # Random monster from Slime:5 + - 'i = place:Elf:3 zombie' # random from Elf, but Zombie + - 'j = generate_awake kobold' # Awake + - 'k = twenty-headed hydra' # Hydra heads + - 'l = very large slime creature' # Size of slime + - 'm = orc god:trog god_gift' # Specify god + - 'n = kobold ; hand cannon' # Kobold with hand cannon + - 'o = kobold ; nothing' # Kobold with nothing (as weapon) + map: |- + ########## + #........# + #....afk.# + #....bgl.# + #.@..chm.# + #....din.# + #....ejo.# + #........# + ########## \ No newline at end of file diff --git a/dcss-scenario-builder/src/lib.rs b/dcss-scenario-builder/src/lib.rs index 437d821..6f8c2c1 100644 --- a/dcss-scenario-builder/src/lib.rs +++ b/dcss-scenario-builder/src/lib.rs @@ -29,7 +29,7 @@ use crate::lua_builder::process_scenario; /// ```no_run /// // Start a scenario game, for a Minotaur (b), Berserker (f), with a mace (b) using the /// // branches.yaml scenario. -/// start_game_with_scenario(&mut webtile, "dcss-0.32", "b", "f", "b", "./scenarios/branches.yaml")?; +/// start_game_with_scenario(&mut webtile, "dcss-0.33", "b", "f", "b", "./scenarios/branches.yaml")?; /// ``` pub fn start_game_with_scenario( webtile: &mut Webtile, diff --git a/dcss-scenario-builder/src/lua_builder.rs b/dcss-scenario-builder/src/lua_builder.rs index 42d1243..8aa4f58 100644 --- a/dcss-scenario-builder/src/lua_builder.rs +++ b/dcss-scenario-builder/src/lua_builder.rs @@ -1,7 +1,7 @@ -use crate::common::{branch_keys, Coord}; +use crate::common::{Coord, branch_keys}; use crate::{Error, YamlParsingError}; use rustc_hash::FxHashMap; -use serde_yaml::{from_reader, Value}; +use serde_yaml::{Value, from_reader}; /// Reads the scenario file, processes the input, identifies the features, /// items and monsters and converts each floor into lua commands to be @@ -75,7 +75,7 @@ pub(crate) fn process_scenario( // back on D:1 and 2 on Slime Pit will spawn you back on Lair:2) // Must be from real parent (e.g. can put slime pit entrance in dungeon, but leaving // will place you in a real dungeon) - lua_scenario.push(format!("debug.goto_place(\"{}\", 1)\n", level_name).to_owned()); + lua_scenario.push(format!("debug.goto_place(\"{level_name}\", 1)\n").to_owned()); lua_scenario.push("you.moveto(1,1)\n".to_owned()); @@ -98,7 +98,7 @@ pub(crate) fn process_scenario( /// # Arguments /// /// * `glyphs` - a vector of glyphs and equivalent text from the YAML that -/// can be understood by DCSS. +/// can be understood by DCSS. fn process_glyphs(glyphs: Vec<&str>) -> FxHashMap { glyphs .iter() @@ -115,14 +115,14 @@ fn process_glyphs(glyphs: Vec<&str>) -> FxHashMap { /// # Arguments /// /// * `features` - [FxHashMap] of the mapping between the glyphs -/// in the map and the feature understandable by -/// DCSS. +/// in the map and the feature understandable by +/// DCSS. /// * `items` - [FxHashMap] of the mapping between the glyphs -/// in the map and the item understandable by -/// DCSS. +/// in the map and the item understandable by +/// DCSS. /// * `monsters` - [FxHashMap] of the mapping between the glyphs -/// in the map and the monster understandable by -/// DCSS. +/// in the map and the monster understandable by +/// DCSS. /// * `map` - the map from the YAML. /// * `default_feature` - the default feature for missing glyphs. fn process_map( @@ -176,8 +176,7 @@ fn process_map( &features[glyph] }; - let lua_feat_line = - format!("dgn.terrain_changed({}, {}, \"{}\")\n", x, y, glyph_feature); + let lua_feat_line = format!("dgn.terrain_changed({x}, {y}, \"{glyph_feature}\")\n"); lua_map.push(lua_feat_line); if items.is_some() && items.unwrap().contains_key(glyph) { diff --git a/dcss-scenario-builder/src/scenario_errors.rs b/dcss-scenario-builder/src/scenario_errors.rs index e8f5c51..0722879 100644 --- a/dcss-scenario-builder/src/scenario_errors.rs +++ b/dcss-scenario-builder/src/scenario_errors.rs @@ -5,7 +5,7 @@ use thiserror::Error; #[derive(Error)] pub enum Error { #[error(transparent)] - APIError(#[from] APIError), + APIError(#[from] Box), #[error(transparent)] IOError(#[from] std::io::Error), #[error(transparent)] @@ -18,7 +18,7 @@ pub enum Error { impl std::fmt::Debug for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self)?; + write!(f, "{self}")?; Ok(()) } } diff --git a/dcss-scenario-builder/src/wizmode.rs b/dcss-scenario-builder/src/wizmode.rs index e49bc29..702f7ab 100644 --- a/dcss-scenario-builder/src/wizmode.rs +++ b/dcss-scenario-builder/src/wizmode.rs @@ -1,4 +1,4 @@ -use crate::common::{branch_keys, Coord}; +use crate::common::{Coord, branch_keys}; use crate::scenario_errors::Error; use dcss_api::{BlockingError, Error as APIError, Webtile}; @@ -15,9 +15,13 @@ pub(crate) fn enable_wiz(webtile: &mut Webtile) -> Result<(), Error> { // Will have an error because of the "yes" prompt if let Err(e) = webtile.read_until("", None, None) { - match e { + match *e { APIError::Blocking(BlockingError::TextInput) => { - webtile.write_key("yes")?; + if webtile.game_version() == Some("0.33".to_string()) { + webtile.write_key("wiz")?; + } else { + webtile.write_key("yes")?; + } webtile.write_key("key_enter")?; } _ => Err(e)?, @@ -62,7 +66,7 @@ pub(crate) fn setup_map( webtile.write_key(&branch_key)?; if let Err(e) = webtile.read_until("map", Some("player_on_level"), None) { - match e { + match *e { APIError::Blocking(BlockingError::TextInput) => { webtile.write_key(&branch_level)?; webtile.write_key("key_enter")?; @@ -81,7 +85,7 @@ pub(crate) fn setup_map( // Ignore "TextInput" error, enter the lua and run it (by chunk, max ~100 lines) for lua_chunk in &level_lua.lines().chunks(100) { if let Err(e) = webtile.read_until("", None, None) { - match e { + match *e { APIError::Blocking(BlockingError::TextInput) => { webtile.write_key(&lua_chunk.collect::())?; webtile.write_key("key_enter")?; @@ -93,7 +97,7 @@ pub(crate) fn setup_map( // Ignore "TextInput" error, leave lua interpreter if let Err(e) = webtile.read_until("", None, None) { - match e { + match *e { APIError::Blocking(BlockingError::TextInput) => { webtile.write_key("key_esc")?; } @@ -121,7 +125,7 @@ pub(crate) fn setup_map( // Prevent "more" -- especially in the Abyss if let Err(e) = webtile.read_until("map", None, None) { - match e { + match *e { APIError::Blocking(BlockingError::More) => { webtile.write_key(" ")?; webtile.read_until("map", None, None)?; @@ -155,7 +159,7 @@ pub(crate) fn setup_map( webtile.read_until("menu", None, None)?; webtile.write_key("D")?; if let Err(e) = webtile.read_until("player", Some("place"), None) { - match e { + match *e { APIError::Blocking(BlockingError::TextInput) => { webtile.write_key("1")?; webtile.write_key("key_enter")?; @@ -172,7 +176,7 @@ pub(crate) fn setup_map( webtile.write_key("key_ctrl_t")?; if let Err(e) = webtile.read_until("", None, None) { - match e { + match *e { APIError::Blocking(BlockingError::TextInput) => { let lua_line = format!("you.moveto({}, {})\n", player_pos_d1.0, player_pos_d1.1); webtile.write_key(lua_line.as_ref())?; @@ -183,7 +187,7 @@ pub(crate) fn setup_map( } if let Err(e) = webtile.read_until("", None, None) { - match e { + match *e { APIError::Blocking(BlockingError::TextInput) => { webtile.write_key("key_esc")?; } diff --git a/dcss-scenario-builder/tests/common.rs b/dcss-scenario-builder/tests/common.rs index e346f72..82301d6 100644 --- a/dcss-scenario-builder/tests/common.rs +++ b/dcss-scenario-builder/tests/common.rs @@ -4,8 +4,7 @@ use dcss_api::Webtile; pub(crate) fn reset_test(username: &str, game_id: &str) { // Connect to DCSS Webtile - let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect"); + let mut webtile = Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect"); // Empty message queue; while webtile.get_message().is_some() {} diff --git a/dcss-scenario-builder/tests/test_incorrect.rs b/dcss-scenario-builder/tests/test_incorrect.rs index b7f020b..eca0a3d 100644 --- a/dcss-scenario-builder/tests/test_incorrect.rs +++ b/dcss-scenario-builder/tests/test_incorrect.rs @@ -6,14 +6,14 @@ use dcss_scenario_builder::start_game_with_scenario; #[should_panic] #[test] fn verify_no_character() { - let game_id = std::env::var("GAME_ID").unwrap(); + let game_id = std::env::var("GAME_ID").unwrap_or("dcss-0.33".to_owned()); // Safe test -- login start game, quit, and then test common::reset_test("Username", game_id.as_str()); // Connect to DCSS Webtile let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect."); + Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect."); // Empty message queue; while webtile.get_message().is_some() {} @@ -38,14 +38,14 @@ fn verify_no_character() { #[should_panic] #[test] fn verify_too_wide() { - let game_id = std::env::var("GAME_ID").unwrap(); + let game_id = std::env::var("GAME_ID").unwrap_or("dcss-0.33".to_owned()); // Safe test -- login start game, quit, and then test common::reset_test("Username", game_id.as_str()); // Connect to DCSS Webtile let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect."); + Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect."); // Empty message queue; while webtile.get_message().is_some() {} @@ -70,14 +70,14 @@ fn verify_too_wide() { #[should_panic] #[test] fn verify_too_long() { - let game_id = std::env::var("GAME_ID").unwrap(); + let game_id = std::env::var("GAME_ID").unwrap_or("dcss-0.33".to_owned()); // Safe test -- login start game, quit, and then test common::reset_test("Username", game_id.as_str()); // Connect to DCSS Webtile let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect."); + Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect."); // Empty message queue; while webtile.get_message().is_some() {} diff --git a/dcss-scenario-builder/tests/test_wizmode.rs b/dcss-scenario-builder/tests/test_wizmode.rs index 53e44d1..d6cceee 100644 --- a/dcss-scenario-builder/tests/test_wizmode.rs +++ b/dcss-scenario-builder/tests/test_wizmode.rs @@ -4,15 +4,15 @@ use dcss_api::{Error, Webtile}; use dcss_scenario_builder::start_game_with_scenario; #[test] -fn verify_wizmode() -> Result<(), Error> { - let game_id = std::env::var("GAME_ID").unwrap(); +fn verify_wizmode() -> Result<(), Box> { + let game_id = std::env::var("GAME_ID").unwrap_or("dcss-0.33".to_owned()); // Safe test -- login start game, quit, and then test common::reset_test("Username", game_id.as_str()); // Connect to DCSS Webtile let mut webtile = - Webtile::connect("ws://localhost:8080/socket", 0, "0.32").expect("Failed to connect."); + Webtile::connect("ws://localhost:8080/socket", 0).expect("Failed to connect."); // Empty message queue; while webtile.get_message().is_some() {}