npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

battlemovr

v0.8.15

Published

Drives RPG-like battles between two teams of actors.

Downloads

90

Readme

BattleMovr

Code Style: Prettier TypeScript: Strict NPM version Join the chat at https://gitter.im/FullScreenShenanigans/community

Drives RPG-like battles between two teams of actors.

Battles

BattleMovr coordinates "battles" in which two teams of actors take turns choosing and executing attacks. Each team has one actor considered "active" at any given time. Between turns, teams are given the option to choose the move they'll take the coming turn.

Consider these battles to follow the model of traditional RPGs such as Pokemon.

Actors

Each actor in a team may participate in the battle. They have at least the following attributes:

  • moves: Battle moves the actor knows.
  • nickname: Textual name for the actor.
  • statistics: Mutable in-battle statistics, which include at least health.
  • title: Sprite title the actor displays as.

Actors may be selected for battle as long as their .statistics.health.current isn't 0.

Actions

There are four types of actions a team may choose to take:

  • flee: The team attempts to leave the battle.
  • item: The team attempts to use an item.
  • move: The team's selected actor uses a battle move.
  • switch: The team switches which actor is selected.

Usage

Constructor

const battleMover = new BattleMovr({
    actionsOrderer(actions: UnderEachTeam<Action>): TeamAndAction<Action>[] {
        // Returns the actions in the order they should occur.
    },
    animations: {
        complete(outcome: BattleOutcome, onComplete?: () => void): void {
            // Animates the battle finishing; calls onComplete when done if provided.
        },
        opponent: {
            actions: {
                flee(teamAction: TeamAndAction<FleeAction>, onComplete: () => void): void {
                    // Animates the team choosing to flee.
                },
                item(teamAction: TeamAndAction<ItemAction>, onComplete: () => void): void {
                    // Animates the team choosing to use an item.
                },
                move(teamAction: TeamAndAction<MoveAction>, onComplete: () => void): void {
                    // Animates the team choosing to use an actor move.
                },
                switch(teamAction: TeamAndAction<SwitchAction>, onComplete: () => void): void {
                    // Animates the team choosing to switch actors.
                },
            },
            healthChange(health: number, onComplete: () => void): void {
                // Animates an actor's health changing.
            },
            introduction(onComplete: () => void): void {
                // Animates the team introducing itself.
            },
            switching: {
                enter(onComplete: () => void): void {
                    // Animates an actor entering battle.
                },
                exit(onComplete: () => void): void {
                    // Animates an actor exiting battle.
                },
                knockout(onComplete: () => void): void {
                    // Animates an actor getting knocked out of battle.
                },
                switch(teamAction: TeamAndAction<TAction>, onComplete: () => void): void {
                    // Animates a team switching actors.
                },
            },
        },
        player: {
            // (same as the opponent's properties, but for the player!)
        },
        start(onComplete: () => void): void {
            // Animation for a battle starting.
        },
    },
    selectorFactories: {},
});

actionsOrderer

Runs after each team has chosen their moves for an upcoming turn. It takes in the Action chosen for each team as an UnderEachTeam<Action> and returns the ordered array of when those actions should take place.

For example, an orderer that prioritizes flee, switch, item, and move in that order might look like:

const orders = {
    flee: 0,
    switch: 1,
    item: 2,
    move: 3,
};

const actionsOrderer: ActionsOrderer = (
    actions: UnderEachTeam<Action>
): TeamAndAction<Action>[] => {
    const playerOrder = orders[actions.player];
    const opponentOrder = order[actions.opponent];

    return playerOrder <= opponentOrder
        ? [actions.player, actions.opponent]
        : [actions.opponent, actions.player];
};

See src/Teams.ts for full type signatures.

animations

Animation callbacks for various battle activities. Two basic animation members are:

  • complete: Animation for when a battle is complete.
  • start: Animation for a battle starting.

Also required are team-specific animations under both .opponent and .player:

  • actions: Animations for in-battle selected actions, keyed by their type names (see names above).
  • healthChange: Animation for when an actor's health changes.
  • introduction: Animation for a team introducing itself at the beginning of battle.
  • switching: Animations for actors switching positions, which are:
    • enter: Animation for an actor entering battle.
    • exit: Animation for an actor exiting battle.
    • knockout: Animation for an actor getting knocked out.
    • switch: Animation for actors being swapped.

See src/Animations.ts for full type signatures.

selectorFactories

An object containing methods that return action selectors usable by teams. An action selector contains methods for the team to choose their next action between battle turns. Each selector contains:

  • afterKnockout: Reacts to the selected actor having just been knocked out.
  • nextAction: Determines the next action while there is still a selected actor.

These are keyed by names that will be specified by teams entering battle. For example, a "cowardly" selector might always choose a flee action:

const selectorFactories = {
    cowardly: () => () => ({
        afterKnockout: () => {},
        nextAction: (_, _, onChoice) => {
            onChoice({
                type: "flee",
            });
        },
    }),
};

afterKnockout doesn't provide an onChoice; it might be refactored to animations.

See src/Selectors.ts for full type signatures.

inBattle

Returns whether there is a current battle. Subsequent methods will throw errors if not used in the correct battle state.

  • startBattle throws an error if a battle is already ongoing.
  • getBattleInfo, stopBattle, and switchSelectedActor throw if a battle isn't ongoing.

startBattle

Starting a battle requires passing two teams to participate in the battle. As with other containers, teams are named opponent and player. Each team must at least contain:

  • actors: Array of actors that will fight.
  • selector: How the team chooses their actions (see above).

Teams may also specify a teamLeader with an actor-like nickname and title. Team leaders, if they exist, are animated animated to show actors entering or leaving battle.

For example, simulating battles between two robots, where the player is piloted by a human:

FSP.battles.startBattle({
    teams: {
        opponent: {
            actors: [
                {
                    moves: [
                        {
                            title: "Bend",
                            remaining: 10,
                            uses: 10,
                        },
                    ],
                    nickname: "Flex".split(""),
                    statistics: {
                        health: {
                            current: 100,
                            normal: 100,
                        },
                    },
                    title: "BendingUnit22".split(""),
                },
            ],
            selector: "angry",
        },
        player: {
            actors: [
                {
                    moves: [
                        {
                            title: "Bend",
                            remaining: 10,
                            uses: 10,
                        },
                    ],
                    nickname: "Bender".split(""),
                    statistics: {
                        health: {
                            current: 100,
                            normal: 100,
                        },
                    },
                    title: "BendingUnit22".split(""),
                },
            ],
            leader: {
                nickname: "Fry".split(""),
                title: "LazyHuman".split(""),
            },
            selector: "angry",
        },
    },
});

stopBattle

Reports that the battle has completed with a particular outcome. This is typically used by one of the above animations in response to an action taken. For example, a flee action's animation would typically call it when complete:

const animateOpponentFlee = (
    teamAction: TeamAndAction<FleeAction>,
    onComplete: () => void
): void => {
    console.log("Opponent ran away!");
    battleMover.stopBattle(BattleOutcome.opponentFled, onComplete);
};

switchSelectedActor

Switches the selected actor for a team. This takes in the Team enum being switched and its new actor. It will call the relevant animations in sequential order.

The new actor is expected to be in that team's list of actors.

Development

This repository is a portion of the EightBittr monorepo. See its docs/Development.md for details on how to get started. 💖

Running Tests

yarn run test

Tests are written in Mocha and Chai. Their files are written using alongside source files under src/ and named *.test.ts?. Whenever you add, remove, or rename a *.test.t* file under src/, watch will re-run yarn run test:setup to regenerate the list of static test files in test/index.html. You can open that file in a browser to debug through the tests, or run yarn test:run to run them in headless Chrome.