├── .github └── workflows │ └── check.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Cargo.toml ├── LICENSE ├── README.md ├── logo.png ├── rustfmt.toml └── src ├── console.rs ├── constants.rs ├── constants ├── extra.rs ├── find.rs ├── look.rs ├── numbers.rs ├── recipes.rs ├── seasonal.rs ├── small_enums.rs └── types.rs ├── enums.rs ├── enums └── action_error_codes │ ├── constructionsite_error_codes.rs │ ├── creep_error_codes.rs │ ├── flag_error_codes.rs │ ├── game_cpu_error_codes.rs │ ├── game_map_error_codes.rs │ ├── game_market_error_codes.rs │ ├── mod.rs │ ├── powercreep_error_codes.rs │ ├── room_error_codes.rs │ ├── roomposition_error_codes.rs │ ├── sharedcreep_error_codes.rs │ ├── spawning_error_codes.rs │ ├── structure_error_codes.rs │ ├── structurecontroller_error_codes.rs │ ├── structurefactory_error_codes.rs │ ├── structurelab_error_codes.rs │ ├── structurelink_error_codes.rs │ ├── structurenuker_error_codes.rs │ ├── structureobserver_error_codes.rs │ ├── structurepowerspawn_error_codes.rs │ ├── structurerampart_error_codes.rs │ ├── structurespawn_error_codes.rs │ ├── structureterminal_error_codes.rs │ └── structuretower_error_codes.rs ├── game.rs ├── game ├── cpu.rs ├── gcl.rs ├── gpl.rs ├── map.rs ├── market.rs └── shard.rs ├── inter_shard_memory.rs ├── js_collections.rs ├── lib.rs ├── local.rs ├── local ├── cost_matrix.rs ├── lodash_filter.rs ├── object_id.rs ├── object_id │ ├── errors.rs │ └── raw.rs ├── position.rs ├── position │ ├── approximate_offsets.rs │ ├── extra_math.rs │ ├── game_math.rs │ ├── game_methods.rs │ ├── pair_utils.rs │ └── world_utils.rs ├── room_coordinate.rs ├── room_name.rs ├── room_xy.rs ├── room_xy │ ├── approximate_offsets.rs │ ├── extra_math.rs │ └── game_math.rs └── terrain.rs ├── memory.rs ├── objects.rs ├── objects ├── impls.rs └── impls │ ├── construction_site.rs │ ├── cost_matrix.rs │ ├── creep.rs │ ├── creep_shared.rs │ ├── deposit.rs │ ├── flag.rs │ ├── map_visual.rs │ ├── mineral.rs │ ├── nuke.rs │ ├── owned_structure.rs │ ├── power_creep.rs │ ├── reactor.rs │ ├── resource.rs │ ├── room.rs │ ├── room_object.rs │ ├── room_position.rs │ ├── room_terrain.rs │ ├── room_visual.rs │ ├── ruin.rs │ ├── score_collector.rs │ ├── score_container.rs │ ├── source.rs │ ├── store.rs │ ├── structure.rs │ ├── structure_container.rs │ ├── structure_controller.rs │ ├── structure_extension.rs │ ├── structure_extractor.rs │ ├── structure_factory.rs │ ├── structure_invader_core.rs │ ├── structure_keeper_lair.rs │ ├── structure_lab.rs │ ├── structure_link.rs │ ├── structure_nuker.rs │ ├── structure_observer.rs │ ├── structure_portal.rs │ ├── structure_power_bank.rs │ ├── structure_power_spawn.rs │ ├── structure_rampart.rs │ ├── structure_road.rs │ ├── structure_spawn.rs │ ├── structure_storage.rs │ ├── structure_terminal.rs │ ├── structure_tower.rs │ ├── structure_wall.rs │ ├── symbol_container.rs │ ├── symbol_decoder.rs │ └── tombstone.rs ├── pathfinder.rs ├── prototypes.rs ├── raw_memory.rs └── traits.rs /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | 3 | name: check 4 | 5 | jobs: 6 | stable: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v4 10 | - uses: dtolnay/rust-toolchain@stable 11 | with: 12 | components: clippy, rustfmt 13 | - run: cargo fmt --all -- --check 14 | - run: cargo clippy --all-features -- -D warnings 15 | - run: cargo test --all-features 16 | nightly: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v4 20 | - uses: dtolnay/rust-toolchain@nightly 21 | with: 22 | components: clippy, rustfmt 23 | - run: cargo fmt --all -- --check 24 | - run: cargo clippy --all-features -- -D warnings 25 | - run: cargo test --all-features 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled source # 2 | ################### 3 | target 4 | 5 | # Build files # 6 | ############### 7 | /Cargo.lock 8 | 9 | # Packages # 10 | ############ 11 | *.7z 12 | *.dmg 13 | *.gz 14 | *.iso 15 | *.jar 16 | *.rar 17 | *.tar 18 | *.zip 19 | 20 | # OS generated files # 21 | ###################### 22 | .DS_Store 23 | ehthumbs.db 24 | Icon? 25 | Thumbs.db 26 | 27 | # Project files # 28 | ################# 29 | .classpath 30 | .externalToolBuilders 31 | .idea 32 | .project 33 | .settings 34 | nbproject 35 | *.iml 36 | *.ipr 37 | *.iws 38 | *.sublime-project 39 | *.sublime-workspace 40 | screeps.toml 41 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to `cargo-screeps` and `screeps-game-api`: 2 | 3 | 1. Ask questions. We're all in the `#rust` channel on the [screeps discord]. 4 | 2. Make PRs early, often. We'll review code thoroughly and help where possible. 5 | 3. Issues are your guide for what needs to be done. If you think something needs doing and it isn't 6 | already an issue, make it one! 7 | 4. Whenever possible, include an update to the `CHANGELOG.md` in the Unreleased section briefly 8 | describing your change; include "(breaking)" at the end of the line if appropriate. 9 | 10 | # Style 11 | 12 | We adhere to the following guidelines: 13 | 14 | - Code Formatting: [fmt-rfcs Rust Style Guide] 15 | - API building: [Rust API Guidelines] 16 | 17 | In addition, we have the following in-house guidelines: 18 | 19 | ## Code Formatting and Linting 20 | 21 | Please run `rustfmt` and `clippy` on the files you edit when submitting to this repository. This 22 | will handle all style issues mentioned in the 'fmt-rfcs' guidelines, so you should be able to 23 | simply run `cargo fmt` and `cargo clippy` and be done with it. 24 | 25 | To install the required components, use `rustup`: 26 | 27 | ```console 28 | $ rustup component add rustfmt 29 | $ rustup component add clippy 30 | ``` 31 | 32 | To format the code in this repository, use the following: 33 | 34 | ```console 35 | $ cargo fmt 36 | ``` 37 | 38 | Also run `cargo clippy` and resolve any style issues it warns about. 39 | 40 | ```console 41 | $ cargo clippy 42 | ``` 43 | 44 | ## `use` formatting 45 | 46 | Private `use` statements should all be together: there should be no non-private-`use` statements 47 | between two private `use` statements. 48 | 49 | Importing at the module level should be preferred to importing within functions, with the 50 | exception of importing enum variants. Any statement like `use self::MyEnum::*;` should be used only 51 | within a function in order to avoid polluting the module namespace. 52 | 53 | When importing multiple things, `use` statements should be separated into the following 54 | newline-separated groups: 55 | 56 | - imports from `std` 57 | - imports from external crates 58 | - imports from the crate root 59 | - imports from `super::` 60 | - imports from `self::` 61 | 62 | `pub use` statements should be similarly grouped, but should be separate from private `use` as 63 | mentioned in [Ordering within a module]. 64 | 65 | Last, when importing from within the current crate, try to import from a more specific module rather 66 | than a less specific one. When the crate re-exports tons of types from inner modules, it can be 67 | tempting to just import everything from the crate root, but this makes it all more confusing. Import 68 | from a more specific module which defines the type rather than having 69 | `use {ResourceType, StructureProperties, LocalRoomPosition};` with each type coming from a different 70 | module. Things should at minimum use the top-level module, but can also use more specific imports 71 | for things from within the same top-level module. 72 | 73 | To clarify, each import from within the same crate should be qualified by one level of module 74 | outside of the current module's hierarchy. If in `objects::impl::construction_site`, importing 75 | `objects::impl::room::Step` should be done with `objects::impl::room::Step` or `super::room::Step`, 76 | but if in `constants`, then it can just be done with `objects::Step`. 77 | 78 | [screeps discord]: https://discord.gg/screeps 79 | [fmt-rfcs Rust Style Guide]: https://github.com/rust-lang-nursery/fmt-rfcs/blob/master/guide/guide.md 80 | [Rust API Guidelines]: https://rust-lang-nursery.github.io/api-guidelines/ 81 | [RFC 2128]: https://github.com/rust-lang/rfcs/blob/master/text/2128-use-nested-groups.md 82 | [items]: https://doc.rust-lang.org/reference/items.html 83 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "screeps-game-api" 3 | version = "0.23.0" 4 | authors = ["David Ross "] 5 | documentation = "https://docs.rs/screeps-game-api/" 6 | edition = "2021" 7 | include = [ 8 | "Cargo.toml", 9 | "Web.toml", 10 | "src/**/*", 11 | "tests/**/*", 12 | "examples/**/*", 13 | "README.md", 14 | "CHANGELOG.md", 15 | "LICENSE", 16 | ] 17 | license = "MIT" 18 | readme = "README.md" 19 | repository = "https://github.com/rustyscreeps/screeps-game-api/" 20 | description = "WASM bindings to the in-game Screeps API" 21 | 22 | [lib] 23 | name = "screeps" 24 | 25 | [package.metadata.docs.rs] 26 | all-features = true 27 | # this workaround (and the cfg_attr wrapping around the feature(doc_auto_cfg) call) 28 | # can go once the doc_auto_cfg feature is stablized 29 | rustdoc-args = ["--cfg", "docsrs"] 30 | 31 | [dependencies] 32 | arrayvec = "0.7" 33 | enum_dispatch = "0.3" 34 | enum-iterator = "2.0" 35 | js-sys = "0.3" 36 | num-derive = "0.4" 37 | num-traits = "0.2" 38 | serde = { version = "1", features = ["derive"] } 39 | serde_json = "1" 40 | serde_repr = "0.1" 41 | serde-wasm-bindgen = "0.6" 42 | wasm-bindgen = ">=0.2.93" 43 | 44 | [dev-dependencies] 45 | bincode = "1.3" 46 | wasm-bindgen-test = "0.3" 47 | 48 | [features] 49 | ## Specific features to enable conditional API endpoints 50 | 51 | # Official MMO server features, not present on other environments 52 | mmo = [] 53 | 54 | # Seasonal server, season 1 - enable score container, collector, and resource 55 | seasonal-season-1 = [] 56 | 57 | # Seasonal server, season 2 - enable symbol container, decoder, and resources 58 | seasonal-season-2 = [] 59 | 60 | # Seasonal server, season 5 - enable thorium resource and reactor structure 61 | seasonal-season-5 = [] 62 | 63 | # enable compatibility with the sim environment for positions 64 | sim = [] 65 | 66 | # Enable unsafe conversions of return codes with undefined behavior when values 67 | # aren't in the expected range 68 | unsafe-return-conversion = [] 69 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 David Ross 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | screeps-game-api 2 | ================ 3 | 4 | [![Build Status][actions-badge]][actions-builds] 5 | [![crates.io version badge][cratesio-badge]][crate] 6 | [![dependency status][deps-badge]][deps] 7 | [![docs.rs version badge][docsrs-badge]][docs] 8 | 9 | ![Rusty Screeps Logo][logo] 10 | 11 | Typed bindings to the Screeps in-game API for WASM Rust AIs. 12 | 13 | Also the homepage for tools relating to writing [Screeps] AIs in Rust. 14 | 15 | `screeps-game-api` is a Rust binding to the JavaScript APIs for programs compiled to WASM using 16 | [`wasm-pack`]. 17 | 18 | Please see the [screeps-starter-rust example project] for an example with instructructions for 19 | getting started, or the [docs] for a detailed API reference. 20 | 21 | Writing Screeps code in Rust can be nice, but it can also be annoying. If you have tips, tricks, or 22 | other things you'd like to share, make an issue! We need to write more documentation, and if we have 23 | enough ideas, we can start an mdbook for this repository. 24 | 25 | If you need help or want to share feedback, feel free to open an 26 | [issue](https://github.com/rustyscreeps/screeps-game-api/issues) 27 | or come say "_Hi!_" on [the official Screeps Discord](https://discord.gg/screeps) in the `#rust` 28 | channel! 29 | 30 | [screeps]: https://screeps.com/ 31 | [`wasm-pack`]: https://rustwasm.github.io/wasm-pack/ 32 | [screeps-starter-rust example project]: https://github.com/rustyscreeps/screeps-starter-rust/ 33 | [actions-badge]: https://github.com/rustyscreeps/screeps-game-api/actions/workflows/check.yml/badge.svg 34 | [actions-builds]: https://github.com/rustyscreeps/screeps-game-api/actions/workflows/check.yml 35 | [cratesio-badge]: https://img.shields.io/crates/v/screeps-game-api.svg 36 | [crate]: https://crates.io/crates/screeps-game-api/ 37 | [deps-badge]: https://deps.rs/repo/github/rustyscreeps/screeps-game-api/status.svg 38 | [deps]: https://deps.rs/repo/github/rustyscreeps/screeps-game-api 39 | [docsrs-badge]: https://docs.rs/screeps-game-api/badge.svg 40 | [docs]: https://docs.rs/screeps-game-api/ 41 | [logo]: ./logo.png 42 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rustyscreeps/screeps-game-api/baf7fca00391f42817db7bfe0ebced5402531bb3/logo.png -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | edition = "2021" 2 | version = "One" 3 | 4 | # General 5 | max_width = 100 6 | hard_tabs = false 7 | tab_spaces = 4 8 | 9 | # Comments 10 | comment_width = 80 11 | wrap_comments = true 12 | format_code_in_doc_comments = true 13 | 14 | # Imports 15 | imports_granularity = "Crate" 16 | reorder_imports = true 17 | 18 | # `mod` declarations 19 | reorder_modules = true 20 | 21 | # Items 22 | reorder_impl_items = false 23 | 24 | # fns 25 | fn_params_layout = "Tall" 26 | 27 | # Report bugs (bugs may cause other formatting issues) 28 | error_on_line_overflow = false 29 | error_on_unformatted = false 30 | 31 | # Use `MyStruct { x }` instead of `MyStruct { x: x }` 32 | use_field_init_shorthand = false 33 | -------------------------------------------------------------------------------- /src/console.rs: -------------------------------------------------------------------------------- 1 | //! Utility functions for visuals that the game API exposes on the `console` 2 | //! object. 3 | use js_sys::JsString; 4 | use wasm_bindgen::prelude::*; 5 | 6 | #[wasm_bindgen] 7 | extern "C" { 8 | /// Add a visual, in json format, or multiple visuals separated by `\n`. 9 | /// Each line must be: 10 | /// - A serialized [`Visual`], applying to a given room, if the target is 11 | /// the name of a room 12 | /// - A serialized [`Visual`], which will be shown in all rooms, if target 13 | /// is `None` 14 | /// - A serialized [`MapVisualShape`], if the target is "map" 15 | /// 16 | /// [`Visual`]: crate::objects::Visual 17 | /// [`MapVisualShape`]: crate::objects::MapVisualShape 18 | #[wasm_bindgen(js_namespace = console, js_name = addVisual)] 19 | pub fn add_visual(target: Option<&JsString>, visual: &JsValue); 20 | 21 | /// Get the visuals applied to a given target so far in the current tick 22 | /// separated by `\n`, with the taget being visuals applied to a given room, 23 | /// `None` for visuals applied for all rooms, or "map" for map visuals. 24 | #[wasm_bindgen(js_namespace = console, js_name = getVisual)] 25 | pub fn get_visual(target: Option<&JsString>) -> Option; 26 | 27 | /// Get the size of the visuals applied for the current tick, either for a 28 | /// given room, `None` for visuals applied for all rooms, or "map" for 29 | /// map visuals. 30 | #[wasm_bindgen(js_namespace = console, js_name = getVisualSize)] 31 | pub fn get_visual_size(target: Option<&JsString>) -> u32; 32 | 33 | /// Clear all of the set visuals for the current tick, either for a given 34 | /// room, `None` for visuals applied for all rooms, or "map" for map 35 | /// visuals. 36 | #[wasm_bindgen(js_namespace = console, js_name = clearVisual)] 37 | pub fn clear_visual(target: Option<&JsString>); 38 | } 39 | -------------------------------------------------------------------------------- /src/enums/action_error_codes/constructionsite_error_codes.rs: -------------------------------------------------------------------------------- 1 | use std::{error::Error, fmt}; 2 | 3 | use num_derive::FromPrimitive; 4 | use serde_repr::{Deserialize_repr, Serialize_repr}; 5 | 6 | use crate::{constants::ErrorCode, FromReturnCode}; 7 | 8 | /// Error codes used by 9 | /// [ConstructionSite::remove](crate::ConstructionSite::remove). 10 | /// 11 | /// [Screeps API Docs](https://docs.screeps.com/api/#ConstructionSite.remove). 12 | /// 13 | /// [Screeps Engine Source Code](https://github.com/screeps/engine/blob/97c9d12385fed686655c13b09f5f2457dd83a2bf/src/game/construction-sites.js#L50) 14 | #[derive( 15 | Debug, PartialEq, Eq, Clone, Copy, Hash, FromPrimitive, Deserialize_repr, Serialize_repr, 16 | )] 17 | #[repr(i8)] 18 | pub enum ConstructionSiteRemoveErrorCode { 19 | NotOwner = -1, 20 | } 21 | 22 | impl FromReturnCode for ConstructionSiteRemoveErrorCode { 23 | type Error = Self; 24 | 25 | fn result_from_i8(val: i8) -> Result<(), Self::Error> { 26 | let maybe_result = Self::try_result_from_i8(val); 27 | #[cfg(feature = "unsafe-return-conversion")] 28 | unsafe { 29 | maybe_result.unwrap_unchecked() 30 | } 31 | #[cfg(not(feature = "unsafe-return-conversion"))] 32 | maybe_result.unwrap() 33 | } 34 | 35 | fn try_result_from_i8(val: i8) -> Option> { 36 | match val { 37 | 0 => Some(Ok(())), 38 | -1 => Some(Err(ConstructionSiteRemoveErrorCode::NotOwner)), 39 | _ => None, 40 | } 41 | } 42 | } 43 | 44 | impl fmt::Display for ConstructionSiteRemoveErrorCode { 45 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 46 | let msg: &'static str = match self { 47 | ConstructionSiteRemoveErrorCode::NotOwner => { 48 | "you are not the owner of this construction site, and it's not in your room" 49 | } 50 | }; 51 | 52 | write!(f, "{}", msg) 53 | } 54 | } 55 | 56 | impl Error for ConstructionSiteRemoveErrorCode {} 57 | 58 | impl From for ErrorCode { 59 | fn from(value: ConstructionSiteRemoveErrorCode) -> Self { 60 | // Safety: ConstructionSiteRemoveErrorCode is repr(i8), so we can cast it to get 61 | // the discriminant value, which will match the raw return code value that 62 | // ErrorCode expects. Ref: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.discriminant.coercion.intro 63 | // Safety: ConstructionSiteRemoveErrorCode discriminants are always error code 64 | // values, and thus the Result returned here will always be an `Err` variant, so 65 | // we can always extract the error without panicking 66 | Self::result_from_i8(value as i8).unwrap_err() 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/enums/action_error_codes/game_map_error_codes.rs: -------------------------------------------------------------------------------- 1 | use std::{error::Error, fmt}; 2 | 3 | use num_derive::FromPrimitive; 4 | use serde_repr::{Deserialize_repr, Serialize_repr}; 5 | 6 | use crate::{constants::ErrorCode, FromReturnCode}; 7 | 8 | /// Error codes used by [game::map::find_exit](crate::game::map::find_exit). 9 | /// 10 | /// [Screeps API Docs](https://docs.screeps.com/api/#Game.map.findExit). 11 | /// 12 | /// [Screeps Engine Source Code](https://github.com/screeps/engine/blob/97c9d12385fed686655c13b09f5f2457dd83a2bf/src/game/map.js#L188) 13 | #[derive( 14 | Debug, PartialEq, Eq, Clone, Copy, Hash, FromPrimitive, Deserialize_repr, Serialize_repr, 15 | )] 16 | #[repr(i8)] 17 | pub enum FindExitErrorCode { 18 | NoPath = -2, 19 | InvalidArgs = -10, 20 | } 21 | 22 | impl FromReturnCode for FindExitErrorCode { 23 | type Error = Self; 24 | 25 | fn result_from_i8(val: i8) -> Result<(), Self::Error> { 26 | let maybe_result = Self::try_result_from_i8(val); 27 | #[cfg(feature = "unsafe-return-conversion")] 28 | unsafe { 29 | maybe_result.unwrap_unchecked() 30 | } 31 | #[cfg(not(feature = "unsafe-return-conversion"))] 32 | maybe_result.unwrap() 33 | } 34 | 35 | fn try_result_from_i8(val: i8) -> Option> { 36 | match val { 37 | -2 => Some(Err(FindExitErrorCode::NoPath)), 38 | -10 => Some(Err(FindExitErrorCode::InvalidArgs)), 39 | _ => None, 40 | } 41 | } 42 | } 43 | 44 | impl fmt::Display for FindExitErrorCode { 45 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 46 | let msg: &'static str = match self { 47 | FindExitErrorCode::NoPath => "path can not be found", 48 | FindExitErrorCode::InvalidArgs => "the location is incorrect", 49 | }; 50 | 51 | write!(f, "{}", msg) 52 | } 53 | } 54 | 55 | impl Error for FindExitErrorCode {} 56 | 57 | impl From for ErrorCode { 58 | fn from(value: FindExitErrorCode) -> Self { 59 | // Safety: FindExitErrorCode is repr(i8), so we can cast it to get the 60 | // discriminant value, which will match the raw return code value that ErrorCode 61 | // expects. Ref: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.discriminant.coercion.intro 62 | // Safety: FindExitErrorCode discriminants are always error code values, and 63 | // thus the Result returned here will always be an `Err` variant, so we can 64 | // always extract the error without panicking 65 | Self::result_from_i8(value as i8).unwrap_err() 66 | } 67 | } 68 | 69 | /// Error codes used by [game::map::find_route](crate::game::map::find_route). 70 | /// 71 | /// [Screeps API Docs](https://docs.screeps.com/api/#Game.map.findRoute). 72 | /// 73 | /// [Screeps Engine Source Code](https://github.com/screeps/engine/blob/97c9d12385fed686655c13b09f5f2457dd83a2bf/src/game/map.js#L69) 74 | #[derive( 75 | Debug, PartialEq, Eq, Clone, Copy, Hash, FromPrimitive, Deserialize_repr, Serialize_repr, 76 | )] 77 | #[repr(i8)] 78 | pub enum FindRouteErrorCode { 79 | NoPath = -2, 80 | } 81 | 82 | impl FromReturnCode for FindRouteErrorCode { 83 | type Error = Self; 84 | 85 | fn result_from_i8(val: i8) -> Result<(), Self::Error> { 86 | let maybe_result = Self::try_result_from_i8(val); 87 | #[cfg(feature = "unsafe-return-conversion")] 88 | unsafe { 89 | maybe_result.unwrap_unchecked() 90 | } 91 | #[cfg(not(feature = "unsafe-return-conversion"))] 92 | maybe_result.unwrap() 93 | } 94 | 95 | fn try_result_from_i8(val: i8) -> Option> { 96 | match val { 97 | -2 => Some(Err(FindRouteErrorCode::NoPath)), 98 | _ => None, 99 | } 100 | } 101 | } 102 | 103 | impl fmt::Display for FindRouteErrorCode { 104 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 105 | let msg: &'static str = match self { 106 | FindRouteErrorCode::NoPath => "path can not be found", 107 | }; 108 | 109 | write!(f, "{}", msg) 110 | } 111 | } 112 | 113 | impl Error for FindRouteErrorCode {} 114 | 115 | impl From for ErrorCode { 116 | fn from(value: FindRouteErrorCode) -> Self { 117 | // Safety: FindRouteErrorCode is repr(i8), so we can cast it to get the 118 | // discriminant value, which will match the raw return code value that ErrorCode 119 | // expects. Ref: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.discriminant.coercion.intro 120 | // Safety: FindRouteErrorCode discriminants are always error code values, and 121 | // thus the Result returned here will always be an `Err` variant, so we can 122 | // always extract the error without panicking 123 | Self::result_from_i8(value as i8).unwrap_err() 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/enums/action_error_codes/mod.rs: -------------------------------------------------------------------------------- 1 | //! This module contains error code enums for individual API actions. 2 | 3 | mod constructionsite_error_codes; 4 | mod creep_error_codes; 5 | mod flag_error_codes; 6 | #[cfg(feature = "mmo")] 7 | mod game_cpu_error_codes; 8 | mod game_map_error_codes; 9 | mod game_market_error_codes; 10 | mod powercreep_error_codes; 11 | mod room_error_codes; 12 | mod roomposition_error_codes; 13 | mod sharedcreep_error_codes; 14 | mod spawning_error_codes; 15 | mod structure_error_codes; 16 | mod structurecontroller_error_codes; 17 | mod structurefactory_error_codes; 18 | mod structurelab_error_codes; 19 | mod structurelink_error_codes; 20 | mod structurenuker_error_codes; 21 | mod structureobserver_error_codes; 22 | mod structurepowerspawn_error_codes; 23 | mod structurerampart_error_codes; 24 | mod structurespawn_error_codes; 25 | mod structureterminal_error_codes; 26 | mod structuretower_error_codes; 27 | 28 | pub mod construction_site { 29 | pub use super::constructionsite_error_codes::ConstructionSiteRemoveErrorCode; 30 | } 31 | 32 | pub mod creep { 33 | pub use super::creep_error_codes::{ 34 | AttackControllerErrorCode, BuildErrorCode, ClaimControllerErrorCode, CreepAttackErrorCode, 35 | CreepCancelOrderErrorCode, CreepHealErrorCode, CreepMoveByPathErrorCode, 36 | CreepMoveDirectionErrorCode, CreepMovePulledByErrorCode, CreepMoveToErrorCode, 37 | CreepRepairErrorCode, DismantleErrorCode, GenerateSafeModeErrorCode, HarvestErrorCode, 38 | PullErrorCode, RangedAttackErrorCode, RangedHealErrorCode, RangedMassAttackErrorCode, 39 | ReserveControllerErrorCode, SignControllerErrorCode, UpgradeControllerErrorCode, 40 | }; 41 | 42 | #[cfg(feature = "seasonal-season-5")] 43 | pub use super::creep_error_codes::CreepClaimReactorErrorCode; 44 | } 45 | 46 | pub mod flag { 47 | pub use super::flag_error_codes::{ 48 | FlagRemoveErrorCode, SetColorErrorCode, SetPositionErrorCode, 49 | }; 50 | } 51 | 52 | pub mod game { 53 | use super::{game_map_error_codes, game_market_error_codes}; 54 | 55 | #[cfg(feature = "mmo")] 56 | use super::game_cpu_error_codes; 57 | 58 | #[cfg(feature = "mmo")] 59 | pub mod cpu { 60 | pub use super::game_cpu_error_codes::{ 61 | GeneratePixelErrorCode, SetShardLimitsErrorCode, UnlockErrorCode, 62 | }; 63 | } 64 | 65 | pub mod map { 66 | pub use super::game_map_error_codes::{FindExitErrorCode, FindRouteErrorCode}; 67 | } 68 | 69 | pub mod market { 70 | pub use super::game_market_error_codes::{ 71 | ChangeOrderPriceErrorCode, CreateOrderErrorCode, DealErrorCode, ExtendOrderErrorCode, 72 | MarketCancelOrderErrorCode, 73 | }; 74 | } 75 | } 76 | 77 | pub mod powercreep { 78 | pub use super::powercreep_error_codes::{ 79 | DeleteErrorCode, EnableRoomErrorCode, PowerCreepCancelOrderErrorCode, 80 | PowerCreepCreateErrorCode, PowerCreepMoveByPathErrorCode, PowerCreepMoveDirectionErrorCode, 81 | PowerCreepMoveToErrorCode, RenameErrorCode, RenewErrorCode, SpawnErrorCode, 82 | UpgradeErrorCode, UsePowerErrorCode, 83 | }; 84 | } 85 | 86 | pub mod room { 87 | pub use super::room_error_codes::{ 88 | FindExitToErrorCode, RoomCreateConstructionSiteErrorCode, RoomCreateFlagErrorCode, 89 | }; 90 | } 91 | 92 | pub mod room_position { 93 | pub use super::roomposition_error_codes::{ 94 | RoomPositionCreateConstructionSiteErrorCode, RoomPositionCreateFlagErrorCode, 95 | }; 96 | } 97 | 98 | pub mod shared { 99 | pub use super::sharedcreep_error_codes::{ 100 | DropErrorCode, NotifyWhenAttackedErrorCode, PickupErrorCode, SayErrorCode, 101 | SuicideErrorCode, TransferErrorCode, WithdrawErrorCode, 102 | }; 103 | } 104 | 105 | pub mod spawning { 106 | pub use super::spawning_error_codes::{CancelErrorCode, SetDirectionsErrorCode}; 107 | } 108 | 109 | pub mod structure { 110 | pub use super::structure_error_codes::{ 111 | DestroyErrorCode, StructureNotifyWhenAttackedErrorCode, 112 | }; 113 | } 114 | 115 | pub mod structure_controller { 116 | pub use super::structurecontroller_error_codes::{ActivateSafeModeErrorCode, UnclaimErrorCode}; 117 | } 118 | 119 | pub mod structure_factory { 120 | pub use super::structurefactory_error_codes::ProduceErrorCode; 121 | } 122 | 123 | pub mod structure_lab { 124 | pub use super::structurelab_error_codes::{ 125 | BoostCreepErrorCode, ReverseReactionErrorCode, RunReactionErrorCode, UnboostCreepErrorCode, 126 | }; 127 | } 128 | 129 | pub mod structure_link { 130 | pub use super::structurelink_error_codes::TransferEnergyErrorCode; 131 | } 132 | 133 | pub mod structure_nuker { 134 | pub use super::structurenuker_error_codes::LaunchNukeErrorCode; 135 | } 136 | 137 | pub mod structure_observer { 138 | pub use super::structureobserver_error_codes::ObserveRoomErrorCode; 139 | } 140 | 141 | pub mod structure_powerspawn { 142 | pub use super::structurepowerspawn_error_codes::ProcessPowerErrorCode; 143 | } 144 | 145 | pub mod structure_rampart { 146 | pub use super::structurerampart_error_codes::SetPublicErrorCode; 147 | } 148 | 149 | pub mod structure_spawn { 150 | pub use super::structurespawn_error_codes::{ 151 | RecycleCreepErrorCode, RenewCreepErrorCode, SpawnCreepErrorCode, 152 | }; 153 | } 154 | 155 | pub mod structure_terminal { 156 | pub use super::structureterminal_error_codes::SendErrorCode; 157 | } 158 | 159 | pub mod structure_tower { 160 | pub use super::structuretower_error_codes::{ 161 | TowerAttackErrorCode, TowerHealErrorCode, TowerRepairErrorCode, 162 | }; 163 | } 164 | 165 | pub use self::{ 166 | construction_site::*, creep::*, flag::*, game::*, powercreep::*, room::*, room_position::*, 167 | shared::*, spawning::*, structure::*, structure_controller::*, structure_factory::*, 168 | structure_lab::*, structure_link::*, structure_nuker::*, structure_observer::*, 169 | structure_powerspawn::*, structure_rampart::*, structure_spawn::*, structure_terminal::*, 170 | structure_tower::*, 171 | }; 172 | -------------------------------------------------------------------------------- /src/enums/action_error_codes/spawning_error_codes.rs: -------------------------------------------------------------------------------- 1 | use std::{error::Error, fmt}; 2 | 3 | use num_derive::FromPrimitive; 4 | use serde_repr::{Deserialize_repr, Serialize_repr}; 5 | 6 | use crate::{constants::ErrorCode, FromReturnCode}; 7 | 8 | /// Error codes used by [Spawning::cancel](crate::Spawning::cancel). 9 | /// 10 | /// [Screeps API Docs](https://docs.screeps.com/api/#StructureSpawn.Spawning.cancel). 11 | /// 12 | /// [Screeps Engine Source Code](https://github.com/screeps/engine/blob/97c9d12385fed686655c13b09f5f2457dd83a2bf/src/game/structures.js#L1328) 13 | #[derive( 14 | Debug, PartialEq, Eq, Clone, Copy, Hash, FromPrimitive, Deserialize_repr, Serialize_repr, 15 | )] 16 | #[repr(i8)] 17 | pub enum CancelErrorCode { 18 | NotOwner = -1, 19 | } 20 | 21 | impl FromReturnCode for CancelErrorCode { 22 | type Error = Self; 23 | 24 | fn result_from_i8(val: i8) -> Result<(), Self::Error> { 25 | let maybe_result = Self::try_result_from_i8(val); 26 | #[cfg(feature = "unsafe-return-conversion")] 27 | unsafe { 28 | maybe_result.unwrap_unchecked() 29 | } 30 | #[cfg(not(feature = "unsafe-return-conversion"))] 31 | maybe_result.unwrap() 32 | } 33 | 34 | fn try_result_from_i8(val: i8) -> Option> { 35 | match val { 36 | 0 => Some(Ok(())), 37 | -1 => Some(Err(CancelErrorCode::NotOwner)), 38 | _ => None, 39 | } 40 | } 41 | } 42 | 43 | impl fmt::Display for CancelErrorCode { 44 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 45 | let msg: &'static str = match self { 46 | CancelErrorCode::NotOwner => "you are not the owner of this spawn", 47 | }; 48 | 49 | write!(f, "{}", msg) 50 | } 51 | } 52 | 53 | impl Error for CancelErrorCode {} 54 | 55 | impl From for ErrorCode { 56 | fn from(value: CancelErrorCode) -> Self { 57 | // Safety: CancelErrorCode is repr(i8), so we can cast it to get the 58 | // discriminant value, which will match the raw return code value that ErrorCode 59 | // expects. Ref: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.discriminant.coercion.intro 60 | // Safety: CancelErrorCode discriminants are always error code values, and thus 61 | // the Result returned here will always be an `Err` variant, so we can always 62 | // extract the error without panicking 63 | Self::result_from_i8(value as i8).unwrap_err() 64 | } 65 | } 66 | 67 | /// Error codes used by 68 | /// [Spawning::set_directions](crate::Spawning::set_directions). 69 | /// 70 | /// [Screeps API Docs](https://docs.screeps.com/api/#StructureSpawn.Spawning.setDirections). 71 | /// 72 | /// [Screeps Engine Source Code](https://github.com/screeps/engine/blob/97c9d12385fed686655c13b09f5f2457dd83a2bf/src/game/structures.js#L1312) 73 | #[derive( 74 | Debug, PartialEq, Eq, Clone, Copy, Hash, FromPrimitive, Deserialize_repr, Serialize_repr, 75 | )] 76 | #[repr(i8)] 77 | pub enum SetDirectionsErrorCode { 78 | NotOwner = -1, 79 | InvalidArgs = -10, 80 | } 81 | 82 | impl FromReturnCode for SetDirectionsErrorCode { 83 | type Error = Self; 84 | 85 | fn result_from_i8(val: i8) -> Result<(), Self::Error> { 86 | let maybe_result = Self::try_result_from_i8(val); 87 | #[cfg(feature = "unsafe-return-conversion")] 88 | unsafe { 89 | maybe_result.unwrap_unchecked() 90 | } 91 | #[cfg(not(feature = "unsafe-return-conversion"))] 92 | maybe_result.unwrap() 93 | } 94 | 95 | fn try_result_from_i8(val: i8) -> Option> { 96 | match val { 97 | 0 => Some(Ok(())), 98 | -1 => Some(Err(SetDirectionsErrorCode::NotOwner)), 99 | -10 => Some(Err(SetDirectionsErrorCode::InvalidArgs)), 100 | _ => None, 101 | } 102 | } 103 | } 104 | 105 | impl fmt::Display for SetDirectionsErrorCode { 106 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 107 | let msg: &'static str = match self { 108 | SetDirectionsErrorCode::NotOwner => "you are not the owner of this spawn", 109 | SetDirectionsErrorCode::InvalidArgs => "the directions is array is invalid", 110 | }; 111 | 112 | write!(f, "{}", msg) 113 | } 114 | } 115 | 116 | impl Error for SetDirectionsErrorCode {} 117 | 118 | impl From for ErrorCode { 119 | fn from(value: SetDirectionsErrorCode) -> Self { 120 | // Safety: SetDirectionsErrorCode is repr(i8), so we can cast it to get the 121 | // discriminant value, which will match the raw return code value that ErrorCode 122 | // expects. Ref: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.discriminant.coercion.intro 123 | // Safety: SetDirectionsErrorCode discriminants are always error code values, 124 | // and thus the Result returned here will always be an `Err` variant, so we can 125 | // always extract the error without panicking 126 | Self::result_from_i8(value as i8).unwrap_err() 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/enums/action_error_codes/structure_error_codes.rs: -------------------------------------------------------------------------------- 1 | use std::{error::Error, fmt}; 2 | 3 | use num_derive::FromPrimitive; 4 | use serde_repr::{Deserialize_repr, Serialize_repr}; 5 | 6 | use crate::{constants::ErrorCode, FromReturnCode}; 7 | 8 | /// Error codes used by [Structure::destroy](crate::Structure::destroy). 9 | /// 10 | /// [Screeps API Docs](https://docs.screeps.com/api/#Structure.destroy). 11 | /// 12 | /// [Screeps Engine Source Code](https://github.com/screeps/engine/blob/97c9d12385fed686655c13b09f5f2457dd83a2bf/src/game/structures.js#L72) 13 | #[derive( 14 | Debug, PartialEq, Eq, Clone, Copy, Hash, FromPrimitive, Deserialize_repr, Serialize_repr, 15 | )] 16 | #[repr(i8)] 17 | pub enum DestroyErrorCode { 18 | NotOwner = -1, 19 | Busy = -4, 20 | InvalidTarget = -7, 21 | } 22 | 23 | impl FromReturnCode for DestroyErrorCode { 24 | type Error = Self; 25 | 26 | fn result_from_i8(val: i8) -> Result<(), Self::Error> { 27 | let maybe_result = Self::try_result_from_i8(val); 28 | #[cfg(feature = "unsafe-return-conversion")] 29 | unsafe { 30 | maybe_result.unwrap_unchecked() 31 | } 32 | #[cfg(not(feature = "unsafe-return-conversion"))] 33 | maybe_result.unwrap() 34 | } 35 | 36 | fn try_result_from_i8(val: i8) -> Option> { 37 | match val { 38 | 0 => Some(Ok(())), 39 | -1 => Some(Err(DestroyErrorCode::NotOwner)), 40 | -4 => Some(Err(DestroyErrorCode::Busy)), 41 | -7 => Some(Err(DestroyErrorCode::InvalidTarget)), 42 | _ => None, 43 | } 44 | } 45 | } 46 | 47 | impl fmt::Display for DestroyErrorCode { 48 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 49 | let msg: &'static str = match self { 50 | DestroyErrorCode::NotOwner => { 51 | "you are not the owner of this structure, and it's not in your room" 52 | } 53 | DestroyErrorCode::Busy => "hostile creeps are in the room", 54 | DestroyErrorCode::InvalidTarget => "room property invalid", 55 | }; 56 | 57 | write!(f, "{}", msg) 58 | } 59 | } 60 | 61 | impl Error for DestroyErrorCode {} 62 | 63 | impl From for ErrorCode { 64 | fn from(value: DestroyErrorCode) -> Self { 65 | // Safety: DestroyErrorCode is repr(i8), so we can cast it to get the 66 | // discriminant value, which will match the raw return code value that ErrorCode 67 | // expects. Ref: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.discriminant.coercion.intro 68 | // Safety: DestroyErrorCode discriminants are always error code values, and thus 69 | // the Result returned here will always be an `Err` variant, so we can always 70 | // extract the error without panicking 71 | Self::result_from_i8(value as i8).unwrap_err() 72 | } 73 | } 74 | 75 | /// Error codes used by 76 | /// [Structure::notify_when_attacked](crate::Structure::notify_when_attacked). 77 | /// 78 | /// [Screeps API Docs](https://docs.screeps.com/api/#Structure.notifyWhenAttacked). 79 | /// 80 | /// [Screeps Engine Source Code](https://github.com/screeps/engine/blob/97c9d12385fed686655c13b09f5f2457dd83a2bf/src/game/structures.js#L89) 81 | #[derive( 82 | Debug, PartialEq, Eq, Clone, Copy, Hash, FromPrimitive, Deserialize_repr, Serialize_repr, 83 | )] 84 | #[repr(i8)] 85 | pub enum StructureNotifyWhenAttackedErrorCode { 86 | NotOwner = -1, 87 | InvalidTarget = -7, 88 | InvalidArgs = -10, 89 | } 90 | 91 | impl FromReturnCode for StructureNotifyWhenAttackedErrorCode { 92 | type Error = Self; 93 | 94 | fn result_from_i8(val: i8) -> Result<(), Self::Error> { 95 | let maybe_result = Self::try_result_from_i8(val); 96 | #[cfg(feature = "unsafe-return-conversion")] 97 | unsafe { 98 | maybe_result.unwrap_unchecked() 99 | } 100 | #[cfg(not(feature = "unsafe-return-conversion"))] 101 | maybe_result.unwrap() 102 | } 103 | 104 | fn try_result_from_i8(val: i8) -> Option> { 105 | match val { 106 | 0 => Some(Ok(())), 107 | -1 => Some(Err(StructureNotifyWhenAttackedErrorCode::NotOwner)), 108 | -7 => Some(Err(StructureNotifyWhenAttackedErrorCode::InvalidTarget)), 109 | -10 => Some(Err(StructureNotifyWhenAttackedErrorCode::InvalidArgs)), 110 | _ => None, 111 | } 112 | } 113 | } 114 | 115 | impl fmt::Display for StructureNotifyWhenAttackedErrorCode { 116 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 117 | let msg: &'static str = match self { 118 | StructureNotifyWhenAttackedErrorCode::NotOwner => { 119 | "you are not the owner of this structure" 120 | } 121 | StructureNotifyWhenAttackedErrorCode::InvalidTarget => "room property invalid", 122 | StructureNotifyWhenAttackedErrorCode::InvalidArgs => { 123 | "enable argument is not a boolean value" 124 | } 125 | }; 126 | 127 | write!(f, "{}", msg) 128 | } 129 | } 130 | 131 | impl Error for StructureNotifyWhenAttackedErrorCode {} 132 | 133 | impl From for ErrorCode { 134 | fn from(value: StructureNotifyWhenAttackedErrorCode) -> Self { 135 | // Safety: StructureNotifyWhenAttackedErrorCode is repr(i8), so we can cast it 136 | // to get the discriminant value, which will match the raw return code value 137 | // that ErrorCode expects. Ref: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.discriminant.coercion.intro 138 | // Safety: StructureNotifyWhenAttackedErrorCode discriminants are always error 139 | // code values, and thus the Result returned here will always be an `Err` 140 | // variant, so we can always extract the error without panicking 141 | Self::result_from_i8(value as i8).unwrap_err() 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/enums/action_error_codes/structurecontroller_error_codes.rs: -------------------------------------------------------------------------------- 1 | use std::{error::Error, fmt}; 2 | 3 | use num_derive::FromPrimitive; 4 | use serde_repr::{Deserialize_repr, Serialize_repr}; 5 | 6 | use crate::{constants::ErrorCode, FromReturnCode}; 7 | 8 | /// Error codes used by 9 | /// [StructureController::activate_safe_mode](crate::StructureController::activate_safe_mode). 10 | /// 11 | /// 12 | /// [Screeps API Docs](https://docs.screeps.com/api/#StructureController.activateSafeMode). 13 | /// 14 | /// [Screeps Engine Source Code](https://github.com/screeps/engine/blob/97c9d12385fed686655c13b09f5f2457dd83a2bf/src/game/structures.js#L211) 15 | #[derive( 16 | Debug, PartialEq, Eq, Clone, Copy, Hash, FromPrimitive, Deserialize_repr, Serialize_repr, 17 | )] 18 | #[repr(i8)] 19 | pub enum ActivateSafeModeErrorCode { 20 | NotOwner = -1, 21 | Busy = -4, 22 | NotEnoughResources = -6, 23 | Tired = -11, 24 | } 25 | 26 | impl FromReturnCode for ActivateSafeModeErrorCode { 27 | type Error = Self; 28 | 29 | fn result_from_i8(val: i8) -> Result<(), Self::Error> { 30 | let maybe_result = Self::try_result_from_i8(val); 31 | #[cfg(feature = "unsafe-return-conversion")] 32 | unsafe { 33 | maybe_result.unwrap_unchecked() 34 | } 35 | #[cfg(not(feature = "unsafe-return-conversion"))] 36 | maybe_result.unwrap() 37 | } 38 | 39 | fn try_result_from_i8(val: i8) -> Option> { 40 | match val { 41 | 0 => Some(Ok(())), 42 | -1 => Some(Err(ActivateSafeModeErrorCode::NotOwner)), 43 | -4 => Some(Err(ActivateSafeModeErrorCode::Busy)), 44 | -6 => Some(Err(ActivateSafeModeErrorCode::NotEnoughResources)), 45 | -11 => Some(Err(ActivateSafeModeErrorCode::Tired)), 46 | _ => None, 47 | } 48 | } 49 | } 50 | 51 | impl fmt::Display for ActivateSafeModeErrorCode { 52 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 53 | let msg: &'static str = match self { 54 | ActivateSafeModeErrorCode::NotOwner => "you are not the owner of this controller", 55 | ActivateSafeModeErrorCode::Busy => "there is another room in safe mode already", 56 | ActivateSafeModeErrorCode::NotEnoughResources => "there is no safe mode activations available", 57 | ActivateSafeModeErrorCode::Tired => "the previous safe mode is still cooling down, or the controller is upgradeblocked, or the controller is downgraded for 50% plus 5000 ticks or more", 58 | }; 59 | 60 | write!(f, "{}", msg) 61 | } 62 | } 63 | 64 | impl Error for ActivateSafeModeErrorCode {} 65 | 66 | impl From for ErrorCode { 67 | fn from(value: ActivateSafeModeErrorCode) -> Self { 68 | // Safety: ActivateSafeModeErrorCode is repr(i8), so we can cast it to get the 69 | // discriminant value, which will match the raw return code value that ErrorCode 70 | // expects. Ref: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.discriminant.coercion.intro 71 | // Safety: ActivateSafeModeErrorCode discriminants are always error code values, 72 | // and thus the Result returned here will always be an `Err` variant, so we can 73 | // always extract the error without panicking 74 | Self::result_from_i8(value as i8).unwrap_err() 75 | } 76 | } 77 | 78 | /// Error codes used by 79 | /// [StructureController::unclaim](crate::StructureController::unclaim). 80 | /// 81 | /// [Screeps API Docs](https://docs.screeps.com/api/#StructureController.unclaim). 82 | /// 83 | /// [Screeps Engine Source Code](https://github.com/screeps/engine/blob/97c9d12385fed686655c13b09f5f2457dd83a2bf/src/game/structures.js#L201) 84 | #[derive( 85 | Debug, PartialEq, Eq, Clone, Copy, Hash, FromPrimitive, Deserialize_repr, Serialize_repr, 86 | )] 87 | #[repr(i8)] 88 | pub enum UnclaimErrorCode { 89 | NotOwner = -1, 90 | } 91 | 92 | impl FromReturnCode for UnclaimErrorCode { 93 | type Error = Self; 94 | 95 | fn result_from_i8(val: i8) -> Result<(), Self::Error> { 96 | let maybe_result = Self::try_result_from_i8(val); 97 | #[cfg(feature = "unsafe-return-conversion")] 98 | unsafe { 99 | maybe_result.unwrap_unchecked() 100 | } 101 | #[cfg(not(feature = "unsafe-return-conversion"))] 102 | maybe_result.unwrap() 103 | } 104 | 105 | fn try_result_from_i8(val: i8) -> Option> { 106 | match val { 107 | 0 => Some(Ok(())), 108 | -1 => Some(Err(UnclaimErrorCode::NotOwner)), 109 | _ => None, 110 | } 111 | } 112 | } 113 | 114 | impl fmt::Display for UnclaimErrorCode { 115 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 116 | let msg: &'static str = match self { 117 | UnclaimErrorCode::NotOwner => "you are not the owner of this controller", 118 | }; 119 | 120 | write!(f, "{}", msg) 121 | } 122 | } 123 | 124 | impl Error for UnclaimErrorCode {} 125 | 126 | impl From for ErrorCode { 127 | fn from(value: UnclaimErrorCode) -> Self { 128 | // Safety: UnclaimErrorCode is repr(i8), so we can cast it to get the 129 | // discriminant value, which will match the raw return code value that ErrorCode 130 | // expects. Ref: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.discriminant.coercion.intro 131 | // Safety: UnclaimErrorCode discriminants are always error code values, and thus 132 | // the Result returned here will always be an `Err` variant, so we can always 133 | // extract the error without panicking 134 | Self::result_from_i8(value as i8).unwrap_err() 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/enums/action_error_codes/structurefactory_error_codes.rs: -------------------------------------------------------------------------------- 1 | use std::{error::Error, fmt}; 2 | 3 | use num_derive::FromPrimitive; 4 | use serde_repr::{Deserialize_repr, Serialize_repr}; 5 | 6 | use crate::{constants::ErrorCode, FromReturnCode}; 7 | 8 | /// Error codes used by 9 | /// [StructureFactory::produce](crate::StructureFactory::produce). 10 | /// 11 | /// [Screeps API Docs](https://docs.screeps.com/api/#StructureFactory.produce). 12 | /// 13 | /// [Screeps Engine Source Code](https://github.com/screeps/engine/blob/97c9d12385fed686655c13b09f5f2457dd83a2bf/src/game/structures.js#L1434) 14 | #[derive( 15 | Debug, PartialEq, Eq, Clone, Copy, Hash, FromPrimitive, Deserialize_repr, Serialize_repr, 16 | )] 17 | #[repr(i8)] 18 | pub enum ProduceErrorCode { 19 | NotOwner = -1, 20 | Busy = -4, 21 | NotEnoughResources = -6, 22 | InvalidTarget = -7, 23 | Full = -8, 24 | InvalidArgs = -10, 25 | Tired = -11, 26 | RclNotEnough = -14, 27 | } 28 | 29 | impl FromReturnCode for ProduceErrorCode { 30 | type Error = Self; 31 | 32 | fn result_from_i8(val: i8) -> Result<(), Self::Error> { 33 | let maybe_result = Self::try_result_from_i8(val); 34 | #[cfg(feature = "unsafe-return-conversion")] 35 | unsafe { 36 | maybe_result.unwrap_unchecked() 37 | } 38 | #[cfg(not(feature = "unsafe-return-conversion"))] 39 | maybe_result.unwrap() 40 | } 41 | 42 | fn try_result_from_i8(val: i8) -> Option> { 43 | match val { 44 | 0 => Some(Ok(())), 45 | -1 => Some(Err(ProduceErrorCode::NotOwner)), 46 | -4 => Some(Err(ProduceErrorCode::Busy)), 47 | -6 => Some(Err(ProduceErrorCode::NotEnoughResources)), 48 | -7 => Some(Err(ProduceErrorCode::InvalidTarget)), 49 | -8 => Some(Err(ProduceErrorCode::Full)), 50 | -10 => Some(Err(ProduceErrorCode::InvalidArgs)), 51 | -11 => Some(Err(ProduceErrorCode::Tired)), 52 | -14 => Some(Err(ProduceErrorCode::RclNotEnough)), 53 | _ => None, 54 | } 55 | } 56 | } 57 | 58 | impl fmt::Display for ProduceErrorCode { 59 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 60 | let msg: &'static str = match self { 61 | ProduceErrorCode::NotOwner => "you are not the owner of this structure", 62 | ProduceErrorCode::Busy => { 63 | "the factory is not operated by the pwr_operate_factory power" 64 | } 65 | ProduceErrorCode::NotEnoughResources => { 66 | "the structure does not have the required amount of resources" 67 | } 68 | ProduceErrorCode::InvalidTarget => { 69 | "the factory cannot produce the commodity of this level" 70 | } 71 | ProduceErrorCode::Full => "the factory cannot contain the produce", 72 | ProduceErrorCode::InvalidArgs => "the arguments provided are incorrect", 73 | ProduceErrorCode::Tired => "the factory is still cooling down", 74 | ProduceErrorCode::RclNotEnough => { 75 | "your room controller level is insufficient to use the factory" 76 | } 77 | }; 78 | 79 | write!(f, "{}", msg) 80 | } 81 | } 82 | 83 | impl Error for ProduceErrorCode {} 84 | 85 | impl From for ErrorCode { 86 | fn from(value: ProduceErrorCode) -> Self { 87 | // Safety: ProduceErrorCode is repr(i8), so we can cast it to get the 88 | // discriminant value, which will match the raw return code value that ErrorCode 89 | // expects. Ref: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.discriminant.coercion.intro 90 | // Safety: ProduceErrorCode discriminants are always error code values, and thus 91 | // the Result returned here will always be an `Err` variant, so we can always 92 | // extract the error without panicking 93 | Self::result_from_i8(value as i8).unwrap_err() 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/enums/action_error_codes/structurelink_error_codes.rs: -------------------------------------------------------------------------------- 1 | use std::{error::Error, fmt}; 2 | 3 | use num_derive::FromPrimitive; 4 | use serde_repr::{Deserialize_repr, Serialize_repr}; 5 | 6 | use crate::{constants::ErrorCode, FromReturnCode}; 7 | 8 | /// Error codes used by 9 | /// [StructureLink::transfer_energy](crate::StructureLink::transfer_energy). 10 | /// 11 | /// [Screeps API Docs](https://docs.screeps.com/api/#StructureLink.transferEnergy). 12 | /// 13 | /// [Screeps Engine Source Code](https://github.com/screeps/engine/blob/97c9d12385fed686655c13b09f5f2457dd83a2bf/src/game/structures.js#L488) 14 | #[derive( 15 | Debug, PartialEq, Eq, Clone, Copy, Hash, FromPrimitive, Deserialize_repr, Serialize_repr, 16 | )] 17 | #[repr(i8)] 18 | pub enum TransferEnergyErrorCode { 19 | NotOwner = -1, 20 | NotEnoughEnergy = -6, 21 | InvalidTarget = -7, 22 | Full = -8, 23 | NotInRange = -9, 24 | InvalidArgs = -10, 25 | Tired = -11, 26 | RclNotEnough = -14, 27 | } 28 | 29 | impl FromReturnCode for TransferEnergyErrorCode { 30 | type Error = Self; 31 | 32 | fn result_from_i8(val: i8) -> Result<(), Self::Error> { 33 | let maybe_result = Self::try_result_from_i8(val); 34 | #[cfg(feature = "unsafe-return-conversion")] 35 | unsafe { 36 | maybe_result.unwrap_unchecked() 37 | } 38 | #[cfg(not(feature = "unsafe-return-conversion"))] 39 | maybe_result.unwrap() 40 | } 41 | 42 | fn try_result_from_i8(val: i8) -> Option> { 43 | match val { 44 | 0 => Some(Ok(())), 45 | -1 => Some(Err(TransferEnergyErrorCode::NotOwner)), 46 | -6 => Some(Err(TransferEnergyErrorCode::NotEnoughEnergy)), 47 | -7 => Some(Err(TransferEnergyErrorCode::InvalidTarget)), 48 | -8 => Some(Err(TransferEnergyErrorCode::Full)), 49 | -9 => Some(Err(TransferEnergyErrorCode::NotInRange)), 50 | -10 => Some(Err(TransferEnergyErrorCode::InvalidArgs)), 51 | -11 => Some(Err(TransferEnergyErrorCode::Tired)), 52 | -14 => Some(Err(TransferEnergyErrorCode::RclNotEnough)), 53 | _ => None, 54 | } 55 | } 56 | } 57 | 58 | impl fmt::Display for TransferEnergyErrorCode { 59 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 60 | let msg: &'static str = match self { 61 | TransferEnergyErrorCode::NotOwner => "you are not the owner of this link", 62 | TransferEnergyErrorCode::NotEnoughEnergy => { 63 | "the structure does not have the given amount of energy" 64 | } 65 | TransferEnergyErrorCode::InvalidTarget => { 66 | "the target is not a valid structurelink object" 67 | } 68 | TransferEnergyErrorCode::Full => "the target cannot receive any more energy", 69 | TransferEnergyErrorCode::NotInRange => "the target is too far away", 70 | TransferEnergyErrorCode::InvalidArgs => "the energy amount is incorrect", 71 | TransferEnergyErrorCode::Tired => "the link is still cooling down", 72 | TransferEnergyErrorCode::RclNotEnough => { 73 | "room controller level insufficient to use this link" 74 | } 75 | }; 76 | 77 | write!(f, "{}", msg) 78 | } 79 | } 80 | 81 | impl Error for TransferEnergyErrorCode {} 82 | 83 | impl From for ErrorCode { 84 | fn from(value: TransferEnergyErrorCode) -> Self { 85 | // Safety: TransferEnergyErrorCode is repr(i8), so we can cast it to get the 86 | // discriminant value, which will match the raw return code value that ErrorCode 87 | // expects. Ref: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.discriminant.coercion.intro 88 | // Safety: TransferEnergyErrorCode discriminants are always error code values, 89 | // and thus the Result returned here will always be an `Err` variant, so we can 90 | // always extract the error without panicking 91 | Self::result_from_i8(value as i8).unwrap_err() 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/enums/action_error_codes/structurenuker_error_codes.rs: -------------------------------------------------------------------------------- 1 | use std::{error::Error, fmt}; 2 | 3 | use num_derive::FromPrimitive; 4 | use serde_repr::{Deserialize_repr, Serialize_repr}; 5 | 6 | use crate::{constants::ErrorCode, FromReturnCode}; 7 | 8 | /// Error codes used by 9 | /// [StructureNuker::launch_nuke](crate::StructureNuker::launch_nuke). 10 | /// 11 | /// [Screeps API Docs](https://docs.screeps.com/api/#StructureNuker.launchNuke). 12 | /// 13 | /// [Screeps Engine Source Code](https://github.com/screeps/engine/blob/97c9d12385fed686655c13b09f5f2457dd83a2bf/src/game/structures.js#L1356) 14 | #[derive( 15 | Debug, PartialEq, Eq, Clone, Copy, Hash, FromPrimitive, Deserialize_repr, Serialize_repr, 16 | )] 17 | #[repr(i8)] 18 | pub enum LaunchNukeErrorCode { 19 | NotOwner = -1, 20 | NotEnoughResources = -6, 21 | InvalidTarget = -7, 22 | NotInRange = -9, 23 | InvalidArgs = -10, 24 | Tired = -11, 25 | RclNotEnough = -14, 26 | } 27 | 28 | impl FromReturnCode for LaunchNukeErrorCode { 29 | type Error = Self; 30 | 31 | fn result_from_i8(val: i8) -> Result<(), Self::Error> { 32 | let maybe_result = Self::try_result_from_i8(val); 33 | #[cfg(feature = "unsafe-return-conversion")] 34 | unsafe { 35 | maybe_result.unwrap_unchecked() 36 | } 37 | #[cfg(not(feature = "unsafe-return-conversion"))] 38 | maybe_result.unwrap() 39 | } 40 | 41 | fn try_result_from_i8(val: i8) -> Option> { 42 | match val { 43 | 0 => Some(Ok(())), 44 | -1 => Some(Err(LaunchNukeErrorCode::NotOwner)), 45 | -6 => Some(Err(LaunchNukeErrorCode::NotEnoughResources)), 46 | -7 => Some(Err(LaunchNukeErrorCode::InvalidTarget)), 47 | -9 => Some(Err(LaunchNukeErrorCode::NotInRange)), 48 | -10 => Some(Err(LaunchNukeErrorCode::InvalidArgs)), 49 | -11 => Some(Err(LaunchNukeErrorCode::Tired)), 50 | -14 => Some(Err(LaunchNukeErrorCode::RclNotEnough)), 51 | _ => None, 52 | } 53 | } 54 | } 55 | 56 | impl fmt::Display for LaunchNukeErrorCode { 57 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 58 | let msg: &'static str = match self { 59 | LaunchNukeErrorCode::NotOwner => "you are not the owner of this structure", 60 | LaunchNukeErrorCode::NotEnoughResources => { 61 | "the structure does not have enough energy and/or ghodium" 62 | } 63 | LaunchNukeErrorCode::InvalidTarget => { 64 | "the nuke can't be launched to the specified roomposition (see start areas)" 65 | } 66 | LaunchNukeErrorCode::NotInRange => "the target room is out of range", 67 | LaunchNukeErrorCode::InvalidArgs => "the target is not a valid roomposition", 68 | LaunchNukeErrorCode::Tired => "this structure is still cooling down", 69 | LaunchNukeErrorCode::RclNotEnough => { 70 | "room controller level insufficient to use this structure" 71 | } 72 | }; 73 | 74 | write!(f, "{}", msg) 75 | } 76 | } 77 | 78 | impl Error for LaunchNukeErrorCode {} 79 | 80 | impl From for ErrorCode { 81 | fn from(value: LaunchNukeErrorCode) -> Self { 82 | // Safety: LaunchNukeErrorCode is repr(i8), so we can cast it to get the 83 | // discriminant value, which will match the raw return code value that ErrorCode 84 | // expects. Ref: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.discriminant.coercion.intro 85 | // Safety: LaunchNukeErrorCode discriminants are always error code values, and 86 | // thus the Result returned here will always be an `Err` variant, so we can 87 | // always extract the error without panicking 88 | Self::result_from_i8(value as i8).unwrap_err() 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/enums/action_error_codes/structureobserver_error_codes.rs: -------------------------------------------------------------------------------- 1 | use std::{error::Error, fmt}; 2 | 3 | use num_derive::FromPrimitive; 4 | use serde_repr::{Deserialize_repr, Serialize_repr}; 5 | 6 | use crate::{constants::ErrorCode, FromReturnCode}; 7 | 8 | /// Error codes used by 9 | /// [StructureObserver::observe_room](crate::StructureObserver::observe_room). 10 | /// 11 | /// [Screeps API Docs](https://docs.screeps.com/api/#StructureObserver.observeRoom). 12 | /// 13 | /// [Screeps Engine Source Code](https://github.com/screeps/engine/blob/97c9d12385fed686655c13b09f5f2457dd83a2bf/src/game/structures.js#L548) 14 | #[derive( 15 | Debug, PartialEq, Eq, Clone, Copy, Hash, FromPrimitive, Deserialize_repr, Serialize_repr, 16 | )] 17 | #[repr(i8)] 18 | pub enum ObserveRoomErrorCode { 19 | NotOwner = -1, 20 | NotInRange = -9, 21 | InvalidArgs = -10, 22 | RclNotEnough = -14, 23 | } 24 | 25 | impl FromReturnCode for ObserveRoomErrorCode { 26 | type Error = Self; 27 | 28 | fn result_from_i8(val: i8) -> Result<(), Self::Error> { 29 | let maybe_result = Self::try_result_from_i8(val); 30 | #[cfg(feature = "unsafe-return-conversion")] 31 | unsafe { 32 | maybe_result.unwrap_unchecked() 33 | } 34 | #[cfg(not(feature = "unsafe-return-conversion"))] 35 | maybe_result.unwrap() 36 | } 37 | 38 | fn try_result_from_i8(val: i8) -> Option> { 39 | match val { 40 | 0 => Some(Ok(())), 41 | -1 => Some(Err(ObserveRoomErrorCode::NotOwner)), 42 | -9 => Some(Err(ObserveRoomErrorCode::NotInRange)), 43 | -10 => Some(Err(ObserveRoomErrorCode::InvalidArgs)), 44 | -14 => Some(Err(ObserveRoomErrorCode::RclNotEnough)), 45 | _ => None, 46 | } 47 | } 48 | } 49 | 50 | impl fmt::Display for ObserveRoomErrorCode { 51 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 52 | let msg: &'static str = match self { 53 | ObserveRoomErrorCode::NotOwner => "you are not the owner of this structure", 54 | ObserveRoomErrorCode::NotInRange => "room roomname is not in observing range", 55 | ObserveRoomErrorCode::InvalidArgs => "roomname argument is not a valid room name value", 56 | ObserveRoomErrorCode::RclNotEnough => { 57 | "room controller level insufficient to use this structure" 58 | } 59 | }; 60 | 61 | write!(f, "{}", msg) 62 | } 63 | } 64 | 65 | impl Error for ObserveRoomErrorCode {} 66 | 67 | impl From for ErrorCode { 68 | fn from(value: ObserveRoomErrorCode) -> Self { 69 | // Safety: ObserveRoomErrorCode is repr(i8), so we can cast it to get the 70 | // discriminant value, which will match the raw return code value that ErrorCode 71 | // expects. Ref: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.discriminant.coercion.intro 72 | // Safety: ObserveRoomErrorCode discriminants are always error code values, and 73 | // thus the Result returned here will always be an `Err` variant, so we can 74 | // always extract the error without panicking 75 | Self::result_from_i8(value as i8).unwrap_err() 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/enums/action_error_codes/structurepowerspawn_error_codes.rs: -------------------------------------------------------------------------------- 1 | use std::{error::Error, fmt}; 2 | 3 | use num_derive::FromPrimitive; 4 | use serde_repr::{Deserialize_repr, Serialize_repr}; 5 | 6 | use crate::{constants::ErrorCode, FromReturnCode}; 7 | 8 | /// Error codes used by 9 | /// [StructurePowerSpawn::process_power](crate::StructurePowerSpawn::process_power). 10 | /// 11 | /// 12 | /// [Screeps API Docs](https://docs.screeps.com/api/#StructurePowerSpawn.processPower). 13 | /// 14 | /// [Screeps Engine Source Code](https://github.com/screeps/engine/blob/97c9d12385fed686655c13b09f5f2457dd83a2bf/src/game/structures.js#L613) 15 | #[derive( 16 | Debug, PartialEq, Eq, Clone, Copy, Hash, FromPrimitive, Deserialize_repr, Serialize_repr, 17 | )] 18 | #[repr(i8)] 19 | pub enum ProcessPowerErrorCode { 20 | NotOwner = -1, 21 | NotEnoughResources = -6, 22 | RclNotEnough = -14, 23 | } 24 | 25 | impl FromReturnCode for ProcessPowerErrorCode { 26 | type Error = Self; 27 | 28 | fn result_from_i8(val: i8) -> Result<(), Self::Error> { 29 | let maybe_result = Self::try_result_from_i8(val); 30 | #[cfg(feature = "unsafe-return-conversion")] 31 | unsafe { 32 | maybe_result.unwrap_unchecked() 33 | } 34 | #[cfg(not(feature = "unsafe-return-conversion"))] 35 | maybe_result.unwrap() 36 | } 37 | 38 | fn try_result_from_i8(val: i8) -> Option> { 39 | match val { 40 | 0 => Some(Ok(())), 41 | -1 => Some(Err(ProcessPowerErrorCode::NotOwner)), 42 | -6 => Some(Err(ProcessPowerErrorCode::NotEnoughResources)), 43 | -14 => Some(Err(ProcessPowerErrorCode::RclNotEnough)), 44 | _ => None, 45 | } 46 | } 47 | } 48 | 49 | impl fmt::Display for ProcessPowerErrorCode { 50 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 51 | let msg: &'static str = match self { 52 | ProcessPowerErrorCode::NotOwner => "you are not the owner of this structure", 53 | ProcessPowerErrorCode::NotEnoughResources => { 54 | "the structure does not have enough energy or power resource units" 55 | } 56 | ProcessPowerErrorCode::RclNotEnough => { 57 | "room controller level insufficient to use this structure" 58 | } 59 | }; 60 | 61 | write!(f, "{}", msg) 62 | } 63 | } 64 | 65 | impl Error for ProcessPowerErrorCode {} 66 | 67 | impl From for ErrorCode { 68 | fn from(value: ProcessPowerErrorCode) -> Self { 69 | // Safety: ProcessPowerErrorCode is repr(i8), so we can cast it to get the 70 | // discriminant value, which will match the raw return code value that ErrorCode 71 | // expects. Ref: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.discriminant.coercion.intro 72 | // Safety: ProcessPowerErrorCode discriminants are always error code values, and 73 | // thus the Result returned here will always be an `Err` variant, so we can 74 | // always extract the error without panicking 75 | Self::result_from_i8(value as i8).unwrap_err() 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/enums/action_error_codes/structurerampart_error_codes.rs: -------------------------------------------------------------------------------- 1 | use std::{error::Error, fmt}; 2 | 3 | use num_derive::FromPrimitive; 4 | use serde_repr::{Deserialize_repr, Serialize_repr}; 5 | 6 | use crate::{constants::ErrorCode, FromReturnCode}; 7 | 8 | /// Error codes used by 9 | /// [StructureRampart::set_public](crate::StructureRampart::set_public). 10 | /// 11 | /// [Screeps API Docs](https://docs.screeps.com/api/#StructureRampart.setPublic). 12 | /// 13 | /// [Screeps Engine Source Code](https://github.com/screeps/engine/blob/97c9d12385fed686655c13b09f5f2457dd83a2bf/src/game/structures.js#L651) 14 | #[derive( 15 | Debug, PartialEq, Eq, Clone, Copy, Hash, FromPrimitive, Deserialize_repr, Serialize_repr, 16 | )] 17 | #[repr(i8)] 18 | pub enum SetPublicErrorCode { 19 | NotOwner = -1, 20 | } 21 | 22 | impl FromReturnCode for SetPublicErrorCode { 23 | type Error = Self; 24 | 25 | fn result_from_i8(val: i8) -> Result<(), Self::Error> { 26 | let maybe_result = Self::try_result_from_i8(val); 27 | #[cfg(feature = "unsafe-return-conversion")] 28 | unsafe { 29 | maybe_result.unwrap_unchecked() 30 | } 31 | #[cfg(not(feature = "unsafe-return-conversion"))] 32 | maybe_result.unwrap() 33 | } 34 | 35 | fn try_result_from_i8(val: i8) -> Option> { 36 | match val { 37 | 0 => Some(Ok(())), 38 | -1 => Some(Err(SetPublicErrorCode::NotOwner)), 39 | _ => None, 40 | } 41 | } 42 | } 43 | 44 | impl fmt::Display for SetPublicErrorCode { 45 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 46 | let msg: &'static str = match self { 47 | SetPublicErrorCode::NotOwner => "you are not the owner of this structure", 48 | }; 49 | 50 | write!(f, "{}", msg) 51 | } 52 | } 53 | 54 | impl Error for SetPublicErrorCode {} 55 | 56 | impl From for ErrorCode { 57 | fn from(value: SetPublicErrorCode) -> Self { 58 | // Safety: SetPublicErrorCode is repr(i8), so we can cast it to get the 59 | // discriminant value, which will match the raw return code value that ErrorCode 60 | // expects. Ref: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.discriminant.coercion.intro 61 | // Safety: SetPublicErrorCode discriminants are always error code values, and 62 | // thus the Result returned here will always be an `Err` variant, so we can 63 | // always extract the error without panicking 64 | Self::result_from_i8(value as i8).unwrap_err() 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/enums/action_error_codes/structureterminal_error_codes.rs: -------------------------------------------------------------------------------- 1 | use std::{error::Error, fmt}; 2 | 3 | use num_derive::FromPrimitive; 4 | use serde_repr::{Deserialize_repr, Serialize_repr}; 5 | 6 | use crate::{constants::ErrorCode, FromReturnCode}; 7 | 8 | /// Error codes used by 9 | /// [StructureTerminal::send](crate::StructureTerminal::send). 10 | /// 11 | /// [Screeps API Docs](https://docs.screeps.com/api/#StructureTerminal.send). 12 | /// 13 | /// [Screeps Engine Source Code](https://github.com/screeps/engine/blob/97c9d12385fed686655c13b09f5f2457dd83a2bf/src/game/structures.js#L714) 14 | #[derive( 15 | Debug, PartialEq, Eq, Clone, Copy, Hash, FromPrimitive, Deserialize_repr, Serialize_repr, 16 | )] 17 | #[repr(i8)] 18 | pub enum SendErrorCode { 19 | NotOwner = -1, 20 | NotEnoughResources = -6, 21 | InvalidArgs = -10, 22 | Tired = -11, 23 | RclNotEnough = -14, 24 | } 25 | 26 | impl FromReturnCode for SendErrorCode { 27 | type Error = Self; 28 | 29 | fn result_from_i8(val: i8) -> Result<(), Self::Error> { 30 | let maybe_result = Self::try_result_from_i8(val); 31 | #[cfg(feature = "unsafe-return-conversion")] 32 | unsafe { 33 | maybe_result.unwrap_unchecked() 34 | } 35 | #[cfg(not(feature = "unsafe-return-conversion"))] 36 | maybe_result.unwrap() 37 | } 38 | 39 | fn try_result_from_i8(val: i8) -> Option> { 40 | match val { 41 | 0 => Some(Ok(())), 42 | -1 => Some(Err(SendErrorCode::NotOwner)), 43 | -6 => Some(Err(SendErrorCode::NotEnoughResources)), 44 | -10 => Some(Err(SendErrorCode::InvalidArgs)), 45 | -11 => Some(Err(SendErrorCode::Tired)), 46 | -14 => Some(Err(SendErrorCode::RclNotEnough)), 47 | _ => None, 48 | } 49 | } 50 | } 51 | 52 | impl fmt::Display for SendErrorCode { 53 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 54 | let msg: &'static str = match self { 55 | SendErrorCode::NotOwner => "you are not the owner of this structure", 56 | SendErrorCode::NotEnoughResources => { 57 | "the structure does not have the required amount of resources" 58 | } 59 | SendErrorCode::InvalidArgs => "the arguments provided are incorrect", 60 | SendErrorCode::Tired => "the terminal is still cooling down", 61 | SendErrorCode::RclNotEnough => { 62 | "your room controller level is insufficient to use this terminal" 63 | } 64 | }; 65 | 66 | write!(f, "{}", msg) 67 | } 68 | } 69 | 70 | impl Error for SendErrorCode {} 71 | 72 | impl From for ErrorCode { 73 | fn from(value: SendErrorCode) -> Self { 74 | // Safety: SendErrorCode is repr(i8), so we can cast it to get the discriminant 75 | // value, which will match the raw return code value that ErrorCode expects. Ref: https://doc.rust-lang.org/reference/items/enumerations.html#r-items.enum.discriminant.coercion.intro 76 | // Safety: SendErrorCode discriminants are always error code values, and thus 77 | // the Result returned here will always be an `Err` variant, so we can always 78 | // extract the error without panicking 79 | Self::result_from_i8(value as i8).unwrap_err() 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/game/gcl.rs: -------------------------------------------------------------------------------- 1 | //! Global Control Level information. 2 | //! 3 | //! [Screeps documentation](https://docs.screeps.com/api/#Game.gcl) 4 | use wasm_bindgen::prelude::*; 5 | 6 | #[wasm_bindgen] 7 | extern "C" { 8 | #[wasm_bindgen(js_name = "gcl")] 9 | type Gcl; 10 | 11 | #[wasm_bindgen(js_namespace = ["Game"], js_class = "gcl", static_method_of = Gcl, getter, js_name = level)] 12 | fn level() -> u32; 13 | 14 | #[wasm_bindgen(js_namespace = ["Game"], js_class = "gcl", static_method_of = Gcl, getter, js_name = progress)] 15 | fn progress() -> f64; 16 | 17 | #[wasm_bindgen(js_namespace = ["Game"], js_class = "gcl", static_method_of = Gcl, getter, js_name = progressTotal)] 18 | fn progress_total() -> f64; 19 | } 20 | 21 | /// Your current Global Control Level, which determines the number of rooms 22 | /// you are allowed to claim. 23 | pub fn level() -> u32 { 24 | Gcl::level() 25 | } 26 | 27 | /// Your progress toward the next Global Control Level. 28 | pub fn progress() -> f64 { 29 | Gcl::progress() 30 | } 31 | 32 | /// Total progress needed to reach the next Global Control Level. 33 | pub fn progress_total() -> f64 { 34 | Gcl::progress_total() 35 | } 36 | -------------------------------------------------------------------------------- /src/game/gpl.rs: -------------------------------------------------------------------------------- 1 | //! Global Power Level information. 2 | //! 3 | //! [Screeps documentation](http://docs.screeps.com/api/#Game.gpl) 4 | use wasm_bindgen::prelude::*; 5 | 6 | #[wasm_bindgen] 7 | extern "C" { 8 | #[wasm_bindgen(js_name = "gpl")] 9 | type Gpl; 10 | 11 | #[wasm_bindgen(js_namespace = ["Game"], js_class = "gpl", static_method_of = Gpl, getter, js_name = level)] 12 | fn level() -> u32; 13 | 14 | #[wasm_bindgen(js_namespace = ["Game"], js_class = "gpl", static_method_of = Gpl, getter, js_name = progress)] 15 | fn progress() -> f64; 16 | 17 | #[wasm_bindgen(js_namespace = ["Game"], js_class = "gpl", static_method_of = Gpl, getter, js_name = progressTotal)] 18 | fn progress_total() -> f64; 19 | } 20 | 21 | /// Your current Global Power Level, which determines power creep 22 | /// development. 23 | pub fn level() -> u32 { 24 | Gpl::level() 25 | } 26 | 27 | /// Your progress toward the next Global Power Level. 28 | pub fn progress() -> f64 { 29 | Gpl::progress() 30 | } 31 | 32 | /// Total progress needed to reach the next Global Power Level. 33 | pub fn progress_total() -> f64 { 34 | Gpl::progress_total() 35 | } 36 | -------------------------------------------------------------------------------- /src/game/shard.rs: -------------------------------------------------------------------------------- 1 | //! Information about the current shard. 2 | //! 3 | //! [Screeps documentation](https://docs.screeps.com/api/#Game.shard) 4 | use js_sys::JsString; 5 | use wasm_bindgen::prelude::*; 6 | 7 | #[wasm_bindgen] 8 | extern "C" { 9 | #[wasm_bindgen(js_name = "shard")] 10 | type Shard; 11 | 12 | #[wasm_bindgen(js_namespace = ["Game"], js_class = "shard", static_method_of = Shard, getter, js_name = name)] 13 | fn name() -> JsString; 14 | 15 | #[wasm_bindgen(js_namespace = ["Game"], js_class = "shard", static_method_of = Shard, getter, js_name = type)] 16 | fn shard_type() -> JsString; 17 | 18 | #[wasm_bindgen(js_namespace = ["Game"], js_class = "shard", static_method_of = Shard, getter, js_name = ptr)] 19 | fn ptr() -> bool; 20 | } 21 | 22 | /// Current shard name. 23 | pub fn name() -> String { 24 | Shard::name().into() 25 | } 26 | 27 | /// Shard type. Currently always "normal". 28 | pub fn shard_type() -> String { 29 | Shard::shard_type().into() 30 | } 31 | 32 | /// Flag for if this is a public test server or not. 33 | pub fn ptr() -> bool { 34 | Shard::ptr() 35 | } 36 | -------------------------------------------------------------------------------- /src/inter_shard_memory.rs: -------------------------------------------------------------------------------- 1 | //! Interface for Screeps inter-shard memory, allowing communication between 2 | //! instances of your code running on different shards. 3 | //! 4 | //! [Screeps documentation](https://docs.screeps.com/api/#InterShardMemory) 5 | use js_sys::JsString; 6 | use wasm_bindgen::prelude::*; 7 | 8 | #[wasm_bindgen] 9 | extern "C" { 10 | type InterShardMemory; 11 | 12 | #[wasm_bindgen(static_method_of = InterShardMemory, js_name = getLocal)] 13 | fn get_local() -> Option; 14 | 15 | #[wasm_bindgen(static_method_of = InterShardMemory, js_name = setLocal)] 16 | fn set_local(val: &JsString); 17 | 18 | #[wasm_bindgen(static_method_of = InterShardMemory, js_name = getRemote)] 19 | fn get_remote(shard: &JsString) -> Option; 20 | } 21 | 22 | /// Get the current local [`JsString`] intershard memory for this shard. 23 | /// 24 | /// [Screeps documentation](https://docs.screeps.com/api/#InterShardMemory.getLocal) 25 | pub fn get_local() -> Option { 26 | InterShardMemory::get_local() 27 | } 28 | 29 | /// Overwrite the current shard's intershard memory segment with new 30 | /// contents. Maximum allowed length of [`INTER_SHARD_MEMORY_SIZE_LIMIT`] 31 | /// UTF-16 units. 32 | /// 33 | /// [Screeps documentation](https://docs.screeps.com/api/#InterShardMemory.setLocal) 34 | /// 35 | /// [`INTER_SHARD_MEMORY_SIZE_LIMIT`]: 36 | /// crate::constants::INTER_SHARD_MEMORY_SIZE_LIMIT 37 | pub fn set_local(val: &JsString) { 38 | InterShardMemory::set_local(val) 39 | } 40 | 41 | /// Get the data that another shard's code instance has written to its 42 | /// intershard memory segment. 43 | /// 44 | /// [Screeps documentation](https://docs.screeps.com/api/#InterShardMemory.getRemote) 45 | pub fn get_remote(shard: &JsString) -> Option { 46 | InterShardMemory::get_remote(shard) 47 | } 48 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Typed bindings to the Screeps: World in-game API for WASM Rust AIs. 2 | //! 3 | //! # Performance 4 | //! 5 | //! Due to the limited CPU available to the player in Screeps: World, the 6 | //! performance implications of running WebAssembly are good to be aware of. 7 | //! 8 | //! WebAssembly instances have a dedicated linear memory, and data being passed 9 | //! in or out must be copied. Additionally, Rust uses UTF-8 strings while 10 | //! JavaScript uses UTF-16 strings, so any strings being copied must also be 11 | //! converted between encodings. 12 | //! 13 | //! Additionally, compile time for the `WebAssembly.Module` can be considerable, 14 | //! requiring a lot of CPU time on each initial startup tick (and potentially 15 | //! requiring skipped ticks for larger bots). However, global resets are very 16 | //! infrequent in most environments, so the impact of this isn't severe. 17 | //! 18 | //! After compilation, the WebAssembly environment has near-native performance, 19 | //! and no Javascript garbage collection happening for its memory space, 20 | //! allowing for faster execution of some types of workloads. Overall, the 21 | //! advantages and disadvantages of WebAssembly in Screeps are relatively small, 22 | //! especially when compared to the relatively high 0.2ms cost of game actions. 23 | //! 24 | //! # Data Persistence 25 | //! 26 | //! In the Screeps: World JavaScript environment, the `Memory` object is the 27 | //! typical way to store data in a way that persists through the environment 28 | //! resets that happen occasionally, either triggered by deploying a new version 29 | //! of your code or due to natural expiration in the server. It provides a 30 | //! wrapper that automatically deserializes the contents of `RawMemory` via the 31 | //! `JSON.parse()` JavaScript function when accessed for the first time each 32 | //! tick, then gets serialized by `JSON.stringify()` at the end of the tick. 33 | //! 34 | //! Using this untyped `Memory` object (or the reference to a part of it, which 35 | //! can be obtained from the `memory` function on various game objects) from 36 | //! within WebAssembly can be awkward, but is recommended if you need to 37 | //! maintain compatibility with the default `Memory` object. 38 | //! 39 | //! An alternative that you may prefer is to use `RawMemory` instead, fetching 40 | //! the stored data in string format using [`raw_memory::get`] and deserializing 41 | //! within WebAssembly using [`serde`] or another serializion approach, then 42 | //! serializing and using [`raw_memory::set`] to store the data. 43 | //! 44 | //! If you choose the `RawMemory` approach, be aware that some game methods 45 | //! (notably [`StructureSpawn::spawn_creep`] and [`Creep::move_to`]) directly 46 | //! store data in the `Memory` object; replacing the 'special' `Memory` object 47 | //! with one that doesn't attempt to deserialize the contents of `RawMemory` may 48 | //! be advisable if you're using it directly (note that this needs to be done 49 | //! each tick to be effective). 50 | //! 51 | //! # Cargo Features 52 | //! 53 | //! ## `mmo` 54 | //! 55 | //! Enables a number of functions for CPU management and inter-shard 56 | //! communication present on the Screeps: World official servers but not on 57 | //! private servers. 58 | //! 59 | //! ## `seasonal-season-1` 60 | //! 61 | //! Enables the score resource and entities, introduced for Screeps Seasonal's 62 | //! first season, as well as enabling constants relevant to season 1. 63 | //! 64 | //! ## `seasonal-season-2` 65 | //! 66 | //! Enables the symbol resources and entities, introduced for Screeps Seasonal's 67 | //! second season, as well as enabling constants relevant to season 2. 68 | //! 69 | //! ## `seasonal-season-5` 70 | //! 71 | //! Enables the thorium resource and reactor object, introduced for Screeps 72 | //! Seasonal's fifth season, as well as enabling constants relevant to season 5. 73 | //! 74 | //! ## `sim` 75 | //! 76 | //! Enables special-case handling of the unique room name present in the 77 | //! simulator - must be enabled to build code that is compatible with that 78 | //! environment. If this is enabled, the top-left valid room coordinate has the 79 | //! name `sim`, otherwise it's named `W127N127`. 80 | //! 81 | //! ## `unsafe-return-conversion` 82 | //! 83 | //! Enables return code conversion from game functions that presumes all return 84 | //! code values are in the expected ranges skipping checks, and risks undefined 85 | //! behavior if they are not. 86 | #![recursion_limit = "128"] 87 | // to build locally with doc_cfg enabled, run: 88 | // `RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features` 89 | #![cfg_attr(docsrs, feature(doc_auto_cfg))] 90 | // warn when functions can safely be given the const keyword, see 91 | // https://rust-lang.github.io/rust-clippy/master/index.html#/missing_const_for_fn 92 | // unfortunately this warns for bindgen-attached functions so we can't leave it 93 | // enabled 94 | 95 | // #![warn(clippy::missing_const_for_fn)] 96 | 97 | // disable deprecation warnings - TODO need to figure out how to get wasm_bindgen's new thread_local 98 | // attribute working 99 | #![allow(deprecated)] 100 | 101 | pub mod console; 102 | pub mod constants; 103 | pub mod enums; 104 | pub mod game; 105 | #[cfg(feature = "mmo")] 106 | pub mod inter_shard_memory; 107 | pub mod js_collections; 108 | pub mod local; 109 | pub mod memory; 110 | pub mod objects; 111 | pub mod pathfinder; 112 | pub(crate) mod prototypes; 113 | pub mod raw_memory; 114 | pub mod traits; 115 | 116 | pub use crate::{constants::*, enums::*, js_collections::*, local::*, objects::*, traits::*}; 117 | 118 | /// Traits which implement base functionalities for Screeps types. 119 | /// 120 | /// # Example 121 | /// 122 | /// ```no_run 123 | /// use js_sys::{JsString, Reflect}; 124 | /// use screeps::{game, prelude::*, Creep}; 125 | /// 126 | /// let c = game::creeps().get(String::from("Bob")).unwrap(); 127 | /// 128 | /// // `HasId` trait brought in from prelude 129 | /// let id = c.try_id().unwrap(); 130 | /// ``` 131 | /// 132 | /// This module contains all base functionality traits, and no structures. 133 | pub mod prelude { 134 | pub use crate::{js_collections::*, traits::*}; 135 | } 136 | -------------------------------------------------------------------------------- /src/local.rs: -------------------------------------------------------------------------------- 1 | //! Pure-data structures relating to Screeps. 2 | use std::ops::Range; 3 | 4 | mod cost_matrix; 5 | mod lodash_filter; 6 | mod object_id; 7 | mod position; 8 | mod room_coordinate; 9 | mod room_name; 10 | mod room_xy; 11 | mod terrain; 12 | 13 | /// Represents two constants related to room names. 14 | /// 15 | /// First, this is the constant added to room coordinates before they're stored 16 | /// in the packed representation. 17 | /// 18 | /// Second, `-HALF_WORLD_SIZE` is the minimum representable room name 19 | /// coordinate, and `HALF_WORLD_SIZE - 1` is the maximum representable room name 20 | /// coordinate. 21 | const HALF_WORLD_SIZE: i32 = 128; 22 | 23 | /// Valid room name coordinates. 24 | const VALID_ROOM_NAME_COORDINATES: Range = -HALF_WORLD_SIZE..HALF_WORLD_SIZE; 25 | 26 | /// Valid world positions 27 | // not an inclusive range since the range for world coords is `-128..=127`, and 28 | // the range for room coords is `0..=49`. 29 | const VALID_WORLD_POSITIONS: Range = 30 | -((ROOM_SIZE as i32) * HALF_WORLD_SIZE)..(ROOM_SIZE as i32) * HALF_WORLD_SIZE; 31 | 32 | use crate::ROOM_SIZE; 33 | 34 | pub use self::{ 35 | cost_matrix::*, lodash_filter::*, object_id::*, position::*, room_coordinate::*, room_name::*, 36 | room_xy::*, terrain::*, 37 | }; 38 | -------------------------------------------------------------------------------- /src/local/cost_matrix.rs: -------------------------------------------------------------------------------- 1 | use std::ops::{Index, IndexMut}; 2 | 3 | use serde::{Deserialize, Serialize}; 4 | 5 | use crate::{ 6 | constants::ROOM_AREA, 7 | objects::CostMatrix, 8 | traits::{CostMatrixGet, CostMatrixSet}, 9 | }; 10 | 11 | use super::{linear_index_to_xy, Position, RoomXY, XMajor}; 12 | 13 | /// A matrix of pathing costs for a room, stored in Rust memory. 14 | /// 15 | /// Use [`CostMatrix`] if a reference to data stored in JavaScript memory is 16 | /// preferred. 17 | #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 18 | #[serde(transparent)] 19 | pub struct LocalCostMatrix { 20 | #[serde(with = "serde_impls")] 21 | bits: [u8; ROOM_AREA], 22 | } 23 | 24 | impl Default for LocalCostMatrix { 25 | fn default() -> Self { 26 | Self::new() 27 | } 28 | } 29 | 30 | impl LocalCostMatrix { 31 | /// Create a `LocalCostMatrix` with a default value of 0 for all positions. 32 | /// 33 | /// # Example 34 | /// 35 | /// ```rust 36 | /// use screeps::local::{LocalCostMatrix, RoomXY}; 37 | /// 38 | /// let lcm = LocalCostMatrix::new(); 39 | /// let pos = unsafe { RoomXY::unchecked_new(10, 10) }; 40 | /// assert_eq!(lcm.get(pos), 0); 41 | /// ``` 42 | #[inline] 43 | pub const fn new() -> Self { 44 | LocalCostMatrix::new_with_value(0) 45 | } 46 | 47 | /// Create a `LocalCostMatrix` with a default value for all positions. 48 | /// 49 | /// # Example 50 | /// 51 | /// ```rust 52 | /// use screeps::local::{LocalCostMatrix, RoomXY}; 53 | /// 54 | /// let lcm = LocalCostMatrix::new_with_value(u8::MAX); 55 | /// let pos = unsafe { RoomXY::unchecked_new(10, 10) }; 56 | /// assert_eq!(lcm.get(pos), u8::MAX); 57 | /// ``` 58 | #[inline] 59 | pub const fn new_with_value(value: u8) -> Self { 60 | LocalCostMatrix { 61 | bits: [value; ROOM_AREA], 62 | } 63 | } 64 | 65 | // # Notes 66 | // This method does no bounds checking for the passed-in `RoomXY`, you may use 67 | // `RoomXY::unchecked_new` to skip all bounds checking. 68 | #[inline] 69 | pub fn set(&mut self, xy: RoomXY, val: u8) { 70 | self[xy] = val; 71 | } 72 | 73 | // # Notes 74 | // This method does no bounds checking for the passed-in `RoomXY`, you may use 75 | // `RoomXY::unchecked_new` to skip all bounds checking. 76 | #[inline] 77 | pub fn get(&self, xy: RoomXY) -> u8 { 78 | self[xy] 79 | } 80 | 81 | pub const fn get_bits(&self) -> &[u8; ROOM_AREA] { 82 | &self.bits 83 | } 84 | 85 | pub fn iter(&self) -> impl Iterator + '_ { 86 | self.bits 87 | .iter() 88 | .enumerate() 89 | .map(|(idx, &val)| (linear_index_to_xy(idx), val)) 90 | } 91 | 92 | pub fn iter_mut(&mut self) -> impl Iterator { 93 | self.bits 94 | .iter_mut() 95 | .enumerate() 96 | .map(|(idx, val)| (linear_index_to_xy(idx), val)) 97 | } 98 | } 99 | 100 | impl From for Vec { 101 | /// Returns a vector of bits length ROOM_AREA, where each position is 102 | /// `idx = ((x * ROOM_SIZE) + y)`. 103 | #[inline] 104 | fn from(lcm: LocalCostMatrix) -> Vec { 105 | lcm.bits.into() 106 | } 107 | } 108 | 109 | impl From<&LocalCostMatrix> for Vec { 110 | fn from(lcm: &LocalCostMatrix) -> Vec { 111 | lcm.bits.into() 112 | } 113 | } 114 | 115 | impl From<&CostMatrix> for LocalCostMatrix { 116 | fn from(js_matrix: &CostMatrix) -> Self { 117 | let mut bits = [0; ROOM_AREA]; 118 | js_matrix.get_bits().copy_to(&mut bits); 119 | 120 | LocalCostMatrix { bits } 121 | } 122 | } 123 | 124 | impl AsRef> for LocalCostMatrix { 125 | fn as_ref(&self) -> &XMajor { 126 | XMajor::from_flat_ref(&self.bits) 127 | } 128 | } 129 | 130 | impl AsMut> for LocalCostMatrix { 131 | fn as_mut(&mut self) -> &mut XMajor { 132 | XMajor::from_flat_mut(&mut self.bits) 133 | } 134 | } 135 | 136 | impl Index for LocalCostMatrix { 137 | type Output = u8; 138 | 139 | fn index(&self, xy: RoomXY) -> &Self::Output { 140 | &self.bits[xy.x][xy.y] 141 | } 142 | } 143 | 144 | impl IndexMut for LocalCostMatrix { 145 | fn index_mut(&mut self, xy: RoomXY) -> &mut Self::Output { 146 | &mut self.bits[xy.x][xy.y] 147 | } 148 | } 149 | 150 | impl Index for LocalCostMatrix { 151 | type Output = u8; 152 | 153 | fn index(&self, idx: Position) -> &Self::Output { 154 | &self[RoomXY::from(idx)] 155 | } 156 | } 157 | 158 | impl IndexMut for LocalCostMatrix { 159 | fn index_mut(&mut self, idx: Position) -> &mut Self::Output { 160 | &mut self[RoomXY::from(idx)] 161 | } 162 | } 163 | 164 | impl CostMatrixSet for LocalCostMatrix { 165 | fn set_xy(&mut self, xy: RoomXY, cost: u8) { 166 | LocalCostMatrix::set(self, xy, cost); 167 | } 168 | } 169 | 170 | impl CostMatrixGet for LocalCostMatrix { 171 | fn get_xy(&mut self, xy: RoomXY) -> u8 { 172 | LocalCostMatrix::get(self, xy) 173 | } 174 | } 175 | 176 | // need custom implementation in order to ensure length of 'bits' is always 177 | // ROOM_AREA 178 | mod serde_impls { 179 | use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer}; 180 | 181 | use super::ROOM_AREA; 182 | 183 | pub(super) fn serialize(bits: &[u8; ROOM_AREA], serializer: S) -> Result 184 | where 185 | S: Serializer, 186 | { 187 | bits[..].serialize(serializer) 188 | } 189 | 190 | pub(super) fn deserialize<'de, D>(deserializer: D) -> Result<[u8; ROOM_AREA], D::Error> 191 | where 192 | D: Deserializer<'de>, 193 | { 194 | let bits_slice: &[u8] = <&[u8]>::deserialize(deserializer)?; 195 | 196 | if bits_slice.len() != ROOM_AREA { 197 | return Err(D::Error::invalid_length( 198 | bits_slice.len(), 199 | &format!("a vec of length {ROOM_AREA}").as_str(), 200 | )); 201 | } 202 | 203 | // SAFETY: If the length wasn't right, we would have hit the check above 204 | Ok(bits_slice.try_into().unwrap()) 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /src/local/lodash_filter.rs: -------------------------------------------------------------------------------- 1 | use crate::MarketResourceType; 2 | 3 | use js_sys::Object; 4 | use wasm_bindgen::prelude::*; 5 | 6 | #[wasm_bindgen] 7 | extern "C" { 8 | /// An object that is used to filter returned results from Screeps functions 9 | /// that accept such filters 10 | #[wasm_bindgen] 11 | pub type LodashFilter; 12 | /// Set the `resourceType` to be returned. Pre-filters return results to 13 | /// increase performance when used with [`get_all_orders`]. 14 | #[wasm_bindgen(method, setter = resourceType)] 15 | pub fn resource_type(this: &LodashFilter, resource: MarketResourceType); 16 | 17 | // todo add more setters for use with Room.find() 18 | } 19 | 20 | impl LodashFilter { 21 | pub fn new() -> LodashFilter { 22 | Object::new().unchecked_into() 23 | } 24 | } 25 | 26 | impl Default for LodashFilter { 27 | fn default() -> Self { 28 | Self::new() 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/local/object_id/errors.rs: -------------------------------------------------------------------------------- 1 | use std::{error::Error, fmt, num::ParseIntError}; 2 | 3 | #[derive(Debug, Clone)] 4 | pub enum RawObjectIdParseError { 5 | Parse(ParseIntError), 6 | LargeValue(u128), 7 | } 8 | 9 | impl fmt::Display for RawObjectIdParseError { 10 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 11 | match self { 12 | RawObjectIdParseError::Parse(e) => { 13 | write!(f, "error parsing object id hex digits: {e}") 14 | } 15 | RawObjectIdParseError::LargeValue(value) => write!( 16 | f, 17 | "string contained hex value too big be object id. \ 18 | value {value} bigger than maximum for 24 digits" 19 | ), 20 | } 21 | } 22 | } 23 | 24 | impl Error for RawObjectIdParseError { 25 | fn cause(&self) -> Option<&dyn Error> { 26 | match self { 27 | RawObjectIdParseError::Parse(e) => Some(e), 28 | RawObjectIdParseError::LargeValue(_) => None, 29 | } 30 | } 31 | } 32 | 33 | impl From for RawObjectIdParseError { 34 | fn from(e: ParseIntError) -> Self { 35 | RawObjectIdParseError::Parse(e) 36 | } 37 | } 38 | 39 | impl RawObjectIdParseError { 40 | pub(crate) const fn value_too_large(val: u128) -> Self { 41 | RawObjectIdParseError::LargeValue(val) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/local/position/approximate_offsets.rs: -------------------------------------------------------------------------------- 1 | //! Methods related to approximating positions between other positions. 2 | use super::Position; 3 | 4 | impl Position { 5 | /// Calculates an approximate midpoint between this point and the target. 6 | /// 7 | /// In case of a tie, rounds towards this point. 8 | /// 9 | /// If `distance_towards_target` is bigger than the distance to the target, 10 | /// the target is returned. 11 | pub fn towards(self, target: Position, distance_towards_target: i32) -> Position { 12 | let (offset_x, offset_y) = target - self; 13 | let total_distance = offset_x.abs().max(offset_y.abs()); 14 | if distance_towards_target > total_distance { 15 | return target; 16 | } 17 | 18 | let new_offset_x = (offset_x * distance_towards_target) / total_distance; 19 | let new_offset_y = (offset_y * distance_towards_target) / total_distance; 20 | 21 | self + (new_offset_x, new_offset_y) 22 | } 23 | 24 | /// Calculates an approximate midpoint between this point and the target. 25 | /// 26 | /// In case of a tie, rounds towards the target. 27 | /// 28 | /// If `distance_from_target` is bigger than the distance to the target, 29 | /// this position is returned. 30 | pub fn between(self, target: Position, distance_from_target: i32) -> Position { 31 | target.towards(self, distance_from_target) 32 | } 33 | 34 | /// Calculates an approximate midpoint between this point and the target. 35 | /// 36 | /// In case of a tie, rounds towards the target. 37 | pub fn midpoint_between(self, target: Position) -> Position { 38 | let (offset_x, offset_y) = self - target; 39 | 40 | let new_offset_x = offset_x / 2; 41 | let new_offset_y = offset_y / 2; 42 | 43 | target + (new_offset_x, new_offset_y) 44 | } 45 | } 46 | 47 | #[cfg(test)] 48 | mod test { 49 | use super::Position; 50 | use crate::RoomName; 51 | 52 | fn test_rooms() -> impl Iterator { 53 | ["E0N0", "E20N20", "W20N0", "E20S20", "W20S20"] 54 | .iter() 55 | .map(|s| s.parse().unwrap()) 56 | } 57 | 58 | fn pos(room: RoomName, x: u8, y: u8) -> Position { 59 | Position::new(x.try_into().unwrap(), y.try_into().unwrap(), room) 60 | } 61 | 62 | #[test] 63 | fn towards_accurate() { 64 | for room in test_rooms() { 65 | let start = pos(room, 10, 10); 66 | assert_eq!(start.towards(pos(room, 10, 15), 1), pos(room, 10, 11)); 67 | assert_eq!(start.towards(pos(room, 10, 15), 4), pos(room, 10, 14)); 68 | assert_eq!(start.towards(pos(room, 10, 15), 10), pos(room, 10, 15)); 69 | assert_eq!(start.towards(pos(room, 15, 15), 1), pos(room, 11, 11)); 70 | assert_eq!(start.towards(pos(room, 15, 15), 3), pos(room, 13, 13)); 71 | assert_eq!(start.towards(pos(room, 15, 20), 2), pos(room, 11, 12)); 72 | assert_eq!(start.towards(pos(room, 0, 5), 2), pos(room, 8, 9)); 73 | } 74 | } 75 | #[test] 76 | fn towards_approximate() { 77 | for room in test_rooms() { 78 | let start = pos(room, 10, 10); 79 | assert_eq!(start.towards(pos(room, 15, 20), 1), pos(room, 10, 11)); 80 | assert_eq!(start.towards(pos(room, 15, 20), 9), pos(room, 14, 19)); 81 | assert_eq!(start.towards(pos(room, 0, 5), 1), pos(room, 9, 10)); 82 | } 83 | } 84 | #[test] 85 | fn midpoint_accurate() { 86 | for room in test_rooms() { 87 | let start = pos(room, 10, 10); 88 | assert_eq!(start.midpoint_between(pos(room, 10, 16)), pos(room, 10, 13)); 89 | assert_eq!(start.midpoint_between(pos(room, 20, 10)), pos(room, 15, 10)); 90 | assert_eq!(start.midpoint_between(pos(room, 12, 12)), pos(room, 11, 11)); 91 | assert_eq!(start.midpoint_between(pos(room, 4, 4)), pos(room, 7, 7)); 92 | } 93 | } 94 | #[test] 95 | fn midpoint_approximate() { 96 | for room in test_rooms() { 97 | let start = pos(room, 10, 10); 98 | assert_eq!(start.midpoint_between(pos(room, 10, 15)), pos(room, 10, 13)); 99 | assert_eq!(start.midpoint_between(pos(room, 19, 10)), pos(room, 15, 10)); 100 | assert_eq!(start.midpoint_between(pos(room, 11, 11)), pos(room, 11, 11)); 101 | assert_eq!(start.midpoint_between(pos(room, 15, 15)), pos(room, 13, 13)); 102 | assert_eq!(start.midpoint_between(pos(room, 15, 25)), pos(room, 13, 18)); 103 | assert_eq!(start.midpoint_between(pos(room, 9, 10)), pos(room, 9, 10)); 104 | assert_eq!(start.midpoint_between(pos(room, 7, 10)), pos(room, 8, 10)); 105 | assert_eq!(start.midpoint_between(pos(room, 1, 3)), pos(room, 5, 6)); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/local/position/game_methods.rs: -------------------------------------------------------------------------------- 1 | //! Game method implementations on `Position` 2 | use js_sys::{JsString, Object}; 3 | use wasm_bindgen::prelude::*; 4 | 5 | use crate::{ 6 | constants::{ 7 | look::{LookConstant, LookResult}, 8 | Color, ErrorCode, FindConstant, StructureType, 9 | }, 10 | enums::action_error_codes::{ 11 | RoomPositionCreateConstructionSiteErrorCode, RoomPositionCreateFlagErrorCode, 12 | }, 13 | local::{RoomCoordinate, RoomName}, 14 | objects::{CostMatrix, FindPathOptions, Path, RoomPosition}, 15 | pathfinder::RoomCostResult, 16 | prelude::*, 17 | }; 18 | 19 | use super::Position; 20 | 21 | impl Position { 22 | /// Creates a [`ConstructionSite`] at this position. If it's a 23 | /// [`StructureSpawn`], a name can optionally be assigned for the structure. 24 | /// 25 | /// [Screeps documentation](https://docs.screeps.com/api/#RoomPosition.createConstructionSite) 26 | /// 27 | /// [`ConstructionSite`]: crate::objects::ConstructionSite 28 | /// [`StructureSpawn`]: crate::objects::StructureSpawn 29 | #[inline] 30 | pub fn create_construction_site( 31 | self, 32 | ty: StructureType, 33 | name: Option<&JsString>, 34 | ) -> Result<(), RoomPositionCreateConstructionSiteErrorCode> { 35 | RoomPosition::from(self).create_construction_site(ty, name) 36 | } 37 | 38 | /// Creates a [`Flag`] at this position. If successful, returns the name of 39 | /// the created flag. 40 | /// 41 | /// [Screeps documentation](https://docs.screeps.com/api/#RoomPosition.createFlag) 42 | /// 43 | /// [`Flag`]: crate::objects::Flag 44 | #[inline] 45 | pub fn create_flag( 46 | self, 47 | name: Option<&JsString>, 48 | color: Option, 49 | secondary_color: Option, 50 | ) -> Result { 51 | RoomPosition::from(self).create_flag(name, color, secondary_color) 52 | } 53 | 54 | // todo typed options and version that allows passing target roomobjects 55 | /// Find the closest object by path among a list of objects, or use 56 | /// a [`find` constant] to search for all objects of that type in the room. 57 | /// 58 | /// [Screeps documentation](https://docs.screeps.com/api/#RoomPosition.findClosestByPath) 59 | /// 60 | /// [`find` constant]: crate::constants::find 61 | #[inline] 62 | pub fn find_closest_by_path(self, ty: T, options: Option<&Object>) -> Option 63 | where 64 | T: FindConstant, 65 | ::Item: From, 66 | { 67 | RoomPosition::from(self).find_closest_by_path(ty, options) 68 | } 69 | 70 | // todo version for passing target roomobjects 71 | /// Find the closest object by range among a list of objects, or use 72 | /// a [`find` constant] to search for all objects of that type in the room. 73 | /// Will not work for objects in other rooms. 74 | /// 75 | /// [Screeps documentation](https://docs.screeps.com/api/#RoomPosition.findClosestByRange) 76 | /// 77 | /// [`find` constant]: crate::constants::find 78 | #[inline] 79 | pub fn find_closest_by_range(self, ty: T) -> Option 80 | where 81 | T: FindConstant, 82 | { 83 | RoomPosition::from(self).find_closest_by_range(ty) 84 | } 85 | 86 | // todo version for passing target roomobjects 87 | /// Find all relevant objects within a certain range among a list of 88 | /// objects, or use a [`find` constant] to search all objects of that type 89 | /// in the room. 90 | /// 91 | /// [Screeps documentation](https://docs.screeps.com/api/#RoomPosition.findInRange) 92 | /// 93 | /// [`find` constant]: crate::constants::find 94 | #[inline] 95 | pub fn find_in_range(self, ty: T, range: u8) -> Vec 96 | where 97 | T: FindConstant, 98 | { 99 | RoomPosition::from(self).find_in_range(ty, range) 100 | } 101 | 102 | /// Find a path from this position to a position or room object, with an 103 | /// optional options object 104 | /// 105 | /// [Screeps documentation](https://docs.screeps.com/api/#RoomPosition.findPathTo) 106 | #[inline] 107 | pub fn find_path_to(&self, target: &T, options: Option>) -> Path 108 | where 109 | T: HasPosition, 110 | F: FnMut(RoomName, CostMatrix) -> R, 111 | R: RoomCostResult, 112 | { 113 | RoomPosition::from(self).find_path_to(target, options) 114 | } 115 | 116 | /// Find a path from this position to the given coordinates in the same 117 | /// room, with an optional options object. 118 | /// 119 | /// [Screeps documentation](https://docs.screeps.com/api/#RoomPosition.findPathTo) 120 | #[inline] 121 | pub fn find_path_to_xy( 122 | self, 123 | x: RoomCoordinate, 124 | y: RoomCoordinate, 125 | options: Option>, 126 | ) -> Path 127 | where 128 | F: FnMut(RoomName, CostMatrix) -> R, 129 | R: RoomCostResult, 130 | { 131 | RoomPosition::from(self).find_path_to_xy(x, y, options) 132 | } 133 | 134 | /// Get all objects at this position. Will fail if the position is in a room 135 | /// that's not visible during the current tick. 136 | /// 137 | /// [Screeps documentation](https://docs.screeps.com/api/#RoomPosition.look) 138 | #[inline] 139 | pub fn look(self) -> Result, ErrorCode> { 140 | RoomPosition::from(self).look() 141 | } 142 | 143 | /// Get all objects of a given type at this position, if any. Will fail if 144 | /// the position is in a room that's not visible during the current tick. 145 | /// 146 | /// [Screeps documentation](https://docs.screeps.com/api/#RoomPosition.lookFor) 147 | #[inline] 148 | pub fn look_for(self, ty: T) -> Result, ErrorCode> 149 | where 150 | T: LookConstant, 151 | { 152 | RoomPosition::from(self).look_for(ty) 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/local/position/pair_utils.rs: -------------------------------------------------------------------------------- 1 | //! Utilities for working with Position and coordinate pairs 2 | use super::Position; 3 | use crate::local::RoomXY; 4 | 5 | macro_rules! int_pair_from_position { 6 | ($($num_type:ty),+) => {$( 7 | impl From for ($num_type, $num_type) { 8 | #[inline] 9 | fn from(pos: Position) -> Self { 10 | (u8::from(pos.x()) as $num_type, u8::from(pos.y()) as $num_type) 11 | } 12 | } 13 | )+} 14 | } 15 | 16 | int_pair_from_position!(u8, u16, u32, u64, i8, i16, i32, i64); 17 | 18 | impl Position { 19 | /// Returns this position's in-room coordinates as a pair of unsigned 20 | /// integers. 21 | #[inline] 22 | pub fn coords(&self) -> (u8, u8) { 23 | (self.x().into(), self.y().into()) 24 | } 25 | 26 | /// Returns this position's in-room coordinates as a pair of signed 27 | /// integers. 28 | #[inline] 29 | pub fn coords_signed(&self) -> (i8, i8) { 30 | (u8::from(self.x()) as i8, u8::from(self.y()) as i8) 31 | } 32 | } 33 | 34 | impl From for RoomXY { 35 | #[inline] 36 | fn from(pos: Position) -> RoomXY { 37 | RoomXY { 38 | x: pos.x(), 39 | y: pos.y(), 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/local/room_xy/extra_math.rs: -------------------------------------------------------------------------------- 1 | //! Math utilities on `RoomXY` which don't exist in the Screeps API 2 | //! proper. 3 | 4 | use std::ops::{Add, Sub}; 5 | 6 | use super::RoomXY; 7 | use crate::constants::Direction; 8 | 9 | impl RoomXY { 10 | /// Returns a new position offset from this position by the specified x 11 | /// coords and y coords. 12 | /// 13 | /// Unlike [`Position::offset`], this function operates on room coordinates, 14 | /// and will panic if the new position overflows the room. 15 | /// 16 | /// To return a new position rather than modifying in place, use `pos + (x, 17 | /// y)`. See the implementation of `Add<(i8, i8)>` for 18 | /// [`RoomXY`] further down on this page. 19 | /// 20 | /// # Panics 21 | /// 22 | /// Will panic if the new position overflows the room. 23 | /// 24 | /// # Example 25 | /// 26 | /// ``` 27 | /// # use screeps::RoomXY; 28 | /// 29 | /// let mut pos = RoomXY::checked_new(21, 21).unwrap(); 30 | /// pos.offset(5, 5); 31 | /// assert_eq!(pos, RoomXY::checked_new(26, 26).unwrap()); 32 | /// 33 | /// let mut pos = RoomXY::checked_new(21, 21).unwrap(); 34 | /// pos.offset(-5, 5); 35 | /// assert_eq!(pos, RoomXY::checked_new(16, 26).unwrap()); 36 | /// ``` 37 | /// 38 | /// [`Position::offset`]: crate::local::Position::offset 39 | #[inline] 40 | #[track_caller] 41 | pub fn offset(&mut self, x: i8, y: i8) { 42 | *self = *self + (x, y); 43 | } 44 | } 45 | 46 | impl Add<(i8, i8)> for RoomXY { 47 | type Output = RoomXY; 48 | 49 | /// Adds an `(x, y)` pair to this position's coordinates. 50 | /// 51 | /// # Panics 52 | /// 53 | /// Will panic if the new position is outside standard room bounds. 54 | /// 55 | /// # Example 56 | /// 57 | /// ``` 58 | /// # use screeps::RoomXY; 59 | /// 60 | /// let pos1 = RoomXY::checked_new(42, 42).unwrap(); 61 | /// let pos2 = pos1 + (7, 7); 62 | /// assert_eq!(pos2, RoomXY::checked_new(49, 49).unwrap()); 63 | /// ``` 64 | #[inline] 65 | #[track_caller] 66 | fn add(self, (x, y): (i8, i8)) -> Self { 67 | self.checked_add((x, y)).unwrap() 68 | } 69 | } 70 | 71 | impl Add for RoomXY { 72 | type Output = RoomXY; 73 | 74 | /// Adds a `Direction` to this position's coordinates. 75 | /// 76 | /// # Panics 77 | /// 78 | /// Will panic if the new position is outside standard room bounds. 79 | /// 80 | /// # Example 81 | /// 82 | /// ``` 83 | /// # use screeps::{RoomXY, Direction}; 84 | /// 85 | /// let pos1 = RoomXY::checked_new(49, 40).unwrap(); 86 | /// let pos2 = pos1 + Direction::Top; 87 | /// assert_eq!(pos2, RoomXY::checked_new(49, 39).unwrap()); 88 | /// ``` 89 | #[inline] 90 | #[track_caller] 91 | fn add(self, direction: Direction) -> Self { 92 | self.checked_add_direction(direction).unwrap() 93 | } 94 | } 95 | 96 | impl Sub<(i8, i8)> for RoomXY { 97 | type Output = RoomXY; 98 | 99 | /// Subtracts an `(x, y)` pair from this position's coordinates. 100 | /// 101 | /// # Panics 102 | /// 103 | /// Will panic if the new position is outside standard room bounds. 104 | /// 105 | /// # Example 106 | /// 107 | /// ``` 108 | /// # use screeps::RoomXY; 109 | /// 110 | /// let pos1 = RoomXY::checked_new(49, 40).unwrap(); 111 | /// let pos2 = pos1 - (49, 0); 112 | /// assert_eq!(pos2, RoomXY::checked_new(0, 40).unwrap()); 113 | /// ``` 114 | #[inline] 115 | #[track_caller] 116 | fn sub(self, (x, y): (i8, i8)) -> Self { 117 | self.checked_add((-x, -y)).unwrap() 118 | } 119 | } 120 | 121 | impl Sub for RoomXY { 122 | type Output = RoomXY; 123 | 124 | /// Subtracts a `Direction` from this position's coordinates. 125 | /// 126 | /// # Panics 127 | /// 128 | /// Will panic if the new position is outside standard room bounds. 129 | /// 130 | /// # Example 131 | /// 132 | /// ``` 133 | /// # use screeps::{RoomXY, Direction}; 134 | /// 135 | /// let pos1 = RoomXY::checked_new(49, 40).unwrap(); 136 | /// let pos2 = pos1 - Direction::Top; 137 | /// assert_eq!(pos2, RoomXY::checked_new(49, 41).unwrap()); 138 | /// ``` 139 | #[inline] 140 | fn sub(self, direction: Direction) -> Self { 141 | self.checked_add_direction(-direction).unwrap() 142 | } 143 | } 144 | 145 | impl Sub for RoomXY { 146 | type Output = (i8, i8); 147 | 148 | /// Subtracts the other position from this one, extracting the 149 | /// difference as the output. 150 | /// 151 | /// # Example 152 | /// 153 | /// ``` 154 | /// # use screeps::RoomXY; 155 | /// 156 | /// let pos1 = RoomXY::checked_new(40, 40).unwrap(); 157 | /// let pos2 = RoomXY::checked_new(0, 20).unwrap(); 158 | /// assert_eq!(pos1 - pos2, (40, 20)); 159 | /// 160 | /// let pos3 = RoomXY::checked_new(45, 45).unwrap(); 161 | /// assert_eq!(pos1 - pos3, (-5, -5)); 162 | /// ``` 163 | #[inline] 164 | fn sub(self, other: RoomXY) -> (i8, i8) { 165 | let dx = self.x.u8() as i8 - other.x.u8() as i8; 166 | let dy = self.y.u8() as i8 - other.y.u8() as i8; 167 | (dx, dy) 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/local/room_xy/game_math.rs: -------------------------------------------------------------------------------- 1 | //! Utilities for doing math on [`RoomXY`]s which are present in the 2 | //! JavaScript API. 3 | 4 | use crate::constants::Direction; 5 | 6 | use super::RoomXY; 7 | 8 | impl RoomXY { 9 | /// Gets linear direction to the specified position. 10 | /// 11 | /// Note that this chooses between `Top`/`Bottom`/`Left`/`Right` and 12 | /// `TopLeft`/`TopRight`/`BottomLeft`/`BottomRight` by the magnitude in both 13 | /// directions. For instance, [`Direction::Top`] can be returned even 14 | /// if the target has a slightly different `x` coordinate. 15 | pub fn get_direction_to(self, target: RoomXY) -> Option { 16 | // Logic copied from https://github.com/screeps/engine/blob/020ba168a1fde9a8072f9f1c329d5c0be8b440d7/src/utils.js#L73-L107 17 | let (dx, dy) = target - self; 18 | if dx.abs() > dy.abs() * 2 { 19 | if dx > 0 { 20 | Some(Direction::Right) 21 | } else { 22 | Some(Direction::Left) 23 | } 24 | } else if dy.abs() > dx.abs() * 2 { 25 | if dy > 0 { 26 | Some(Direction::Bottom) 27 | } else { 28 | Some(Direction::Top) 29 | } 30 | } else if dx > 0 && dy > 0 { 31 | Some(Direction::BottomRight) 32 | } else if dx > 0 && dy < 0 { 33 | Some(Direction::TopRight) 34 | } else if dx < 0 && dy > 0 { 35 | Some(Direction::BottomLeft) 36 | } else if dx < 0 && dy < 0 { 37 | Some(Direction::TopLeft) 38 | } else { 39 | None 40 | } 41 | } 42 | 43 | /// Gets linear range to the specified position. 44 | /// 45 | /// Linear range (also called Chebyshev Distance) is an alternate 46 | /// calculation of distance, calculated as the greater of the distance along 47 | /// the x axis or the y axis. Most calculations in Screeps use this distance 48 | /// metric. For more information see [Chebeshev Distance](https://en.wikipedia.org/wiki/Chebyshev_distance). 49 | /// 50 | /// # Examples 51 | /// ```rust 52 | /// # use screeps::RoomXY; 53 | /// let pos_1 = RoomXY::checked_new(5, 10).unwrap(); 54 | /// let pos_2 = RoomXY::checked_new(8, 15).unwrap(); 55 | /// // The differences are 3 along the X axis and 5 along the Y axis 56 | /// // so the linear distance is 5. 57 | /// assert_eq!(pos_1.get_range_to(pos_2), 5); 58 | /// ``` 59 | #[doc(alias = "distance")] 60 | #[inline] 61 | pub fn get_range_to(self, target: RoomXY) -> u8 { 62 | let (dx, dy) = self - target; 63 | dx.unsigned_abs().max(dy.unsigned_abs()) 64 | } 65 | 66 | /// Checks whether this position is in the given range of another position. 67 | /// 68 | /// Linear range (also called Chebyshev Distance) is an alternate 69 | /// calculation of distance, calculated as the greater of the distance along 70 | /// the x axis or the y axis. Most calculations in Screeps use this distance 71 | /// metric. For more information see [Chebeshev Distance](https://en.wikipedia.org/wiki/Chebyshev_distance). 72 | /// 73 | /// # Examples 74 | /// ```rust 75 | /// # use screeps::RoomXY; 76 | /// let pos_1 = RoomXY::checked_new(5, 10).unwrap(); 77 | /// let pos_2 = RoomXY::checked_new(8, 10).unwrap(); 78 | /// 79 | /// // The differences are 3 along the X axis and 0 along the Y axis 80 | /// // so the linear distance is 3. 81 | /// assert_eq!(pos_1.in_range_to(pos_2, 5), true); 82 | /// 83 | /// let pos_3 = RoomXY::checked_new(8, 15).unwrap(); 84 | /// 85 | /// // The differences are 3 along the X axis and 5 along the Y axis 86 | /// // so the linear distance is 5. 87 | /// // `in_range_to` returns true if the linear distance is equal to the range 88 | /// assert_eq!(pos_1.in_range_to(pos_3, 5), true); 89 | /// 90 | /// let pos_4 = RoomXY::checked_new(20, 20).unwrap(); 91 | /// // The differences are 15 along the X axis and 10 along the Y axis 92 | /// // so the linear distance is 15. 93 | /// assert_eq!(pos_1.in_range_to(pos_4, 5), false); 94 | /// assert_eq!(pos_1.in_range_to(pos_4, 10), false); 95 | /// assert_eq!(pos_1.in_range_to(pos_4, 15), true); 96 | /// ``` 97 | #[doc(alias = "distance")] 98 | #[inline] 99 | pub fn in_range_to(self, target: RoomXY, range: u8) -> bool { 100 | self.get_range_to(target) <= range 101 | } 102 | 103 | /// Checks whether this position is the same as the specified position. 104 | /// 105 | /// # Examples 106 | /// ```rust 107 | /// # use screeps::RoomXY; 108 | /// let pos_1 = RoomXY::checked_new(5, 10).unwrap(); 109 | /// let pos_2 = RoomXY::checked_new(5, 10).unwrap(); 110 | /// let pos_3 = RoomXY::checked_new(4, 9).unwrap(); 111 | /// 112 | /// assert_eq!(pos_1.is_equal_to(pos_2), true); 113 | /// assert_eq!(pos_1.is_equal_to(pos_3), false); 114 | /// ``` 115 | #[inline] 116 | pub fn is_equal_to(self, target: RoomXY) -> bool { 117 | self == target 118 | } 119 | 120 | /// True if the range from this position to the target is at most 1. 121 | /// 122 | /// # Examples 123 | /// ```rust 124 | /// # use screeps::RoomXY; 125 | /// let pos_1 = RoomXY::checked_new(5, 10).unwrap(); 126 | /// let pos_2 = RoomXY::checked_new(6, 10).unwrap(); 127 | /// let pos_3 = RoomXY::checked_new(4, 9).unwrap(); 128 | /// let pos_4 = RoomXY::checked_new(20, 20).unwrap(); 129 | /// 130 | /// assert_eq!(pos_1.is_near_to(pos_2), true); 131 | /// assert_eq!(pos_1.is_near_to(pos_3), true); 132 | /// assert_eq!(pos_1.is_near_to(pos_4), false); 133 | /// ``` 134 | #[inline] 135 | pub fn is_near_to(self, target: RoomXY) -> bool { 136 | (u8::from(self.x) as i32 - u8::from(target.x) as i32).abs() <= 1 137 | && (u8::from(self.y) as i32 - u8::from(target.y) as i32).abs() <= 1 138 | } 139 | } 140 | 141 | #[cfg(test)] 142 | mod test { 143 | use crate::{Direction, RoomXY}; 144 | 145 | #[test] 146 | fn test_direction_to() { 147 | let a = RoomXY::checked_new(1, 1).unwrap(); 148 | let b = RoomXY::checked_new(2, 2).unwrap(); 149 | assert_eq!(a.get_direction_to(b), Some(Direction::BottomRight)); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/local/terrain.rs: -------------------------------------------------------------------------------- 1 | use std::mem::MaybeUninit; 2 | 3 | use js_sys::Uint8Array; 4 | 5 | use crate::{ 6 | constants::{Terrain, ROOM_AREA}, 7 | objects::RoomTerrain, 8 | }; 9 | 10 | use super::RoomXY; 11 | 12 | #[derive(Debug, Clone)] 13 | pub struct LocalRoomTerrain { 14 | bits: Box<[u8; ROOM_AREA]>, 15 | } 16 | 17 | /// A matrix representing the terrain of a room, stored in Rust memory. 18 | /// 19 | /// Use [`RoomTerrain`] if data stored in JavaScript memory is preferred. 20 | impl LocalRoomTerrain { 21 | /// Gets the terrain at the specified position in this room. 22 | pub fn get_xy(&self, xy: RoomXY) -> Terrain { 23 | let byte = self.bits[xy.y][xy.x]; 24 | // not using Terrain::from_u8() because `0b11` value, wall+swamp, happens 25 | // in commonly used server environments (notably the private server default 26 | // map), and is special-cased in the engine code; we special-case it here 27 | match byte & 0b11 { 28 | 0b00 => Terrain::Plain, 29 | 0b01 | 0b11 => Terrain::Wall, 30 | 0b10 => Terrain::Swamp, 31 | // Should be optimized out 32 | _ => unreachable!("all combinations of 2 bits are covered"), 33 | } 34 | } 35 | 36 | /// Creates a `LocalRoomTerrain` from the bytes that correspond to the 37 | /// room's terrain data. 38 | /// 39 | /// This is like the `RoomTerrain` type but performs all operations on data 40 | /// stored in wasm memory. Each byte in the array corresponds to the value 41 | /// of the `Terrain` at the given position. 42 | /// 43 | /// The bytes are in row-major order - that is they start at the top left, 44 | /// then move to the top right, and then start at the left of the next row. 45 | /// This is different from `LocalCostMatrix`, which is column-major. 46 | pub fn new_from_bits(bits: Box<[u8; ROOM_AREA]>) -> Self { 47 | Self { bits } 48 | } 49 | } 50 | 51 | impl From for LocalRoomTerrain { 52 | fn from(terrain: RoomTerrain) -> LocalRoomTerrain { 53 | // create an uninitialized array of the correct size 54 | let mut data: Box<[MaybeUninit; ROOM_AREA]> = 55 | Box::new([MaybeUninit::uninit(); ROOM_AREA]); 56 | // create a Uint8Array mapped to the same point in wasm linear memory as our 57 | // uninitialized boxed array 58 | 59 | // SAFETY: if any allocations happen in rust, this buffer will be detached from 60 | // wasm memory and no longer writable - we use it immediately then discard it to 61 | // avoid this 62 | let js_buffer = 63 | unsafe { Uint8Array::view_mut_raw(data.as_mut_ptr() as *mut u8, ROOM_AREA) }; 64 | 65 | // copy the terrain buffer into the memory backing the Uint8Array - this is the 66 | // boxed array, so this initializes it 67 | terrain 68 | .get_raw_buffer_to_array(&js_buffer) 69 | .expect("terrain data to copy"); 70 | // data copied - explicitly drop the Uint8Array, so there's no chance it's used 71 | // again 72 | drop(js_buffer); 73 | // we've got the data in our boxed array, change to the needed type 74 | // SAFETY: `Box` has the same layout for sized types. `MaybeUninit` has the 75 | // same layout as `u8`. The arrays are the same size. The `MaybeUninit` are 76 | // all initialized because JS wrote to them. 77 | LocalRoomTerrain::new_from_bits(unsafe { 78 | std::mem::transmute::; ROOM_AREA]>, Box<[u8; ROOM_AREA]>>(data) 79 | }) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/memory.rs: -------------------------------------------------------------------------------- 1 | //! Interface with Screeps' `Memory` global variable 2 | //! 3 | //! If you wish to access the `Memory` object stored in the javascript heap 4 | //! which has its encoding, storage, and decoding from JSON handled by the game, 5 | //! this allows accessing a reference to the [`ROOT`] of Memory object. Game 6 | //! objects which have an automatic memory accessor can access references to 7 | //! their respective parts of the object, eg. 8 | //! [`Creep::memory`]/[`StructureSpawn::memory`]. You can work with these 9 | //! objects using [`js_sys::Reflect`], or by converting the value into a 10 | //! wasm_bindgen compatible type with the properly access functions you need via 11 | //! [`wasm_bindgen::JsCast`]. 12 | //! 13 | //! [`ROOT`]: crate::memory::ROOT 14 | //! [`Creep::memory`]: crate::objects::Creep::memory 15 | //! [`StructureSpawn::memory`]: crate::objects::StructureSpawn::memory 16 | use js_sys::Object; 17 | use wasm_bindgen::prelude::*; 18 | 19 | #[wasm_bindgen] 20 | extern "C" { 21 | /// Get a reference to the `Memory` global object. Note that this object 22 | /// gets recreated each tick by the Screeps engine, so references from it 23 | /// should not be held beyond the current tick. 24 | #[wasm_bindgen(js_name = Memory)] 25 | pub static ROOT: Object; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/objects.rs: -------------------------------------------------------------------------------- 1 | //! Screeps object wrappers. 2 | //! 3 | //! Objects types that inherit [`RoomObject`] represent game objects with are 4 | //! valid to be used only during the current tick; reading or writing a 'stale' 5 | //! game object from a past tick will result in undefined behavior. 6 | mod impls; 7 | 8 | pub use event::*; 9 | pub use game_types::*; 10 | pub use input::*; 11 | pub use output::*; 12 | pub use room_objects::*; 13 | pub use visual::*; 14 | 15 | /// Object wrappers representing data retrieved from room event logs. 16 | pub mod event { 17 | pub use super::impls::{ 18 | AttackEvent, AttackType, BuildEvent, Event, EventType, ExitEvent, HarvestEvent, HealEvent, 19 | HealType, ObjectDestroyedEvent, PowerEvent, RepairEvent, ReserveControllerEvent, 20 | TransferEvent, UpgradeControllerEvent, 21 | }; 22 | } 23 | 24 | /// Object wrappers for game types that are not room objects (are safe to use 25 | /// in future ticks). 26 | mod game_types { 27 | pub use super::impls::{CostMatrix, RoomPosition, RoomTerrain}; 28 | } 29 | 30 | /// Object wrappers for simple javascript objects with known properties sent to 31 | /// game functions. 32 | pub mod input { 33 | pub use super::impls::{FindPathOptions, JsFindPathOptions, MoveToOptions}; 34 | } 35 | 36 | /// Object wrappers for simple javascript objects with known properties returned 37 | /// by game functions. 38 | pub mod output { 39 | pub use super::impls::{ 40 | AccountPowerCreep, BodyPart, Effect, InterShardPortalDestination, Owner, Path, 41 | PortalDestination, PowerInfo, Reservation, Sign, SpawnOptions, Step, 42 | }; 43 | } 44 | 45 | /// Object wrappers for room objects. 46 | mod room_objects { 47 | pub use super::impls::{ 48 | ConstructionSite, Creep, Deposit, Flag, Mineral, Nuke, OwnedStructure, PowerCreep, 49 | Resource, Room, RoomObject, Ruin, Source, Spawning, Store, Structure, StructureContainer, 50 | StructureController, StructureExtension, StructureExtractor, StructureFactory, 51 | StructureInvaderCore, StructureKeeperLair, StructureLab, StructureLink, StructureNuker, 52 | StructureObserver, StructurePortal, StructurePowerBank, StructurePowerSpawn, 53 | StructureRampart, StructureRoad, StructureSpawn, StructureStorage, StructureTerminal, 54 | StructureTower, StructureWall, Tombstone, 55 | }; 56 | 57 | #[cfg(feature = "seasonal-season-1")] 58 | pub use super::impls::{ScoreCollector, ScoreContainer}; 59 | 60 | #[cfg(feature = "seasonal-season-2")] 61 | pub use super::impls::{SymbolContainer, SymbolDecoder}; 62 | 63 | #[cfg(feature = "seasonal-season-5")] 64 | pub use super::impls::Reactor; 65 | } 66 | 67 | /// Object wrappers allowing drawing of shapes in rooms or on the map in the 68 | /// game world. 69 | pub mod visual { 70 | pub use super::impls::{ 71 | CircleStyle, FontStyle, LineDrawStyle, LineStyle, MapFontStyle, MapFontVariant, 72 | MapTextStyle, MapVisual, MapVisualShape, PolyStyle, RectStyle, RoomVisual, TextAlign, 73 | TextStyle, Visual, 74 | }; 75 | } 76 | -------------------------------------------------------------------------------- /src/objects/impls.rs: -------------------------------------------------------------------------------- 1 | mod construction_site; 2 | mod cost_matrix; 3 | mod creep; 4 | mod creep_shared; 5 | mod deposit; 6 | mod flag; 7 | mod map_visual; 8 | mod mineral; 9 | mod nuke; 10 | mod owned_structure; 11 | mod power_creep; 12 | mod resource; 13 | mod room; 14 | mod room_object; 15 | mod room_position; 16 | mod room_terrain; 17 | mod room_visual; 18 | mod ruin; 19 | mod source; 20 | mod store; 21 | mod structure; 22 | mod structure_container; 23 | mod structure_controller; 24 | mod structure_extension; 25 | mod structure_extractor; 26 | mod structure_factory; 27 | mod structure_invader_core; 28 | mod structure_keeper_lair; 29 | mod structure_lab; 30 | mod structure_link; 31 | mod structure_nuker; 32 | mod structure_observer; 33 | mod structure_portal; 34 | mod structure_power_bank; 35 | mod structure_power_spawn; 36 | mod structure_rampart; 37 | mod structure_road; 38 | mod structure_spawn; 39 | mod structure_storage; 40 | mod structure_terminal; 41 | mod structure_tower; 42 | mod structure_wall; 43 | mod tombstone; 44 | 45 | #[cfg(feature = "seasonal-season-1")] 46 | mod score_collector; 47 | #[cfg(feature = "seasonal-season-1")] 48 | mod score_container; 49 | 50 | #[cfg(feature = "seasonal-season-2")] 51 | mod symbol_container; 52 | #[cfg(feature = "seasonal-season-2")] 53 | mod symbol_decoder; 54 | 55 | #[cfg(feature = "seasonal-season-5")] 56 | mod reactor; 57 | 58 | pub use self::{ 59 | construction_site::ConstructionSite, 60 | cost_matrix::CostMatrix, 61 | creep::{BodyPart, Creep}, 62 | creep_shared::MoveToOptions, 63 | deposit::Deposit, 64 | flag::Flag, 65 | mineral::Mineral, 66 | nuke::Nuke, 67 | owned_structure::{OwnedStructure, Owner}, 68 | power_creep::{AccountPowerCreep, PowerCreep, PowerInfo}, 69 | resource::Resource, 70 | room::{ 71 | AttackEvent, AttackType, BuildEvent, Event, EventType, ExitEvent, FindPathOptions, 72 | HarvestEvent, HealEvent, HealType, JsFindPathOptions, ObjectDestroyedEvent, Path, 73 | PowerEvent, RepairEvent, ReserveControllerEvent, Room, Step, TransferEvent, 74 | UpgradeControllerEvent, 75 | }, 76 | room_object::{Effect, RoomObject}, 77 | room_position::RoomPosition, 78 | room_terrain::RoomTerrain, 79 | ruin::Ruin, 80 | source::Source, 81 | store::Store, 82 | structure::Structure, 83 | structure_container::StructureContainer, 84 | structure_controller::{Reservation, Sign, StructureController}, 85 | structure_extension::StructureExtension, 86 | structure_extractor::StructureExtractor, 87 | structure_factory::StructureFactory, 88 | structure_invader_core::StructureInvaderCore, 89 | structure_keeper_lair::StructureKeeperLair, 90 | structure_lab::StructureLab, 91 | structure_link::StructureLink, 92 | structure_nuker::StructureNuker, 93 | structure_observer::StructureObserver, 94 | structure_portal::{InterShardPortalDestination, PortalDestination, StructurePortal}, 95 | structure_power_bank::StructurePowerBank, 96 | structure_power_spawn::StructurePowerSpawn, 97 | structure_rampart::StructureRampart, 98 | structure_road::StructureRoad, 99 | structure_spawn::{SpawnOptions, Spawning, StructureSpawn}, 100 | structure_storage::StructureStorage, 101 | structure_terminal::StructureTerminal, 102 | structure_tower::StructureTower, 103 | structure_wall::StructureWall, 104 | tombstone::Tombstone, 105 | }; 106 | 107 | pub use self::room_visual::{ 108 | CircleStyle, FontStyle, LineDrawStyle, LineStyle, PolyStyle, RectStyle, RoomVisual, TextAlign, 109 | TextStyle, Visual, 110 | }; 111 | 112 | pub use self::map_visual::{MapFontStyle, MapFontVariant, MapTextStyle, MapVisual, MapVisualShape}; 113 | 114 | #[cfg(feature = "seasonal-season-1")] 115 | pub use self::{score_collector::ScoreCollector, score_container::ScoreContainer}; 116 | 117 | #[cfg(feature = "seasonal-season-2")] 118 | pub use self::{symbol_container::SymbolContainer, symbol_decoder::SymbolDecoder}; 119 | 120 | #[cfg(feature = "seasonal-season-5")] 121 | pub use self::reactor::Reactor; 122 | -------------------------------------------------------------------------------- /src/objects/impls/construction_site.rs: -------------------------------------------------------------------------------- 1 | use js_sys::JsString; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{ 5 | constants::StructureType, 6 | enums::action_error_codes::construction_site::*, 7 | objects::{Owner, RoomObject}, 8 | prelude::*, 9 | }; 10 | 11 | #[wasm_bindgen] 12 | extern "C" { 13 | /// A [`ConstructionSite`] which is an object representing a structure under 14 | /// construction. 15 | /// 16 | /// [Screeps documentation](https://docs.screeps.com/api/#ConstructionSite) 17 | #[wasm_bindgen(extends = RoomObject)] 18 | #[derive(Clone, Debug)] 19 | pub type ConstructionSite; 20 | 21 | #[wasm_bindgen(method, getter = id)] 22 | fn id_internal(this: &ConstructionSite) -> Option; 23 | 24 | #[wasm_bindgen(method, getter = my)] 25 | fn my_internal(this: &ConstructionSite) -> bool; 26 | 27 | #[wasm_bindgen(method, getter = owner)] 28 | fn owner_internal(this: &ConstructionSite) -> Owner; 29 | 30 | #[wasm_bindgen(method, getter = progress)] 31 | fn progress_internal(this: &ConstructionSite) -> u32; 32 | 33 | #[wasm_bindgen(method, getter = progressTotal)] 34 | fn progress_total_internal(this: &ConstructionSite) -> u32; 35 | 36 | #[wasm_bindgen(method, getter = structureType)] 37 | fn structure_type_internal(this: &ConstructionSite) -> StructureType; 38 | 39 | #[wasm_bindgen(method, js_name = remove)] 40 | fn remove_internal(this: &ConstructionSite) -> i8; 41 | } 42 | 43 | impl ConstructionSite { 44 | /// Whether you own the [`ConstructionSite`]. 45 | /// 46 | /// [Screeps documentation](https://docs.screeps.com/api/#ConstructionSite.my) 47 | pub fn my(&self) -> bool { 48 | self.my_internal() 49 | } 50 | 51 | /// The [`Owner`] of this construction site, which contains the owner's 52 | /// username. 53 | /// 54 | /// [Screeps documentation](https://docs.screeps.com/api/#ConstructionSite.owner) 55 | pub fn owner(&self) -> Owner { 56 | self.owner_internal() 57 | } 58 | 59 | /// The current progress toward completion of the structure being built. 60 | /// 61 | /// [Screeps documentation](https://docs.screeps.com/api/#ConstructionSite.progress) 62 | pub fn progress(&self) -> u32 { 63 | self.progress_internal() 64 | } 65 | 66 | /// The total progess toward constuction progress needed for the structure 67 | /// to be completed. 68 | /// 69 | /// [Screeps documentation](https://docs.screeps.com/api/#ConstructionSite.progressTotal) 70 | pub fn progress_total(&self) -> u32 { 71 | self.progress_total_internal() 72 | } 73 | 74 | /// The type of structure being constructed. 75 | /// 76 | /// [Screeps documentation](https://docs.screeps.com/api/#Structure.structureType) 77 | pub fn structure_type(&self) -> StructureType { 78 | self.structure_type_internal() 79 | } 80 | 81 | /// Remove the [`ConstructionSite`]. 82 | /// 83 | /// [Screeps documentation](https://docs.screeps.com/api/#ConstructionSite.remove) 84 | pub fn remove(&self) -> Result<(), ConstructionSiteRemoveErrorCode> { 85 | ConstructionSiteRemoveErrorCode::result_from_i8(self.remove_internal()) 86 | } 87 | } 88 | 89 | impl MaybeHasId for ConstructionSite { 90 | /// The Object ID of the [`ConstructionSite`], or `None` if it was created 91 | /// this tick. 92 | /// 93 | /// [Screeps documentation](https://docs.screeps.com/api/#ConstructionSite.id) 94 | fn try_js_raw_id(&self) -> Option { 95 | self.id_internal() 96 | } 97 | } 98 | 99 | impl JsCollectionFromValue for ConstructionSite { 100 | fn from_value(val: JsValue) -> Self { 101 | val.unchecked_into() 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/objects/impls/cost_matrix.rs: -------------------------------------------------------------------------------- 1 | use js_sys::{Array, Object, Uint8Array}; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{ 5 | local::{LocalCostMatrix, RoomXY}, 6 | prototypes::COST_MATRIX_PROTOTYPE, 7 | traits::{CostMatrixGet, CostMatrixSet}, 8 | }; 9 | 10 | #[wasm_bindgen] 11 | extern "C" { 12 | /// A reference to a matrix of pathing costs for a room, stored in 13 | /// JavaScript memory. 14 | /// 15 | /// Use [`LocalCostMatrix`] to store and access the same data in Rust 16 | /// memory. 17 | /// 18 | /// [Screeps documentation](https://docs.screeps.com/api/#PathFinder-CostMatrix) 19 | #[wasm_bindgen(js_namespace = PathFinder)] 20 | pub type CostMatrix; 21 | 22 | /// Create a new reference to a CostMatrix, containing 0s in all positions, 23 | /// using the normal constructor. 24 | /// 25 | /// [Screeps documentation](https://docs.screeps.com/api/#PathFinder.CostMatrix.constructor) 26 | #[wasm_bindgen(constructor, js_namespace = PathFinder)] 27 | pub fn new() -> CostMatrix; 28 | 29 | /// Gets a reference to the [`Uint8Array`] underlying this [`CostMatrix`]. 30 | #[wasm_bindgen(method, getter = _bits)] 31 | pub fn get_bits(this: &CostMatrix) -> Uint8Array; 32 | 33 | /// Sets a [`Uint8Array`] to this [`CostMatrix`], overwriting any current 34 | /// contents. 35 | #[wasm_bindgen(method, setter = _bits)] 36 | pub fn set_bits(this: &CostMatrix, arr: &Uint8Array); 37 | 38 | /// Sets a new value for a specific position in this [`CostMatrix`]. 39 | /// 40 | /// [Screeps documentation](https://docs.screeps.com/api/#PathFinder.CostMatrix.set) 41 | #[wasm_bindgen(method)] 42 | pub fn set(this: &CostMatrix, x: u8, y: u8, cost: u8); 43 | 44 | /// Get the value of a specific position in this [`CostMatrix`]. 45 | /// 46 | /// [Screeps documentation](https://docs.screeps.com/api/#PathFinder.CostMatrix.get) 47 | #[wasm_bindgen(method)] 48 | pub fn get(this: &CostMatrix, x: u8, y: u8) -> u8; 49 | 50 | /// Get a new [`CostMatrix`] with data copied from the current one 51 | /// 52 | /// [Screeps documentation](https://docs.screeps.com/api/#PathFinder.CostMatrix.clone) 53 | #[wasm_bindgen(method)] 54 | pub fn clone(this: &CostMatrix) -> CostMatrix; 55 | 56 | /// Get an [`Array`] of numbers representing the [`CostMatrix`] that's 57 | /// appropriate for memory serialization. 58 | /// 59 | /// [Screeps documentation](https://docs.screeps.com/api/#PathFinder.CostMatrix.serialize) 60 | #[wasm_bindgen(method)] 61 | pub fn serialize(this: &CostMatrix) -> Array; 62 | 63 | /// Get a new [`CostMatrix`] using the array representation from 64 | /// [`CostMatrix::serialize`]. 65 | /// 66 | /// [Screeps documentation](https://docs.screeps.com/api/#PathFinder.CostMatrix.deserialize) 67 | #[wasm_bindgen(static_method_of = CostMatrix, js_namespace = PathFinder)] 68 | pub fn deserialize(val: Array) -> CostMatrix; 69 | } 70 | 71 | impl CostMatrix { 72 | /// Create a new [`CostMatrix`], taking a u8 slice with 2500 members such as 73 | /// that returned from [`LocalCostMatrix::get_bits`] which will be copied 74 | /// across the memory boundary. 75 | /// 76 | /// [`LocalCostMatrix::get_bits`]: crate::local::LocalCostMatrix 77 | pub fn new_from_bits(bits: &[u8]) -> CostMatrix { 78 | let matrix = CostMatrix::from(JsValue::from(Object::create(&COST_MATRIX_PROTOTYPE))); 79 | matrix.set_bits(&Uint8Array::from(bits)); 80 | matrix 81 | } 82 | 83 | // todo also a function that takes the unsafe view into wasm linear mem with 84 | // view for a matrix that'll easily go bad 85 | } 86 | 87 | impl From for CostMatrix { 88 | fn from(matrix: LocalCostMatrix) -> Self { 89 | CostMatrix::new_from_bits(matrix.get_bits()) 90 | } 91 | } 92 | 93 | impl CostMatrixSet for CostMatrix { 94 | fn set_xy(&mut self, xy: RoomXY, cost: u8) { 95 | CostMatrix::set(self, xy.x.u8(), xy.y.u8(), cost); 96 | } 97 | } 98 | 99 | impl CostMatrixGet for CostMatrix { 100 | fn get_xy(&mut self, xy: RoomXY) -> u8 { 101 | CostMatrix::get(self, xy.x.u8(), xy.y.u8()) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/objects/impls/deposit.rs: -------------------------------------------------------------------------------- 1 | use js_sys::JsString; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{constants::ResourceType, objects::RoomObject, prelude::*}; 5 | 6 | #[wasm_bindgen] 7 | extern "C" { 8 | /// A [`Deposit`], which can be harvested for resources used in commodities. 9 | /// 10 | /// [Screeps documentation](https://docs.screeps.com/api/#Deposit) 11 | #[wasm_bindgen(extends = RoomObject)] 12 | #[derive(Clone, Debug)] 13 | pub type Deposit; 14 | 15 | /// Ticks until the deposit can be harvested again. 16 | /// 17 | /// [Screeps documentation](https://docs.screeps.com/api/#Deposit.cooldown) 18 | #[wasm_bindgen(method, getter)] 19 | pub fn cooldown(this: &Deposit) -> u32; 20 | 21 | /// Type of resource contained in this deposit. 22 | /// 23 | /// [Screeps documentation](https://docs.screeps.com/api/#Deposit.depositType) 24 | #[wasm_bindgen(method, getter = depositType)] 25 | pub fn deposit_type(this: &Deposit) -> ResourceType; 26 | 27 | /// Object ID of the deposit, which can be used to efficiently fetch a fresh 28 | /// reference to the object on subsequent ticks. 29 | /// 30 | /// [Screeps documentation](https://docs.screeps.com/api/#Deposit.id) 31 | #[wasm_bindgen(method, getter = id)] 32 | fn id_internal(this: &Deposit) -> JsString; 33 | 34 | /// The cooldown caused by the most recent harvest action for this deposit. 35 | /// 36 | /// [Screeps documentation](https://docs.screeps.com/api/#Deposit.lastCooldown) 37 | #[wasm_bindgen(method, getter = lastCooldown)] 38 | pub fn last_cooldown(this: &Deposit) -> u32; 39 | 40 | /// The number of ticks until this deposit disappears, which is reset if it 41 | /// is harvested. 42 | /// 43 | /// [Screeps documentation](https://docs.screeps.com/api/#Deposit.ticksToDecay) 44 | #[wasm_bindgen(method, getter = ticksToDecay)] 45 | pub fn ticks_to_decay(this: &Deposit) -> u32; 46 | } 47 | 48 | impl CanDecay for Deposit { 49 | fn ticks_to_decay(&self) -> u32 { 50 | self.ticks_to_decay() 51 | } 52 | } 53 | 54 | impl HasCooldown for Deposit { 55 | fn cooldown(&self) -> u32 { 56 | self.cooldown() 57 | } 58 | } 59 | 60 | impl HasId for Deposit { 61 | fn js_raw_id(&self) -> JsString { 62 | self.id_internal() 63 | } 64 | } 65 | 66 | impl Harvestable for Deposit {} 67 | -------------------------------------------------------------------------------- /src/objects/impls/flag.rs: -------------------------------------------------------------------------------- 1 | use js_sys::JsString; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{ 5 | constants::Color, 6 | enums::action_error_codes::flag::*, 7 | objects::{RoomObject, RoomPosition}, 8 | prelude::*, 9 | }; 10 | 11 | #[wasm_bindgen] 12 | extern "C" { 13 | /// A [`Flag`], which can be placed by the player or created automatically 14 | /// and are only visible to their owners. You can't create more than 15 | /// [`FLAGS_LIMIT`]. 16 | /// 17 | /// [Screeps documentation](https://docs.screeps.com/api/#Flag) 18 | /// 19 | /// [`FLAGS_LIMIT`]: crate::constants::FLAGS_LIMIT 20 | #[wasm_bindgen(extends = RoomObject)] 21 | #[derive(Clone, Debug)] 22 | pub type Flag; 23 | 24 | /// Primary color of the flag. 25 | /// 26 | /// [Screeps documentation](https://docs.screeps.com/api/#Flag.color) 27 | #[wasm_bindgen(method, getter)] 28 | pub fn color(this: &Flag) -> Color; 29 | 30 | /// A shortcut to `Memory.flags[flag.name]`. 31 | /// 32 | /// [Screeps documentation](https://docs.screeps.com/api/#Flag.memory) 33 | #[wasm_bindgen(method, getter)] 34 | pub fn memory(this: &Flag) -> JsValue; 35 | 36 | /// Sets a new value to `Memory.flags[flag.name]`. 37 | /// 38 | /// [Screeps documentation](https://docs.screeps.com/api/#Flag.memory) 39 | #[wasm_bindgen(method, setter)] 40 | pub fn set_memory(this: &Flag, val: &JsValue); 41 | 42 | /// The flag's name as a [`String`]. 43 | /// 44 | /// [Screeps documentation](https://docs.screeps.com/api/#Flag.name) 45 | #[wasm_bindgen(method, getter)] 46 | pub fn name(this: &Flag) -> String; 47 | 48 | /// The flag's name as a [`JsString`]. 49 | /// 50 | /// [Screeps documentation](https://docs.screeps.com/api/#Flag.name) 51 | #[wasm_bindgen(method, getter = name)] 52 | pub fn name_jsstring(this: &Flag) -> JsString; 53 | 54 | #[wasm_bindgen(method, js_name = remove)] 55 | fn remove_internal(this: &Flag) -> i8; 56 | 57 | #[wasm_bindgen(method, js_name = setColor)] 58 | fn set_color_internal(this: &Flag, color: Color, secondary_color: Option) -> i8; 59 | 60 | #[wasm_bindgen(method, js_name = setPosition)] 61 | fn set_position_internal(this: &Flag, pos: RoomPosition) -> i8; 62 | } 63 | 64 | impl Flag { 65 | /// Remove the flag. 66 | /// 67 | /// [Screeps documentation](https://docs.screeps.com/api/#Flag.remove) 68 | pub fn remove(&self) -> Result<(), FlagRemoveErrorCode> { 69 | FlagRemoveErrorCode::result_from_i8(self.remove_internal()) 70 | } 71 | 72 | /// Set the color (and optionally, the secondary color) of the flag. 73 | /// 74 | /// [Screeps documentation](https://docs.screeps.com/api/#Flag.setColor) 75 | pub fn set_color( 76 | &self, 77 | color: Color, 78 | secondary_color: Option, 79 | ) -> Result<(), SetColorErrorCode> { 80 | SetColorErrorCode::result_from_i8(self.set_color_internal(color, secondary_color)) 81 | } 82 | 83 | /// Set the position of the flag 84 | /// 85 | /// [Screeps documentation](https://docs.screeps.com/api/#Flag.setPosition) 86 | pub fn set_position(&self, pos: RoomPosition) -> Result<(), SetPositionErrorCode> { 87 | SetPositionErrorCode::result_from_i8(self.set_position_internal(pos)) 88 | } 89 | } 90 | 91 | impl JsCollectionFromValue for Flag { 92 | fn from_value(val: JsValue) -> Self { 93 | val.unchecked_into() 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/objects/impls/mineral.rs: -------------------------------------------------------------------------------- 1 | use js_sys::JsString; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{ 5 | constants::{Density, ResourceType}, 6 | objects::RoomObject, 7 | prelude::*, 8 | }; 9 | 10 | #[wasm_bindgen] 11 | extern "C" { 12 | /// A [`Mineral`], which can be harvested for resources with an extractor. 13 | /// 14 | /// [Screeps documentation](https://docs.screeps.com/api/#Mineral) 15 | #[wasm_bindgen(extends = RoomObject)] 16 | #[derive(Clone, Debug)] 17 | pub type Mineral; 18 | 19 | /// The density of the mineral on the next refill after it's depleted. 20 | /// 21 | /// [Screeps documentation](https://docs.screeps.com/api/#Mineral.density) 22 | #[wasm_bindgen(method, getter)] 23 | pub fn density(this: &Mineral) -> Density; 24 | 25 | /// Type of resource contained in this mineral. 26 | /// 27 | /// [Screeps documentation](https://docs.screeps.com/api/#Mineral.mineralType) 28 | #[wasm_bindgen(method, getter = mineralAmount)] 29 | pub fn mineral_amount(this: &Mineral) -> u32; 30 | 31 | /// Type of resource contained in this mineral. 32 | /// 33 | /// [Screeps documentation](https://docs.screeps.com/api/#Mineral.mineralType) 34 | #[wasm_bindgen(method, getter = mineralType)] 35 | pub fn mineral_type(this: &Mineral) -> ResourceType; 36 | 37 | /// Object ID of the mineral, which can be used to efficiently fetch a fresh 38 | /// reference to the object on subsequent ticks. 39 | /// 40 | /// [Screeps documentation](https://docs.screeps.com/api/#Mineral.id) 41 | #[wasm_bindgen(method, getter = id)] 42 | fn id_internal(this: &Mineral) -> JsString; 43 | 44 | /// The number of ticks until this mineral regenerates from depletion, or 45 | /// `None` if it's not currently regenerating. 46 | /// 47 | /// [Screeps documentation](https://docs.screeps.com/api/#Mineral.ticksToRegeneration) 48 | #[wasm_bindgen(method, getter = ticksToRegeneration)] 49 | pub fn ticks_to_regeneration(this: &Mineral) -> Option; 50 | } 51 | 52 | impl HasId for Mineral { 53 | fn js_raw_id(&self) -> JsString { 54 | Self::id_internal(self) 55 | } 56 | } 57 | 58 | impl Harvestable for Mineral {} 59 | -------------------------------------------------------------------------------- /src/objects/impls/nuke.rs: -------------------------------------------------------------------------------- 1 | use js_sys::JsString; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{objects::RoomObject, prelude::*}; 5 | 6 | #[wasm_bindgen] 7 | extern "C" { 8 | /// A [`Nuke`] in flight, which will deal damage in an area and kill all 9 | /// creeps in the room when it lands. 10 | /// 11 | /// [Screeps documentation](https://docs.screeps.com/api/#Nuke) 12 | #[wasm_bindgen(extends = RoomObject)] 13 | #[derive(Clone, Debug)] 14 | pub type Nuke; 15 | 16 | /// Object ID of the Nuke, which can be used to efficiently fetch a fresh 17 | /// reference to the object on subsequent ticks. 18 | /// 19 | /// [Screeps documentation](https://docs.screeps.com/api/#Nuke.id) 20 | #[wasm_bindgen(method, getter = id)] 21 | fn id_internal(this: &Nuke) -> JsString; 22 | 23 | /// The name of the room the nuke was fired from. 24 | /// 25 | /// [Screeps documentation](https://docs.screeps.com/api/#Nuke.launchRoomName) 26 | #[wasm_bindgen(method, getter)] 27 | pub fn launch_room_name(this: &Nuke) -> JsString; 28 | 29 | /// Ticks until the nuke lands. 30 | /// 31 | /// [Screeps documentation](https://docs.screeps.com/api/#Nuke.timeToLand) 32 | #[wasm_bindgen(method, getter = timeToLand)] 33 | pub fn time_to_land(this: &Nuke) -> u32; 34 | } 35 | 36 | impl HasId for Nuke { 37 | fn js_raw_id(&self) -> JsString { 38 | Self::id_internal(self) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/objects/impls/owned_structure.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | use crate::{ 4 | objects::{RoomObject, Structure}, 5 | prelude::*, 6 | }; 7 | 8 | #[wasm_bindgen] 9 | extern "C" { 10 | /// Parent class for all [`Structure`] objects types which are (or can be) 11 | /// owned by a specific player. 12 | /// 13 | /// [Screeps documentation](https://docs.screeps.com/api/#OwnedStructure) 14 | #[wasm_bindgen(extends = RoomObject, extends = Structure)] 15 | #[derive(Clone, Debug)] 16 | pub type OwnedStructure; 17 | 18 | // For controllers (possibly other structures?) user can be set to null, even 19 | // though it's meant to always be owned. This internal method is used to map 20 | // that case to false. 21 | #[wasm_bindgen(method, getter = my)] 22 | fn my_internal(this: &OwnedStructure) -> Option; 23 | 24 | /// The [`Owner`] of this structure that contains the owner's username, or 25 | /// `None` if it's an ownable structure currently not under a player's 26 | /// control. 27 | /// 28 | /// [Screeps documentation](https://docs.screeps.com/api/#OwnedStructure.owner) 29 | #[wasm_bindgen(method, getter)] 30 | pub fn owner(this: &OwnedStructure) -> Option; 31 | } 32 | 33 | impl OwnedStructure { 34 | /// Whether this structure is owned by the player. 35 | /// 36 | /// [Screeps documentation](https://docs.screeps.com/api/#OwnedStructure.my) 37 | pub fn my(&self) -> bool { 38 | // If there is no user assigned, like in unowned controllers, `my` returns 39 | // undefined. That should be `false`, since that's not owned by the caller. 40 | self.my_internal().unwrap_or(false) 41 | } 42 | } 43 | 44 | impl Attackable for OwnedStructure {} 45 | 46 | impl OwnedStructureProperties for T 47 | where 48 | T: AsRef, 49 | { 50 | fn my(&self) -> bool { 51 | OwnedStructure::my(self.as_ref()) 52 | } 53 | 54 | fn owner(&self) -> Option { 55 | OwnedStructure::owner(self.as_ref()) 56 | } 57 | } 58 | 59 | #[wasm_bindgen] 60 | extern "C" { 61 | /// Object with owner info for an owned game object. 62 | #[wasm_bindgen] 63 | pub type Owner; 64 | 65 | /// The name of the player that owns this object. 66 | #[wasm_bindgen(method, getter)] 67 | pub fn username(this: &Owner) -> String; 68 | } 69 | -------------------------------------------------------------------------------- /src/objects/impls/reactor.rs: -------------------------------------------------------------------------------- 1 | use js_sys::JsString; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{ 5 | objects::{Owner, RoomObject, Store}, 6 | prelude::*, 7 | }; 8 | 9 | #[wasm_bindgen] 10 | extern "C" { 11 | /// An object representing a [`Reactor`], which process [`Thorium`] to gain 12 | /// season score. 13 | /// 14 | /// [Screeps documentation](https://docs-season.screeps.com/api/#Reactor) 15 | /// 16 | /// [`Thorium`]: crate::constants::ResourceType::Thorium 17 | #[wasm_bindgen(extends = RoomObject)] 18 | #[derive(Clone, Debug)] 19 | pub type Reactor; 20 | 21 | #[wasm_bindgen(method, getter = id)] 22 | fn id_internal(this: &Reactor) -> JsString; 23 | 24 | /// Ticks of continuous work this reactor has done. 25 | /// 26 | /// [Screeps documentation](https://docs-season.screeps.com/api/#Reactor.continuousWork) 27 | #[wasm_bindgen(method, getter = continuousWork)] 28 | pub fn continuous_work(this: &Reactor) -> u32; 29 | 30 | /// The [`Store`] of the reactor, which contains information about what 31 | /// [`Thorium`] it is it holding. 32 | /// 33 | /// [Screeps documentation](https://docs-season.screeps.com/api/#Reactor.store) 34 | /// 35 | /// [`Thorium`]: crate::constants::ResourceType::Thorium 36 | #[wasm_bindgen(method, getter)] 37 | pub fn store(this: &Reactor) -> Store; 38 | 39 | // owner and my are on OwnedStructure and we'd usually inherit them, but since 40 | // it inherits Structure, and Reactor is not a Structure, implementing these 41 | // directly. 42 | /// Whether this reactor is owned by the player. 43 | /// 44 | /// [Screeps documentation](https://docs-season.screeps.com/api/#Reactor.my) 45 | #[wasm_bindgen(method, getter)] 46 | pub fn my(this: &Reactor) -> bool; 47 | 48 | /// The [`Owner`] of this reactor that contains the owner's username, or 49 | /// `None` if it's currently not under a player's control. 50 | /// 51 | /// [Screeps documentation](https://docs-season.screeps.com/api/#Reactor.owner) 52 | #[wasm_bindgen(method, getter)] 53 | pub fn owner(this: &Reactor) -> Option; 54 | } 55 | 56 | impl HasId for Reactor { 57 | fn js_raw_id(&self) -> JsString { 58 | Self::id_internal(self) 59 | } 60 | } 61 | 62 | impl HasStore for Reactor { 63 | fn store(&self) -> Store { 64 | Self::store(self) 65 | } 66 | } 67 | 68 | impl Transferable for Reactor {} 69 | -------------------------------------------------------------------------------- /src/objects/impls/resource.rs: -------------------------------------------------------------------------------- 1 | use js_sys::JsString; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{constants::ResourceType, objects::RoomObject, prelude::*}; 5 | 6 | #[wasm_bindgen] 7 | extern "C" { 8 | /// A [`Resource`] is an object representing resources that have been 9 | /// dropped and can be picked up. 10 | /// 11 | /// [Screeps documentation](https://docs.screeps.com/api/#Resource) 12 | #[wasm_bindgen(extends = RoomObject)] 13 | #[derive(Clone, Debug)] 14 | pub type Resource; 15 | 16 | /// Amount of resource this contains. 17 | /// 18 | /// [Screeps documentation](https://docs.screeps.com/api/#Resource.amount) 19 | #[wasm_bindgen(method, getter)] 20 | pub fn amount(this: &Resource) -> u32; 21 | 22 | /// Object ID of the resource, which can be used to efficiently fetch a 23 | /// fresh reference to the object on subsequent ticks. 24 | /// 25 | /// [Screeps documentation](https://docs.screeps.com/api/#Resource.id) 26 | #[wasm_bindgen(method, getter = id)] 27 | fn id_internal(this: &Resource) -> JsString; 28 | 29 | /// The type of resource this contains. 30 | /// 31 | /// [Screeps documentation](https://docs.screeps.com/api/#Resource.resourceType) 32 | #[wasm_bindgen(method, getter = resourceType)] 33 | pub fn resource_type(this: &Resource) -> ResourceType; 34 | } 35 | 36 | impl HasId for Resource { 37 | fn js_raw_id(&self) -> JsString { 38 | Self::id_internal(self) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/objects/impls/room_object.rs: -------------------------------------------------------------------------------- 1 | use js_sys::Array; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{ 5 | constants::EffectType, 6 | local::Position, 7 | objects::{Room, RoomPosition}, 8 | prelude::*, 9 | }; 10 | 11 | #[wasm_bindgen] 12 | extern "C" { 13 | /// Parent class for all objects in rooms in the game world. 14 | /// 15 | /// [Screeps documentation](https://docs.screeps.com/api/#Room) 16 | #[derive(Clone, Debug)] 17 | pub type RoomObject; 18 | 19 | /// Effects applied to the object. 20 | /// 21 | /// [Screeps documentation](https://docs.screeps.com/api/#RoomObject.effects) 22 | #[wasm_bindgen(method, getter = effects)] 23 | fn effects_internal(this: &RoomObject) -> Option; 24 | 25 | /// Gets the [`RoomPosition`] of an object, which is a reference to an 26 | /// object in the javascript heap. In most cases, you'll likely want a 27 | /// native [`Position`] instead of using this function (see 28 | /// [`HasPosition::pos`]), there may be cases where this can provide 29 | /// some slight performance benefits due to reducing object churn in the js 30 | /// heap, so this is kept public. 31 | /// 32 | /// [Screeps documentation](https://docs.screeps.com/api/#RoomObject.pos) 33 | #[wasm_bindgen(method, getter = pos)] 34 | pub fn js_pos(this: &RoomObject) -> RoomPosition; 35 | 36 | /// A link to the room that the object is currently in, or `None` if the 37 | /// object is a power creep not spawned on the current shard, or a flag or 38 | /// construction site not in a visible room. 39 | /// 40 | /// [Screeps documentation](https://docs.screeps.com/api/#RoomObject.room) 41 | #[wasm_bindgen(method, getter)] 42 | pub fn room(this: &RoomObject) -> Option; 43 | } 44 | 45 | #[wasm_bindgen] 46 | extern "C" { 47 | #[wasm_bindgen] 48 | #[derive(Debug)] 49 | pub type Effect; 50 | 51 | #[wasm_bindgen(method, getter)] 52 | pub fn effect(this: &Effect) -> EffectType; 53 | 54 | #[wasm_bindgen(method, getter)] 55 | pub fn level(this: &Effect) -> Option; 56 | 57 | #[wasm_bindgen(method, getter = ticksRemaining)] 58 | pub fn ticks_remaining(this: &Effect) -> EffectType; 59 | } 60 | 61 | impl HasPosition for T 62 | where 63 | T: AsRef, 64 | { 65 | fn pos(&self) -> Position { 66 | self.as_ref().js_pos().into() 67 | } 68 | } 69 | 70 | impl RoomObjectProperties for T 71 | where 72 | T: AsRef, 73 | { 74 | fn effects(&self) -> Vec { 75 | RoomObject::effects_internal(self.as_ref()) 76 | .map(|arr| arr.iter().map(JsCast::unchecked_into).collect()) 77 | .unwrap_or_default() 78 | } 79 | 80 | fn effects_raw(&self) -> Option { 81 | RoomObject::effects_internal(self.as_ref()) 82 | } 83 | 84 | fn room(&self) -> Option { 85 | RoomObject::room(self.as_ref()) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/objects/impls/room_terrain.rs: -------------------------------------------------------------------------------- 1 | use js_sys::{JsString, Uint8Array}; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{ 5 | constants::{ErrorCode, Terrain}, 6 | local::{RoomName, RoomXY}, 7 | prelude::*, 8 | }; 9 | 10 | #[wasm_bindgen] 11 | extern "C" { 12 | /// A matrix representing the terrain of a room, held in the JavaScript 13 | /// heap. 14 | /// 15 | /// Use [`LocalRoomTerrain`] to store and access the same data in Rust 16 | /// memory. 17 | /// 18 | /// [Screeps documentation](https://docs.screeps.com/api/#Room-Terrain) 19 | #[wasm_bindgen(js_namespace = Room, js_name = Terrain)] 20 | pub type RoomTerrain; 21 | 22 | #[wasm_bindgen(constructor, js_namespace = Room, js_class = Terrain, catch)] 23 | fn new_internal(room_name: &JsString) -> Result; 24 | 25 | /// Get the type of terrain at given coordinates. 26 | /// 27 | /// [Screeps documentation](https://docs.screeps.com/api/#Room.Terrain.get) 28 | #[wasm_bindgen(method)] 29 | pub fn get(this: &RoomTerrain, x: u8, y: u8) -> Terrain; 30 | 31 | // when called without a destination array, can't fail - no error code possible 32 | #[wasm_bindgen(method, js_name = getRawBuffer)] 33 | fn get_raw_buffer_internal(this: &RoomTerrain) -> Uint8Array; 34 | 35 | // and when called with a destination, it can only ever return a return code int 36 | #[wasm_bindgen(method, js_name = getRawBuffer)] 37 | fn get_raw_buffer_to_array_internal(this: &RoomTerrain, destination: &Uint8Array) -> JsValue; 38 | } 39 | 40 | impl RoomTerrain { 41 | /// Gets the terrain for any room by name, regardless of current visibility 42 | /// of the room. 43 | /// 44 | /// [Screeps documentation](https://docs.screeps.com/api/#Room.Terrain.constructor) 45 | pub fn new(room_name: RoomName) -> Option { 46 | let name = room_name.into(); 47 | 48 | Self::new_internal(&name).ok() 49 | } 50 | 51 | /// Get a copy of the underlying Uint8Array with the data about the room's 52 | /// terrain. 53 | /// 54 | /// [Screeps documentation](https://docs.screeps.com/api/#Room.Terrain.getRawBuffer) 55 | #[inline] 56 | pub fn get_raw_buffer(&self) -> Uint8Array { 57 | self.get_raw_buffer_internal() 58 | } 59 | 60 | /// Copy the data about the room's terrain into an existing [`Uint8Array`]. 61 | /// 62 | /// [Screeps documentation](https://docs.screeps.com/api/#Room.Terrain.getRawBuffer) 63 | #[inline] 64 | pub fn get_raw_buffer_to_array(&self, destination: &Uint8Array) -> Result<(), ErrorCode> { 65 | let val = self.get_raw_buffer_to_array_internal(destination); 66 | 67 | // val is integer if error; if object it's another reference to the Uint8Array; 68 | // function was successful in that case 69 | match val.as_f64() { 70 | Some(n) => ErrorCode::result_from_i8(n as i8), 71 | None => Ok(()), 72 | } 73 | } 74 | 75 | /// Get the type of terrain at the given [`RoomXY`]. 76 | #[inline] 77 | pub fn get_xy(&mut self, xy: RoomXY) -> Terrain { 78 | self.get(xy.x.u8(), xy.y.u8()) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/objects/impls/ruin.rs: -------------------------------------------------------------------------------- 1 | use js_sys::JsString; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{ 5 | objects::{RoomObject, Store, Structure}, 6 | prelude::*, 7 | }; 8 | 9 | #[wasm_bindgen] 10 | extern "C" { 11 | /// A [`Ruin`], which represents a destroyed structure and can have 12 | /// resources withdrawn from it. 13 | /// 14 | /// [Screeps documentation](https://docs.screeps.com/api/#Ruin) 15 | #[wasm_bindgen(extends = RoomObject)] 16 | #[derive(Clone, Debug)] 17 | pub type Ruin; 18 | 19 | /// The tick that the structure was destroyed 20 | /// 21 | /// [Screeps documentation](https://docs.screeps.com/api/#Ruin.destroyTime) 22 | #[wasm_bindgen(method, getter = destroyTime)] 23 | pub fn destroy_time(this: &Ruin) -> u32; 24 | 25 | /// Object ID of the ruin, which can be used to efficiently fetch a fresh 26 | /// reference to the object on subsequent ticks. 27 | /// 28 | /// [Screeps documentation](https://docs.screeps.com/api/#Ruin.id) 29 | #[wasm_bindgen(method, getter = id)] 30 | fn id_internal(this: &Ruin) -> JsString; 31 | 32 | /// The [`Store`] of the ruin, which contains any resources in the ruin. 33 | /// 34 | /// [Screeps documentation](https://docs.screeps.com/api/#Ruin.store) 35 | #[wasm_bindgen(method, getter)] 36 | pub fn store(this: &Ruin) -> Store; 37 | 38 | /// The destroyed [`Structure`] that this ruin represents. Note that this 39 | /// object is not fully safe to use as a [`Structure`], missing critical 40 | /// properties such as position; it's only safe to access basic information 41 | /// about the structure on this object, like the structure type, owner name, 42 | /// and id. 43 | /// 44 | /// [Screeps documentation](https://docs.screeps.com/api/#Ruin.structure) 45 | #[wasm_bindgen(method, getter)] 46 | pub fn structure(this: &Ruin) -> Structure; 47 | 48 | /// The number of ticks until this ruin disappears. 49 | /// 50 | /// [Screeps documentation](https://docs.screeps.com/api/#Ruin.ticksToDecay) 51 | #[wasm_bindgen(method, getter = ticksToDecay)] 52 | pub fn ticks_to_decay(this: &Ruin) -> u32; 53 | } 54 | 55 | impl CanDecay for Ruin { 56 | fn ticks_to_decay(&self) -> u32 { 57 | Self::ticks_to_decay(self) 58 | } 59 | } 60 | 61 | impl HasId for Ruin { 62 | fn js_raw_id(&self) -> JsString { 63 | Self::id_internal(self) 64 | } 65 | } 66 | 67 | impl HasStore for Ruin { 68 | fn store(&self) -> Store { 69 | Self::store(self) 70 | } 71 | } 72 | 73 | impl Withdrawable for Ruin {} 74 | -------------------------------------------------------------------------------- /src/objects/impls/score_collector.rs: -------------------------------------------------------------------------------- 1 | use js_sys::JsString; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{ 5 | objects::{RoomObject, Store}, 6 | prelude::*, 7 | }; 8 | 9 | #[wasm_bindgen] 10 | extern "C" { 11 | /// An object representing a [`ScoreCollector`], which can have 12 | /// [`ResourceType::Score`] transferred to it in order to score points on 13 | /// the leaderboard. 14 | /// 15 | /// [Screeps documentation](https://docs-season.screeps.com/api/#ScoreCollector) 16 | /// 17 | /// [`ResourceType::Score`]: crate::constants::ResourceType::Score 18 | #[wasm_bindgen(extends = RoomObject)] 19 | #[derive(Clone, Debug)] 20 | pub type ScoreCollector; 21 | 22 | /// Object ID of the collector, which can be used to efficiently fetch a 23 | /// fresh reference to the object on subsequent ticks. 24 | /// 25 | /// [Screeps documentation](https://docs-season.screeps.com/api/#ScoreCollector.id) 26 | #[wasm_bindgen(method, getter = id)] 27 | fn id_internal(this: &ScoreCollector) -> JsString; 28 | 29 | /// The [`Store`] of the container, which contains information about what 30 | /// resources it is it holding. 31 | /// 32 | /// [Screeps documentation](https://docs-season.screeps.com/api/#ScoreCollector.store) 33 | #[wasm_bindgen(method, getter)] 34 | pub fn store(this: &ScoreCollector) -> Store; 35 | } 36 | 37 | impl HasId for ScoreCollector { 38 | fn js_raw_id(&self) -> JsString { 39 | Self::id_internal(self) 40 | } 41 | } 42 | 43 | impl HasStore for ScoreCollector { 44 | fn store(&self) -> Store { 45 | Self::store(self) 46 | } 47 | } 48 | 49 | impl Transferable for ScoreCollector {} 50 | -------------------------------------------------------------------------------- /src/objects/impls/score_container.rs: -------------------------------------------------------------------------------- 1 | use js_sys::JsString; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{ 5 | objects::{RoomObject, Store}, 6 | prelude::*, 7 | }; 8 | 9 | #[wasm_bindgen] 10 | extern "C" { 11 | /// An object representing a [`ScoreContainer`], which appears randomly 12 | /// around the map and contains [`ResourceType::Score`] which can be 13 | /// collected. 14 | /// 15 | /// [Screeps documentation](https://docs-season.screeps.com/api/#ScoreContainer) 16 | /// 17 | /// [`ResourceType::Score`]: crate::constants::ResourceType::Score 18 | #[wasm_bindgen(extends = RoomObject)] 19 | #[derive(Clone, Debug)] 20 | pub type ScoreContainer; 21 | 22 | /// Object ID of the collector, which can be used to efficiently fetch a 23 | /// fresh reference to the object on subsequent ticks. 24 | /// 25 | /// [Screeps documentation](https://docs-season.screeps.com/api/#ScoreContainer.id) 26 | #[wasm_bindgen(method, getter = id)] 27 | fn id_internal(this: &ScoreContainer) -> JsString; 28 | 29 | /// The [`Store`] of the container, which contains information about what 30 | /// resources it is it holding. 31 | /// 32 | /// [Screeps documentation](https://docs-season.screeps.com/api/#ScoreContainer.store) 33 | #[wasm_bindgen(method, getter)] 34 | pub fn store(this: &ScoreContainer) -> Store; 35 | 36 | /// The number of ticks until the [`ScoreContainer`] will decay, 37 | /// disappearing completely. 38 | /// 39 | /// [Screeps documentation](https://docs-season.screeps.com/api/#ScoreContainer.ticksToDecay) 40 | #[wasm_bindgen(method, getter = ticksToDecay)] 41 | pub fn ticks_to_decay(this: &ScoreContainer) -> u32; 42 | } 43 | 44 | impl CanDecay for ScoreContainer { 45 | fn ticks_to_decay(&self) -> u32 { 46 | Self::ticks_to_decay(self) 47 | } 48 | } 49 | 50 | impl HasId for ScoreContainer { 51 | fn js_raw_id(&self) -> JsString { 52 | Self::id_internal(self) 53 | } 54 | } 55 | 56 | impl HasStore for ScoreContainer { 57 | fn store(&self) -> Store { 58 | Self::store(self) 59 | } 60 | } 61 | 62 | impl Withdrawable for ScoreContainer {} 63 | -------------------------------------------------------------------------------- /src/objects/impls/source.rs: -------------------------------------------------------------------------------- 1 | use js_sys::JsString; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{objects::RoomObject, prelude::*}; 5 | 6 | #[wasm_bindgen] 7 | extern "C" { 8 | /// A [`Source`], which can be harvested for energy. 9 | /// 10 | /// [Screeps documentation](https://docs.screeps.com/api/#Source) 11 | #[wasm_bindgen(extends = RoomObject)] 12 | #[derive(Clone, Debug)] 13 | pub type Source; 14 | 15 | /// Amount of energy available to be harvested from the source. 16 | /// 17 | /// [Screeps documentation](https://docs.screeps.com/api/#Source.energy) 18 | #[wasm_bindgen(method, getter)] 19 | pub fn energy(this: &Source) -> u32; 20 | 21 | /// Amount of energy this source will regenerate to after 22 | /// [`Source::ticks_to_regeneration`] reaches 0. 23 | /// 24 | /// Value depends on the type of room the source is in: 25 | /// 26 | /// - Owned and reserved rooms: [`SOURCE_ENERGY_CAPACITY`] 27 | /// - Neutral rooms: [`SOURCE_ENERGY_NEUTRAL_CAPACITY`] 28 | /// - Source Keeper rooms: [`SOURCE_ENERGY_KEEPER_CAPACITY`] 29 | /// 30 | /// [Screeps documentation](https://docs.screeps.com/api/#Source.energy) 31 | /// 32 | /// [`SOURCE_ENERGY_CAPACITY`]: crate::constants::SOURCE_ENERGY_CAPACITY 33 | /// [`SOURCE_ENERGY_NEUTRAL_CAPACITY`]: 34 | /// crate::constants::SOURCE_ENERGY_NEUTRAL_CAPACITY 35 | /// [`SOURCE_ENERGY_KEEPER_CAPACITY`]: 36 | /// crate::constants::SOURCE_ENERGY_KEEPER_CAPACITY 37 | #[wasm_bindgen(method, getter = energyCapacity)] 38 | pub fn energy_capacity(this: &Source) -> u32; 39 | 40 | /// Object ID of the source, which can be used to efficiently fetch a fresh 41 | /// reference to the object on subsequent ticks. 42 | /// 43 | /// [Screeps documentation](https://docs.screeps.com/api/#Source.id) 44 | #[wasm_bindgen(method, getter = id)] 45 | fn id_internal(this: &Source) -> JsString; 46 | 47 | /// The number of ticks until this source regenerates to its 48 | /// [`Source::energy_capacity`], or `None` if the source has not started to 49 | /// regenerate. 50 | /// 51 | /// [Screeps documentation](https://docs.screeps.com/api/#Source.ticksToRegeneration) 52 | #[wasm_bindgen(method, getter = ticksToRegeneration)] 53 | pub fn ticks_to_regeneration(this: &Source) -> Option; 54 | } 55 | 56 | impl HasId for Source { 57 | fn js_raw_id(&self) -> JsString { 58 | Self::id_internal(self) 59 | } 60 | } 61 | 62 | impl Harvestable for Source {} 63 | -------------------------------------------------------------------------------- /src/objects/impls/store.rs: -------------------------------------------------------------------------------- 1 | use js_sys::Object; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::constants::ResourceType; 5 | 6 | //TODO: wiarchbe: Need types for general purpose store and specific store. 7 | // (Specific store can return undefined for missing types.) 8 | #[wasm_bindgen] 9 | extern "C" { 10 | /// An object that represents the cargo within an entity in the game world. 11 | /// 12 | /// [Screeps documentation](https://docs.screeps.com/api/#Store) 13 | #[wasm_bindgen] 14 | pub type Store; 15 | 16 | #[wasm_bindgen(method, structural, indexing_getter)] 17 | pub fn get(this: &Store, ty: ResourceType) -> Option; 18 | 19 | /// Get the capacity of the [`Store`] for the specified resource. If the 20 | /// [`Store`] can contain any resource, passing `None` as the type will get 21 | /// the general store capacity. 22 | /// 23 | /// [Screeps documentation](https://docs.screeps.com/api/#Store.getCapacity) 24 | #[wasm_bindgen(method, js_name = getCapacity)] 25 | fn get_capacity_internal(this: &Store, ty: Option) -> Option; 26 | 27 | /// Return the free capacity of the [`Store`] for the specified resource. 28 | /// 29 | /// [Screeps documentation](https://docs.screeps.com/api/#Store.getFreeCapacity) 30 | #[wasm_bindgen(method, js_name = getFreeCapacity)] 31 | fn get_free_capacity_internal(this: &Store, ty: Option) -> Option; 32 | 33 | /// Return the used capacity of the [`Store`] for the specified resource. If 34 | /// the [`Store`] can contain any resource, passing `None` as the type will 35 | /// get the total used capacity. 36 | /// 37 | /// [Screeps documentation](https://docs.screeps.com/api/#Store.getUsedCapacity) 38 | #[wasm_bindgen(method, js_name = getUsedCapacity)] 39 | fn get_used_capacity_internal(this: &Store, ty: Option) -> Option; 40 | } 41 | 42 | impl Store { 43 | pub fn store_types(&self) -> Vec { 44 | Object::keys(self.unchecked_ref()) 45 | .iter() 46 | .filter_map(|v| ResourceType::from_js_value(&v)) 47 | .collect() 48 | } 49 | 50 | pub fn get_capacity(&self, ty: Option) -> u32 { 51 | self.get_capacity_internal(ty).unwrap_or(0) 52 | } 53 | 54 | pub fn get_free_capacity(&self, ty: Option) -> i32 { 55 | self.get_free_capacity_internal(ty).unwrap_or(0) 56 | } 57 | 58 | pub fn get_used_capacity(&self, ty: Option) -> u32 { 59 | self.get_used_capacity_internal(ty).unwrap_or(0) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/objects/impls/structure.rs: -------------------------------------------------------------------------------- 1 | use js_sys::JsString; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{ 5 | constants::StructureType, enums::action_error_codes::structure::*, objects::RoomObject, 6 | prelude::*, 7 | }; 8 | 9 | #[wasm_bindgen] 10 | extern "C" { 11 | /// Parent class for all objects that represent a structure in the game 12 | /// world. 13 | /// 14 | /// [Screeps documentation](https://docs.screeps.com/api/#Structure) 15 | #[wasm_bindgen(extends = RoomObject)] 16 | #[derive(Clone, Debug)] 17 | pub type Structure; 18 | 19 | #[wasm_bindgen(method, getter = hits)] 20 | fn hits_internal(this: &Structure) -> Option; 21 | 22 | #[wasm_bindgen(method, getter = hitsMax)] 23 | fn hits_max_internal(this: &Structure) -> Option; 24 | 25 | /// Object ID of the structure, which can be used to efficiently fetch a 26 | /// fresh reference to the object on subsequent ticks. 27 | /// 28 | /// [Screeps documentation](https://docs.screeps.com/api/#Structure.id) 29 | #[wasm_bindgen(method, getter = id)] 30 | fn id_internal(this: &Structure) -> JsString; 31 | 32 | /// The type of structure this is. 33 | /// 34 | /// [Screeps documentation](https://docs.screeps.com/api/#Structure.structureType) 35 | #[wasm_bindgen(method, getter = structureType)] 36 | pub fn structure_type(this: &Structure) -> StructureType; 37 | 38 | #[wasm_bindgen(method, js_name = destroy)] 39 | fn destroy_internal(this: &Structure) -> i8; 40 | 41 | /// Determine if the structure is active and can be used at the current RCL. 42 | /// 43 | /// [Screeps documentation](https://docs.screeps.com/api/#Structure.isActive) 44 | #[wasm_bindgen(method, js_name = isActive)] 45 | pub fn is_active(this: &Structure) -> bool; 46 | 47 | #[wasm_bindgen(method, js_name = notifyWhenAttacked)] 48 | fn notify_when_attacked_internal(this: &Structure, val: bool) -> i8; 49 | } 50 | 51 | impl Structure { 52 | /// Retrieve the current hits of this structure, or `0` if this structure is 53 | /// indestructible, such as a notice area border wall, portal, or room 54 | /// controller. 55 | /// 56 | /// [Screeps documentation](https://docs.screeps.com/api/#Structure.hits) 57 | pub fn hits(&self) -> u32 { 58 | self.hits_internal().unwrap_or(0) 59 | } 60 | 61 | /// Retrieve the maximum hits of this structure, or `0` if this structure is 62 | /// indestructible, such as a notice area border wall, portal, or room 63 | /// controller. 64 | /// 65 | /// [Screeps documentation](https://docs.screeps.com/api/#Structure.hitsMax) 66 | pub fn hits_max(&self) -> u32 { 67 | self.hits_max_internal().unwrap_or(0) 68 | } 69 | 70 | /// Destroy the structure, if possible. 71 | /// 72 | /// [Screeps documentation](https://docs.screeps.com/api/#Structure.destroy) 73 | pub fn destroy(&self) -> Result<(), DestroyErrorCode> { 74 | DestroyErrorCode::result_from_i8(self.destroy_internal()) 75 | } 76 | 77 | /// Set whether a notification email should be sent when the structure is 78 | /// attacked. 79 | /// 80 | /// [Screeps documentation](https://docs.screeps.com/api/#Structure.notifyWhenAttacked) 81 | pub fn notify_when_attacked( 82 | &self, 83 | val: bool, 84 | ) -> Result<(), StructureNotifyWhenAttackedErrorCode> { 85 | StructureNotifyWhenAttackedErrorCode::result_from_i8( 86 | self.notify_when_attacked_internal(val), 87 | ) 88 | } 89 | } 90 | 91 | impl HasId for T 92 | where 93 | T: AsRef + JsCast, 94 | { 95 | fn js_raw_id(&self) -> JsString { 96 | Structure::id_internal(self.as_ref()) 97 | } 98 | } 99 | 100 | impl HasHits for T 101 | where 102 | T: AsRef, 103 | { 104 | fn hits(&self) -> u32 { 105 | Structure::hits(self.as_ref()) 106 | } 107 | 108 | fn hits_max(&self) -> u32 { 109 | Structure::hits_max(self.as_ref()) 110 | } 111 | } 112 | 113 | impl StructureProperties for T 114 | where 115 | T: AsRef, 116 | { 117 | fn structure_type(&self) -> StructureType { 118 | Structure::structure_type(self.as_ref()) 119 | } 120 | 121 | fn destroy(&self) -> Result<(), DestroyErrorCode> { 122 | Structure::destroy(self.as_ref()) 123 | } 124 | 125 | fn is_active(&self) -> bool { 126 | Structure::is_active(self.as_ref()) 127 | } 128 | 129 | fn notify_when_attacked(&self, val: bool) -> Result<(), StructureNotifyWhenAttackedErrorCode> { 130 | Structure::notify_when_attacked(self.as_ref(), val) 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/objects/impls/structure_container.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | use crate::{ 4 | objects::{RoomObject, Store, Structure}, 5 | prelude::*, 6 | }; 7 | 8 | #[wasm_bindgen] 9 | extern "C" { 10 | /// An object representing a [`StructureContainer`], which can store 11 | /// resources and does not block creep movement, but requires regular repair 12 | /// due to decay. 13 | /// 14 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureContainer) 15 | #[wasm_bindgen(extends = RoomObject, extends = Structure)] 16 | #[derive(Clone, Debug)] 17 | pub type StructureContainer; 18 | 19 | /// The [`Store`] of the container, which contains information about what 20 | /// resources it is it holding. 21 | /// 22 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureContainer.store) 23 | #[wasm_bindgen(method, getter)] 24 | pub fn store(this: &StructureContainer) -> Store; 25 | 26 | /// The number of ticks until the container will decay, losing 27 | /// [`CONTAINER_DECAY`] hits. The time between each decay interval 28 | /// depends whether the container is in an owned room; 29 | /// [`CONTAINER_DECAY_TIME_OWNED`] in owned rooms and 30 | /// [`CONTAINER_DECAY_TIME`] in all other rooms. 31 | /// 32 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureContainer.ticksToDecay) 33 | /// 34 | /// [`CONTAINER_DECAY`]: crate::constants::CONTAINER_DECAY 35 | /// [`CONTAINER_DECAY_TIME_OWNED`]: crate::constants::CONTAINER_DECAY_TIME_OWNED 36 | /// [`CONTAINER_DECAY_TIME`]: crate::constants::CONTAINER_DECAY_TIME 37 | #[wasm_bindgen(method, getter = ticksToDecay)] 38 | pub fn ticks_to_decay(this: &StructureContainer) -> u32; 39 | } 40 | 41 | impl CanDecay for StructureContainer { 42 | fn ticks_to_decay(&self) -> u32 { 43 | Self::ticks_to_decay(self) 44 | } 45 | } 46 | 47 | impl HasStore for StructureContainer { 48 | fn store(&self) -> Store { 49 | Self::store(self) 50 | } 51 | } 52 | 53 | impl Attackable for StructureContainer {} 54 | impl Dismantleable for StructureContainer {} 55 | impl Repairable for StructureContainer {} 56 | impl Transferable for StructureContainer {} 57 | impl Withdrawable for StructureContainer {} 58 | -------------------------------------------------------------------------------- /src/objects/impls/structure_extension.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | use crate::{ 4 | objects::{OwnedStructure, RoomObject, Store, Structure}, 5 | prelude::*, 6 | }; 7 | 8 | #[wasm_bindgen] 9 | extern "C" { 10 | /// An object representing a [`StructureExtension`], which can store energy 11 | /// to be used by spawns in the room to spawn creeps. 12 | /// 13 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureExtension) 14 | #[wasm_bindgen(extends = RoomObject, extends = Structure, extends = OwnedStructure)] 15 | #[derive(Clone, Debug)] 16 | pub type StructureExtension; 17 | 18 | /// The [`Store`] of the extension, which contains information about the 19 | /// amount of energy in it. 20 | /// 21 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureExtension.store) 22 | #[wasm_bindgen(method, getter)] 23 | pub fn store(this: &StructureExtension) -> Store; 24 | } 25 | 26 | impl HasStore for StructureExtension { 27 | fn store(&self) -> Store { 28 | Self::store(self) 29 | } 30 | } 31 | 32 | impl Attackable for StructureExtension {} 33 | impl Dismantleable for StructureExtension {} 34 | impl Repairable for StructureExtension {} 35 | impl Transferable for StructureExtension {} 36 | impl Withdrawable for StructureExtension {} 37 | -------------------------------------------------------------------------------- /src/objects/impls/structure_extractor.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | use crate::{ 4 | objects::{OwnedStructure, RoomObject, Structure}, 5 | prelude::*, 6 | }; 7 | 8 | #[wasm_bindgen] 9 | extern "C" { 10 | /// An object representing a [`StructureExtractor`], which can be placed on 11 | /// top of a [`Mineral`] to extract resources. 12 | /// 13 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureExtractor) 14 | /// 15 | /// [`Mineral`]: crate::objects::Mineral 16 | #[wasm_bindgen(extends = RoomObject, extends = Structure, extends = OwnedStructure)] 17 | #[derive(Clone, Debug)] 18 | pub type StructureExtractor; 19 | 20 | /// Ticks until this extractor can be used to [`Creep::harvest`] its 21 | /// [`Mineral`] after a previous harvest. 22 | /// 23 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureExtractor.cooldown) 24 | /// 25 | /// [`Creep::harvest`]: crate::objects::Creep::harvest 26 | /// [`Mineral`]: crate::objects::Mineral 27 | #[wasm_bindgen(method, getter)] 28 | pub fn cooldown(this: &StructureExtractor) -> u32; 29 | } 30 | 31 | impl HasCooldown for StructureExtractor { 32 | fn cooldown(&self) -> u32 { 33 | Self::cooldown(self) 34 | } 35 | } 36 | 37 | impl Attackable for StructureExtractor {} 38 | impl Dismantleable for StructureExtractor {} 39 | impl Repairable for StructureExtractor {} 40 | -------------------------------------------------------------------------------- /src/objects/impls/structure_factory.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | use crate::{ 4 | constants::ResourceType, 5 | enums::action_error_codes::structure_factory::*, 6 | objects::{OwnedStructure, RoomObject, Store, Structure}, 7 | prelude::*, 8 | }; 9 | 10 | #[wasm_bindgen] 11 | extern "C" { 12 | /// An object representing a [`StructureFactory`], which can compress and 13 | /// decompress resources and produce commodities for sale. 14 | /// 15 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureFactory) 16 | #[wasm_bindgen(extends = RoomObject, extends = Structure, extends = OwnedStructure)] 17 | #[derive(Clone, Debug)] 18 | pub type StructureFactory; 19 | 20 | /// Ticks until [`StructureFactory::produce`] can be used again. 21 | /// 22 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureFactory.cooldown) 23 | /// 24 | /// [`StructureFactory::produce`]: crate::objects::StructureFactory::produce 25 | #[wasm_bindgen(method, getter)] 26 | pub fn cooldown(this: &StructureFactory) -> u32; 27 | 28 | /// The level of the factory, which cannot be changed once set by a power 29 | /// creep. 30 | /// 31 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureFactory.level) 32 | #[wasm_bindgen(method, getter)] 33 | pub fn level(this: &StructureFactory) -> u8; 34 | 35 | /// The [`Store`] of the factory, which contains information about what 36 | /// resources it is it holding. 37 | /// 38 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureFactory.store) 39 | #[wasm_bindgen(method, getter)] 40 | pub fn store(this: &StructureFactory) -> Store; 41 | 42 | #[wasm_bindgen(method, js_name = produce)] 43 | fn produce_internal(this: &StructureFactory, ty: ResourceType) -> i8; 44 | } 45 | 46 | impl StructureFactory { 47 | /// Produce a commodity in the factory. 48 | /// 49 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureFactory.produce) 50 | pub fn produce(&self, ty: ResourceType) -> Result<(), ProduceErrorCode> { 51 | ProduceErrorCode::result_from_i8(self.produce_internal(ty)) 52 | } 53 | } 54 | 55 | impl HasCooldown for StructureFactory { 56 | fn cooldown(&self) -> u32 { 57 | Self::cooldown(self) 58 | } 59 | } 60 | 61 | impl HasStore for StructureFactory { 62 | fn store(&self) -> Store { 63 | Self::store(self) 64 | } 65 | } 66 | 67 | impl Attackable for StructureFactory {} 68 | impl Dismantleable for StructureFactory {} 69 | impl Repairable for StructureFactory {} 70 | impl Transferable for StructureFactory {} 71 | impl Withdrawable for StructureFactory {} 72 | -------------------------------------------------------------------------------- /src/objects/impls/structure_invader_core.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | use crate::{ 4 | objects::{OwnedStructure, RoomObject, Spawning, Structure}, 5 | prelude::*, 6 | }; 7 | 8 | #[wasm_bindgen] 9 | extern "C" { 10 | /// An object representing a [`StructureInvaderCore`], which is at the 11 | /// center of NPC strongholds, as well as reserving neutral rooms. 12 | /// 13 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureInvaderCore) 14 | #[wasm_bindgen(extends = RoomObject, extends = Structure, extends = OwnedStructure)] 15 | #[derive(Clone, Debug)] 16 | pub type StructureInvaderCore; 17 | 18 | /// The level of the [`StructureInvaderCore`]; 0 is a lesser invader core 19 | /// that simply reserves rooms, while levels 1-5 are strongholds which 20 | /// defend themselves. 21 | /// 22 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureInvaderCore.level) 23 | #[wasm_bindgen(method, getter)] 24 | pub fn level(this: &StructureInvaderCore) -> u8; 25 | 26 | /// The number of ticks until the [`StructureInvaderCore`] is fully deployed 27 | /// and can be attacked. 28 | /// 29 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureInvaderCore.ticksToDeploy) 30 | #[wasm_bindgen(method, getter = ticksToDeploy)] 31 | pub fn ticks_to_deploy(this: &StructureInvaderCore) -> u32; 32 | 33 | /// Information about the spawning creep, if one is currently being spawned. 34 | /// 35 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureInvaderCore.spawning) 36 | #[wasm_bindgen(method, getter)] 37 | pub fn spawning(this: &StructureInvaderCore) -> Option; 38 | } 39 | 40 | impl Attackable for StructureInvaderCore {} 41 | -------------------------------------------------------------------------------- /src/objects/impls/structure_keeper_lair.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | use crate::{ 4 | objects::{OwnedStructure, RoomObject, Structure}, 5 | prelude::*, 6 | }; 7 | 8 | #[wasm_bindgen] 9 | extern "C" { 10 | /// An object representing a [`StructureKeeperLair`], which regularly spawns 11 | /// creeps to defend nearby resources. 12 | /// 13 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureKeeperLair) 14 | #[wasm_bindgen(extends = RoomObject, extends = Structure, extends = OwnedStructure)] 15 | #[derive(Clone, Debug)] 16 | pub type StructureKeeperLair; 17 | 18 | /// The number of ticks until the [`StructureKeeperLair`] will spawn a new 19 | /// creep. 20 | /// 21 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureKeeperLair.ticksToSpawn) 22 | #[wasm_bindgen(method, getter = ticksToSpawn)] 23 | pub fn ticks_to_spawn(this: &StructureKeeperLair) -> u32; 24 | } 25 | 26 | impl Attackable for StructureKeeperLair {} 27 | -------------------------------------------------------------------------------- /src/objects/impls/structure_lab.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | use crate::{ 4 | constants::ResourceType, 5 | enums::action_error_codes::structure_lab::*, 6 | objects::{Creep, OwnedStructure, RoomObject, Store, Structure}, 7 | prelude::*, 8 | }; 9 | 10 | #[wasm_bindgen] 11 | extern "C" { 12 | /// An object representing a [`StructureLab`], which can be used to create 13 | /// mineral compounds. 14 | /// 15 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureLab) 16 | #[wasm_bindgen(extends = RoomObject, extends = Structure, extends = OwnedStructure)] 17 | #[derive(Clone, Debug)] 18 | pub type StructureLab; 19 | 20 | /// The number of ticks until the [`StructureLab`] can use 21 | /// [`StructureLab::run_reaction`] or [`StructureLab::unboost_creep`] again. 22 | /// 23 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureLab.cooldown) 24 | #[wasm_bindgen(method, getter)] 25 | pub fn cooldown(this: &StructureLab) -> u32; 26 | 27 | /// The [`Store`] of the lab, which can contain energy and one type of 28 | /// resource at a time. 29 | /// 30 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureLab.store) 31 | #[wasm_bindgen(method, getter)] 32 | pub fn store(this: &StructureLab) -> Store; 33 | 34 | /// Get the type of mineral currently contained in the lab, which can only 35 | /// hold one type at a time 36 | /// 37 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureLab.mineralType) 38 | #[wasm_bindgen(method, getter = mineralType)] 39 | pub fn mineral_type(this: &StructureLab) -> Option; 40 | 41 | #[wasm_bindgen(method, js_name = boostCreep)] 42 | fn boost_creep_internal(this: &StructureLab, creep: &Creep, body_part_count: Option) 43 | -> i8; 44 | 45 | #[wasm_bindgen(method, js_name = reverseReaction)] 46 | fn reverse_reaction_internal( 47 | this: &StructureLab, 48 | lab1: &StructureLab, 49 | lab2: &StructureLab, 50 | ) -> i8; 51 | 52 | #[wasm_bindgen(method, js_name = runReaction)] 53 | fn run_reaction_internal(this: &StructureLab, lab1: &StructureLab, lab2: &StructureLab) -> i8; 54 | 55 | #[wasm_bindgen(method, js_name = unboostCreep)] 56 | fn unboost_creep_internal(this: &StructureLab, creep: &Creep) -> i8; 57 | } 58 | 59 | impl StructureLab { 60 | /// Boost a [`Creep`] in melee range, consuming [`LAB_BOOST_ENERGY`] energy 61 | /// and [`LAB_BOOST_MINERAL`] of the boost compound from the 62 | /// [`StructureLab::store`] per boosted body part. 63 | /// 64 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureLab.boostCreep) 65 | /// 66 | /// [`LAB_BOOST_ENERGY`]: crate::constants::LAB_BOOST_ENERGY 67 | /// [`LAB_BOOST_MINERAL`]: crate::constants::LAB_BOOST_MINERAL 68 | pub fn boost_creep( 69 | &self, 70 | creep: &Creep, 71 | body_part_count: Option, 72 | ) -> Result<(), BoostCreepErrorCode> { 73 | BoostCreepErrorCode::result_from_i8(self.boost_creep_internal(creep, body_part_count)) 74 | } 75 | 76 | /// Reverse a reaction, splitting the compound in this [`StructureLab`] into 77 | /// its components in two other labs. 78 | /// 79 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureLab.reverseReaction) 80 | pub fn reverse_reaction( 81 | &self, 82 | lab1: &StructureLab, 83 | lab2: &StructureLab, 84 | ) -> Result<(), ReverseReactionErrorCode> { 85 | ReverseReactionErrorCode::result_from_i8(self.reverse_reaction_internal(lab1, lab2)) 86 | } 87 | 88 | /// Run a reaction, combining components from two other [`StructureLab`]s 89 | /// into a new compound in this lab. 90 | /// 91 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureLab.runReaction) 92 | pub fn run_reaction( 93 | &self, 94 | lab1: &StructureLab, 95 | lab2: &StructureLab, 96 | ) -> Result<(), RunReactionErrorCode> { 97 | RunReactionErrorCode::result_from_i8(self.run_reaction_internal(lab1, lab2)) 98 | } 99 | 100 | /// Unboost a [`Creep`], removing all boosts from its body and dropping 101 | /// [`LAB_UNBOOST_MINERAL`] per body part on the ground, with a cooldown 102 | /// equal to the total time to produce the removed boosts. 103 | /// 104 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureLab.unboostCreep) 105 | /// 106 | /// [`LAB_UNBOOST_MINERAL`]: crate::constants::LAB_UNBOOST_MINERAL 107 | pub fn unboost_creep(&self, creep: &Creep) -> Result<(), UnboostCreepErrorCode> { 108 | UnboostCreepErrorCode::result_from_i8(self.unboost_creep_internal(creep)) 109 | } 110 | } 111 | 112 | impl HasCooldown for StructureLab { 113 | fn cooldown(&self) -> u32 { 114 | Self::cooldown(self) 115 | } 116 | } 117 | 118 | impl HasStore for StructureLab { 119 | fn store(&self) -> Store { 120 | Self::store(self) 121 | } 122 | } 123 | 124 | impl Attackable for StructureLab {} 125 | impl Dismantleable for StructureLab {} 126 | impl Repairable for StructureLab {} 127 | impl Transferable for StructureLab {} 128 | impl Withdrawable for StructureLab {} 129 | -------------------------------------------------------------------------------- /src/objects/impls/structure_link.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | use crate::{ 4 | enums::action_error_codes::structure_link::*, 5 | objects::{OwnedStructure, RoomObject, Store, Structure}, 6 | prelude::*, 7 | }; 8 | 9 | #[wasm_bindgen] 10 | extern "C" { 11 | /// An object representing a [`StructureLink`], which can hold energy and 12 | /// transfer it to other links within the room. 13 | /// 14 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureLink) 15 | #[wasm_bindgen(extends = RoomObject, extends = Structure, extends = OwnedStructure)] 16 | #[derive(Clone, Debug)] 17 | pub type StructureLink; 18 | 19 | /// The number of ticks until the [`StructureLink`] can use 20 | /// [`StructureLink::transfer`] again. 21 | /// 22 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureLink.cooldown) 23 | #[wasm_bindgen(method, getter)] 24 | pub fn cooldown(this: &StructureLink) -> u32; 25 | 26 | /// The [`Store`] of the extension, which contains information about the 27 | /// amount of energy in it. 28 | /// 29 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureLink.store) 30 | #[wasm_bindgen(method, getter)] 31 | pub fn store(this: &StructureLink) -> Store; 32 | 33 | #[wasm_bindgen(method, js_name = transferEnergy)] 34 | fn transfer_energy_internal( 35 | this: &StructureLink, 36 | target: &StructureLink, 37 | amount: Option, 38 | ) -> i8; 39 | } 40 | 41 | impl StructureLink { 42 | /// Transfer energy from this [`StructureLink`] to another, losing 43 | /// [`LINK_LOSS_RATIO`] percent of the energt and incurring a cooldown of 44 | /// [`LINK_COOLDOWN`] tick per range to the target. 45 | /// 46 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureLink.transferEnergy) 47 | /// 48 | /// [`LINK_LOSS_RATIO`]: crate::constants::LINK_LOSS_RATIO 49 | /// [`LINK_COOLDOWN`]: crate::constants::LINK_COOLDOWN 50 | pub fn transfer_energy( 51 | &self, 52 | target: &StructureLink, 53 | amount: Option, 54 | ) -> Result<(), TransferEnergyErrorCode> { 55 | TransferEnergyErrorCode::result_from_i8(self.transfer_energy_internal(target, amount)) 56 | } 57 | } 58 | 59 | impl HasCooldown for StructureLink { 60 | fn cooldown(&self) -> u32 { 61 | Self::cooldown(self) 62 | } 63 | } 64 | 65 | impl HasStore for StructureLink { 66 | fn store(&self) -> Store { 67 | Self::store(self) 68 | } 69 | } 70 | 71 | impl Attackable for StructureLink {} 72 | impl Dismantleable for StructureLink {} 73 | impl Repairable for StructureLink {} 74 | impl Transferable for StructureLink {} 75 | impl Withdrawable for StructureLink {} 76 | -------------------------------------------------------------------------------- /src/objects/impls/structure_nuker.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | use crate::{ 4 | enums::action_error_codes::structure_nuker::*, 5 | objects::{OwnedStructure, RoomObject, RoomPosition, Store, Structure}, 6 | prelude::*, 7 | }; 8 | 9 | #[wasm_bindgen] 10 | extern "C" { 11 | /// An object representing a [`StructureNuker`], which consumes energy and 12 | /// ghodium to fire [`Nuke`]s. 13 | /// 14 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureNuker) 15 | /// 16 | /// [`Nuke`]: crate::objects::Nuke 17 | #[wasm_bindgen(extends = RoomObject, extends = Structure, extends = OwnedStructure)] 18 | #[derive(Clone, Debug)] 19 | pub type StructureNuker; 20 | 21 | /// The number of ticks until the [`StructureNuker`] can use 22 | /// [`StructureNuker::launch_nuke`] again. 23 | /// 24 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureNuker.cooldown) 25 | #[wasm_bindgen(method, getter)] 26 | pub fn cooldown(this: &StructureNuker) -> u32; 27 | 28 | /// The [`Store`] of the nuker, which can have energy and ghodium 29 | /// transferred in (but not withdrawn). 30 | /// 31 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureNuker.store) 32 | #[wasm_bindgen(method, getter)] 33 | pub fn store(this: &StructureNuker) -> Store; 34 | 35 | #[wasm_bindgen(method, js_name = launchNuke)] 36 | fn launch_nuke_internal(this: &StructureNuker, target: &RoomPosition) -> i8; 37 | } 38 | 39 | impl StructureNuker { 40 | /// Launch a nuke at a target [`RoomPosition`]. 41 | /// 42 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureNuker.launchNuke) 43 | pub fn launch_nuke(&self, target: &RoomPosition) -> Result<(), LaunchNukeErrorCode> { 44 | LaunchNukeErrorCode::result_from_i8(self.launch_nuke_internal(target)) 45 | } 46 | } 47 | 48 | impl HasCooldown for StructureNuker { 49 | fn cooldown(&self) -> u32 { 50 | Self::cooldown(self) 51 | } 52 | } 53 | 54 | impl HasStore for StructureNuker { 55 | fn store(&self) -> Store { 56 | Self::store(self) 57 | } 58 | } 59 | 60 | impl Attackable for StructureNuker {} 61 | impl Dismantleable for StructureNuker {} 62 | impl Repairable for StructureNuker {} 63 | impl Transferable for StructureNuker {} 64 | -------------------------------------------------------------------------------- /src/objects/impls/structure_observer.rs: -------------------------------------------------------------------------------- 1 | use js_sys::JsString; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{ 5 | enums::action_error_codes::structure_observer::*, 6 | local::RoomName, 7 | objects::{OwnedStructure, RoomObject, Structure}, 8 | prelude::*, 9 | }; 10 | 11 | #[wasm_bindgen] 12 | extern "C" { 13 | /// An object representing a [`StructureObserver`], which can grant vision 14 | /// to remote rooms. 15 | /// 16 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureObserver) 17 | #[wasm_bindgen(extends = RoomObject, extends = Structure, extends = OwnedStructure)] 18 | #[derive(Clone, Debug)] 19 | pub type StructureObserver; 20 | 21 | #[wasm_bindgen(method, js_name = observeRoom)] 22 | fn observe_room_internal(this: &StructureObserver, target: &JsString) -> i8; 23 | } 24 | 25 | impl StructureObserver { 26 | /// Set the [`StructureObserver`] to provide vision of a target room next 27 | /// tick. 28 | /// 29 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureObserver.observeRoom) 30 | pub fn observe_room(&self, target: RoomName) -> Result<(), ObserveRoomErrorCode> { 31 | let target = target.into(); 32 | 33 | ObserveRoomErrorCode::result_from_i8(self.observe_room_internal(&target)) 34 | } 35 | } 36 | 37 | impl Attackable for StructureObserver {} 38 | impl Dismantleable for StructureObserver {} 39 | impl Repairable for StructureObserver {} 40 | -------------------------------------------------------------------------------- /src/objects/impls/structure_portal.rs: -------------------------------------------------------------------------------- 1 | use js_sys::JsString; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{ 5 | local::{Position, RoomName}, 6 | objects::{RoomObject, RoomPosition, Structure}, 7 | prelude::*, 8 | }; 9 | 10 | #[wasm_bindgen] 11 | extern "C" { 12 | /// An object representing a [`StructurePortal`], which allows movement 13 | /// between remote locations or other shards. 14 | /// 15 | /// [Screeps documentation](https://docs.screeps.com/api/#StructurePortal) 16 | #[wasm_bindgen(extends = RoomObject, extends = Structure)] 17 | #[derive(Clone, Debug)] 18 | pub type StructurePortal; 19 | 20 | #[wasm_bindgen(method, getter = destination)] 21 | fn destination_internal(this: &StructurePortal) -> JsValue; 22 | 23 | /// The number of ticks until the portal will decay, if it's unstable, or 0 24 | /// if it's stable. 25 | /// 26 | /// [Screeps documentation](https://docs.screeps.com/api/#StructurePortal.ticksToDecay) 27 | #[wasm_bindgen(method, getter = ticksToDecay)] 28 | pub fn ticks_to_decay(this: &StructurePortal) -> u32; 29 | } 30 | 31 | impl StructurePortal { 32 | pub fn destination(&self) -> PortalDestination { 33 | let dest = Self::destination_internal(self); 34 | match dest.dyn_ref::() { 35 | Some(room_pos) => PortalDestination::InterRoom(room_pos.into()), 36 | None => PortalDestination::InterShard(dest.unchecked_into()), 37 | } 38 | } 39 | } 40 | 41 | impl CanDecay for StructurePortal { 42 | fn ticks_to_decay(&self) -> u32 { 43 | Self::ticks_to_decay(self) 44 | } 45 | } 46 | 47 | pub enum PortalDestination { 48 | InterRoom(Position), 49 | InterShard(InterShardPortalDestination), 50 | } 51 | 52 | #[wasm_bindgen] 53 | extern "C" { 54 | /// An object which contains the destination shard and room of an 55 | /// inter-shard portal. 56 | /// 57 | /// [Screeps documentation](https://docs.screeps.com/api/#StructurePortal.destination) 58 | #[wasm_bindgen] 59 | pub type InterShardPortalDestination; 60 | 61 | #[wasm_bindgen(method, getter = room)] 62 | fn room_internal(this: &InterShardPortalDestination) -> JsString; 63 | 64 | #[wasm_bindgen(method, getter)] 65 | pub fn shard(this: &InterShardPortalDestination) -> String; 66 | } 67 | 68 | impl InterShardPortalDestination { 69 | pub fn room(&self) -> RoomName { 70 | Self::room_internal(self) 71 | .try_into() 72 | .expect("expected parseable room name") 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/objects/impls/structure_power_bank.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | use crate::{ 4 | objects::{RoomObject, Structure}, 5 | prelude::*, 6 | }; 7 | 8 | #[wasm_bindgen] 9 | extern "C" { 10 | /// An object representing a [`StructurePowerBank`], which can be destroyed 11 | /// for power resources. 12 | /// 13 | /// [Screeps documentation](https://docs.screeps.com/api/#StructurePowerBank) 14 | #[wasm_bindgen(extends = RoomObject, extends = Structure)] 15 | #[derive(Clone, Debug)] 16 | pub type StructurePowerBank; 17 | 18 | /// The amount of power contained within the [`StructurePowerBank`]. 19 | /// 20 | /// [Screeps documentation](https://docs.screeps.com/api/#StructurePowerBank.power) 21 | #[wasm_bindgen(method, getter)] 22 | pub fn power(this: &StructurePowerBank) -> u32; 23 | 24 | /// The number of ticks until the [`StructurePowerBank`] will decay. 25 | /// 26 | /// [Screeps documentation](https://docs.screeps.com/api/#StructurePowerBank.ticksToDecay) 27 | #[wasm_bindgen(method, getter = ticksToDecay)] 28 | pub fn ticks_to_decay(this: &StructurePowerBank) -> u32; 29 | } 30 | 31 | impl CanDecay for StructurePowerBank { 32 | fn ticks_to_decay(&self) -> u32 { 33 | Self::ticks_to_decay(self) 34 | } 35 | } 36 | 37 | impl Attackable for StructurePowerBank {} 38 | impl Dismantleable for StructurePowerBank {} 39 | impl Repairable for StructurePowerBank {} 40 | -------------------------------------------------------------------------------- /src/objects/impls/structure_power_spawn.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | use crate::{ 4 | enums::action_error_codes::structure_powerspawn::*, 5 | objects::{OwnedStructure, RoomObject, Store, Structure}, 6 | prelude::*, 7 | }; 8 | 9 | #[wasm_bindgen] 10 | extern "C" { 11 | /// An object representing a [`StructurePowerSpawn`], which can process 12 | /// power to contribute to your GPL as well as renewing power creeps. 13 | /// 14 | /// [Screeps documentation](https://docs.screeps.com/api/#StructurePowerSpawn) 15 | #[wasm_bindgen(extends = RoomObject, extends = Structure, extends = OwnedStructure)] 16 | #[derive(Clone, Debug)] 17 | pub type StructurePowerSpawn; 18 | 19 | /// The [`Store`] of the power spawn, which can contain power and energy. 20 | /// 21 | /// [Screeps documentation](https://docs.screeps.com/api/#StructurePowerSpawn.store) 22 | #[wasm_bindgen(method, getter)] 23 | pub fn store(this: &StructurePowerSpawn) -> Store; 24 | 25 | /// Process power, consuming 1 power and [`POWER_SPAWN_ENERGY_RATIO`] energy 26 | /// and increasing your GPL by one point. 27 | /// 28 | /// [Screeps documentation](https://docs.screeps.com/api/#StructurePowerSpawn.processPower) 29 | /// 30 | /// [`POWER_SPAWN_ENERGY_RATIO`]: 31 | /// crate::constants::numbers::POWER_SPAWN_ENERGY_RATIO 32 | #[wasm_bindgen(method, js_name = processPower)] 33 | fn process_power_internal(this: &StructurePowerSpawn) -> i8; 34 | } 35 | 36 | impl StructurePowerSpawn { 37 | /// Process power, consuming 1 power and [`POWER_SPAWN_ENERGY_RATIO`] energy 38 | /// and increasing your GPL by one point. 39 | /// 40 | /// [Screeps documentation](https://docs.screeps.com/api/#StructurePowerSpawn.processPower) 41 | /// 42 | /// [`POWER_SPAWN_ENERGY_RATIO`]: crate::constants::POWER_SPAWN_ENERGY_RATIO 43 | pub fn process_power(&self) -> Result<(), ProcessPowerErrorCode> { 44 | ProcessPowerErrorCode::result_from_i8(self.process_power_internal()) 45 | } 46 | } 47 | 48 | impl HasStore for StructurePowerSpawn { 49 | fn store(&self) -> Store { 50 | Self::store(self) 51 | } 52 | } 53 | 54 | impl Attackable for StructurePowerSpawn {} 55 | impl Dismantleable for StructurePowerSpawn {} 56 | impl Repairable for StructurePowerSpawn {} 57 | impl Transferable for StructurePowerSpawn {} 58 | impl Withdrawable for StructurePowerSpawn {} 59 | -------------------------------------------------------------------------------- /src/objects/impls/structure_rampart.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | use crate::{ 4 | enums::action_error_codes::structure_rampart::*, 5 | objects::{OwnedStructure, RoomObject, Structure}, 6 | prelude::*, 7 | }; 8 | 9 | #[wasm_bindgen] 10 | extern "C" { 11 | /// An object representing a [`StructureRampart`], which is selectively 12 | /// walkable and protects creeps and structures at the same position. 13 | /// 14 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureRampart) 15 | #[wasm_bindgen(extends = RoomObject, extends = Structure, extends = OwnedStructure)] 16 | #[derive(Clone, Debug)] 17 | pub type StructureRampart; 18 | 19 | /// Whether the [`StructureRampart`] is set to be public, allowing hostile 20 | /// creeps to walk on it. 21 | /// 22 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureRampart.isPublic) 23 | #[wasm_bindgen(method, getter = isPublic)] 24 | pub fn is_public(this: &StructureRampart) -> bool; 25 | 26 | /// The number of ticks until the rampart will decay, losing 27 | /// [`RAMPART_DECAY_AMOUNT`] hits. 28 | /// 29 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureRampart.ticksToDecay) 30 | /// 31 | /// [`RAMPART_DECAY_AMOUNT`]: 32 | /// crate::constants::numbers::RAMPART_DECAY_AMOUNT 33 | #[wasm_bindgen(method, getter = ticksToDecay)] 34 | pub fn ticks_to_decay(this: &StructureRampart) -> u32; 35 | 36 | #[wasm_bindgen(method, js_name = setPublic)] 37 | fn set_public_internal(this: &StructureRampart, val: bool) -> i8; 38 | } 39 | 40 | impl StructureRampart { 41 | /// Set whether [`StructureRampart`] is public, allowing hostile creeps to 42 | /// walk on it. 43 | /// 44 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureRampart.setPublic) 45 | pub fn set_public(&self, public: bool) -> Result<(), SetPublicErrorCode> { 46 | SetPublicErrorCode::result_from_i8(self.set_public_internal(public)) 47 | } 48 | } 49 | 50 | impl CanDecay for StructureRampart { 51 | fn ticks_to_decay(&self) -> u32 { 52 | Self::ticks_to_decay(self) 53 | } 54 | } 55 | 56 | impl Attackable for StructureRampart {} 57 | impl Dismantleable for StructureRampart {} 58 | impl Repairable for StructureRampart {} 59 | -------------------------------------------------------------------------------- /src/objects/impls/structure_road.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | use crate::{ 4 | objects::{RoomObject, Structure}, 5 | prelude::*, 6 | }; 7 | 8 | #[wasm_bindgen] 9 | extern "C" { 10 | /// An object representing a [`StructureRoad`], which allows creeps to move 11 | /// onto this position for half of the fatigue of moving onto a plains tile, 12 | /// as well as through terrain walls. 13 | /// 14 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureRoad) 15 | #[wasm_bindgen(extends = RoomObject, extends = Structure)] 16 | #[derive(Clone, Debug)] 17 | pub type StructureRoad; 18 | 19 | /// The number of ticks until the road will decay, losing 20 | /// [`ROAD_DECAY_AMOUNT`] hits. 21 | /// 22 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureRoad.ticksToDecay) 23 | /// 24 | /// [`ROAD_DECAY_AMOUNT`]: crate::constants::ROAD_DECAY_AMOUNT 25 | #[wasm_bindgen(method, getter = ticksToDecay)] 26 | pub fn ticks_to_decay(this: &StructureRoad) -> u32; 27 | } 28 | 29 | impl CanDecay for StructureRoad { 30 | fn ticks_to_decay(&self) -> u32 { 31 | Self::ticks_to_decay(self) 32 | } 33 | } 34 | 35 | impl Attackable for StructureRoad {} 36 | impl Dismantleable for StructureRoad {} 37 | impl Repairable for StructureRoad {} 38 | -------------------------------------------------------------------------------- /src/objects/impls/structure_storage.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | use crate::{ 4 | objects::{OwnedStructure, RoomObject, Store, Structure}, 5 | prelude::*, 6 | }; 7 | 8 | #[wasm_bindgen] 9 | extern "C" { 10 | /// An object representing a [`StructureStorage`], which can store large 11 | /// amounts of resources. 12 | /// 13 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureStorage) 14 | #[wasm_bindgen(extends = RoomObject, extends = Structure, extends = OwnedStructure)] 15 | #[derive(Clone, Debug)] 16 | pub type StructureStorage; 17 | 18 | /// The [`Store`] of the storage, which contains information about what 19 | /// resources it is it holding. 20 | /// 21 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureStorage.store) 22 | #[wasm_bindgen(method, getter)] 23 | pub fn store(this: &StructureStorage) -> Store; 24 | } 25 | 26 | impl HasStore for StructureStorage { 27 | fn store(&self) -> Store { 28 | Self::store(self) 29 | } 30 | } 31 | 32 | impl Attackable for StructureStorage {} 33 | impl Dismantleable for StructureStorage {} 34 | impl Repairable for StructureStorage {} 35 | impl Transferable for StructureStorage {} 36 | impl Withdrawable for StructureStorage {} 37 | -------------------------------------------------------------------------------- /src/objects/impls/structure_terminal.rs: -------------------------------------------------------------------------------- 1 | use js_sys::JsString; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{ 5 | constants::ResourceType, 6 | enums::action_error_codes::structure_terminal::*, 7 | local::RoomName, 8 | objects::{OwnedStructure, RoomObject, Store, Structure}, 9 | prelude::*, 10 | }; 11 | 12 | #[wasm_bindgen] 13 | extern "C" { 14 | /// An object representing a [`StructureTerminal`], which can send resources 15 | /// to distant rooms and participate in the market. 16 | /// 17 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureTerminal) 18 | #[wasm_bindgen(extends = RoomObject, extends = Structure, extends = OwnedStructure)] 19 | #[derive(Clone, Debug)] 20 | pub type StructureTerminal; 21 | 22 | /// The number of ticks until the [`StructureTerminal`] can use 23 | /// [`StructureTerminal::send`] or be used in a market transaction again. 24 | /// 25 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureTerminal.cooldown) 26 | #[wasm_bindgen(method, getter)] 27 | pub fn cooldown(this: &StructureTerminal) -> u32; 28 | 29 | /// The [`Store`] of the terminal, which contains information about what 30 | /// resources it is it holding. 31 | /// 32 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureTerminal.store) 33 | #[wasm_bindgen(method, getter)] 34 | pub fn store(this: &StructureTerminal) -> Store; 35 | 36 | #[wasm_bindgen(method, js_name = send)] 37 | fn send_internal( 38 | this: &StructureTerminal, 39 | resource_type: ResourceType, 40 | amount: u32, 41 | destination: &JsString, 42 | description: Option<&JsString>, 43 | ) -> i8; 44 | } 45 | 46 | impl StructureTerminal { 47 | /// Send resources to another room's terminal. 48 | /// 49 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureTerminal.send) 50 | pub fn send( 51 | &self, 52 | resource_type: ResourceType, 53 | amount: u32, 54 | destination: RoomName, 55 | description: Option<&str>, 56 | ) -> Result<(), SendErrorCode> { 57 | let desination = destination.into(); 58 | let description = description.map(JsString::from); 59 | 60 | SendErrorCode::result_from_i8(self.send_internal( 61 | resource_type, 62 | amount, 63 | &desination, 64 | description.as_ref(), 65 | )) 66 | } 67 | } 68 | 69 | impl HasCooldown for StructureTerminal { 70 | fn cooldown(&self) -> u32 { 71 | Self::cooldown(self) 72 | } 73 | } 74 | 75 | impl HasStore for StructureTerminal { 76 | fn store(&self) -> Store { 77 | Self::store(self) 78 | } 79 | } 80 | 81 | impl Attackable for StructureTerminal {} 82 | impl Dismantleable for StructureTerminal {} 83 | impl Repairable for StructureTerminal {} 84 | impl Transferable for StructureTerminal {} 85 | impl Withdrawable for StructureTerminal {} 86 | -------------------------------------------------------------------------------- /src/objects/impls/structure_tower.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | use crate::{ 4 | enums::action_error_codes::structure_tower::*, 5 | objects::{OwnedStructure, RoomObject, Store, Structure}, 6 | prelude::*, 7 | }; 8 | 9 | #[wasm_bindgen] 10 | extern "C" { 11 | /// An object representing a [`StructureTower`], which can heal, repair, or 12 | /// attack anywhere in the room. 13 | /// 14 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureTower) 15 | #[wasm_bindgen(extends = RoomObject, extends = Structure, extends = OwnedStructure)] 16 | #[derive(Clone, Debug)] 17 | pub type StructureTower; 18 | 19 | /// The [`Store`] of the tower, which contains energy which is consumed when 20 | /// it takes actions. 21 | /// 22 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureTower.store) 23 | #[wasm_bindgen(method, getter)] 24 | pub fn store(this: &StructureTower) -> Store; 25 | 26 | #[wasm_bindgen(method, js_name = attack)] 27 | fn attack_internal(this: &StructureTower, target: &RoomObject) -> i8; 28 | 29 | #[wasm_bindgen(method, js_name = heal)] 30 | fn heal_internal(this: &StructureTower, target: &RoomObject) -> i8; 31 | 32 | #[wasm_bindgen(method, js_name = repair)] 33 | fn repair_internal(this: &StructureTower, target: &Structure) -> i8; 34 | } 35 | 36 | impl StructureTower { 37 | /// Attack a [`Creep`], [`PowerCreep`], or [`Structure`] in the room, 38 | /// dealing damage depending on range. 39 | /// 40 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureTower.attack) 41 | /// 42 | /// [`Creep`]: crate::objects::Creep 43 | /// [`PowerCreep`]: crate::objects::PowerCreep 44 | pub fn attack(&self, target: &T) -> Result<(), TowerAttackErrorCode> 45 | where 46 | T: ?Sized + Attackable, 47 | { 48 | TowerAttackErrorCode::result_from_i8(self.attack_internal(target.as_ref())) 49 | } 50 | 51 | /// Heal a [`Creep`] or [`PowerCreep`] in the room, adding hit points 52 | /// depending on range. 53 | /// 54 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureTower.heal) 55 | /// 56 | /// [`Creep`]: crate::objects::Creep 57 | /// [`PowerCreep`]: crate::objects::PowerCreep 58 | pub fn heal(&self, target: &T) -> Result<(), TowerHealErrorCode> 59 | where 60 | T: ?Sized + Healable, 61 | { 62 | TowerHealErrorCode::result_from_i8(self.heal_internal(target.as_ref())) 63 | } 64 | 65 | /// Repair a [`Structure`] in the room, adding hit points depending on 66 | /// range. 67 | /// 68 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureTower.repair) 69 | pub fn repair(&self, target: &T) -> Result<(), TowerRepairErrorCode> 70 | where 71 | T: ?Sized + Repairable, 72 | { 73 | TowerRepairErrorCode::result_from_i8(self.repair_internal(target.as_ref())) 74 | } 75 | } 76 | 77 | impl HasStore for StructureTower { 78 | fn store(&self) -> Store { 79 | Self::store(self) 80 | } 81 | } 82 | 83 | impl Attackable for StructureTower {} 84 | impl Dismantleable for StructureTower {} 85 | impl Repairable for StructureTower {} 86 | impl Transferable for StructureTower {} 87 | impl Withdrawable for StructureTower {} 88 | -------------------------------------------------------------------------------- /src/objects/impls/structure_wall.rs: -------------------------------------------------------------------------------- 1 | use wasm_bindgen::prelude::*; 2 | 3 | use crate::{ 4 | objects::{RoomObject, Structure}, 5 | prelude::*, 6 | }; 7 | 8 | #[wasm_bindgen] 9 | extern "C" { 10 | /// An object representing a [`StructureWall`], which blocks movement of all 11 | /// creeps. 12 | /// 13 | /// [Screeps documentation](https://docs.screeps.com/api/#StructureWall) 14 | #[wasm_bindgen(extends = RoomObject, extends = Structure)] 15 | #[derive(Clone, Debug)] 16 | pub type StructureWall; 17 | } 18 | 19 | impl Attackable for StructureWall {} 20 | impl Dismantleable for StructureWall {} 21 | impl Repairable for StructureWall {} 22 | -------------------------------------------------------------------------------- /src/objects/impls/symbol_container.rs: -------------------------------------------------------------------------------- 1 | use js_sys::JsString; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{ 5 | constants::ResourceType, 6 | objects::{RoomObject, Store}, 7 | prelude::*, 8 | }; 9 | 10 | #[wasm_bindgen] 11 | extern "C" { 12 | /// An object representing a [`SymbolContainer`], which appears randomly 13 | /// around the map and contains symbol resources which can be 14 | /// collected. 15 | /// 16 | /// [Screeps documentation](https://docs-season.screeps.com/api/#SymbolContainer) 17 | /// 18 | /// [`ResourceType::Score`]: crate::constants::ResourceType::Score 19 | #[wasm_bindgen(extends = RoomObject)] 20 | #[derive(Clone, Debug)] 21 | pub type SymbolContainer; 22 | 23 | /// Object ID of the collector, which can be used to efficiently fetch a 24 | /// fresh reference to the object on subsequent ticks. 25 | /// 26 | /// [Screeps documentation](https://docs-season.screeps.com/api/#SymbolContainer.id) 27 | #[wasm_bindgen(method, getter = id)] 28 | fn id_internal(this: &SymbolContainer) -> JsString; 29 | 30 | /// The [`Store`] of the container, which contains information about what 31 | /// resources it is it holding. 32 | /// 33 | /// [Screeps documentation](https://docs-season.screeps.com/api/#SymbolContainer.store) 34 | #[wasm_bindgen(method, getter)] 35 | pub fn store(this: &SymbolContainer) -> Store; 36 | 37 | /// The number of ticks until the [`SymbolContainer`] will decay, 38 | /// disappearing completely. 39 | /// 40 | /// [Screeps documentation](https://docs-season.screeps.com/api/#SymbolContainer.ticksToDecay) 41 | #[wasm_bindgen(method, getter = ticksToDecay)] 42 | pub fn ticks_to_decay(this: &SymbolContainer) -> u32; 43 | 44 | /// The [`ResourceType`] contained within this [`SymbolContainer`] to score 45 | /// points. 46 | /// 47 | /// [Screeps documentation](https://docs-season.screeps.com/api/#SymbolContainer.resourceType) 48 | #[wasm_bindgen(method, getter = resourceType)] 49 | pub fn resource_type(this: &SymbolContainer) -> ResourceType; 50 | 51 | } 52 | 53 | impl CanDecay for SymbolContainer { 54 | fn ticks_to_decay(&self) -> u32 { 55 | Self::ticks_to_decay(self) 56 | } 57 | } 58 | 59 | impl HasId for SymbolContainer { 60 | fn js_raw_id(&self) -> JsString { 61 | Self::id_internal(self) 62 | } 63 | } 64 | 65 | impl HasStore for SymbolContainer { 66 | fn store(&self) -> Store { 67 | Self::store(self) 68 | } 69 | } 70 | 71 | impl Withdrawable for SymbolContainer {} 72 | -------------------------------------------------------------------------------- /src/objects/impls/symbol_decoder.rs: -------------------------------------------------------------------------------- 1 | use js_sys::JsString; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{constants::ResourceType, objects::RoomObject, prelude::*}; 5 | 6 | #[wasm_bindgen] 7 | extern "C" { 8 | /// An object representing a [`SymbolDecoder`], which can be used to decode 9 | /// matching symbol resources to score points on the leaderboard. 10 | /// 11 | /// [Screeps documentation](https://docs-season.screeps.com/api/#SymbolDecoder) 12 | /// 13 | /// [`ResourceType::Score`]: crate::constants::ResourceType::Score 14 | #[wasm_bindgen(extends = RoomObject)] 15 | #[derive(Clone, Debug)] 16 | pub type SymbolDecoder; 17 | 18 | /// Object ID of the collector, which can be used to efficiently fetch a 19 | /// fresh reference to the object on subsequent ticks. 20 | /// 21 | /// [Screeps documentation](https://docs-season.screeps.com/api/#SymbolDecoder.id) 22 | #[wasm_bindgen(method, getter = id)] 23 | fn id_internal(this: &SymbolDecoder) -> JsString; 24 | 25 | /// The [`ResourceType`] allowed to be transferred to this [`SymbolDecoder`] 26 | /// to score points. 27 | /// 28 | /// [Screeps documentation](https://docs-season.screeps.com/api/#SymbolDecoder.resourceType) 29 | #[wasm_bindgen(method, getter = resourceType)] 30 | pub fn resource_type(this: &SymbolDecoder) -> ResourceType; 31 | 32 | /// The multipler applied to points scored at this decoder, as determined by 33 | /// the level of the room's controller. 34 | /// 35 | /// [Screeps documentation](https://docs-season.screeps.com/api/#SymbolDecoder.scoreMultiplier) 36 | #[wasm_bindgen(method, getter = scoreMultiplier)] 37 | pub fn score_multiplier(this: &SymbolDecoder) -> u32; 38 | } 39 | 40 | impl HasId for SymbolDecoder { 41 | fn js_raw_id(&self) -> JsString { 42 | Self::id_internal(self) 43 | } 44 | } 45 | 46 | impl Transferable for SymbolDecoder {} 47 | -------------------------------------------------------------------------------- /src/objects/impls/tombstone.rs: -------------------------------------------------------------------------------- 1 | use js_sys::JsString; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{ 5 | objects::{RoomObject, Store}, 6 | prelude::*, 7 | }; 8 | 9 | #[wasm_bindgen] 10 | extern "C" { 11 | /// A [`Tombstone`], which represents a dead creep and can have resources 12 | /// withdrawn from it. 13 | /// 14 | /// [Screeps documentation](https://docs.screeps.com/api/#Tombstone) 15 | #[wasm_bindgen(extends = RoomObject)] 16 | #[derive(Clone, Debug)] 17 | pub type Tombstone; 18 | 19 | /// The dead [`Creep`] or [`PowerCreep`] that this tombstone represents. 20 | /// Note that this object is not fully safe to use, and needs to be cast 21 | /// into the correct type. 22 | /// 23 | /// [Screeps documentation](https://docs.screeps.com/api/#Tombstone.creep) 24 | #[wasm_bindgen(method, getter)] 25 | pub fn creep(this: &Tombstone) -> RoomObject; 26 | 27 | /// The tick that the creep was killed. 28 | /// 29 | /// [Screeps documentation](https://docs.screeps.com/api/#Tombstone.deathTime) 30 | #[wasm_bindgen(method, getter = deathTime)] 31 | pub fn death_time(this: &Tombstone) -> u32; 32 | 33 | /// Object ID of the tombstone, which can be used to efficiently fetch a 34 | /// fresh reference to the object on subsequent ticks. 35 | /// 36 | /// [Screeps documentation](https://docs.screeps.com/api/#Tombstone.id) 37 | #[wasm_bindgen(method, getter = id)] 38 | fn id_internal(this: &Tombstone) -> JsString; 39 | 40 | /// The [`Store`] of the tombstone, which contains any resources in the 41 | /// tombstone. 42 | /// 43 | /// [Screeps documentation](https://docs.screeps.com/api/#Tombstone.store) 44 | #[wasm_bindgen(method, getter)] 45 | pub fn store(this: &Tombstone) -> Store; 46 | 47 | /// The number of ticks until this tombstone disappears. 48 | /// 49 | /// [Screeps documentation](https://docs.screeps.com/api/#Tombstone.ticksToDecay) 50 | #[wasm_bindgen(method, getter = ticksToDecay)] 51 | pub fn ticks_to_decay(this: &Tombstone) -> u32; 52 | } 53 | 54 | impl CanDecay for Tombstone { 55 | fn ticks_to_decay(&self) -> u32 { 56 | Self::ticks_to_decay(self) 57 | } 58 | } 59 | 60 | impl HasId for Tombstone { 61 | fn js_raw_id(&self) -> JsString { 62 | Self::id_internal(self) 63 | } 64 | } 65 | 66 | impl HasStore for Tombstone { 67 | fn store(&self) -> Store { 68 | Self::store(self) 69 | } 70 | } 71 | 72 | impl Withdrawable for Tombstone {} 73 | -------------------------------------------------------------------------------- /src/prototypes.rs: -------------------------------------------------------------------------------- 1 | //! Prototypes of Screeps object types, used for constructing some object types 2 | //! without using their default constructor. 3 | use js_sys::Object; 4 | use wasm_bindgen::prelude::*; 5 | 6 | #[wasm_bindgen] 7 | extern "C" { 8 | /// The object prototype of [`RoomPosition`] objects, for use in manual 9 | /// object construction 10 | /// 11 | /// [`RoomPosition`]: crate::objects::RoomPosition 12 | #[wasm_bindgen(js_name = prototype, js_namespace = RoomPosition)] 13 | pub static ROOM_POSITION_PROTOTYPE: Object; 14 | 15 | /// The object prototype of [`CostMatrix`] objects, for use in manual object 16 | /// construction 17 | /// 18 | /// [`CostMatrix`]: crate::objects::CostMatrix 19 | #[wasm_bindgen(js_name = prototype, js_namespace = ["PathFinder", "CostMatrix"])] 20 | pub static COST_MATRIX_PROTOTYPE: Object; 21 | } 22 | -------------------------------------------------------------------------------- /src/raw_memory.rs: -------------------------------------------------------------------------------- 1 | //! Interface for Screeps [`RawMemory`] global object. 2 | //! 3 | //! This is available as an alternative to the `Memory` object in the js heap, 4 | //! which itself is just a light wrapper around serializing into and 5 | //! deserializing JSON into [`RawMemory`]. String data stored can be retrieved 6 | //! after the running bot code is restarted (either by the server or by a new 7 | //! version of the code being uploaded) and decoded using serde or another 8 | //! option. 9 | //! 10 | //! Also contains functions for accessing memory segments and other 11 | //! players' active foreign segments. 12 | //! 13 | //! [`RawMemory`]: https://docs.screeps.com/api/#RawMemory 14 | use js_sys::{Array, JsString, Object}; 15 | 16 | use wasm_bindgen::prelude::*; 17 | 18 | use crate::prelude::*; 19 | 20 | #[wasm_bindgen] 21 | extern "C" { 22 | type RawMemory; 23 | 24 | #[wasm_bindgen(static_method_of = RawMemory, getter = segments)] 25 | fn segments() -> Object; 26 | 27 | #[wasm_bindgen(static_method_of = RawMemory, getter = foreignSegment)] 28 | fn foreign_segment() -> Option; 29 | 30 | #[wasm_bindgen(static_method_of = RawMemory)] 31 | fn get() -> JsString; 32 | 33 | #[wasm_bindgen(static_method_of = RawMemory)] 34 | fn set(val: &JsString); 35 | 36 | #[wasm_bindgen(static_method_of = RawMemory, js_name = setActiveSegments)] 37 | fn set_active_segments(segment_ids: &Array); 38 | 39 | #[wasm_bindgen(static_method_of = RawMemory, js_name = setActiveForeignSegment)] 40 | fn set_active_foreign_segment(username: &JsString, segment_id: Option); 41 | 42 | #[wasm_bindgen(static_method_of = RawMemory, js_name = setDefaultPublicSegment)] 43 | fn set_default_public_segment(segment_id: JsValue); 44 | 45 | #[wasm_bindgen(static_method_of = RawMemory, js_name = setPublicSegments)] 46 | fn set_public_segments(segment_ids: &Array); 47 | } 48 | 49 | /// Get a [`JsHashMap`] with all of the segments requested on 50 | /// the previous tick, with segment numbers as keys and segment data in 51 | /// [`String`] form as values. 52 | /// 53 | /// [Screeps documentation](https://docs.screeps.com/api/#RawMemory.segments) 54 | pub fn segments() -> JsHashMap { 55 | RawMemory::segments().into() 56 | } 57 | 58 | /// Get a [`JsHashMap`] with all of the segments requested on 59 | /// the previous tick, with segment numbers as keys and segment data in 60 | /// [`JsString`] form as values. 61 | /// 62 | /// [Screeps documentation](https://docs.screeps.com/api/#RawMemory.segments) 63 | pub fn segments_jsstring() -> JsHashMap { 64 | RawMemory::segments().into() 65 | } 66 | 67 | /// Get the foreign memory segment belonging to another player requested 68 | /// last tick. 69 | /// 70 | /// [Screeps documentation](https://docs.screeps.com/api/#RawMemory.foreignSegment) 71 | pub fn foreign_segment() -> Option { 72 | RawMemory::foreign_segment() 73 | } 74 | 75 | /// Get the stored serialized memory as a [`JsString`]. 76 | /// 77 | /// [Screeps documentation](https://docs.screeps.com/api/#RawMemory.get) 78 | pub fn get() -> JsString { 79 | RawMemory::get() 80 | } 81 | 82 | /// Overwrite the stored memory with a new [`JsString`]. Maximum allowed 83 | /// size [`MEMORY_SIZE_LIMIT`] UTF-16 units. 84 | /// 85 | /// [Screeps documentation](https://docs.screeps.com/api/#RawMemory.set) 86 | /// 87 | /// [`MEMORY_SIZE_LIMIT`]: crate::constants::MEMORY_SIZE_LIMIT 88 | pub fn set(val: &JsString) { 89 | RawMemory::set(val) 90 | } 91 | 92 | /// Sets available memory segments for the next tick, as an array of numbers 93 | /// from 0 to 99 (max of 10 segments allowed). 94 | /// 95 | /// [Screeps documentation](https://docs.screeps.com/api/#RawMemory.setActiveSegments) 96 | pub fn set_active_segments(segment_ids: &[u8]) { 97 | let segment_ids: Array = segment_ids 98 | .iter() 99 | .map(|s| *s as f64) 100 | .map(JsValue::from_f64) 101 | .collect(); 102 | 103 | RawMemory::set_active_segments(&segment_ids) 104 | } 105 | 106 | /// Sets available foreign memory segment for the next tick to a memory 107 | /// segment marked as public by another user. If no id is passed, the user's 108 | /// default public segment is retrieved. 109 | /// 110 | /// [Screeps documentation](https://docs.screeps.com/api/#RawMemory.setActiveForeignSegment) 111 | pub fn set_active_foreign_segment(username: &JsString, segment_id: Option) { 112 | RawMemory::set_active_foreign_segment(username, segment_id) 113 | } 114 | 115 | /// Sets your default foreign memory segment for other players to read, or 116 | /// remove your public segment with `None`. 117 | /// 118 | /// [Screeps documentation](https://docs.screeps.com/api/#RawMemory.setDefaultPublicSegment) 119 | pub fn set_default_public_segment(segment_id: Option) { 120 | RawMemory::set_default_public_segment( 121 | segment_id 122 | .map(|f| JsValue::from_f64(f as f64)) 123 | .unwrap_or(JsValue::NULL), 124 | ) 125 | } 126 | 127 | /// Sets which of your memory segments are readable to other players as 128 | /// foreign segments, overriding previous settings. 129 | /// 130 | /// [Screeps documentation](https://docs.screeps.com/api/#RawMemory.setPublicSegments) 131 | pub fn set_public_segments(segment_ids: &[u8]) { 132 | let segment_ids: Array = segment_ids 133 | .iter() 134 | .map(|s| *s as f64) 135 | .map(JsValue::from_f64) 136 | .collect(); 137 | 138 | RawMemory::set_public_segments(&segment_ids) 139 | } 140 | 141 | #[wasm_bindgen] 142 | extern "C" { 143 | /// The data from another user's foreign memory segment, which can be 144 | /// retrieved by [`foreign_segment`], after being requested on the previous 145 | /// tick by [`set_active_foreign_segment`]. 146 | #[wasm_bindgen] 147 | pub type ForeignSegment; 148 | #[wasm_bindgen(method, getter)] 149 | pub fn username(this: &ForeignSegment) -> JsString; 150 | #[wasm_bindgen(method, getter)] 151 | pub fn id(this: &ForeignSegment) -> u8; 152 | #[wasm_bindgen(method, getter)] 153 | pub fn data(this: &ForeignSegment) -> JsString; 154 | } 155 | --------------------------------------------------------------------------------