screeps-game-api 0.21.0

WASM bindings to the in-game Screeps API
Documentation
//! Traits associated with how specific [game objects] can be used.
//!
//! [game objects]: crate::objects
use std::str::FromStr;

use enum_dispatch::enum_dispatch;
use js_sys::{Array, JsString};
use wasm_bindgen::prelude::*;

use crate::{
    constants::*,
    enums::*,
    local::{ObjectId, Position, RawObjectId, RoomName, RoomXY},
    objects::*,
    pathfinder::SingleRoomCostResult,
    prelude::*,
};

pub trait FromReturnCode {
    type Error;

    fn result_from_i8(val: i8) -> Result<(), Self::Error>;

    fn try_result_from_i8(val: i8) -> Option<Result<(), Self::Error>>;

    fn try_result_from_jsvalue(val: &JsValue) -> Option<Result<(), Self::Error>> {
        val.as_f64().and_then(|f| Self::try_result_from_i8(f as i8))
    }
}

#[enum_dispatch]
pub trait HasHits {
    /// Retrieve the current hits of this object.
    fn hits(&self) -> u32;

    /// Retrieve the maximum hits of this object.
    fn hits_max(&self) -> u32;
}

#[enum_dispatch]
pub trait CanDecay {
    /// The number of ticks until the object will decay, losing hits.
    fn ticks_to_decay(&self) -> u32;
}

#[enum_dispatch]
pub trait HasCooldown {
    /// The number of ticks until the object can be used again.
    fn cooldown(&self) -> u32;
}

/// Trait for all game objects which have an associated unique identifier.
pub trait HasId: MaybeHasId {
    /// Object ID of the object stored in Rust memory, which can be used to
    /// efficiently fetch a fresh reference to the object on subsequent
    /// ticks.
    fn id(&self) -> ObjectId<Self>
    where
        Self: Sized,
    {
        self.raw_id().into()
    }

    /// Object ID of the object stored in Rust memory, without its associated
    /// type information.
    fn raw_id(&self) -> RawObjectId {
        let id: String = self.js_raw_id().into();

        RawObjectId::from_str(&id).expect("expected object ID to be parseable")
    }

    /// Object ID of the object stored in JavaScript memory, which can be used
    /// to efficiently fetch a fresh reference to the object on subsequent
    /// ticks.
    fn js_id(&self) -> JsObjectId<Self>
    where
        Self: Sized,
    {
        self.js_raw_id().into()
    }

    /// Object ID of the object stored in JavaScript memory, without its
    /// associated type information.
    fn js_raw_id(&self) -> JsString;
}

/// Trait for all game objects which may (or may not) have an associated unique
/// identifier.
pub trait MaybeHasId {
    /// Object ID of the object, which can be used to efficiently fetch a
    /// fresh reference to the object on subsequent ticks, or `None` if the
    /// object doesn't currently have an ID.
    fn try_id(&self) -> Option<ObjectId<Self>>
    where
        Self: Sized,
    {
        self.try_raw_id().map(Into::into)
    }

    /// Object ID of the object, without its associated type information, or
    /// `None` if the object doesn't currently have an ID.
    fn try_raw_id(&self) -> Option<RawObjectId> {
        self.try_js_raw_id()
            .map(String::from)
            .map(|id| RawObjectId::from_str(&id).expect("expected object ID to be parseable"))
    }

    /// Object ID of the object stored in JavaScript memory, which can be used
    /// to efficiently fetch a fresh reference to the object on subsequent
    /// ticks, or `None` if the object doesn't currently have an ID.
    fn try_js_id(&self) -> Option<JsObjectId<Self>>
    where
        Self: Sized,
    {
        self.try_js_raw_id().map(Into::into)
    }

    /// Object ID of the object stored in JavaScript memory, without its
    /// associated type information, or `None` if the object doesn't currently
    /// have an ID.
    fn try_js_raw_id(&self) -> Option<JsString>;
}

impl<T> MaybeHasId for T
where
    T: HasId,
{
    fn try_js_raw_id(&self) -> Option<JsString> {
        Some(self.js_raw_id())
    }
}

#[enum_dispatch]
pub trait HasPosition {
    /// Position of the object.
    fn pos(&self) -> Position;
}

#[enum_dispatch]
pub trait MaybeHasPosition {
    /// Position of the object, or `None` if the object is a power creep not
    /// spawned on the current shard.
    fn try_pos(&self) -> Option<Position>;
}

pub trait CostMatrixSet {
    fn set_xy(&mut self, xy: RoomXY, cost: u8);
}

pub trait CostMatrixGet {
    fn get_xy(&mut self, xy: RoomXY) -> u8;
}

#[enum_dispatch]
pub trait HasStore {
    /// The store of the object, containing information about the resources it
    /// is holding.
    fn store(&self) -> Store;
}

#[enum_dispatch]
pub trait OwnedStructureProperties {
    /// Whether this structure is owned by the player.
    ///
    /// [Screeps documentation](https://docs.screeps.com/api/#OwnedStructure.my)
    fn my(&self) -> bool;

    /// The [`Owner`] of this structure that contains the owner's username, or
    /// `None` if it's an ownable structure currently not under a player's
    /// control.
    ///
    /// [Screeps documentation](https://docs.screeps.com/api/#OwnedStructure.owner)
    fn owner(&self) -> Option<Owner>;
}

#[enum_dispatch]
pub trait RoomObjectProperties {
    /// Effects applied to the object.
    ///
    /// [Screeps documentation](https://docs.screeps.com/api/#RoomObject.effects)
    fn effects(&self) -> Vec<Effect>;

    /// Effects applied to the object.
    ///
    /// [Screeps documentation](https://docs.screeps.com/api/#RoomObject.effects)
    fn effects_raw(&self) -> Option<Array>;

    /// A link to the room that the object is currently in, or `None` if the
    /// object is a power creep not spawned on the current shard, or a flag or
    /// construction site not in a visible room.
    ///
    /// [Screeps documentation](https://docs.screeps.com/api/#RoomObject.room)
    fn room(&self) -> Option<Room>;
}

#[enum_dispatch]
pub trait SharedCreepProperties {
    /// A shortcut to the part of the `Memory` tree used for this creep by
    /// default
    fn memory(&self) -> JsValue;

    /// Sets a new value to the memory object shortcut for this creep.
    fn set_memory(&self, val: &JsValue);

    /// Whether this creep is owned by the player.
    fn my(&self) -> bool;

    /// The creep's name as a [`String`].
    ///
    /// [Screeps documentation](https://docs.screeps.com/api/#Creep.name)
    fn name(&self) -> String;

    /// The creep's name as a [`JsString`].
    ///
    /// [Screeps documentation](https://docs.screeps.com/api/#Creep.name)
    fn name_jsstring(&self) -> JsString;

    /// The [`Owner`] of this creep that contains the owner's username.
    fn owner(&self) -> Owner;

    /// What the creep said last tick.
    fn saying(&self) -> Option<JsString>;

    /// The number of ticks the creep has left to live.
    fn ticks_to_live(&self) -> Option<u32>;

    /// Cancel an a successfully called creep function from earlier in the tick,
    /// with a [`JsString`] that must contain the JS version of the function
    /// name.
    fn cancel_order(&self, target: &JsString) -> Result<(), ErrorCode>;

    /// Drop a resource on the ground from the creep's [`Store`].
    fn drop(&self, ty: ResourceType, amount: Option<u32>) -> Result<(), ErrorCode>;

    /// Move one square in the specified direction.
    fn move_direction(&self, direction: Direction) -> Result<(), ErrorCode>;

    /// Move the creep along a previously determined path returned from a
    /// pathfinding function, in array or serialized string form.
    fn move_by_path(&self, path: &JsValue) -> Result<(), ErrorCode>;

    /// Move the creep toward the specified goal, either a [`RoomPosition`] or
    /// [`RoomObject`]. Note that using this function will store data in
    /// `Memory.creeps[creep_name]` and enable the default serialization
    /// behavior of the `Memory` object, which may hamper attempts to directly
    /// use `RawMemory`.
    fn move_to<T>(&self, target: T) -> Result<(), ErrorCode>
    where
        T: HasPosition;

    /// Move the creep toward the specified goal, either a [`RoomPosition`] or
    /// [`RoomObject`]. Note that using this function will store data in
    /// `Memory.creeps[creep_name]` and enable the default serialization
    /// behavior of the `Memory` object, which may hamper attempts to directly
    /// use `RawMemory`.
    fn move_to_with_options<T, F>(
        &self,
        target: T,
        options: Option<MoveToOptions<F>>,
    ) -> Result<(), ErrorCode>
    where
        T: HasPosition,
        F: FnMut(RoomName, CostMatrix) -> SingleRoomCostResult;

    /// Whether to send an email notification when this creep is attacked.
    fn notify_when_attacked(&self, enabled: bool) -> Result<(), ErrorCode>;

    /// Pick up a [`Resource`] in melee range (or at the same position as the
    /// creep).
    fn pickup(&self, target: &Resource) -> Result<(), ErrorCode>;

    /// Display a string in a bubble above the creep next tick. 10 character
    /// limit.
    fn say(&self, message: &str, public: bool) -> Result<(), ErrorCode>;

    /// Immediately kill the creep.
    fn suicide(&self) -> Result<(), ErrorCode>;

    /// Transfer a resource from the creep's store to [`Structure`],
    /// [`PowerCreep`], or another [`Creep`].
    fn transfer<T>(
        &self,
        target: &T,
        ty: ResourceType,
        amount: Option<u32>,
    ) -> Result<(), ErrorCode>
    where
        T: Transferable + ?Sized;

    /// Withdraw a resource from a [`Structure`], [`Tombstone`], or [`Ruin`].
    fn withdraw<T>(
        &self,
        target: &T,
        ty: ResourceType,
        amount: Option<u32>,
    ) -> Result<(), ErrorCode>
    where
        T: Withdrawable + ?Sized;
}

#[enum_dispatch]
pub trait StructureProperties {
    fn structure_type(&self) -> StructureType;

    fn destroy(&self) -> Result<(), ErrorCode>;

    fn is_active(&self) -> bool;

    fn notify_when_attacked(&self, val: bool) -> Result<(), ErrorCode>;
}

/// Trait for all wrappers over Screeps JavaScript objects which can be the
/// target of `Creep.transfer`.
///
/// # Contracts
///
/// The reference returned from `AsRef<RoomObject>::as_ref` must be a valid
/// target for `Creep.transfer`.
#[enum_dispatch]
pub trait Transferable: AsRef<RoomObject> {}

/// Trait for all wrappers over Screeps JavaScript objects which can be the
/// target of `Creep.withdraw`.
///
/// # Contracts
///
/// The reference returned from `AsRef<RoomObject>::as_ref` must be a valid
/// target for `Creep.withdraw`.
pub trait Withdrawable: AsRef<RoomObject> {}

/// Trait for all wrappers over Screeps JavaScript objects which can be the
/// target of `Creep.harvest`.
///
/// # Contracts
///
/// The reference returned from `AsRef<RoomObject>::as_ref` must be a valid
/// target for `Creep.harvest`.
pub trait Harvestable: AsRef<RoomObject> {}

/// Trait for all wrappers over Screeps JavaScript objects which can be the
/// target of `Creep.attack`.
///
/// # Contracts
///
/// The reference returned from `AsRef<RoomObject>::as_ref` must be a valid
/// target for `Creep.attack`.
pub trait Attackable: HasHits + AsRef<RoomObject> {}

/// Trait for all wrappers over Screeps JavaScript objects which can be the
/// target of `Creep.dismantle`.
///
/// # Contracts
///
/// The reference returned from `AsRef<Structure>::as_ref` must be a valid
/// target for `Creep.dismantle`.
pub trait Dismantleable: HasHits + AsRef<Structure> {}

/// Trait for all wrappers over Screeps JavaScript objects which can be the
/// target of `Creep.repair` or `StructureTower.repair`.
///
/// # Contracts
///
/// The reference returned from `AsRef<Structure>::as_ref` must be a valid
/// target for repair.
pub trait Repairable: HasHits + AsRef<Structure> {}

/// Trait for all wrappers over Screeps JavaScript objects which can be the
/// target of `Creep.heal`.
///
/// # Contracts
///
/// The reference returned from `AsRef<RoomObject>::as_ref` must be a valid
/// target for `Creep.heal`.
pub trait Healable: AsRef<RoomObject> {}