├── .babelrc
├── .github
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── App.js
├── CODE_OF_CONDUCT.md
├── Dockerfile
├── Examples
├── Actions
│ └── actions.js
├── Mobs
│ ├── Blob.js
│ ├── Ent.js
│ ├── Golem.js
│ ├── MerQueen.js
│ └── Raptor.js
└── index.js
├── LICENSE
├── README.md
├── docker-compose.yml
├── index.js
├── lib
├── constants.js
├── core
│ ├── animation.js
│ ├── assetmanager.js
│ ├── canvas.js
│ ├── entity.js
│ ├── eventmanager.js
│ ├── exit.js
│ ├── floor.js
│ ├── game.js
│ ├── index.js
│ ├── keyboard.js
│ ├── map.js
│ ├── map
│ │ ├── arena.js
│ │ ├── cellular.js
│ │ ├── digger.js
│ │ ├── dividedmaze.js
│ │ ├── dungeon.js
│ │ ├── ellermaze.js
│ │ ├── features.js
│ │ ├── iceymaze.js
│ │ ├── index.js
│ │ ├── map.js
│ │ ├── rogue.js
│ │ └── uniform.js
│ ├── options.js
│ ├── player.js
│ ├── plugin.js
│ ├── pointer.js
│ ├── pool.js
│ ├── quadtree.js
│ ├── rng.js
│ ├── sprite.js
│ ├── spritesheet.js
│ ├── store.js
│ ├── tile.js
│ ├── tileengine.js
│ ├── util.js
│ ├── vector.js
│ └── wall.js
├── index.defaults.js
└── index.js
├── package.json
├── public
├── index.html
└── moiboi.png
├── src
├── constants.js
├── core
│ ├── AssetManager.js
│ ├── EventManager.js
│ ├── animation.js
│ ├── canvas.js
│ ├── entity.js
│ ├── exit.js
│ ├── floor.js
│ ├── game.js
│ ├── keyboard.js
│ ├── map
│ │ ├── arena.js
│ │ ├── cellular.js
│ │ ├── digger.js
│ │ ├── dividedmaze.js
│ │ ├── dungeon.js
│ │ ├── ellermaze.js
│ │ ├── features.js
│ │ ├── iceymaze.js
│ │ ├── index.js
│ │ ├── map.js
│ │ ├── rogue.js
│ │ └── uniform.js
│ ├── options.js
│ ├── player.js
│ ├── plugin.js
│ ├── pointer.js
│ ├── pool.js
│ ├── quadtree.js
│ ├── rng.js
│ ├── sprite.js
│ ├── spritesheet.js
│ ├── store.js
│ ├── tile.js
│ ├── tileengine.js
│ ├── util.js
│ ├── vector.js
│ └── wall.js
├── index.defaults.js
└── index.js
├── webpack.config.babel.js
├── yarn-error.log
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/preset-env",
5 | {
6 | "useBuiltIns": "entry"
7 | }
8 | ]
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | node_modules/
3 |
--------------------------------------------------------------------------------
/App.js:
--------------------------------------------------------------------------------
1 | // import RogueIO from "./index.js";
2 | import Options from "./src/core/options";
3 | import RogueIO from "./src";
4 | let { init, RNG, Map, Sprite, Game } = RogueIO;
5 |
6 | RNG.setSeed("Miya");
7 | let { canvas, context } = init();
8 |
9 | let map = {};
10 |
11 | var tileSize = 64,
12 | numTiles = 9,
13 | uiWidth = 4;
14 | var w = tileSize * (numTiles + uiWidth),
15 | h = tileSize * numTiles;
16 | canvas.width = tileSize * (numTiles + uiWidth);
17 | canvas.height = tileSize * numTiles;
18 | canvas.style.width = canvas.width + "px";
19 | canvas.style.height = canvas.height + "px";
20 | canvas.style.fontSize = "15px";
21 | context.font = "15px sans-serif";
22 | context.imageSmoothingEnabled = false;
23 | console.log(context, Map, canvas);
24 |
25 | const _generateMap = () => {
26 | var freeCells = [];
27 | var digger = new Map.Digger(w, h);
28 | console.log(digger);
29 | var digCallback = function(x, y, value) {
30 | if (value) {
31 | return;
32 | } /* do not store walls */
33 |
34 | var key = x + "," + y;
35 | freeCells.push(key);
36 | map[key] = ".";
37 | };
38 | digger.create(digCallback.bind(this));
39 | _drawWholeMap();
40 | };
41 | const _drawWholeMap = function() {
42 | for (var key in map) {
43 | var parts = key.split(",");
44 | var x = parseInt(parts[0]);
45 | var y = parseInt(parts[1]);
46 | let sprite = Sprite({
47 | x: x, // starting x,y position of the sprite
48 | y: y,
49 | radius: 5,
50 | color: "#000", // fill color of the sprite rectangle
51 | width: 1, // width and height of the sprite rectangle
52 | height: 1,
53 | render: function() {
54 | this.draw();
55 | // this.context.font = "50px"
56 | }
57 | });
58 | // sprite.context.font = "14px sans-serif";
59 | sprite.render();
60 | }
61 | };
62 | _generateMap();
63 | console.log(map);
64 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | - Using welcoming and inclusive language
18 | - Being respectful of differing viewpoints and experiences
19 | - Gracefully accepting constructive criticism
20 | - Focusing on what is best for the community
21 | - Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | - The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | - Trolling, insulting/derogatory comments, and personal or political attacks
28 | - Public or private harassment
29 | - Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | - Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at nodeggofficial@gmail.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:lts
2 |
3 | #Creates Working App
4 | WORKDIR /usr/src/app
5 | RUN npm i -g nodemon
6 | #copy's package.json file and installs deps
7 | COPY package.json ./
8 | RUN npm install --quiet
9 |
10 | #bundles source
11 | COPY . .
--------------------------------------------------------------------------------
/Examples/Actions/actions.js:
--------------------------------------------------------------------------------
1 | import Game from "../../src/core/game";
2 | import Floor from "../../src/core/floor";
3 |
4 | let actions = {
5 | WARP() {
6 | Game.player.move(Game.map.randomPassableTile());
7 | },
8 | QUAKE() {
9 | for (let i = 0; i < Game.numTiles; i++) {
10 | for (let j = 0; j < Game.numTiles; j++) {
11 | let tile = Game.map.getTile(i, j);
12 | if (Game.map.monster) {
13 | let numWalls = 4 - tile.getAdjacentPassableNeighbors().length;
14 | tile.monster.hit(numWalls * 2);
15 | }
16 | }
17 | }
18 | Game.shakeAmount = 20;
19 | },
20 | MAELSTROM() {
21 | for (let i = 0; i < Game.map.monsters.length; i++) {
22 | Game.map.monsters[i].move(Game.map.randomPassableTile());
23 | Game.map.monsters[i].teleportCounter = 2;
24 | }
25 | },
26 | MULLIGAN() {
27 | Game.startLevel(1, Game.player.spells);
28 | },
29 | AURA() {
30 | Game.player.tile.getAdjacentNeighbors().forEach(t => {
31 | t.setEffect(13);
32 | if (t.monster) {
33 | t.monster.heal(1);
34 | }
35 | });
36 | Game.player.tile.setEffect(13);
37 | Game.player.heal(1);
38 | },
39 | DASH() {
40 | let newTile = Game.player.tile;
41 | while (true) {
42 | let testTile = newTile.getNeighbor(
43 | Game.player.lastMove[0],
44 | Game.player.lastMove[1]
45 | );
46 | if (testTile.passable && !testTile.monster) {
47 | newTile = testTile;
48 | } else {
49 | break;
50 | }
51 | }
52 | if (Game.player.tile != newTile) {
53 | Game.player.move(newTile);
54 | newTile.getAdjacentNeighbors().forEach(t => {
55 | if (t.monster) {
56 | t.setEffect(14);
57 | t.monster.stunned = true;
58 | t.monster.hit(1);
59 | }
60 | });
61 | }
62 | },
63 | DIG() {
64 | for (let i = 1; i < Game.numTiles - 1; i++) {
65 | for (let j = 1; j < Game.numTiles - 1; j++) {
66 | let tile = Game.map.getTile(i, j);
67 | if (!tile.passable) {
68 | tile.replace(Floor);
69 | }
70 | }
71 | }
72 | Game.player.tile.setEffect(13);
73 | Game.player.heal(2);
74 | },
75 | KINGMAKER() {
76 | for (let i = 0; i < Game.map.monsters.length; i++) {
77 | Game.map.monsters[i].heal(1);
78 | Game.map.monsters[i].tile.treasure = true;
79 | }
80 | },
81 | ALCHEMY() {
82 | Game.player.tile.getAdjacentNeighbors().forEach(t => {
83 | if (!t.passable && inBounds(t.x, t.y)) {
84 | t.replace(Floor).treasure = true;
85 | }
86 | });
87 | },
88 | POWER() {
89 | Game.player.bonusAttack = 5;
90 | },
91 | BUBBLE() {
92 | for (let i = Game.player.actions.length - 1; i > 0; i--) {
93 | if (!Game.player.actions[i]) {
94 | Game.player.actions[i] = Game.player.actions[i - 1];
95 | }
96 | }
97 | },
98 | BRAVERY() {
99 | Game.player.shield = 2;
100 | for (let i = 0; i < Game.map.monsters.length; i++) {
101 | Game.map.monsters[i].stunned = true;
102 | }
103 | },
104 | BOLT() {
105 | boltTravel(Game.player.lastMove, 15 + Math.abs(Game.player.lastMove[1]), 4);
106 | },
107 | CROSS() {
108 | let directions = [
109 | [0, -1],
110 | [0, 1],
111 | [-1, 0],
112 | [1, 0]
113 | ];
114 | for (let k = 0; k < directions.length; k++) {
115 | boltTravel(directions[k], 15 + Math.abs(directions[k][1]), 2);
116 | }
117 | },
118 | EX() {
119 | let directions = [
120 | [-1, -1],
121 | [-1, 1],
122 | [1, -1],
123 | [1, 1]
124 | ];
125 | for (let k = 0; k < directions.length; k++) {
126 | boltTravel(directions[k], 14, 3);
127 | }
128 | }
129 | };
130 | //Add to Action Manager
131 | const boltTravel = (direction, effect, damage) => {
132 | let newTile = Game.player.tile;
133 | while (true) {
134 | let testTile = newTile.getNeighbor(direction[0], direction[1]);
135 |
136 | if (testTile.passable) {
137 | newTile = testTile;
138 | if (newTile.monster) newTile.monster.hit(damage);
139 | newTile.setEffect(effect);
140 | } else {
141 | break;
142 | }
143 | }
144 | };
145 | export default actions;
146 |
--------------------------------------------------------------------------------
/Examples/Mobs/Blob.js:
--------------------------------------------------------------------------------
1 | // import init from "./lib";
2 | import RogueIO from "../../src";
3 | let { Entity } = RogueIO();
4 |
5 | export default class Blob extends Entity {
6 | constructor(tile) {
7 | super(tile, 4, 3);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Examples/Mobs/Ent.js:
--------------------------------------------------------------------------------
1 | // import init from "./lib";
2 | import RogueIO from "../../src";
3 | let { Game, Entity, Floor } = RogueIO();
4 |
5 | export default class Ent extends Entity {
6 | constructor(tile) {
7 | super(tile, 7, 1);
8 | }
9 | doStuff() {
10 | let neighbors = this.tile
11 | .getAdjacentNeighbors()
12 | .filter(t => !t.passable && Game.map.inBounds(t.x, t.y));
13 | if (neighbors.length) {
14 | neighbors[0].replace(Floor);
15 | this.heal(0.5);
16 | } else {
17 | super.doStuff();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Examples/Mobs/Golem.js:
--------------------------------------------------------------------------------
1 | // import init from "./lib";
2 | import RogueIO from "../../src";
3 | let { Entity } = RogueIO();
4 |
5 | export default class Golem extends Entity {
6 | constructor(tile) {
7 | super(tile, 6, 2);
8 | }
9 | update() {
10 | let startedStunned = this.stunned;
11 | super.update();
12 | if (!startedStunned) {
13 | this.stunned = true;
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Examples/Mobs/MerQueen.js:
--------------------------------------------------------------------------------
1 | // import init from "./lib";
2 | import RogueIO from "../../src";
3 | let { Entity } = RogueIO();
4 |
5 | export default class MerQueen extends Entity {
6 | constructor(tile) {
7 | super(tile, 8, 5);
8 | }
9 | doStuff() {
10 | let neighbors = this.tile.getAdjacentPassableNeighbors();
11 | if (neighbors.length) {
12 | this.tryMove(neighbors[0].x - this.tile.x, neighbors[0].y - this.tile.y);
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Examples/Mobs/Raptor.js:
--------------------------------------------------------------------------------
1 | // import init from "./lib";
2 | import RogueIO from "../../src";
3 | let { Entity } = RogueIO();
4 |
5 | export default class Raptor extends Entity {
6 | constructor(tile) {
7 | super(tile, 5, 1);
8 | }
9 | doStuff() {
10 | this.attackedThisTurn = false;
11 | super.doStuff();
12 |
13 | if (!this.attackedThisTurn) {
14 | super.doStuff();
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Examples/index.js:
--------------------------------------------------------------------------------
1 | import Blob from './Mobs/Blob'
2 | import Ent from './Mobs/Ent'
3 | import Golem from './Mobs/Golem'
4 | import MerQueen from './Mobs/MerQueen'
5 | import Raptor from './Mobs/Raptor'
6 | export {
7 | Blob,
8 | Ent,
9 | Golem,
10 | MerQueen,
11 | Raptor
12 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Node >< GG
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 | # RogueIO
2 |
3 | > A RogueLike Javascript Library/Game Engine built with ❤
4 |
5 |
6 |
7 | [](https://github.com/NodeGG/RogueIO/blob/master/LICENSE) [](https://twitter.com/MOIKUNE) [](https://discord.gg/atuZfDJ) [](https://www.reddit.com/r/RogueIO)[](https://www.npmjs.com/package/rogueio)
8 |
9 |
10 |
11 | ## Introduction
12 | RogueIO is an engine heavily inspired by both Rot.js and KontraJS to the point we merged the two together to create a whole new library for Javascript Game Developers.
13 |
14 | ### Intended Features
15 |
16 | - [ x ] Basic Game Engine
17 |
18 | - Including RNG, FOV, LIGHTING...
19 | - Pathfinding, and turn scheduling
20 |
21 | - [ ] Procedural Map Generation
22 |
23 | - ASCII and Tile Based
24 |
25 | - [ x ] Asset Manager
26 |
27 | - A promise based asset loader for loading images, audio, and data files.
28 |
29 | - [ x ] Tile Manager
30 |
31 | - For managing and drawing tilesets.
32 |
33 | - [ x ] Event Manager
34 |
35 | - A simple event system. Allows you to hook into RogueIO lifecycle events or create your own, i.e Plugins.
36 |
37 | - [ x ] Plugin Manager
38 |
39 | - A plugin system based on the interceptor pattern, designed to share reusable code such as more advance collision detection or a 2D physics engine.
40 |
41 | - [ x ] Vector Engine
42 |
43 | - The Ability to create simple 2D vector objects
44 |
45 | - [ x ] Sprite Engine
46 |
47 | - A versatile way to update and draw your game objects. It can handle simple rectangles, images, and sprite sheet animations. It can be used for your main player object as well as tiny particles in a particle engine.
48 |
49 | - [ x ] Pointer Api
50 |
51 | - A simple pointer API. You can use to move the main sprite or respond to a pointer event.(Mouse and touch events.)
52 |
53 | - [ x ] Store Manager
54 |
55 | - A Simple Storage API to save data locally or to a Database
56 |
57 | - [ x ] A Minimalistic Keyboard Api
58 |
59 | - [ x ] Animation Api
60 |
61 | - [ ] Basic Multiplayer
62 |
63 | ### Project Resources That Help Guide the Way
64 |
65 | - https://nluqo.github.io/broughlike-tutorial/index.html
66 | - https://www.reddit.com/r/roguelikedev/wiki/python_tutorial_series
67 | - https://straker.github.io/kontra/
68 | - https://ondras.github.io/rot.js/hp/
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: "3"
2 |
3 | services:
4 | dev:
5 | build: .
6 | command: yarn dev
7 | volumes:
8 | - .:/usr/src/app
9 | - /usr/src/app/node_modules
10 | ports:
11 | - 8085:8085
12 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * RougeJS
3 | * MIT Licensed
4 | */
5 |
6 | "use strict";
7 |
8 | module.exports = require("./lib");
9 |
--------------------------------------------------------------------------------
/lib/core/animation.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = animationFactory;
7 |
8 | var _canvas = require("./canvas.js");
9 |
10 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
11 |
12 | function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
13 |
14 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
15 |
16 | /**
17 | * An object for drawing sprite sheet animations.
18 | *
19 | * An animation defines the sequence of frames to use from a sprite sheet. It also defines at what speed the animation should run using `frameRate`.
20 | *
21 | * Typically you don't create an kontra.Animation directly, but rather you would create them from kontra.SpriteSheet by passing the `animations` argument.
22 | *
23 | * ```js
24 | * import { SpriteSheet, Animation } from 'kontra';
25 | *
26 | * let image = new Image();
27 | * image.src = 'assets/imgs/character_walk_sheet.png';
28 | * image.onload = function() {
29 | * let spriteSheet = SpriteSheet({
30 | * image: image,
31 | * frameWidth: 72,
32 | * frameHeight: 97
33 | * });
34 | *
35 | * // you typically wouldn't create an Animation this way
36 | * let animation = Animation({
37 | * spriteSheet: spriteSheet,
38 | * frames: [1,2,3,6],
39 | * frameRate: 30
40 | * });
41 | * };
42 | * ```
43 | * @class Animation
44 | *
45 | * @param {Object} properties - Properties of the animation.
46 | * @param {kontra.SpriteSheet} properties.spriteSheet - Sprite sheet for the animation.
47 | * @param {Number[]} properties.frames - List of frames of the animation.
48 | * @param {Number} properties.frameRate - Number of frames to display in one second.
49 | * @param {Boolean} [properties.loop=true] - If the animation should loop.
50 | */
51 | var Animation =
52 | /*#__PURE__*/
53 | function () {
54 | function Animation() {
55 | var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
56 | spriteSheet = _ref.spriteSheet,
57 | frames = _ref.frames,
58 | frameRate = _ref.frameRate,
59 | _ref$loop = _ref.loop,
60 | loop = _ref$loop === void 0 ? true : _ref$loop;
61 |
62 | _classCallCheck(this, Animation);
63 |
64 | /**
65 | * The sprite sheet to use for the animation.
66 | * @memberof Animation
67 | * @property {kontra.SpriteSheet} spriteSheet
68 | */
69 | this.spriteSheet = spriteSheet;
70 | /**
71 | * Sequence of frames to use from the sprite sheet.
72 | * @memberof Animation
73 | * @property {Number[]} frames
74 | */
75 |
76 | this.frames = frames;
77 | /**
78 | * Number of frames to display per second. Adjusting this value will change the speed of the animation.
79 | * @memberof Animation
80 | * @property {Number} frameRate
81 | */
82 |
83 | this.frameRate = frameRate;
84 | /**
85 | * If the animation should loop back to the beginning once completed.
86 | * @memberof Animation
87 | * @property {Boolean} loop
88 | */
89 |
90 | this.loop = loop;
91 | var _spriteSheet$frame = spriteSheet.frame,
92 | width = _spriteSheet$frame.width,
93 | height = _spriteSheet$frame.height,
94 | _spriteSheet$frame$ma = _spriteSheet$frame.margin,
95 | margin = _spriteSheet$frame$ma === void 0 ? 0 : _spriteSheet$frame$ma;
96 | /**
97 | * The width of an individual frame. Taken from the property of the same name in the [spriteSheet](api/animation#spriteSheet).
98 | * @memberof Animation
99 | * @property {Number} width
100 | */
101 |
102 | this.width = width;
103 | /**
104 | * The height of an individual frame. Taken from the property of the same name in the [spriteSheet](api/animation#spriteSheet).
105 | * @memberof Animation
106 | * @property {Number} height
107 | */
108 |
109 | this.height = height;
110 | /**
111 | * The space between each frame. Taken from the property of the same name in the [spriteSheet](api/animation#spriteSheet).
112 | * @memberof Animation
113 | * @property {Number} margin
114 | */
115 |
116 | this.margin = margin; // f = frame, a = accumulator
117 |
118 | this._f = 0;
119 | this._a = 0;
120 | }
121 | /**
122 | * Clone an animation so it can be used more than once. By default animations passed to kontra.Sprite will be cloned so no two sprites update the same animation. Otherwise two sprites who shared the same animation would make it update twice as fast.
123 | * @memberof Animation
124 | * @function clone
125 | *
126 | * @returns {kontra.Animation} A new kontra.Animation instance.
127 | */
128 |
129 |
130 | _createClass(Animation, [{
131 | key: "clone",
132 | value: function clone() {
133 | return animationFactory(this);
134 | }
135 | /**
136 | * Reset an animation to the first frame.
137 | * @memberof Animation
138 | * @function reset
139 | */
140 |
141 | }, {
142 | key: "reset",
143 | value: function reset() {
144 | this._f = 0;
145 | this._a = 0;
146 | }
147 | /**
148 | * Update the animation.
149 | * @memberof Animation
150 | * @function update
151 | *
152 | * @param {Number} [dt=1/60] - Time since last update.
153 | */
154 |
155 | }, {
156 | key: "update",
157 | value: function update() {
158 | var dt = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1 / 60;
159 | // if the animation doesn't loop we stop at the last frame
160 | if (!this.loop && this._f == this.frames.length - 1) return;
161 | this._a += dt; // update to the next frame if it's time
162 |
163 | while (this._a * this.frameRate >= 1) {
164 | this._f = ++this._f % this.frames.length;
165 | this._a -= 1 / this.frameRate;
166 | }
167 | }
168 | /**
169 | * Draw the current frame of the animation.
170 | * @memberof Animation
171 | * @function render
172 | *
173 | * @param {Object} properties - Properties to draw the animation.
174 | * @param {Number} properties.x - X position to draw the animation.
175 | * @param {Number} properties.y - Y position to draw the animation.
176 | * @param {Number} [properties.width] - width of the sprite. Defaults to [Animation.width](api/animation#width).
177 | * @param {Number} [properties.height] - height of the sprite. Defaults to [Animation.height](api/animation#height).
178 | * @param {CanvasRenderingContext2D} [properties.context] - The context the animation should draw to. Defaults to [core.getContext()](api/core#getContext).
179 | */
180 |
181 | }, {
182 | key: "render",
183 | value: function render() {
184 | var _ref2 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
185 | x = _ref2.x,
186 | y = _ref2.y,
187 | _ref2$width = _ref2.width,
188 | width = _ref2$width === void 0 ? this.width : _ref2$width,
189 | _ref2$height = _ref2.height,
190 | height = _ref2$height === void 0 ? this.height : _ref2$height,
191 | _ref2$context = _ref2.context,
192 | context = _ref2$context === void 0 ? (0, _canvas.getContext)() : _ref2$context;
193 |
194 | // get the row and col of the frame
195 | var row = this.frames[this._f] / this.spriteSheet._f | 0;
196 | var col = this.frames[this._f] % this.spriteSheet._f | 0;
197 | context.drawImage(this.spriteSheet.image, col * this.width + (col * 2 + 1) * this.margin, row * this.height + (row * 2 + 1) * this.margin, this.width, this.height, x, y, width, height);
198 | }
199 | }]);
200 |
201 | return Animation;
202 | }();
203 |
204 | function animationFactory(properties) {
205 | return new Animation(properties);
206 | }
207 |
208 | animationFactory.prototype = Animation.prototype;
209 | animationFactory["class"] = Animation;
--------------------------------------------------------------------------------
/lib/core/canvas.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports.getCanvas = getCanvas;
7 | exports.getContext = getContext;
8 | exports.init = init;
9 |
10 | var _options = _interopRequireDefault(require("./options"));
11 |
12 | var _eventmanager = require("./eventmanager");
13 |
14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
15 |
16 | /**
17 | * Functions for initializing the RogueIO library and getting the canvas and context
18 | * objects.
19 | *
20 | * ```js
21 | * import { getCanvas, getContext, init } from 'RogueIO';
22 | *
23 | * let { canvas, context } = init();
24 | *
25 | * // or can get canvas and context through functions
26 | * canvas = getCanvas();
27 | * context = getContext();
28 | * ```
29 | * @sectionName Core
30 | */
31 | var canvasEl, context;
32 | /**
33 | * Return the canvas element.
34 | * @function getCanvas
35 | *
36 | * @returns {HTMLCanvasElement} The canvas element for the game.
37 | */
38 |
39 | function getCanvas() {
40 | return canvasEl;
41 | }
42 | /**
43 | * Return the context object.
44 | * @function getContext
45 | *
46 | * @returns {CanvasRenderingContext2D} The context object the game draws to.
47 | */
48 |
49 |
50 | function getContext() {
51 | return context;
52 | }
53 | /**
54 | * Initialize the library and set up the canvas. Typically you will call `init()` as the first thing and give it the canvas to use. This will allow all RogueIO objects to reference the canvas when created.
55 | *
56 | * ```js
57 | * import { init } from 'RogueIO';
58 | *
59 | * let { canvas, context } = init('game');
60 | * ```
61 | * @function init
62 | *
63 | * @param {String|HTMLCanvasElement} [canvas] - The canvas for RogueIO to use. Can either be the ID of the canvas element or the canvas element itself. Defaults to using the first canvas element on the page.
64 | *
65 | * @returns {Object} An object with properties `canvas` and `context`. `canvas` it the canvas element for the game and `context` is the context object the game draws to.
66 | */
67 |
68 |
69 | function init(canvas) {
70 | // check if canvas is a string first, an element next, or default to getting
71 | // first canvas on page
72 | canvasEl = document.getElementById(canvas) || canvas || document.querySelector("canvas"); // @if DEBUG
73 |
74 | if (!canvasEl) {
75 | throw Error("You must provide a canvas element for the game");
76 | } // @endif
77 |
78 |
79 | context = canvasEl.getContext("2d");
80 | context.font = '15px sans-serif';
81 | console.log(context.font);
82 | context.imageSmoothingEnabled = false;
83 | (0, _eventmanager.emit)("init");
84 | return {
85 | canvas: canvasEl,
86 | context: context
87 | };
88 | }
--------------------------------------------------------------------------------
/lib/core/entity.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 |
8 | var _assetmanager = require("./assetmanager");
9 |
10 | var _game = _interopRequireDefault(require("./game"));
11 |
12 | var _spritesheet = _interopRequireDefault(require("./spritesheet"));
13 |
14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
15 |
16 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
17 |
18 | function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
19 |
20 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
21 |
22 | var Entity =
23 | /*#__PURE__*/
24 | function () {
25 | function Entity(tile, sprite, hp) {
26 | _classCallCheck(this, Entity);
27 |
28 | this.spritesheet = null;
29 | this.ctx = null;
30 | this.move(tile);
31 | this.sprite = sprite;
32 | this.hp = hp;
33 | this.teleportCounter = 2;
34 | this.offsetX = 0;
35 | this.offsetY = 0;
36 | this.lastMove = [-1, 0];
37 | this.bonusAttack = 0;
38 | }
39 |
40 | _createClass(Entity, [{
41 | key: "heal",
42 | value: function heal(damage) {
43 | this.hp = Math.min(_game["default"].maxHp, this.hp + damage);
44 | }
45 | }, {
46 | key: "getDisplayX",
47 | value: function getDisplayX() {
48 | return this.tile.x + this.offsetX;
49 | }
50 | }, {
51 | key: "getDisplayY",
52 | value: function getDisplayY() {
53 | return this.tile.y + this.offsetY;
54 | }
55 | }, {
56 | key: "draw",
57 | value: function draw() {
58 | this.ctx = _game["default"].canvas.getCtx();
59 | this.spritesheet = new _spritesheet["default"]({
60 | ctx: this.ctx,
61 | tilesize: _game["default"].tilesize
62 | });
63 |
64 | if (this.teleportCounter > 0) {
65 | this.spritesheet.drawSprite(10, this.getDisplayX(), this.getDisplayY());
66 | } else {
67 | this.spritesheet.drawSprite(this.sprite, this.getDisplayX(), this.getDisplayY());
68 | this.drawHp();
69 | }
70 |
71 | this.offsetX -= Math.sign(this.offsetX) * (1 / 8);
72 | this.offsetY -= Math.sign(this.offsetY) * (1 / 8);
73 | }
74 | }, {
75 | key: "drawHp",
76 | value: function drawHp() {
77 | for (var i = 0; i < this.hp; i++) {
78 | this.spritesheet.drawSprite(9, this.getDisplayX() + i % 3 * (5 / 16), this.getDisplayY() - Math.floor(i / 3) * (5 / 16));
79 | }
80 | }
81 | }, {
82 | key: "tryMove",
83 | value: function tryMove(dx, dy) {
84 | var newTile = this.tile.getNeighbor(dx, dy);
85 |
86 | if (newTile.passable) {
87 | this.lastMove = [dx, dy];
88 |
89 | if (!newTile.monster) {
90 | this.move(newTile);
91 | } else {
92 | if (this.isPlayer != newTile.monster.isPlayer) {
93 | this.attackedThisTurn = true;
94 | newTile.monster.stunned = true;
95 | newTile.monster.hit(1 + this.bonusAttack);
96 | this.bonusAttack = 0;
97 | _game["default"].shakeAmount = 5;
98 | this.offsetX = (newTile.x - this.tile.x) / 2;
99 | this.offsetY = (newTile.y - this.tile.y) / 2;
100 | }
101 | }
102 |
103 | return true;
104 | }
105 | }
106 | }, {
107 | key: "update",
108 | value: function update() {
109 | this.teleportCounter--;
110 |
111 | if (this.stunned || this.teleportCounter > 0) {
112 | this.stunned = false;
113 | return;
114 | }
115 |
116 | this.doStuff();
117 | }
118 | }, {
119 | key: "doStuff",
120 | value: function doStuff() {
121 | var neighbors = this.tile.getAdjacentPassableNeighbors();
122 | neighbors = neighbors.filter(function (t) {
123 | return !t.monster || t.monster.isPlayer;
124 | });
125 |
126 | if (neighbors.length) {
127 | neighbors.sort(function (a, b) {
128 | return a.dist(_game["default"].player.tile) - b.dist(_game["default"].player.tile);
129 | });
130 | var newTile = neighbors[0];
131 | this.tryMove(newTile.x - this.tile.x, newTile.y - this.tile.y);
132 | }
133 | }
134 | }, {
135 | key: "hit",
136 | value: function hit(damage) {
137 | if (this.sheild > 0) {}
138 |
139 | this.hp -= damage;
140 |
141 | if (this.hp <= 0) {
142 | this.die();
143 | }
144 |
145 | if (this.isPlayer) {
146 | (0, _assetmanager.playSound)("hit1");
147 | } else {
148 | (0, _assetmanager.playSound)("hit2");
149 | }
150 | }
151 | }, {
152 | key: "die",
153 | value: function die() {
154 | this.dead = true;
155 | this.tile.monster = null;
156 | this.sprite = 1;
157 | }
158 | }, {
159 | key: "move",
160 | value: function move(tile) {
161 | if (this.tile) {
162 | this.tile.monster = null;
163 | this.offsetX = this.tile.x - tile.x;
164 | this.offsetY = this.tile.y - tile.y;
165 | }
166 |
167 | this.tile = tile;
168 | tile.monster = this;
169 | tile.stepOn(this);
170 | }
171 | }]);
172 |
173 | return Entity;
174 | }();
175 |
176 | exports["default"] = Entity;
--------------------------------------------------------------------------------
/lib/core/eventmanager.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports.emit = exports.off = exports.on = exports.callbacks = void 0;
7 |
8 | /**
9 | * A Simple Event Manager to allow for user to create their own hooks into RogueIO, or create Events for Plugins
10 | * @section Events
11 | */
12 | var callbacks = {};
13 | /**
14 | * 3 Important lifecycle Events:
15 | * - `init` Emits after Rogue.JS is called
16 | * - `tick` Emmits every frame of the RogueIO.GameLoop [Loops Update and Render]
17 | * - `assetload` Emitted after an asset has fully loaded using the asset loader. The callback function is passed the asset and the url of the asset as parameters
18 | * @section Lifecycel Events
19 | */
20 |
21 | /**
22 | * Register a callback for an event to be called whenever the event is emitted. The callback will be passed all arguments used in the `emit` call.
23 | * @function on
24 | *
25 | * @param {String} event - Name of the event.
26 | * @param {Function} callback - Function that will be called when the event is emitted.
27 | */
28 |
29 | exports.callbacks = callbacks;
30 |
31 | var on = function on(event, callback) {
32 | callbacks[event] = callbacks[event] || [];
33 | callbacks[event].push(callback);
34 | };
35 | /**
36 | * Remove a callback for an event.
37 | * @function off
38 | *
39 | * @param {String} event - Name of the event.
40 | * @param {Function} callback - The function that was passed during registration.
41 | */
42 |
43 |
44 | exports.on = on;
45 |
46 | var off = function off(event, callback) {
47 | var index;
48 | if (!callbacks[event] || (index = callbacks[event].indexOf(callback)) < 0) return;
49 | callbacks[event].splice(index, 1);
50 | };
51 | /**
52 | * Call all callback functions for the event. All arguments will be passed to the callback functions.
53 | * @function emit
54 | *
55 | * @param {String} event - Name of the event.
56 | * @param {*} [args] - Arguments passed to all callbacks.
57 | */
58 |
59 |
60 | exports.off = off;
61 |
62 | var emit = function emit(event) {
63 | for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
64 | args[_key - 1] = arguments[_key];
65 | }
66 |
67 | if (callbacks !== undefined) {
68 | if (!callbacks[event]) return;
69 | callbacks[event].map(function (fn) {
70 | return fn.apply(void 0, args);
71 | });
72 | }
73 | };
74 |
75 | exports.emit = emit;
--------------------------------------------------------------------------------
/lib/core/exit.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 |
8 | var _assetmanager = _interopRequireDefault(require("./assetmanager"));
9 |
10 | var _tile = _interopRequireDefault(require("./tile"));
11 |
12 | var _game = _interopRequireDefault(require("./game"));
13 |
14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
15 |
16 | function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
17 |
18 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
19 |
20 | function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
21 |
22 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
23 |
24 | function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
25 |
26 | function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
27 |
28 | function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
29 |
30 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
31 |
32 | function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
33 |
34 | var Exit =
35 | /*#__PURE__*/
36 | function (_Tile) {
37 | _inherits(Exit, _Tile);
38 |
39 | function Exit(x, y) {
40 | _classCallCheck(this, Exit);
41 |
42 | return _possibleConstructorReturn(this, _getPrototypeOf(Exit).call(this, x, y, 11, true));
43 | }
44 |
45 | _createClass(Exit, [{
46 | key: "stepOn",
47 | value: function stepOn(monster) {
48 | if (monster.isPlayer) {
49 | _assetmanager["default"].playSound("newLevel");
50 |
51 | if (_game["default"].level == _game["default"].numLevels) {
52 | _game["default"].addScore(_game["default"].score, true);
53 |
54 | _game["default"].showTitle();
55 | } else {
56 | _game["default"].level++;
57 |
58 | _game["default"].startLevel(Math.min(_game["default"].maxHp, _game["default"].player.hp + 1));
59 | }
60 | }
61 | }
62 | }]);
63 |
64 | return Exit;
65 | }(_tile["default"]);
66 |
67 | exports["default"] = Exit;
--------------------------------------------------------------------------------
/lib/core/floor.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 |
8 | var _assetmanager = require("./assetmanager");
9 |
10 | var _game = _interopRequireDefault(require("./game"));
11 |
12 | var _tile = _interopRequireDefault(require("./tile"));
13 |
14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
15 |
16 | function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
17 |
18 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
19 |
20 | function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
21 |
22 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
23 |
24 | function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
25 |
26 | function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
27 |
28 | function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
29 |
30 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
31 |
32 | function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
33 |
34 | var Floor =
35 | /*#__PURE__*/
36 | function (_Tile) {
37 | _inherits(Floor, _Tile);
38 |
39 | function Floor(x, y) {
40 | _classCallCheck(this, Floor);
41 |
42 | return _possibleConstructorReturn(this, _getPrototypeOf(Floor).call(this, x, y, 2, true));
43 | }
44 |
45 | _createClass(Floor, [{
46 | key: "stepOn",
47 | value: function stepOn(monster) {
48 | //TODO: complete
49 | if (monster.isPlayer && this.treasure) {
50 | _game["default"].score++;
51 |
52 | if (_game["default"].score % 3 == 0 && _game["default"].numActions < 9) {
53 | _game["default"].numActions++;
54 |
55 | _game["default"].player.addSpell();
56 | }
57 |
58 | (0, _assetmanager.playSound)("treasure");
59 | this.treasure = false;
60 |
61 | _game["default"].map.spawnMonster();
62 | }
63 | }
64 | }]);
65 |
66 | return Floor;
67 | }(_tile["default"]);
68 |
69 | exports["default"] = Floor;
--------------------------------------------------------------------------------
/lib/core/game.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = GameLoop;
7 |
8 | var _util = require("./util.js");
9 |
10 | var _eventmanager = require("./eventmanager.js");
11 |
12 | var _canvas = require("./canvas.js");
13 |
14 | /**
15 | * Clear the canvas.
16 | */
17 | function clear() {
18 | var canvas = (0, _canvas.getCanvas)();
19 | (0, _canvas.getContext)().clearRect(0, 0, canvas.width, canvas.height);
20 | }
21 | /**
22 | * The game loop updates and renders the game every frame. The game loop is stopped by default and will not start until the loops `start()` function is called.
23 | *
24 | * The game loop uses a time-based animation with a fixed `dt` to [avoid frame rate issues](http://blog.sklambert.com/using-time-based-animation-implement/). Each update call is guaranteed to equal 1/60 of a second.
25 | *
26 | * This means that you can avoid having to do time based calculations in your update functions and instead do fixed updates.
27 | *
28 | * ```js
29 | * import { Sprite, GameLoop } from 'kontra';
30 | *
31 | * let sprite = Sprite({
32 | * x: 100,
33 | * y: 200,
34 | * width: 20,
35 | * height: 40,
36 | * color: 'red'
37 | * });
38 | *
39 | * let loop = GameLoop({
40 | * update: function(dt) {
41 | * // no need to determine how many pixels you want to
42 | * // move every second and multiple by dt
43 | * // sprite.x += 180 * dt;
44 | *
45 | * // instead just update by how many pixels you want
46 | * // to move every frame and the loop will ensure 60FPS
47 | * sprite.x += 3;
48 | * },
49 | * render: function() {
50 | * sprite.render();
51 | * }
52 | * });
53 | *
54 | * loop.start();
55 | * ```
56 | * @sectionName GameLoop
57 | *
58 | * @param {Object} properties - Properties of the game loop.
59 | * @param {Function} properties.update - Function called every frame to update the game. Is passed the fixed `dt` as a parameter.
60 | * @param {Function} properties.render - Function called every frame to render the game.
61 | * @param {Number} [properties.fps=60] - Desired frame rate.
62 | * @param {Boolean} [properties.clearCanvas=true] - Clear the canvas every frame before the `render()` function is called.
63 | */
64 |
65 |
66 | function GameLoop() {
67 | var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
68 | _ref$fps = _ref.fps,
69 | fps = _ref$fps === void 0 ? 60 : _ref$fps,
70 | _ref$clearCanvas = _ref.clearCanvas,
71 | clearCanvas = _ref$clearCanvas === void 0 ? true : _ref$clearCanvas,
72 | update = _ref.update,
73 | render = _ref.render;
74 |
75 | // check for required functions
76 | // @if DEBUG
77 | if (!(update && render)) {
78 | throw Error("You must provide update() and render() functions");
79 | } // @endif
80 | // animation variables
81 |
82 |
83 | var accumulator = 0;
84 | var delta = 1e3 / fps; // delta between performance.now timings (in ms)
85 |
86 | var step = 1 / fps;
87 | var clearFn = clearCanvas ? clear : _util.noop;
88 | var last, rAF, now, dt, loop;
89 | /**
90 | * Called every frame of the game loop.
91 | */
92 |
93 | function frame() {
94 | rAF = requestAnimationFrame(frame);
95 | now = performance.now();
96 | dt = now - last;
97 | last = now; // prevent updating the game with a very large dt if the game were to lose focus
98 | // and then regain focus later
99 |
100 | if (dt > 1e3) {
101 | return;
102 | }
103 |
104 | (0, _eventmanager.emit)("tick");
105 | accumulator += dt;
106 |
107 | while (accumulator >= delta) {
108 | loop.update(step);
109 | accumulator -= delta;
110 | }
111 |
112 | clearFn();
113 | loop.render();
114 | } // game loop object
115 |
116 |
117 | loop = {
118 | /**
119 | * Called every frame to update the game. Put all of your games update logic here.
120 | * @memberof GameLoop
121 | * @function update
122 | *
123 | * @param {Number} dt - The fixed dt time of 1/60 of a frame.
124 | */
125 | update: update,
126 |
127 | /**
128 | * Called every frame to render the game. Put all of your games render logic here.
129 | * @memberof GameLoop
130 | * @function render
131 | */
132 | render: render,
133 |
134 | /**
135 | * If the game loop is currently stopped.
136 | *
137 | * ```js
138 | * import { GameLoop } from 'kontra';
139 | *
140 | * let loop = GameLoop({
141 | * // ...
142 | * });
143 | * console.log(loop.isStopped); //=> true
144 | *
145 | * loop.start();
146 | * console.log(loop.isStopped); //=> false
147 | *
148 | * loop.stop();
149 | * console.log(loop.isStopped); //=> true
150 | * ```
151 | * @memberof GameLoop
152 | * @property {Boolean} isStopped
153 | */
154 | isStopped: true,
155 |
156 | /**
157 | * Start the game loop.
158 | * @memberof GameLoop
159 | * @function start
160 | */
161 | start: function start() {
162 | last = performance.now();
163 | this.isStopped = false;
164 | requestAnimationFrame(frame);
165 | },
166 |
167 | /**
168 | * Stop the game loop.
169 | * @memberof GameLoop
170 | * @function stop
171 | */
172 | stop: function stop() {
173 | this.isStopped = true;
174 | cancelAnimationFrame(rAF);
175 | },
176 | // expose properties for testing
177 | // @if DEBUG
178 | _frame: frame,
179 |
180 | set _last(value) {
181 | last = value;
182 | } // @endif
183 |
184 |
185 | };
186 | return loop;
187 | }
--------------------------------------------------------------------------------
/lib/core/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 |
8 | var _canvas = _interopRequireDefault(require("./canvas"));
9 |
10 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
11 |
12 | var init = function init() {
13 | return {
14 | Canvas: _canvas["default"]
15 | };
16 | };
17 |
18 | var _default = init;
19 | exports["default"] = _default;
--------------------------------------------------------------------------------
/lib/core/keyboard.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports.initKeys = initKeys;
7 | exports.bindKeys = bindKeys;
8 | exports.unbindKeys = unbindKeys;
9 | exports.keyPressed = keyPressed;
10 | exports.keyMap = void 0;
11 |
12 | /**
13 | * A minimalistic keyboard API. You can use it move the main sprite or respond to a key press.
14 | *
15 | * ```js
16 | * import { initKeys, keyPressed } from 'kontra';
17 | *
18 | * // this function must be called first before keyboard
19 | * // functions will work
20 | * initKeys();
21 | *
22 | * function update() {
23 | * if (keyPressed('left')) {
24 | * // move left
25 | * }
26 | * }
27 | * ```
28 | * @sectionName Keyboard
29 | */
30 |
31 | /**
32 | * Below is a list of keys that are provided by default. If you need to extend this list, you can use the [keyMap](api/keyboard#keyMap) property.
33 | *
34 | * - a-z
35 | * - 0-9
36 | * - enter, esc, space, left, up, right, down
37 | * @sectionName Available Keys
38 | */
39 | var callbacks = {};
40 | var pressedKeys = {};
41 | /**
42 | * A map of keycodes to key names. Add to this object to expand the list of [available keys](api/keyboard#available-keys).
43 | *
44 | * ```js
45 | * import { keyMap, bindKeys } from 'kontra';
46 | *
47 | * keyMap[34] = 'pageDown';
48 | *
49 | * bindKeys('pageDown', function(e) {
50 | * // handle pageDown key
51 | * });
52 | * ```
53 | * @property {Object} keyMap
54 | */
55 |
56 | var keyMap = {
57 | // named keys
58 | Enter: "enter",
59 | Escape: "esc",
60 | Space: "space",
61 | ArrowLeft: "left",
62 | ArrowUp: "up",
63 | ArrowRight: "right",
64 | ArrowDown: "down",
65 | // for Edge compatibility
66 | 13: "enter",
67 | 27: "esc",
68 | 32: "space",
69 | 37: "left",
70 | 38: "up",
71 | 39: "right",
72 | 40: "down"
73 | };
74 | /**
75 | * Execute a function that corresponds to a keyboard key.
76 | *
77 | * @param {KeyboardEvent} evt
78 | */
79 |
80 | exports.keyMap = keyMap;
81 |
82 | function keydownEventHandler(evt) {
83 | var key = keyMap[evt.code || evt.which];
84 | pressedKeys[key] = true;
85 |
86 | if (callbacks[key]) {
87 | callbacks[key](evt);
88 | }
89 | }
90 | /**
91 | * Set the released key to not being pressed.
92 | *
93 | * @param {KeyboardEvent} evt
94 | */
95 |
96 |
97 | function keyupEventHandler(evt) {
98 | pressedKeys[keyMap[evt.code || evt.which]] = false;
99 | }
100 | /**
101 | * Reset pressed keys.
102 | */
103 |
104 |
105 | function blurEventHandler() {
106 | pressedKeys = {};
107 | }
108 | /**
109 | * Initialize keyboard event listeners. This function must be called before using other keyboard functions.
110 | * @function initKeys
111 | */
112 |
113 |
114 | function initKeys() {
115 | var i; // alpha keys
116 | // @see https://stackoverflow.com/a/43095772/2124254
117 |
118 | for (i = 0; i < 26; i++) {
119 | // rollupjs considers this a side-effect (for now), so we'll do it in the
120 | // initKeys function
121 | keyMap[i + 65] = keyMap["Key" + String.fromCharCode(i + 65)] = String.fromCharCode(i + 97);
122 | } // numeric keys
123 |
124 |
125 | for (i = 0; i < 10; i++) {
126 | keyMap[48 + i] = keyMap["Digit" + i] = "" + i;
127 | }
128 |
129 | window.addEventListener("keydown", keydownEventHandler);
130 | window.addEventListener("keyup", keyupEventHandler);
131 | window.addEventListener("blur", blurEventHandler);
132 | }
133 | /**
134 | * Bind a set of keys that will call the callback function when they are pressed. Takes a single key or an array of keys. Is passed the original KeyboardEvent as a parameter.
135 | *
136 | * ```js
137 | * import { initKeys, bindKeys } from 'kontra';
138 | *
139 | * initKeys();
140 | *
141 | * bindKeys('p', function(e) {
142 | * // pause the game
143 | * });
144 | * bindKeys(['enter', 'space'], function(e) {
145 | * e.preventDefault();
146 | * // fire gun
147 | * });
148 | * ```
149 | * @function bindKeys
150 | *
151 | * @param {String|String[]} keys - Key or keys to bind.
152 | */
153 |
154 |
155 | function bindKeys(keys, callback) {
156 | // smaller than doing `Array.isArray(keys) ? keys : [keys]`
157 | [].concat(keys).map(function (key) {
158 | return callbacks[key] = callback;
159 | });
160 | }
161 | /**
162 | * Remove the callback function for a bound set of keys. Takes a single key or an array of keys.
163 | *
164 | * ```js
165 | * import { unbindKeys } from 'kontra';
166 | *
167 | * unbindKeys('left');
168 | * unbindKeys(['enter', 'space']);
169 | * ```
170 | * @function unbindKeys
171 | *
172 | * @param {String|String[]} keys - Key or keys to unbind.
173 | */
174 |
175 |
176 | function unbindKeys(keys) {
177 | // 0 is the smallest falsy value
178 | [].concat(keys).map(function (key) {
179 | return callbacks[key] = 0;
180 | });
181 | }
182 | /**
183 | * Check if a key is currently pressed. Use during an `update()` function to perform actions each frame.
184 | *
185 | * ```js
186 | * import { Sprite, initKeys, keyPressed } from 'kontra';
187 | *
188 | * initKeys();
189 | *
190 | * let sprite = Sprite({
191 | * update: function() {
192 | * if (keyPressed('left')){
193 | * // left arrow pressed
194 | * }
195 | * else if (keyPressed('right')) {
196 | * // right arrow pressed
197 | * }
198 | *
199 | * if (keyPressed('up')) {
200 | * // up arrow pressed
201 | * }
202 | * else if (keyPressed('down')) {
203 | * // down arrow pressed
204 | * }
205 | * }
206 | * });
207 | * ```
208 | * @function keyPressed
209 | *
210 | * @param {String} key - Key to check for pressed state.
211 | *
212 | * @returns {Boolean} `true` if the key is pressed, `false` otherwise.
213 | */
214 |
215 |
216 | function keyPressed(key) {
217 | return !!pressedKeys[key];
218 | }
--------------------------------------------------------------------------------
/lib/core/map.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 |
8 | var _game = _interopRequireDefault(require("./game"));
9 |
10 | var _wall = _interopRequireDefault(require("./wall"));
11 |
12 | var _floor = _interopRequireDefault(require("./floor"));
13 |
14 | var _exit = _interopRequireDefault(require("./exit"));
15 |
16 | var _util = _interopRequireDefault(require("./util"));
17 |
18 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
19 |
20 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
21 |
22 | function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
23 |
24 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
25 |
26 | var Map =
27 | /*#__PURE__*/
28 | function () {
29 | function Map(numTiles) {
30 | _classCallCheck(this, Map);
31 |
32 | this.numTiles = numTiles;
33 | this.tiles = [];
34 | this.monsters = null;
35 | this.treasure = null;
36 | }
37 |
38 | _createClass(Map, [{
39 | key: "generateLevel",
40 | value: function generateLevel() {
41 | var _this = this;
42 |
43 | _util["default"].tryTo("generate map", function () {
44 | return _this.generateTiles() == _this.randomPassableTile().getConnectedTiles().length;
45 | });
46 |
47 | this.generateMonsters();
48 |
49 | for (var i = 0; i < 3; i++) {
50 | this.randomPassableTile().treasure = true;
51 | }
52 | }
53 | }, {
54 | key: "generateTiles",
55 | value: function generateTiles() {
56 | var passableTiles = 0;
57 |
58 | for (var i = 0; i < this.numTiles; i++) {
59 | this.tiles[i] = [];
60 |
61 | for (var j = 0; j < this.numTiles; j++) {
62 | if (Math.random() < 0.3 || !this.inBounds(i, j)) {
63 | this.tiles[i][j] = new _wall["default"](i, j);
64 | } else {
65 | this.tiles[i][j] = new _floor["default"](i, j);
66 | passableTiles++;
67 | }
68 | }
69 | }
70 |
71 | return passableTiles;
72 | }
73 | }, {
74 | key: "inBounds",
75 | value: function inBounds(x, y) {
76 | return x > 0 && y > 0 && x < this.numTiles - 1 && y < this.numTiles - 1;
77 | }
78 | }, {
79 | key: "getTile",
80 | value: function getTile(x, y) {
81 | if (this.inBounds(x, y)) {
82 | return this.tiles[x][y];
83 | } else {
84 | return new _wall["default"](x, y);
85 | }
86 | }
87 | }, {
88 | key: "randomPassableTile",
89 | value: function randomPassableTile() {
90 | var _this2 = this;
91 |
92 | var tile;
93 |
94 | _util["default"].tryTo("get random tile", function () {
95 | var x = _util["default"].randomRange(0, _this2.numTiles - 1);
96 |
97 | var y = _util["default"].randomRange(0, _this2.numTiles - 1);
98 |
99 | tile = _this2.getTile(x, y);
100 | return tile.passable && !tile.monster;
101 | });
102 |
103 | return tile;
104 | }
105 | }, {
106 | key: "generateMonsters",
107 | value: function generateMonsters() {
108 | this.monsters = [];
109 | var numMonsters = _game["default"].level + 1;
110 |
111 | for (var i = 0; i < numMonsters; i++) {
112 | this.spawnMonster();
113 | }
114 | }
115 | }, {
116 | key: "spawnMonster",
117 | value: function spawnMonster() {
118 | var monsterType = _util["default"].shuffle(_game["default"].monsterClasses)[0];
119 |
120 | var monster = new monsterType(this.randomPassableTile());
121 | this.monsters.push(monster);
122 | }
123 | }]);
124 |
125 | return Map;
126 | }();
127 |
128 | exports["default"] = Map;
--------------------------------------------------------------------------------
/lib/core/map/arena.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 |
8 | var _map = _interopRequireDefault(require("./map.js"));
9 |
10 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
11 |
12 | function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
13 |
14 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
15 |
16 | function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
17 |
18 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
19 |
20 | function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
21 |
22 | function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
23 |
24 | function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
25 |
26 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
27 |
28 | function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
29 |
30 | /**
31 | * @class Simple empty rectangular room
32 | * @augments ROT.Map
33 | */
34 | var Arena =
35 | /*#__PURE__*/
36 | function (_Map) {
37 | _inherits(Arena, _Map);
38 |
39 | function Arena() {
40 | _classCallCheck(this, Arena);
41 |
42 | return _possibleConstructorReturn(this, _getPrototypeOf(Arena).apply(this, arguments));
43 | }
44 |
45 | _createClass(Arena, [{
46 | key: "create",
47 | value: function create(callback) {
48 | var w = this._width - 1;
49 | var h = this._height - 1;
50 |
51 | for (var i = 0; i <= w; i++) {
52 | for (var j = 0; j <= h; j++) {
53 | var empty = i && j && i < w && j < h;
54 | callback(i, j, empty ? 0 : 1);
55 | }
56 | }
57 |
58 | return this;
59 | }
60 | }]);
61 |
62 | return Arena;
63 | }(_map["default"]);
64 |
65 | exports["default"] = Arena;
--------------------------------------------------------------------------------
/lib/core/map/dividedmaze.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 |
8 | var _map = _interopRequireDefault(require("./map.js"));
9 |
10 | var _rng = _interopRequireDefault(require("../rng.js"));
11 |
12 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
13 |
14 | function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
15 |
16 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
17 |
18 | function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
19 |
20 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
21 |
22 | function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
23 |
24 | function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
25 |
26 | function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
27 |
28 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
29 |
30 | function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
31 |
32 | /**
33 | * @class Recursively divided maze, http://en.wikipedia.org/wiki/Maze_generation_algorithm#Recursive_division_method
34 | * @augments ROT.Map
35 | */
36 | var DividedMaze =
37 | /*#__PURE__*/
38 | function (_Map) {
39 | _inherits(DividedMaze, _Map);
40 |
41 | function DividedMaze() {
42 | var _this;
43 |
44 | _classCallCheck(this, DividedMaze);
45 |
46 | _this = _possibleConstructorReturn(this, _getPrototypeOf(DividedMaze).apply(this, arguments));
47 | _this._stack = [];
48 | _this._map = [];
49 | return _this;
50 | }
51 |
52 | _createClass(DividedMaze, [{
53 | key: "create",
54 | value: function create(callback) {
55 | var w = this._width;
56 | var h = this._height;
57 | this._map = [];
58 |
59 | for (var i = 0; i < w; i++) {
60 | this._map.push([]);
61 |
62 | for (var j = 0; j < h; j++) {
63 | var border = i == 0 || j == 0 || i + 1 == w || j + 1 == h;
64 |
65 | this._map[i].push(border ? 1 : 0);
66 | }
67 | }
68 |
69 | this._stack = [[1, 1, w - 2, h - 2]];
70 |
71 | this._process();
72 |
73 | for (var _i = 0; _i < w; _i++) {
74 | for (var _j = 0; _j < h; _j++) {
75 | callback(_i, _j, this._map[_i][_j]);
76 | }
77 | }
78 |
79 | this._map = [];
80 | return this;
81 | }
82 | }, {
83 | key: "_process",
84 | value: function _process() {
85 | while (this._stack.length) {
86 | var room = this._stack.shift();
87 | /* [left, top, right, bottom] */
88 |
89 |
90 | this._partitionRoom(room);
91 | }
92 | }
93 | }, {
94 | key: "_partitionRoom",
95 | value: function _partitionRoom(room) {
96 | var availX = [];
97 | var availY = [];
98 |
99 | for (var i = room[0] + 1; i < room[2]; i++) {
100 | var top = this._map[i][room[1] - 1];
101 | var bottom = this._map[i][room[3] + 1];
102 |
103 | if (top && bottom && !(i % 2)) {
104 | availX.push(i);
105 | }
106 | }
107 |
108 | for (var j = room[1] + 1; j < room[3]; j++) {
109 | var left = this._map[room[0] - 1][j];
110 | var right = this._map[room[2] + 1][j];
111 |
112 | if (left && right && !(j % 2)) {
113 | availY.push(j);
114 | }
115 | }
116 |
117 | if (!availX.length || !availY.length) {
118 | return;
119 | }
120 |
121 | var x = _rng["default"].getItem(availX);
122 |
123 | var y = _rng["default"].getItem(availY);
124 |
125 | this._map[x][y] = 1;
126 | var walls = [];
127 | var w = [];
128 | walls.push(w);
129 | /* left part */
130 |
131 | for (var _i2 = room[0]; _i2 < x; _i2++) {
132 | this._map[_i2][y] = 1;
133 | if (_i2 % 2) w.push([_i2, y]);
134 | }
135 |
136 | w = [];
137 | walls.push(w);
138 | /* right part */
139 |
140 | for (var _i3 = x + 1; _i3 <= room[2]; _i3++) {
141 | this._map[_i3][y] = 1;
142 | if (_i3 % 2) w.push([_i3, y]);
143 | }
144 |
145 | w = [];
146 | walls.push(w);
147 | /* top part */
148 |
149 | for (var _j2 = room[1]; _j2 < y; _j2++) {
150 | this._map[x][_j2] = 1;
151 | if (_j2 % 2) w.push([x, _j2]);
152 | }
153 |
154 | w = [];
155 | walls.push(w);
156 | /* bottom part */
157 |
158 | for (var _j3 = y + 1; _j3 <= room[3]; _j3++) {
159 | this._map[x][_j3] = 1;
160 | if (_j3 % 2) w.push([x, _j3]);
161 | }
162 |
163 | var solid = _rng["default"].getItem(walls);
164 |
165 | for (var _i4 = 0; _i4 < walls.length; _i4++) {
166 | var _w = walls[_i4];
167 |
168 | if (_w == solid) {
169 | continue;
170 | }
171 |
172 | var hole = _rng["default"].getItem(_w);
173 |
174 | this._map[hole[0]][hole[1]] = 0;
175 | }
176 |
177 | this._stack.push([room[0], room[1], x - 1, y - 1]);
178 | /* left top */
179 |
180 |
181 | this._stack.push([x + 1, room[1], room[2], y - 1]);
182 | /* right top */
183 |
184 |
185 | this._stack.push([room[0], y + 1, x - 1, room[3]]);
186 | /* left bottom */
187 |
188 |
189 | this._stack.push([x + 1, y + 1, room[2], room[3]]);
190 | /* right bottom */
191 |
192 | }
193 | }]);
194 |
195 | return DividedMaze;
196 | }(_map["default"]);
197 |
198 | exports["default"] = DividedMaze;
--------------------------------------------------------------------------------
/lib/core/map/dungeon.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 |
8 | var _map = _interopRequireDefault(require("./map.js"));
9 |
10 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
11 |
12 | function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
13 |
14 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
15 |
16 | function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
17 |
18 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
19 |
20 | function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
21 |
22 | function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
23 |
24 | function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
25 |
26 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
27 |
28 | function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
29 |
30 | /**
31 | * @class Dungeon map: has rooms and corridors
32 | * @augments ROT.Map
33 | */
34 | var Dungeon =
35 | /*#__PURE__*/
36 | function (_Map) {
37 | _inherits(Dungeon, _Map);
38 |
39 | function Dungeon(width, height) {
40 | var _this;
41 |
42 | _classCallCheck(this, Dungeon);
43 |
44 | _this = _possibleConstructorReturn(this, _getPrototypeOf(Dungeon).call(this, width, height));
45 | _this._rooms = [];
46 | _this._corridors = [];
47 | return _this;
48 | }
49 | /**
50 | * Get all generated rooms
51 | * @returns {ROT.Map.Feature.Room[]}
52 | */
53 |
54 |
55 | _createClass(Dungeon, [{
56 | key: "getRooms",
57 | value: function getRooms() {
58 | return this._rooms;
59 | }
60 | /**
61 | * Get all generated corridors
62 | * @returns {ROT.Map.Feature.Corridor[]}
63 | */
64 |
65 | }, {
66 | key: "getCorridors",
67 | value: function getCorridors() {
68 | return this._corridors;
69 | }
70 | }]);
71 |
72 | return Dungeon;
73 | }(_map["default"]);
74 |
75 | exports["default"] = Dungeon;
--------------------------------------------------------------------------------
/lib/core/map/ellermaze.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 |
8 | var _map = _interopRequireDefault(require("./map.js"));
9 |
10 | var _rng = _interopRequireDefault(require("../rng.js"));
11 |
12 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
13 |
14 | function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
15 |
16 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
17 |
18 | function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
19 |
20 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
21 |
22 | function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
23 |
24 | function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
25 |
26 | function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
27 |
28 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
29 |
30 | function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
31 |
32 | /**
33 | * Join lists with "i" and "i+1"
34 | */
35 | function addToList(i, L, R) {
36 | R[L[i + 1]] = R[i];
37 | L[R[i]] = L[i + 1];
38 | R[i] = i + 1;
39 | L[i + 1] = i;
40 | }
41 | /**
42 | * Remove "i" from its list
43 | */
44 |
45 |
46 | function removeFromList(i, L, R) {
47 | R[L[i]] = R[i];
48 | L[R[i]] = L[i];
49 | R[i] = i;
50 | L[i] = i;
51 | }
52 | /**
53 | * Maze generator - Eller's algorithm
54 | * See http://homepages.cwi.nl/~tromp/maze.html for explanation
55 | */
56 |
57 |
58 | var EllerMaze =
59 | /*#__PURE__*/
60 | function (_Map) {
61 | _inherits(EllerMaze, _Map);
62 |
63 | function EllerMaze() {
64 | _classCallCheck(this, EllerMaze);
65 |
66 | return _possibleConstructorReturn(this, _getPrototypeOf(EllerMaze).apply(this, arguments));
67 | }
68 |
69 | _createClass(EllerMaze, [{
70 | key: "create",
71 | value: function create(callback) {
72 | var map = this._fillMap(1);
73 |
74 | var w = Math.ceil((this._width - 2) / 2);
75 | var rand = 9 / 24;
76 | var L = [];
77 | var R = [];
78 |
79 | for (var i = 0; i < w; i++) {
80 | L.push(i);
81 | R.push(i);
82 | }
83 |
84 | L.push(w - 1);
85 | /* fake stop-block at the right side */
86 |
87 | var j;
88 |
89 | for (j = 1; j + 3 < this._height; j += 2) {
90 | /* one row */
91 | for (var _i = 0; _i < w; _i++) {
92 | /* cell coords (will be always empty) */
93 | var x = 2 * _i + 1;
94 | var y = j;
95 | map[x][y] = 0;
96 | /* right connection */
97 |
98 | if (_i != L[_i + 1] && _rng["default"].getUniform() > rand) {
99 | addToList(_i, L, R);
100 | map[x + 1][y] = 0;
101 | }
102 | /* bottom connection */
103 |
104 |
105 | if (_i != L[_i] && _rng["default"].getUniform() > rand) {
106 | /* remove connection */
107 | removeFromList(_i, L, R);
108 | } else {
109 | /* create connection */
110 | map[x][y + 1] = 0;
111 | }
112 | }
113 | }
114 | /* last row */
115 |
116 |
117 | for (var _i2 = 0; _i2 < w; _i2++) {
118 | /* cell coords (will be always empty) */
119 | var _x = 2 * _i2 + 1;
120 |
121 | var _y = j;
122 | map[_x][_y] = 0;
123 | /* right connection */
124 |
125 | if (_i2 != L[_i2 + 1] && (_i2 == L[_i2] || _rng["default"].getUniform() > rand)) {
126 | /* dig right also if the cell is separated, so it gets connected to the rest of maze */
127 | addToList(_i2, L, R);
128 | map[_x + 1][_y] = 0;
129 | }
130 |
131 | removeFromList(_i2, L, R);
132 | }
133 |
134 | for (var _i3 = 0; _i3 < this._width; _i3++) {
135 | for (var _j = 0; _j < this._height; _j++) {
136 | callback(_i3, _j, map[_i3][_j]);
137 | }
138 | }
139 |
140 | return this;
141 | }
142 | }]);
143 |
144 | return EllerMaze;
145 | }(_map["default"]);
146 |
147 | exports["default"] = EllerMaze;
--------------------------------------------------------------------------------
/lib/core/map/iceymaze.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 |
8 | var _map = _interopRequireDefault(require("./map.js"));
9 |
10 | var _rng = _interopRequireDefault(require("../rng.js"));
11 |
12 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
13 |
14 | function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
15 |
16 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
17 |
18 | function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
19 |
20 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
21 |
22 | function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
23 |
24 | function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
25 |
26 | function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
27 |
28 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
29 |
30 | function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
31 |
32 | /**
33 | * Icey's Maze generator
34 | * See http://www.roguebasin.roguelikedevelopment.org/index.php?title=Simple_maze for explanation
35 | */
36 | var IceyMaze =
37 | /*#__PURE__*/
38 | function (_Map) {
39 | _inherits(IceyMaze, _Map);
40 |
41 | function IceyMaze(width, height) {
42 | var _this;
43 |
44 | var regularity = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
45 |
46 | _classCallCheck(this, IceyMaze);
47 |
48 | _this = _possibleConstructorReturn(this, _getPrototypeOf(IceyMaze).call(this, width, height));
49 | _this._regularity = regularity;
50 | _this._map = [];
51 | return _this;
52 | }
53 |
54 | _createClass(IceyMaze, [{
55 | key: "create",
56 | value: function create(callback) {
57 | var width = this._width;
58 | var height = this._height;
59 |
60 | var map = this._fillMap(1);
61 |
62 | width -= width % 2 ? 1 : 2;
63 | height -= height % 2 ? 1 : 2;
64 | var cx = 0;
65 | var cy = 0;
66 | var nx = 0;
67 | var ny = 0;
68 | var done = 0;
69 | var blocked = false;
70 | var dirs = [[0, 0], [0, 0], [0, 0], [0, 0]];
71 |
72 | do {
73 | cx = 1 + 2 * Math.floor(_rng["default"].getUniform() * (width - 1) / 2);
74 | cy = 1 + 2 * Math.floor(_rng["default"].getUniform() * (height - 1) / 2);
75 |
76 | if (!done) {
77 | map[cx][cy] = 0;
78 | }
79 |
80 | if (!map[cx][cy]) {
81 | this._randomize(dirs);
82 |
83 | do {
84 | if (Math.floor(_rng["default"].getUniform() * (this._regularity + 1)) == 0) {
85 | this._randomize(dirs);
86 | }
87 |
88 | blocked = true;
89 |
90 | for (var i = 0; i < 4; i++) {
91 | nx = cx + dirs[i][0] * 2;
92 | ny = cy + dirs[i][1] * 2;
93 |
94 | if (this._isFree(map, nx, ny, width, height)) {
95 | map[nx][ny] = 0;
96 | map[cx + dirs[i][0]][cy + dirs[i][1]] = 0;
97 | cx = nx;
98 | cy = ny;
99 | blocked = false;
100 | done++;
101 | break;
102 | }
103 | }
104 | } while (!blocked);
105 | }
106 | } while (done + 1 < width * height / 4);
107 |
108 | for (var _i = 0; _i < this._width; _i++) {
109 | for (var j = 0; j < this._height; j++) {
110 | callback(_i, j, map[_i][j]);
111 | }
112 | }
113 |
114 | this._map = [];
115 | return this;
116 | }
117 | }, {
118 | key: "_randomize",
119 | value: function _randomize(dirs) {
120 | for (var i = 0; i < 4; i++) {
121 | dirs[i][0] = 0;
122 | dirs[i][1] = 0;
123 | }
124 |
125 | switch (Math.floor(_rng["default"].getUniform() * 4)) {
126 | case 0:
127 | dirs[0][0] = -1;
128 | dirs[1][0] = 1;
129 | dirs[2][1] = -1;
130 | dirs[3][1] = 1;
131 | break;
132 |
133 | case 1:
134 | dirs[3][0] = -1;
135 | dirs[2][0] = 1;
136 | dirs[1][1] = -1;
137 | dirs[0][1] = 1;
138 | break;
139 |
140 | case 2:
141 | dirs[2][0] = -1;
142 | dirs[3][0] = 1;
143 | dirs[0][1] = -1;
144 | dirs[1][1] = 1;
145 | break;
146 |
147 | case 3:
148 | dirs[1][0] = -1;
149 | dirs[0][0] = 1;
150 | dirs[3][1] = -1;
151 | dirs[2][1] = 1;
152 | break;
153 | }
154 | }
155 | }, {
156 | key: "_isFree",
157 | value: function _isFree(map, x, y, width, height) {
158 | if (x < 1 || y < 1 || x >= width || y >= height) {
159 | return false;
160 | }
161 |
162 | return map[x][y];
163 | }
164 | }]);
165 |
166 | return IceyMaze;
167 | }(_map["default"]);
168 |
169 | exports["default"] = IceyMaze;
--------------------------------------------------------------------------------
/lib/core/map/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 |
8 | var _arena = _interopRequireDefault(require("./arena.js"));
9 |
10 | var _uniform = _interopRequireDefault(require("./uniform.js"));
11 |
12 | var _cellular = _interopRequireDefault(require("./cellular.js"));
13 |
14 | var _digger = _interopRequireDefault(require("./digger.js"));
15 |
16 | var _ellermaze = _interopRequireDefault(require("./ellermaze.js"));
17 |
18 | var _dividedmaze = _interopRequireDefault(require("./dividedmaze.js"));
19 |
20 | var _iceymaze = _interopRequireDefault(require("./iceymaze.js"));
21 |
22 | var _rogue = _interopRequireDefault(require("./rogue.js"));
23 |
24 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
25 |
26 | var _default = {
27 | Arena: _arena["default"],
28 | Uniform: _uniform["default"],
29 | Cellular: _cellular["default"],
30 | Digger: _digger["default"],
31 | EllerMaze: _ellermaze["default"],
32 | DividedMaze: _dividedmaze["default"],
33 | IceyMaze: _iceymaze["default"],
34 | Rogue: _rogue["default"]
35 | };
36 | exports["default"] = _default;
--------------------------------------------------------------------------------
/lib/core/map/map.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 |
8 | var _constants = require("../../constants");
9 |
10 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
11 |
12 | function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
13 |
14 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
15 |
16 | var Map =
17 | /*#__PURE__*/
18 | function () {
19 | /**
20 | * @class Base map generator
21 | * @param {int} [width=ROT.DEFAULT_WIDTH]
22 | * @param {int} [height=ROT.DEFAULT_HEIGHT]
23 | */
24 | function Map() {
25 | var width = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _constants.DEFAULT_WIDTH;
26 | var height = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _constants.DEFAULT_HEIGHT;
27 |
28 | _classCallCheck(this, Map);
29 |
30 | this._width = width;
31 | this._height = height;
32 | }
33 |
34 | _createClass(Map, [{
35 | key: "create",
36 | value: function create(callback) {}
37 | }, {
38 | key: "_fillMap",
39 | value: function _fillMap(value) {
40 | var map = [];
41 |
42 | for (var i = 0; i < this._width; i++) {
43 | map.push([]);
44 |
45 | for (var j = 0; j < this._height; j++) {
46 | map[i].push(value);
47 | }
48 | }
49 |
50 | return map;
51 | }
52 | }]);
53 |
54 | return Map;
55 | }();
56 |
57 | exports["default"] = Map;
--------------------------------------------------------------------------------
/lib/core/options.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 | var Options = {
8 | x: 0,
9 | y: 0,
10 | gameState: "loading"
11 | };
12 | var _default = Options;
13 | exports["default"] = _default;
--------------------------------------------------------------------------------
/lib/core/player.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 |
8 | var _assetmanager = require("./assetmanager");
9 |
10 | var _game = _interopRequireDefault(require("./game"));
11 |
12 | var _entity = _interopRequireDefault(require("./entity"));
13 |
14 | var _actions = _interopRequireDefault(require("../../Examples/Actions/actions"));
15 |
16 | var _util = _interopRequireDefault(require("./util"));
17 |
18 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
19 |
20 | function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
21 |
22 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
23 |
24 | function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
25 |
26 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
27 |
28 | function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
29 |
30 | function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
31 |
32 | function _get(target, property, receiver) { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(receiver); } return desc.value; }; } return _get(target, property, receiver || target); }
33 |
34 | function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; }
35 |
36 | function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
37 |
38 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
39 |
40 | function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
41 |
42 | var Player =
43 | /*#__PURE__*/
44 | function (_Entity) {
45 | _inherits(Player, _Entity);
46 |
47 | function Player(tile) {
48 | var _this;
49 |
50 | _classCallCheck(this, Player);
51 |
52 | _this = _possibleConstructorReturn(this, _getPrototypeOf(Player).call(this, tile, 0, 3));
53 | _this.isPlayer = true;
54 | _this.teleportCounter = 0;
55 | _this.actions = _util["default"].shuffle(Object.keys(_actions["default"])).splice(0, _game["default"].numActions);
56 | return _this;
57 | }
58 |
59 | _createClass(Player, [{
60 | key: "update",
61 | value: function update() {
62 | this.shield--;
63 | }
64 | }, {
65 | key: "tryMove",
66 | value: function tryMove(dx, dy) {
67 | if (_get(_getPrototypeOf(Player.prototype), "tryMove", this).call(this, dx, dy)) {
68 | _game["default"].tick();
69 | }
70 | }
71 | }, {
72 | key: "addAction",
73 | value: function addAction() {
74 | var newAction = _util["default"].shuffle(Object.keys(_actions["default"]))[0];
75 |
76 | this.actions.push(newAction);
77 | } // TODO Fix perform actions
78 |
79 | }, {
80 | key: "performAction",
81 | value: function performAction(index) {
82 | var actionName = this.actions[index];
83 |
84 | if (actionName) {
85 | delete this.actions[index];
86 |
87 | _actions["default"][actionName]();
88 |
89 | (0, _assetmanager.playSound)("spell");
90 |
91 | _game["default"].tick();
92 | }
93 | }
94 | }]);
95 |
96 | return Player;
97 | }(_entity["default"]);
98 |
99 | exports["default"] = Player;
--------------------------------------------------------------------------------
/lib/core/plugin.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports.registerPlugin = registerPlugin;
7 | exports.unregisterPlugin = unregisterPlugin;
8 | exports.extendObject = extendObject;
9 |
10 | function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }
11 |
12 | function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }
13 |
14 | function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }
15 |
16 | function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }
17 |
18 | /**
19 | * A plugin system based on the [interceptor pattern](https://en.wikipedia.org/wiki/Interceptor_pattern), designed to share reusable code such as more advance collision detection or a 2D physics engine.
20 | *
21 | * ```js
22 | * import { registerPlugin, Sprite } from 'RogueIO';
23 | * import loggingPlugin from 'path/to/plugin/code.js'
24 | *
25 | * // register a plugin that adds logging to all Sprites
26 | * registerPlugin(Sprite, loggingPlugin);
27 | * ```
28 | * @sectionName Plugin
29 | */
30 |
31 | /**
32 | * @docs docs/api_docs/plugin.js
33 | */
34 |
35 | /**
36 | * Get the RogueIO object method name from the plugin.
37 | *
38 | * @param {String} methodName - Before/After function name
39 | *
40 | * @returns {String}
41 | */
42 | function getMethod(methodName) {
43 | var methodTitle = methodName.substr(methodName.search(/[A-Z]/));
44 | return methodTitle[0].toLowerCase() + methodTitle.substr(1);
45 | }
46 | /**
47 | * Remove an interceptor.
48 | *
49 | * @param {function[]} interceptors - Before/After interceptor list
50 | * @param {function} fn - Interceptor function
51 | */
52 |
53 |
54 | function removeInterceptor(interceptors, fn) {
55 | var index = interceptors.indexOf(fn);
56 |
57 | if (index !== -1) {
58 | interceptors.splice(index, 1);
59 | }
60 | }
61 | /**
62 | * Register a plugin to run a set of functions before or after the RogueIO object functions.
63 | * @function registerPlugin
64 | *
65 | * @param {Object} RogueIOObj - RogueIO object to attach the plugin to.
66 | * @param {Object} pluginObj - Plugin object with before and after intercept functions.
67 | */
68 |
69 |
70 | function registerPlugin(RogueIOObj, pluginObj) {
71 | var objectProto = RogueIOObj.prototype;
72 | if (!objectProto) return; // create interceptor list and functions
73 |
74 | if (!objectProto._inc) {
75 | objectProto._inc = {};
76 |
77 | objectProto._bInc = function beforePlugins(context, method) {
78 | for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
79 | args[_key - 2] = arguments[_key];
80 | }
81 |
82 | return this._inc[method].before.reduce(function (acc, fn) {
83 | var newArgs = fn.apply(void 0, [context].concat(_toConsumableArray(acc)));
84 | return newArgs ? newArgs : acc;
85 | }, args);
86 | };
87 |
88 | objectProto._aInc = function afterPlugins(context, method, result) {
89 | for (var _len2 = arguments.length, args = new Array(_len2 > 3 ? _len2 - 3 : 0), _key2 = 3; _key2 < _len2; _key2++) {
90 | args[_key2 - 3] = arguments[_key2];
91 | }
92 |
93 | return this._inc[method].after.reduce(function (acc, fn) {
94 | var newResult = fn.apply(void 0, [context, acc].concat(args));
95 | return newResult ? newResult : acc;
96 | }, result);
97 | };
98 | } // add plugin to interceptors
99 |
100 |
101 | Object.getOwnPropertyNames(pluginObj).forEach(function (methodName) {
102 | var method = getMethod(methodName);
103 | if (!objectProto[method]) return; // override original method
104 |
105 | if (!objectProto["_o" + method]) {
106 | objectProto["_o" + method] = objectProto[method];
107 |
108 | objectProto[method] = function interceptedFn() {
109 | var _objectProto;
110 |
111 | for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
112 | args[_key3] = arguments[_key3];
113 | }
114 |
115 | // call before interceptors
116 | var alteredArgs = this._bInc.apply(this, [this, method].concat(args));
117 |
118 | var result = (_objectProto = objectProto["_o" + method]).call.apply(_objectProto, [this].concat(_toConsumableArray(alteredArgs))); // call after interceptors
119 |
120 |
121 | return this._aInc.apply(this, [this, method, result].concat(args));
122 | };
123 | } // create interceptors for the method
124 |
125 |
126 | if (!objectProto._inc[method]) {
127 | objectProto._inc[method] = {
128 | before: [],
129 | after: []
130 | };
131 | }
132 |
133 | if (methodName.startsWith("before")) {
134 | objectProto._inc[method].before.push(pluginObj[methodName]);
135 | } else if (methodName.startsWith("after")) {
136 | objectProto._inc[method].after.push(pluginObj[methodName]);
137 | }
138 | });
139 | }
140 | /**
141 | * Unregister a plugin from a RogueIO object.
142 | * @function unregisterPlugin
143 | *
144 | * @param {Object} RogueIOObj - RogueIO object to detach plugin from.
145 | * @param {Object} pluginObj - The plugin object that was passed during registration.
146 | */
147 |
148 |
149 | function unregisterPlugin(RogueIOObj, pluginObj) {
150 | var objectProto = RogueIOObj.prototype;
151 | if (!objectProto || !objectProto._inc) return; // remove plugin from interceptors
152 |
153 | Object.getOwnPropertyNames(pluginObj).forEach(function (methodName) {
154 | var method = getMethod(methodName);
155 |
156 | if (methodName.startsWith("before")) {
157 | removeInterceptor(objectProto._inc[method].before, pluginObj[methodName]);
158 | } else if (methodName.startsWith("after")) {
159 | removeInterceptor(objectProto._inc[method].after, pluginObj[methodName]);
160 | }
161 | });
162 | }
163 | /**
164 | * Safely extend the functionality of a RogueIO object. Any properties that already exist on the RogueIO object will not be added.
165 | *
166 | * ```js
167 | * import { extendObject, Vector } from 'RogueIO';
168 | *
169 | * // add a subtract function to all Vectors
170 | * extendObject(Vector, {
171 | * subtract(vec) {
172 | * return Vector(this.x - vec.x, this.y - vec.y);
173 | * }
174 | * });
175 | * ```
176 | * @function extendObject
177 | *
178 | * @param {Object} RogueIOObj - RogueIO object to extend
179 | * @param {Object} properties - Properties to add.
180 | */
181 |
182 |
183 | function extendObject(RogueIOObj, properties) {
184 | var objectProto = RogueIOObj.prototype;
185 | if (!objectProto) return;
186 | Object.getOwnPropertyNames(properties).forEach(function (prop) {
187 | if (!objectProto[prop]) {
188 | objectProto[prop] = properties[prop];
189 | }
190 | });
191 | }
--------------------------------------------------------------------------------
/lib/core/pool.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = poolFactory;
7 |
8 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
9 |
10 | function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
11 |
12 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
13 |
14 | /**
15 | * A fast and memory efficient [object pool](https://gameprogrammingpatterns.com/object-pool.html) for sprite reuse. Perfect for particle systems or SHUMPs. The pool starts out with just one object, but will grow in size to accommodate as many objects as are needed.
16 | *
17 | *
18 | *
19 | * @class Pool
20 | *
21 | * @param {Object} properties - Properties of the pool.
22 | * @param {Function} properties.create - Function that returns a new object to be added to the pool when there are no more alive objects.
23 | * @param {Number} [properties.maxSize=1024] - The maximum number of objects allowed in the pool. The pool will never grow beyond this size.
24 | */
25 | var Pool =
26 | /*#__PURE__*/
27 | function () {
28 | /**
29 | * @docs docs/api_docs/pool.js
30 | */
31 | function Pool() {
32 | var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
33 | create = _ref.create,
34 | _ref$maxSize = _ref.maxSize,
35 | maxSize = _ref$maxSize === void 0 ? 1024 : _ref$maxSize;
36 |
37 | _classCallCheck(this, Pool);
38 |
39 | // check for the correct structure of the objects added to pools so we know that the
40 | // rest of the pool code will work without errors
41 | // @if DEBUG
42 | var obj;
43 |
44 | if (!create || !(obj = create()) || !(obj.update && obj.init && obj.isAlive)) {
45 | throw Error("Must provide create() function which returns an object with init(), update(), and isAlive() functions");
46 | } // @endif
47 | // c = create
48 |
49 |
50 | this._c = create;
51 | /**
52 | * All objects currently in the pool, both alive and not alive.
53 | * @memberof Pool
54 | * @property {Object[]} objects
55 | */
56 |
57 | this.objects = [create()]; // start the pool with an object
58 |
59 | /**
60 | * The number of alive objects.
61 | * @memberof Pool
62 | * @property {Number} size
63 | */
64 |
65 | this.size = 0;
66 | /**
67 | * The maximum number of objects allowed in the pool. The pool will never grow beyond this size.
68 | * @memberof Pool
69 | * @property {Number} maxSize
70 | */
71 |
72 | this.maxSize = maxSize;
73 | }
74 | /**
75 | * Get and return an object from the pool. The properties parameter will be passed directly to the objects `init()` function. If you're using a kontra.Sprite, you should also pass the `ttl` property to designate how many frames you want the object to be alive for.
76 | *
77 | * If you want to control when the sprite is ready for reuse, pass `Infinity` for `ttl`. You'll need to set the sprites `ttl` to `0` when you're ready for the sprite to be reused.
78 | *
79 | * ```js
80 | * // exclude-tablist
81 | * let sprite = pool.get({
82 | * // the object will get these properties and values
83 | * x: 100,
84 | * y: 200,
85 | * width: 20,
86 | * height: 40,
87 | * color: 'red',
88 | *
89 | * // pass Infinity for ttl to prevent the object from being reused
90 | * // until you set it back to 0
91 | * ttl: Infinity
92 | * });
93 | * ```
94 | * @memberof Pool
95 | * @function get
96 | *
97 | * @param {Object} properties - Properties to pass to the objects `init()` function.
98 | *
99 | * @returns {Object} The newly initialized object.
100 | */
101 |
102 |
103 | _createClass(Pool, [{
104 | key: "get",
105 | value: function get() {
106 | var properties = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
107 |
108 | // the pool is out of objects if the first object is in use and it can't grow
109 | if (this.size === this.objects.length) {
110 | if (this.size === this.maxSize) {
111 | return;
112 | } // double the size of the array by adding twice as many new objects to the end
113 | else {
114 | for (var i = 0; i < this.size && this.objects.length < this.maxSize; i++) {
115 | this.objects.push(this._c());
116 | }
117 | }
118 | } // save off first object in pool to reassign to last object after unshift
119 |
120 |
121 | var obj = this.objects[this.size];
122 | this.size++;
123 | obj.init(properties);
124 | return obj;
125 | }
126 | /**
127 | * Returns an array of all alive objects. Useful if you need to do special processing on all alive objects outside of the pool, such as add all alive objects to a kontra.Quadtree.
128 | * @memberof Pool
129 | * @function getAliveObjects
130 | *
131 | * @returns {Object[]} An Array of all alive objects.
132 | */
133 |
134 | }, {
135 | key: "getAliveObjects",
136 | value: function getAliveObjects() {
137 | return this.objects.slice(0, this.size);
138 | }
139 | /**
140 | * Clear the object pool. Removes all objects from the pool and resets its [size](api/pool#size) to 1.
141 | * @memberof Pool
142 | * @function clear
143 | */
144 |
145 | }, {
146 | key: "clear",
147 | value: function clear() {
148 | this.size = this.objects.length = 0;
149 | this.objects.push(this._c());
150 | }
151 | /**
152 | * Update all alive objects in the pool by calling the objects `update()` function. This function also manages when each object should be recycled, so it is recommended that you do not call the objects `update()` function outside of this function.
153 | * @memberof Pool
154 | * @function update
155 | *
156 | * @param {Number} [dt] - Time since last update.
157 | */
158 |
159 | }, {
160 | key: "update",
161 | value: function update(dt) {
162 | var obj;
163 | var doSort = false;
164 |
165 | for (var i = this.size; i--;) {
166 | obj = this.objects[i];
167 | obj.update(dt);
168 |
169 | if (!obj.isAlive()) {
170 | doSort = true;
171 | this.size--;
172 | }
173 | } // sort all dead elements to the end of the pool
174 |
175 |
176 | if (doSort) {
177 | this.objects.sort(function (a, b) {
178 | return b.isAlive() - a.isAlive();
179 | });
180 | }
181 | }
182 | /**
183 | * Render all alive objects in the pool by calling the objects `render()` function.
184 | * @memberof Pool
185 | * @function render
186 | */
187 |
188 | }, {
189 | key: "render",
190 | value: function render() {
191 | for (var i = this.size; i--;) {
192 | this.objects[i].render();
193 | }
194 | }
195 | }]);
196 |
197 | return Pool;
198 | }();
199 |
200 | function poolFactory(properties) {
201 | return new Pool(properties);
202 | }
203 |
204 | poolFactory.prototype = Pool.prototype;
205 | poolFactory["class"] = Pool;
--------------------------------------------------------------------------------
/lib/core/rng.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 |
8 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
9 |
10 | function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
11 |
12 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
13 |
14 | /**
15 | * This code is an implementation of Alea algorithm; (C) 2010 Johannes Baagøe.
16 | * Alea is licensed according to the http://en.wikipedia.org/wiki/MIT_License.
17 | */
18 | var FRAC = 2.3283064365386963e-10;
19 | /* 2^-32 */
20 |
21 | var RNG =
22 | /*#__PURE__*/
23 | function () {
24 | function RNG() {
25 | _classCallCheck(this, RNG);
26 |
27 | this._seed = 0;
28 | this._s0 = 0;
29 | this._s1 = 0;
30 | this._s2 = 0;
31 | this._c = 0;
32 | }
33 |
34 | _createClass(RNG, [{
35 | key: "getSeed",
36 | value: function getSeed() {
37 | return this._seed;
38 | }
39 | /**
40 | * Seed the number generator
41 | */
42 |
43 | }, {
44 | key: "setSeed",
45 | value: function setSeed(seed) {
46 | seed = seed < 1 ? 1 / seed : seed;
47 | this._seed = seed;
48 | this._s0 = (seed >>> 0) * FRAC;
49 | seed = seed * 69069 + 1 >>> 0;
50 | this._s1 = seed * FRAC;
51 | seed = seed * 69069 + 1 >>> 0;
52 | this._s2 = seed * FRAC;
53 | this._c = 1;
54 | return this;
55 | }
56 | /**
57 | * @returns Pseudorandom value [0,1), uniformly distributed
58 | */
59 |
60 | }, {
61 | key: "getUniform",
62 | value: function getUniform() {
63 | var t = 2091639 * this._s0 + this._c * FRAC;
64 | this._s0 = this._s1;
65 | this._s1 = this._s2;
66 | this._c = t | 0;
67 | this._s2 = t - this._c;
68 | return this._s2;
69 | }
70 | /**
71 | * @param lowerBound The lower end of the range to return a value from, inclusive
72 | * @param upperBound The upper end of the range to return a value from, inclusive
73 | * @returns Pseudorandom value [lowerBound, upperBound], using ROT.RNG.getUniform() to distribute the value
74 | */
75 |
76 | }, {
77 | key: "getUniformInt",
78 | value: function getUniformInt(lowerBound, upperBound) {
79 | var max = Math.max(lowerBound, upperBound);
80 | var min = Math.min(lowerBound, upperBound);
81 | return Math.floor(this.getUniform() * (max - min + 1)) + min;
82 | }
83 | /**
84 | * @param mean Mean value
85 | * @param stddev Standard deviation. ~95% of the absolute values will be lower than 2*stddev.
86 | * @returns A normally distributed pseudorandom value
87 | */
88 |
89 | }, {
90 | key: "getNormal",
91 | value: function getNormal() {
92 | var mean = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
93 | var stddev = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
94 | var u, v, r;
95 |
96 | do {
97 | u = 2 * this.getUniform() - 1;
98 | v = 2 * this.getUniform() - 1;
99 | r = u * u + v * v;
100 | } while (r > 1 || r == 0);
101 |
102 | var gauss = u * Math.sqrt(-2 * Math.log(r) / r);
103 | return mean + gauss * stddev;
104 | }
105 | /**
106 | * @returns Pseudorandom value [1,100] inclusive, uniformly distributed
107 | */
108 |
109 | }, {
110 | key: "getPercentage",
111 | value: function getPercentage() {
112 | return 1 + Math.floor(this.getUniform() * 100);
113 | }
114 | /**
115 | * @returns Randomly picked item, null when length=0
116 | */
117 |
118 | }, {
119 | key: "getItem",
120 | value: function getItem(array) {
121 | if (!array.length) {
122 | return null;
123 | }
124 |
125 | return array[Math.floor(this.getUniform() * array.length)];
126 | }
127 | /**
128 | * @returns New array with randomized items
129 | */
130 |
131 | }, {
132 | key: "shuffle",
133 | value: function shuffle(array) {
134 | var result = [];
135 | var clone = array.slice();
136 |
137 | while (clone.length) {
138 | var index = clone.indexOf(this.getItem(clone));
139 | result.push(clone.splice(index, 1)[0]);
140 | }
141 |
142 | return result;
143 | }
144 | /**
145 | * @param data key=whatever, value=weight (relative probability)
146 | * @returns whatever
147 | */
148 |
149 | }, {
150 | key: "getWeightedValue",
151 | value: function getWeightedValue(data) {
152 | var total = 0;
153 |
154 | for (var _id in data) {
155 | total += data[_id];
156 | }
157 |
158 | var random = this.getUniform() * total;
159 | var id,
160 | part = 0;
161 |
162 | for (id in data) {
163 | part += data[id];
164 |
165 | if (random < part) {
166 | return id;
167 | }
168 | } // If by some floating-point annoyance we have
169 | // random >= total, just return the last id.
170 |
171 |
172 | return id;
173 | }
174 | /**
175 | * Get RNG state. Useful for storing the state and re-setting it via setState.
176 | * @returns Internal state
177 | */
178 |
179 | }, {
180 | key: "getState",
181 | value: function getState() {
182 | return [this._s0, this._s1, this._s2, this._c];
183 | }
184 | /**
185 | * Set a previously retrieved state.
186 | */
187 |
188 | }, {
189 | key: "setState",
190 | value: function setState(state) {
191 | this._s0 = state[0];
192 | this._s1 = state[1];
193 | this._s2 = state[2];
194 | this._c = state[3];
195 | return this;
196 | }
197 | /**
198 | * Returns a cloned RNG
199 | */
200 |
201 | }, {
202 | key: "clone",
203 | value: function clone() {
204 | var clone = new RNG();
205 | return clone.setState(this.getState());
206 | }
207 | }]);
208 |
209 | return RNG;
210 | }();
211 |
212 | var _default = new RNG().setSeed(Date.now());
213 |
214 | exports["default"] = _default;
--------------------------------------------------------------------------------
/lib/core/store.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports.setStoreItem = setStoreItem;
7 | exports.getStoreItem = getStoreItem;
8 |
9 | /**
10 | * A simple interface to LocalStorage based on [store.js](https://github.com/marcuswestin/store.js), whose sole purpose is to ensure that any keys you save to LocalStorage come out the same type as when they went in.
11 | *
12 | * Normally when you save something to LocalStorage, it converts it into a string. So if you were to save a number, it would be saved as `"12"` instead of `12`. This means when you retrieved the number, it would now be a string.
13 | *
14 | * ```js
15 | * import { setStoreItem, getStoreItem } from 'RogueIO';
16 | *
17 | * setStoreItem('highScore', 100);
18 | * getStoreItem('highScore'); //=> 100
19 | * ```
20 | * @sectionName Store
21 | */
22 |
23 | /**
24 | * Save an item to localStorage.
25 | * @function setStoreItem
26 | *
27 | * @param {String} key - The name of the key.
28 | * @param {*} value - The value to store.
29 | */
30 | function setStoreItem(key, value) {
31 | if (value === undefined) {
32 | localStorage.removeItem(key);
33 | } else {
34 | localStorage.setItem(key, JSON.stringify(value));
35 | }
36 | }
37 | /**
38 | * Retrieve an item from localStorage and convert it back to its original type.
39 | * @function getStoreItem
40 | *
41 | * @param {String} key - Name of the key of the item to retrieve.
42 | *
43 | * @returns {*} The retrieved item.
44 | */
45 |
46 |
47 | function getStoreItem(key) {
48 | var value = localStorage.getItem(key);
49 |
50 | try {
51 | value = JSON.parse(value);
52 | } catch (e) {}
53 |
54 | return value;
55 | }
--------------------------------------------------------------------------------
/lib/core/tile.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 |
8 | var _game = _interopRequireDefault(require("./game"));
9 |
10 | var _spritesheet = _interopRequireDefault(require("./spritesheet"));
11 |
12 | var _util = _interopRequireDefault(require("./util"));
13 |
14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
15 |
16 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
17 |
18 | function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
19 |
20 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
21 |
22 | var Tile =
23 | /*#__PURE__*/
24 | function () {
25 | function Tile(x, y, sprite, passable) {
26 | _classCallCheck(this, Tile);
27 |
28 | this.ctx = null;
29 | this.x = x;
30 | this.y = y;
31 | this.sprite = sprite;
32 | this.passable = passable;
33 | }
34 |
35 | _createClass(Tile, [{
36 | key: "replace",
37 | value: function replace(newTileType) {
38 | _game["default"].map.tiles[this.x][this.y] = new newTileType(this.x, this.y);
39 | return _game["default"].map.tiles[this.x][this.y];
40 | } //manhattan distance
41 |
42 | }, {
43 | key: "dist",
44 | value: function dist(other) {
45 | return Math.abs(this.x - other.x) + Math.abs(this.y - other.y);
46 | }
47 | }, {
48 | key: "getNeighbor",
49 | value: function getNeighbor(dx, dy) {
50 | return _game["default"].map.getTile(this.x + dx, this.y + dy);
51 | }
52 | }, {
53 | key: "getAdjacentNeighbors",
54 | value: function getAdjacentNeighbors() {
55 | return _util["default"].shuffle([this.getNeighbor(0, -1), this.getNeighbor(0, 1), this.getNeighbor(-1, 0), this.getNeighbor(1, 0)]);
56 | }
57 | }, {
58 | key: "getAdjacentPassableNeighbors",
59 | value: function getAdjacentPassableNeighbors() {
60 | return this.getAdjacentNeighbors().filter(function (t) {
61 | return t.passable;
62 | });
63 | }
64 | }, {
65 | key: "getConnectedTiles",
66 | value: function getConnectedTiles() {
67 | var connectedTiles = [this];
68 | var frontier = [this];
69 |
70 | while (frontier.length) {
71 | var neighbors = frontier.pop().getAdjacentPassableNeighbors().filter(function (t) {
72 | return !connectedTiles.includes(t);
73 | });
74 | connectedTiles = connectedTiles.concat(neighbors);
75 | frontier = frontier.concat(neighbors);
76 | }
77 |
78 | return connectedTiles;
79 | }
80 | }, {
81 | key: "draw",
82 | value: function draw() {
83 | this.ctx = _game["default"].canvas.getCtx();
84 | var spriteSheet = new _spritesheet["default"]({
85 | ctx: this.ctx,
86 | tilesize: _game["default"].tilesize
87 | });
88 | spriteSheet.drawSprite(this.sprite, this.x, this.y);
89 |
90 | if (this.treasure) {
91 | spriteSheet.drawSprite(12, this.x, this.y);
92 | }
93 |
94 | if (this.effectCounter) {
95 | this.effectCounter--;
96 | this.ctx.globalAlpha = this.effectCounter / 30;
97 | spriteSheet.drawSprite(this.effect, this.x, this.y);
98 | this.ctx.globalAlpha = 1;
99 | }
100 | }
101 | }, {
102 | key: "setEffect",
103 | value: function setEffect(effectSprite) {
104 | this.effect = effectSprite;
105 | this.effectCounter = 30;
106 | }
107 | }]);
108 |
109 | return Tile;
110 | }();
111 |
112 | exports["default"] = Tile;
--------------------------------------------------------------------------------
/lib/core/util.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports.mod = mod;
7 | exports.clamp = clamp;
8 | exports.capitalize = capitalize;
9 | exports.format = format;
10 | exports.rightPad = exports.shuffle = exports.randomRange = exports.tryTo = exports.noop = void 0;
11 |
12 | var _this = void 0;
13 |
14 | var noop = function noop() {};
15 |
16 | exports.noop = noop;
17 |
18 | var tryTo = function tryTo(desc, callback) {
19 | for (var timeout = 1000; timeout > 0; timeout--) {
20 | if (callback()) {
21 | return;
22 | }
23 | }
24 |
25 | throw "Timeout while tring to " + desc;
26 | };
27 |
28 | exports.tryTo = tryTo;
29 |
30 | var randomRange = function randomRange(min, max) {
31 | return Math.floor(Math.random() * (max - min + 1)) + min;
32 | };
33 |
34 | exports.randomRange = randomRange;
35 |
36 | var shuffle = function shuffle(arr) {
37 | var temp, r;
38 |
39 | for (var i = 1; i < arr.length; i++) {
40 | r = _this.randomRange(0, i);
41 | temp = arr[i];
42 | arr[i] = arr[r];
43 | arr[r] = temp;
44 | }
45 |
46 | return arr;
47 | };
48 |
49 | exports.shuffle = shuffle;
50 |
51 | var rightPad = function rightPad(textArray) {
52 | var finalText = "";
53 | textArray.forEach(function (text) {
54 | text += "";
55 |
56 | for (var i = text.length; i < 10; i++) {
57 | text += " ";
58 | }
59 |
60 | finalText += text;
61 | });
62 | return finalText;
63 | };
64 | /**
65 | * Always positive modulus
66 | * @param x Operand
67 | * @param n Modulus
68 | * @returns x modulo n
69 | */
70 |
71 |
72 | exports.rightPad = rightPad;
73 |
74 | function mod(x, n) {
75 | return (x % n + n) % n;
76 | }
77 |
78 | function clamp(val) {
79 | var min = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
80 | var max = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
81 | if (val < min) return min;
82 | if (val > max) return max;
83 | return val;
84 | }
85 |
86 | function capitalize(string) {
87 | return string.charAt(0).toUpperCase() + string.substring(1);
88 | }
89 | /**
90 | * Format a string in a flexible way. Scans for %s strings and replaces them with arguments. List of patterns is modifiable via String.format.map.
91 | * @param {string} template
92 | * @param {any} [argv]
93 | */
94 |
95 |
96 | function format(template) {
97 | for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
98 | args[_key - 1] = arguments[_key];
99 | }
100 |
101 | var map = format.map;
102 |
103 | var replacer = function replacer(match, group1, group2, index) {
104 | if (template.charAt(index - 1) == "%") {
105 | return match.substring(1);
106 | }
107 |
108 | if (!args.length) {
109 | return match;
110 | }
111 |
112 | var obj = args[0];
113 | var group = group1 || group2;
114 | var parts = group.split(",");
115 | var name = parts.shift() || "";
116 | var method = map[name.toLowerCase()];
117 |
118 | if (!method) {
119 | return match;
120 | }
121 |
122 | obj = args.shift();
123 | var replaced = obj[method].apply(obj, parts);
124 | var first = name.charAt(0);
125 |
126 | if (first != first.toLowerCase()) {
127 | replaced = capitalize(replaced);
128 | }
129 |
130 | return replaced;
131 | };
132 |
133 | return template.replace(/%(?:([a-z]+)|(?:{([^}]+)}))/gi, replacer);
134 | }
--------------------------------------------------------------------------------
/lib/core/vector.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = vectorFactory;
7 |
8 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
9 |
10 | function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
11 |
12 | function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
13 |
14 | /**
15 | * A simple 2d vector object.
16 | *
17 | * ```js
18 | * import { Vector } from 'kontra';
19 | *
20 | * let vector = Vector(100, 200);
21 | * ```
22 | * @class Vector
23 | *
24 | * @param {Number} [x=0] - X coordinate of the vector.
25 | * @param {Number} [y=0] - Y coordinate of the vector.
26 | */
27 | var Vector =
28 | /*#__PURE__*/
29 | function () {
30 | function Vector() {
31 | var x = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
32 | var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
33 |
34 | _classCallCheck(this, Vector);
35 |
36 | this._x = x;
37 | this._y = y;
38 | }
39 | /**
40 | * Return a new Vector whose value is the addition of the current Vector and the passed in Vector. If `dt` is provided, the result is multiplied by the value.
41 | * @memberof Vector
42 | * @function add
43 | *
44 | * @param {kontra.Vector} vector - Vector to add to the current Vector.
45 | * @param {Number} [dt=1] - Time since last update.
46 | *
47 | * @returns {kontra.Vector} A new kontra.Vector instance.
48 | */
49 |
50 |
51 | _createClass(Vector, [{
52 | key: "add",
53 | value: function add(vec) {
54 | var dt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1;
55 | return vectorFactory(this.x + (vec.x || 0) * dt, this.y + (vec.y || 0) * dt, this);
56 | }
57 | /**
58 | * Clamp the Vector between two points, preventing `x` and `y` from going below or above the minimum and maximum values. Perfect for keeping a sprite from going outside the game boundaries.
59 | *
60 | * ```js
61 | * import { Vector } from 'kontra';
62 | *
63 | * let vector = Vector(100, 200);
64 | * vector.clamp(0, 0, 200, 300);
65 | *
66 | * vector.x += 200;
67 | * console.log(vector.x); //=> 200
68 | *
69 | * vector.y -= 300;
70 | * console.log(vector.y); //=> 0
71 | *
72 | * vector.add({x: -500, y: 500});
73 | * console.log(vector); //=> {x: 0, y: 300}
74 | * ```
75 | * @memberof Vector
76 | * @function clamp
77 | *
78 | * @param {Number} xMin - Minimum x value.
79 | * @param {Number} yMin - Minimum y value.
80 | * @param {Number} xMax - Maximum x value.
81 | * @param {Number} yMax - Maximum y value.
82 | */
83 |
84 | }, {
85 | key: "clamp",
86 | value: function clamp(xMin, yMin, xMax, yMax) {
87 | this._c = true;
88 | this._a = xMin;
89 | this._b = yMin;
90 | this._d = xMax;
91 | this._e = yMax;
92 | }
93 | /**
94 | * X coordinate of the vector.
95 | * @memberof Vector
96 | * @property {Number} x
97 | */
98 |
99 | }, {
100 | key: "x",
101 | get: function get() {
102 | return this._x;
103 | }
104 | /**
105 | * Y coordinate of the vector.
106 | * @memberof Vector
107 | * @property {Number} y
108 | */
109 | ,
110 | set: function set(value) {
111 | this._x = this._c ? Math.min(Math.max(this._a, value), this._d) : value;
112 | }
113 | }, {
114 | key: "y",
115 | get: function get() {
116 | return this._y;
117 | },
118 | set: function set(value) {
119 | this._y = this._c ? Math.min(Math.max(this._b, value), this._e) : value;
120 | }
121 | }]);
122 |
123 | return Vector;
124 | }();
125 |
126 | function vectorFactory(x, y) {
127 | var vec = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
128 | var vector = new Vector(x, y); // preserve vector clamping when creating new vectors
129 |
130 | if (vec._c) {
131 | vector.clamp(vec._a, vec._b, vec._d, vec._e); // reset x and y so clamping takes effect
132 |
133 | vector.x = x;
134 | vector.y = y;
135 | }
136 |
137 | return vector;
138 | }
139 |
140 | vectorFactory.prototype = Vector.prototype;
141 | vectorFactory["class"] = Vector;
--------------------------------------------------------------------------------
/lib/core/wall.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 |
8 | var _tile = _interopRequireDefault(require("./tile"));
9 |
10 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
11 |
12 | function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
13 |
14 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
15 |
16 | function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
17 |
18 | function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
19 |
20 | function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
21 |
22 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
23 |
24 | function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
25 |
26 | var Wall =
27 | /*#__PURE__*/
28 | function (_Tile) {
29 | _inherits(Wall, _Tile);
30 |
31 | function Wall(x, y) {
32 | _classCallCheck(this, Wall);
33 |
34 | return _possibleConstructorReturn(this, _getPrototypeOf(Wall).call(this, x, y, 3, false));
35 | }
36 |
37 | return Wall;
38 | }(_tile["default"]);
39 |
40 | exports["default"] = Wall;
--------------------------------------------------------------------------------
/lib/index.defaults.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | Object.defineProperty(exports, "__esModule", {
4 | value: true
5 | });
6 | exports["default"] = void 0;
7 |
8 | var _animation = _interopRequireDefault(require("./core/animation.js"));
9 |
10 | var _assetmanager = require("./core/assetmanager");
11 |
12 | var _canvas = require("./core/canvas");
13 |
14 | var _eventmanager = require("./core/eventmanager");
15 |
16 | var _game = _interopRequireDefault(require("./core/game"));
17 |
18 | var _keyboard = require("./core/keyboard.js");
19 |
20 | var _index = _interopRequireDefault(require("./core/map/index.js"));
21 |
22 | var _plugin = require("./core/plugin.js");
23 |
24 | var _pointer = require("./core/pointer.js");
25 |
26 | var _pool = _interopRequireDefault(require("./core/pool.js"));
27 |
28 | var _rng = _interopRequireDefault(require("./core/rng.js"));
29 |
30 | var _quadtree = _interopRequireDefault(require("./core/quadtree.js"));
31 |
32 | var _sprite = _interopRequireDefault(require("./core/sprite.js"));
33 |
34 | var _spritesheet = _interopRequireDefault(require("./core/spritesheet.js"));
35 |
36 | var _store = require("./core/store.js");
37 |
38 | var _tileengine = _interopRequireDefault(require("./core/tileengine.js"));
39 |
40 | var _vector = _interopRequireDefault(require("./core/vector.js"));
41 |
42 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
43 |
44 | var RogueIO = {
45 | Animation: _animation["default"],
46 | imageAssets: _assetmanager.imageAssets,
47 | audioAssets: _assetmanager.audioAssets,
48 | dataAssets: _assetmanager.dataAssets,
49 | setImagePath: _assetmanager.setImagePath,
50 | setAudioPath: _assetmanager.setAudioPath,
51 | setDataPath: _assetmanager.setDataPath,
52 | loadImage: _assetmanager.loadImage,
53 | loadAudio: _assetmanager.loadAudio,
54 | loadData: _assetmanager.loadData,
55 | load: _assetmanager.load,
56 | init: _canvas.init,
57 | getCanvas: _canvas.getCanvas,
58 | getContext: _canvas.getContext,
59 | on: _eventmanager.on,
60 | off: _eventmanager.off,
61 | emit: _eventmanager.emit,
62 | Game: _game["default"],
63 | keyMap: _keyboard.keyMap,
64 | initKeys: _keyboard.initKeys,
65 | bindKeys: _keyboard.bindKeys,
66 | unbindKeys: _keyboard.unbindKeys,
67 | keyPressed: _keyboard.keyPressed,
68 | Map: _index["default"],
69 | registerPlugin: _plugin.registerPlugin,
70 | unregisterPlugin: _plugin.unregisterPlugin,
71 | extendObject: _plugin.extendObject,
72 | initPointer: _pointer.initPointer,
73 | pointer: _pointer.pointer,
74 | track: _pointer.track,
75 | untrack: _pointer.untrack,
76 | pointerOver: _pointer.pointerOver,
77 | onPointerDown: _pointer.onPointerDown,
78 | onPointerUp: _pointer.onPointerUp,
79 | pointerPressed: _pointer.pointerPressed,
80 | Pool: _pool["default"],
81 | Quadtree: _quadtree["default"],
82 | RNG: _rng["default"],
83 | Sprite: _sprite["default"],
84 | SpriteSheet: _spritesheet["default"],
85 | setStoreItem: _store.setStoreItem,
86 | getStoreItem: _store.getStoreItem,
87 | TileEngine: _tileengine["default"],
88 | Vector: _vector["default"]
89 | };
90 | var _default = RogueIO;
91 | exports["default"] = _default;
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rogueio",
3 | "version": "0.0.0-b",
4 | "description": "A Light Rogue Javascript Game Engine",
5 | "main": "index.js",
6 | "scripts": {
7 | "dev": "webpack-dev-server --open --watch",
8 | "build": "babel ./src -d lib",
9 | "build:docker": "docker-compose build",
10 | "dev:docker": "docker-compose up dev",
11 | "end:docker": "docker-compose down",
12 | "clean:docker": "docker system prune -f"
13 | },
14 | "repository": "https://github.com/NodeGG/RogueIO.git",
15 | "author": "Warren Gates ",
16 | "license": "MIT",
17 | "private": false,
18 | "dependencies": {
19 | "@babel/polyfill": "^7.4.4",
20 | "core-js": "3",
21 | "dotenv": "^8.0.0",
22 | "lodash": "^4.17.13"
23 | },
24 | "devDependencies": {
25 | "@babel/cli": "^7.4.4",
26 | "@babel/core": "^7.2.2",
27 | "@babel/preset-env": "^7.4.5",
28 | "@babel/register": "^7.4.4",
29 | "babel-loader": "^8.0.6",
30 | "css-loader": "^3.0.0",
31 | "html-webpack-plugin": "^3.2.0",
32 | "prettier": "^1.19.1",
33 | "script-ext-html-webpack-plugin": "^2.1.3",
34 | "style-loader": "^0.23.1",
35 | "webpack": "^4.34.0",
36 | "webpack-cli": "^3.3.4",
37 | "webpack-dev-server": "^3.7.2",
38 | "yarn": "^1.21.1"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 |
11 |
17 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/public/moiboi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DEVMOI/RogueIO/9c388050812d24e3e77933daf1c0e9bab8670a75/public/moiboi.png
--------------------------------------------------------------------------------
/src/core/EventManager.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A Simple Event Manager to allow for user to create their own hooks into RogueIO, or create Events for Plugins
3 | * @section Events
4 | */
5 | export let callbacks = {};
6 | /**
7 | * 3 Important lifecycle Events:
8 | * - `init` Emits after Rogue.JS is called
9 | * - `tick` Emmits every frame of the RogueIO.GameLoop [Loops Update and Render]
10 | * - `assetload` Emitted after an asset has fully loaded using the asset loader. The callback function is passed the asset and the url of the asset as parameters
11 | * @section Lifecycel Events
12 | */
13 |
14 | /**
15 | * Register a callback for an event to be called whenever the event is emitted. The callback will be passed all arguments used in the `emit` call.
16 | * @function on
17 | *
18 | * @param {String} event - Name of the event.
19 | * @param {Function} callback - Function that will be called when the event is emitted.
20 | */
21 | export let on = (event, callback) => {
22 | callbacks[event] = callbacks[event] || [];
23 | callbacks[event].push(callback);
24 | };
25 | /**
26 | * Remove a callback for an event.
27 | * @function off
28 | *
29 | * @param {String} event - Name of the event.
30 | * @param {Function} callback - The function that was passed during registration.
31 | */
32 | export let off = (event, callback) => {
33 | let index;
34 |
35 | if (!callbacks[event] || (index = callbacks[event].indexOf(callback)) < 0)
36 | return;
37 | callbacks[event].splice(index, 1);
38 | };
39 | /**
40 | * Call all callback functions for the event. All arguments will be passed to the callback functions.
41 | * @function emit
42 | *
43 | * @param {String} event - Name of the event.
44 | * @param {*} [args] - Arguments passed to all callbacks.
45 | */
46 | export let emit = (event, ...args) => {
47 | if (callbacks !== undefined) {
48 | if (!callbacks[event]) return;
49 | callbacks[event].map(fn => fn(...args));
50 | }
51 | };
52 |
--------------------------------------------------------------------------------
/src/core/animation.js:
--------------------------------------------------------------------------------
1 | import { getContext } from "./canvas.js";
2 |
3 | /**
4 | * An object for drawing sprite sheet animations.
5 | *
6 | * An animation defines the sequence of frames to use from a sprite sheet. It also defines at what speed the animation should run using `frameRate`.
7 | *
8 | * Typically you don't create an kontra.Animation directly, but rather you would create them from kontra.SpriteSheet by passing the `animations` argument.
9 | *
10 | * ```js
11 | * import { SpriteSheet, Animation } from 'kontra';
12 | *
13 | * let image = new Image();
14 | * image.src = 'assets/imgs/character_walk_sheet.png';
15 | * image.onload = function() {
16 | * let spriteSheet = SpriteSheet({
17 | * image: image,
18 | * frameWidth: 72,
19 | * frameHeight: 97
20 | * });
21 | *
22 | * // you typically wouldn't create an Animation this way
23 | * let animation = Animation({
24 | * spriteSheet: spriteSheet,
25 | * frames: [1,2,3,6],
26 | * frameRate: 30
27 | * });
28 | * };
29 | * ```
30 | * @class Animation
31 | *
32 | * @param {Object} properties - Properties of the animation.
33 | * @param {kontra.SpriteSheet} properties.spriteSheet - Sprite sheet for the animation.
34 | * @param {Number[]} properties.frames - List of frames of the animation.
35 | * @param {Number} properties.frameRate - Number of frames to display in one second.
36 | * @param {Boolean} [properties.loop=true] - If the animation should loop.
37 | */
38 | class Animation {
39 | constructor({ spriteSheet, frames, frameRate, loop = true } = {}) {
40 | /**
41 | * The sprite sheet to use for the animation.
42 | * @memberof Animation
43 | * @property {kontra.SpriteSheet} spriteSheet
44 | */
45 | this.spriteSheet = spriteSheet;
46 |
47 | /**
48 | * Sequence of frames to use from the sprite sheet.
49 | * @memberof Animation
50 | * @property {Number[]} frames
51 | */
52 | this.frames = frames;
53 |
54 | /**
55 | * Number of frames to display per second. Adjusting this value will change the speed of the animation.
56 | * @memberof Animation
57 | * @property {Number} frameRate
58 | */
59 | this.frameRate = frameRate;
60 |
61 | /**
62 | * If the animation should loop back to the beginning once completed.
63 | * @memberof Animation
64 | * @property {Boolean} loop
65 | */
66 | this.loop = loop;
67 |
68 | let { width, height, margin = 0 } = spriteSheet.frame;
69 |
70 | /**
71 | * The width of an individual frame. Taken from the property of the same name in the [spriteSheet](api/animation#spriteSheet).
72 | * @memberof Animation
73 | * @property {Number} width
74 | */
75 | this.width = width;
76 |
77 | /**
78 | * The height of an individual frame. Taken from the property of the same name in the [spriteSheet](api/animation#spriteSheet).
79 | * @memberof Animation
80 | * @property {Number} height
81 | */
82 | this.height = height;
83 |
84 | /**
85 | * The space between each frame. Taken from the property of the same name in the [spriteSheet](api/animation#spriteSheet).
86 | * @memberof Animation
87 | * @property {Number} margin
88 | */
89 | this.margin = margin;
90 |
91 | // f = frame, a = accumulator
92 | this._f = 0;
93 | this._a = 0;
94 | }
95 |
96 | /**
97 | * Clone an animation so it can be used more than once. By default animations passed to kontra.Sprite will be cloned so no two sprites update the same animation. Otherwise two sprites who shared the same animation would make it update twice as fast.
98 | * @memberof Animation
99 | * @function clone
100 | *
101 | * @returns {kontra.Animation} A new kontra.Animation instance.
102 | */
103 | clone() {
104 | return animationFactory(this);
105 | }
106 |
107 | /**
108 | * Reset an animation to the first frame.
109 | * @memberof Animation
110 | * @function reset
111 | */
112 | reset() {
113 | this._f = 0;
114 | this._a = 0;
115 | }
116 |
117 | /**
118 | * Update the animation.
119 | * @memberof Animation
120 | * @function update
121 | *
122 | * @param {Number} [dt=1/60] - Time since last update.
123 | */
124 | update(dt = 1 / 60) {
125 | // if the animation doesn't loop we stop at the last frame
126 | if (!this.loop && this._f == this.frames.length - 1) return;
127 |
128 | this._a += dt;
129 |
130 | // update to the next frame if it's time
131 | while (this._a * this.frameRate >= 1) {
132 | this._f = ++this._f % this.frames.length;
133 | this._a -= 1 / this.frameRate;
134 | }
135 | }
136 |
137 | /**
138 | * Draw the current frame of the animation.
139 | * @memberof Animation
140 | * @function render
141 | *
142 | * @param {Object} properties - Properties to draw the animation.
143 | * @param {Number} properties.x - X position to draw the animation.
144 | * @param {Number} properties.y - Y position to draw the animation.
145 | * @param {Number} [properties.width] - width of the sprite. Defaults to [Animation.width](api/animation#width).
146 | * @param {Number} [properties.height] - height of the sprite. Defaults to [Animation.height](api/animation#height).
147 | * @param {CanvasRenderingContext2D} [properties.context] - The context the animation should draw to. Defaults to [core.getContext()](api/core#getContext).
148 | */
149 | render({
150 | x,
151 | y,
152 | width = this.width,
153 | height = this.height,
154 | context = getContext()
155 | } = {}) {
156 | // get the row and col of the frame
157 | let row = (this.frames[this._f] / this.spriteSheet._f) | 0;
158 | let col = this.frames[this._f] % this.spriteSheet._f | 0;
159 |
160 | context.drawImage(
161 | this.spriteSheet.image,
162 | col * this.width + (col * 2 + 1) * this.margin,
163 | row * this.height + (row * 2 + 1) * this.margin,
164 | this.width,
165 | this.height,
166 | x,
167 | y,
168 | width,
169 | height
170 | );
171 | }
172 | }
173 |
174 | export default function animationFactory(properties) {
175 | return new Animation(properties);
176 | }
177 | animationFactory.prototype = Animation.prototype;
178 | animationFactory.class = Animation;
179 |
--------------------------------------------------------------------------------
/src/core/canvas.js:
--------------------------------------------------------------------------------
1 | import Options from "./options";
2 | import { emit } from "./eventmanager";
3 |
4 | /**
5 | * Functions for initializing the RogueIO library and getting the canvas and context
6 | * objects.
7 | *
8 | * ```js
9 | * import { getCanvas, getContext, init } from 'RogueIO';
10 | *
11 | * let { canvas, context } = init();
12 | *
13 | * // or can get canvas and context through functions
14 | * canvas = getCanvas();
15 | * context = getContext();
16 | * ```
17 | * @sectionName Core
18 | */
19 |
20 | let canvasEl, context;
21 |
22 | /**
23 | * Return the canvas element.
24 | * @function getCanvas
25 | *
26 | * @returns {HTMLCanvasElement} The canvas element for the game.
27 | */
28 | export function getCanvas() {
29 | return canvasEl;
30 | }
31 |
32 | /**
33 | * Return the context object.
34 | * @function getContext
35 | *
36 | * @returns {CanvasRenderingContext2D} The context object the game draws to.
37 | */
38 | export function getContext() {
39 | return context;
40 | }
41 |
42 | /**
43 | * Initialize the library and set up the canvas. Typically you will call `init()` as the first thing and give it the canvas to use. This will allow all RogueIO objects to reference the canvas when created.
44 | *
45 | * ```js
46 | * import { init } from 'RogueIO';
47 | *
48 | * let { canvas, context } = init('game');
49 | * ```
50 | * @function init
51 | *
52 | * @param {String|HTMLCanvasElement} [canvas] - The canvas for RogueIO to use. Can either be the ID of the canvas element or the canvas element itself. Defaults to using the first canvas element on the page.
53 | *
54 | * @returns {Object} An object with properties `canvas` and `context`. `canvas` it the canvas element for the game and `context` is the context object the game draws to.
55 | */
56 | export function init(canvas) {
57 | // check if canvas is a string first, an element next, or default to getting
58 | // first canvas on page
59 | canvasEl =
60 | document.getElementById(canvas) ||
61 | canvas ||
62 | document.querySelector("canvas");
63 | // @if DEBUG
64 | if (!canvasEl) {
65 | throw Error("You must provide a canvas element for the game");
66 | }
67 | // @endif
68 |
69 | context = canvasEl.getContext("2d");
70 | context.font='15px sans-serif';
71 | console.log(context.font)
72 | context.imageSmoothingEnabled = false;
73 |
74 | emit("init");
75 |
76 | return { canvas: canvasEl, context };
77 | }
78 |
--------------------------------------------------------------------------------
/src/core/entity.js:
--------------------------------------------------------------------------------
1 | import { initSounds, playSound } from "./assetmanager";
2 | import Game from "./game";
3 | import SpriteSheet from "./spritesheet";
4 | export default class Entity {
5 | constructor(tile, sprite, hp) {
6 | this.spritesheet = null;
7 | this.ctx = null;
8 | this.move(tile);
9 | this.sprite = sprite;
10 | this.hp = hp;
11 | this.teleportCounter = 2;
12 | this.offsetX = 0;
13 | this.offsetY = 0;
14 | this.lastMove = [-1, 0];
15 | this.bonusAttack = 0;
16 | }
17 | heal(damage) {
18 | this.hp = Math.min(Game.maxHp, this.hp + damage);
19 | }
20 |
21 | getDisplayX() {
22 | return this.tile.x + this.offsetX;
23 | }
24 |
25 | getDisplayY() {
26 | return this.tile.y + this.offsetY;
27 | }
28 | draw() {
29 | this.ctx = Game.canvas.getCtx();
30 | this.spritesheet = new SpriteSheet({
31 | ctx: this.ctx,
32 | tilesize: Game.tilesize
33 | });
34 | if (this.teleportCounter > 0) {
35 | this.spritesheet.drawSprite(10, this.getDisplayX(), this.getDisplayY());
36 | } else {
37 | this.spritesheet.drawSprite(
38 | this.sprite,
39 | this.getDisplayX(),
40 | this.getDisplayY()
41 | );
42 | this.drawHp();
43 | }
44 | this.offsetX -= Math.sign(this.offsetX) * (1 / 8);
45 | this.offsetY -= Math.sign(this.offsetY) * (1 / 8);
46 | }
47 | drawHp() {
48 | for (let i = 0; i < this.hp; i++) {
49 | this.spritesheet.drawSprite(
50 | 9,
51 | this.getDisplayX() + (i % 3) * (5 / 16),
52 | this.getDisplayY() - Math.floor(i / 3) * (5 / 16)
53 | );
54 | }
55 | }
56 | tryMove(dx, dy) {
57 | let newTile = this.tile.getNeighbor(dx, dy);
58 | if (newTile.passable) {
59 | this.lastMove = [dx, dy];
60 | if (!newTile.monster) {
61 | this.move(newTile);
62 | } else {
63 | if (this.isPlayer != newTile.monster.isPlayer) {
64 | this.attackedThisTurn = true;
65 | newTile.monster.stunned = true;
66 | newTile.monster.hit(1 + this.bonusAttack);
67 | this.bonusAttack = 0;
68 |
69 | Game.shakeAmount = 5;
70 |
71 | this.offsetX = (newTile.x - this.tile.x) / 2;
72 | this.offsetY = (newTile.y - this.tile.y) / 2;
73 | }
74 | }
75 | return true;
76 | }
77 | }
78 | update() {
79 | this.teleportCounter--;
80 | if (this.stunned || this.teleportCounter > 0) {
81 | this.stunned = false;
82 | return;
83 | }
84 | this.doStuff();
85 | }
86 |
87 | doStuff() {
88 | let neighbors = this.tile.getAdjacentPassableNeighbors();
89 |
90 | neighbors = neighbors.filter(t => !t.monster || t.monster.isPlayer);
91 |
92 | if (neighbors.length) {
93 | neighbors.sort(
94 | (a, b) => a.dist(Game.player.tile) - b.dist(Game.player.tile)
95 | );
96 | let newTile = neighbors[0];
97 | this.tryMove(newTile.x - this.tile.x, newTile.y - this.tile.y);
98 | }
99 | }
100 | hit(damage) {
101 | if (this.sheild > 0) {
102 | }
103 | this.hp -= damage;
104 | if (this.hp <= 0) {
105 | this.die();
106 | }
107 |
108 | if (this.isPlayer) {
109 | playSound("hit1");
110 | } else {
111 | playSound("hit2");
112 | }
113 | }
114 |
115 | die() {
116 | this.dead = true;
117 | this.tile.monster = null;
118 | this.sprite = 1;
119 | }
120 |
121 | move(tile) {
122 | if (this.tile) {
123 | this.tile.monster = null;
124 | this.offsetX = this.tile.x - tile.x;
125 | this.offsetY = this.tile.y - tile.y;
126 | }
127 | this.tile = tile;
128 | tile.monster = this;
129 | tile.stepOn(this);
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/src/core/exit.js:
--------------------------------------------------------------------------------
1 | import AssetManager from "./assetmanager";
2 | import Tile from "./tile";
3 | import Game from "./game";
4 | export default class Exit extends Tile {
5 | constructor(x, y) {
6 | super(x, y, 11, true);
7 | }
8 |
9 | stepOn(monster) {
10 | if (monster.isPlayer) {
11 | AssetManager.playSound("newLevel");
12 | if (Game.level == Game.numLevels) {
13 | Game.addScore(Game.score, true);
14 | Game.showTitle();
15 | } else {
16 | Game.level++;
17 | Game.startLevel(Math.min(Game.maxHp, Game.player.hp + 1));
18 | }
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/core/floor.js:
--------------------------------------------------------------------------------
1 | import { playSound } from "./assetmanager";
2 | import Game from "./game";
3 | import Tile from "./tile";
4 | export default class Floor extends Tile {
5 | constructor(x, y) {
6 | super(x, y, 2, true);
7 | }
8 | stepOn(monster) {
9 | //TODO: complete
10 | if (monster.isPlayer && this.treasure) {
11 | Game.score++;
12 | if (Game.score % 3 == 0 && Game.numActions < 9) {
13 | Game.numActions++;
14 | Game.player.addSpell();
15 | }
16 | playSound("treasure");
17 | this.treasure = false;
18 | Game.map.spawnMonster();
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/core/game.js:
--------------------------------------------------------------------------------
1 | import { noop } from "./util.js";
2 | import { emit } from "./eventmanager.js";
3 | import { getContext, getCanvas } from "./canvas.js";
4 |
5 | /**
6 | * Clear the canvas.
7 | */
8 | function clear() {
9 | let canvas = getCanvas();
10 | getContext().clearRect(0, 0, canvas.width, canvas.height);
11 | }
12 |
13 | /**
14 | * The game loop updates and renders the game every frame. The game loop is stopped by default and will not start until the loops `start()` function is called.
15 | *
16 | * The game loop uses a time-based animation with a fixed `dt` to [avoid frame rate issues](http://blog.sklambert.com/using-time-based-animation-implement/). Each update call is guaranteed to equal 1/60 of a second.
17 | *
18 | * This means that you can avoid having to do time based calculations in your update functions and instead do fixed updates.
19 | *
20 | * ```js
21 | * import { Sprite, GameLoop } from 'kontra';
22 | *
23 | * let sprite = Sprite({
24 | * x: 100,
25 | * y: 200,
26 | * width: 20,
27 | * height: 40,
28 | * color: 'red'
29 | * });
30 | *
31 | * let loop = GameLoop({
32 | * update: function(dt) {
33 | * // no need to determine how many pixels you want to
34 | * // move every second and multiple by dt
35 | * // sprite.x += 180 * dt;
36 | *
37 | * // instead just update by how many pixels you want
38 | * // to move every frame and the loop will ensure 60FPS
39 | * sprite.x += 3;
40 | * },
41 | * render: function() {
42 | * sprite.render();
43 | * }
44 | * });
45 | *
46 | * loop.start();
47 | * ```
48 | * @sectionName GameLoop
49 | *
50 | * @param {Object} properties - Properties of the game loop.
51 | * @param {Function} properties.update - Function called every frame to update the game. Is passed the fixed `dt` as a parameter.
52 | * @param {Function} properties.render - Function called every frame to render the game.
53 | * @param {Number} [properties.fps=60] - Desired frame rate.
54 | * @param {Boolean} [properties.clearCanvas=true] - Clear the canvas every frame before the `render()` function is called.
55 | */
56 | export default function GameLoop({
57 | fps = 60,
58 | clearCanvas = true,
59 | update,
60 | render
61 | } = {}) {
62 | // check for required functions
63 | // @if DEBUG
64 | if (!(update && render)) {
65 | throw Error("You must provide update() and render() functions");
66 | }
67 | // @endif
68 |
69 | // animation variables
70 | let accumulator = 0;
71 | let delta = 1e3 / fps; // delta between performance.now timings (in ms)
72 | let step = 1 / fps;
73 | let clearFn = clearCanvas ? clear : noop;
74 | let last, rAF, now, dt, loop;
75 |
76 | /**
77 | * Called every frame of the game loop.
78 | */
79 | function frame() {
80 | rAF = requestAnimationFrame(frame);
81 |
82 | now = performance.now();
83 | dt = now - last;
84 | last = now;
85 |
86 | // prevent updating the game with a very large dt if the game were to lose focus
87 | // and then regain focus later
88 | if (dt > 1e3) {
89 | return;
90 | }
91 |
92 | emit("tick");
93 | accumulator += dt;
94 |
95 | while (accumulator >= delta) {
96 | loop.update(step);
97 |
98 | accumulator -= delta;
99 | }
100 |
101 | clearFn();
102 | loop.render();
103 | }
104 |
105 | // game loop object
106 | loop = {
107 | /**
108 | * Called every frame to update the game. Put all of your games update logic here.
109 | * @memberof GameLoop
110 | * @function update
111 | *
112 | * @param {Number} dt - The fixed dt time of 1/60 of a frame.
113 | */
114 | update,
115 |
116 | /**
117 | * Called every frame to render the game. Put all of your games render logic here.
118 | * @memberof GameLoop
119 | * @function render
120 | */
121 | render,
122 |
123 | /**
124 | * If the game loop is currently stopped.
125 | *
126 | * ```js
127 | * import { GameLoop } from 'kontra';
128 | *
129 | * let loop = GameLoop({
130 | * // ...
131 | * });
132 | * console.log(loop.isStopped); //=> true
133 | *
134 | * loop.start();
135 | * console.log(loop.isStopped); //=> false
136 | *
137 | * loop.stop();
138 | * console.log(loop.isStopped); //=> true
139 | * ```
140 | * @memberof GameLoop
141 | * @property {Boolean} isStopped
142 | */
143 | isStopped: true,
144 |
145 | /**
146 | * Start the game loop.
147 | * @memberof GameLoop
148 | * @function start
149 | */
150 | start() {
151 | last = performance.now();
152 | this.isStopped = false;
153 | requestAnimationFrame(frame);
154 | },
155 |
156 | /**
157 | * Stop the game loop.
158 | * @memberof GameLoop
159 | * @function stop
160 | */
161 | stop() {
162 | this.isStopped = true;
163 | cancelAnimationFrame(rAF);
164 | },
165 |
166 | // expose properties for testing
167 | // @if DEBUG
168 | _frame: frame,
169 | set _last(value) {
170 | last = value;
171 | }
172 | // @endif
173 | };
174 |
175 | return loop;
176 | }
177 |
--------------------------------------------------------------------------------
/src/core/keyboard.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A minimalistic keyboard API. You can use it move the main sprite or respond to a key press.
3 | *
4 | * ```js
5 | * import { initKeys, keyPressed } from 'kontra';
6 | *
7 | * // this function must be called first before keyboard
8 | * // functions will work
9 | * initKeys();
10 | *
11 | * function update() {
12 | * if (keyPressed('left')) {
13 | * // move left
14 | * }
15 | * }
16 | * ```
17 | * @sectionName Keyboard
18 | */
19 |
20 | /**
21 | * Below is a list of keys that are provided by default. If you need to extend this list, you can use the [keyMap](api/keyboard#keyMap) property.
22 | *
23 | * - a-z
24 | * - 0-9
25 | * - enter, esc, space, left, up, right, down
26 | * @sectionName Available Keys
27 | */
28 |
29 | let callbacks = {};
30 | let pressedKeys = {};
31 |
32 | /**
33 | * A map of keycodes to key names. Add to this object to expand the list of [available keys](api/keyboard#available-keys).
34 | *
35 | * ```js
36 | * import { keyMap, bindKeys } from 'kontra';
37 | *
38 | * keyMap[34] = 'pageDown';
39 | *
40 | * bindKeys('pageDown', function(e) {
41 | * // handle pageDown key
42 | * });
43 | * ```
44 | * @property {Object} keyMap
45 | */
46 | export let keyMap = {
47 | // named keys
48 | Enter: "enter",
49 | Escape: "esc",
50 | Space: "space",
51 | ArrowLeft: "left",
52 | ArrowUp: "up",
53 | ArrowRight: "right",
54 | ArrowDown: "down",
55 | // for Edge compatibility
56 | 13: "enter",
57 | 27: "esc",
58 | 32: "space",
59 | 37: "left",
60 | 38: "up",
61 | 39: "right",
62 | 40: "down"
63 | };
64 |
65 | /**
66 | * Execute a function that corresponds to a keyboard key.
67 | *
68 | * @param {KeyboardEvent} evt
69 | */
70 | function keydownEventHandler(evt) {
71 | let key = keyMap[evt.code || evt.which];
72 | pressedKeys[key] = true;
73 |
74 | if (callbacks[key]) {
75 | callbacks[key](evt);
76 | }
77 | }
78 |
79 | /**
80 | * Set the released key to not being pressed.
81 | *
82 | * @param {KeyboardEvent} evt
83 | */
84 | function keyupEventHandler(evt) {
85 | pressedKeys[keyMap[evt.code || evt.which]] = false;
86 | }
87 |
88 | /**
89 | * Reset pressed keys.
90 | */
91 | function blurEventHandler() {
92 | pressedKeys = {};
93 | }
94 |
95 | /**
96 | * Initialize keyboard event listeners. This function must be called before using other keyboard functions.
97 | * @function initKeys
98 | */
99 | export function initKeys() {
100 | let i;
101 |
102 | // alpha keys
103 | // @see https://stackoverflow.com/a/43095772/2124254
104 | for (i = 0; i < 26; i++) {
105 | // rollupjs considers this a side-effect (for now), so we'll do it in the
106 | // initKeys function
107 | keyMap[i + 65] = keyMap[
108 | "Key" + String.fromCharCode(i + 65)
109 | ] = String.fromCharCode(i + 97);
110 | }
111 |
112 | // numeric keys
113 | for (i = 0; i < 10; i++) {
114 | keyMap[48 + i] = keyMap["Digit" + i] = "" + i;
115 | }
116 |
117 | window.addEventListener("keydown", keydownEventHandler);
118 | window.addEventListener("keyup", keyupEventHandler);
119 | window.addEventListener("blur", blurEventHandler);
120 | }
121 |
122 | /**
123 | * Bind a set of keys that will call the callback function when they are pressed. Takes a single key or an array of keys. Is passed the original KeyboardEvent as a parameter.
124 | *
125 | * ```js
126 | * import { initKeys, bindKeys } from 'kontra';
127 | *
128 | * initKeys();
129 | *
130 | * bindKeys('p', function(e) {
131 | * // pause the game
132 | * });
133 | * bindKeys(['enter', 'space'], function(e) {
134 | * e.preventDefault();
135 | * // fire gun
136 | * });
137 | * ```
138 | * @function bindKeys
139 | *
140 | * @param {String|String[]} keys - Key or keys to bind.
141 | */
142 | export function bindKeys(keys, callback) {
143 | // smaller than doing `Array.isArray(keys) ? keys : [keys]`
144 | [].concat(keys).map(key => (callbacks[key] = callback));
145 | }
146 |
147 | /**
148 | * Remove the callback function for a bound set of keys. Takes a single key or an array of keys.
149 | *
150 | * ```js
151 | * import { unbindKeys } from 'kontra';
152 | *
153 | * unbindKeys('left');
154 | * unbindKeys(['enter', 'space']);
155 | * ```
156 | * @function unbindKeys
157 | *
158 | * @param {String|String[]} keys - Key or keys to unbind.
159 | */
160 | export function unbindKeys(keys) {
161 | // 0 is the smallest falsy value
162 | [].concat(keys).map(key => (callbacks[key] = 0));
163 | }
164 |
165 | /**
166 | * Check if a key is currently pressed. Use during an `update()` function to perform actions each frame.
167 | *
168 | * ```js
169 | * import { Sprite, initKeys, keyPressed } from 'kontra';
170 | *
171 | * initKeys();
172 | *
173 | * let sprite = Sprite({
174 | * update: function() {
175 | * if (keyPressed('left')){
176 | * // left arrow pressed
177 | * }
178 | * else if (keyPressed('right')) {
179 | * // right arrow pressed
180 | * }
181 | *
182 | * if (keyPressed('up')) {
183 | * // up arrow pressed
184 | * }
185 | * else if (keyPressed('down')) {
186 | * // down arrow pressed
187 | * }
188 | * }
189 | * });
190 | * ```
191 | * @function keyPressed
192 | *
193 | * @param {String} key - Key to check for pressed state.
194 | *
195 | * @returns {Boolean} `true` if the key is pressed, `false` otherwise.
196 | */
197 | export function keyPressed(key) {
198 | return !!pressedKeys[key];
199 | }
200 |
--------------------------------------------------------------------------------
/src/core/map/arena.js:
--------------------------------------------------------------------------------
1 | import Map from "./map.js";
2 | /**
3 | * @class Simple empty rectangular room
4 | * @augments ROT.Map
5 | */
6 | export default class Arena extends Map {
7 | create(callback) {
8 | let w = this._width - 1;
9 | let h = this._height - 1;
10 | for (let i = 0; i <= w; i++) {
11 | for (let j = 0; j <= h; j++) {
12 | let empty = i && j && i < w && j < h;
13 | callback(i, j, empty ? 0 : 1);
14 | }
15 | }
16 | return this;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/core/map/digger.js:
--------------------------------------------------------------------------------
1 | import Dungeon from "./dungeon.js";
2 | import { Room, Corridor } from "./features.js";
3 | import RNG from "../rng.js";
4 | import { DIRS } from "../../constants.js";
5 | const FEATURES = {
6 | room: Room,
7 | corridor: Corridor
8 | };
9 | /**
10 | * Random dungeon generator using human-like digging patterns.
11 | * Heavily based on Mike Anderson's ideas from the "Tyrant" algo, mentioned at
12 | * http://www.roguebasin.roguelikedevelopment.org/index.php?title=Dungeon-Building_Algorithm.
13 | */
14 | export default class Digger extends Dungeon {
15 | constructor(width, height, options = {}) {
16 | super(width, height);
17 | this._options = Object.assign(
18 | {
19 | roomWidth: [3, 9],
20 | roomHeight: [3, 5],
21 | corridorLength: [3, 10],
22 | dugPercentage: 0.2,
23 | timeLimit: 1000 /* we stop after this much time has passed (msec) */
24 | },
25 | options
26 | );
27 | this._features = {
28 | room: 4,
29 | corridor: 4
30 | };
31 | this._map = [];
32 | this._featureAttempts = 20; /* how many times do we try to create a feature on a suitable wall */
33 | this._walls = {}; /* these are available for digging */
34 | this._dug = 0;
35 | this._digCallback = this._digCallback.bind(this);
36 | this._canBeDugCallback = this._canBeDugCallback.bind(this);
37 | this._isWallCallback = this._isWallCallback.bind(this);
38 | this._priorityWallCallback = this._priorityWallCallback.bind(this);
39 | }
40 | create(callback) {
41 | this._rooms = [];
42 | this._corridors = [];
43 | this._map = this._fillMap(1);
44 | this._walls = {};
45 | this._dug = 0;
46 | let area = (this._width - 2) * (this._height - 2);
47 | this._firstRoom();
48 | let t1 = Date.now();
49 | let priorityWalls;
50 | do {
51 | priorityWalls = 0;
52 | let t2 = Date.now();
53 | if (t2 - t1 > this._options.timeLimit) {
54 | break;
55 | }
56 | /* find a good wall */
57 | let wall = this._findWall();
58 | if (!wall) {
59 | break;
60 | } /* no more walls */
61 | let parts = wall.split(",");
62 | let x = parseInt(parts[0]);
63 | let y = parseInt(parts[1]);
64 | let dir = this._getDiggingDirection(x, y);
65 | if (!dir) {
66 | continue;
67 | } /* this wall is not suitable */
68 | // console.log("wall", x, y);
69 | /* try adding a feature */
70 | let featureAttempts = 0;
71 | do {
72 | featureAttempts++;
73 | if (this._tryFeature(x, y, dir[0], dir[1])) {
74 | /* feature added */
75 | //if (this._rooms.length + this._corridors.length == 2) { this._rooms[0].addDoor(x, y); } /* first room oficially has doors */
76 | this._removeSurroundingWalls(x, y);
77 | this._removeSurroundingWalls(x - dir[0], y - dir[1]);
78 | break;
79 | }
80 | } while (featureAttempts < this._featureAttempts);
81 | for (let id in this._walls) {
82 | if (this._walls[id] > 1) {
83 | priorityWalls++;
84 | }
85 | }
86 | } while (
87 | this._dug / area < this._options.dugPercentage ||
88 | priorityWalls
89 | ); /* fixme number of priority walls */
90 | this._addDoors();
91 | if (callback) {
92 | for (let i = 0; i < this._width; i++) {
93 | for (let j = 0; j < this._height; j++) {
94 | callback(i, j, this._map[i][j]);
95 | }
96 | }
97 | }
98 | this._walls = {};
99 | this._map = [];
100 | return this;
101 | }
102 | _digCallback(x, y, value) {
103 | if (value == 0 || value == 2) {
104 | /* empty */
105 | this._map[x][y] = 0;
106 | this._dug++;
107 | } else {
108 | /* wall */
109 | this._walls[x + "," + y] = 1;
110 | }
111 | }
112 | _isWallCallback(x, y) {
113 | if (x < 0 || y < 0 || x >= this._width || y >= this._height) {
114 | return false;
115 | }
116 | return this._map[x][y] == 1;
117 | }
118 | _canBeDugCallback(x, y) {
119 | if (x < 1 || y < 1 || x + 1 >= this._width || y + 1 >= this._height) {
120 | return false;
121 | }
122 | return this._map[x][y] == 1;
123 | }
124 | _priorityWallCallback(x, y) {
125 | this._walls[x + "," + y] = 2;
126 | }
127 | _firstRoom() {
128 | let cx = Math.floor(this._width / 2);
129 | let cy = Math.floor(this._height / 2);
130 | let room = Room.createRandomCenter(cx, cy, this._options);
131 | this._rooms.push(room);
132 | room.create(this._digCallback);
133 | }
134 | /**
135 | * Get a suitable wall
136 | */
137 | _findWall() {
138 | let prio1 = [];
139 | let prio2 = [];
140 | for (let id in this._walls) {
141 | let prio = this._walls[id];
142 | if (prio == 2) {
143 | prio2.push(id);
144 | } else {
145 | prio1.push(id);
146 | }
147 | }
148 | let arr = prio2.length ? prio2 : prio1;
149 | if (!arr.length) {
150 | return null;
151 | } /* no walls :/ */
152 | let id = RNG.getItem(arr.sort()); // sort to make the order deterministic
153 | delete this._walls[id];
154 | return id;
155 | }
156 | /**
157 | * Tries adding a feature
158 | * @returns {bool} was this a successful try?
159 | */
160 | _tryFeature(x, y, dx, dy) {
161 | let featureName = RNG.getWeightedValue(this._features);
162 | let ctor = FEATURES[featureName];
163 | let feature = ctor.createRandomAt(x, y, dx, dy, this._options);
164 | if (!feature.isValid(this._isWallCallback, this._canBeDugCallback)) {
165 | // console.log("not valid");
166 | // feature.debug();
167 | return false;
168 | }
169 | feature.create(this._digCallback);
170 | // feature.debug();
171 | if (feature instanceof Room) {
172 | this._rooms.push(feature);
173 | }
174 | if (feature instanceof Corridor) {
175 | feature.createPriorityWalls(this._priorityWallCallback);
176 | this._corridors.push(feature);
177 | }
178 | return true;
179 | }
180 | _removeSurroundingWalls(cx, cy) {
181 | let deltas = DIRS[4];
182 | for (let i = 0; i < deltas.length; i++) {
183 | let delta = deltas[i];
184 | let x = cx + delta[0];
185 | let y = cy + delta[1];
186 | delete this._walls[x + "," + y];
187 | x = cx + 2 * delta[0];
188 | y = cy + 2 * delta[1];
189 | delete this._walls[x + "," + y];
190 | }
191 | }
192 | /**
193 | * Returns vector in "digging" direction, or false, if this does not exist (or is not unique)
194 | */
195 | _getDiggingDirection(cx, cy) {
196 | if (cx <= 0 || cy <= 0 || cx >= this._width - 1 || cy >= this._height - 1) {
197 | return null;
198 | }
199 | let result = null;
200 | let deltas = DIRS[4];
201 | for (let i = 0; i < deltas.length; i++) {
202 | let delta = deltas[i];
203 | let x = cx + delta[0];
204 | let y = cy + delta[1];
205 | if (!this._map[x][y]) {
206 | /* there already is another empty neighbor! */
207 | if (result) {
208 | return null;
209 | }
210 | result = delta;
211 | }
212 | }
213 | /* no empty neighbor */
214 | if (!result) {
215 | return null;
216 | }
217 | return [-result[0], -result[1]];
218 | }
219 | /**
220 | * Find empty spaces surrounding rooms, and apply doors.
221 | */
222 | _addDoors() {
223 | let data = this._map;
224 | function isWallCallback(x, y) {
225 | return data[x][y] == 1;
226 | }
227 | for (let i = 0; i < this._rooms.length; i++) {
228 | let room = this._rooms[i];
229 | room.clearDoors();
230 | room.addDoors(isWallCallback);
231 | }
232 | }
233 | }
234 |
--------------------------------------------------------------------------------
/src/core/map/dividedmaze.js:
--------------------------------------------------------------------------------
1 | import Map from "./map.js";
2 | import RNG from "../rng.js";
3 | /**
4 | * @class Recursively divided maze, http://en.wikipedia.org/wiki/Maze_generation_algorithm#Recursive_division_method
5 | * @augments ROT.Map
6 | */
7 | export default class DividedMaze extends Map {
8 | constructor() {
9 | super(...arguments);
10 | this._stack = [];
11 | this._map = [];
12 | }
13 | create(callback) {
14 | let w = this._width;
15 | let h = this._height;
16 | this._map = [];
17 | for (let i = 0; i < w; i++) {
18 | this._map.push([]);
19 | for (let j = 0; j < h; j++) {
20 | let border = i == 0 || j == 0 || i + 1 == w || j + 1 == h;
21 | this._map[i].push(border ? 1 : 0);
22 | }
23 | }
24 | this._stack = [[1, 1, w - 2, h - 2]];
25 | this._process();
26 | for (let i = 0; i < w; i++) {
27 | for (let j = 0; j < h; j++) {
28 | callback(i, j, this._map[i][j]);
29 | }
30 | }
31 | this._map = [];
32 | return this;
33 | }
34 | _process() {
35 | while (this._stack.length) {
36 | let room = this._stack.shift(); /* [left, top, right, bottom] */
37 | this._partitionRoom(room);
38 | }
39 | }
40 | _partitionRoom(room) {
41 | let availX = [];
42 | let availY = [];
43 | for (let i = room[0] + 1; i < room[2]; i++) {
44 | let top = this._map[i][room[1] - 1];
45 | let bottom = this._map[i][room[3] + 1];
46 | if (top && bottom && !(i % 2)) {
47 | availX.push(i);
48 | }
49 | }
50 | for (let j = room[1] + 1; j < room[3]; j++) {
51 | let left = this._map[room[0] - 1][j];
52 | let right = this._map[room[2] + 1][j];
53 | if (left && right && !(j % 2)) {
54 | availY.push(j);
55 | }
56 | }
57 | if (!availX.length || !availY.length) {
58 | return;
59 | }
60 | let x = RNG.getItem(availX);
61 | let y = RNG.getItem(availY);
62 | this._map[x][y] = 1;
63 | let walls = [];
64 | let w = [];
65 | walls.push(w); /* left part */
66 | for (let i = room[0]; i < x; i++) {
67 | this._map[i][y] = 1;
68 | if (i % 2) w.push([i, y]);
69 | }
70 | w = [];
71 | walls.push(w); /* right part */
72 | for (let i = x + 1; i <= room[2]; i++) {
73 | this._map[i][y] = 1;
74 | if (i % 2) w.push([i, y]);
75 | }
76 | w = [];
77 | walls.push(w); /* top part */
78 | for (let j = room[1]; j < y; j++) {
79 | this._map[x][j] = 1;
80 | if (j % 2) w.push([x, j]);
81 | }
82 | w = [];
83 | walls.push(w); /* bottom part */
84 | for (let j = y + 1; j <= room[3]; j++) {
85 | this._map[x][j] = 1;
86 | if (j % 2) w.push([x, j]);
87 | }
88 | let solid = RNG.getItem(walls);
89 | for (let i = 0; i < walls.length; i++) {
90 | let w = walls[i];
91 | if (w == solid) {
92 | continue;
93 | }
94 | let hole = RNG.getItem(w);
95 | this._map[hole[0]][hole[1]] = 0;
96 | }
97 | this._stack.push([room[0], room[1], x - 1, y - 1]); /* left top */
98 | this._stack.push([x + 1, room[1], room[2], y - 1]); /* right top */
99 | this._stack.push([room[0], y + 1, x - 1, room[3]]); /* left bottom */
100 | this._stack.push([x + 1, y + 1, room[2], room[3]]); /* right bottom */
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/src/core/map/dungeon.js:
--------------------------------------------------------------------------------
1 | import Map from "./map.js";
2 | /**
3 | * @class Dungeon map: has rooms and corridors
4 | * @augments ROT.Map
5 | */
6 | export default class Dungeon extends Map {
7 | constructor(width, height) {
8 | super(width, height);
9 | this._rooms = [];
10 | this._corridors = [];
11 | }
12 | /**
13 | * Get all generated rooms
14 | * @returns {ROT.Map.Feature.Room[]}
15 | */
16 | getRooms() {
17 | return this._rooms;
18 | }
19 | /**
20 | * Get all generated corridors
21 | * @returns {ROT.Map.Feature.Corridor[]}
22 | */
23 | getCorridors() {
24 | return this._corridors;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/core/map/ellermaze.js:
--------------------------------------------------------------------------------
1 | import Map from "./map.js";
2 | import RNG from "../rng.js";
3 | /**
4 | * Join lists with "i" and "i+1"
5 | */
6 | function addToList(i, L, R) {
7 | R[L[i + 1]] = R[i];
8 | L[R[i]] = L[i + 1];
9 | R[i] = i + 1;
10 | L[i + 1] = i;
11 | }
12 | /**
13 | * Remove "i" from its list
14 | */
15 | function removeFromList(i, L, R) {
16 | R[L[i]] = R[i];
17 | L[R[i]] = L[i];
18 | R[i] = i;
19 | L[i] = i;
20 | }
21 | /**
22 | * Maze generator - Eller's algorithm
23 | * See http://homepages.cwi.nl/~tromp/maze.html for explanation
24 | */
25 | export default class EllerMaze extends Map {
26 | create(callback) {
27 | let map = this._fillMap(1);
28 | let w = Math.ceil((this._width - 2) / 2);
29 | let rand = 9 / 24;
30 | let L = [];
31 | let R = [];
32 | for (let i = 0; i < w; i++) {
33 | L.push(i);
34 | R.push(i);
35 | }
36 | L.push(w - 1); /* fake stop-block at the right side */
37 | let j;
38 | for (j = 1; j + 3 < this._height; j += 2) {
39 | /* one row */
40 | for (let i = 0; i < w; i++) {
41 | /* cell coords (will be always empty) */
42 | let x = 2 * i + 1;
43 | let y = j;
44 | map[x][y] = 0;
45 | /* right connection */
46 | if (i != L[i + 1] && RNG.getUniform() > rand) {
47 | addToList(i, L, R);
48 | map[x + 1][y] = 0;
49 | }
50 | /* bottom connection */
51 | if (i != L[i] && RNG.getUniform() > rand) {
52 | /* remove connection */
53 | removeFromList(i, L, R);
54 | } else {
55 | /* create connection */
56 | map[x][y + 1] = 0;
57 | }
58 | }
59 | }
60 | /* last row */
61 | for (let i = 0; i < w; i++) {
62 | /* cell coords (will be always empty) */
63 | let x = 2 * i + 1;
64 | let y = j;
65 | map[x][y] = 0;
66 | /* right connection */
67 | if (i != L[i + 1] && (i == L[i] || RNG.getUniform() > rand)) {
68 | /* dig right also if the cell is separated, so it gets connected to the rest of maze */
69 | addToList(i, L, R);
70 | map[x + 1][y] = 0;
71 | }
72 | removeFromList(i, L, R);
73 | }
74 | for (let i = 0; i < this._width; i++) {
75 | for (let j = 0; j < this._height; j++) {
76 | callback(i, j, map[i][j]);
77 | }
78 | }
79 | return this;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/core/map/iceymaze.js:
--------------------------------------------------------------------------------
1 | import Map from "./map.js";
2 | import RNG from "../rng.js";
3 | /**
4 | * Icey's Maze generator
5 | * See http://www.roguebasin.roguelikedevelopment.org/index.php?title=Simple_maze for explanation
6 | */
7 | export default class IceyMaze extends Map {
8 | constructor(width, height, regularity = 0) {
9 | super(width, height);
10 | this._regularity = regularity;
11 | this._map = [];
12 | }
13 | create(callback) {
14 | let width = this._width;
15 | let height = this._height;
16 | let map = this._fillMap(1);
17 | width -= width % 2 ? 1 : 2;
18 | height -= height % 2 ? 1 : 2;
19 | let cx = 0;
20 | let cy = 0;
21 | let nx = 0;
22 | let ny = 0;
23 | let done = 0;
24 | let blocked = false;
25 | let dirs = [
26 | [0, 0],
27 | [0, 0],
28 | [0, 0],
29 | [0, 0]
30 | ];
31 | do {
32 | cx = 1 + 2 * Math.floor((RNG.getUniform() * (width - 1)) / 2);
33 | cy = 1 + 2 * Math.floor((RNG.getUniform() * (height - 1)) / 2);
34 | if (!done) {
35 | map[cx][cy] = 0;
36 | }
37 | if (!map[cx][cy]) {
38 | this._randomize(dirs);
39 | do {
40 | if (Math.floor(RNG.getUniform() * (this._regularity + 1)) == 0) {
41 | this._randomize(dirs);
42 | }
43 | blocked = true;
44 | for (let i = 0; i < 4; i++) {
45 | nx = cx + dirs[i][0] * 2;
46 | ny = cy + dirs[i][1] * 2;
47 | if (this._isFree(map, nx, ny, width, height)) {
48 | map[nx][ny] = 0;
49 | map[cx + dirs[i][0]][cy + dirs[i][1]] = 0;
50 | cx = nx;
51 | cy = ny;
52 | blocked = false;
53 | done++;
54 | break;
55 | }
56 | }
57 | } while (!blocked);
58 | }
59 | } while (done + 1 < (width * height) / 4);
60 | for (let i = 0; i < this._width; i++) {
61 | for (let j = 0; j < this._height; j++) {
62 | callback(i, j, map[i][j]);
63 | }
64 | }
65 | this._map = [];
66 | return this;
67 | }
68 | _randomize(dirs) {
69 | for (let i = 0; i < 4; i++) {
70 | dirs[i][0] = 0;
71 | dirs[i][1] = 0;
72 | }
73 | switch (Math.floor(RNG.getUniform() * 4)) {
74 | case 0:
75 | dirs[0][0] = -1;
76 | dirs[1][0] = 1;
77 | dirs[2][1] = -1;
78 | dirs[3][1] = 1;
79 | break;
80 | case 1:
81 | dirs[3][0] = -1;
82 | dirs[2][0] = 1;
83 | dirs[1][1] = -1;
84 | dirs[0][1] = 1;
85 | break;
86 | case 2:
87 | dirs[2][0] = -1;
88 | dirs[3][0] = 1;
89 | dirs[0][1] = -1;
90 | dirs[1][1] = 1;
91 | break;
92 | case 3:
93 | dirs[1][0] = -1;
94 | dirs[0][0] = 1;
95 | dirs[3][1] = -1;
96 | dirs[2][1] = 1;
97 | break;
98 | }
99 | }
100 | _isFree(map, x, y, width, height) {
101 | if (x < 1 || y < 1 || x >= width || y >= height) {
102 | return false;
103 | }
104 | return map[x][y];
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/core/map/index.js:
--------------------------------------------------------------------------------
1 | import Arena from "./arena.js";
2 | import Uniform from "./uniform.js";
3 | import Cellular from "./cellular.js";
4 | import Digger from "./digger.js";
5 | import EllerMaze from "./ellermaze.js";
6 | import DividedMaze from "./dividedmaze.js";
7 | import IceyMaze from "./iceymaze.js";
8 | import Rogue from "./rogue.js";
9 |
10 | export default {
11 | Arena,
12 | Uniform,
13 | Cellular,
14 | Digger,
15 | EllerMaze,
16 | DividedMaze,
17 | IceyMaze,
18 | Rogue
19 | };
20 |
--------------------------------------------------------------------------------
/src/core/map/map.js:
--------------------------------------------------------------------------------
1 | import { DEFAULT_WIDTH, DEFAULT_HEIGHT } from "../../constants";
2 | export default class Map {
3 | /**
4 | * @class Base map generator
5 | * @param {int} [width=ROT.DEFAULT_WIDTH]
6 | * @param {int} [height=ROT.DEFAULT_HEIGHT]
7 | */
8 | constructor(width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT) {
9 | this._width = width;
10 | this._height = height;
11 | }
12 |
13 | create(callback) {}
14 |
15 | _fillMap(value) {
16 | let map = [];
17 | for (let i = 0; i < this._width; i++) {
18 | map.push([]);
19 | for (let j = 0; j < this._height; j++) {
20 | map[i].push(value);
21 | }
22 | }
23 | return map;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/core/options.js:
--------------------------------------------------------------------------------
1 | let Options = {
2 | x: 0,
3 | y: 0,
4 | gameState: "loading",
5 | };
6 | export default Options
--------------------------------------------------------------------------------
/src/core/player.js:
--------------------------------------------------------------------------------
1 | import { playSound } from "./assetmanager";
2 | import Game from "./game";
3 | import Entity from "./entity";
4 | import Actions from "../../Examples/Actions/actions";
5 | import util from "./util";
6 | export default class Player extends Entity {
7 | constructor(tile) {
8 | super(tile, 0, 3);
9 | this.isPlayer = true;
10 | this.teleportCounter = 0;
11 | this.actions = util
12 | .shuffle(Object.keys(Actions))
13 | .splice(0, Game.numActions);
14 | }
15 | update() {
16 | this.shield--;
17 | }
18 | tryMove(dx, dy) {
19 | if (super.tryMove(dx, dy)) {
20 | Game.tick();
21 | }
22 | }
23 | addAction() {
24 | let newAction = util.shuffle(Object.keys(Actions))[0];
25 | this.actions.push(newAction);
26 | }
27 | // TODO Fix perform actions
28 | performAction(index) {
29 | let actionName = this.actions[index];
30 | if (actionName) {
31 | delete this.actions[index];
32 | Actions[actionName]();
33 | playSound("spell");
34 | Game.tick();
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/core/plugin.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A plugin system based on the [interceptor pattern](https://en.wikipedia.org/wiki/Interceptor_pattern), designed to share reusable code such as more advance collision detection or a 2D physics engine.
3 | *
4 | * ```js
5 | * import { registerPlugin, Sprite } from 'RogueIO';
6 | * import loggingPlugin from 'path/to/plugin/code.js'
7 | *
8 | * // register a plugin that adds logging to all Sprites
9 | * registerPlugin(Sprite, loggingPlugin);
10 | * ```
11 | * @sectionName Plugin
12 | */
13 |
14 | /**
15 | * @docs docs/api_docs/plugin.js
16 | */
17 |
18 | /**
19 | * Get the RogueIO object method name from the plugin.
20 | *
21 | * @param {String} methodName - Before/After function name
22 | *
23 | * @returns {String}
24 | */
25 | function getMethod(methodName) {
26 | let methodTitle = methodName.substr(methodName.search(/[A-Z]/));
27 | return methodTitle[0].toLowerCase() + methodTitle.substr(1);
28 | }
29 |
30 | /**
31 | * Remove an interceptor.
32 | *
33 | * @param {function[]} interceptors - Before/After interceptor list
34 | * @param {function} fn - Interceptor function
35 | */
36 | function removeInterceptor(interceptors, fn) {
37 | let index = interceptors.indexOf(fn);
38 | if (index !== -1) {
39 | interceptors.splice(index, 1);
40 | }
41 | }
42 |
43 | /**
44 | * Register a plugin to run a set of functions before or after the RogueIO object functions.
45 | * @function registerPlugin
46 | *
47 | * @param {Object} RogueIOObj - RogueIO object to attach the plugin to.
48 | * @param {Object} pluginObj - Plugin object with before and after intercept functions.
49 | */
50 | export function registerPlugin(RogueIOObj, pluginObj) {
51 | let objectProto = RogueIOObj.prototype;
52 |
53 | if (!objectProto) return;
54 |
55 | // create interceptor list and functions
56 | if (!objectProto._inc) {
57 | objectProto._inc = {};
58 | objectProto._bInc = function beforePlugins(context, method, ...args) {
59 | return this._inc[method].before.reduce((acc, fn) => {
60 | let newArgs = fn(context, ...acc);
61 | return newArgs ? newArgs : acc;
62 | }, args);
63 | };
64 | objectProto._aInc = function afterPlugins(
65 | context,
66 | method,
67 | result,
68 | ...args
69 | ) {
70 | return this._inc[method].after.reduce((acc, fn) => {
71 | let newResult = fn(context, acc, ...args);
72 | return newResult ? newResult : acc;
73 | }, result);
74 | };
75 | }
76 |
77 | // add plugin to interceptors
78 | Object.getOwnPropertyNames(pluginObj).forEach(methodName => {
79 | let method = getMethod(methodName);
80 |
81 | if (!objectProto[method]) return;
82 |
83 | // override original method
84 | if (!objectProto["_o" + method]) {
85 | objectProto["_o" + method] = objectProto[method];
86 |
87 | objectProto[method] = function interceptedFn(...args) {
88 | // call before interceptors
89 | let alteredArgs = this._bInc(this, method, ...args);
90 |
91 | let result = objectProto["_o" + method].call(this, ...alteredArgs);
92 |
93 | // call after interceptors
94 | return this._aInc(this, method, result, ...args);
95 | };
96 | }
97 |
98 | // create interceptors for the method
99 | if (!objectProto._inc[method]) {
100 | objectProto._inc[method] = {
101 | before: [],
102 | after: []
103 | };
104 | }
105 |
106 | if (methodName.startsWith("before")) {
107 | objectProto._inc[method].before.push(pluginObj[methodName]);
108 | } else if (methodName.startsWith("after")) {
109 | objectProto._inc[method].after.push(pluginObj[methodName]);
110 | }
111 | });
112 | }
113 |
114 | /**
115 | * Unregister a plugin from a RogueIO object.
116 | * @function unregisterPlugin
117 | *
118 | * @param {Object} RogueIOObj - RogueIO object to detach plugin from.
119 | * @param {Object} pluginObj - The plugin object that was passed during registration.
120 | */
121 | export function unregisterPlugin(RogueIOObj, pluginObj) {
122 | let objectProto = RogueIOObj.prototype;
123 |
124 | if (!objectProto || !objectProto._inc) return;
125 |
126 | // remove plugin from interceptors
127 | Object.getOwnPropertyNames(pluginObj).forEach(methodName => {
128 | let method = getMethod(methodName);
129 |
130 | if (methodName.startsWith("before")) {
131 | removeInterceptor(objectProto._inc[method].before, pluginObj[methodName]);
132 | } else if (methodName.startsWith("after")) {
133 | removeInterceptor(objectProto._inc[method].after, pluginObj[methodName]);
134 | }
135 | });
136 | }
137 |
138 | /**
139 | * Safely extend the functionality of a RogueIO object. Any properties that already exist on the RogueIO object will not be added.
140 | *
141 | * ```js
142 | * import { extendObject, Vector } from 'RogueIO';
143 | *
144 | * // add a subtract function to all Vectors
145 | * extendObject(Vector, {
146 | * subtract(vec) {
147 | * return Vector(this.x - vec.x, this.y - vec.y);
148 | * }
149 | * });
150 | * ```
151 | * @function extendObject
152 | *
153 | * @param {Object} RogueIOObj - RogueIO object to extend
154 | * @param {Object} properties - Properties to add.
155 | */
156 | export function extendObject(RogueIOObj, properties) {
157 | let objectProto = RogueIOObj.prototype;
158 |
159 | if (!objectProto) return;
160 |
161 | Object.getOwnPropertyNames(properties).forEach(prop => {
162 | if (!objectProto[prop]) {
163 | objectProto[prop] = properties[prop];
164 | }
165 | });
166 | }
167 |
--------------------------------------------------------------------------------
/src/core/pool.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A fast and memory efficient [object pool](https://gameprogrammingpatterns.com/object-pool.html) for sprite reuse. Perfect for particle systems or SHUMPs. The pool starts out with just one object, but will grow in size to accommodate as many objects as are needed.
3 | *
4 | *
5 | *
6 | * @class Pool
7 | *
8 | * @param {Object} properties - Properties of the pool.
9 | * @param {Function} properties.create - Function that returns a new object to be added to the pool when there are no more alive objects.
10 | * @param {Number} [properties.maxSize=1024] - The maximum number of objects allowed in the pool. The pool will never grow beyond this size.
11 | */
12 | class Pool {
13 | /**
14 | * @docs docs/api_docs/pool.js
15 | */
16 |
17 | constructor({ create, maxSize = 1024 } = {}) {
18 | // check for the correct structure of the objects added to pools so we know that the
19 | // rest of the pool code will work without errors
20 | // @if DEBUG
21 | let obj;
22 | if (
23 | !create ||
24 | !(obj = create()) || !(obj.update && obj.init && obj.isAlive)
25 | ) {
26 | throw Error(
27 | "Must provide create() function which returns an object with init(), update(), and isAlive() functions"
28 | );
29 | }
30 | // @endif
31 |
32 | // c = create
33 | this._c = create;
34 |
35 | /**
36 | * All objects currently in the pool, both alive and not alive.
37 | * @memberof Pool
38 | * @property {Object[]} objects
39 | */
40 | this.objects = [create()]; // start the pool with an object
41 |
42 | /**
43 | * The number of alive objects.
44 | * @memberof Pool
45 | * @property {Number} size
46 | */
47 | this.size = 0;
48 |
49 | /**
50 | * The maximum number of objects allowed in the pool. The pool will never grow beyond this size.
51 | * @memberof Pool
52 | * @property {Number} maxSize
53 | */
54 | this.maxSize = maxSize;
55 | }
56 |
57 | /**
58 | * Get and return an object from the pool. The properties parameter will be passed directly to the objects `init()` function. If you're using a kontra.Sprite, you should also pass the `ttl` property to designate how many frames you want the object to be alive for.
59 | *
60 | * If you want to control when the sprite is ready for reuse, pass `Infinity` for `ttl`. You'll need to set the sprites `ttl` to `0` when you're ready for the sprite to be reused.
61 | *
62 | * ```js
63 | * // exclude-tablist
64 | * let sprite = pool.get({
65 | * // the object will get these properties and values
66 | * x: 100,
67 | * y: 200,
68 | * width: 20,
69 | * height: 40,
70 | * color: 'red',
71 | *
72 | * // pass Infinity for ttl to prevent the object from being reused
73 | * // until you set it back to 0
74 | * ttl: Infinity
75 | * });
76 | * ```
77 | * @memberof Pool
78 | * @function get
79 | *
80 | * @param {Object} properties - Properties to pass to the objects `init()` function.
81 | *
82 | * @returns {Object} The newly initialized object.
83 | */
84 | get(properties = {}) {
85 | // the pool is out of objects if the first object is in use and it can't grow
86 | if (this.size === this.objects.length) {
87 | if (this.size === this.maxSize) {
88 | return;
89 | }
90 | // double the size of the array by adding twice as many new objects to the end
91 | else {
92 | for (
93 | let i = 0;
94 | i < this.size && this.objects.length < this.maxSize;
95 | i++
96 | ) {
97 | this.objects.push(this._c());
98 | }
99 | }
100 | }
101 |
102 | // save off first object in pool to reassign to last object after unshift
103 | let obj = this.objects[this.size];
104 | this.size++;
105 | obj.init(properties);
106 | return obj;
107 | }
108 |
109 | /**
110 | * Returns an array of all alive objects. Useful if you need to do special processing on all alive objects outside of the pool, such as add all alive objects to a kontra.Quadtree.
111 | * @memberof Pool
112 | * @function getAliveObjects
113 | *
114 | * @returns {Object[]} An Array of all alive objects.
115 | */
116 | getAliveObjects() {
117 | return this.objects.slice(0, this.size);
118 | }
119 |
120 | /**
121 | * Clear the object pool. Removes all objects from the pool and resets its [size](api/pool#size) to 1.
122 | * @memberof Pool
123 | * @function clear
124 | */
125 | clear() {
126 | this.size = this.objects.length = 0;
127 | this.objects.push(this._c());
128 | }
129 |
130 | /**
131 | * Update all alive objects in the pool by calling the objects `update()` function. This function also manages when each object should be recycled, so it is recommended that you do not call the objects `update()` function outside of this function.
132 | * @memberof Pool
133 | * @function update
134 | *
135 | * @param {Number} [dt] - Time since last update.
136 | */
137 | update(dt) {
138 | let obj;
139 | let doSort = false;
140 | for (let i = this.size; i--; ) {
141 | obj = this.objects[i];
142 |
143 | obj.update(dt);
144 |
145 | if (!obj.isAlive()) {
146 | doSort = true;
147 | this.size--;
148 | }
149 | }
150 | // sort all dead elements to the end of the pool
151 | if (doSort) {
152 | this.objects.sort((a, b) => b.isAlive() - a.isAlive());
153 | }
154 | }
155 |
156 | /**
157 | * Render all alive objects in the pool by calling the objects `render()` function.
158 | * @memberof Pool
159 | * @function render
160 | */
161 | render() {
162 | for (let i = this.size; i--; ) {
163 | this.objects[i].render();
164 | }
165 | }
166 | }
167 |
168 | export default function poolFactory(properties) {
169 | return new Pool(properties);
170 | }
171 | poolFactory.prototype = Pool.prototype;
172 | poolFactory.class = Pool;
173 |
--------------------------------------------------------------------------------
/src/core/rng.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This code is an implementation of Alea algorithm; (C) 2010 Johannes Baagøe.
3 | * Alea is licensed according to the http://en.wikipedia.org/wiki/MIT_License.
4 | */
5 |
6 | const FRAC = 2.3283064365386963e-10; /* 2^-32 */
7 |
8 | class RNG {
9 | constructor() {
10 | this._seed = 0;
11 | this._s0 = 0;
12 | this._s1 = 0;
13 | this._s2 = 0;
14 | this._c = 0;
15 | }
16 |
17 | getSeed() {
18 | return this._seed;
19 | }
20 |
21 | /**
22 | * Seed the number generator
23 | */
24 | setSeed(seed) {
25 | seed = seed < 1 ? 1 / seed : seed;
26 |
27 | this._seed = seed;
28 | this._s0 = (seed >>> 0) * FRAC;
29 |
30 | seed = (seed * 69069 + 1) >>> 0;
31 | this._s1 = seed * FRAC;
32 |
33 | seed = (seed * 69069 + 1) >>> 0;
34 | this._s2 = seed * FRAC;
35 |
36 | this._c = 1;
37 | return this;
38 | }
39 |
40 | /**
41 | * @returns Pseudorandom value [0,1), uniformly distributed
42 | */
43 | getUniform() {
44 | let t = 2091639 * this._s0 + this._c * FRAC;
45 | this._s0 = this._s1;
46 | this._s1 = this._s2;
47 | this._c = t | 0;
48 | this._s2 = t - this._c;
49 | return this._s2;
50 | }
51 |
52 | /**
53 | * @param lowerBound The lower end of the range to return a value from, inclusive
54 | * @param upperBound The upper end of the range to return a value from, inclusive
55 | * @returns Pseudorandom value [lowerBound, upperBound], using ROT.RNG.getUniform() to distribute the value
56 | */
57 | getUniformInt(lowerBound, upperBound) {
58 | let max = Math.max(lowerBound, upperBound);
59 | let min = Math.min(lowerBound, upperBound);
60 | return Math.floor(this.getUniform() * (max - min + 1)) + min;
61 | }
62 |
63 | /**
64 | * @param mean Mean value
65 | * @param stddev Standard deviation. ~95% of the absolute values will be lower than 2*stddev.
66 | * @returns A normally distributed pseudorandom value
67 | */
68 | getNormal(mean = 0, stddev = 1) {
69 | let u, v, r;
70 | do {
71 | u = 2 * this.getUniform() - 1;
72 | v = 2 * this.getUniform() - 1;
73 | r = u * u + v * v;
74 | } while (r > 1 || r == 0);
75 |
76 | let gauss = u * Math.sqrt((-2 * Math.log(r)) / r);
77 | return mean + gauss * stddev;
78 | }
79 |
80 | /**
81 | * @returns Pseudorandom value [1,100] inclusive, uniformly distributed
82 | */
83 | getPercentage() {
84 | return 1 + Math.floor(this.getUniform() * 100);
85 | }
86 |
87 | /**
88 | * @returns Randomly picked item, null when length=0
89 | */
90 | getItem(array) {
91 | if (!array.length) {
92 | return null;
93 | }
94 | return array[Math.floor(this.getUniform() * array.length)];
95 | }
96 |
97 | /**
98 | * @returns New array with randomized items
99 | */
100 | shuffle(array) {
101 | let result = [];
102 | let clone = array.slice();
103 | while (clone.length) {
104 | let index = clone.indexOf(this.getItem(clone));
105 | result.push(clone.splice(index, 1)[0]);
106 | }
107 | return result;
108 | }
109 |
110 | /**
111 | * @param data key=whatever, value=weight (relative probability)
112 | * @returns whatever
113 | */
114 | getWeightedValue(data) {
115 | let total = 0;
116 |
117 | for (let id in data) {
118 | total += data[id];
119 | }
120 | let random = this.getUniform() * total;
121 |
122 | let id,
123 | part = 0;
124 | for (id in data) {
125 | part += data[id];
126 | if (random < part) {
127 | return id;
128 | }
129 | }
130 |
131 | // If by some floating-point annoyance we have
132 | // random >= total, just return the last id.
133 | return id;
134 | }
135 |
136 | /**
137 | * Get RNG state. Useful for storing the state and re-setting it via setState.
138 | * @returns Internal state
139 | */
140 | getState() {
141 | return [this._s0, this._s1, this._s2, this._c];
142 | }
143 |
144 | /**
145 | * Set a previously retrieved state.
146 | */
147 | setState(state) {
148 | this._s0 = state[0];
149 | this._s1 = state[1];
150 | this._s2 = state[2];
151 | this._c = state[3];
152 | return this;
153 | }
154 |
155 | /**
156 | * Returns a cloned RNG
157 | */
158 | clone() {
159 | let clone = new RNG();
160 | return clone.setState(this.getState());
161 | }
162 | }
163 |
164 | export default new RNG().setSeed(Date.now());
165 |
--------------------------------------------------------------------------------
/src/core/spritesheet.js:
--------------------------------------------------------------------------------
1 | import Animation from "./animation.js";
2 |
3 | /**
4 | * Parse a string of consecutive frames.
5 | *
6 | * @param {Number|String} frames - Start and end frame.
7 | *
8 | * @returns {Number|Number[]} List of frames.
9 | */
10 | function parseFrames(consecutiveFrames) {
11 | // return a single number frame
12 | // @see https://github.com/jed/140bytes/wiki/Byte-saving-techniques#coercion-to-test-for-types
13 | if (+consecutiveFrames === consecutiveFrames) {
14 | return consecutiveFrames;
15 | }
16 |
17 | let sequence = [];
18 | let frames = consecutiveFrames.split("..");
19 |
20 | // coerce string to number
21 | // @see https://github.com/jed/140bytes/wiki/Byte-saving-techniques#coercion-to-test-for-types
22 | let start = +frames[0];
23 | let end = +frames[1];
24 | let i = start;
25 |
26 | // ascending frame order
27 | if (start < end) {
28 | for (; i <= end; i++) {
29 | sequence.push(i);
30 | }
31 | }
32 | // descending order
33 | else {
34 | for (; i >= end; i--) {
35 | sequence.push(i);
36 | }
37 | }
38 |
39 | return sequence;
40 | }
41 |
42 | /**
43 | * A sprite sheet to animate a sequence of images. Used to create [animation sprites](api/sprite#animation-sprite).
44 | *
45 | *
46 | *
47 | *
48 | *
49 | * Sprite sheet image courtesy of Kenney.
50 | *
51 | *
52 | * Typically you create a sprite sheet just to create animations and then use the animations for your sprite.
53 | *
54 | * ```js
55 | * import { Sprite, SpriteSheet } from 'kontra';
56 | *
57 | * let image = new Image();
58 | * image.src = 'assets/imgs/character_walk_sheet.png';
59 | * image.onload = function() {
60 | * let spriteSheet = SpriteSheet({
61 | * image: image,
62 | * frameWidth: 72,
63 | * frameHeight: 97,
64 | * animations: {
65 | * // create a named animation: walk
66 | * walk: {
67 | * frames: '0..9', // frames 0 through 9
68 | * frameRate: 30
69 | * }
70 | * }
71 | * });
72 | *
73 | * let sprite = Sprite({
74 | * x: 200,
75 | * y: 100,
76 | *
77 | * // use the sprite sheet animations for the sprite
78 | * animations: spriteSheet.animations
79 | * });
80 | * };
81 | * ```
82 | * @class SpriteSheet
83 | *
84 | * @param {Object} properties - Properties of the sprite sheet.
85 | * @param {Image|HTMLCanvasElement} properties.image - The sprite sheet image.
86 | * @param {Number} properties.frameWidth - The width of a single frame.
87 | * @param {Number} properties.frameHeight - The height of a single frame.
88 | * @param {Number} [properties.frameMargin=0] - The amount of whitespace between each frame.
89 | * @param {Object} [properties.animations] - Animations to create from the sprite sheet using kontra.Animation. Passed directly into the sprite sheets [createAnimations()](api/spriteSheet#createAnimations) function.
90 | */
91 | class SpriteSheet {
92 | constructor({
93 | image,
94 | frameWidth,
95 | frameHeight,
96 | frameMargin,
97 | animations
98 | } = {}) {
99 | // @if DEBUG
100 | if (!image) {
101 | throw Error("You must provide an Image for the SpriteSheet");
102 | }
103 | // @endif
104 |
105 | /**
106 | * An object of named kontra.Animation objects. Typically you pass this object into kontra.Sprite to create an [animation sprites](api/spriteSheet#animation-sprite).
107 | * @memberof SpriteSheet
108 | * @property {Object} animations
109 | */
110 | this.animations = {};
111 |
112 | /**
113 | * The sprite sheet image.
114 | * @memberof SpriteSheet
115 | * @property {Image|HTMLCanvasElement} image
116 | */
117 | this.image = image;
118 |
119 | /**
120 | * An object that defines properties of a single frame in the sprite sheet. It has properties of `width`, `height`, and `margin`.
121 | *
122 | * `width` and `height` are the width of a single frame, while `margin` defines the amount of whitespace between each frame.
123 | * @memberof SpriteSheet
124 | * @property {Object} frame
125 | */
126 | this.frame = {
127 | width: frameWidth,
128 | height: frameHeight,
129 | margin: frameMargin
130 | };
131 |
132 | // f = framesPerRow
133 | this._f = (image.width / frameWidth) | 0;
134 |
135 | this.createAnimations(animations);
136 | }
137 |
138 | /**
139 | * Create named animations from the sprite sheet. Called from the constructor if the `animations` argument is passed.
140 | *
141 | * This function populates the sprite sheets `animations` property with kontra.Animation objects. Each animation is accessible by its name.
142 | *
143 | * ```js
144 | * import { Sprite, SpriteSheet } from 'kontra';
145 | *
146 | * let image = new Image();
147 | * image.src = 'assets/imgs/character_walk_sheet.png';
148 | * image.onload = function() {
149 | *
150 | * let spriteSheet = SpriteSheet({
151 | * image: image,
152 | * frameWidth: 72,
153 | * frameHeight: 97,
154 | *
155 | * // this will also call createAnimations()
156 | * animations: {
157 | * // create 1 animation: idle
158 | * idle: {
159 | * // a single frame
160 | * frames: 1
161 | * }
162 | * }
163 | * });
164 | *
165 | * spriteSheet.createAnimations({
166 | * // create 4 animations: jump, walk, moonWalk, attack
167 | * jump: {
168 | * // sequence of frames (can be non-consecutive)
169 | * frames: [1, 10, 1],
170 | * frameRate: 10,
171 | * loop: false,
172 | * },
173 | * walk: {
174 | * // ascending consecutive frame animation (frames 2-6, inclusive)
175 | * frames: '2..6',
176 | * frameRate: 20
177 | * },
178 | * moonWalk: {
179 | * // descending consecutive frame animation (frames 6-2, inclusive)
180 | * frames: '6..2',
181 | * frameRate: 20
182 | * },
183 | * attack: {
184 | * // you can also mix and match, in this case frames [8,9,10,13,10,9,8]
185 | * frames: ['8..10', 13, '10..8'],
186 | * frameRate: 10,
187 | * loop: false,
188 | * }
189 | * });
190 | * };
191 | * ```
192 | * @memberof SpriteSheet
193 | * @function createAnimations
194 | *
195 | * @param {Object} animations - Object of named animations to create from the sprite sheet.
196 | * @param {Number|String|Number[]|String[]} animations..frames - The sequence of frames to use from the sprite sheet. It can either be a single frame (`1`), a sequence of frames (`[1,2,3,4]`), or a consecutive frame notation (`'1..4'`). Sprite sheet frames are `0` indexed.
197 | * @param {Number} animations..frameRate - The number frames to display per second.
198 | * @param {Boolean} [animations..loop=true] - If the animation should loop back to the beginning once completed.
199 | */
200 | createAnimations(animations) {
201 | let sequence, name;
202 |
203 | for (name in animations) {
204 | let { frames, frameRate, loop } = animations[name];
205 |
206 | // array that holds the order of the animation
207 | sequence = [];
208 |
209 | // @if DEBUG
210 | if (frames === undefined) {
211 | throw Error("Animation " + name + " must provide a frames property");
212 | }
213 | // @endif
214 |
215 | // add new frames to the end of the array
216 | [].concat(frames).map(frame => {
217 | sequence = sequence.concat(parseFrames(frame));
218 | });
219 |
220 | this.animations[name] = Animation({
221 | spriteSheet: this,
222 | frames: sequence,
223 | frameRate,
224 | loop
225 | });
226 | }
227 | }
228 | }
229 |
230 | export default function spriteSheetFactory(properties) {
231 | return new SpriteSheet(properties);
232 | }
233 | spriteSheetFactory.prototype = SpriteSheet.prototype;
234 | spriteSheetFactory.class = SpriteSheet;
235 |
--------------------------------------------------------------------------------
/src/core/store.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A simple interface to LocalStorage based on [store.js](https://github.com/marcuswestin/store.js), whose sole purpose is to ensure that any keys you save to LocalStorage come out the same type as when they went in.
3 | *
4 | * Normally when you save something to LocalStorage, it converts it into a string. So if you were to save a number, it would be saved as `"12"` instead of `12`. This means when you retrieved the number, it would now be a string.
5 | *
6 | * ```js
7 | * import { setStoreItem, getStoreItem } from 'RogueIO';
8 | *
9 | * setStoreItem('highScore', 100);
10 | * getStoreItem('highScore'); //=> 100
11 | * ```
12 | * @sectionName Store
13 | */
14 |
15 | /**
16 | * Save an item to localStorage.
17 | * @function setStoreItem
18 | *
19 | * @param {String} key - The name of the key.
20 | * @param {*} value - The value to store.
21 | */
22 | export function setStoreItem(key, value) {
23 | if (value === undefined) {
24 | localStorage.removeItem(key);
25 | } else {
26 | localStorage.setItem(key, JSON.stringify(value));
27 | }
28 | }
29 |
30 | /**
31 | * Retrieve an item from localStorage and convert it back to its original type.
32 | * @function getStoreItem
33 | *
34 | * @param {String} key - Name of the key of the item to retrieve.
35 | *
36 | * @returns {*} The retrieved item.
37 | */
38 | export function getStoreItem(key) {
39 | let value = localStorage.getItem(key);
40 |
41 | try {
42 | value = JSON.parse(value);
43 | } catch (e) {}
44 |
45 | return value;
46 | }
47 |
--------------------------------------------------------------------------------
/src/core/tile.js:
--------------------------------------------------------------------------------
1 | import Game from "./game";
2 | import SpriteSheet from "./spritesheet";
3 | import util from "./util";
4 | export default class Tile {
5 | constructor(x, y, sprite, passable) {
6 | this.ctx = null;
7 | this.x = x;
8 | this.y = y;
9 | this.sprite = sprite;
10 | this.passable = passable;
11 | }
12 | replace(newTileType) {
13 | Game.map.tiles[this.x][this.y] = new newTileType(this.x, this.y);
14 | return Game.map.tiles[this.x][this.y];
15 | }
16 | //manhattan distance
17 | dist(other) {
18 | return Math.abs(this.x - other.x) + Math.abs(this.y - other.y);
19 | }
20 |
21 | getNeighbor(dx, dy) {
22 | return Game.map.getTile(this.x + dx, this.y + dy);
23 | }
24 |
25 | getAdjacentNeighbors() {
26 | return util.shuffle([
27 | this.getNeighbor(0, -1),
28 | this.getNeighbor(0, 1),
29 | this.getNeighbor(-1, 0),
30 | this.getNeighbor(1, 0)
31 | ]);
32 | }
33 |
34 | getAdjacentPassableNeighbors() {
35 | return this.getAdjacentNeighbors().filter(t => t.passable);
36 | }
37 |
38 | getConnectedTiles() {
39 | let connectedTiles = [this];
40 | let frontier = [this];
41 | while (frontier.length) {
42 | let neighbors = frontier
43 | .pop()
44 | .getAdjacentPassableNeighbors()
45 | .filter(t => !connectedTiles.includes(t));
46 | connectedTiles = connectedTiles.concat(neighbors);
47 | frontier = frontier.concat(neighbors);
48 | }
49 | return connectedTiles;
50 | }
51 | draw() {
52 | this.ctx = Game.canvas.getCtx();
53 | let spriteSheet = new SpriteSheet({
54 | ctx: this.ctx,
55 | tilesize: Game.tilesize
56 | });
57 | spriteSheet.drawSprite(this.sprite, this.x, this.y);
58 | if (this.treasure) {
59 | spriteSheet.drawSprite(12, this.x, this.y);
60 | }
61 | if (this.effectCounter) {
62 | this.effectCounter--;
63 | this.ctx.globalAlpha = this.effectCounter / 30;
64 | spriteSheet.drawSprite(this.effect, this.x, this.y);
65 | this.ctx.globalAlpha = 1;
66 | }
67 | }
68 | setEffect(effectSprite) {
69 | this.effect = effectSprite;
70 | this.effectCounter = 30;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/core/util.js:
--------------------------------------------------------------------------------
1 | export const noop = () => {};
2 | export const tryTo = (desc, callback) => {
3 | for (let timeout = 1000; timeout > 0; timeout--) {
4 | if (callback()) {
5 | return;
6 | }
7 | }
8 | throw "Timeout while tring to " + desc;
9 | };
10 | export const randomRange = (min, max) => {
11 | return Math.floor(Math.random() * (max - min + 1)) + min;
12 | };
13 | export const shuffle = arr => {
14 | let temp, r;
15 | for (let i = 1; i < arr.length; i++) {
16 | r = this.randomRange(0, i);
17 | temp = arr[i];
18 | arr[i] = arr[r];
19 | arr[r] = temp;
20 | }
21 | return arr;
22 | };
23 | export const rightPad = textArray => {
24 | let finalText = "";
25 | textArray.forEach(text => {
26 | text += "";
27 | for (let i = text.length; i < 10; i++) {
28 | text += " ";
29 | }
30 | finalText += text;
31 | });
32 | return finalText;
33 | };
34 | /**
35 | * Always positive modulus
36 | * @param x Operand
37 | * @param n Modulus
38 | * @returns x modulo n
39 | */
40 | export function mod(x, n) {
41 | return ((x % n) + n) % n;
42 | }
43 |
44 | export function clamp(val, min = 0, max = 1) {
45 | if (val < min) return min;
46 | if (val > max) return max;
47 | return val;
48 | }
49 |
50 | export function capitalize(string) {
51 | return string.charAt(0).toUpperCase() + string.substring(1);
52 | }
53 |
54 | /**
55 | * Format a string in a flexible way. Scans for %s strings and replaces them with arguments. List of patterns is modifiable via String.format.map.
56 | * @param {string} template
57 | * @param {any} [argv]
58 | */
59 | export function format(template, ...args) {
60 | let map = format.map;
61 |
62 | let replacer = function(match, group1, group2, index) {
63 | if (template.charAt(index - 1) == "%") {
64 | return match.substring(1);
65 | }
66 | if (!args.length) {
67 | return match;
68 | }
69 | let obj = args[0];
70 |
71 | let group = group1 || group2;
72 | let parts = group.split(",");
73 | let name = parts.shift() || "";
74 | let method = map[name.toLowerCase()];
75 | if (!method) {
76 | return match;
77 | }
78 |
79 | obj = args.shift();
80 | let replaced = obj[method].apply(obj, parts);
81 |
82 | let first = name.charAt(0);
83 | if (first != first.toLowerCase()) {
84 | replaced = capitalize(replaced);
85 | }
86 |
87 | return replaced;
88 | };
89 | return template.replace(/%(?:([a-z]+)|(?:{([^}]+)}))/gi, replacer);
90 | }
91 |
--------------------------------------------------------------------------------
/src/core/vector.js:
--------------------------------------------------------------------------------
1 | /**
2 | * A simple 2d vector object.
3 | *
4 | * ```js
5 | * import { Vector } from 'kontra';
6 | *
7 | * let vector = Vector(100, 200);
8 | * ```
9 | * @class Vector
10 | *
11 | * @param {Number} [x=0] - X coordinate of the vector.
12 | * @param {Number} [y=0] - Y coordinate of the vector.
13 | */
14 | class Vector {
15 | constructor(x = 0, y = 0) {
16 | this._x = x;
17 | this._y = y;
18 | }
19 |
20 | /**
21 | * Return a new Vector whose value is the addition of the current Vector and the passed in Vector. If `dt` is provided, the result is multiplied by the value.
22 | * @memberof Vector
23 | * @function add
24 | *
25 | * @param {kontra.Vector} vector - Vector to add to the current Vector.
26 | * @param {Number} [dt=1] - Time since last update.
27 | *
28 | * @returns {kontra.Vector} A new kontra.Vector instance.
29 | */
30 | add(vec, dt = 1) {
31 | return vectorFactory(
32 | this.x + (vec.x || 0) * dt,
33 | this.y + (vec.y || 0) * dt,
34 | this
35 | );
36 | }
37 |
38 | /**
39 | * Clamp the Vector between two points, preventing `x` and `y` from going below or above the minimum and maximum values. Perfect for keeping a sprite from going outside the game boundaries.
40 | *
41 | * ```js
42 | * import { Vector } from 'kontra';
43 | *
44 | * let vector = Vector(100, 200);
45 | * vector.clamp(0, 0, 200, 300);
46 | *
47 | * vector.x += 200;
48 | * console.log(vector.x); //=> 200
49 | *
50 | * vector.y -= 300;
51 | * console.log(vector.y); //=> 0
52 | *
53 | * vector.add({x: -500, y: 500});
54 | * console.log(vector); //=> {x: 0, y: 300}
55 | * ```
56 | * @memberof Vector
57 | * @function clamp
58 | *
59 | * @param {Number} xMin - Minimum x value.
60 | * @param {Number} yMin - Minimum y value.
61 | * @param {Number} xMax - Maximum x value.
62 | * @param {Number} yMax - Maximum y value.
63 | */
64 | clamp(xMin, yMin, xMax, yMax) {
65 | this._c = true;
66 | this._a = xMin;
67 | this._b = yMin;
68 | this._d = xMax;
69 | this._e = yMax;
70 | }
71 |
72 | /**
73 | * X coordinate of the vector.
74 | * @memberof Vector
75 | * @property {Number} x
76 | */
77 | get x() {
78 | return this._x;
79 | }
80 |
81 | /**
82 | * Y coordinate of the vector.
83 | * @memberof Vector
84 | * @property {Number} y
85 | */
86 | get y() {
87 | return this._y;
88 | }
89 |
90 | set x(value) {
91 | this._x = this._c ? Math.min(Math.max(this._a, value), this._d) : value;
92 | }
93 |
94 | set y(value) {
95 | this._y = this._c ? Math.min(Math.max(this._b, value), this._e) : value;
96 | }
97 | }
98 |
99 | export default function vectorFactory(x, y, vec = {}) {
100 | let vector = new Vector(x, y);
101 |
102 | // preserve vector clamping when creating new vectors
103 | if (vec._c) {
104 | vector.clamp(vec._a, vec._b, vec._d, vec._e);
105 |
106 | // reset x and y so clamping takes effect
107 | vector.x = x;
108 | vector.y = y;
109 | }
110 |
111 | return vector;
112 | }
113 | vectorFactory.prototype = Vector.prototype;
114 | vectorFactory.class = Vector;
115 |
--------------------------------------------------------------------------------
/src/core/wall.js:
--------------------------------------------------------------------------------
1 | import Tile from "./tile";
2 | export default class Wall extends Tile {
3 | constructor(x, y) {
4 | super(x, y, 3, false);
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/src/index.defaults.js:
--------------------------------------------------------------------------------
1 | import Animation from "./core/animation.js";
2 | import {
3 | imageAssets,
4 | audioAssets,
5 | dataAssets,
6 | setImagePath,
7 | setAudioPath,
8 | setDataPath,
9 | loadImage,
10 | loadAudio,
11 | loadData,
12 | load
13 | } from "./core/assetmanager";
14 | import { init, getCanvas, getContext } from "./core/canvas";
15 | import { on, off, emit } from "./core/eventmanager";
16 | import Game from "./core/game";
17 | import {
18 | keyMap,
19 | initKeys,
20 | bindKeys,
21 | unbindKeys,
22 | keyPressed
23 | } from "./core/keyboard.js";
24 | import Map from "./core/map/index.js";
25 | import {
26 | registerPlugin,
27 | unregisterPlugin,
28 | extendObject
29 | } from "./core/plugin.js";
30 | import {
31 | initPointer,
32 | pointer,
33 | track,
34 | untrack,
35 | pointerOver,
36 | onPointerDown,
37 | onPointerUp,
38 | pointerPressed
39 | } from "./core/pointer.js";
40 | import Pool from "./core/pool.js";
41 |
42 | import RNG from "./core/rng.js";
43 | import Quadtree from "./core/quadtree.js";
44 | import Sprite from "./core/sprite.js";
45 | import SpriteSheet from "./core/spritesheet.js";
46 | import { setStoreItem, getStoreItem } from "./core/store.js";
47 | import TileEngine from "./core/tileengine.js";
48 | import Vector from "./core/vector.js";
49 |
50 | let RogueIO = {
51 | Animation,
52 |
53 | imageAssets,
54 | audioAssets,
55 | dataAssets,
56 | setImagePath,
57 | setAudioPath,
58 | setDataPath,
59 | loadImage,
60 | loadAudio,
61 | loadData,
62 | load,
63 |
64 | init,
65 | getCanvas,
66 | getContext,
67 |
68 | on,
69 | off,
70 | emit,
71 |
72 | Game,
73 |
74 | keyMap,
75 | initKeys,
76 | bindKeys,
77 | unbindKeys,
78 | keyPressed,
79 | Map,
80 | registerPlugin,
81 | unregisterPlugin,
82 | extendObject,
83 |
84 | initPointer,
85 | pointer,
86 | track,
87 | untrack,
88 | pointerOver,
89 | onPointerDown,
90 | onPointerUp,
91 | pointerPressed,
92 |
93 | Pool,
94 | Quadtree,
95 | RNG,
96 | Sprite,
97 | SpriteSheet,
98 |
99 | setStoreItem,
100 | getStoreItem,
101 |
102 | TileEngine,
103 | Vector
104 | };
105 |
106 | export default RogueIO;
107 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | export { default as Animation } from "./core/animation.js";
2 | export {
3 | imageAssets,
4 | audioAssets,
5 | dataAssets,
6 | setImagePath,
7 | setAudioPath,
8 | setDataPath,
9 | loadImage,
10 | loadAudio,
11 | loadData,
12 | load
13 | } from "./core/assetmanager";
14 | export { init, getCanvas, getContext } from "./core/canvas";
15 | export { on, off, emit } from "./core/eventmanager";
16 |
17 | // import Entity from "./core/entity";
18 | export { default as Game } from "./core/game";
19 | export {
20 | keyMap,
21 | initKeys,
22 | bindKeys,
23 | unbindKeys,
24 | keyPressed
25 | } from "./core/keyboard.js";
26 | export { default as Map } from "./core/map/index.js";
27 | export {
28 | registerPlugin,
29 | unregisterPlugin,
30 | extendObject
31 | } from "./core/plugin.js";
32 | export {
33 | initPointer,
34 | pointer,
35 | track,
36 | untrack,
37 | pointerOver,
38 | onPointerDown,
39 | onPointerUp,
40 | pointerPressed
41 | } from "./core/pointer.js";
42 | export { default as Pool } from "./core/pool.js";
43 | export { default as Quadtree } from "./core/quadtree.js";
44 | export { default as RNG } from "./core/rng.js";
45 | export { default as Sprite } from "./core/sprite.js";
46 | export { default as SpriteSheet } from "./core/spritesheet.js";
47 | export { setStoreItem, getStoreItem } from "./core/store.js";
48 | export { default as TileEngine } from "./core/tileengine.js";
49 | export { default as Vector } from "./core/vector.js";
50 | export { default } from "./index.defaults.js";
--------------------------------------------------------------------------------
/webpack.config.babel.js:
--------------------------------------------------------------------------------
1 | import path from "path";
2 | import HtmlWebpackPlugin from "html-webpack-plugin";
3 | import ScriptExtHtmlWebpackPlugin from "script-ext-html-webpack-plugin";
4 | export default {
5 | entry: path.join(__dirname, "App.js"),
6 | output: {
7 | path: path.join(__dirname, "lib"),
8 | filename: "[name].bundle.js"
9 | },
10 | module: {
11 | rules: [
12 | {
13 | test: /\.js/,
14 | exclude: /(node_modules|bower_components)/,
15 | use: [
16 | {
17 | loader: "babel-loader"
18 | }
19 | ]
20 | },
21 | {
22 | test: /\.css$/,
23 | use: ["style-loader", "css-loader"]
24 | }
25 | ]
26 | },
27 | plugins: [
28 | new HtmlWebpackPlugin({
29 | title: "pack",
30 | template: path.join(__dirname, "public/index.html"),
31 | inject: "body"
32 | }),
33 | new ScriptExtHtmlWebpackPlugin({
34 | defaultAttribute: "defer"
35 | })
36 | ],
37 | stats: {
38 | colors: true
39 | },
40 | devtool: "source-map",
41 | mode: "development",
42 | devServer: {
43 | contentBase: "./public",
44 | inline: true,
45 | port: 8085 //my prefered port for development, but change as you see fit
46 | }
47 | };
48 |
--------------------------------------------------------------------------------