diff --git a/source/images/sprites/monsters/mother_spider_alpha.png b/source/images/sprites/monsters/mother_spider_alpha.png new file mode 100755 index 0000000..cfe7ecc Binary files /dev/null and b/source/images/sprites/monsters/mother_spider_alpha.png differ diff --git a/source/images/sprites/monsters/mother_spider_omega.png b/source/images/sprites/monsters/mother_spider_omega.png new file mode 100755 index 0000000..ec5e104 Binary files /dev/null and b/source/images/sprites/monsters/mother_spider_omega.png differ diff --git a/source/images/sprites/monsters/spider_alpha.png b/source/images/sprites/monsters/spider_alpha.png new file mode 100755 index 0000000..db0f0b6 Binary files /dev/null and b/source/images/sprites/monsters/spider_alpha.png differ diff --git a/source/images/sprites/monsters/spider_omega.png b/source/images/sprites/monsters/spider_omega.png new file mode 100755 index 0000000..ace01c9 Binary files /dev/null and b/source/images/sprites/monsters/spider_omega.png differ diff --git a/source/images/sprites/terrain/web.png b/source/images/sprites/terrain/web.png new file mode 100755 index 0000000..3e3a8ec Binary files /dev/null and b/source/images/sprites/terrain/web.png differ diff --git a/source/index.css b/source/index.css index d09d055..1e94d9a 100644 --- a/source/index.css +++ b/source/index.css @@ -39,6 +39,30 @@ html { 100% {transform: translateX(0px)} } +@keyframes attack-southeastwards { + 0% {transform: translate(0px,0px)} + 50% {transform: translate(+7px,+7px)} + 100% {transform: translate(0px,0px)} +} + +@keyframes attack-northeastwards { + 0% {transform: translate(0px,0px)} + 50% {transform: translate(+7px,-7px)} + 100% {transform: translate(0px,0px)} +} + +@keyframes attack-southeastwards { + 0% {transform: translate(0px,0px)} + 50% {transform: translate(-7px,+7px)} + 100% {transform: translate(0px,0px)} +} + +@keyframes attack-southwestwards { + 0% {transform: translate(0px,0px)} + 50% {transform: translate(-7px,-7px)} + 100% {transform: translate(0px,0px)} +} + @function strip-unit($number) { @if type-of($number) == 'number' and not unitless($number) { @return $number / ($number * 0 + 1); diff --git a/source/scripts/data/index.js b/source/scripts/data/index.js index 0dfecce..b711dce 100644 --- a/source/scripts/data/index.js +++ b/source/scripts/data/index.js @@ -46,6 +46,14 @@ export default { ALPHA: require("images/sprites/monsters/thief_alpha.png"), OMEGA: require("images/sprites/monsters/thief_omega.png"), }, + SPIDER: { + ALPHA: require("images/sprites/monsters/spider_alpha.png"), + OMEGA: require("images/sprites/monsters/spider_omega.png"), + }, + MOTHER_SPIDER: { + ALPHA: require("images/sprites/monsters/mother_spider_alpha.png"), + OMEGA: require("images/sprites/monsters/mother_spider_omega.png"), + }, }, EFFECTS: { SLICE: [ @@ -67,6 +75,7 @@ export default { require("images/sprites/terrain/dot-1.png"), require("images/sprites/terrain/dot-2.png"), ], + WEB: require("images/sprites/terrain/web.png"), }, BLOOD: [ require("images/sprites/blood/0.png"), @@ -91,5 +100,6 @@ export default { 100: require("images/sprites/hud/heart-100.png"), }, }, + NULL: require("images/textures/null.png"), } } diff --git a/source/scripts/data/monsters.js b/source/scripts/data/monsters.js index 4e6fb91..8e9c5e0 100644 --- a/source/scripts/data/monsters.js +++ b/source/scripts/data/monsters.js @@ -225,4 +225,144 @@ export default { } } }, + NORMAL_SPIDER: { + sprite: DATA.SPRITES.MONSTERS.SPIDER, + color: DATA.COLORS.WHITE, + health: 1, + strength: 1, + movement: function () { + + var dx = this.game.adventurer.position.x - this.position.x + var dy = this.game.adventurer.position.y - this.position.y + + var move = { + x: Math.sign(dx || DATA.FRAME.WIDTH/2 - this.position.x), + y: Math.sign(dy || DATA.FRAME.HEIGHT/2 - this.position.y) + } + + if (this.outOfBounds(move)) { + if (this.outOfBounds({x: move.x, y: 0})) { + move.x = -move.x + } + if (this.outOfBounds({x: 0, y: move.y})) { + move.y = -move.y + } + } + + return move + + } + }, + MOTHER_SPIDER: { + sprite: DATA.SPRITES.MONSTERS.MOTHER_SPIDER, + color: DATA.COLORS.GREEN, + health: 5, + strength: 0, + turnCounter: function() { + this.phase = !this.phase + this.turnsUntilSpawn = (this.turnsUntilSpawn || 4) - 1 + this.childCount = this.childCount || 0 + + if (this.turnsUntilSpawn <= 0 && this.childCount < 3) { + var child = new Monster(this.game, { + protomonster: MONSTERS.NORMAL_SPIDER, + position: {x: this.position.x, y: this.position.y}, + }) + var mother = this + child.onDeath = function() { + mother.childCount -= 1 + this.game.wave.killcount += 1 + } + this.game.monsters.push(child) + this.childCount += 1 + } + }, + movement: function () { + + var dx = this.game.adventurer.position.x - this.position.x + var dy = this.game.adventurer.position.y - this.position.y + + if (this.outOfBounds()) { + dx = 0 + dy = 0 + } + + var move = { + x: Math.sign(-dx || DATA.FRAME.WIDTH/2 - this.position.x), + y: Math.sign(-dy || DATA.FRAME.HEIGHT/2 - this.position.y) + } + + if (this.outOfBounds(move)) { + if (this.outOfBounds({x: move.x, y: 0})) { + move.x = -move.x + } + if (this.outOfBounds({x: 0, y: move.y})) { + move.y = -move.y + } + } + + return move + + } + }, + WEB: { + sprite: DATA.SPRITES.TERRAIN.WEB, + color: DATA.COLORS.WHITE, + opacity: 0.5, + isTerrain: true, + health: 10, + stack: -100, + strength: 0, + movement: function() {}, + hasAlternateSprite: false, + turnCounter: function() { + this.phase = true + }, + grabCounter: function() { + this.turnCount = this.turnCount || 0 + if(this.game.adventurer.grabCount == 0 && this.turnCount == 0) { + this.turnCount += 1 + this.game.adventurer.grabCount += 1 + this.game.adventurer.grabMonster = this + } + } + }, + WEB_SPIDER: { + sprite: DATA.SPRITES.MONSTERS.SPIDER, + color: DATA.COLORS.BLUE, + health: 5, + strength: 0, + turnCounter: function() { + this.phase = !this.phase + this.turnsUntilSpawn = (this.turnsUntilSpawn || 4) - 1 + if (this.turnsUntilSpawn <= 0) { + this.game.monsters.push(new Monster(this.game, { + protomonster: MONSTERS.WEB, + position: {x: this.position.x, y: this.position.y}, + })) + } + }, + movement: function () { + + var dx = this.game.adventurer.position.x - this.position.x + var dy = this.game.adventurer.position.y - this.position.y + + var move = { + x: Math.sign(dx || DATA.FRAME.WIDTH/2 - this.position.x), + y: Math.sign(dy || DATA.FRAME.HEIGHT/2 - this.position.y) + } + + if (this.outOfBounds(move)) { + if (this.outOfBounds({x: move.x, y: 0})) { + move.x = -move.x + } + if (this.outOfBounds({x: 0, y: move.y})) { + move.y = -move.y + } + } + + return move + + } + }, } diff --git a/source/scripts/model/Adventurer.js b/source/scripts/model/Adventurer.js index 710b465..ca89112 100644 --- a/source/scripts/model/Adventurer.js +++ b/source/scripts/model/Adventurer.js @@ -23,9 +23,9 @@ export default class Adventurer { this.maxhealth = 3 this.health = this.maxhealth - + this.wave = 0 - + this.grabCount = 0 this.grabMonster = null } @@ -58,7 +58,7 @@ export default class Adventurer { this.animation = false var didSomething = false - + // collision with room if(this.position.x + movement.x < DATA.FRAME.WIDTH * 0 || this.position.x + movement.x >= DATA.FRAME.WIDTH * 1) { @@ -75,20 +75,20 @@ export default class Adventurer { console.log("!!") movement.y = 0 } - + this.bloodscreen = false if(this.grabCount == 0) { // collision with monsters this.game.monsters.forEach((monster) => { - if(!monster.isDead) { + if(!monster.isDead && !monster.isTerrain) { if(this.position.x + movement.x == monster.position.x && this.position.y + movement.y == monster.position.y) { monster.handleAttack(1) - + didSomething = true - + if(movement.x < 0 && movement.y == 0) { this.animation = "attack-westwards" } else if(movement.x > 0 && movement.y == 0) { @@ -124,9 +124,10 @@ export default class Adventurer { movement.x = 0 movement.y = 0 } + console.log(this.game.tiles[key]) } } - + // translation this.position.x += movement.x this.position.y += movement.y @@ -155,7 +156,7 @@ export default class Adventurer { this.grabCount = this.grabCount - 1 this.grabMonster.handleAttack(1) } - + // signaling if(didSomething || movement.x != 0 || movement.y != 0) { this.game.onAction() diff --git a/source/scripts/model/Monster.js b/source/scripts/model/Monster.js index ea3e497..ecaf7eb 100644 --- a/source/scripts/model/Monster.js +++ b/source/scripts/model/Monster.js @@ -10,8 +10,17 @@ export default class Monster { this.key = "monster" + "-" + ShortID.generate() this.color = monster.protomonster.color || DATA.COLORS.PINK this.basesprite = monster.protomonster.sprite || DATA.SPRITES.MONSTERS.SLIME - this.sprite = this.pickSprite() this.isSpawned = true + this.opacity = monster.protomonster.opacity || 1 + this.isDead = monster.protomonster.isDead || false + this.stack = monster.protomonster.stack || 0 + if (monster.protomonster.hasAlternateSprite == undefined) { + this.hasAlternateSprite = true + } else { + this.hasAlternateSprite = monster.protomonster.hasAlternateSprite + } + this.sprite = this.pickSprite() + this.isTerrain = monster.protomonster.isTerrain || false this.game = game @@ -38,13 +47,19 @@ export default class Monster { this.health = monster.protomonster.health || 1 - + if (monster.protomonster.onSpawn) { + monster.protomonster.onSpawn() + } } pickSprite() { - if(this.phase == true) { - return this.basesprite.ALPHA + if (this.hasAlternateSprite) { + if(this.phase == true) { + return this.basesprite.ALPHA + } else { + return this.basesprite.OMEGA + } } else { - return this.basesprite.OMEGA + return this.basesprite } } onAction() { @@ -63,7 +78,7 @@ export default class Monster { movement = movement || {} movement.x = movement.x || 0 movement.y = movement.y || 0 - + // collision with the camera if(this.position.x + movement.x < DATA.FRAME.WIDTH * 0 || this.position.x + movement.x >= DATA.FRAME.WIDTH * 1) { @@ -90,28 +105,40 @@ export default class Monster { // collsiion with adventurer if(this.position.x + movement.x == this.game.adventurer.position.x && this.position.y + movement.y == this.game.adventurer.position.y) { - this.game.adventurer.beAttacked() - this.grabCounter() - if(movement.x < 0 && movement.y == 0) { - this.animation = "attack-westwards" - } else if(movement.x > 0 && movement.y == 0) { - this.animation = "attack-eastwards" - } else if(movement.x == 0 && movement.y < 0) { - this.animation = "attack-northwards" - } else if(movement.x == 0 && movement.y > 0) { - this.animation = "attack-southwards" + if (!this.isTerrain) { + this.game.adventurer.beAttacked() } - this.game.add("effects", new Effect({ - sprite: new AnimatedSprite({ - images: DATA.SPRITES.EFFECTS.SLASH, - isLoop: false, - timing: 20, - }), - position: { - x: this.position.x + movement.x, - y: this.position.y + movement.y, + this.grabCounter() + if (!this.isTerrain) { + if(movement.x < 0 && movement.y == 0) { + this.animation = "attack-westwards" + } else if(movement.x > 0 && movement.y == 0) { + this.animation = "attack-eastwards" + } else if(movement.x == 0 && movement.y < 0) { + this.animation = "attack-northwards" + } else if(movement.x == 0 && movement.y > 0) { + this.animation = "attack-southwards" + } else if(movement.x > 0 && movement.y > 0) { + this.animation = "attack-southeastwards" + } else if(movement.x > 0 && movement.y < 0) { + this.animation = "attack-northeastwards" + } else if(movement.x < 0 && movement.y > 0) { + this.animation = "attack-southeastwards" + } else if(movement.x < 0 && movement.y < 0) { + this.animation = "attack-northwestwards" } - })) + this.game.add("effects", new Effect({ + sprite: new AnimatedSprite({ + images: DATA.SPRITES.EFFECTS.SLASH, + isLoop: false, + timing: 20, + }), + position: { + x: this.position.x + movement.x, + y: this.position.y + movement.y, + } + })) + } movement.x = 0 movement.y = 0 } @@ -164,6 +191,7 @@ export default class Monster { return temp } outOfBounds(positionVector) { + positionVector = positionVector || {x: 0, y: 0} if (positionVector.x + this.position.x < 0) { return true } diff --git a/source/scripts/model/MonsterWave.js b/source/scripts/model/MonsterWave.js index 75b3e27..d18e064 100644 --- a/source/scripts/model/MonsterWave.js +++ b/source/scripts/model/MonsterWave.js @@ -13,6 +13,7 @@ // then, enjoy the waves of monsters. :] import DATA from "scripts/data" +import MONSTERS from "scripts/data/monsters.js" import Monster from "scripts/model/Monster.js" export default class MonsterWave { @@ -30,7 +31,7 @@ export default class MonsterWave { if(this.killcount === undefined) { this.killcount = 10 } - + this.message = wave.message this.specialMessage = wave.specialMessage this.isRespawnRoom = wave.isRespawnRoom @@ -40,7 +41,7 @@ export default class MonsterWave { if(this.monsters.length == 0) { return } - + // If attached to a game... if(this.game != undefined) { // If there are still monsters left to kill... @@ -95,7 +96,7 @@ export default class MonsterWave { } getCapacity() { return this.game.monsters.reduce((capacity, monster) => { - return capacity + (monster.isDead ? 0 : 1) + return capacity + ((monster.isDead || monster.isTerrain) ? 0 : 1) }, 0) } get capacity() { diff --git a/source/scripts/tests/SpiderTest.js b/source/scripts/tests/SpiderTest.js new file mode 100644 index 0000000..381df46 --- /dev/null +++ b/source/scripts/tests/SpiderTest.js @@ -0,0 +1,45 @@ +import Expect from "expect.js" + +import Game from "scripts/model/Game.js" + +import MONSTERS from "scripts/data/monsters.js" +import DATA from "scripts/data/index.js" + +export default function SpiderTest() { + + // Normal Spider test + var game1 = new Game({ + adventurer: { + position: {x: 3, y: 3}, + }, + monsters: [ + { + position: {x: 1, y: 1}, + protomonster: MONSTERS.NORMAL_SPIDER + } + ] + }) + + Expect(game1.monsters[0].position).to.be.eql({x: 1,y: 1}) + game1.monsters[0].onAction() + Expect(game1.monsters[0].position).to.be.eql({x: 2,y: 2}) + + + // Mother Spider test + var game2 = new Game({ + adventurer: { + position: {x: 3, y: 3}, + }, + monsters: [ + { + position: {x: 2, y: 2}, + protomonster: MONSTERS.MOTHER_SPIDER + } + ] + }) + + Expect(game2.monsters[0].position).to.be.eql({x: 2,y: 2}) + game2.monsters[0].onAction() + Expect(game2.monsters[0].position).to.be.eql({x: 1,y: 1}) + +}