Skip to content
Browse files

Onslaught2 prototype

  • Loading branch information...
0 parents commit 0ba8e3b85e6e6041720dfd5c163cd81b93e270c5 @geoffb geoffb committed Apr 27, 2012
Showing with 2,535 additions and 0 deletions.
  1. +6 −0 .gitignore
  2. +5 −0 README.markdown
  3. +49 −0 htdocs/index.html
  4. +186 −0 htdocs/lib/game/entities/abstract/base.js
  5. +61 −0 htdocs/lib/game/entities/abstract/hero.js
  6. +104 −0 htdocs/lib/game/entities/abstract/mob.js
  7. +100 −0 htdocs/lib/game/entities/abstract/monster.js
  8. +28 −0 htdocs/lib/game/entities/abstract/power-up.js
  9. +61 −0 htdocs/lib/game/entities/abstract/spawner.js
  10. +66 −0 htdocs/lib/game/entities/abstract/weapon.js
  11. +25 −0 htdocs/lib/game/entities/barrel.js
  12. +50 −0 htdocs/lib/game/entities/bat.js
  13. +27 −0 htdocs/lib/game/entities/bush.js
  14. +30 −0 htdocs/lib/game/entities/coin.js
  15. +60 −0 htdocs/lib/game/entities/cube.js
  16. +21 −0 htdocs/lib/game/entities/food.js
  17. +57 −0 htdocs/lib/game/entities/goblin.js
  18. +42 −0 htdocs/lib/game/entities/heal-point.js
  19. +21 −0 htdocs/lib/game/entities/location.js
  20. +40 −0 htdocs/lib/game/entities/misc/corpse.js
  21. +43 −0 htdocs/lib/game/entities/reticle.js
  22. +24 −0 htdocs/lib/game/entities/save-point.js
  23. +17 −0 htdocs/lib/game/entities/spawn-cave.js
  24. +21 −0 htdocs/lib/game/entities/spawn-invis.js
  25. +16 −0 htdocs/lib/game/entities/spawn-pyramid.js
  26. +20 −0 htdocs/lib/game/entities/torch.js
  27. +35 −0 htdocs/lib/game/entities/warp.js
  28. +21 −0 htdocs/lib/game/entities/weapons/spear.js
  29. +20 −0 htdocs/lib/game/entities/weapons/sword.js
  30. +50 −0 htdocs/lib/game/entities/wizard.js
  31. +15 −0 htdocs/lib/game/entities/xam.js
  32. +112 −0 htdocs/lib/game/levels/ai_test.js
  33. +439 −0 htdocs/lib/game/levels/test.js
  34. +191 −0 htdocs/lib/game/levels/village.js
  35. +241 −0 htdocs/lib/game/main.js
  36. +148 −0 htdocs/lib/math/astar.js
  37. +83 −0 htdocs/lib/math/vector.js
  38. BIN htdocs/media/entities/bat.png
  39. BIN htdocs/media/entities/bat_brown.png
  40. BIN htdocs/media/entities/cube.png
  41. BIN htdocs/media/entities/cyclops.png
  42. BIN htdocs/media/entities/demoblin.png
  43. BIN htdocs/media/entities/dragon.png
  44. BIN htdocs/media/entities/gel.png
  45. BIN htdocs/media/entities/goblin.png
  46. BIN htdocs/media/entities/imp.png
  47. BIN htdocs/media/entities/objects.png
  48. BIN htdocs/media/entities/owlbear.png
  49. BIN htdocs/media/entities/powerups.png
  50. BIN htdocs/media/entities/reticle.png
  51. BIN htdocs/media/entities/sandworm.png
  52. BIN htdocs/media/entities/sandworm_submerged.png
  53. BIN htdocs/media/entities/skull.png
  54. BIN htdocs/media/entities/skull_big.png
  55. BIN htdocs/media/entities/spawner_alpha.png
  56. BIN htdocs/media/entities/spawner_alpha_03.png
  57. BIN htdocs/media/entities/weapons.png
  58. BIN htdocs/media/entities/wizard.png
  59. BIN htdocs/media/entities/xam.png
  60. BIN htdocs/media/music/cave.mp3
  61. BIN htdocs/media/music/forest.mp3
  62. BIN htdocs/media/music/forest.ogg
  63. BIN htdocs/media/music/normal_battle.mp3
  64. BIN htdocs/media/sounds/bat_damage.mp3
  65. BIN htdocs/media/sounds/bat_damage.ogg
  66. BIN htdocs/media/sounds/bat_death.mp3
  67. BIN htdocs/media/sounds/bat_death.ogg
  68. BIN htdocs/media/sounds/cube_damage.mp3
  69. BIN htdocs/media/sounds/cube_damage.ogg
  70. BIN htdocs/media/sounds/cube_death.mp3
  71. BIN htdocs/media/sounds/cube_death.ogg
  72. BIN htdocs/media/sounds/cyclops_attacks.mp3
  73. BIN htdocs/media/sounds/cyclops_damage.mp3
  74. BIN htdocs/media/sounds/cyclops_death.mp3
  75. BIN htdocs/media/sounds/goblin_attacks.mp3
  76. BIN htdocs/media/sounds/goblin_attacks.ogg
  77. BIN htdocs/media/sounds/goblin_damage.mp3
  78. BIN htdocs/media/sounds/goblin_damage.ogg
  79. BIN htdocs/media/sounds/goblin_death.mp3
  80. BIN htdocs/media/sounds/goblin_death.ogg
  81. BIN htdocs/media/sounds/hero_attacks.mp3
  82. BIN htdocs/media/sounds/hero_attacks.ogg
  83. BIN htdocs/media/sounds/hero_damage.mp3
  84. BIN htdocs/media/sounds/hero_damage.ogg
  85. BIN htdocs/media/sounds/hero_death.mp3
  86. BIN htdocs/media/sounds/hero_death.ogg
  87. BIN htdocs/media/sounds/pickup_coin.mp3
  88. BIN htdocs/media/sounds/pickup_coin.ogg
  89. BIN htdocs/media/sounds/pickup_food.mp3
  90. BIN htdocs/media/tilesets/cave.png
  91. BIN htdocs/media/tilesets/collision.png
  92. BIN htdocs/media/tilesets/forest.png
  93. BIN htdocs/media/tilesets/tileset.png
  94. BIN htdocs/media/tilesets/village.png
6 .gitignore
@@ -0,0 +1,6 @@
+.DS_Store
+build/
+htdocs/tools
+htdocs/lib/impact
+htdocs/lib/weltmeister
+htdocs/weltmeister.html
5 README.markdown
@@ -0,0 +1,5 @@
+# Onslaught2 Prototype
+
+Built using [ImpactJS][1] 1.18a.
+
+[1]: http://impactjs.com/
49 htdocs/index.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <title>Onslaught2 Prototype</title>
+ <meta charset="utf-8">
+ <style>
+ html,body {
+ background-color: #000;
+ color: #fff;
+ font-family: helvetica, arial, sans-serif;
+ margin: 0;
+ padding: 0;
+ font-size: 12pt;
+ }
+ #canvas {
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ margin: auto;
+ border: 1px solid #555;
+ }
+ </style>
+
+ <script src="lib/impact/impact.js"></script>
+ <script src="lib/game/main.js"></script>
+
+ <script>
+ // Suspend/resume ImpactJS on blur/focus
+ window.addEventListener("blur", function () {
+ if (ig.system) {
+ ig.music.stop();
+ ig.system.stopRunLoop();
+ }
+ }, false);
+ window.addEventListener("focus", function () {
+ if (ig.system) {
+ ig.music.play();
+ ig.system.startRunLoop();
+ }
+ }, false);
+ </script>
+
+</head>
+<body>
+ <canvas id="canvas"></canvas>
+</body>
+</html>
186 htdocs/lib/game/entities/abstract/base.js
@@ -0,0 +1,186 @@
+ig.module(
+ "game.entities.abstract.base"
+)
+.requires(
+ "impact.entity",
+ "game.entities.misc.corpse"
+)
+.defines(function () {
+
+EntityBase = ig.Entity.extend({
+
+ // ImpactJS properties
+ size: {x: 16, y: 16},
+ type: ig.Entity.TYPE.NONE,
+ collides: ig.Entity.COLLIDES.FIXED,
+ health: 1,
+ zIndex: 1,
+ // Custom properties
+ sounds: {},
+ states: [],
+
+ attackTimer: new ig.Timer(0),
+
+ alpha: 1,
+
+ pushState: function (state, duration) {
+ if (!this.hasState(state)) {
+ this.states.push({
+ type: state,
+ timer: new ig.Timer(duration)
+ });
+ }
+ },
+
+ hasState: function (type) {
+ for (var i = 0, j = this.states.length; i < j; ++i) {
+ if (this.states[i].type == type) {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ updateStates: function () {
+ var indices = [];
+ for (var i = 0, j = this.states.length; i < j; ++i) {
+ var state = this.states[i];
+ if (state.timer.delta() >= 0) {
+ // This state has expired
+ indices.push(i);
+ }
+ }
+ // Remove expired states
+ for (var i = 0, j = indices.length; i < j; ++i) {
+ this.states.splice(i, 1);
+ }
+ },
+
+ getStateTimer: function (type) {
+ for (var i = 0, j = this.states.length; i < j; ++i) {
+ if (this.states[i].type == type) {
+ return this.states[i].timer;
+ }
+ }
+ // TODO: Good idea to return 0?
+ return false;
+ },
+
+ getStateAnim: function () {
+ var state = "idle";
+ if (this.vel.x != 0 || this.vel.y != 0) {
+ state = "move";
+ }
+ if (this.hasState(EntityBase.STATES.PAIN)) {
+ state = "pain";
+ }
+ return state;
+ },
+
+ setAnim: function (anim, flip) {
+ flip = flip || false;
+ if (this.anims[anim] && this.currentAnim != this.anims[anim]) {
+ this.currentAnim = this.anims[anim].rewind();
+ }
+ this.currentAnim.flip.x = flip;
+ },
+
+ updateAnim: function () {
+ this.setAnim(this.getStateAnim());
+ },
+
+ update: function () {
+ this.updateStates();
+ this.updateAnim();
+ if (this.currentAnim) {
+ this.currentAnim.alpha = 1;
+ var t = this.getStateTimer(EntityBase.STATES.SPAWNING);
+ if (t) {
+ var alpha = (1 - (t.delta() / -t.target));
+ this.currentAnim.alpha = alpha.limit(0, 1);
+ }
+ t = this.getStateTimer(EntityBase.STATES.INVINCIBLE);
+ if (t) {
+ var alpha = Math.sin(20 * ig.Timer.time).map(-1, 1, 0.1, 1);
+ this.currentAnim.alpha = alpha.limit(0, 1);
+ }
+ }
+ this.parent();
+ },
+
+ triggerSound: function (sound) {
+ if (this.sounds[sound]) {
+ this.sounds[sound].play();
+ }
+ },
+
+ receiveDamage: function (amount, from) {
+ if (this.hasState(EntityBase.STATES.INVINCIBLE)) {
+ return;
+ }
+ this.parent(amount, from);
+ if (this.health <= 0) {
+ this.triggerSound("death");
+ this.spawnCorpse();
+ } else {
+ this.pushState(EntityBase.STATES.PAIN, 0.125);
+ this.triggerSound("damage");
+ }
+ },
+
+ spawnCorpse: function () {
+ var pos = {
+ x: (this.pos.x - this.offset.x),
+ y: (this.pos.y - this.offset.y)
+ };
+ var e = ig.game.spawnEntity(EntityCorpse, pos.x, pos.y, {
+ animSheet: this.animSheet,
+ size: {
+ x: (this.size.x + this.offset.x),
+ y: (this.size.y + this.offset.y)
+ },
+ frames: [24, 25, 26]
+ });
+ },
+
+ spawn: function (type) {
+ var check = ig.Entity.TYPE.NONE;
+ if (this.type == ig.Entity.TYPE.A) {
+ check = ig.Entity.TYPE.B;
+ } else if (this.type == ig.Entity.TYPE.B) {
+ check = ig.Entity.TYPE.A;
+ }
+ var pos = {
+ x: (this.pos.x + (this.size.x / 2)),
+ y: (this.pos.y + (this.size.y / 2))
+ };
+ var e = ig.game.spawnEntity(type, pos.x, pos.y, {
+ parent: this,
+ type: this.type,
+ checkAgainst: check,
+ heading: this.heading
+ });
+ e.pos.x -= (e.size.x / 2);
+ e.pos.y -= (e.size.y / 2);
+ e.pos.x += (e.vel.x * ig.system.tick * 2);
+ e.pos.y += (e.vel.y * ig.system.tick * 2);
+ },
+
+ attack: function () {
+ if (this.attackTimer.delta() >= 0) {
+ // TODO: Assign weapons to specific entities
+ this.spawn(EntitySword);
+ this.triggerSound("attack");
+ this.attackTimer.set(0.25);
+ }
+ }
+
+});
+
+EntityBase.STATES = {
+ PAIN: 0,
+ SPAWNING: 1,
+ INVINCIBLE: 2
+};
+
+});
61 htdocs/lib/game/entities/abstract/hero.js
@@ -0,0 +1,61 @@
+ig.module(
+ "game.entities.abstract.hero"
+)
+.requires(
+ "game.entities.abstract.mob"
+)
+.defines(function () {
+
+EntityHero = EntityMob.extend({
+
+ type: ig.Entity.TYPE.A,
+ health: 100,
+
+ sounds: {
+ attack: new ig.Sound("media/sounds/hero_attacks.*"),
+ damage: new ig.Sound("media/sounds/hero_damage.*"),
+ death: new ig.Sound("media/sounds/hero_death.*")
+ },
+
+ gold: 0,
+
+ update: function () {
+
+ if (ig.input.state("left")) {
+ this.vel.x = -75;
+ } else if (ig.input.state("right")) {
+ this.vel.x = 75;
+ } else {
+ this.vel.x = 0;
+ }
+
+ if (ig.input.state("up")) {
+ this.vel.y = -75;
+ } else if (ig.input.state("down")) {
+ this.vel.y = 75;
+ } else {
+ this.vel.y = 0;
+ }
+
+ this.parent();
+
+ if (ig.input.state("shoot")) {
+ var reticle = ig.game.getEntitiesByType(EntityReticle)[0];
+ var r = new Vector(reticle.pos).add(new Vector(reticle.size).scale(0.5));
+ var m = new Vector(this.pos).add(new Vector(this.size).scale(0.5));
+ this.heading = r.subtract(m).normalize();
+ this.attack();
+ }
+
+ },
+
+ receiveDamage: function (damage, from) {
+ this.parent(damage, from);
+ if (!this.hasState(EntityBase.STATES.INVINCIBLE)) {
+ this.pushState(EntityBase.STATES.INVINCIBLE, 2.5);
+ }
+ }
+
+});
+
+});
104 htdocs/lib/game/entities/abstract/mob.js
@@ -0,0 +1,104 @@
+ig.module(
+ "game.entities.abstract.mob"
+)
+.requires(
+ "game.entities.abstract.base",
+ "math.vector"
+)
+.defines(function () {
+
+EntityMob = EntityBase.extend({
+
+ collides: ig.Entity.COLLIDES.PASSIVE,
+ size: {x: 12, y: 8},
+ offset: {x: 2, y: 8},
+ zIndex: 2,
+
+ heading: new Vector(0, 1),
+ waypoints: null,
+
+ init: function (x, y, settings) {
+ this.parent(x, y, settings);
+ this.initAnimation();
+ },
+
+ initAnimation: function () {
+
+ var idleDelay = 0.4;
+ var moveDelay = 0.25;
+
+ this.addAnim("idleDown", idleDelay, [0, 1]);
+ this.addAnim("idleUp", idleDelay, [4, 5]);
+ this.addAnim("idleLeft", idleDelay, [8, 9]);
+
+ this.addAnim("moveDown", moveDelay, [0, 1]);
+ this.addAnim("moveUp", moveDelay, [4, 5]);
+ this.addAnim("moveLeft", moveDelay, [8, 9]);
+
+ this.addAnim("painDown", moveDelay, [12, 13]);
+ this.addAnim("painUp", moveDelay, [16, 17]);
+ this.addAnim("painLeft", moveDelay, [20, 21]);
+
+ },
+
+ updateAnim: function () {
+
+ var dir;
+ var flip = false;
+ var h = this.heading;
+
+ dir = "Down";
+
+ if (h.y < 0) {
+ dir = "Up";
+ } else if (h.y > 0) {
+ dir = "Down";
+ }
+
+ if (h.x < 0) {
+ if (h.x < h.y) {
+ dir = "Left";
+ }
+ } else if (h.x > 0) {
+ if (h.x > h.y) {
+ dir = "Left";
+ flip = true;
+ }
+ }
+
+ var state = this.getStateAnim();
+ this.setAnim(state + dir, flip);
+
+ },
+
+ update: function () {
+
+ // Handle waypoints
+ if (this.waypoints !== null) {
+ var point = new Vector().set(this.waypoints[0]);
+ var pos = new Vector(this.pos).subtract(this.offset);
+ var distance = point.clone().subtract(pos);
+ if (distance.getLength() < 2) {
+ // Snap to waypoint and remove it
+ this.pos.x = (point.x + this.offset.x - 1);
+ this.pos.y = (point.y + this.offset.y - 1);
+ this.waypoints.shift();
+ } else {
+ distance.normalize();
+ this.vel.x = (this.maxVel.x * distance.x);
+ this.vel.y = (this.maxVel.y * distance.y);
+ }
+ }
+
+ // Update heading based on velocity
+ if (this.vel.x !== 0 || this.vel.y !== 0) {
+ this.heading.set(this.vel).normalize();
+ }
+
+ this.parent();
+
+ }
+
+});
+
+});
100 htdocs/lib/game/entities/abstract/monster.js
@@ -0,0 +1,100 @@
+ig.module(
+ "game.entities.abstract.monster"
+)
+.requires(
+ "game.entities.abstract.mob",
+ "math.vector"
+)
+.defines(function () {
+
+EntityMonster = EntityMob.extend({
+
+ type: ig.Entity.TYPE.B,
+ checkAgainst: ig.Entity.TYPE.A,
+
+ damage: 1,
+
+ // Phases
+ phases: {},
+ currentPhase: null,
+ phaseTimer: null,
+
+ check: function (other) {
+ other.receiveDamage(this.damage, this);
+ },
+
+ handleMovementTrace: function (res) {
+ // Change direction when a wall is it
+ if (res.collision.x || res.collision.y) {
+ if (res.collision.x) {
+ this.vel.x *= -1;
+ }
+ if (res.collision.y) {
+ this.vel.y *= -1;
+ }
+ }
+ this.pos = res.pos;
+ },
+
+ moveRandom: function () {
+ var r = Math.random().map(0, 1, 0, Math.PI * 2);
+ var v = Vector.fromAngle(r);
+ this.vel = {
+ x: (this.maxVel.x * v.x),
+ y: (this.maxVel.y * v.y)
+ };
+ },
+
+ update: function () {
+ var phase = this.currentPhase;
+ if (phase != null) {
+ if (phase.update) {
+ phase.update.call(this);
+ }
+ if (
+ this.phaseTimer != null
+ && this.phaseTimer.delta() >= 0
+ && phase.end
+ ) {
+ phase.end.call(this);
+ }
+ }
+ this.parent();
+ },
+
+ addPhase: function (id, phase) {
+ this.phases[id] = phase;
+ if (this.currentPhase == null) {
+ this.gotoPhase(id);
+ }
+ },
+
+ gotoPhase: function (id) {
+ var phase = this.currentPhase = this.phases[id];
+ if (phase.init) {
+ // Init the new phase
+ phase.init.call(this);
+ }
+ if (phase.duration) {
+ if (typeof phase.duration == "object") {
+ // Randomize duration within the given range
+ var duration = Math.random().map(
+ 0, 1,
+ phase.duration.min,
+ phase.duration.max
+ );
+ } else {
+ var duration = phase.duration;
+ }
+ this.phaseTimer = new ig.Timer(duration);
+ } else {
+ // Phase has no timed duration; it's up to the
+ // specific phase code to determine it's exit
+ // conditions and call .gotoPhase().
+ this.phaseTimer = null;
+ }
+ }
+
+});
+
+});
28 htdocs/lib/game/entities/abstract/power-up.js
@@ -0,0 +1,28 @@
+ig.module(
+ "game.entities.abstract.power-up"
+)
+.requires(
+ "impact.entity"
+)
+.defines(function () {
+
+EntityPowerUp = ig.Entity.extend({
+
+ type: ig.Entity.TYPE.NONE,
+ checkAgainst: ig.Entity.TYPE.A,
+ size: {x: 16, y: 16},
+ zIndex: -1,
+
+ check: function (other) {
+ if (other instanceof EntityXam) {
+ this.affect(other);
+ }
+ },
+
+ affect: function (other) {
+ // Affect the player somehow
+ }
+
+});
+
+});
61 htdocs/lib/game/entities/abstract/spawner.js
@@ -0,0 +1,61 @@
+ig.module(
+ "game.entities.abstract.spawner"
+)
+.requires(
+ "game.entities.abstract.base"
+)
+.defines(function () {
+
+EntitySpawner = EntityBase.extend({
+
+ type: ig.Entity.TYPE.B,
+ checkAgainst: ig.Entity.TYPE.BOTH,
+ collides: ig.Entity.COLLIDES.FIXED,
+ health: 10,
+ zIndex: -1,
+
+ // Set these properties via Weltmeister to control spawn behavior:
+ spawnInterval: 5,
+ spawnTimer: null,
+ spawnEntity: null,
+
+ init: function (x, y, settings) {
+ this.parent(x, y, settings);
+ this.spawnTimer = new ig.Timer(this.spawnInterval);
+ if (this.animSheet) {
+ this.addAnim("idle", 1, [0]);
+ this.addAnim("pain", 1, [5]);
+ }
+ },
+
+ update: function () {
+ this.parent();
+ if (this.spawnEntity != null && this.spawnTimer.delta() >= 0) {
+ var e = ig.game.spawnEntity(
+ this.spawnEntity,
+ this.pos.x,
+ this.pos.y
+ );
+ e.pushState(EntityBase.STATES.SPAWNING, 0.3);
+ this.spawnTimer.reset();
+ }
+ },
+
+ spawnCorpse: function () {
+ var pos = {
+ x: (this.pos.x - this.offset.x),
+ y: (this.pos.y - this.offset.y)
+ };
+ var e = ig.game.spawnEntity(EntityCorpse, pos.x, pos.y, {
+ animSheet: this.animSheet,
+ size: {
+ x: (this.size.x + this.offset.x),
+ y: (this.size.y + this.offset.y)
+ },
+ frames: [1, 2, 3]
+ });
+ }
+
+});
+
+});
66 htdocs/lib/game/entities/abstract/weapon.js
@@ -0,0 +1,66 @@
+ig.module(
+ "game.entities.abstract.weapon"
+)
+.requires(
+ "impact.entity"
+)
+.defines(function () {
+
+EntityWeapon = ig.Entity.extend({
+
+ type: ig.Entity.TYPE.NONE,
+ checkAgainst: ig.Entity.TYPE.NONE,
+ collides: ig.Entity.COLLIDES.PASSIVE,
+ size: {x: 8, y: 8},
+ offset: {x: 4, y: 4},
+ maxVel: {x: 150, y: 150},
+ animSheet: new ig.AnimationSheet("media/entities/weapons.png", 16, 16),
+ zIndex: 1,
+
+ damage: 1,
+
+ init: function (x, y, settings) {
+ this.parent(x, y, settings);
+ if (settings.heading) {
+ this.vel = {
+ x: settings.heading.x * this.maxVel.x,
+ y: settings.heading.y * this.maxVel.y
+ };
+ }
+ if (this.currentAnim) {
+ this.currentAnim.angle = this.heading.getAngle();
+ }
+ },
+
+ handleMovementTrace: function (res) {
+ if (res.collision.x || res.collision.y) {
+ if (
+ (res.collision.x && res.tile.x == 2)
+ || (res.collision.y && res.tile.y == 2)
+ ) {
+ // Keep moving
+ this.pos.x += this.vel.x * ig.system.tick;
+ this.pos.y += this.vel.y * ig.system.tick;
+ return;
+ }
+ this.kill();
+ }
+ this.parent(res);
+ },
+
+ check: function (other) {
+ other.receiveDamage(this.damage, this);
+ this.kill();
+ },
+
+ collideWith: function (other, axis) {
+ if (other.type != this.type) {
+ other.receiveDamage(this.damage, this);
+ this.kill();
+ }
+ this.parent(other, axis);
+ }
+
+});
+
+});
25 htdocs/lib/game/entities/barrel.js
@@ -0,0 +1,25 @@
+ig.module(
+ "game.entities.barrel"
+)
+.requires(
+ "game.entities.abstract.base"
+)
+.defines(function () {
+
+EntityBarrel = EntityBase.extend({
+
+ animSheet: new ig.AnimationSheet("media/tilesets/tileset.png", 16, 16),
+
+ sounds: {
+ damage: new ig.Sound("media/sounds/goblin_damage.*"),
+ death: new ig.Sound("media/sounds/goblin_death.*")
+ },
+
+ init: function (x, y, settings) {
+ this.parent(x, y, settings);
+ this.addAnim("idle", 1, [20]);
+ }
+
+});
+
+});
50 htdocs/lib/game/entities/bat.js
@@ -0,0 +1,50 @@
+ig.module(
+ "game.entities.bat"
+)
+.requires(
+ "game.entities.abstract.monster"
+)
+.defines(function () {
+
+EntityBat = EntityMonster.extend({
+
+ health: 1,
+ maxVel: {x: 50, y: 50},
+
+ animSheet: new ig.AnimationSheet("media/entities/bat.png", 16, 16),
+
+ sounds: {
+ damage: new ig.Sound("media/sounds/bat_damage.*"),
+ death: new ig.Sound("media/sounds/bat_death.*")
+ },
+
+ moveChangeTimer: null,
+
+ init: function (x, y, settings) {
+ this.parent(x, y, settings);
+ var delay = Math.random().map(0, 1, 1.5, 3);
+ this.moveChangeTimer = new ig.Timer(delay);
+ this.moveRandom();
+ },
+
+ update: function () {
+
+ if (this.moveChangeTimer.delta() >= 0) {
+ this.moveRandom();
+ this.moveChangeTimer.reset();
+ }
+
+ this.parent();
+
+ },
+
+ handleMovementTrace: function (res) {
+ if (res.collision.x || res.collision.y) {
+ this.moveChangeTimer.reset();
+ }
+ this.parent(res);
+ }
+
+});
+
+});
27 htdocs/lib/game/entities/bush.js
@@ -0,0 +1,27 @@
+ig.module(
+ "game.entities.bush"
+)
+.requires(
+ "game.entities.abstract.base"
+)
+.defines(function () {
+
+EntityBush = EntityBase.extend({
+
+ zIndex: 0,
+ collides: ig.Entity.COLLIDES.NEVER,
+ animSheet: new ig.AnimationSheet("media/entities/objects.png", 16, 16),
+
+ sounds: {
+ damage: new ig.Sound("media/sounds/goblin_damage.*"),
+ death: new ig.Sound("media/sounds/goblin_death.*")
+ },
+
+ init: function (x, y, settings) {
+ this.parent(x, y, settings);
+ this.addAnim("idle", 1, [63]);
+ }
+
+});
+
+});
30 htdocs/lib/game/entities/coin.js
@@ -0,0 +1,30 @@
+ig.module(
+ "game.entities.coin"
+)
+.requires(
+ "game.entities.abstract.power-up"
+)
+.defines(function () {
+
+EntityCoin = EntityPowerUp.extend({
+
+ animSheet: new ig.AnimationSheet("media/entities/powerups.png", 16, 16),
+ pickupSound: new ig.Sound("media/sounds/pickup_coin.*"),
+
+ goldValue: 10,
+
+ init: function (x, y, settings) {
+ this.parent(x, y, settings);
+ this.addAnim("idle", 0.15, [21, 22, 23, 24, 25, 26, 23, 27]);
+ this.pickupSound.volume = 0.1;
+ },
+
+ affect: function (hero) {
+ hero.gold += this.goldValue;
+ this.pickupSound.play();
+ this.kill();
+ }
+
+});
+
+});
60 htdocs/lib/game/entities/cube.js
@@ -0,0 +1,60 @@
+ig.module(
+ "game.entities.cube"
+)
+.requires(
+ "game.entities.abstract.monster"
+)
+.defines(function () {
+
+EntityCube = EntityMonster.extend({
+
+ health: 500,
+ maxVel: {x: 50, y: 50},
+
+ size: {x: 24, y: 24},
+ offset: {x: 4, y: 6},
+ animSheet: new ig.AnimationSheet("media/entities/cube.png", 32, 32),
+
+ sounds: {
+ damage: new ig.Sound("media/sounds/cube_damage.*"),
+ death: new ig.Sound("media/sounds/cube_death.*")
+ },
+
+ init: function (x, y, settings) {
+ this.parent(x, y, settings);
+
+ this.addPhase("moveLeft", {
+ duration: 2,
+ init: function () {
+ this.vel = {x: -this.maxVel.x, y: 0};
+ },
+ end: function () {
+ this.gotoPhase("moveRight");
+ }
+ });
+
+ this.addPhase("moveRight", {
+ duration: 2,
+ init: function () {
+ this.vel = {x: this.maxVel.x, y: 0};
+ },
+ end: function () {
+ this.gotoPhase("moveDown");
+ }
+ });
+
+ this.addPhase("moveDown", {
+ duration: 2,
+ init: function () {
+ this.vel = {x: 0, y: this.maxVel.y};
+ },
+ end: function () {
+ this.gotoPhase("moveLeft");
+ }
+ });
+
+ }
+
+});
+
+});
21 htdocs/lib/game/entities/food.js
@@ -0,0 +1,21 @@
+ig.module(
+ "game.entities.food"
+)
+.requires(
+ "game.entities.abstract.power-up"
+)
+.defines(function () {
+
+EntityFood = EntityPowerUp.extend({
+
+ pickupSound: new ig.Sound("media/sounds/pickup_food.*"),
+
+ check: function (other) {
+ other.health += 10;
+ this.pickupSound.play();
+ this.kill();
+ }
+
+});
+
+});
57 htdocs/lib/game/entities/goblin.js
@@ -0,0 +1,57 @@
+ig.module(
+ "game.entities.goblin"
+)
+.requires(
+ "game.entities.abstract.monster"
+)
+.defines(function () {
+
+EntityGoblin = EntityMonster.extend({
+
+ health: 10,
+ maxVel: {x: 50, y: 50},
+
+ animSheet: new ig.AnimationSheet("media/entities/goblin.png", 16, 16),
+
+ sounds: {
+ attack: new ig.Sound("media/sounds/goblin_attacks.*"),
+ damage: new ig.Sound("media/sounds/goblin_damage.*"),
+ death: new ig.Sound("media/sounds/goblin_death.*")
+ },
+
+ pathTimer: null,
+
+ init: function (x, y, settings) {
+ this.parent(x, y, settings);
+ this.pathTimer = new ig.Timer(Math.random().map(0, 1, 0.5, 1.5));
+ },
+
+ update: function () {
+
+ if (!this.hasState(EntityBase.STATES.SPAWNING)) {
+ // TODO: Move this whole AI bit to the EntityMonster object
+ if (this.waypoints == null || this.pathTimer.delta() >= 0) {
+ var player = ig.game.getPlayer();
+ if (player) {
+ var distance = new Vector(this.pos).subtract(player.pos);
+ // TODO: Create a variable for this number, such as "aggroDistance"
+ if (distance.getLength() < 200) {
+ this.waypoints = ig.game.tracePath(this, player);
+ } else {
+ // TODO: Wander or something?
+ this.waypoints = null;
+ this.vel.x = 0;
+ this.vel.y = 0;
+ }
+ }
+ this.pathTimer.reset();
+ }
+ }
+
+ this.parent();
+
+ }
+
+});
+
+});
42 htdocs/lib/game/entities/heal-point.js
@@ -0,0 +1,42 @@
+ig.module(
+ "game.entities.heal-point"
+)
+.requires(
+ "game.entities.abstract.power-up"
+)
+.defines(function () {
+
+EntityHealPoint = EntityPowerUp.extend({
+
+ animSheet: new ig.AnimationSheet("media/entities/powerups.png", 16, 16),
+
+ cooldownTimer: new ig.Timer(),
+ active: true,
+
+ init: function (x, y, settings) {
+ this.parent(x, y, settings);
+ this.addAnim("active", 0.25, [14, 15, 16, 15]);
+ this.addAnim("inactive", 1, [17]);
+ },
+
+ update: function () {
+ if (!this.active && this.cooldownTimer.delta() >= 0) {
+ this.active = true;
+ this.currentAnim = this.anims.active.rewind();
+ }
+ this.parent();
+ },
+
+ affect: function (hero) {
+ if (this.active) {
+ // TODO: Implement: hero.heal(other.maxHealth);
+ hero.health = 100;
+ this.active = false;
+ this.currentAnim = this.anims.inactive;
+ this.cooldownTimer.set(30);
+ }
+ }
+
+});
+
+});
21 htdocs/lib/game/entities/location.js
@@ -0,0 +1,21 @@
+ig.module(
+ "game.entities.location"
+)
+.requires(
+ "impact.entity"
+)
+.defines(function () {
+
+EntityLocation = ig.Entity.extend({
+
+ _wmScalable: true,
+ _wmDrawBox: true,
+ _wmBoxColor: "rgba(0, 255, 0, 0.5)",
+
+ type: ig.Entity.TYPE.NONE,
+ checkAgainst: ig.Entity.TYPE.A,
+ size: {x: 16, y: 16}
+
+});
+
+});
40 htdocs/lib/game/entities/misc/corpse.js
@@ -0,0 +1,40 @@
+ig.module(
+ "game.entities.misc.corpse"
+)
+.requires(
+ "impact.entity"
+)
+.defines(function () {
+
+EntityCorpse = ig.Entity.extend({
+
+ zIndex: 0,
+
+ ttlTimer: null,
+
+ init: function (x, y, settings) {
+ this.parent(x, y, settings);
+ this.addAnim("death", 0.25, settings.frames, true);
+ this.ttlTimer = new ig.Timer(2.5);
+ },
+
+ update: function () {
+
+ this.parent();
+
+ var delta = this.ttlTimer.delta();
+
+ // Fade out during the last second of ttl
+ if (delta >= -1 && delta <= 0) {
+ this.currentAnim.alpha = (delta / -1);
+ }
+
+ if (delta >= 0) {
+ this.kill();
+ }
+
+ }
+
+});
+
+});
43 htdocs/lib/game/entities/reticle.js
@@ -0,0 +1,43 @@
+ig.module(
+ "game.entities.reticle"
+)
+.requires(
+ "impact.entity"
+)
+.defines(function () {
+
+EntityReticle = ig.Entity.extend({
+
+ type: ig.Entity.TYPE.NONE,
+ collides: ig.Entity.COLLIDES.NEVER,
+
+ size: {x: 32, y: 32},
+
+ animSheet: new ig.AnimationSheet("media/entities/reticle.png", 32, 32),
+ zIndex: -2,
+
+ rotateSpeed: (Math.PI / 4),
+
+ init: function (x, y, settings) {
+ this.parent(x, y, settings);
+ this.addAnim("idle", 1, [0]);
+ },
+
+ update: function () {
+
+ // Follow the mouse cursor
+ this.pos = {
+ x: (ig.input.mouse.x + ig.game.screen.x - (this.size.x / 2)),
+ y: (ig.input.mouse.y + ig.game.screen.y - (this.size.y / 2))
+ };
+
+ // Rotate
+ this.currentAnim.angle += (this.rotateSpeed * ig.system.tick);
+
+ this.parent();
+
+ }
+
+});
+
+});
24 htdocs/lib/game/entities/save-point.js
@@ -0,0 +1,24 @@
+ig.module(
+ "game.entities.save-point"
+)
+.requires(
+ "game.entities.abstract.power-up"
+)
+.defines(function () {
+
+EntitySavePoint = EntityPowerUp.extend({
+
+ animSheet: new ig.AnimationSheet("media/entities/powerups.png", 16, 16),
+
+ init: function (x, y, settings) {
+ this.parent(x, y, settings);
+ this.addAnim("active", 0.25, [0, 1, 2, 1]);
+ },
+
+ affect: function (hero) {
+ // TODO: save the game
+ }
+
+});
+
+});
17 htdocs/lib/game/entities/spawn-cave.js
@@ -0,0 +1,17 @@
+ig.module(
+ "game.entities.spawn-cave"
+)
+.requires(
+ "game.entities.abstract.spawner"
+)
+.defines(function () {
+
+EntitySpawnCave = EntitySpawner.extend({
+
+ health: 200,
+ size: {x: 32, y: 32},
+ animSheet: new ig.AnimationSheet("media/entities/spawner_alpha_03.png", 32, 32)
+
+});
+
+});
21 htdocs/lib/game/entities/spawn-invis.js
@@ -0,0 +1,21 @@
+ig.module(
+ "game.entities.spawn-invis"
+)
+.requires(
+ "game.entities.abstract.spawner"
+)
+.defines(function () {
+
+EntitySpawnInvis = EntitySpawner.extend({
+
+ type: ig.Entity.TYPE.NONE,
+ checkAgainst: ig.Entity.TYPE.NONE,
+ collides: ig.Entity.COLLIDES.NEVER,
+ health: 1,
+
+ _wmDrawBox: true,
+ _wmBoxColor: "rgba(255, 0, 0, 0.5)"
+
+});
+
+});
16 htdocs/lib/game/entities/spawn-pyramid.js
@@ -0,0 +1,16 @@
+ig.module(
+ "game.entities.spawn-pyramid"
+)
+.requires(
+ "game.entities.abstract.spawner"
+)
+.defines(function () {
+
+EntitySpawnPyramid = EntitySpawner.extend({
+
+ health: 100,
+ animSheet: new ig.AnimationSheet("media/entities/spawner_alpha.png", 16, 16)
+
+});
+
+});
20 htdocs/lib/game/entities/torch.js
@@ -0,0 +1,20 @@
+ig.module(
+ "game.entities.torch"
+)
+.requires(
+ "impact.entity"
+)
+.defines(function () {
+
+EntityTorch = ig.Entity.extend({
+
+ animSheet: new ig.AnimationSheet("media/entities/objects.png", 16, 16),
+
+ init: function (x, y, settings) {
+ this.parent(x, y, settings);
+ this.addAnim("idle", 0.2, [75, 74, 75, 73]);
+ }
+
+});
+
+});
35 htdocs/lib/game/entities/warp.js
@@ -0,0 +1,35 @@
+ig.module(
+ "game.entities.warp"
+)
+.requires(
+ "impact.entity"
+)
+.defines(function () {
+
+EntityWarp = ig.Entity.extend({
+
+ _wmScalable: true,
+ _wmDrawBox: true,
+ _wmBoxColor: "rgba(0, 0, 255, 0.5)",
+
+ type: ig.Entity.TYPE.NONE,
+ checkAgainst: ig.Entity.TYPE.A,
+ size: {x: 16, y: 16},
+
+ level: null,
+ location: null,
+
+ check: function (other) {
+ if (
+ other instanceof EntityHero
+ && this.level != null
+ && ig.global[this.level]
+ && this.location != null
+ ) {
+ ig.game.warp(ig.global[this.level], this.location);
+ }
+ }
+
+});
+
+});
21 htdocs/lib/game/entities/weapons/spear.js
@@ -0,0 +1,21 @@
+ig.module(
+ "game.entities.weapons.spear"
+)
+.requires(
+ "game.entities.abstract.weapon"
+)
+.defines(function () {
+
+EntitySpear = EntityWeapon.extend({
+
+ damage: 10,
+ maxVel: {x: 250, y: 250},
+
+ init: function (x, y, settings) {
+ this.addAnim("idle", 1, [12]);
+ this.parent(x, y, settings);
+ }
+
+});
+
+});
20 htdocs/lib/game/entities/weapons/sword.js
@@ -0,0 +1,20 @@
+ig.module(
+ "game.entities.weapons.sword"
+)
+.requires(
+ "game.entities.abstract.weapon"
+)
+.defines(function () {
+
+EntitySword = EntityWeapon.extend({
+
+ damage: 5,
+
+ init: function (x, y, settings) {
+ this.addAnim("idle", 1, [0]);
+ this.parent(x, y, settings);
+ }
+
+});
+
+});
50 htdocs/lib/game/entities/wizard.js
@@ -0,0 +1,50 @@
+ig.module(
+ "game.entities.wizard"
+)
+.requires(
+ "game.entities.abstract.monster"
+)
+.defines(function () {
+
+EntityWizard = EntityMonster.extend({
+
+ health: 50,
+ maxVel: {x: 50, y: 50},
+
+ animSheet: new ig.AnimationSheet("media/entities/wizard.png", 16, 16),
+
+ /*
+ sounds: {
+ damage: new ig.Sound("media/sounds/bat_damage.*"),
+ death: new ig.Sound("media/sounds/bat_death.*")
+ },
+ */
+
+ init: function (x, y, settings) {
+ this.parent(x, y, settings);
+
+ this.addPhase("moveLeft", {
+ duration: 2,
+ init: function () {
+ this.vel = {x: -this.maxVel.x, y: 0};
+ },
+ end: function () {
+ this.gotoPhase("moveRight");
+ }
+ });
+
+ this.addPhase("moveRight", {
+ duration: 2,
+ init: function () {
+ this.vel = {x: this.maxVel.x, y: 0};
+ },
+ end: function () {
+ this.gotoPhase("moveLeft");
+ }
+ });
+
+ }
+
+});
+
+});
15 htdocs/lib/game/entities/xam.js
@@ -0,0 +1,15 @@
+ig.module(
+ "game.entities.xam"
+)
+.requires(
+ "game.entities.abstract.hero"
+)
+.defines(function () {
+
+EntityXam = EntityHero.extend({
+
+ animSheet: new ig.AnimationSheet("media/entities/xam.png", 16, 16)
+
+});
+
+});
112 htdocs/lib/game/levels/ai_test.js
@@ -0,0 +1,112 @@
+ig.module( 'game.levels.ai_test' )
+.requires('impact.image')
+.defines(function(){
+LevelAi_test=/*JSON[*/{
+ "entities": [
+ {
+ "type": "EntityXam",
+ "x": 82,
+ "y": 40
+ },
+ {
+ "type": "EntityHealPoint",
+ "x": 32,
+ "y": 32
+ },
+ {
+ "type": "EntityWizard",
+ "x": 226,
+ "y": 88
+ }
+ ],
+ "layer": [
+ {
+ "name": "ground",
+ "width": 30,
+ "height": 30,
+ "linkWithCollision": false,
+ "visible": 1,
+ "tilesetName": "media/tilesets/forest.png",
+ "repeat": false,
+ "distance": "1",
+ "tilesize": 16,
+ "data": [
+ [35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,35],
+ [35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35]
+ ]
+ },
+ {
+ "name": "collision",
+ "width": 30,
+ "height": 30,
+ "linkWithCollision": false,
+ "visible": 1,
+ "tilesetName": "media/tilesets/collision.png",
+ "repeat": false,
+ "distance": "1",
+ "tilesize": 16,
+ "data": [
+ [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
+ [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
+ ]
+ }
+ ]
+}/*]JSON*/;
+LevelAi_testResources=[new ig.Image('media/tilesets/forest.png')];
+});
439 htdocs/lib/game/levels/test.js
@@ -0,0 +1,439 @@
+ig.module( 'game.levels.test' )
+.requires('impact.image')
+.defines(function(){
+LevelTest=/*JSON[*/{
+ "entities": [
+ {
+ "type": "EntityGoblin",
+ "x": 98,
+ "y": 760
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 66,
+ "y": 744
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 402,
+ "y": 712
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 418,
+ "y": 616
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 514,
+ "y": 56
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 258,
+ "y": 88
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 82,
+ "y": 312
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 402,
+ "y": 88
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 274,
+ "y": 312
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 114,
+ "y": 408
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 290,
+ "y": 104
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 162,
+ "y": 360
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 98,
+ "y": 456
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 290,
+ "y": 456
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 290,
+ "y": 360
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 258,
+ "y": 456
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 450,
+ "y": 728
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 450,
+ "y": 648
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 482,
+ "y": 696
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 514,
+ "y": 744
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 482,
+ "y": 296
+ },
+ {
+ "type": "EntityGoblin",
+ "x": 466,
+ "y": 312
+ },
+ {
+ "type": "EntityTorch",
+ "x": 272,
+ "y": 16
+ },
+ {
+ "type": "EntityHealPoint",
+ "x": 176,
+ "y": 448
+ },
+ {
+ "type": "EntitySavePoint",
+ "x": 48,
+ "y": 80
+ },
+ {
+ "type": "EntityBat",
+ "x": 98,
+ "y": 360
+ },
+ {
+ "type": "EntityBat",
+ "x": 162,
+ "y": 392
+ },
+ {
+ "type": "EntityBat",
+ "x": 146,
+ "y": 456
+ },
+ {
+ "type": "EntityBat",
+ "x": 194,
+ "y": 440
+ },
+ {
+ "type": "EntityBat",
+ "x": 242,
+ "y": 360
+ },
+ {
+ "type": "EntityBat",
+ "x": 290,
+ "y": 408
+ },
+ {
+ "type": "EntityBat",
+ "x": 418,
+ "y": 664
+ },
+ {
+ "type": "EntityBat",
+ "x": 546,
+ "y": 712
+ },
+ {
+ "type": "EntityBat",
+ "x": 418,
+ "y": 744
+ },
+ {
+ "type": "EntityBat",
+ "x": 338,
+ "y": 120
+ },
+ {
+ "type": "EntityTorch",
+ "x": 160,
+ "y": 48
+ },
+ {
+ "type": "EntityTorch",
+ "x": 320,
+ "y": 16
+ },
+ {
+ "type": "EntityTorch",
+ "x": 80,
+ "y": 48
+ },
+ {
+ "type": "EntityCoin",
+ "x": 80,
+ "y": 192
+ },
+ {
+ "type": "EntityCoin",
+ "x": 64,
+ "y": 208
+ },
+ {
+ "type": "EntityCube",
+ "x": 184,
+ "y": 312
+ },
+ {
+ "type": "EntitySpawnCave",
+ "x": 288,
+ "y": 64,
+ "settings": {
+ "spawnEntity": "EntityGoblin",
+ "spawnInterval": 2
+ }
+ },
+ {
+ "type": "EntityWarp",
+ "x": 400,
+ "y": 528,
+ "settings": {
+ "level": "LevelVillage",
+ "location": "loc_a"
+ }
+ },
+ {
+ "type": "EntityLocation",
+ "x": 64,
+ "y": 96,
+ "settings": {
+ "name": "loc_spawn"
+ }
+ },
+ {
+ "type": "EntityLocation",
+ "x": 400,
+ "y": 544,
+ "settings": {
+ "name": "loc_b"
+ }
+ }
+ ],
+ "layer": [
+ {
+ "name": "ground",
+ "width": 50,
+ "height": 50,
+ "linkWithCollision": false,
+ "visible": 1,
+ "tilesetName": "media/tilesets/cave.png",
+ "repeat": false,
+ "distance": "1",
+ "tilesize": 16,
+ "data": [
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,32,32,32,32,32,32,32,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,32,32,32,32,32,6,32,32,32,32,18,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,1,1,1,1,1,1,1,1,1,16,32,32,32,32,6,32,32,32,32,32,6,32,32,33,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,1,1,1,1,1,4,1,4,1,31,32,32,32,32,32,32,32,32,32,32,32,32,32,33,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,1,1,1,2,1,1,1,1,1,46,32,32,32,32,32,6,32,32,32,32,32,32,32,48,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,1,1,2,1,1,1,0,0,0,0,0,0,32,32,32,32,6,32,32,32,32,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,32,32,32,32,32,32,32,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,1,1,1,1,2,1,1,4,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,1,2,2,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,1,1,1,1,1,1,1,3,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,31,32,32,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,31,32,32,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,2,2,1,46,47,47,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,1,1,3,1,1,1,4,1,1,1,1,1,1,2,2,1,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,1,1,1,1,1,1,1,1,1,1,4,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,1,1,1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,1,1,1,1,2,1,2,2,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,1,1,1,2,2,1,1,1,1,1,1,1,1,1,1,2,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,1,1,1,2,1,1,1,1,1,1,1,3,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,1,1,1,1,1,1,16,17,17,17,18,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,1,1,1,1,1,1,31,32,32,32,33,1,2,2,2,1,1,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,1,1,4,1,1,2,31,32,32,32,33,1,1,1,2,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,1,1,1,1,1,1,31,32,32,32,33,1,4,1,1,2,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,1,1,1,4,1,1,31,32,32,32,33,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,1,1,1,1,1,1,31,32,32,32,33,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
+ ]
+ },
+ {
+ "name": "cave_walls",
+ "width": 50,
+ "height": 50,
+ "linkWithCollision": true,
+ "visible": 1,
+ "tilesetName": "media/tilesets/cave.png",
+ "repeat": false,
+ "distance": "1",
+ "tilesize": 16,
+ "data": [
+ [26,26,26,26,26,26,26,26,26,26,26,26,26,26,42,24,23,23,23,23,23,23,22,40,41,41,41,41,41,41,42,24,23,23,24,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26],
+ [26,13,14,14,14,14,14,14,14,14,14,14,14,42,24,24,23,23,23,23,109,23,22,23,23,23,109,23,109,96,23,24,23,23,22,30,26,26,26,26,26,26,26,26,26,26,26,26,26,26],
+ [26,27,24,23,23,109,23,23,23,23,23,23,23,23,24,55,89,89,89,56,56,89,57,109,23,23,23,23,109,109,109,55,56,89,57,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26],
+ [26,27,24,23,23,23,23,23,109,23,23,23,109,23,55,90,0,0,0,0,0,0,88,56,89,56,89,89,56,89,56,90,0,0,72,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26],
+ [26,27,55,56,89,89,89,56,89,56,89,56,56,56,90,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,72,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26],
+ [26,28,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,58,86,86,87,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26],
+ [26,28,70,0,0,0,0,58,86,86,86,86,86,86,60,0,0,0,0,0,0,0,58,86,86,86,86,86,60,0,0,72,10,11,11,45,26,26,26,26,26,26,26,26,26,26,26,26,26,26],
+ [26,28,70,0,0,0,0,72,10,44,44,44,44,12,85,86,60,0,0,0,0,0,72,10,11,11,11,12,70,0,0,72,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26],
+ [26,28,70,0,0,0,58,87,25,26,26,26,26,43,44,12,85,86,86,86,86,86,87,25,26,26,26,27,70,0,0,72,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26],
+ [26,28,85,60,0,0,72,10,45,26,26,26,26,26,26,43,44,44,44,44,44,44,11,45,26,26,26,27,70,0,0,72,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26],
+ [26,43,12,70,0,0,72,40,41,41,41,41,41,15,26,26,26,26,26,26,26,26,26,26,26,26,26,27,70,0,0,72,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26],
+ [26,26,28,70,0,0,88,56,56,56,56,56,57,25,26,26,26,26,26,26,26,26,26,26,26,26,26,27,70,0,0,72,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26],
+ [26,26,28,70,0,0,0,0,0,0,0,0,72,25,26,26,26,26,26,26,26,26,26,26,26,26,26,27,70,0,0,72,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26],
+ [26,26,28,70,0,0,0,0,0,0,0,0,72,25,26,26,26,26,26,26,26,26,26,26,26,26,26,27,70,0,0,72,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26],
+ [26,26,28,85,86,86,86,86,86,60,0,0,72,25,26,26,26,26,26,26,26,26,26,26,26,26,26,27,70,0,0,72,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26],
+ [26,26,43,11,11,11,11,11,12,70,0,0,72,40,41,41,41,41,41,41,41,15,26,26,26,26,26,27,70,0,0,72,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26],
+ [26,26,13,14,14,14,14,14,42,75,0,0,88,56,56,56,56,56,56,56,57,25,26,26,26,26,26,27,70,0,0,72,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26],
+ [26,26,27,55,56,56,56,56,56,90,0,0,0,0,0,0,0,0,0,0,72,25,26,26,26,26,26,27,70,0,0,72,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26],
+ [26,26,27,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,72,25,26,26,26,26,26,27,70,0,0,72,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26],
+ [26,26,27,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,72,25,26,26,26,26,26,27,70,0,0,72,25,26,26,26,26,2