├── .gitignore ├── README ├── TODO ├── dojo ├── DeferredList.js ├── dojo.js └── dojo.js.uncompressed.js ├── index.css ├── index.html ├── index2.html ├── png.js ├── pocjs ├── Art.js ├── EscapeComponent.js ├── Game.js ├── InputHandler.js ├── Sound.js ├── all.js ├── entities │ ├── BatBossEntity.js │ ├── BatEntity.js │ ├── BossOgre.js │ ├── BoulderEntity.js │ ├── Bullet.js │ ├── EnemyEntity.js │ ├── Entity.js │ ├── EyeBossEntity.js │ ├── EyeEntity.js │ ├── GhostBossEntity.js │ ├── GhostEntity.js │ ├── Item.js │ ├── KeyEntity.js │ ├── OgreEntity.js │ └── Player.js ├── gui │ ├── Bitmap.js │ ├── Bitmap3D.js │ ├── PoofSprite.js │ ├── RubbleSprite.js │ ├── Screen.js │ └── Sprite.js ├── level │ ├── CryptLevel.js │ ├── DungeonLevel.js │ ├── IceLevel.js │ ├── Level.js │ ├── OverworldLevel.js │ ├── StartLevel.js │ ├── TempleLevel.js │ └── block │ │ ├── AltarBlock.js │ │ ├── BarsBlock.js │ │ ├── Block.js │ │ ├── ChestBlock.js │ │ ├── DoorBlock.js │ │ ├── FinalUnlockBlock.js │ │ ├── IceBlock.js │ │ ├── LadderBlock.js │ │ ├── LockedDoorBlock.js │ │ ├── LootBlock.js │ │ ├── PitBlock.js │ │ ├── PressurePlateBlock.js │ │ ├── SolidBlock.js │ │ ├── SpiritWallBlock.js │ │ ├── SwitchBlock.js │ │ ├── TorchBlock.js │ │ ├── VanishBlock.js │ │ ├── WaterBlock.js │ │ └── WinBlock.js └── menu │ ├── AboutMenu.js │ ├── GotLootMenu.js │ ├── InstructionsMenu.js │ ├── LoseMenu.js │ ├── Menu.js │ ├── PauseMenu.js │ ├── TitleMenu.js │ └── WinMenu.js ├── res ├── gui │ └── logo.png ├── level │ ├── crypt.png │ ├── dungeon.png │ ├── ice.png │ ├── overworld.png │ ├── start.png │ └── temple.png ├── snd │ ├── altar.wav │ ├── bosskill.wav │ ├── click1.wav │ ├── click2.wav │ ├── crumble.wav │ ├── cut.wav │ ├── death.wav │ ├── hit.wav │ ├── hurt.wav │ ├── hurt2.wav │ ├── key.wav │ ├── kill.wav │ ├── ladder.wav │ ├── pickup.wav │ ├── potion.wav │ ├── roll.wav │ ├── shoot.wav │ ├── slide.wav │ ├── splash.wav │ ├── thud.wav │ └── treasure.wav └── tex │ ├── floors.png │ ├── font.png │ ├── items.png │ ├── panel.png │ ├── sky.png │ ├── sprites.png │ └── walls.png └── zlib.js /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | PoC-JS 2 | ====== 3 | 4 | This is a JavaScript port of the game 5 | "Prelude of the Chambered" by Markus "notch" Persson. 6 | 7 | Currently this is already working in current versions of Firefox, 8 | Chrome/Chromium and likely also Safari (and other WebKit browsers). Support for 9 | Opera and Internet Explorer 9+ is planned. 10 | 11 | The game looks best on Firefox as its canvas scaling can be made to _not_ use 12 | anti-aliasing. WebKit-based browsers produce a really squishy scale. 13 | 14 | Performance is acceptable although there surely are laggy moments. 15 | 16 | Some bugs are still to fix. 17 | 18 | Lessons learned 19 | ---------------- 20 | 21 | - CanvasContext.drawImage takes the PNG alpha channel into account. 22 | The original pixel values are therefore not identical to 23 | CanvasContext.getImageData(...).data 24 | 25 | - doing level design as graphics may be a good idea, storing level meta data 26 | in the alpha channel may be not 27 | 28 | - having no Integer type sucks 29 | 30 | - having only function level scope sucks (no lexical scope? seriously?) 31 | 32 | - having the canvas engine scale an image is much faster than doing it 33 | in JS (oh, really?) 34 | 35 | - all browsers use anti-aliasing when scaling by default. 36 | Only Firefox can be told with 37 | 38 | CanvasContext.mozImageSmoothingEnabled = false 39 | 40 | to have a nice ruff, blocky scale 41 | 42 | - play testing a permadeath game that has no saves is annoying 43 | 44 | 45 | Copyright 46 | --------- 47 | 48 | - Idea, code, assets (c) 2011 Mojang AB 49 | 50 | - Javascript port by Sebastian Bober 51 | 52 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - performance work 2 | 3 | -------------------------------------------------------------------------------- /dojo/DeferredList.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved. 3 | Available via Academic Free License >= 2.1 OR the modified BSD license. 4 | see: http://dojotoolkit.org/license for details 5 | */ 6 | 7 | 8 | if(!dojo._hasResource["dojo.DeferredList"]){ 9 | dojo._hasResource["dojo.DeferredList"]=true; 10 | dojo.provide("dojo.DeferredList"); 11 | dojo.DeferredList=function(_1,_2,_3,_4,_5){ 12 | var _6=[]; 13 | dojo.Deferred.call(this); 14 | var _7=this; 15 | if(_1.length===0&&!_2){ 16 | this.resolve([0,[]]); 17 | } 18 | var _8=0; 19 | dojo.forEach(_1,function(_9,i){ 20 | _9.then(function(_a){ 21 | if(_2){ 22 | _7.resolve([i,_a]); 23 | }else{ 24 | _b(true,_a); 25 | } 26 | },function(_c){ 27 | if(_3){ 28 | _7.reject(_c); 29 | }else{ 30 | _b(false,_c); 31 | } 32 | if(_4){ 33 | return null; 34 | } 35 | throw _c; 36 | }); 37 | function _b(_d,_e){ 38 | _6[i]=[_d,_e]; 39 | _8++; 40 | if(_8===_1.length){ 41 | _7.resolve(_6); 42 | } 43 | }; 44 | }); 45 | }; 46 | dojo.DeferredList.prototype=new dojo.Deferred(); 47 | dojo.DeferredList.prototype.gatherResults=function(_f){ 48 | var d=new dojo.DeferredList(_f,false,true,false); 49 | d.addCallback(function(_10){ 50 | var ret=[]; 51 | dojo.forEach(_10,function(_11){ 52 | ret.push(_11[1]); 53 | }); 54 | return ret; 55 | }); 56 | return d; 57 | }; 58 | } 59 | -------------------------------------------------------------------------------- /index.css: -------------------------------------------------------------------------------- 1 | canvas { 2 | border: 1px dotted; 3 | /*image-rendering: -webkit-optimize-contrast;*/ 4 | image-rendering: -moz-crisp-edges; 5 | } 6 | 7 | h1 a { 8 | font-size: small; 9 | } 10 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |Starting ...
24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /index2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |Starting ...
19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /png.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | /* 3 | # MIT LICENSE 4 | # Copyright (c) 2011 Devon Govett 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy of this 7 | # software and associated documentation files (the "Software"), to deal in the Software 8 | # without restriction, including without limitation the rights to use, copy, modify, merge, 9 | # publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons 10 | # to whom the Software is furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in all copies or 13 | # substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 16 | # BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ var PNG; 21 | var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 22 | PNG = (function() { 23 | var APNG_BLEND_OP_OVER, APNG_BLEND_OP_SOURCE, APNG_DISPOSE_OP_BACKGROUND, APNG_DISPOSE_OP_NONE, APNG_DISPOSE_OP_PREVIOUS, makeImage, scratchCanvas, scratchCtx; 24 | PNG.load = function(url, canvas, callback) { 25 | var xhr; 26 | if (typeof canvas === 'function') { 27 | callback = canvas; 28 | } 29 | xhr = new XMLHttpRequest; 30 | xhr.open("GET", url, true); 31 | xhr.responseType = "arraybuffer"; 32 | xhr.onload = __bind(function() { 33 | var data, png; 34 | data = new Uint8Array(xhr.response || xhr.mozResponseArrayBuffer); 35 | png = new PNG(data); 36 | if (typeof (canvas != null ? canvas.getContext : void 0) === 'function') { 37 | png.render(canvas); 38 | } 39 | return typeof callback === "function" ? callback(png) : void 0; 40 | }, this); 41 | return xhr.send(null); 42 | }; 43 | APNG_DISPOSE_OP_NONE = 0; 44 | APNG_DISPOSE_OP_BACKGROUND = 1; 45 | APNG_DISPOSE_OP_PREVIOUS = 2; 46 | APNG_BLEND_OP_SOURCE = 0; 47 | APNG_BLEND_OP_OVER = 1; 48 | function PNG(data) { 49 | var chunkSize, colors, delayDen, delayNum, frame, i, section, rest, _ref; 50 | this.data = data; 51 | this.pos = 8; 52 | this.palette = []; 53 | this.imgData = []; 54 | this.transparency = {}; 55 | this.animation = null; 56 | frame = null; 57 | while (true) { 58 | chunkSize = this.readUInt32(); 59 | section = ((function() { 60 | var _results; 61 | _results = []; 62 | for (i = 0; i < 4; i++) { 63 | _results.push(String.fromCharCode(this.data[this.pos++])); 64 | } 65 | return _results; 66 | }).call(this)).join(''); 67 | switch (section) { 68 | case 'IHDR': 69 | this.width = this.readUInt32(); 70 | this.height = this.readUInt32(); 71 | this.bits = this.data[this.pos++]; 72 | this.colorType = this.data[this.pos++]; 73 | this.compressionMethod = this.data[this.pos++]; 74 | this.filterMethod = this.data[this.pos++]; 75 | this.interlaceMethod = this.data[this.pos++]; 76 | break; 77 | case 'acTL': 78 | this.animation = { 79 | numFrames: this.readUInt32(), 80 | numPlays: this.readUInt32() || Infinity, 81 | frames: [] 82 | }; 83 | break; 84 | case 'PLTE': 85 | this.palette = this.read(chunkSize); 86 | break; 87 | case 'fcTL': 88 | if (frame) { 89 | this.animation.frames.push(frame); 90 | } 91 | this.pos += 4; 92 | frame = { 93 | width: this.readUInt32(), 94 | height: this.readUInt32(), 95 | xOffset: this.readUInt32(), 96 | yOffset: this.readUInt32() 97 | }; 98 | delayNum = this.readUInt16(); 99 | delayDen = this.readUInt16() || 100; 100 | frame.delay = 1000 * delayNum / delayDen; 101 | frame.disposeOp = this.data[this.pos++]; 102 | frame.blendOp = this.data[this.pos++]; 103 | frame.data = []; 104 | break; 105 | case 'IDAT': 106 | case 'fdAT': 107 | if (section === 'fdAT') { 108 | this.pos += 4; 109 | chunkSize -= 4; 110 | } 111 | data = (frame != null ? frame.data : void 0) || this.imgData; 112 | for (i = 0; 0 <= chunkSize ? i < chunkSize : i > chunkSize; 0 <= chunkSize ? i++ : i--) { 113 | data.push(this.data[this.pos++]); 114 | } 115 | break; 116 | case 'tRNS': 117 | this.transparency = {}; 118 | switch (this.colorType) { 119 | case 3: 120 | // alpha for indexed palette; fill up alpha for all colors 121 | this.transparency.indexed = this.read(chunkSize); 122 | rest = 255 - this.transparency.indexed.length; 123 | if (rest > 0) { 124 | for (i = 0; i < rest; i++) { 125 | this.transparency.indexed.push(255); 126 | } 127 | } 128 | break; 129 | case 0: 130 | this.transparency.grayscale = this.read(chunkSize)[0]; 131 | break; 132 | case 2: 133 | this.transparency.rgb = this.read(chunkSize); 134 | } 135 | break; 136 | case 'IEND': 137 | if (frame) { 138 | this.animation.frames.push(frame); 139 | } 140 | this.colors = (function() { 141 | switch (this.colorType) { 142 | case 0: 143 | case 3: 144 | case 4: 145 | return 1; 146 | case 2: 147 | case 6: 148 | return 3; 149 | } 150 | }).call(this); 151 | this.hasAlphaChannel = (_ref = this.colorType) === 4 || _ref === 6; 152 | colors = this.colors + (this.hasAlphaChannel ? 1 : 0); 153 | this.pixelBitlength = this.bits * colors; 154 | this.colorSpace = (function() { 155 | switch (this.colors) { 156 | case 1: 157 | return 'DeviceGray'; 158 | case 3: 159 | return 'DeviceRGB'; 160 | } 161 | }).call(this); 162 | this.imgData = new Uint8Array(this.imgData); 163 | return; 164 | default: 165 | this.pos += chunkSize; 166 | } 167 | this.pos += 4; 168 | } 169 | } 170 | PNG.prototype.read = function(bytes) { 171 | var i, _results; 172 | _results = []; 173 | for (i = 0; 0 <= bytes ? i < bytes : i > bytes; 0 <= bytes ? i++ : i--) { 174 | _results.push(this.data[this.pos++]); 175 | } 176 | return _results; 177 | }; 178 | PNG.prototype.readUInt32 = function() { 179 | var b1, b2, b3, b4; 180 | b1 = this.data[this.pos++] << 24; 181 | b2 = this.data[this.pos++] << 16; 182 | b3 = this.data[this.pos++] << 8; 183 | b4 = this.data[this.pos++]; 184 | return b1 | b2 | b3 | b4; 185 | }; 186 | PNG.prototype.readUInt16 = function() { 187 | var b1, b2; 188 | b1 = this.data[this.pos++] << 8; 189 | b2 = this.data[this.pos++]; 190 | return b1 | b2; 191 | }; 192 | PNG.prototype.decodePixels = function(data) { 193 | var read_byte, col, filter, i, left, length, p, pa, paeth, pb, pc, pixelBytes, pixels, pos, row, rowData, s, scanlineLength, upper, upperLeft, _ref, _step; 194 | if (data == null) { 195 | data = this.imgData; 196 | } 197 | if (data.length === 0) { 198 | return []; 199 | } 200 | data = new FlateStream(data); 201 | data = data.getBytes(); 202 | pixelBytes = this.pixelBitlength / 8; 203 | scanlineLength = pixelBytes * this.width; 204 | row = 0; 205 | pixels = []; 206 | length = data.length; 207 | pos = 0; 208 | while (pos < length) { 209 | filter = data[pos++]; 210 | i = 0; 211 | rowData = []; 212 | switch (filter) { 213 | case 0: 214 | while (i < scanlineLength) { 215 | rowData[i++] = data[pos++]; 216 | } 217 | break; 218 | case 1: 219 | while (i < scanlineLength) { 220 | read_byte = data[pos++]; 221 | left = i < pixelBytes ? 0 : rowData[i - pixelBytes]; 222 | rowData[i++] = (read_byte + left) % 256; 223 | } 224 | break; 225 | case 2: 226 | while (i < scanlineLength) { 227 | read_byte = data[pos++]; 228 | col = (i - (i % pixelBytes)) / pixelBytes; 229 | upper = row === 0 ? 0 : pixels[row - 1][col][i % pixelBytes]; 230 | rowData[i++] = (upper + read_byte) % 256; 231 | } 232 | break; 233 | case 3: 234 | while (i < scanlineLength) { 235 | read_byte = data[pos++]; 236 | col = (i - (i % pixelBytes)) / pixelBytes; 237 | left = i < pixelBytes ? 0 : rowData[i - pixelBytes]; 238 | upper = row === 0 ? 0 : pixels[row - 1][col][i % pixelBytes]; 239 | rowData[i++] = (read_byte + Math.floor((left + upper) / 2)) % 256; 240 | } 241 | break; 242 | case 4: 243 | while (i < scanlineLength) { 244 | read_byte = data[pos++]; 245 | col = (i - (i % pixelBytes)) / pixelBytes; 246 | left = i < pixelBytes ? 0 : rowData[i - pixelBytes]; 247 | if (row === 0) { 248 | upper = upperLeft = 0; 249 | } else { 250 | upper = pixels[row - 1][col][i % pixelBytes]; 251 | upperLeft = col === 0 ? 0 : pixels[row - 1][col - 1][i % pixelBytes]; 252 | } 253 | p = left + upper - upperLeft; 254 | pa = Math.abs(p - left); 255 | pb = Math.abs(p - upper); 256 | pc = Math.abs(p - upperLeft); 257 | if (pa <= pb && pa <= pc) { 258 | paeth = left; 259 | } else if (pb <= pc) { 260 | paeth = upper; 261 | } else { 262 | paeth = upperLeft; 263 | } 264 | rowData[i++] = (read_byte + paeth) % 256; 265 | } 266 | break; 267 | default: 268 | throw new Error("Invalid filter algorithm: " + filter); 269 | } 270 | s = []; 271 | for (i = 0, _ref = rowData.length, _step = pixelBytes; 0 <= _ref ? i < _ref : i > _ref; i += _step) { 272 | s.push(rowData.slice(i, i + pixelBytes)); 273 | } 274 | pixels.push(s); 275 | row += 1; 276 | } 277 | return pixels; 278 | }; 279 | PNG.prototype.decodePalette = function() { 280 | var alpha, decodingMap, i, index, palette, pixel, transparency, _ref, _ref2, _ref3, _step; 281 | palette = this.palette; 282 | transparency = (_ref = this.transparency.indexed) != null ? _ref : []; 283 | decodingMap = []; 284 | index = 0; 285 | for (i = 0, _ref2 = palette.length, _step = 3; 0 <= _ref2 ? i < _ref2 : i > _ref2; i += _step) { 286 | alpha = (_ref3 = transparency[index++]) != null ? _ref3 : 255; 287 | pixel = palette.slice(i, i + 3).concat(alpha); 288 | decodingMap.push(pixel); 289 | } 290 | return decodingMap; 291 | }; 292 | PNG.prototype.copyToImageData = function(imageData, pixels) { 293 | var alpha, copy_byte, colors, data, i, palette, pixel, row, v, _i, _j, _k, _len, _len2, _len3, _ref; 294 | colors = this.colors; 295 | palette = null; 296 | alpha = this.hasAlphaChannel; 297 | if (this.palette.length) { 298 | palette = (_ref = this._decodedPalette) != null ? _ref : this._decodedPalette = this.decodePalette(); 299 | colors = 4; 300 | alpha = true; 301 | } 302 | data = imageData.data; 303 | i = 0; 304 | for (_i = 0, _len = pixels.length; _i < _len; _i++) { 305 | row = pixels[_i]; 306 | for (_j = 0, _len2 = row.length; _j < _len2; _j++) { 307 | pixel = row[_j]; 308 | if (palette) { 309 | pixel = palette[pixel]; 310 | } 311 | if (colors === 1) { 312 | v = pixel[0]; 313 | data[i++] = v; 314 | data[i++] = v; 315 | data[i++] = v; 316 | data[i++] = pixel[1] || 255; 317 | } else { 318 | for (_k = 0, _len3 = pixel.length; _k < _len3; _k++) { 319 | copy_byte = pixel[_k]; 320 | data[i++] = copy_byte; 321 | } 322 | if (!alpha) { 323 | data[i++] = 255; 324 | } 325 | } 326 | } 327 | } 328 | }; 329 | scratchCanvas = document.createElement('canvas'); 330 | scratchCtx = scratchCanvas.getContext('2d'); 331 | makeImage = function(imageData) { 332 | var img; 333 | scratchCtx.width = imageData.width; 334 | scratchCtx.height = imageData.height; 335 | scratchCtx.clearRect(0, 0, imageData.width, imageData.height); 336 | scratchCtx.putImageData(imageData, 0, 0); 337 | img = new Image; 338 | img.src = scratchCanvas.toDataURL(); 339 | return img; 340 | }; 341 | PNG.prototype.decodeFrames = function(ctx) { 342 | var frame, i, imageData, pixels, _len, _ref, _results; 343 | if (!this.animation) { 344 | return; 345 | } 346 | _ref = this.animation.frames; 347 | _results = []; 348 | for (i = 0, _len = _ref.length; i < _len; i++) { 349 | frame = _ref[i]; 350 | imageData = ctx.createImageData(frame.width, frame.height); 351 | pixels = this.decodePixels(new Uint8Array(frame.data)); 352 | this.copyToImageData(imageData, pixels); 353 | frame.imageData = imageData; 354 | _results.push(frame.image = makeImage(imageData)); 355 | } 356 | return _results; 357 | }; 358 | PNG.prototype.renderFrame = function(ctx, number) { 359 | var frame, frames, prev; 360 | frames = this.animation.frames; 361 | frame = frames[number]; 362 | prev = frames[number - 1]; 363 | if (number === 0) { 364 | ctx.clearRect(0, 0, this.width, this.height); 365 | } 366 | if ((prev != null ? prev.disposeOp : void 0) === APNG_DISPOSE_OP_BACKGROUND) { 367 | ctx.clearRect(prev.xOffset, prev.yOffset, prev.width, prev.height); 368 | } else if ((prev != null ? prev.disposeOp : void 0) === APNG_DISPOSE_OP_PREVIOUS) { 369 | ctx.putImageData(prev.imageData, prev.xOffset, prev.yOffset); 370 | } 371 | if (frame.blendOp === APNG_BLEND_OP_SOURCE) { 372 | ctx.clearRect(frame.xOffset, frame.yOffset, frame.width, frame.height); 373 | } 374 | return ctx.drawImage(frame.image, frame.xOffset, frame.yOffset); 375 | }; 376 | PNG.prototype.animate = function(ctx) { 377 | var doFrame, frameNumber, frames, numFrames, numPlays, _ref; 378 | frameNumber = 0; 379 | _ref = this.animation, numFrames = _ref.numFrames, frames = _ref.frames, numPlays = _ref.numPlays; 380 | return (doFrame = __bind(function() { 381 | var f, frame; 382 | f = frameNumber++ % numFrames; 383 | frame = frames[f]; 384 | this.renderFrame(ctx, f); 385 | if (numFrames > 1 && frameNumber / numFrames < numPlays) { 386 | return this.animation._timeout = setTimeout(doFrame, frame.delay); 387 | } 388 | }, this))(); 389 | }; 390 | PNG.prototype.stopAnimation = function() { 391 | var _ref; 392 | return clearTimeout((_ref = this.animation) != null ? _ref._timeout : void 0); 393 | }; 394 | PNG.prototype.render = function(canvas) { 395 | var ctx, data; 396 | if (canvas._png) { 397 | canvas._png.stopAnimation(); 398 | } 399 | canvas._png = this; 400 | canvas.width = this.width; 401 | canvas.height = this.height; 402 | ctx = canvas.getContext("2d"); 403 | if (this.animation) { 404 | this.decodeFrames(ctx); 405 | return this.animate(ctx); 406 | } else { 407 | data = ctx.createImageData(this.width, this.height); 408 | this.copyToImageData(data, this.decodePixels()); 409 | return ctx.putImageData(data, 0, 0); 410 | } 411 | }; 412 | return PNG; 413 | })(); 414 | window.PNG = PNG; 415 | }).call(this); 416 | -------------------------------------------------------------------------------- /pocjs/Art.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.Art"); 2 | 3 | dojo.declare("pocjs.Art", null, { 4 | }); 5 | 6 | pocjs.Art.loadBitmap = function(name, filename) { 7 | var self = this; 8 | 9 | var dfd = new dojo.Deferred(); 10 | 11 | PNG.load(filename, function(png) { 12 | var w = png.width; 13 | var h = png.height; 14 | var pixels = new Array(w * h << 0); 15 | var ppix = png.decodePixels(); 16 | 17 | var result = new pocjs.gui.Bitmap(w, h); 18 | for (var y = 0; y < h; y++) { 19 | for (var x = 0; x < w; x++) { 20 | var data = ppix[y][x]; 21 | 22 | var input = data[3] << 24 23 | | data[0] << 16 24 | | data[1] << 8 25 | | data[2]; 26 | var col = (input & 0xf) >> 2; 27 | // if (input == (0xffff00ff << 0)) { col = -1; } 28 | // silence closure compiler 29 | if (input == -65281) { col = -1; } 30 | result.pixels[x + y*w] = col; 31 | pixels[x + y*w] = input; 32 | } 33 | } 34 | 35 | self[name] = result; 36 | dfd.resolve(name); 37 | }); 38 | return dfd; 39 | } 40 | 41 | 42 | pocjs.Art.getCol = function(c) { 43 | var r = (c >> 16) & 0xff; 44 | var g = (c >> 8) & 0xff; 45 | var b = (c) & 0xff; 46 | 47 | r = r * 0x55 / 0xff; 48 | g = g * 0x55 / 0xff; 49 | b = b * 0x55 / 0xff; 50 | 51 | return r << 16 | g << 8 | b; 52 | }; 53 | 54 | -------------------------------------------------------------------------------- /pocjs/EscapeComponent.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.EscapeComponent"); 2 | 3 | 4 | dojo.declare("pocjs.EscapeComponent", null, { 5 | WIDTH: 160, 6 | HEIGHT: 120, 7 | SCALE: 4, 8 | context: null, 9 | canvas: null, 10 | game: null, 11 | screen: null, 12 | img: null, 13 | pixels: null, 14 | input: null, 15 | running: false, 16 | lastTime: null, 17 | frames: 0, 18 | inFlight: false, 19 | resizeArray: null, 20 | 21 | constructor: function(canvas) { 22 | this.context = canvas.getContext('2d'); 23 | this.canvas = canvas; 24 | canvas.width = this.WIDTH * this.SCALE; 25 | canvas.height = this.HEIGHT * this.SCALE; 26 | 27 | var self = this; 28 | this.dfd = this.loadResources().then(function(res){ 29 | self.game = new pocjs.Game(); 30 | self.screen = new pocjs.gui.Screen(self.WIDTH, self.HEIGHT); 31 | 32 | self.img = self.context.createImageData(canvas.width, canvas.height); 33 | self.tmpcanvas = document.createElement('canvas'); 34 | self.tmpcanvas.width = self.WIDTH; 35 | self.tmpcanvas.height = self.HEIGHT; 36 | self.tmpctx = self.tmpcanvas.getContext('2d'); 37 | self.context.mozImageSmoothingEnabled = false; 38 | // self.context.scale(self.SCALE, self.SCALE); 39 | self.tmpimg = self.tmpctx.createImageData(self.WIDTH, self.HEIGHT); 40 | //self.pixels = self.img.data; 41 | 42 | //self.resizeArray = new Array(canvas.width * canvas.height); 43 | self.input = new pocjs.InputHandler(); 44 | 45 | dojo.connect(document, "onkeyup", self.input, "keyup"); 46 | dojo.connect(document, "onkeydown", self.input, "keydown"); 47 | return("done"); 48 | }); 49 | 50 | 51 | }, 52 | 53 | loadResources: function() { 54 | var list = []; 55 | var self = this; 56 | dojo.byId("status").innerHTML = "Loading resources ..."; 57 | "start crypt ice temple overworld dungeon" 58 | .split(" ") 59 | .forEach(function(name) { 60 | list.push( pocjs.level.Level.loadLevelBitmap(name) ); 61 | }); 62 | 63 | "walls floors sprites font panel items sky" 64 | .split(" ") 65 | .forEach(function(name) { 66 | list.push( pocjs.Art.loadBitmap(name, "res/tex/"+name+".png") ); 67 | }); 68 | 69 | list.push( pocjs.Art.loadBitmap("logo", "res/gui/logo.png") ); 70 | 71 | ( "altar bosskill click1 click2 crumble cut death " + 72 | "hit hurt2 hurt key kill ladder pickup potion roll " + 73 | "shoot slide splash thud treasure" 74 | ).split(" ").forEach(function(name) { 75 | list.push( pocjs.Sound.loadSound(name) ); 76 | }); 77 | var dfd = new dojo.DeferredList(list).then(function(res){ 78 | dojo.byId("status").innerHTML = "Done."; 79 | return res; 80 | }); 81 | this.list = list; 82 | return dfd; 83 | }, 84 | 85 | start: function() { 86 | var self = this; 87 | dojo.create('button', { 88 | onclick: 'pocjs.__game.stop();', 89 | innerHTML: 'Stop wild JS' 90 | }, dojo.body()); 91 | 92 | // this.run(); 93 | this.dfd.then(function(res) { 94 | self.running = true; 95 | self.lastTime = Date.now(); 96 | self.loopHandle = setInterval( function() { self.run() }, 1000/60 ); 97 | }); 98 | }, 99 | 100 | stop: function() { 101 | clearInterval(this.loopHandle); 102 | }, 103 | run: function() { 104 | if (this.inFlight) return; 105 | this.inFlight = true; 106 | this.tick(); 107 | this.render(); 108 | 109 | var passedTime = (Date.now() - this.lastTime)/1000; 110 | if (passedTime >= 2) { 111 | var fps = this.frames / passedTime <<0; 112 | dojo.byId('status').innerHTML = "" + fps + " FPS"; 113 | this.frames = 0; 114 | this.lastTime = Date.now(); 115 | } 116 | this.frames++; 117 | this.inFlight = false; 118 | }, 119 | 120 | tick: function() { 121 | this.game.tick(this.input.keys); 122 | }, 123 | render: function() { 124 | this.screen.render(this.game); 125 | var spixels = this.screen.pixels; 126 | //this.resize(spixels); 127 | for (var i = 0; i < spixels.length; i++) { 128 | var pix = spixels[i]; 129 | var off = i*4; 130 | this.tmpimg.data[off] = (pix >> 16) & 0xff; // r 131 | this.tmpimg.data[off+1] = (pix >> 8) & 0xff; // g 132 | this.tmpimg.data[off+2] = pix & 0xff; // b 133 | this.tmpimg.data[off+3] = 255; //pix >> 24; // a 134 | } 135 | 136 | this.tmpctx.putImageData(this.tmpimg, 0, 0); 137 | this.context.drawImage(this.tmpcanvas, 0, 0, this.WIDTH, this.HEIGHT, 0, 0, this.WIDTH * this.SCALE, this.HEIGHT * this.SCALE); 138 | }, 139 | resize: function(pixels) { 140 | var w1 = this.WIDTH; 141 | var w2 = this.WIDTH * this.SCALE; 142 | var h1 = this.HEIGHT; 143 | var h2 = this.HEIGHT * this.SCALE; 144 | var x_ratio = w1 / w2; 145 | var y_ratio = h1 / h2; 146 | var px, py; 147 | for (var i = 0; i < h2; i++) { 148 | for (var j = 0; j < w2; j++) { 149 | px = j*x_ratio >>>0; 150 | py = i*y_ratio >>>0; 151 | this.resizeArray[i*w2+j] = pixels[py*w1+px]; 152 | } 153 | } 154 | } 155 | }); 156 | -------------------------------------------------------------------------------- /pocjs/Game.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.Game"); 2 | 3 | dojo.declare("pocjs.Game", null, { 4 | time: null, 5 | level: null, 6 | player: null, 7 | pauseTime: null, 8 | menu: null, 9 | 10 | constructor: function() { 11 | this.setMenu(new pocjs.menu.TitleMenu()); 12 | }, 13 | 14 | newGame: function() { 15 | pocjs.level.Level.clear(); 16 | this.level = pocjs.level.Level.loadLevel(this, "start"); 17 | this.player = new pocjs.entities.Player(); 18 | this.player.level = this.level; 19 | this.level.player = this.player; 20 | this.player.x = this.level.xSpawn; 21 | this.player.z = this.level.ySpawn; 22 | this.level.addEntity(this.player); 23 | this.player.rot = Math.PI + 0.4; 24 | }, 25 | 26 | 27 | switchLevel: function(name, id) { 28 | this.pauseTime = 30; 29 | this.level.removeEntityImmediately(this.player); 30 | this.level = pocjs.level.Level.loadLevel(this, name); 31 | this.level.findSpawn(id); 32 | this.player.x = this.level.xSpawn; 33 | this.player.z = this.level.ySpawn; 34 | this.level.getBlock(this.level.xSpawn, this.level.ySpawn).wait = true; 35 | this.player.x += Math.sin(this.player.rot) * 0.2; 36 | this.player.z += Math.cos(this.player.rot) * 0.2; 37 | this.level.addEntity(this.player); 38 | }, 39 | 40 | tick: function(keys) { 41 | if (this.pauseTime > 0) { 42 | this.pauseTime--; 43 | return; 44 | } 45 | 46 | var kmap = { 47 | w: "W".charCodeAt(), 48 | s: "S".charCodeAt(), 49 | a: "A".charCodeAt(), 50 | d: "D".charCodeAt(), 51 | q: "Q".charCodeAt(), 52 | e: "E".charCodeAt() 53 | }; 54 | 55 | this.time++; 56 | 57 | var dk = dojo.keys; 58 | 59 | var strafe = keys[dk.CTRL] || keys[dk.ALT] || keys[dk.META] || keys[dk.SHIFT]; 60 | 61 | var lk = keys[dk.LEFT_ARROW] || keys[dk.NUMPAD_4]; 62 | var rk = keys[dk.RIGHT_ARROW] || keys[dk.NUMPAD_6]; 63 | 64 | var up = keys[kmap.w] || keys[dk.UP_ARROW] || keys[dk.NUMPAD_8]; 65 | var down = keys[kmap.s] || keys[dk.DOWN_ARROW] || keys[dk.NUMPAD_2]; 66 | 67 | var left = keys[kmap.a] || (strafe && lk); 68 | var right = keys[kmap.d] || (strafe && rk); 69 | 70 | var turnLeft = keys[kmap.q] || (!strafe && lk); 71 | var turnRight = keys[kmap.e] || (!strafe && rk); 72 | 73 | var use = keys[dk.SPACE]; 74 | 75 | for (var i = 0; i < 8; i++) { 76 | if (keys["1".charCodeAt() + i]) { 77 | keys["1".charCodeAt() + i] = false; 78 | this.player.selectedSlot = i; 79 | this.player.itemUseTime = 0; 80 | } 81 | } 82 | 83 | if (keys[dk.ESCAPE]) { 84 | keys[dk.ESCAPE] = false; 85 | if (this.menu == null) { 86 | this.setMenu(new pocjs.menu.PauseMenu()); 87 | } 88 | } 89 | 90 | if (use) { 91 | keys[dk.SPACE] = false; 92 | } 93 | 94 | if (this.menu != null) { 95 | keys[kmap.w] = keys[dk.UP_ARROW] = keys[dk.NUMPAD_8] = false; 96 | keys[kmap.s] = keys[dk.DOWN_ARROW] = keys[dk.NUMPAD_2] = false; 97 | keys[kmap.a] = false; 98 | keys[kmap.d] = false; 99 | 100 | this.menu.tick(this, up, down, left, right, use); 101 | } 102 | else { 103 | this.player.tick(up, down, left, right, turnLeft, turnRight); 104 | if (use) { 105 | this.player.activate(); 106 | } 107 | 108 | this.level.tick(); 109 | } 110 | }, 111 | 112 | getLoot: function(item) { 113 | this.player.addLoot(item); 114 | }, 115 | 116 | win: function(player) { 117 | this.setMenu(new pocjs.menu.WinMenu(player)); 118 | }, 119 | 120 | setMenu: function(menu) { 121 | this.menu = menu; 122 | }, 123 | 124 | lose: function(player) { 125 | this.setMenu(new pocjs.menu.LoseMenu(player)); 126 | } 127 | }); 128 | -------------------------------------------------------------------------------- /pocjs/InputHandler.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.InputHandler"); 2 | 3 | dojo.declare("pocjs.InputHandler", null, { 4 | keys: [], 5 | 6 | keyup: function(evt) { 7 | this.keys[evt.keyCode] = false; 8 | // console.log("up keycode: " + evt.keyCode); 9 | evt.preventDefault(); 10 | }, 11 | 12 | keydown: function(evt) { 13 | this.keys[evt.keyCode] = true; 14 | evt.preventDefault(); 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /pocjs/Sound.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.Sound"); 2 | 3 | dojo.declare("pocjs.Sound", null, { 4 | }); 5 | 6 | dojo.mixin(pocjs.Sound, { 7 | loadSound: function(name) { 8 | var dfd = new dojo.Deferred(); 9 | var audio = new Audio(); 10 | audio.addEventListener("canplay", function(res) { 11 | if (dfd.fired == -1) dfd.resolve(name); 12 | }, false); 13 | audio.src = "res/snd/" + name + ".wav"; 14 | this[name] = audio; 15 | return dfd; 16 | } 17 | }); 18 | 19 | -------------------------------------------------------------------------------- /pocjs/all.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.all"); 2 | 3 | dojo.require("dojo.DeferredList"); 4 | 5 | dojo.require("pocjs.InputHandler"); 6 | dojo.require("pocjs.Sound"); 7 | dojo.require("pocjs.Art"); 8 | 9 | dojo.require("pocjs.gui.Bitmap"); 10 | dojo.require("pocjs.gui.Bitmap3D"); 11 | dojo.require("pocjs.gui.Sprite"); 12 | dojo.require("pocjs.gui.PoofSprite"); 13 | dojo.require("pocjs.gui.RubbleSprite"); 14 | 15 | dojo.require("pocjs.entities.Item"); 16 | 17 | dojo.require("pocjs.menu.Menu"); 18 | dojo.require("pocjs.menu.AboutMenu"); 19 | dojo.require("pocjs.menu.GotLootMenu"); 20 | dojo.require("pocjs.menu.InstructionsMenu"); 21 | dojo.require("pocjs.menu.LoseMenu"); 22 | dojo.require("pocjs.menu.PauseMenu"); 23 | dojo.require("pocjs.menu.TitleMenu"); 24 | dojo.require("pocjs.menu.WinMenu"); 25 | 26 | dojo.require("pocjs.entities.Entity"); 27 | dojo.require("pocjs.entities.Player"); 28 | 29 | dojo.require("pocjs.entities.EnemyEntity"); 30 | dojo.require("pocjs.entities.BatBossEntity"); 31 | dojo.require("pocjs.entities.BatEntity"); 32 | dojo.require("pocjs.entities.BossOgre"); 33 | dojo.require("pocjs.entities.BoulderEntity"); 34 | dojo.require("pocjs.entities.Bullet"); 35 | dojo.require("pocjs.entities.EyeBossEntity"); 36 | dojo.require("pocjs.entities.EyeEntity"); 37 | dojo.require("pocjs.entities.GhostBossEntity"); 38 | dojo.require("pocjs.entities.GhostEntity"); 39 | dojo.require("pocjs.entities.KeyEntity"); 40 | dojo.require("pocjs.entities.OgreEntity"); 41 | 42 | dojo.require("pocjs.level.block.Block"); 43 | dojo.require("pocjs.level.block.SolidBlock"); 44 | 45 | dojo.require("pocjs.level.block.DoorBlock"); 46 | dojo.require("pocjs.level.block.LockedDoorBlock"); 47 | 48 | dojo.require("pocjs.level.block.AltarBlock"); 49 | dojo.require("pocjs.level.block.BarsBlock"); 50 | dojo.require("pocjs.level.block.ChestBlock"); 51 | dojo.require("pocjs.level.block.FinalUnlockBlock"); 52 | dojo.require("pocjs.level.block.IceBlock"); 53 | dojo.require("pocjs.level.block.LadderBlock"); 54 | dojo.require("pocjs.level.block.LootBlock"); 55 | dojo.require("pocjs.level.block.PitBlock"); 56 | dojo.require("pocjs.level.block.PressurePlateBlock"); 57 | dojo.require("pocjs.level.block.SpiritWallBlock"); 58 | dojo.require("pocjs.level.block.SwitchBlock"); 59 | dojo.require("pocjs.level.block.TorchBlock"); 60 | dojo.require("pocjs.level.block.VanishBlock"); 61 | dojo.require("pocjs.level.block.WaterBlock"); 62 | dojo.require("pocjs.level.block.WinBlock"); 63 | 64 | dojo.require("pocjs.level.Level"); 65 | 66 | dojo.require("pocjs.level.CryptLevel"); 67 | dojo.require("pocjs.level.DungeonLevel"); 68 | dojo.require("pocjs.level.DungeonLevel"); 69 | dojo.require("pocjs.level.IceLevel"); 70 | dojo.require("pocjs.level.OverworldLevel"); 71 | dojo.require("pocjs.level.StartLevel"); 72 | dojo.require("pocjs.level.TempleLevel"); 73 | 74 | dojo.require("pocjs.Game"); 75 | 76 | dojo.require("pocjs.gui.Screen"); 77 | 78 | dojo.require("pocjs.EscapeComponent"); 79 | 80 | //dojo.declare("pocjs.all", null, {}); 81 | 82 | -------------------------------------------------------------------------------- /pocjs/entities/BatBossEntity.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.entities.BatBossEntity"); 2 | 3 | dojo.declare("pocjs.entities.BatBossEntity", pocjs.entities.EnemyEntity, { 4 | 5 | "-chains-": {constructor: "manual"}, 6 | constructor: function(x, z) { 7 | this.inherited(arguments, [x, z, 4 * 8, pocjs.Art.getCol(0xffff00)]); 8 | this.x = x; 9 | this.z = z; 10 | this.health = 5; 11 | this.r = 0.3; 12 | 13 | this.flying = true; 14 | }, 15 | 16 | die: function() { 17 | pocjs.Sound.bosskill.play(); 18 | this.level.addEntity(new pocjs.entities.KeyEntity(this.x, this.z)); 19 | }, 20 | 21 | tick: function() { 22 | this.inherited(arguments); 23 | if (Math.random() * 20 < 1) { 24 | var xx = this.x + (Math.random() - 0.5) * 2; 25 | var zz = this.z + (Math.random() - 0.5) * 2; 26 | var batEntity = new pocjs.entities.BatEntity(xx, zz); 27 | batEntity.level = this.level; 28 | 29 | if (batEntity.isFree(xx, zz)) { 30 | this.level.addEntity(batEntity); 31 | } 32 | } 33 | } 34 | }); 35 | 36 | -------------------------------------------------------------------------------- /pocjs/entities/BatEntity.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.entities.BatEntity"); 2 | 3 | dojo.declare("pocjs.entities.BatEntity", pocjs.entities.EnemyEntity, { 4 | 5 | "-chains-": {constructor: "manual"}, 6 | constructor: function(x, z) { 7 | this.inherited(arguments, [x, z, 4 * 8, pocjs.Art.getCol(0x82666E)]); 8 | this.x = x; 9 | this.z = z; 10 | this.health = 2; 11 | this.r = 0.3; 12 | 13 | this.flying = true; 14 | } 15 | }); 16 | 17 | -------------------------------------------------------------------------------- /pocjs/entities/BossOgre.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.entities.BossOgre"); 2 | 3 | dojo.declare("pocjs.entities.BossOgre", pocjs.entities.EnemyEntity, { 4 | 5 | shootDelay: null, 6 | shootPhase: null, 7 | 8 | 9 | "-chains-": {constructor: "manual"}, 10 | constructor: function(x, z) { 11 | this.inherited(arguments, [x, z, 4 * 8 + 2, pocjs.Art.getCol(0xffff00)]); 12 | this.x = x; 13 | this.z = z; 14 | this.health = 10; 15 | this.r = 0.4; 16 | this.spinSpeed = 0.05; 17 | }, 18 | 19 | die: function() { 20 | pocjs.Sound.bosskill.play(); 21 | this.level.addEntity(new pocjs.entities.KeyEntity(this.x, this.z)); 22 | }, 23 | 24 | tick: function() { 25 | this.inherited(arguments); 26 | if (this.shootDelay > 0) this.shootDelay--; 27 | else { 28 | this.shootDelay = 5; 29 | var salva = 10; 30 | 31 | for (var i = 0; i < 4; i++) { 32 | var rot = Math.PI / 2 * (i + this.shootPhase / salva % 2 * 0.5); 33 | this.level.addEntity( 34 | new pocjs.entities.Bullet( 35 | this, this.x, this.z, rot, 0.4, 1, this.defaultColor 36 | )); 37 | } 38 | 39 | this.shootPhase++; 40 | if (this.shootPhase % salva == 0) this.shootDelay = 40; 41 | } 42 | } 43 | 44 | }); 45 | 46 | -------------------------------------------------------------------------------- /pocjs/entities/BoulderEntity.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.entities.BoulderEntity"); 2 | 3 | dojo.declare("pocjs.entities.BoulderEntity", pocjs.entities.Entity, { 4 | COLOR: pocjs.Art.getCol(0xAFA293), 5 | sprite: null, 6 | rollDist: 0, 7 | 8 | constructor: function(x, z) { 9 | this.x = x; 10 | this.z = z; 11 | this.sprite = new pocjs.gui.Sprite(0, 0, 0, 16, this.COLOR); 12 | this.sprites.push(this.sprite); 13 | }, 14 | 15 | tick: function() { 16 | this.rollDist += Math.sqrt(this.xa * this.xa + this.za * this.za); 17 | this.sprite.tex = 8 + ((this.rollDist * 4) & 1); 18 | var xao = this.xa; 19 | var zao = this.za; 20 | this.move(); 21 | if (this.xa == 0 && xao != 0) this.xa = -xao * 0.3; 22 | if (this.za == 0 && zao != 0) this.za = -zao * 0.3; 23 | this.xa *= 0.98; 24 | this.za *= 0.98; 25 | if (this.xa * this.xa + this.za * this.za < 0.0001) { 26 | this.xa = this.za = 0; 27 | } 28 | }, 29 | 30 | use: function(source, item) { 31 | if (item != pocjs.entities.Item.powerGlove) return false; 32 | pocjs.Sound.roll.play(); 33 | 34 | this.xa += Math.sin(source.rot) * 0.1; 35 | this.za += Math.cos(source.rot) * 0.1; 36 | return true; 37 | } 38 | }); 39 | -------------------------------------------------------------------------------- /pocjs/entities/Bullet.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.entities.Bullet"); 2 | 3 | dojo.declare("pocjs.entities.Bullet", pocjs.entities.Entity, { 4 | owner: null, 5 | 6 | constructor: function(owner, x, z, rot, pow, sprite, col) { 7 | this.r = 0.01; 8 | this.owner = owner; 9 | 10 | this.xa = Math.sin(rot) * 0.2 * pow; 11 | this.za = Math.cos(rot) * 0.2 * pow; 12 | this.x = x - this.za / 2; 13 | this.z = z + this.xa / 2; 14 | 15 | this.sprites.push( 16 | new pocjs.gui.Sprite( 17 | 0, 0, 0, 8 * 3 + sprite, pocjs.Art.getCol(col) 18 | ) 19 | ); 20 | 21 | this.flying = true; 22 | }, 23 | 24 | tick: function() { 25 | var xao = this.xa; 26 | var zao = this.za; 27 | this.move(); 28 | 29 | if ((this.xa == 0 && this.za == 0) || this.xa != xao || this.za != zao) { 30 | this.remove(); 31 | } 32 | }, 33 | 34 | blocks: function(entity, x2, z2, r2) { 35 | if (entity instanceof pocjs.entities.Bullet) { 36 | return false; 37 | } 38 | if (entity === this.owner) return false; 39 | 40 | return this.inherited(arguments); 41 | }, 42 | 43 | collide: function(entity) { 44 | } 45 | }); 46 | 47 | -------------------------------------------------------------------------------- /pocjs/entities/EnemyEntity.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.entities.EnemyEntity"); 2 | 3 | dojo.declare("pocjs.entities.EnemyEntity", pocjs.entities.Entity, { 4 | 5 | sprite: null, 6 | rot: 0, 7 | rota: 0, 8 | defaultTex: null, 9 | defaultColor: null, 10 | hurtTime: 0, 11 | animTime: 0, 12 | health: 3, 13 | spinSpeed: 0.1, 14 | runSpeed: 1, 15 | 16 | constructor: function(x, z, defaultTex, defaultColor) { 17 | 18 | this.inherited(arguments); 19 | this.x = x; 20 | this.z = z; 21 | this.defaultColor = defaultColor; 22 | this.defaultTex = defaultTex; 23 | this.sprite = new pocjs.gui.Sprite(0, 0, 0, 4 * 8, defaultColor); 24 | this.sprites.push(this.sprite); 25 | this.r = 0.3; 26 | }, 27 | 28 | haveNextGaussian: false, 29 | nextNextGaussian: null, 30 | nextGaussian: function() { 31 | if (this.haveNextNextGaussian) { 32 | this.haveNextNextGaussian = false; 33 | return this.nextNextGaussian; 34 | } 35 | else { 36 | var v1, v2, s; 37 | do { 38 | v1 = 2 * Math.random() - 1; // between -1.0 and 1.0 39 | v2 = 2 * Math.random() - 1; // between -1.0 and 1.0 40 | s = v1 * v1 + v2 * v2; 41 | } while (s >= 1 || s == 0); 42 | var multiplier = Math.sqrt(-2 * Math.log(s)/s); 43 | this.nextNextGaussian = v2 * multiplier; 44 | this.haveNextNextGaussian = true; 45 | return v1 * multiplier; 46 | } 47 | }, 48 | 49 | tick: function() { 50 | if (this.hurtTime > 0) { 51 | this.hurtTime--; 52 | if (this.hurtTime == 0) { 53 | this.sprite.col = this.defaultColor; 54 | } 55 | } 56 | this.animTime++; 57 | this.sprite.tex = this.defaultTex + (this.animTime / 10 <<0) % 2; 58 | this.move(); 59 | if (this.xa == 0 || this.za == 0) { 60 | this.rota += (this.nextGaussian() * Math.random()) * 0.3; 61 | } 62 | 63 | this.rota += (this.nextGaussian() * Math.random()) * this.spinSpeed; 64 | this.rot += this.rota; 65 | this.rota *= 0.8; 66 | this.xa *= 0.8; 67 | this.za *= 0.8; 68 | this.xa += Math.sin(this.rot) * 0.004 * this.runSpeed; 69 | this.za += Math.cos(this.rot) * 0.004 * this.runSpeed; 70 | }, 71 | 72 | use: function(source, item) { 73 | if (this.hurtTime > 0) return false; 74 | if (item != pocjs.entities.Item.powerGlove) return false; 75 | 76 | this.hurt(Math.sin(source.rot), Math.cos(source.rot)); 77 | 78 | return true; 79 | }, 80 | 81 | hurt: function(xd, zd) { 82 | this.sprite.col = pocjs.Art.getCol(0xff0000); 83 | this.hurtTime = 15; 84 | 85 | var dd = Math.sqrt(xd * xd + zd * zd); 86 | this.xa += xd / dd * 0.2; 87 | this.za += zd / dd * 0.2; 88 | pocjs.Sound.hurt2.play(); 89 | this.health--; 90 | if (this.health <= 0) { 91 | var xt = (this.x + 0.5) << 0; 92 | var zt = (this.z + 0.5) << 0; 93 | this.level.getBlock(xt, zt) 94 | .addSprite(new pocjs.gui.PoofSprite(this.x - xt, 0, this.z - zt)); 95 | this.die(); 96 | this.remove(); 97 | pocjs.Sound.kill.play(); 98 | } 99 | }, 100 | 101 | die: function() { 102 | 103 | }, 104 | 105 | collide: function(entity) { 106 | if (entity instanceof pocjs.entities.Bullet) { 107 | var bullet = entity; 108 | if (bullet.owner.declaredClass == this.declaredClass) { 109 | return; 110 | } 111 | if (this.hurtTime > 0) return; 112 | entity.remove(); 113 | this.hurt(entity.xa, entity.za); 114 | } 115 | if (entity instanceof pocjs.entities.Player) { 116 | entity.hurt(this, 1); 117 | } 118 | } 119 | }); 120 | -------------------------------------------------------------------------------- /pocjs/entities/Entity.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.entities.Entity"); 2 | 3 | 4 | dojo.declare("pocjs.entities.Entity", null, { 5 | 6 | sprites: null, 7 | 8 | x: 0, z: 0, rot: 0, 9 | xa: 0, za: 0, rota: 0, 10 | r: 0.4, 11 | 12 | level: null, 13 | xTileO: -1, 14 | zTileO: -1, 15 | flying: false, 16 | 17 | removed: false, 18 | 19 | //constructor: function(a, b, c, d) { 20 | constructor: function(x, z, defaultTex, defaultColor) { 21 | this.sprites = []; 22 | }, 23 | updatePos: function() { 24 | var xTile = (this.x + 0.5) << 0; 25 | var zTile = (this.z + 0.5) << 0; 26 | if (xTile != this.xTileO || zTile != this.zTileO) { 27 | this.level.getBlock(this.xTileO, this.zTileO).removeEntity(this); 28 | 29 | this.xTileO = xTile; 30 | this.zTileO = zTile; 31 | 32 | if (!this.removed) this.level.getBlock(this.xTileO, this.zTileO).addEntity(this); 33 | } 34 | }, 35 | 36 | isRemoved: function() { 37 | return this.removed; 38 | }, 39 | 40 | remove: function() { 41 | this.level.getBlock(this.xTileO, this.zTileO).removeEntity(this); 42 | this.removed = true; 43 | }, 44 | 45 | move: function() { 46 | 47 | var xSteps = (Math.abs(this.xa * 100) + 1) << 0; 48 | for (var i = xSteps; i > 0; i--) { 49 | var xxa = this.xa; 50 | if (this.isFree(this.x + xxa * i / xSteps, this.z)) { 51 | this.x += xxa * i / xSteps; 52 | break; 53 | } else { 54 | this.xa = 0; 55 | } 56 | } 57 | 58 | var zSteps = (Math.abs(this.za * 100) + 1) << 0; 59 | for (var i = zSteps; i > 0; i--) { 60 | var zza = this.za; 61 | if (this.isFree(this.x, this.z + zza * i / zSteps)) { 62 | this.z += zza * i / zSteps; 63 | break; 64 | } else { 65 | this.za = 0; 66 | } 67 | } 68 | }, 69 | 70 | isFree: function(xx, yy) { 71 | var x0 = Math.floor(xx + 0.5 - this.r); 72 | var x1 = Math.floor(xx + 0.5 + this.r); 73 | var y0 = Math.floor(yy + 0.5 - this.r); 74 | var y1 = Math.floor(yy + 0.5 + this.r); 75 | 76 | 77 | if (this.level.getBlock(x0, y0).blocks(this)) return false; 78 | if (this.level.getBlock(x1, y0).blocks(this)) return false; 79 | if (this.level.getBlock(x0, y1).blocks(this)) return false; 80 | if (this.level.getBlock(x1, y1).blocks(this)) return false; 81 | 82 | var xc = Math.floor(xx + 0.5); 83 | var zc = Math.floor(yy + 0.5); 84 | var rr = 2; 85 | for (var z = zc - rr; z <= zc + rr; z++) { 86 | for (var x = xc - rr; x <= xc + rr; x++) { 87 | var es = this.level.getBlock(x, z).entities; 88 | for (var i = 0; i < es.length; i++) { 89 | var e = es[i]; 90 | if (e == this) continue; 91 | 92 | if (e.blocks(this, xx, yy, this.r)) { 93 | e.collide(this); 94 | this.collide(e); 95 | return false; 96 | } 97 | } 98 | } 99 | } 100 | return true; 101 | }, 102 | 103 | collide: function(entity) { 104 | }, 105 | 106 | blocks: function(entity, x2, z2, r2) { 107 | if (entity instanceof pocjs.entities.Bullet) { 108 | if (entity.owner == this) return false; 109 | } 110 | if (this.x + this.r <= x2 - r2) return false; 111 | if (this.x - this.r >= x2 + r2) return false; 112 | 113 | if (this.z + this.r <= z2 - r2) return false; 114 | if (this.z - this.r >= z2 + r2) return false; 115 | 116 | return true; 117 | }, 118 | 119 | contains: function(x2, z2) { 120 | if (this.x + this.r <= x2) return false; 121 | if (this.x - this.r >= x2) return false; 122 | 123 | if (this.z + this.r <= z2) return false; 124 | if (this.z - this.r >= z2) return false; 125 | 126 | return true; 127 | }, 128 | 129 | isInside: function(x0, z0, x1, z1) { 130 | if (this.x + this.r <= x0) return false; 131 | if (this.x - this.r >= x1) return false; 132 | 133 | if (this.z + this.r <= z0) return false; 134 | if (this.z - this.r >= z1) return false; 135 | 136 | return true; 137 | }, 138 | 139 | use: function(source, item) { 140 | return false; 141 | }, 142 | 143 | tick: function() { 144 | } 145 | }); 146 | 147 | -------------------------------------------------------------------------------- /pocjs/entities/EyeBossEntity.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.entities.EyeBossEntity"); 2 | 3 | dojo.declare("pocjs.entities.EyeBossEntity", pocjs.entities.EnemyEntity, { 4 | 5 | 6 | "-chains-": {constructor: "manual"}, 7 | constructor: function(x, z) { 8 | this.inherited(arguments, [x, z, 4 * 8 + 4, pocjs.Art.getCol(0xffff00)]); 9 | this.x = x; 10 | this.z = z; 11 | this.health = 10; 12 | this.r = 0.3; 13 | this.runSpeed = 4; 14 | this.spinSpeed *= 1.5; 15 | 16 | this.flying = true; 17 | }, 18 | 19 | die: function() { 20 | pocjs.Sound.bosskill.play(); 21 | this.level.addEntity(new pocjs.entities.KeyEntity(this.x, this.z)); 22 | } 23 | }); 24 | -------------------------------------------------------------------------------- /pocjs/entities/EyeEntity.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.entities.EyeEntity"); 2 | 3 | dojo.declare("pocjs.entities.EyeEntity", pocjs.entities.EnemyEntity, { 4 | 5 | "-chains-": {constructor: "manual"}, 6 | 7 | constructor: function(x, z) { 8 | this.inherited(arguments, [x, z, 4 * 8+4, pocjs.Art.getCol(0x84ECFF)]); 9 | this.x = x; 10 | this.z = z; 11 | this.health = 4; 12 | this.r = 0.3; 13 | this.runSpeed = 2; 14 | this.spinSpeed *= 1.5; 15 | 16 | this.flying = true; 17 | } 18 | }); 19 | -------------------------------------------------------------------------------- /pocjs/entities/GhostBossEntity.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.entities.GhostBossEntity"); 2 | 3 | dojo.declare("pocjs.entities.GhostBossEntity", pocjs.entities.EnemyEntity, { 4 | rotatePos: 0, 5 | shootDelay: 0, 6 | 7 | 8 | "-chains-": {constructor: "manual"}, 9 | constructor: function(x, z) { 10 | this.inherited(arguments, [x, z, 4 * 8 + 6, pocjs.Art.getCol(0xffff00)]); 11 | this.x = x; 12 | this.z = z; 13 | this.health = 10; 14 | this.flying = true; 15 | }, 16 | 17 | tick: function() { 18 | this.animTime++; 19 | this.sprite.tex = this.defaultTex + (this.animTime / 10 | 0 ) % 2; 20 | 21 | var xd = (this.level.player.x + Math.sin(this.rotatePos) * 2) - this.x; 22 | var zd = (this.level.player.z + Math.cos(this.rotatePos) * 2) - this.z; 23 | var dd = xd * xd + zd * zd; 24 | 25 | if (dd < 1) { 26 | this.rotatePos += 0.04; 27 | } else { 28 | this.rotatePos = this.level.player.rot; 29 | } 30 | if (dd < 4 * 4) { 31 | dd = Math.sqrt(dd); 32 | 33 | xd /= dd; 34 | zd /= dd; 35 | 36 | this.xa += xd * 0.006; 37 | this.za += zd * 0.006; 38 | 39 | if (this.shootDelay > 0) this.shootDelay--; 40 | else if ((Math.random() * 10 | 0) == 0) { 41 | this.shootDelay = 10; 42 | this.level.addEntity( 43 | new pocjs.entities.Bullet( 44 | this, this.x, this.z, 45 | Math.atan2( this.level.player.x - this.x, this.level.player.z - this.z), 46 | 0.20, 1, this.defaultColor)); 47 | } 48 | 49 | } 50 | 51 | this.move(); 52 | 53 | this.xa *= 0.9; 54 | this.za *= 0.9; 55 | }, 56 | 57 | hurt: function(xd, zd) { 58 | }, 59 | 60 | move: function() { 61 | this.x += this.xa; 62 | this.z += this.za; 63 | } 64 | }); 65 | 66 | -------------------------------------------------------------------------------- /pocjs/entities/GhostEntity.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.entities.GhostEntity"); 2 | 3 | dojo.declare("pocjs.entities.GhostEntity", pocjs.entities.EnemyEntity, { 4 | rotatePos: 0, 5 | 6 | 7 | "-chains-": {constructor: "manual"}, 8 | constructor: function(x, z) { 9 | this.inherited(arguments, [x, z, 4 * 8 + 6, pocjs.Art.getCol(0xffffff)]); 10 | this.x = x; 11 | this.z = z; 12 | this.health = 4; 13 | this.r = 0.3; 14 | 15 | this.flying = true; 16 | }, 17 | 18 | tick: function() { 19 | this.animTime++; 20 | this.sprite.tex = this.defaultTex + (this.animTime / 10 << 0) % 2; 21 | 22 | var xd = (this.level.player.x + Math.sin(this.rotatePos)) - this.x; 23 | var zd = (this.level.player.z + Math.cos(this.rotatePos)) - this.z; 24 | var dd = xd * xd + zd * zd; 25 | 26 | if (dd < 4 * 4) { 27 | if (dd < 1) { 28 | this.rotatePos += 0.04; 29 | } else { 30 | this.rotatePos = this.level.player.rot; 31 | this.xa += (Math.random() - 0.5) * 0.02; 32 | this.za += (Math.random() - 0.5) * 0.02; 33 | } 34 | 35 | dd = Math.sqrt(dd); 36 | 37 | xd /= dd; 38 | zd /= dd; 39 | 40 | this.xa += xd * 0.004; 41 | this.za += zd * 0.004; 42 | } 43 | 44 | this.move(); 45 | 46 | this.xa *= 0.9; 47 | this.za *= 0.9; 48 | }, 49 | 50 | hurt: function(xd, zd) { 51 | }, 52 | 53 | move: function() { 54 | this.x += this.xa; 55 | this.z += this.za; 56 | } 57 | }); 58 | -------------------------------------------------------------------------------- /pocjs/entities/Item.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.entities.Item"); 2 | 3 | dojo.declare("pocjs.entities.Item", null, { 4 | 5 | icon: null, 6 | color: null, 7 | name: null, 8 | description: null, 9 | 10 | constructor: function(icon, color, name, description) { 11 | this.icon = icon; 12 | this.color = color; 13 | this.name = name; 14 | this.description = description; 15 | } 16 | 17 | }); 18 | 19 | dojo.mixin(pocjs.entities.Item, { 20 | none: new pocjs.entities.Item(-1, 0xFFC363, "", ""), 21 | powerGlove: new pocjs.entities.Item(0, 0xFFC363, "Power Glove", "Smaaaash!!"), 22 | pistol: new pocjs.entities.Item(1, 0xEAEAEA, "Pistol", "Pew, pew, pew!"), 23 | flippers: new pocjs.entities.Item(2, 0x7CBBFF, "Flippers", "Splish splash!"), 24 | cutters: new pocjs.entities.Item(3, 0xCCCCCC, "Cutters", "Snip, snip!"), 25 | skates: new pocjs.entities.Item(4, 0xAE70FF, "Skates", "Sharp!"), 26 | key: new pocjs.entities.Item(5, 0xFF4040, "Key", "How did you get this?"), 27 | potion: new pocjs.entities.Item(6, 0x4AFF47, "Potion", "Healthy!") 28 | }); 29 | -------------------------------------------------------------------------------- /pocjs/entities/KeyEntity.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.entities.KeyEntity"); 2 | 3 | dojo.declare("pocjs.entities.KeyEntity", pocjs.entities.Entity, { 4 | COLOR: pocjs.Art.getCol(0x00ffff), 5 | sprite: null, 6 | y: null, ya: null, 7 | 8 | constructor: function(x, z) { 9 | this.x = x; 10 | this.z = z; 11 | this.y = 0.5; 12 | this.ya = 0.025; 13 | this.sprite = new pocjs.gui.Sprite(0, 0, 0, 16 + 3, this.COLOR); 14 | this.sprites.push(this.sprite); 15 | }, 16 | 17 | tick: function() { 18 | this.move(); 19 | this.y += this.ya; 20 | if (this.y < 0) this.y = 0; 21 | this.ya -= 0.005; 22 | this.sprite.y = this.y; 23 | }, 24 | 25 | collide: function(entity) { 26 | if (entity instanceof pocjs.entities.Player) { 27 | pocjs.Sound.key.play(); 28 | entity.keys++; 29 | this.remove(); 30 | } 31 | } 32 | }); 33 | -------------------------------------------------------------------------------- /pocjs/entities/OgreEntity.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.entities.OgreEntity"); 2 | 3 | dojo.declare("pocjs.entities.OgreEntity", pocjs.entities.EnemyEntity, { 4 | 5 | shootDelay: null, 6 | 7 | 8 | "-chains-": {constructor: "manual"}, 9 | constructor: function(x, z) { 10 | this.inherited(arguments, [x, z, 4 * 8 + 2, pocjs.Art.getCol(0x82A821)]); 11 | this.x = x; 12 | this.z = z; 13 | this.health = 6; 14 | this.r = 0.4; 15 | this.spinSpeed = 0.05; 16 | }, 17 | 18 | hurt: function(xd, zd) { 19 | this.inherited(arguments); 20 | this.shootDelay = 50; 21 | }, 22 | 23 | tick: function() { 24 | this.inherited(arguments); 25 | if (this.shootDelay > 0) this.shootDelay--; 26 | else if ((Math.random() * 40 << 0) == 0) { 27 | this.shootDelay = 40; 28 | this.level.addEntity( 29 | new pocjs.entities.Bullet( 30 | this, this.x, this.z, 31 | Math.atan2( 32 | this.level.player.x - this.x, this.level.player.z - this.z 33 | ), 34 | 0.3, 1, this.defaultColor)); 35 | } 36 | } 37 | }); 38 | -------------------------------------------------------------------------------- /pocjs/entities/Player.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.entities.Player"); 2 | 3 | dojo.declare("pocjs.entities.Player", pocjs.entities.Entity, { 4 | bob: null, bobPhase: null, turnBob: null, 5 | selectedSlot: 0, 6 | itemUseTime: 0, 7 | y: null, ya: null, 8 | hurtTime: 0, 9 | health: 20, 10 | keys: 0, 11 | loot: 0, 12 | dead: false, 13 | deadTime: 0, 14 | ammo: 0, 15 | potions: 0, 16 | lastBlock: null, 17 | 18 | items: null, 19 | 20 | constructor: function() { 21 | this.r = 0.3; 22 | this.items = new Array(8); 23 | for (var i = 0; i < this.items.length; i++) { 24 | this.items[i] = pocjs.entities.Item.none; 25 | } 26 | }, 27 | 28 | sliding: false, 29 | time: null, 30 | 31 | tick: function(up, down, left, right, turnLeft, turnRight) { 32 | if (this.dead) { 33 | up = down = left = right = turnLeft = turnRight = false; 34 | this.deadTime++; 35 | if (this.deadTime > 60 * 2) { 36 | this.level.lose(); 37 | } 38 | } 39 | else { 40 | this.time++; 41 | } 42 | 43 | if (this.itemUseTime > 0) this.itemUseTime--; 44 | if (this.hurtTime > 0) this.hurtTime--; 45 | 46 | var onBlock = this.level.getBlock((this.x + 0.5) << 0, (this.z + 0.5) << 0); 47 | 48 | var fh = onBlock.getFloorHeight(this); 49 | if (onBlock instanceof pocjs.level.block.WaterBlock 50 | && !(this.lastBlock instanceof pocjs.level.block.WaterBlock)) { 51 | pocjs.Sound.splash.play(); 52 | } 53 | 54 | this.lastBlock = onBlock; 55 | 56 | if (this.dead) fh = -0.6; 57 | if (fh > this.y) { 58 | this.y += (fh - this.y) * 0.2; 59 | this.ya = 0; 60 | } else { 61 | this.ya -= 0.01; 62 | this.y += this.ya; 63 | if (this.y < fh) { 64 | this.y = fh; 65 | this.ya = 0; 66 | } 67 | } 68 | 69 | var rotSpeed = 0.05; 70 | var walkSpeed = 0.03 * onBlock.getWalkSpeed(this); 71 | 72 | if (turnLeft) this.rota += rotSpeed; 73 | if (turnRight) this.rota -= rotSpeed; 74 | 75 | var xm = 0; 76 | var zm = 0; 77 | if (up) zm--; 78 | if (down) zm++; 79 | if (left) xm--; 80 | if (right) xm++; 81 | var dd = xm * xm + zm * zm; 82 | if (dd > 0) dd = Math.sqrt(dd); 83 | else dd = 1; 84 | xm /= dd; 85 | zm /= dd; 86 | 87 | this.bob *= 0.6; 88 | this.turnBob *= 0.8; 89 | this.turnBob += this.rota; 90 | this.bob += Math.sqrt(xm * xm + zm * zm); 91 | this.bobPhase += Math.sqrt(xm * xm + zm * zm) * onBlock.getWalkSpeed(this); 92 | var wasSliding = this.sliding; 93 | this.sliding = false; 94 | 95 | if (onBlock instanceof pocjs.level.block.IceBlock 96 | && this.getSelectedItem() != pocjs.entities.Item.skates) { 97 | if (this.xa * this.xa > this.za * this.za) { 98 | this.sliding = true; 99 | this.za = 0; 100 | if (this.xa > 0) this.xa = 0.08; 101 | else this.xa = -0.08; 102 | this.z += ( Math.floor(this.z + 0.5) - this.z) * 0.2; 103 | } 104 | else if (this.xa * this.xa < this.za * this.za) { 105 | this.sliding = true; 106 | this.xa = 0; 107 | if (this.za > 0) this.za = 0.08; 108 | else this.za = -0.08; 109 | this.x += ( Math.floor(this.x + 0.5) - this.x) * 0.2; 110 | } 111 | else { 112 | this.xa -= (xm * Math.cos(this.rot) + zm * Math.sin(this.rot)) * 0.1; 113 | this.za -= (zm * Math.cos(this.rot) - xm * Math.sin(this.rot)) * 0.1; 114 | } 115 | 116 | if (!wasSliding && this.sliding) { 117 | pocjs.Sound.slide.play(); 118 | } 119 | } 120 | else { 121 | this.xa -= (xm * Math.cos(this.rot) + zm * Math.sin(this.rot)) * walkSpeed; 122 | this.za -= (zm * Math.cos(this.rot) - xm * Math.sin(this.rot)) * walkSpeed; 123 | } 124 | 125 | this.move(); 126 | 127 | var friction = onBlock.getFriction(this); 128 | this.xa *= friction; 129 | this.za *= friction; 130 | this.rot += this.rota; 131 | this.rota *= 0.4; 132 | }, 133 | 134 | activate: function() { 135 | if (this.dead) return; 136 | if (this.itemUseTime > 0) return; 137 | var item = this.items[this.selectedSlot]; 138 | if (item == pocjs.entities.Item.pistol) { 139 | if (this.ammo > 0) { 140 | pocjs.Sound.shoot.play(); 141 | this.itemUseTime = 10; 142 | this.level.addEntity( 143 | new pocjs.entities.Bullet( 144 | this, this.x, this.z, this.rot, 1, 0, 0xffffff)); 145 | this.ammo--; 146 | } 147 | return; 148 | } 149 | if (item == pocjs.entities.Item.potion) { 150 | if (this.potions > 0 && this.health < 20) { 151 | pocjs.Sound.potion.play(); 152 | this.itemUseTime = 20; 153 | this.health += 5 + (Math.random() * 6 << 0); 154 | if (this.health > 20) this.health = 20; 155 | this.potions--; 156 | } 157 | return; 158 | } 159 | if (item == pocjs.entities.Item.key) this.itemUseTime = 10; 160 | if (item == pocjs.entities.Item.powerGlove) this.itemUseTime = 10; 161 | if (item == pocjs.entities.Item.cutters) this.itemUseTime = 10; 162 | 163 | var xa = (2 * Math.sin(this.rot)); 164 | var za = (2 * Math.cos(this.rot)); 165 | 166 | var rr = 3; 167 | var xc = (this.x + 0.5) << 0; 168 | var zc = (this.z + 0.5) << 0; 169 | var possibleHits = []; 170 | for (var z = zc - rr; z <= zc + rr; z++) { 171 | for (var x = xc - rr; x <= xc + rr; x++) { 172 | var es = this.level.getBlock(x, z).entities; 173 | for (var i = 0; i < es.length; i++) { 174 | var e = es[i]; 175 | if (e == this) continue; 176 | possibleHits.push(e); 177 | } 178 | } 179 | } 180 | 181 | var divs = 100; 182 | for (var i = 0; i < divs; i++) { 183 | var xx = this.x + xa * i / divs; 184 | var zz = this.z + za * i / divs; 185 | for (var j = 0; j < possibleHits.length; j++) { 186 | var e = possibleHits[j]; 187 | if (e.contains(xx, zz)) { 188 | if (e.use(this, this.items[this.selectedSlot])) { 189 | return; 190 | } 191 | } 192 | 193 | } 194 | if (this.level.getBlock( (xx + 0.5) << 0, (zz + 0.5) << 0) 195 | .use( this.level, this.items[this.selectedSlot])) { 196 | return; 197 | } 198 | } 199 | }, 200 | 201 | blocks: function(entity, x2, z2, r2) { 202 | if (entity instanceof pocjs.entities.Bullet) return false; 203 | return this.inherited(arguments); 204 | }, 205 | 206 | getSelectedItem: function() { 207 | return this.items[this.selectedSlot]; 208 | }, 209 | 210 | addLoot: function(item) { 211 | if (item == pocjs.entities.Item.pistol) this.ammo += 20; 212 | if (item == pocjs.entities.Item.potion) this.potions += 1; 213 | for (var i = 0; i < this.items.length; i++) { 214 | if (this.items[i] == item) { 215 | this.level.showLootScreen(item); 216 | return; 217 | } 218 | } 219 | 220 | for (var i = 0; i < this.items.length; i++) { 221 | if (this.items[i] == pocjs.entities.Item.none) { 222 | this.items[i] = item; 223 | this.selectedSlot = i; 224 | this.itemUseTime = 0; 225 | this.level.showLootScreen(item); 226 | return; 227 | } 228 | } 229 | }, 230 | 231 | hurt: function(enemy, dmg) { 232 | if (this.hurtTime > 0 || this.dead) return; 233 | 234 | this.hurtTime = 40; 235 | this.health -= dmg; 236 | 237 | if (this.health <= 0) { 238 | this.health = 0; 239 | pocjs.Sound.death.play(); 240 | this.dead = true; 241 | } 242 | 243 | pocjs.Sound.hurt.play(); 244 | 245 | var xd = enemy.x - this.x; 246 | var zd = enemy.z - this.z; 247 | var dd = Math.sqrt(xd * xd + zd * zd); 248 | this.xa -= xd / dd * 0.1; 249 | this.za -= zd / dd * 0.1; 250 | this.rota += (Math.random() - 0.5) * 0.2; 251 | }, 252 | 253 | collide: function(entity) { 254 | if (entity instanceof pocjs.entities.Bullet) { 255 | var bullet = entity; 256 | if (bullet.owner.declaredClass == this.declaredClass) { 257 | return; 258 | } 259 | if (this.hurtTime > 0) return; 260 | entity.remove(); 261 | this.hurt(entity, 1); 262 | } 263 | }, 264 | 265 | win: function() { 266 | this.level.win(); 267 | } 268 | }); 269 | -------------------------------------------------------------------------------- /pocjs/gui/Bitmap.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbober/pocjs/25fca68b4c5d57c5facb8d97d86ea948bf411d33/pocjs/gui/Bitmap.js -------------------------------------------------------------------------------- /pocjs/gui/Bitmap3D.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.gui.Bitmap3D"); 2 | 3 | dojo.declare("pocjs.gui.Bitmap3D", pocjs.gui.Bitmap, { 4 | zBuffer: null, 5 | zBufferWall: null, 6 | xCam: 0, yCam: 0, zCam: 0, 7 | rCos: 0, rSin: 0, fov: 0, 8 | xCenter: 0, yCenter: 0, rot: 0, 9 | 10 | 11 | "-chains-": {constructor: "manual"}, 12 | constructor: function(width, height) { 13 | this.inherited(arguments); 14 | this.zBuffer = new Array(width * height); 15 | this.zBufferWall = new Array(width); 16 | }, 17 | 18 | render: function(game) { 19 | for (var x = 0; x < this.width; x++) { 20 | this.zBufferWall[x] = 0; 21 | } 22 | for (var i = 0; i < this.width * this.height; i++) { 23 | this.zBuffer[i] = 10000; 24 | } 25 | this.rot = game.player.rot; 26 | this.xCam = game.player.x - Math.sin(this.rot) * 0.3; 27 | this.yCam = game.player.z - Math.cos(this.rot) * 0.3; 28 | this.zCam = -0.2 + Math.sin(game.player.bobPhase * 0.4) * 0.01 * game.player.bob - game.player.y; 29 | 30 | this.xCenter = this.width / 2.0; 31 | this.yCenter = this.height / 3.0; 32 | 33 | this.rCos = Math.cos(this.rot); 34 | this.rSin = Math.sin(this.rot); 35 | 36 | this.fov = this.height; 37 | 38 | var level = game.level; 39 | var i_r = 6; 40 | 41 | var i_xCenter = Math.floor(this.xCam); 42 | var i_zCenter = Math.floor(this.yCam); 43 | for (var zb = i_zCenter - i_r; zb <= i_zCenter + i_r; zb++) { 44 | for (var xb = i_xCenter - i_r; xb <= i_xCenter + i_r; xb++) { 45 | var c = level.getBlock(xb, zb); 46 | var e = level.getBlock(xb + 1, zb); 47 | var s = level.getBlock(xb, zb + 1); 48 | 49 | if (c instanceof pocjs.level.block.DoorBlock) { 50 | var rr = 1 / 8.0; 51 | var openness = 1 - c.openness * 7 / 8; 52 | if (e.solidRender) { 53 | this.renderWall(xb + openness, zb + 0.5 - rr, 54 | xb, zb + 0.5 - rr, 55 | c.tex, 56 | (c.col & 0xfefefe) >> 1, 57 | 0, openness); 58 | this.renderWall(xb, zb + 0.5 + rr, 59 | xb + openness, zb + 0.5 + rr, 60 | c.tex, 61 | (c.col & 0xfefefe) >> 1, 62 | openness, 0); 63 | this.renderWall(xb + openness, zb + 0.5 + rr, 64 | xb + openness, zb + 0.5 - rr, 65 | c.tex, 66 | c.col, 67 | 0.5 - rr, 0.5 + rr); 68 | } 69 | else { 70 | this.renderWall(xb + 0.5 - rr, zb, 71 | xb + 0.5 - rr, zb + openness, 72 | c.tex, 73 | c.col, 74 | openness, 0); 75 | this.renderWall(xb + 0.5 + rr, zb + openness, 76 | xb + 0.5 + rr, zb, 77 | c.tex, 78 | c.col, 79 | 0, openness); 80 | this.renderWall(xb + 0.5 - rr, zb + openness, 81 | xb + 0.5 + rr, zb + openness, 82 | c.tex, 83 | (c.col & 0xfefefe) >> 1, 84 | 0.5 - rr, 0.5 + rr); 85 | } 86 | 87 | } 88 | 89 | if (c.solidRender) { 90 | if (!e.solidRender) { 91 | this.renderWall(xb + 1, zb + 1, xb + 1, zb, c.tex, c.col); 92 | } 93 | if (!s.solidRender) { 94 | this.renderWall(xb, zb + 1, 95 | xb + 1, zb + 1, 96 | c.tex, 97 | (c.col & 0xfefefe) >> 1); 98 | } 99 | } 100 | else { 101 | if (e.solidRender) { 102 | this.renderWall(xb + 1, zb, xb + 1, zb + 1, e.tex, e.col); 103 | } 104 | if (s.solidRender) { 105 | this.renderWall(xb + 1, zb + 1, 106 | xb, zb + 1, 107 | s.tex, 108 | (s.col & 0xfefefe) >> 1); 109 | } 110 | } 111 | } 112 | } 113 | for (var zb = i_zCenter - i_r; zb <= i_zCenter + i_r; zb++) { 114 | for (var xb = i_xCenter - i_r; xb <= i_xCenter + i_r; xb++) { 115 | var c = level.getBlock(xb, zb); 116 | 117 | for (var j = 0; j < c.entities.length; j++) { 118 | var e = c.entities[j]; 119 | for (var i = 0; i < e.sprites.length; i++) { 120 | var sprite = e.sprites[i]; 121 | this.renderSprite(e.x + sprite.x, 0 - sprite.y, e.z + sprite.z, 122 | sprite.tex, sprite.col); 123 | } 124 | } 125 | 126 | for (var i = 0; i < c.sprites.length; i++) { 127 | var sprite = c.sprites[i]; 128 | this.renderSprite(xb + sprite.x, 0 - sprite.y, zb + sprite.z, 129 | sprite.tex, sprite.col); 130 | } 131 | } 132 | } 133 | 134 | this.renderFloor(level); 135 | }, 136 | 137 | renderFloor: function(level) { 138 | var fpixels = pocjs.Art.floors.pixels; 139 | var height = this.height, width = this.width, 140 | xCenter = this.xCenter, yCenter = this.yCenter, 141 | fov = this.fov, 142 | xCam = this.xCam, yCam = this.yCam, zCam = this.zCam, 143 | rCos = this.rCos, rSin = this.rSin, 144 | zBuffer = this.zBuffer, pixels = this.pixels; 145 | 146 | var xbase = (xCam + 0.5) * 8; 147 | var ybase = (yCam + 0.5) * 8; 148 | 149 | for (var y = 0; y < height; y++) { 150 | var yd = ((y + 0.5) - yCenter) / fov; 151 | 152 | var floor = true; 153 | var zd = (4 - zCam * 8) / yd; 154 | if (yd < 0) { 155 | floor = false; 156 | zd = (4 + zCam * 8) / -yd; 157 | } 158 | 159 | var zSin = zd * rSin; 160 | var zCos = zd * rCos; 161 | 162 | for (var x = 0; x < width; x++) { 163 | if (zBuffer[x + y * width] <= zd) continue; 164 | 165 | var xd = (xCenter - x) / fov; 166 | xd *= zd; 167 | 168 | var xx = xd * rCos + zSin + xbase; 169 | var yy = zCos - xd * rSin + ybase; 170 | 171 | var i_xPix = xx * 2 <<0; 172 | var i_yPix = yy * 2 <<0; 173 | var xTile = i_xPix >> 4; 174 | var yTile = i_yPix >> 4; 175 | 176 | var block = level.getBlock(xTile, yTile); 177 | var col = block.floorCol; 178 | var tex = block.floorTex; 179 | if (!floor) { 180 | col = block.ceilCol; 181 | tex = block.ceilTex; 182 | } 183 | 184 | if (tex < 0) { 185 | zBuffer[x + y * width] = -1; 186 | } 187 | else { 188 | zBuffer[x + y * width] = zd; 189 | var offset = ((i_xPix & 15) + (tex % 8) * 16) + ((i_yPix & 15) + (tex / 8 <<0) * 16) * 128; 190 | pixels[x + y * width] = fpixels[offset] * col; 191 | } 192 | } 193 | } 194 | 195 | }, 196 | 197 | renderSprite: function(x, y, z, tex, color) { 198 | var height = this.height, width = this.width, 199 | xCenter = this.xCenter, yCenter = this.yCenter, 200 | fov = this.fov, 201 | xCam = this.xCam, yCam = this.yCam, zCam = this.zCam, 202 | rCos = this.rCos, rSin = this.rSin, 203 | zBuffer = this.zBuffer, pixels = this.pixels; 204 | 205 | var fpixels = pocjs.Art.sprites.pixels; 206 | 207 | var xc = (x - xCam) * 2 - rSin * 0.2; 208 | var yc = (y - zCam) * 2; 209 | var zc = (z - yCam) * 2 - rCos * 0.2; 210 | 211 | var xx = xc * rCos - zc * rSin; 212 | var yy = yc; 213 | var zz = zc * rCos + xc * rSin; 214 | 215 | if (zz < 0.1) return; 216 | 217 | var xPixel = xCenter - (xx / zz * fov); 218 | var yPixel = (yy / zz * fov + yCenter); 219 | 220 | var zh = height / zz; 221 | var xPixel0 = xPixel - zh; 222 | var xPixel1 = xPixel + zh; 223 | 224 | var yPixel0 = yPixel - zh; 225 | var yPixel1 = yPixel + zh; 226 | 227 | var i_xp0 = Math.ceil(xPixel0); 228 | var i_xp1 = Math.ceil(xPixel1); 229 | var i_yp0 = Math.ceil(yPixel0); 230 | var i_yp1 = Math.ceil(yPixel1); 231 | 232 | if (i_xp0 < 0) i_xp0 = 0; 233 | if (i_xp1 > width) i_xp1 = width; 234 | if (i_yp0 < 0) i_yp0 = 0; 235 | if (i_yp1 > height) i_yp1 = height; 236 | zz *= 4; 237 | 238 | var xtex = tex % 8 * 16; 239 | var ytex = (tex / 8 <<0) * 16; 240 | 241 | for (var yp = i_yp0; yp < i_yp1; yp++) { 242 | var ypr = (yp - yPixel0) / (yPixel1 - yPixel0); 243 | var i_yt = ypr * 16 <<0; 244 | for (var xp = i_xp0; xp < i_xp1; xp++) { 245 | var xpr = (xp - xPixel0) / (xPixel1 - xPixel0); 246 | var i_xt = xpr * 16 <<0; 247 | if (zBuffer[xp + yp * width] > zz) { 248 | var offset = i_xt + xtex + (i_yt + ytex) * 128; 249 | var col = fpixels[offset]; 250 | if (col >= 0) { 251 | pixels[xp + yp * width] = col * color; 252 | zBuffer[xp + yp * width] = zz; 253 | } 254 | } 255 | } 256 | } 257 | 258 | }, 259 | 260 | renderWall: function(x0, y0, x1, y1, tex, color, xt0, xt1) { 261 | if (xt0 === undefined) xt0 = 0; 262 | if (xt1 === undefined) xt1 = 1; 263 | 264 | var xc0 = ((x0 - 0.5) - this.xCam) * 2; 265 | var yc0 = ((y0 - 0.5) - this.yCam) * 2; 266 | 267 | var xx0 = xc0 * this.rCos - yc0 * this.rSin; 268 | var u0 = ((-0.5) - this.zCam) * 2; 269 | var l0 = ((+0.5) - this.zCam) * 2; 270 | var zz0 = yc0 * this.rCos + xc0 * this.rSin; 271 | 272 | var xc1 = ((x1 - 0.5) - this.xCam) * 2; 273 | var yc1 = ((y1 - 0.5) - this.yCam) * 2; 274 | 275 | var xx1 = xc1 * this.rCos - yc1 * this.rSin; 276 | var u1 = ((-0.5) - this.zCam) * 2; 277 | var l1 = ((+0.5) - this.zCam) * 2; 278 | var zz1 = yc1 * this.rCos + xc1 * this.rSin; 279 | 280 | xt0 *= 16; 281 | xt1 *= 16; 282 | 283 | var zClip = 0.2; 284 | 285 | if (zz0 < zClip && zz1 < zClip) return; 286 | 287 | if (zz0 < zClip) { 288 | var p = (zClip - zz0) / (zz1 - zz0); 289 | zz0 = zz0 + (zz1 - zz0) * p; 290 | xx0 = xx0 + (xx1 - xx0) * p; 291 | xt0 = xt0 + (xt1 - xt0) * p; 292 | } 293 | 294 | if (zz1 < zClip) { 295 | var p = (zClip - zz0) / (zz1 - zz0); 296 | zz1 = zz0 + (zz1 - zz0) * p; 297 | xx1 = xx0 + (xx1 - xx0) * p; 298 | xt1 = xt0 + (xt1 - xt0) * p; 299 | } 300 | 301 | var xPixel0 = this.xCenter - (xx0 / zz0 * this.fov); 302 | var xPixel1 = this.xCenter - (xx1 / zz1 * this.fov); 303 | 304 | if (xPixel0 >= xPixel1) return; 305 | var i_xp0 = Math.ceil(xPixel0); 306 | var i_xp1 = Math.ceil(xPixel1); 307 | if (i_xp0 < 0) i_xp0 = 0; 308 | if (i_xp1 > this.width) i_xp1 = this.width; 309 | 310 | var yPixel00 = (u0 / zz0 * this.fov + this.yCenter); 311 | var yPixel01 = (l0 / zz0 * this.fov + this.yCenter); 312 | var yPixel10 = (u1 / zz1 * this.fov + this.yCenter); 313 | var yPixel11 = (l1 / zz1 * this.fov + this.yCenter); 314 | 315 | var iz0 = 1 / zz0; 316 | var iz1 = 1 / zz1; 317 | 318 | var iza = iz1 - iz0; 319 | 320 | var ixt0 = xt0 * iz0; 321 | var ixta = xt1 * iz1 - ixt0; 322 | var iw = 1 / (xPixel1 - xPixel0); 323 | 324 | var xtex = tex % 8 * 16; 325 | var ytex = (tex / 8 <<0) * 16; 326 | for (var x = i_xp0; x < i_xp1; x++) { 327 | var pr = (x - xPixel0) * iw; 328 | var iz = iz0 + iza * pr; 329 | 330 | if (this.zBufferWall[x] > iz) continue; 331 | this.zBufferWall[x] = iz; 332 | var i_xTex = ((ixt0 + ixta * pr) / iz) << 0; 333 | 334 | var yPixel0 = yPixel00 + (yPixel10 - yPixel00) * pr - 0.5; 335 | var yPixel1 = yPixel01 + (yPixel11 - yPixel01) * pr; 336 | 337 | var i_yp0 = Math.ceil(yPixel0); 338 | var i_yp1 = Math.ceil(yPixel1); 339 | if (i_yp0 < 0) i_yp0 = 0; 340 | if (i_yp1 > this.height) i_yp1 = this.height; 341 | 342 | var ih = 1 / (yPixel1 - yPixel0); 343 | for (var y = i_yp0; y < i_yp1; y++) { 344 | var pry = (y - yPixel0) * ih; 345 | var i_yTex = 16 * pry << 0; 346 | var offset = i_xTex + xtex + (i_yTex + ytex) * 128; 347 | this.pixels[x + y * this.width] = pocjs.Art.walls.pixels[offset] * color; 348 | this.zBuffer[x + y * this.width] = 1 / iz * 4; 349 | } 350 | } 351 | }, 352 | 353 | postProcess: function(level) { 354 | for (var i = 0; i < this.width * this.height; i++) { 355 | var zl = this.zBuffer[i]; 356 | if (zl < 0) { 357 | var xx = ((i % this.width) - this.rot * 512 / (Math.PI * 2)) & 511; 358 | var yy = (i / this.width) <<0; 359 | this.pixels[i] = pocjs.Art.sky.pixels[xx + yy * 512] * 0x444455; 360 | } else { 361 | var xp = (i % this.width); 362 | var yp = ((i / this.width) << 0) * 14; 363 | 364 | var xx = ((i % this.width - this.width / 2.0) / this.width); 365 | var col = this.pixels[i]; 366 | var brightness = (300 - zl * 6 * (xx * xx * 2 + 1)) << 0; 367 | brightness = (brightness + ((xp + yp) & 3) * 4) >> 4 << 4; 368 | if (brightness < 0) brightness = 0; 369 | if (brightness > 255) brightness = 255; 370 | 371 | var r = (col >> 16) & 0xff; 372 | var g = (col >> 8) & 0xff; 373 | var b = (col) & 0xff; 374 | 375 | r = r * brightness / 255; 376 | g = g * brightness / 255; 377 | b = b * brightness / 255; 378 | 379 | this.pixels[i] = r << 16 | g << 8 | b; 380 | } 381 | } 382 | } 383 | }); 384 | 385 | -------------------------------------------------------------------------------- /pocjs/gui/PoofSprite.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.gui.PoofSprite"); 2 | 3 | 4 | dojo.declare("pocjs.gui.PoofSprite", pocjs.gui.Sprite, { 5 | life: 20, 6 | 7 | 8 | "-chains-": {constructor: "manual"}, 9 | constructor: function(x, y, z) { 10 | this.inherited(arguments, [x, y, z, 5, 0x222222]); 11 | }, 12 | 13 | tick: function() { 14 | if (this.life-- <= 0) this.removed = true; 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /pocjs/gui/RubbleSprite.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.gui.RubbleSprite"); 2 | 3 | dojo.declare("pocjs.gui.RubbleSprite", pocjs.gui.Sprite, { 4 | xa: null, ya: null, za: null, 5 | 6 | 7 | "-chains-": {constructor: "manual"}, 8 | constructor: function() { 9 | this.inherited(arguments, [ Math.random() - 0.5, 10 | Math.random() * 0.8, 11 | Math.random() - 0.5, 12 | 2, 0x555555 13 | ]); 14 | this.xa = Math.random() - 0.5; 15 | this.ya = Math.random(); 16 | this.za = Math.random() - 0.5; 17 | }, 18 | 19 | tick: function() { 20 | this.x += this.xa * 0.03; 21 | this.y += this.ya * 0.03; 22 | this.z += this.za * 0.03; 23 | this.ya -= 0.1; 24 | if (this.y < 0) { 25 | this.y = 0; 26 | this.xa *= 0.8; 27 | this.za *= 0.8; 28 | if (Math.random() < 0.04) 29 | this.removed = true; 30 | } 31 | } 32 | }); 33 | 34 | -------------------------------------------------------------------------------- /pocjs/gui/Screen.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbober/pocjs/25fca68b4c5d57c5facb8d97d86ea948bf411d33/pocjs/gui/Screen.js -------------------------------------------------------------------------------- /pocjs/gui/Sprite.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.gui.Sprite"); 2 | 3 | dojo.declare("pocjs.gui.Sprite", null, { 4 | x: null, y: null, z:null, 5 | tex: null, 6 | col: 0x202020, 7 | removed: false, 8 | 9 | constructor: function(x, y, z, tex, color) { 10 | this.x = x; 11 | this.y = y; 12 | this.z = z; 13 | this.tex = tex; 14 | this.col = color; 15 | }, 16 | 17 | tick: function() { 18 | } 19 | }); 20 | 21 | -------------------------------------------------------------------------------- /pocjs/level/CryptLevel.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.CryptLevel"); 2 | 3 | dojo.declare("pocjs.level.CryptLevel", pocjs.level.Level, { 4 | constructor: function() { 5 | this.floorCol = 0x404040; 6 | this.ceilCol = 0x404040; 7 | this.wallCol = 0x404040; 8 | this.name = "The Crypt"; 9 | }, 10 | 11 | switchLevel: function(id) { 12 | if (id == 1) this.game.switchLevel("overworld", 2); 13 | }, 14 | 15 | getLoot: function(id) { 16 | this.inherited(arguments); 17 | if (id == 1) this.game.getLoot(pocjs.entities.Item.flippers); 18 | } 19 | }); 20 | -------------------------------------------------------------------------------- /pocjs/level/DungeonLevel.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.DungeonLevel"); 2 | 3 | dojo.declare("pocjs.level.DungeonLevel", pocjs.level.Level, { 4 | constructor: function() { 5 | this.wallCol = 0xC64954; 6 | this.floorCol = 0x8E4A51; 7 | this.ceilCol = 0x8E4A51; 8 | this.name = "The Dungeons"; 9 | }, 10 | 11 | init: function(game, name, w, h, pixels) { 12 | this.inherited(arguments); 13 | this.inherited("trigger", [6, true]); 14 | this.inherited("trigger",[7, true]); 15 | }, 16 | 17 | switchLevel: function(id) { 18 | if (id == 1) this.game.switchLevel("start", 2); 19 | }, 20 | 21 | getLoot: function(id) { 22 | this.inherited(arguments); 23 | if (id == 1) this.game.getLoot(pocjs.entities.Item.powerGlove); 24 | }, 25 | 26 | trigger: function(id, pressed) { 27 | this.inherited(arguments); 28 | if (id == 5) this.inherited("trigger", [6, !pressed]); 29 | if (id == 4) this.inherited("trigger", [7, !pressed]); 30 | } 31 | }); 32 | -------------------------------------------------------------------------------- /pocjs/level/IceLevel.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.IceLevel"); 2 | 3 | dojo.declare("pocjs.level.IceLevel", pocjs.level.Level, { 4 | constructor: function() { 5 | this.ceilCol = 0xB8DBE0; 6 | this.floorCol = 0xB8DBE0; 7 | this.wallCol = 0x6BE8FF; 8 | this.name = "The Frost Cave"; 9 | }, 10 | 11 | switchLevel: function(id) { 12 | if (id == 1) this.game.switchLevel("overworld", 5); 13 | }, 14 | 15 | getLoot: function(id) { 16 | this.inherited(arguments); 17 | if (id == 1) this.game.getLoot(pocjs.entities.Item.skates); 18 | } 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /pocjs/level/Level.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.Level"); 2 | 3 | dojo.declare("pocjs.level.Level", null, { 4 | 5 | blocks: null, 6 | width: null, height: null, 7 | 8 | xSpawn: null, 9 | ySpawn: null, 10 | 11 | wallCol: 0xB3CEE2, 12 | floorCol: 0x9CA09B, 13 | ceilCol: 0x9CA09B, 14 | 15 | wallTex: 0, 16 | floorTex: 0, 17 | ceilTex: 0, 18 | 19 | entities: null, 20 | game: null, 21 | name: "", 22 | 23 | player: null, 24 | 25 | 26 | 27 | init: function(game, name, w, h, pixels) { 28 | this.game = game; 29 | 30 | this.player = game.player; 31 | 32 | this.solidWall = new pocjs.level.block.SolidBlock(); 33 | this.solidWall.col = pocjs.Art.getCol(this.wallCol); 34 | this.solidWall.tex = pocjs.Art.getCol(this.wallTex); 35 | this.width = w; 36 | this.height = h; 37 | this.blocks = new Array(w * h << 0 ); 38 | this.entities = []; 39 | 40 | for (var y = 0; y < h; y++) { 41 | for (var x = 0; x < w; x++) { 42 | var col = pixels[x + y * w] & 0xffffff; 43 | 44 | var id = 255 - ((pixels[x + y * w] >> 24) & 0xff); 45 | 46 | var block = this.getNewBlock(x, y, col); 47 | block.id = id; 48 | 49 | if (block.tex == -1) block.tex = this.wallTex; 50 | if (block.floorTex == -1) block.floorTex = this.floorTex; 51 | if (block.ceilTex == -1) block.ceilTex = this.ceilTex; 52 | if (block.col == -1) block.col = pocjs.Art.getCol(this.wallCol); 53 | if (block.floorCol == -1) block.floorCol = pocjs.Art.getCol(this.floorCol); 54 | if (block.ceilCol == -1) block.ceilCol = pocjs.Art.getCol(this.ceilCol); 55 | 56 | block.level = this; 57 | block.x = x; 58 | block.y = y; 59 | this.blocks[x + y * w] = block; 60 | 61 | } 62 | } 63 | for (var y = 0; y < h; y++) { 64 | for (var x = 0; x < w; x++) { 65 | var col = pixels[x + y * w] & 0xffffff; 66 | this.decorateBlock(x, y, this.blocks[x + y * w], col); 67 | } 68 | } 69 | }, 70 | 71 | addEntity: function(e) { 72 | this.entities.push(e); 73 | e.level = this; 74 | e.updatePos(); 75 | }, 76 | 77 | removeEntityImmediately: function(player) { 78 | var index = this.entities.indexOf(player); 79 | if (index < 0) throw "element not found"; 80 | 81 | this.entities.slice(index, 1); 82 | this.getBlock(player.xTileO, player.zTileO).removeEntity(player); 83 | }, 84 | 85 | decorateBlock: function(x, y, block, col) { 86 | block.decorate(this, x, y); 87 | if (col == 0xFFFF00) { 88 | this.xSpawn = x; 89 | this.ySpawn = y; 90 | } 91 | if (col == 0xAA5500) this.addEntity(new pocjs.entities.BoulderEntity(x, y)); 92 | if (col == 0xff0000) this.addEntity(new pocjs.entities.BatEntity(x, y)); 93 | if (col == 0xff0001) this.addEntity(new pocjs.entities.BatBossEntity(x, y)); 94 | if (col == 0xff0002) this.addEntity(new pocjs.entities.OgreEntity(x, y)); 95 | if (col == 0xff0003) this.addEntity(new pocjs.entities.BossOgre(x, y)); 96 | if (col == 0xff0004) this.addEntity(new pocjs.entities.EyeEntity(x, y)); 97 | if (col == 0xff0005) this.addEntity(new pocjs.entities.EyeBossEntity(x, y)); 98 | if (col == 0xff0006) this.addEntity(new pocjs.entities.GhostEntity(x, y)); 99 | if (col == 0xff0007) this.addEntity(new pocjs.entities.GhostBossEntity(x, y)); 100 | if (col == 0x1A2108 || col == 0xff0007) { 101 | block.floorTex = 7; 102 | block.ceilTex = 7; 103 | } 104 | 105 | if (col == 0xC6C6C6) block.col = pocjs.Art.getCol(0xa0a0a0); 106 | if (col == 0xC6C697) block.col = pocjs.Art.getCol(0xa0a0a0); 107 | if (col == 0x653A00) { 108 | block.floorCol = pocjs.Art.getCol(0xB56600); 109 | block.floorTex = 3 * 8 + 1; 110 | } 111 | 112 | if (col == 0x93FF9B) { 113 | block.col = pocjs.Art.getCol(0x2AAF33); 114 | block.tex = 8; 115 | } 116 | }, 117 | 118 | getNewBlock: function(x, y, col) { 119 | if (col == 0x93FF9B) return new pocjs.level.block.SolidBlock(); 120 | if (col == 0x009300) return new pocjs.level.block.PitBlock(); 121 | if (col == 0xFFFFFF) return new pocjs.level.block.SolidBlock(); 122 | if (col == 0x00FFFF) return new pocjs.level.block.VanishBlock(); 123 | if (col == 0xFFFF64) return new pocjs.level.block.ChestBlock(); 124 | if (col == 0x0000FF) return new pocjs.level.block.WaterBlock(); 125 | if (col == 0xFF3A02) return new pocjs.level.block.TorchBlock(); 126 | if (col == 0x4C4C4C) return new pocjs.level.block.BarsBlock(); 127 | if (col == 0xFF66FF) return new pocjs.level.block.LadderBlock(false); 128 | if (col == 0x9E009E) return new pocjs.level.block.LadderBlock(true); 129 | if (col == 0xC1C14D) return new pocjs.level.block.LootBlock(); 130 | if (col == 0xC6C6C6) return new pocjs.level.block.DoorBlock(); 131 | if (col == 0x00FFA7) return new pocjs.level.block.SwitchBlock(); 132 | if (col == 0x009380) return new pocjs.level.block.PressurePlateBlock(); 133 | if (col == 0xff0005) return new pocjs.level.block.IceBlock(); 134 | if (col == 0x3F3F60) return new pocjs.level.block.IceBlock(); 135 | if (col == 0xC6C697) return new pocjs.level.block.LockedDoorBlock(); 136 | if (col == 0xFFBA02) return new pocjs.level.block.AltarBlock(); 137 | if (col == 0x749327) return new pocjs.level.block.SpiritWallBlock(); 138 | if (col == 0x1A2108) return new pocjs.level.block.Block(); 139 | if (col == 0x00C2A7) return new pocjs.level.block.FinalUnlockBlock(); 140 | if (col == 0x000056) return new pocjs.level.block.WinBlock(); 141 | 142 | return new pocjs.level.block.Block(); 143 | }, 144 | 145 | getBlock: function(x, y) { 146 | if (x < 0 || y < 0 || x >= this.width || y >= this.height) { 147 | return this.solidWall; 148 | } 149 | 150 | var b = this.blocks[x + y * this.width]; 151 | return b; 152 | }, 153 | 154 | 155 | containsBlockingEntity: function(x0, y0, x1, y1) { 156 | var xc = Math.floor((x1 + x0) / 2); 157 | var zc = Math.floor((y1 + y0) / 2); 158 | var rr = 2; 159 | for (var z = zc - rr; z <= zc + rr; z++) { 160 | for (var x = xc - rr; x <= xc + rr; x++) { 161 | var es = this.getBlock(x, z).entities; 162 | for (var i = 0; i < es.length; i++) { 163 | var e = es[i]; 164 | if (e.isInside(x0, y0, x1, y1)) return true; 165 | } 166 | } 167 | } 168 | return false; 169 | }, 170 | 171 | containsBlockingNonFlyingEntity: function(x0, y0, x1, y1) { 172 | var xc = Math.floor((x1 + x0) / 2); 173 | var zc = Math.floor((y1 + y0) / 2); 174 | var rr = 2; 175 | for (var z = zc - rr; z <= zc + rr; z++) { 176 | for (var x = xc - rr; x <= xc + rr; x++) { 177 | var es = this.getBlock(x, z).entities; 178 | for (var i = 0; i < es.length; i++) { 179 | var e = es[i]; 180 | if (!e.flying && e.isInside(x0, y0, x1, y1)) return true; 181 | } 182 | } 183 | } 184 | return false; 185 | }, 186 | 187 | tick: function() { 188 | for (var i = 0; i < this.entities.length; i++) { 189 | var e = this.entities[i]; 190 | e.tick(); 191 | e.updatePos(); 192 | if (e.isRemoved()) { 193 | this.entities.splice(i, 1); 194 | i--; 195 | } 196 | } 197 | 198 | for (var y = 0; y < this.height; y++) { 199 | for (var x = 0; x < this.width; x++) { 200 | this.blocks[x + y * this.width].tick(); 201 | } 202 | } 203 | }, 204 | 205 | trigger: function(id, pressed) { 206 | for (var y = 0; y < this.height; y++) { 207 | for (var x = 0; x < this.width; x++) { 208 | var b = this.blocks[x + y * this.width]; 209 | if (b.id == id) { 210 | b.trigger(pressed); 211 | } 212 | } 213 | } 214 | }, 215 | 216 | switchLevel: function(id) { 217 | }, 218 | 219 | findSpawn: function(id) { 220 | for (var y = 0; y < this.height; y++) { 221 | for (var x = 0; x < this.width; x++) { 222 | var b = this.blocks[x + y * this.width]; 223 | if (b.id == id && b instanceof pocjs.level.block.LadderBlock) { 224 | this.xSpawn = x; 225 | this.ySpawn = y; 226 | } 227 | } 228 | } 229 | }, 230 | 231 | getLoot: function(id) { 232 | if (id == 20) this.game.getLoot(pocjs.entities.Item.pistol); 233 | if (id == 21) this.game.getLoot(pocjs.entities.Item.potion); 234 | }, 235 | 236 | win: function() { 237 | this.game.win(this.player); 238 | }, 239 | 240 | lose: function() { 241 | this.game.lose(this.player); 242 | }, 243 | 244 | showLootScreen: function(item) { 245 | this.game.setMenu(new pocjs.menu.GotLootMenu(item)); 246 | } 247 | }); 248 | 249 | 250 | dojo.mixin(pocjs.level.Level, { 251 | loaded: {}, 252 | pixels: {}, 253 | dims: {}, 254 | clear: function() { 255 | this.loaded = {}; 256 | }, 257 | 258 | loadLevelBitmap: function(name) { 259 | 260 | var self = this; 261 | 262 | var dfd = new dojo.Deferred(); 263 | 264 | PNG.load("res/level/" + name + ".png", function(png) { 265 | var w = png.width; 266 | var h = png.height; 267 | var pixels = new Array(w * h << 0); 268 | var ppix = png.decodePixels(); 269 | 270 | for (var y = 0; y < h; y++) { 271 | for (var x = 0; x < w; x++) { 272 | var data = ppix[y][x]; 273 | 274 | var input = data[3] << 24 275 | | data[0] << 16 276 | | data[1] << 8 277 | | data[2]; 278 | pixels[x + y*w] = input; 279 | } 280 | } 281 | 282 | self.pixels[name] = pixels; 283 | self.dims[name] = {w: w, h: h}; 284 | dfd.resolve(name); 285 | }); 286 | return dfd; 287 | 288 | }, 289 | 290 | loadLevel: function(game, name) { 291 | if (name in this.loaded) return this.loaded[name]; 292 | var level = this.byName(name); 293 | level.init(game, name, this.dims[name].w, this.dims[name].h, this.pixels[name]); 294 | this.loaded[name] = level; 295 | return level; 296 | }, 297 | 298 | byName: function(name) { 299 | var clazz = "pocjs.level." + name.slice(0, 1).toUpperCase() + name.slice(1) + "Level"; 300 | //dojo.require(clazz); 301 | return new dojo.getObject(clazz)(); 302 | } 303 | }); 304 | 305 | -------------------------------------------------------------------------------- /pocjs/level/OverworldLevel.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.OverworldLevel"); 2 | 3 | dojo.declare("pocjs.level.OverworldLevel", pocjs.level.Level, { 4 | constructor: function() { 5 | this.ceilTex = -1; 6 | this.floorCol = 0x508253; 7 | this.floorTex = 8 * 3; 8 | this.wallCol = 0xa0a0a0; 9 | this.name = "The Island"; 10 | }, 11 | 12 | switchLevel: function(id) { 13 | if (id == 1) this.game.switchLevel("start", 1); 14 | if (id == 2) this.game.switchLevel("crypt", 1); 15 | if (id == 3) this.game.switchLevel("temple", 1); 16 | if (id == 5) this.game.switchLevel("ice", 1); 17 | }, 18 | 19 | getLoot: function(id) { 20 | this.inherited(arguments); 21 | if (id == 1) this.game.getLoot(pocjs.entities.Item.cutters); 22 | } 23 | }); 24 | 25 | -------------------------------------------------------------------------------- /pocjs/level/StartLevel.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.StartLevel"); 2 | 3 | dojo.declare("pocjs.level.StartLevel", pocjs.level.Level, { 4 | constructor: function() { 5 | this.name = "The Prison"; 6 | }, 7 | 8 | decorateBlock: function(x, y, block, col) { 9 | this.inherited(arguments); 10 | }, 11 | 12 | getNewBlock: function(x, y, col) { 13 | return this.inherited(arguments); 14 | }, 15 | 16 | switchLevel: function(id) { 17 | if (id == 1) this.game.switchLevel("overworld", 1); 18 | if (id == 2) this.game.switchLevel("dungeon", 1); 19 | }, 20 | 21 | getLoot: function(id) { 22 | this.inherited(arguments); 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /pocjs/level/TempleLevel.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.TempleLevel"); 2 | 3 | dojo.declare("pocjs.level.TempleLevel", pocjs.level.Level, { 4 | triggerMask: 0, 5 | 6 | constructor: function() { 7 | this.floorCol = 0x8A6496; 8 | this.ceilCol = 0x8A6496; 9 | this.wallCol = 0xCFADDB; 10 | this.name = "The Temple"; 11 | }, 12 | 13 | switchLevel: function(id) { 14 | if (id == 1) this.game.switchLevel("overworld", 3); 15 | }, 16 | 17 | getLoot: function(id) { 18 | this.inherited(arguments); 19 | if (id == 1) this.game.getLoot(pocjs.entities.Item.skates); 20 | }, 21 | 22 | trigger: function(id, pressed) { 23 | this.triggerMask |= 1 << id; 24 | this.inherited(arguments); 25 | if (!pressed) this.triggerMask ^= 1 << id; 26 | 27 | if (this.triggerMask == 14) { 28 | this.inherited(arguments, [1, true]); 29 | } else { 30 | this.inherited(arguments, [1, false]); 31 | } 32 | } 33 | }); 34 | -------------------------------------------------------------------------------- /pocjs/level/block/AltarBlock.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.block.AltarBlock"); 2 | 3 | dojo.declare("pocjs.level.block.AltarBlock", pocjs.level.block.Block, { 4 | filled: false, 5 | sprite: null, 6 | 7 | constructor: function() { 8 | this.blocksMotion = true; 9 | this.sprite = new pocjs.gui.Sprite(0, 0, 0, 16 + 4, pocjs.Art.getCol(0xE2FFE4)); 10 | this.addSprite(this.sprite); 11 | }, 12 | 13 | addEntity: function(entity) { 14 | this.inherited(arguments); 15 | if (!this.filled && ( 16 | entity instanceof pocjs.entities.GhostEntity || 17 | entity instanceof pocjs.entities.GhostBossEntity)) { 18 | entity.remove(); 19 | this.filled = true; 20 | this.blocksMotion = false; 21 | this.sprite.removed = true; 22 | 23 | for (var i = 0; i < 8; i++) { 24 | var sprite = new pocjs.gui.RubbleSprite(); 25 | sprite.col = this.sprite.col; 26 | this.addSprite(sprite); 27 | } 28 | 29 | if (entity instanceof pocjs.entities.GhostBossEntity) { 30 | this.level.addEntity(new pocjs.entities.KeyEntity(this.x, this.y)); 31 | pocjs.Sound.bosskill.play(); 32 | } else { 33 | pocjs.Sound.altar.play(); 34 | } 35 | } 36 | }, 37 | 38 | blocks: function(entity) { 39 | return this.blocksMotion; 40 | } 41 | }); 42 | -------------------------------------------------------------------------------- /pocjs/level/block/BarsBlock.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.block.BarsBlock"); 2 | 3 | dojo.declare("pocjs.level.block.BarsBlock", pocjs.level.block.Block, { 4 | sprite: null, 5 | open: false, 6 | 7 | constructor: function() { 8 | this.sprite = new pocjs.gui.Sprite(0, 0, 0, 0, 0x202020); 9 | this.addSprite(this.sprite); 10 | this.blocksMotion = true; 11 | }, 12 | 13 | use: function(level, item) { 14 | if (this.open) return false; 15 | 16 | if (item == pocjs.entities.Item.cutters) { 17 | pocjs.Sound.cut.play(); 18 | this.sprite.tex = 1; 19 | this.open = true; 20 | } 21 | 22 | return true; 23 | }, 24 | 25 | blocks: function(entity) { 26 | if (this.open && entity instanceof pocjs.entities.Player) return false; 27 | if (this.open && entity instanceof pocjs.entities.Bullet) return false; 28 | return this.blocksMotion; 29 | } 30 | }); 31 | -------------------------------------------------------------------------------- /pocjs/level/block/Block.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.block.Block"); 2 | 3 | 4 | dojo.declare("pocjs.level.block.Block", null, { 5 | 6 | blocksMotion: false, 7 | solidRender: false, 8 | 9 | messages: null, 10 | 11 | sprites: null, 12 | entities: null, 13 | 14 | tex: -1, 15 | col: -1, 16 | 17 | floorCol: -1, 18 | ceilCol: -1, 19 | 20 | floorTex: -1, 21 | ceilTex: -1, 22 | 23 | level: null, 24 | x: 0, y: 0, 25 | 26 | id: 0, 27 | 28 | constructor: function() { 29 | this.messages = []; 30 | this.sprites = []; 31 | this.entities = []; 32 | }, 33 | 34 | addSprite: function(sprite) { 35 | this.sprites.push(sprite); 36 | }, 37 | 38 | use: function(level, item) { 39 | return false; 40 | }, 41 | 42 | tick: function() { 43 | this.sprites = this.sprites.filter(function(sprite) { 44 | sprite.tick(); 45 | if (sprite.removed) return false; 46 | else return true; 47 | }); 48 | }, 49 | 50 | removeEntity: function(entity) { 51 | var index = this.entities.indexOf(entity); 52 | this.entities.splice(index, 1); 53 | }, 54 | 55 | addEntity: function(entity) { 56 | this.entities.push(entity); 57 | }, 58 | 59 | blocks: function(entity) { 60 | return this.blocksMotion; 61 | }, 62 | 63 | decorate: function(level, x, y) { 64 | }, 65 | 66 | getFloorHeight: function(e) { 67 | return 0; 68 | }, 69 | 70 | getWalkSpeed: function(player) { 71 | return 1; 72 | }, 73 | 74 | getFriction: function(player) { 75 | return 0.6; 76 | }, 77 | 78 | trigger: function(pressed) { 79 | } 80 | }); 81 | 82 | 83 | -------------------------------------------------------------------------------- /pocjs/level/block/ChestBlock.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.block.ChestBlock"); 2 | 3 | dojo.declare("pocjs.level.block.ChestBlock", pocjs.level.block.Block, { 4 | open: false, 5 | 6 | chestSprite: null, 7 | 8 | constructor: function() { 9 | this.tex = 1; 10 | this.blocksMotion = true; 11 | 12 | this.chestSprite = new pocjs.gui.Sprite(0, 0, 0, 8 * 2 + 0, pocjs.Art.getCol(0xffff00)); 13 | this.addSprite(this.chestSprite); 14 | }, 15 | 16 | use: function(level, item) { 17 | if (this.open) return false; 18 | 19 | this.chestSprite.tex++; 20 | this.open = true; 21 | 22 | level.getLoot(this.id); 23 | pocjs.Sound.treasure.play(); 24 | 25 | return true; 26 | } 27 | }); 28 | 29 | -------------------------------------------------------------------------------- /pocjs/level/block/DoorBlock.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.block.DoorBlock"); 2 | 3 | dojo.declare("pocjs.level.block.DoorBlock", pocjs.level.block.SolidBlock, { 4 | open: false, 5 | openness: 0, 6 | 7 | constructor: function() { 8 | this.tex = 4; 9 | this.solidRender = false; 10 | }, 11 | 12 | use: function(level, item) { 13 | this.open = !this.open; 14 | if (this.open) pocjs.Sound.click1.play(); 15 | else pocjs.Sound.click2.play(); 16 | return true; 17 | }, 18 | 19 | tick: function() { 20 | this.inherited(arguments); 21 | 22 | if (this.open) this.openness += 0.2; 23 | else this.openness -= 0.2; 24 | if (this.openness < 0) this.openness = 0; 25 | if (this.openness > 1) this.openness = 1; 26 | 27 | var openLimit = 7 / 8.0; 28 | if (this.openness < openLimit && !this.open && !this.blocksMotion) { 29 | if (this.level.containsBlockingEntity(this.x - 0.5, this.y - 0.5, this.x + 0.5, this.y + 0.5)) { 30 | this.openness = openLimit; 31 | return; 32 | } 33 | } 34 | 35 | this.blocksMotion = this.openness < openLimit; 36 | }, 37 | 38 | blocks: function(entity) { 39 | var openLimit = 7 / 8.0; 40 | var goodClass = "Player Bullet OgreEntity".split(" ").some(function(clazz) { 41 | return entity instanceof pocjs.entities[clazz]; 42 | }); 43 | if (this.openness >= openLimit && goodClass) return this.blocksMotion; 44 | 45 | return true; 46 | } 47 | }); 48 | 49 | -------------------------------------------------------------------------------- /pocjs/level/block/FinalUnlockBlock.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.block.FinalUnlockBlock"); 2 | 3 | dojo.declare("pocjs.level.block.FinalUnlockBlock", pocjs.level.block.SolidBlock, { 4 | pressed: false, 5 | 6 | constructor: function() { 7 | this.tex = 8 + 3; 8 | }, 9 | 10 | use: function(level, item) { 11 | if (this.pressed) return false; 12 | if (level.player.keys < 4) return false; 13 | 14 | pocjs.Sound.click1.play(); 15 | this.pressed = true; 16 | level.trigger(this.id, true); 17 | 18 | return true; 19 | } 20 | }); 21 | 22 | -------------------------------------------------------------------------------- /pocjs/level/block/IceBlock.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.block.IceBlock"); 2 | 3 | dojo.declare("pocjs.level.block.IceBlock", pocjs.level.block.Block, { 4 | constructor: function() { 5 | this.blocksMotion = false; 6 | this.floorTex = 16; 7 | }, 8 | 9 | tick: function() { 10 | this.inherited(arguments); 11 | this.floorCol = pocjs.Art.getCol(0x8080ff); 12 | }, 13 | 14 | getWalkSpeed: function(player) { 15 | if (player.getSelectedItem() == pocjs.entities.Item.skates) return 0.05; 16 | return 1.4; 17 | }, 18 | 19 | getFriction: function(player) { 20 | if (player.getSelectedItem() == pocjs.entities.Item.skates) return 0.98; 21 | return 1; 22 | }, 23 | 24 | blocks: function(entity) { 25 | if (entity instanceof pocjs.entities.Player) return false; 26 | if (entity instanceof pocjs.entities.Bullet) return false; 27 | if (entity instanceof pocjs.entities.EyeBossEntity) return false; 28 | if (entity instanceof pocjs.entities.EyeEntity) return false; 29 | return true; 30 | } 31 | }); 32 | 33 | -------------------------------------------------------------------------------- /pocjs/level/block/LadderBlock.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.block.LadderBlock"); 2 | 3 | dojo.declare("pocjs.level.block.LadderBlock", pocjs.level.block.Block, { 4 | LADDER_COLOR: 0xDB8E53, 5 | wait: null, 6 | 7 | constructor: function(down) { 8 | if (down) { 9 | this.floorTex = 1; 10 | this.addSprite( 11 | new pocjs.gui.Sprite( 12 | 0, 0, 0, 8 + 3, pocjs.Art.getCol(this.LADDER_COLOR))); 13 | } 14 | else { 15 | this.ceilTex = 1; 16 | this.addSprite( 17 | new pocjs.gui.Sprite( 18 | 0, 0, 0, 8 + 4, pocjs.Art.getCol(this.LADDER_COLOR))); 19 | } 20 | }, 21 | 22 | removeEntity: function(entity) { 23 | this.inherited(arguments); 24 | if (entity instanceof pocjs.entities.Player) { 25 | this.wait = false; 26 | } 27 | }, 28 | 29 | addEntity: function(entity) { 30 | this.inherited(arguments); 31 | 32 | if (!this.wait && entity instanceof pocjs.entities.Player) { 33 | this.level.switchLevel(this.id); 34 | pocjs.Sound.ladder.play(); 35 | } 36 | } 37 | }); 38 | 39 | -------------------------------------------------------------------------------- /pocjs/level/block/LockedDoorBlock.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.block.LockedDoorBlock"); 2 | 3 | dojo.declare("pocjs.level.block.LockedDoorBlock", pocjs.level.block.DoorBlock, { 4 | constructor: function() { 5 | this.tex = 5; 6 | }, 7 | 8 | use: function(level, item) { 9 | return false; 10 | }, 11 | 12 | trigger: function(pressed) { 13 | this.open = pressed; 14 | } 15 | 16 | }); 17 | -------------------------------------------------------------------------------- /pocjs/level/block/LootBlock.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.block.LootBlock"); 2 | 3 | dojo.declare("pocjs.level.block.LootBlock", pocjs.level.block.Block, { 4 | taken: false, 5 | sprite: null, 6 | 7 | constructor: function() { 8 | this.sprite = new pocjs.gui.Sprite( 9 | 0, 0, 0, 16 + 2, pocjs.Art.getCol(0xffff80) 10 | ); 11 | this.addSprite(this.sprite); 12 | this.blocksMotion = true; 13 | }, 14 | 15 | addEntity: function(entity) { 16 | this.inherited(arguments,[entity]); 17 | if (!this.taken && entity instanceof pocjs.entities.Player) { 18 | this.sprite.removed = true; 19 | this.taken = true; 20 | this.blocksMotion = false; 21 | entity.loot++; 22 | pocjs.Sound.pickup.play(); 23 | } 24 | }, 25 | 26 | blocks: function(entity) { 27 | if (entity instanceof pocjs.entities.Player) return false; 28 | return this.blocksMotion; 29 | } 30 | }); 31 | 32 | -------------------------------------------------------------------------------- /pocjs/level/block/PitBlock.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.block.PitBlock"); 2 | 3 | dojo.declare("pocjs.level.block.PitBlock", pocjs.level.block.Block, { 4 | filled: false, 5 | 6 | constructor: function() { 7 | this.floorTex = 1; 8 | this.blocksMotion = true; 9 | }, 10 | 11 | addEntity: function(entity) { 12 | this.inherited(arguments); 13 | if (!this.filled && entity instanceof pocjs.entities.BoulderEntity) { 14 | entity.remove(); 15 | this.filled = true; 16 | this.blocksMotion = false; 17 | this.addSprite( 18 | new pocjs.gui.Sprite(0, 0, 0, 8 + 2, pocjs.entities.BoulderEntity.prototype.COLOR) 19 | ); 20 | pocjs.Sound.thud.play(); 21 | } 22 | }, 23 | 24 | blocks: function(entity) { 25 | if (entity instanceof pocjs.entities.BoulderEntity) return false; 26 | return this.blocksMotion; 27 | } 28 | }); 29 | 30 | -------------------------------------------------------------------------------- /pocjs/level/block/PressurePlateBlock.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.block.PressurePlateBlock"); 2 | 3 | dojo.declare("pocjs.level.block.PressurePlateBlock", pocjs.level.block.Block, { 4 | pressed: false, 5 | 6 | constructor: function() { 7 | this.floorTex = 2; 8 | }, 9 | 10 | tick: function() { 11 | this.inherited(arguments); 12 | var r = 0.2; 13 | var steppedOn = this.level.containsBlockingNonFlyingEntity( 14 | this.x - r, this.y - r, this.x + r, this.y + r 15 | ); 16 | if (steppedOn != this.pressed) { 17 | this.pressed = steppedOn; 18 | if (this.pressed) this.floorTex = 3; 19 | else this.floorTex = 2; 20 | 21 | this.level.trigger(this.id, this.pressed); 22 | if (this.pressed) 23 | pocjs.Sound.click1.play(); 24 | else 25 | pocjs.Sound.click2.play(); 26 | } 27 | }, 28 | 29 | getFloorHeight: function(e) { 30 | if (this.pressed) return -0.02; 31 | else return 0.02; 32 | } 33 | }); 34 | 35 | -------------------------------------------------------------------------------- /pocjs/level/block/SolidBlock.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.block.SolidBlock"); 2 | 3 | dojo.declare("pocjs.level.block.SolidBlock", pocjs.level.block.Block, { 4 | constructor: function() { 5 | this.solidRender = true; 6 | this.blocksMotion = true; 7 | } 8 | }); 9 | 10 | dojo.extend(pocjs.level.block.Block, { 11 | solidWall: new pocjs.level.block.SolidBlock() 12 | }); 13 | -------------------------------------------------------------------------------- /pocjs/level/block/SpiritWallBlock.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.block.SpiritWallBlock"); 2 | 3 | dojo.declare("pocjs.level.block.SpiritWallBlock", pocjs.level.block.Block, { 4 | constructor: function() { 5 | this.floorTex = 7; 6 | this.ceilTex = 7; 7 | this.blocksMotion = true; 8 | for (var i = 0; i < 6; i++) { 9 | var x = (Math.random() - 0.5); 10 | var y = (Math.random() - 0.7) * 0.3; 11 | var z = (Math.random() - 0.5); 12 | this.addSprite( 13 | new pocjs.gui.Sprite( 14 | x, y, z, 15 | 4 * 8 + 6 + Math.random() * 2 << 0, 16 | pocjs.Art.getCol(0x202020))); 17 | } 18 | }, 19 | 20 | blocks: function(entity) { 21 | if (entity instanceof pocjs.entities.Bullet) return false; 22 | return this.inherited(arguments); 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /pocjs/level/block/SwitchBlock.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.block.SwitchBlock"); 2 | 3 | dojo.declare("pocjs.level.block.SwitchBlock", pocjs.level.block.SolidBlock, { 4 | pressed: false, 5 | 6 | constructor: function() { 7 | this.tex = 2; 8 | }, 9 | 10 | use: function(level, item) { 11 | this.pressed = !this.pressed; 12 | if (this.pressed) this.tex = 3; 13 | else this.tex = 2; 14 | 15 | level.trigger(this.id, this.pressed); 16 | if (this.pressed) 17 | pocjs.Sound.click1.play(); 18 | else 19 | pocjs.Sound.click2.play(); 20 | 21 | return true; 22 | } 23 | }); 24 | -------------------------------------------------------------------------------- /pocjs/level/block/TorchBlock.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.block.TorchBlock"); 2 | 3 | dojo.declare("pocjs.level.block.TorchBlock", pocjs.level.block.Block, { 4 | torchSprite: null, 5 | 6 | constructor: function() { 7 | this.torchSprite = new pocjs.gui.Sprite(0, 0, 0, 3, pocjs.Art.getCol(0xffff00)); 8 | this.sprites.push(this.torchSprite); 9 | }, 10 | 11 | decorate: function(level, x, y) { 12 | // Random random = new Random((x + y * 1000) * 341871231); 13 | var r = 0.4; 14 | var block; 15 | for (var i = 0; i < 1000; i++) { 16 | var face = Math.random() * 4 << 0; 17 | 18 | block = level.getBlock(x - 1, y); 19 | if (face == 0 && block.solidRender && !(block instanceof pocjs.level.block.VanishBlock)) { 20 | this.torchSprite.x -= r; 21 | break; 22 | } 23 | 24 | block = level.getBlock(x, y - 1); 25 | if (face == 1 && block.solidRender && !(block instanceof pocjs.level.block.VanishBlock)) { 26 | this.torchSprite.z -= r; 27 | break; 28 | } 29 | 30 | block = level.getBlock(x + 1, y); 31 | if (face == 2 && block.solidRender && !(block instanceof pocjs.level.block.VanishBlock)) { 32 | this.torchSprite.x += r; 33 | break; 34 | } 35 | 36 | block = level.getBlock(x, y + 1); 37 | if (face == 3 && block.solidRender && !(block instanceof pocjs.level.block.VanishBlock)) { 38 | this.torchSprite.z += r; 39 | break; 40 | } 41 | } 42 | }, 43 | 44 | tick: function() { 45 | this.inherited(arguments); 46 | if ((Math.random() * 4 << 0) == 0) 47 | this.torchSprite.tex = 3 + (Math.random() * 2 << 0); 48 | } 49 | }); 50 | 51 | -------------------------------------------------------------------------------- /pocjs/level/block/VanishBlock.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.block.VanishBlock"); 2 | 3 | dojo.declare("pocjs.level.block.VanishBlock", pocjs.level.block.SolidBlock, { 4 | gone: false, 5 | 6 | constructor: function() { 7 | this.tex = 1; 8 | }, 9 | 10 | use: function(level, item) { 11 | if (this.gone) return false; 12 | 13 | this.gone = true; 14 | this.blocksMotion = false; 15 | this.solidRender = false; 16 | pocjs.Sound.crumble.play(); 17 | 18 | for (var i = 0; i < 32; i++) { 19 | var sprite = new pocjs.gui.RubbleSprite(); 20 | sprite.col = this.col; 21 | this.addSprite(sprite); 22 | } 23 | 24 | return true; 25 | } 26 | }); 27 | 28 | -------------------------------------------------------------------------------- /pocjs/level/block/WaterBlock.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.block.WaterBlock"); 2 | 3 | dojo.declare("pocjs.level.block.WaterBlock", pocjs.level.block.Block, { 4 | steps: 0, 5 | 6 | constructor: function() { 7 | this.blocksMotion = true; 8 | }, 9 | 10 | tick: function() { 11 | this.inherited(arguments); 12 | this.steps--; 13 | if (this.steps <= 0) { 14 | this.floorTex = 8 + Math.random() * 3 << 0; 15 | this.floorCol = pocjs.Art.getCol(0x0000ff); 16 | this.steps = 16; 17 | } 18 | }, 19 | 20 | blocks: function(entity) { 21 | if (entity instanceof pocjs.entities.Player) { 22 | if (entity.getSelectedItem() == pocjs.entities.Item.flippers) return false; 23 | } 24 | if (entity instanceof pocjs.entities.Bullet) return false; 25 | return this.blocksMotion; 26 | }, 27 | 28 | getFloorHeight: function(e) { 29 | return -0.5; 30 | }, 31 | 32 | getWalkSpeed: function(player) { 33 | return 0.4; 34 | } 35 | 36 | }); 37 | -------------------------------------------------------------------------------- /pocjs/level/block/WinBlock.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.level.block.WinBlock"); 2 | 3 | dojo.declare("pocjs.level.block.WinBlock", pocjs.level.block.Block, { 4 | addEntity: function(entity) { 5 | this.inherited(arguments); 6 | if (entity instanceof pocjs.entities.Player) { 7 | entity.win(); 8 | } 9 | } 10 | }); 11 | 12 | -------------------------------------------------------------------------------- /pocjs/menu/AboutMenu.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.menu.AboutMenu"); 2 | 3 | dojo.declare("pocjs.menu.AboutMenu", pocjs.menu.Menu, { 4 | 5 | tickDelay: 30, 6 | 7 | render: function(target) { 8 | target.fill(0, 0, 160, 120, 0); 9 | 10 | target.drawString("About", 60, 8, pocjs.Art.getCol(0xffffff)); 11 | 12 | var lines = [ 13 | "Prelude of the Chambered", 14 | "by Markus Persson.", 15 | "Made Aug 2011 for the", 16 | "21'st Ludum Dare compo.", 17 | "", 18 | "This game is freeware,", 19 | "and was made from scratch", 20 | "in just 48 hours." 21 | ]; 22 | 23 | for (var i = 0; i < lines.length; i++) { 24 | target.drawString(lines[i], 4, 28+i*8, pocjs.Art.getCol(0xa0a0a0)); 25 | } 26 | 27 | if (this.tickDelay == 0) 28 | target.drawString("-> Continue", 40, target.height - 16, pocjs.Art.getCol(0xffff80)); 29 | }, 30 | 31 | tick: function(game, up, down, left, right, use) { 32 | if (this.tickDelay > 0) this.tickDelay--; 33 | else if (use) { 34 | pocjs.Sound.click1.play(); 35 | game.setMenu(new pocjs.menu.TitleMenu()); 36 | } 37 | } 38 | }); 39 | 40 | -------------------------------------------------------------------------------- /pocjs/menu/GotLootMenu.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.menu.GotLootMenu"); 2 | 3 | dojo.declare("pocjs.menu.GotLootMenu", pocjs.menu.Menu, { 4 | tickDelay: 30, 5 | item: null, 6 | 7 | constructor: function(item) { 8 | this.item = item; 9 | }, 10 | 11 | render: function(target) { 12 | var str = "You found the " + this.item.name + "!"; 13 | target.scaleDraw( 14 | pocjs.Art.items, 3, 15 | target.width / 2 - 8 * 3, 2, this.item.icon * 16, 0, 16, 16, 16 | pocjs.Art.getCol(this.item.color)); 17 | target.drawString( 18 | str, (target.width - str.length * 6) / 2 + 2, 60 - 10, 19 | pocjs.Art.getCol(0xffff80)); 20 | 21 | str = this.item.description; 22 | target.drawString( 23 | str, (target.width - str.length * 6) / 2 + 2, 60, 24 | pocjs.Art.getCol(0xa0a0a0)); 25 | 26 | if (this.tickDelay == 0) 27 | target.drawString("-> Continue", 40, target.height - 40, pocjs.Art.getCol(0xffff80)); 28 | }, 29 | 30 | tick: function(game, up, down, left, right, use) { 31 | if (this.tickDelay > 0) this.tickDelay--; 32 | else if (use) { 33 | game.setMenu(null); 34 | } 35 | } 36 | }); 37 | 38 | -------------------------------------------------------------------------------- /pocjs/menu/InstructionsMenu.js: -------------------------------------------------------------------------------- 1 | dojo.provide("pocjs.menu.InstructionsMenu"); 2 | 3 | dojo.declare("pocjs.menu.InstructionsMenu", pocjs.menu.Menu, { 4 | 5 | tickDelay: 30, 6 | 7 | render: function(target) { 8 | target.fill(0, 0, 160, 120, 0); 9 | 10 | target.drawString("Instructions", 40, 8, pocjs.Art.getCol(0xffffff)); 11 | 12 | var lines = [ 13 | "Use W,A,S,D to move, and", 14 | "the arrow keys to turn.", 15 | "", 16 | "The 1-8 keys select", 17 | "items from the inventory", 18 | "", 19 | "Space uses items" 20 | ]; 21 | 22 | for (var i=0; i