├── README.md └── src ├── Gruntfile.js ├── MelonJS_MIT-LICENSE ├── MusicAttribution.txt ├── README.md ├── data ├── bgm │ ├── instruction_screen.aac │ ├── level01bgm.aac │ ├── lost_island.aac │ ├── low_point.aac │ └── title_music.aac ├── fnt │ ├── font.fnt │ ├── font.png │ ├── moneyfont.fnt │ └── moneyfont.png ├── img │ ├── HUD │ │ ├── HUD_bar.png │ │ ├── level_complete.png │ │ ├── level_failed.png │ │ ├── pause_menu.png │ │ └── pause_text.png │ ├── enemies │ │ ├── footmanchilled.png │ │ ├── goblinchilled.png │ │ └── impchilled.png │ ├── gui │ │ ├── Instructions1.xcf │ │ ├── Instructions2.xcf │ │ ├── Instructions3.xcf │ │ ├── Instructions4.xcf │ │ ├── Instructions5.xcf │ │ ├── Instructions6.xcf │ │ ├── gameOver.png │ │ ├── gameOver.xcf │ │ ├── instructions1.png │ │ ├── instructions2.png │ │ ├── instructions3.png │ │ ├── instructions4.png │ │ ├── instructions5.png │ │ ├── instructions6.png │ │ ├── introLevel01.png │ │ ├── introLevel01.xcf │ │ ├── introLevel02.png │ │ ├── introLevel02.xcf │ │ ├── introLevel03.png │ │ ├── introLevel03.xcf │ │ ├── title2.png │ │ ├── title2.xcf │ │ ├── title3.png │ │ ├── title3.xcf │ │ ├── title3low.png │ │ ├── title_screen.png │ │ ├── title_screen.xcf │ │ ├── winscreen.png │ │ ├── xxintroLevel01.png │ │ ├── xxintroLevel02.png │ │ └── xxintroLevel03.png │ ├── maps │ │ ├── Castle.png │ │ ├── Castle2.png │ │ ├── erodaxia summary.png │ │ ├── map01.png │ │ ├── map02.png │ │ ├── map03.png │ │ ├── stone-bridge.png │ │ ├── tilesheet.png │ │ ├── trees_plants_rocks.png │ │ └── wood_tileset.png │ ├── menu │ │ ├── arrow_bleed_icons.png │ │ ├── arrow_icons.png │ │ ├── arrow_multi_icons.png │ │ ├── cancel_icon.png │ │ ├── cannon_aoe_icons.png │ │ ├── cannon_damage_icons.png │ │ ├── cannon_icons.png │ │ ├── icons.png │ │ ├── menu_button.png │ │ ├── menu_circle.png │ │ ├── option_menu.png │ │ ├── sell_icon.png │ │ ├── sell_icons.png │ │ ├── slow_damage_icons.png │ │ ├── slow_icons.png │ │ ├── slow_slower_icons.png │ │ ├── tower_location.png │ │ └── upgraded_icon.png │ ├── other │ │ └── smallFire.png │ ├── projectiles │ │ ├── arrows.png │ │ ├── bleedEffect.png │ │ ├── cannonball.png │ │ ├── explosion.png │ │ └── freeze_exp.png │ └── towers │ │ ├── archer_tower.png │ │ ├── cannon_tower.png │ │ ├── slow_tower.png │ │ └── tower-base.xcf ├── map │ ├── introLevel01.png │ ├── map01.tmx │ ├── map01Intro.png │ ├── map01Intro.tmx │ ├── map01Intro.xcf │ ├── map01backup.tmx │ ├── map02.tmx │ ├── map02Intro.png │ ├── map02Intro.tmx │ ├── map02Intro.xcf │ ├── map02backup.tmx │ ├── map03.tmx │ ├── map03Intro.png │ ├── map03Intro.tmx │ ├── map03Intro.xcf │ └── map03backup.tmx └── sfx │ ├── arrow_shoot.aac │ ├── boss_death.aac │ ├── cannon_shoot.aac │ ├── footman_death.aac │ ├── goblin_death.aac │ ├── imp_death.aac │ ├── sell_item.aac │ ├── slow_shoot.aac │ ├── tower_drop.aac │ └── upgrade.aac ├── icons ├── touch-icon-ipad-76x76.png ├── touch-icon-ipad-retina-152x152.png ├── touch-icon-iphone-60x60.png ├── touch-icon-iphone-retina-120x120.png └── touch-icon-marketplace-128x128.png ├── index.css ├── index.html ├── js ├── entities │ ├── HUD.js │ ├── archerTower.js │ ├── archerTowerMenu.js │ ├── cannonTower.js │ ├── cannonTowerMenu.js │ ├── entities.js │ ├── footmanEntity.js │ ├── goblinEntity.js │ ├── impEntity.js │ ├── option_menu.js │ ├── projectiles.js │ ├── slowTower.js │ ├── slowTowerMenu.js │ └── tower_menu.js ├── game.js ├── gamefunctions.js └── screens │ ├── gameOver.js │ ├── instructions.js │ ├── level01.js │ ├── level02.js │ ├── level03.js │ ├── levelIntro.js │ └── title.js ├── lib ├── melonJS.js └── plugins │ └── debug │ └── debugPanel.js ├── license └── CCby3.0.PNG ├── main.js ├── manifest.json ├── package.json └── tasks └── grunt-resources.js /README.md: -------------------------------------------------------------------------------- 1 | # PixelDefense 2 | 3 | A HTML5/JS based tower defense game. 4 | 5 | Collaborated with Michael Tarantino and Morgan Howard to produce for 6 | Oregon State University as a capstone project for a BS Comp Sci. 7 | 8 | Currently hosted at people.oregonstate.edu/~thorenje/OctansTDFinal/ 9 | -------------------------------------------------------------------------------- /src/Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | grunt.initConfig({ 3 | pkg: grunt.file.readJSON('package.json'), 4 | 5 | concat: { 6 | dist: { 7 | src: [ 8 | 'lib/melonJS.js', 9 | 'lib/plugins/*.js', 10 | 'js/game.js', 11 | 'build/js/resources.js', 12 | 'js/**/*.js', 13 | ], 14 | dest: 'build/js/app.js' 15 | } 16 | }, 17 | 18 | copy: { 19 | dist: { 20 | files: [{ 21 | src: 'index.css', 22 | dest: 'build/index.css' 23 | },{ 24 | src: 'main.js', 25 | dest: 'build/main.js' 26 | },{ 27 | src: 'manifest.json', 28 | dest: 'build/manifest.json' 29 | },{ 30 | src: 'package.json', 31 | dest: 'build/package.json' 32 | },{ 33 | src: 'data/**/*', 34 | dest: 'build/', 35 | expand: true 36 | },{ 37 | src: 'icons/*', 38 | dest: 'build/', 39 | expand: true 40 | }] 41 | } 42 | }, 43 | 44 | clean: { 45 | app: ['build/js/app.js'], 46 | dist: ['build/','bin/'], 47 | }, 48 | 49 | processhtml: { 50 | dist: { 51 | options: { 52 | process: true, 53 | data: { 54 | title: '<%= pkg.name %>', 55 | } 56 | }, 57 | files: { 58 | 'build/index.html': ['index.html'] 59 | } 60 | } 61 | }, 62 | 63 | replace : { 64 | dist : { 65 | options : { 66 | usePrefix : false, 67 | force : true, 68 | patterns : [ 69 | { 70 | match : /this\._super\(\s*([\w\.]+)\s*,\s*["'](\w+)["']\s*(,\s*)?/g, 71 | replacement : '$1.prototype.$2.apply(this$3' 72 | }, 73 | ], 74 | }, 75 | files : [ 76 | { 77 | src : [ 'build/js/app.js' ], 78 | dest : 'build/js/app.js' 79 | } 80 | ] 81 | }, 82 | }, 83 | 84 | uglify: { 85 | options: { 86 | report: 'min', 87 | preserveComments: 'some' 88 | }, 89 | dist: { 90 | files: { 91 | 'build/js/app.min.js': [ 92 | 'build/js/app.js' 93 | ] 94 | } 95 | } 96 | }, 97 | 98 | connect: { 99 | server: { 100 | options: { 101 | port: 8000, 102 | keepalive: false 103 | } 104 | } 105 | }, 106 | 107 | 'download-electron': { 108 | version: '1.4.6', 109 | outputDir: 'bin', 110 | rebuild: false, 111 | }, 112 | 113 | asar: { 114 | dist: { 115 | cwd: 'build', 116 | src: ['**/*', '!js/app.js'], 117 | expand: true, 118 | dest: 'bin/' + ( 119 | process.platform === 'darwin' 120 | ? 'Electron.app/Contents/Resources/' 121 | : 'resources/' 122 | ) + 'app.asar' 123 | }, 124 | }, 125 | 126 | resources: { 127 | dist: { 128 | options: { 129 | dest: 'build/js/resources.js', 130 | varname: 'game.resources', 131 | }, 132 | files: [{ 133 | src: ['data/bgm/**/*', 'data/sfx/**/*'], 134 | type: 'audio' 135 | },{ 136 | src: ['data/img/**/*.png'], 137 | type: 'image' 138 | },{ 139 | src: ['data/img/**/*.json'], 140 | type: 'json' 141 | },{ 142 | src: ['data/map/**/*.tmx', 'data/map/**/*.json'], 143 | type: 'tmx' 144 | },{ 145 | src: ['data/map/**/*.tsx'], 146 | type: 'tsx' 147 | },{ 148 | src: ['data/fnt/**/*.fnt'], 149 | type: 'binary' 150 | },{ 151 | src: ['data/fnt/**/*.png'], 152 | type: 'image' 153 | }] 154 | } 155 | }, 156 | 157 | watch: { 158 | resources: { 159 | files: ['data/**/*'], 160 | tasks: ['resources'], 161 | options: { 162 | spawn: false, 163 | }, 164 | }, 165 | }, 166 | 167 | }); 168 | 169 | grunt.loadNpmTasks('grunt-contrib-concat'); 170 | grunt.loadNpmTasks('grunt-contrib-uglify'); 171 | grunt.loadNpmTasks('grunt-contrib-copy'); 172 | grunt.loadNpmTasks('grunt-contrib-clean'); 173 | grunt.loadNpmTasks('grunt-contrib-watch'); 174 | grunt.loadNpmTasks('grunt-processhtml'); 175 | grunt.loadNpmTasks("grunt-replace"); 176 | grunt.loadNpmTasks('grunt-contrib-connect'); 177 | grunt.loadNpmTasks('grunt-download-electron'); 178 | grunt.loadNpmTasks('grunt-asar'); 179 | 180 | // Custom Tasks 181 | grunt.loadTasks('tasks'); 182 | 183 | grunt.registerTask('default', [ 184 | 'resources', 185 | 'concat', 186 | 'replace', 187 | 'uglify', 188 | 'copy', 189 | 'processhtml', 190 | 'clean:app', 191 | ]); 192 | grunt.registerTask('dist', ['default', 'download-electron', 'asar']); 193 | grunt.registerTask('serve', ['resources', 'connect', 'watch']); 194 | } 195 | -------------------------------------------------------------------------------- /src/MelonJS_MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) <2011 - 2013> by 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/MusicAttribution.txt: -------------------------------------------------------------------------------- 1 | If you are using only my music and not that of another artist(s) then your credits screen in your video or game needs to say: 2 | 3 | Music by Eric Matyas 4 | 5 | www.soundimage.org 6 | 7 | If you are using my music as well as those of another artist(s) then you need to identify which tracks (and/or sound effects) are mine and credit me, for example: 8 | 9 | "Lost-Island" by Eric Matyas 10 | "Low-Point" by Eric Matyas 11 | "RPG Intro" by Eric Matyas 12 | 13 | www.soundimage.org -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | melonJS boilerplate 2 | ------------------------------------------------------------------------------- 3 | 4 | features : 5 | - video autoscaling 6 | - mobile optimized HTML/CSS 7 | - swiping disabled on iOS devices 8 | - debug Panel (if #debug) 9 | - default icons 10 | - distribution build 11 | - standalone build for desktop operating systems 12 | 13 | ## To run distribution 14 | 15 | To build, be sure you have [node](http://nodejs.org) installed. Clone the project: 16 | 17 | git clone https://github.com/melonjs/boilerplate.git 18 | 19 | Then in the cloned directory, simply run: 20 | 21 | npm install 22 | 23 | You must also have `grunt-cli` installed globally: 24 | 25 | npm install -g grunt-cli 26 | 27 | Running the game: 28 | 29 | grunt serve 30 | 31 | And you will have the boilerplate example running on http://localhost:8000 32 | 33 | ## Building Release Versions 34 | 35 | To build: 36 | 37 | grunt 38 | 39 | This will create a `build` directory containing the files that can be uploaded to a server, or packaged into a mobile app. 40 | 41 | ---- 42 | 43 | Building a standalone desktop release: 44 | 45 | grunt dist 46 | 47 | Running the desktop release on Windows: 48 | 49 | .\bin\electron.exe 50 | 51 | Running the desktop release on macOS: 52 | 53 | open ./bin/Electron.app 54 | 55 | Running the desktop release on Linux: 56 | 57 | ./bin/electron 58 | 59 | Note that you may have to edit the file `Gruntfile.js` if you need to better dictate the order your files load in. Note how by default the game.js and resources.js are specified in a specific order. 60 | 61 | ------------------------------------------------------------------------------- 62 | Copyright (C) 2011 - 2015 Olivier Biot, Jason Oster, Aaron McLeod 63 | melonJS is licensed under the [MIT License](http://www.opensource.org/licenses/mit-license.php) 64 | -------------------------------------------------------------------------------- /src/data/bgm/instruction_screen.aac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/bgm/instruction_screen.aac -------------------------------------------------------------------------------- /src/data/bgm/level01bgm.aac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/bgm/level01bgm.aac -------------------------------------------------------------------------------- /src/data/bgm/lost_island.aac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/bgm/lost_island.aac -------------------------------------------------------------------------------- /src/data/bgm/low_point.aac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/bgm/low_point.aac -------------------------------------------------------------------------------- /src/data/bgm/title_music.aac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/bgm/title_music.aac -------------------------------------------------------------------------------- /src/data/fnt/font.fnt: -------------------------------------------------------------------------------- 1 | info face=font size=24 bold=0 italic=0 charset= unicode= stretchH=100 smooth=1 aa=1 padding=4,4,4,4 spacing=0,0 outline=0 2 | common lineHeight=27 base=18 scaleW=128 scaleH=512 pages=1 packed=0 3 | page id=0 file="font.png" 4 | chars count=61 5 | char id=65 x=4 y=4 width=19 height=20 xoffset=0 yoffset=0 xadvance=16 page=0 chnl=15 6 | char id=66 x=4 y=28 width=15 height=20 xoffset=2 yoffset=0 xadvance=16 page=0 chnl=15 7 | char id=67 x=4 y=52 width=18 height=20 xoffset=1 yoffset=0 xadvance=17 page=0 chnl=15 8 | char id=68 x=23 y=28 width=17 height=20 xoffset=2 yoffset=0 xadvance=17 page=0 chnl=15 9 | char id=69 x=27 y=4 width=15 height=19 xoffset=2 yoffset=0 xadvance=16 page=0 chnl=15 10 | char id=70 x=4 y=76 width=14 height=20 xoffset=2 yoffset=0 xadvance=15 page=0 chnl=15 11 | char id=71 x=4 y=100 width=18 height=20 xoffset=1 yoffset=0 xadvance=19 page=0 chnl=15 12 | char id=72 x=22 y=76 width=16 height=20 xoffset=2 yoffset=0 xadvance=17 page=0 chnl=15 13 | char id=73 x=26 y=52 width=4 height=20 xoffset=2 yoffset=0 xadvance=7 page=0 chnl=15 14 | char id=74 x=34 y=52 width=12 height=20 xoffset=1 yoffset=0 xadvance=12 page=0 chnl=15 15 | char id=75 x=44 y=27 width=17 height=20 xoffset=2 yoffset=0 xadvance=16 page=0 chnl=15 16 | char id=76 x=46 y=4 width=13 height=19 xoffset=2 yoffset=0 xadvance=13 page=0 chnl=15 17 | char id=77 x=4 y=124 width=19 height=20 xoffset=2 yoffset=0 xadvance=20 page=0 chnl=15 18 | char id=78 x=26 y=100 width=16 height=20 xoffset=2 yoffset=0 xadvance=17 page=0 chnl=15 19 | char id=79 x=42 y=76 width=19 height=20 xoffset=1 yoffset=0 xadvance=19 page=0 chnl=15 20 | char id=80 x=50 y=51 width=15 height=20 xoffset=2 yoffset=0 xadvance=16 page=0 chnl=15 21 | char id=81 x=65 y=4 width=19 height=21 xoffset=1 yoffset=0 xadvance=19 page=0 chnl=15 22 | char id=82 x=4 y=148 width=17 height=20 xoffset=2 yoffset=0 xadvance=17 page=0 chnl=15 23 | char id=83 x=4 y=172 width=16 height=20 xoffset=1 yoffset=0 xadvance=16 page=0 chnl=15 24 | char id=84 x=4 y=196 width=16 height=20 xoffset=1 yoffset=0 xadvance=15 page=0 chnl=15 25 | char id=86 x=4 y=220 width=19 height=20 xoffset=0 yoffset=0 xadvance=16 page=0 chnl=15 26 | char id=87 x=24 y=172 width=24 height=20 xoffset=0 yoffset=0 xadvance=23 page=0 chnl=15 27 | char id=88 x=25 y=148 width=19 height=20 xoffset=0 yoffset=0 xadvance=16 page=0 chnl=15 28 | char id=89 x=27 y=124 width=18 height=20 xoffset=0 yoffset=0 xadvance=16 page=0 chnl=15 29 | char id=90 x=48 y=148 width=16 height=19 xoffset=0 yoffset=0 xadvance=15 page=0 chnl=15 30 | char id=48 x=46 y=100 width=14 height=20 xoffset=1 yoffset=0 xadvance=13 page=0 chnl=15 31 | char id=49 x=49 y=124 width=8 height=20 xoffset=3 yoffset=0 xadvance=13 page=0 chnl=15 32 | char id=50 x=61 y=124 width=14 height=19 xoffset=1 yoffset=0 xadvance=13 page=0 chnl=15 33 | char id=51 x=64 y=100 width=14 height=20 xoffset=1 yoffset=0 xadvance=13 page=0 chnl=15 34 | char id=52 x=24 y=196 width=14 height=20 xoffset=0 yoffset=0 xadvance=13 page=0 chnl=15 35 | char id=53 x=65 y=75 width=14 height=20 xoffset=1 yoffset=1 xadvance=13 page=0 chnl=15 36 | char id=54 x=69 y=29 width=14 height=20 xoffset=1 yoffset=0 xadvance=13 page=0 chnl=15 37 | char id=55 x=4 y=244 width=13 height=19 xoffset=1 yoffset=1 xadvance=13 page=0 chnl=15 38 | char id=56 x=4 y=267 width=14 height=20 xoffset=1 yoffset=0 xadvance=13 page=0 chnl=15 39 | char id=57 x=4 y=291 width=14 height=20 xoffset=1 yoffset=0 xadvance=13 page=0 chnl=15 40 | char id=97 x=69 y=53 width=14 height=15 xoffset=1 yoffset=5 xadvance=13 page=0 chnl=15 41 | char id=98 x=4 y=315 width=13 height=20 xoffset=2 yoffset=0 xadvance=13 page=0 chnl=15 42 | char id=99 x=21 y=244 width=13 height=15 xoffset=1 yoffset=5 xadvance=12 page=0 chnl=15 43 | char id=100 x=27 y=220 width=13 height=20 xoffset=1 yoffset=0 xadvance=13 page=0 chnl=15 44 | char id=101 x=42 y=196 width=14 height=15 xoffset=1 yoffset=5 xadvance=13 page=0 chnl=15 45 | char id=102 x=52 y=171 width=10 height=20 xoffset=0 yoffset=0 xadvance=7 page=0 chnl=15 46 | char id=103 x=4 y=339 width=13 height=20 xoffset=1 yoffset=5 xadvance=13 page=0 chnl=15 47 | char id=104 x=4 y=363 width=12 height=20 xoffset=2 yoffset=0 xadvance=13 page=0 chnl=15 48 | char id=105 x=4 y=387 width=4 height=20 xoffset=2 yoffset=0 xadvance=5 page=0 chnl=15 49 | char id=106 x=4 y=411 width=7 height=25 xoffset=-1 yoffset=0 xadvance=5 page=0 chnl=15 50 | char id=107 x=12 y=387 width=13 height=20 xoffset=2 yoffset=0 xadvance=12 page=0 chnl=15 51 | char id=108 x=20 y=363 width=4 height=20 xoffset=2 yoffset=0 xadvance=5 page=0 chnl=15 52 | char id=109 x=21 y=315 width=19 height=15 xoffset=2 yoffset=5 xadvance=20 page=0 chnl=15 53 | char id=110 x=21 y=334 width=12 height=15 xoffset=2 yoffset=5 xadvance=13 page=0 chnl=15 54 | char id=111 x=28 y=353 width=14 height=15 xoffset=1 yoffset=5 xadvance=13 page=0 chnl=15 55 | char id=112 x=22 y=263 width=13 height=20 xoffset=2 yoffset=5 xadvance=13 page=0 chnl=15 56 | char id=113 x=22 y=287 width=13 height=20 xoffset=1 yoffset=5 xadvance=13 page=0 chnl=15 57 | char id=114 x=38 y=244 width=9 height=15 xoffset=2 yoffset=5 xadvance=8 page=0 chnl=15 58 | char id=115 x=37 y=334 width=13 height=15 xoffset=1 yoffset=5 xadvance=12 page=0 chnl=15 59 | char id=116 x=44 y=215 width=8 height=20 xoffset=0 yoffset=1 xadvance=7 page=0 chnl=15 60 | char id=117 x=39 y=263 width=12 height=15 xoffset=2 yoffset=5 xadvance=13 page=0 chnl=15 61 | char id=118 x=51 y=239 width=14 height=15 xoffset=0 yoffset=5 xadvance=12 page=0 chnl=15 62 | char id=119 x=56 y=215 width=20 height=15 xoffset=-1 yoffset=5 xadvance=17 page=0 chnl=15 63 | char id=120 x=60 y=195 width=14 height=15 xoffset=0 yoffset=5 xadvance=12 page=0 chnl=15 64 | char id=121 x=66 y=171 width=14 height=20 xoffset=0 yoffset=5 xadvance=12 page=0 chnl=15 65 | char id=122 x=78 y=195 width=13 height=15 xoffset=0 yoffset=5 xadvance=12 page=0 chnl=15 66 | char id=32 x=0 y=0 width=0 height=0 xoffset=0 yoffset=5 xadvance=7 page=0 chnl=15 67 | kernings count=65 68 | kerning first=32 second=65 amount=-1 69 | kerning first=32 second=84 amount=0 70 | kerning first=32 second=89 amount=0 71 | kerning first=49 second=49 amount=-2 72 | kerning first=65 second=32 amount=-1 73 | kerning first=65 second=84 amount=-2 74 | kerning first=65 second=86 amount=-2 75 | kerning first=65 second=87 amount=-1 76 | kerning first=65 second=89 amount=-2 77 | kerning first=65 second=118 amount=0 78 | kerning first=65 second=119 amount=0 79 | kerning first=65 second=121 amount=0 80 | kerning first=70 second=65 amount=-1 81 | kerning first=76 second=32 amount=-1 82 | kerning first=76 second=84 amount=-2 83 | kerning first=76 second=86 amount=-2 84 | kerning first=76 second=87 amount=-2 85 | kerning first=76 second=89 amount=-2 86 | kerning first=76 second=121 amount=-1 87 | kerning first=80 second=32 amount=0 88 | kerning first=80 second=65 amount=-2 89 | kerning first=82 second=84 amount=0 90 | kerning first=82 second=86 amount=0 91 | kerning first=82 second=87 amount=0 92 | kerning first=82 second=89 amount=0 93 | kerning first=84 second=32 amount=0 94 | kerning first=84 second=65 amount=-2 95 | kerning first=84 second=79 amount=0 96 | kerning first=84 second=97 amount=-3 97 | kerning first=84 second=99 amount=-3 98 | kerning first=84 second=101 amount=-3 99 | kerning first=84 second=105 amount=-1 100 | kerning first=84 second=111 amount=-3 101 | kerning first=84 second=114 amount=-1 102 | kerning first=84 second=115 amount=-3 103 | kerning first=84 second=117 amount=-1 104 | kerning first=84 second=119 amount=-1 105 | kerning first=84 second=121 amount=-1 106 | kerning first=86 second=65 amount=-2 107 | kerning first=86 second=97 amount=-2 108 | kerning first=86 second=101 amount=-1 109 | kerning first=86 second=105 amount=0 110 | kerning first=86 second=111 amount=-1 111 | kerning first=86 second=114 amount=-1 112 | kerning first=86 second=117 amount=-1 113 | kerning first=86 second=121 amount=-1 114 | kerning first=87 second=65 amount=-1 115 | kerning first=87 second=97 amount=-1 116 | kerning first=87 second=101 amount=0 117 | kerning first=87 second=105 amount=0 118 | kerning first=87 second=111 amount=0 119 | kerning first=87 second=114 amount=0 120 | kerning first=87 second=117 amount=0 121 | kerning first=87 second=121 amount=0 122 | kerning first=89 second=32 amount=0 123 | kerning first=89 second=65 amount=-2 124 | kerning first=89 second=97 amount=-2 125 | kerning first=89 second=101 amount=-2 126 | kerning first=89 second=105 amount=-1 127 | kerning first=89 second=111 amount=-2 128 | kerning first=89 second=112 amount=-2 129 | kerning first=89 second=113 amount=-2 130 | kerning first=89 second=117 amount=-1 131 | kerning first=89 second=118 amount=-1 132 | kerning first=102 second=102 amount=0 -------------------------------------------------------------------------------- /src/data/fnt/font.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/fnt/font.png -------------------------------------------------------------------------------- /src/data/fnt/moneyfont.fnt: -------------------------------------------------------------------------------- 1 | info face=font size=16 bold=0 italic=0 charset= unicode= stretchH=100 smooth=1 aa=1 padding=4,4,4,4 spacing=0,0 outline=0 2 | common lineHeight=18 base=13 scaleW=32 scaleH=256 pages=1 packed=0 3 | page id=0 file="font.png" 4 | chars count=11 5 | char id=36 x=4 y=4 width=10 height=17 xoffset=1 yoffset=0 xadvance=9 page=0 chnl=15 6 | char id=48 x=4 y=25 width=10 height=14 xoffset=1 yoffset=1 xadvance=9 page=0 chnl=15 7 | char id=49 x=4 y=43 width=6 height=14 xoffset=2 yoffset=1 xadvance=9 page=0 chnl=15 8 | char id=50 x=4 y=61 width=10 height=14 xoffset=0 yoffset=1 xadvance=9 page=0 chnl=15 9 | char id=51 x=14 y=43 width=10 height=14 xoffset=1 yoffset=1 xadvance=9 page=0 chnl=15 10 | char id=52 x=18 y=4 width=10 height=14 xoffset=0 yoffset=1 xadvance=9 page=0 chnl=15 11 | char id=53 x=18 y=22 width=10 height=14 xoffset=1 yoffset=1 xadvance=9 page=0 chnl=15 12 | char id=54 x=4 y=79 width=10 height=14 xoffset=1 yoffset=1 xadvance=9 page=0 chnl=15 13 | char id=55 x=4 y=97 width=10 height=14 xoffset=1 yoffset=1 xadvance=9 page=0 chnl=15 14 | char id=56 x=4 y=115 width=10 height=14 xoffset=1 yoffset=1 xadvance=9 page=0 chnl=15 15 | char id=57 x=4 y=133 width=10 height=14 xoffset=1 yoffset=1 xadvance=9 page=0 chnl=15 16 | char id=32 x=0 y=0 width=0 height=0 xoffset=1 yoffset=1 xadvance=4 page=0 chnl=15 17 | kernings count=1 18 | kerning first=49 second=49 amount=-1 -------------------------------------------------------------------------------- /src/data/fnt/moneyfont.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/fnt/moneyfont.png -------------------------------------------------------------------------------- /src/data/img/HUD/HUD_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/HUD/HUD_bar.png -------------------------------------------------------------------------------- /src/data/img/HUD/level_complete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/HUD/level_complete.png -------------------------------------------------------------------------------- /src/data/img/HUD/level_failed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/HUD/level_failed.png -------------------------------------------------------------------------------- /src/data/img/HUD/pause_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/HUD/pause_menu.png -------------------------------------------------------------------------------- /src/data/img/HUD/pause_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/HUD/pause_text.png -------------------------------------------------------------------------------- /src/data/img/enemies/footmanchilled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/enemies/footmanchilled.png -------------------------------------------------------------------------------- /src/data/img/enemies/goblinchilled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/enemies/goblinchilled.png -------------------------------------------------------------------------------- /src/data/img/enemies/impchilled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/enemies/impchilled.png -------------------------------------------------------------------------------- /src/data/img/gui/Instructions1.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/Instructions1.xcf -------------------------------------------------------------------------------- /src/data/img/gui/Instructions2.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/Instructions2.xcf -------------------------------------------------------------------------------- /src/data/img/gui/Instructions3.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/Instructions3.xcf -------------------------------------------------------------------------------- /src/data/img/gui/Instructions4.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/Instructions4.xcf -------------------------------------------------------------------------------- /src/data/img/gui/Instructions5.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/Instructions5.xcf -------------------------------------------------------------------------------- /src/data/img/gui/Instructions6.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/Instructions6.xcf -------------------------------------------------------------------------------- /src/data/img/gui/gameOver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/gameOver.png -------------------------------------------------------------------------------- /src/data/img/gui/gameOver.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/gameOver.xcf -------------------------------------------------------------------------------- /src/data/img/gui/instructions1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/instructions1.png -------------------------------------------------------------------------------- /src/data/img/gui/instructions2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/instructions2.png -------------------------------------------------------------------------------- /src/data/img/gui/instructions3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/instructions3.png -------------------------------------------------------------------------------- /src/data/img/gui/instructions4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/instructions4.png -------------------------------------------------------------------------------- /src/data/img/gui/instructions5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/instructions5.png -------------------------------------------------------------------------------- /src/data/img/gui/instructions6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/instructions6.png -------------------------------------------------------------------------------- /src/data/img/gui/introLevel01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/introLevel01.png -------------------------------------------------------------------------------- /src/data/img/gui/introLevel01.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/introLevel01.xcf -------------------------------------------------------------------------------- /src/data/img/gui/introLevel02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/introLevel02.png -------------------------------------------------------------------------------- /src/data/img/gui/introLevel02.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/introLevel02.xcf -------------------------------------------------------------------------------- /src/data/img/gui/introLevel03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/introLevel03.png -------------------------------------------------------------------------------- /src/data/img/gui/introLevel03.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/introLevel03.xcf -------------------------------------------------------------------------------- /src/data/img/gui/title2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/title2.png -------------------------------------------------------------------------------- /src/data/img/gui/title2.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/title2.xcf -------------------------------------------------------------------------------- /src/data/img/gui/title3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/title3.png -------------------------------------------------------------------------------- /src/data/img/gui/title3.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/title3.xcf -------------------------------------------------------------------------------- /src/data/img/gui/title3low.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/title3low.png -------------------------------------------------------------------------------- /src/data/img/gui/title_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/title_screen.png -------------------------------------------------------------------------------- /src/data/img/gui/title_screen.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/title_screen.xcf -------------------------------------------------------------------------------- /src/data/img/gui/winscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/winscreen.png -------------------------------------------------------------------------------- /src/data/img/gui/xxintroLevel01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/xxintroLevel01.png -------------------------------------------------------------------------------- /src/data/img/gui/xxintroLevel02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/xxintroLevel02.png -------------------------------------------------------------------------------- /src/data/img/gui/xxintroLevel03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/gui/xxintroLevel03.png -------------------------------------------------------------------------------- /src/data/img/maps/Castle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/maps/Castle.png -------------------------------------------------------------------------------- /src/data/img/maps/Castle2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/maps/Castle2.png -------------------------------------------------------------------------------- /src/data/img/maps/erodaxia summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/maps/erodaxia summary.png -------------------------------------------------------------------------------- /src/data/img/maps/map01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/maps/map01.png -------------------------------------------------------------------------------- /src/data/img/maps/map02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/maps/map02.png -------------------------------------------------------------------------------- /src/data/img/maps/map03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/maps/map03.png -------------------------------------------------------------------------------- /src/data/img/maps/stone-bridge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/maps/stone-bridge.png -------------------------------------------------------------------------------- /src/data/img/maps/tilesheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/maps/tilesheet.png -------------------------------------------------------------------------------- /src/data/img/maps/trees_plants_rocks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/maps/trees_plants_rocks.png -------------------------------------------------------------------------------- /src/data/img/maps/wood_tileset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/maps/wood_tileset.png -------------------------------------------------------------------------------- /src/data/img/menu/arrow_bleed_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/menu/arrow_bleed_icons.png -------------------------------------------------------------------------------- /src/data/img/menu/arrow_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/menu/arrow_icons.png -------------------------------------------------------------------------------- /src/data/img/menu/arrow_multi_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/menu/arrow_multi_icons.png -------------------------------------------------------------------------------- /src/data/img/menu/cancel_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/menu/cancel_icon.png -------------------------------------------------------------------------------- /src/data/img/menu/cannon_aoe_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/menu/cannon_aoe_icons.png -------------------------------------------------------------------------------- /src/data/img/menu/cannon_damage_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/menu/cannon_damage_icons.png -------------------------------------------------------------------------------- /src/data/img/menu/cannon_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/menu/cannon_icons.png -------------------------------------------------------------------------------- /src/data/img/menu/icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/menu/icons.png -------------------------------------------------------------------------------- /src/data/img/menu/menu_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/menu/menu_button.png -------------------------------------------------------------------------------- /src/data/img/menu/menu_circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/menu/menu_circle.png -------------------------------------------------------------------------------- /src/data/img/menu/option_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/menu/option_menu.png -------------------------------------------------------------------------------- /src/data/img/menu/sell_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/menu/sell_icon.png -------------------------------------------------------------------------------- /src/data/img/menu/sell_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/menu/sell_icons.png -------------------------------------------------------------------------------- /src/data/img/menu/slow_damage_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/menu/slow_damage_icons.png -------------------------------------------------------------------------------- /src/data/img/menu/slow_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/menu/slow_icons.png -------------------------------------------------------------------------------- /src/data/img/menu/slow_slower_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/menu/slow_slower_icons.png -------------------------------------------------------------------------------- /src/data/img/menu/tower_location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/menu/tower_location.png -------------------------------------------------------------------------------- /src/data/img/menu/upgraded_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/menu/upgraded_icon.png -------------------------------------------------------------------------------- /src/data/img/other/smallFire.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/other/smallFire.png -------------------------------------------------------------------------------- /src/data/img/projectiles/arrows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/projectiles/arrows.png -------------------------------------------------------------------------------- /src/data/img/projectiles/bleedEffect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/projectiles/bleedEffect.png -------------------------------------------------------------------------------- /src/data/img/projectiles/cannonball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/projectiles/cannonball.png -------------------------------------------------------------------------------- /src/data/img/projectiles/explosion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/projectiles/explosion.png -------------------------------------------------------------------------------- /src/data/img/projectiles/freeze_exp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/projectiles/freeze_exp.png -------------------------------------------------------------------------------- /src/data/img/towers/archer_tower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/towers/archer_tower.png -------------------------------------------------------------------------------- /src/data/img/towers/cannon_tower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/towers/cannon_tower.png -------------------------------------------------------------------------------- /src/data/img/towers/slow_tower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/towers/slow_tower.png -------------------------------------------------------------------------------- /src/data/img/towers/tower-base.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/img/towers/tower-base.xcf -------------------------------------------------------------------------------- /src/data/map/introLevel01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/map/introLevel01.png -------------------------------------------------------------------------------- /src/data/map/map01.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /src/data/map/map01Intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/map/map01Intro.png -------------------------------------------------------------------------------- /src/data/map/map01Intro.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/map/map01Intro.xcf -------------------------------------------------------------------------------- /src/data/map/map02.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /src/data/map/map02Intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/map/map02Intro.png -------------------------------------------------------------------------------- /src/data/map/map02Intro.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/map/map02Intro.xcf -------------------------------------------------------------------------------- /src/data/map/map03.tmx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbQAAAG4AAABtAAAAbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG0AAABuAAAAbQAAAG4AAAAAAAAAAAAAAAAAAAAAAAAAbQAAAG4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH0AAAB+AAAAfQAAAH4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB9AAAAfgAAAH0AAAB+AAAAAAAAAAAAAAAAAAAAAAAAAH0AAAB+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbQAAAG4AAABtAAAAbgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG0AAABuAAAAbQAAAG4AAAAAAAAAAAAAAAAAAAAAAAAAbQAAAG4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH0AAAB+AAAAfQAAAH4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB9AAAAfgAAAH0AAAB+AAAAAAAAAAAAAAAAAAAAAAAAAH0AAAB+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= 44 | 45 | 46 | 47 | 48 | +wAAAPwAAAC7AAAAvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABtAAAAbgAAAG0AAABuAAAAbQAAAG4AAAAAAAAAAAAAAKgCAACpAgAAqgIAAAAAAAAAAAAAywAAAMwAAAAAAAAAAAAAAAAAAAABAgAAAgIAAAMCAAAEAgAABAIAAAQCAAAEAgAABAIAAAQCAAAEAgAABAIAAAQCAAAEAgAABAIAAAQCAAAEAgAABAIAAAQCAAAEAgAABAIAAAgCAAAJAgAAfQAAAH4AAAB9AAAAfgAAAH0AAAB+AAAAAAAAAAAAAAC/AgAAwAIAAMECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABtAAAAbgAAAAAAAAAAAAAA1gIAANcCAADYAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAH4AAAAAAAAAAAAAAO0CAADuAgAA7wIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAhAgAAIgIAACMCAAAkAgAAJAIAACQCAAAkAgAAJAIAACQCAAAkAgAAJAIAACQCAAAkAgAAJAIAACQCAAAkAgAAJAIAACQCAAAkAgAAJAIAACgCAAApAgAAKgIAAAAAAAAAAAAAAAAAAG0AAABuAAAAAAAAAAAAAAAEAwAABQMAAAYDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB9AAAAfgAAAAAAAAAAAAAAGwMAABwDAAAdAwAA2wAAANwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbQAAAG4AAAAAAAAAAAAAADIDAAAzAwAANAMAAOsAAADsAAAAKQAAACkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH0AAAB+AAAAAAAAAAAAAABJAwAASgMAAEsDAAD7AAAA/AAAACkAAAApAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAMAAGEDAABiAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAECAAACAgAAAwIAAAQCAAAEAgAABAIAAAQCAAAEAgAABAIAAAQCAAAEAgAABAIAAAQCAAAEAgAABAIAAAQCAAAEAgAABAIAAAQCAAAEAgAACAIAAAkCAAAKAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHcDAAB4AwAAeQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACECAAAiAgAAIwIAACQCAAAkAgAAJAIAACQCAAAkAgAAJAIAACQCAAAkAgAAJAIAACQCAAAkAgAAJAIAACQCAAAkAgAAJAIAACQCAAAkAgAAKAIAACkCAAAqAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKgCAACpAgAAqgIAAM0AAADOAAAAzwAAANAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC/AgAAwAIAAMECAADdAAAA3gAAAN8AAADgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1gIAANcCAADYAgAA7QAAAO4AAADvAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbQAAAG4AAAAAAAAAAAAAAO0CAADuAgAA7wIAAP0AAAD+AAAA/wAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH0AAAB+AAAAAAAAAAAAAADtAgAA7gIAAO8CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQIAAAICAAADAgAABAIAAAQCAAAEAgAABAIAAAQCAAAEAgAABAIAAAQCAAAEAgAABAIAAAQCAAAEAgAABAIAAAQCAAAEAgAABAIAAAQCAAAIAgAACQIAAAoCAAAAAAAAAAAAAAAAAABtAAAAbgAAAAAAAAAAAAAA7QIAAO4CAADvAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAH4AAAAAAAAAAAAAAO0CAADuAgAA7wIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG0AAABuAAAAAAAAAAAAAAAEAwAABQMAAAYDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIQIAACICAAAjAgAAJAIAACQCAAAkAgAAJAIAACQCAAAkAgAAJAIAACQCAAAkAgAAJAIAACQCAAAkAgAAJAIAACQCAAAkAgAAJAIAACQCAAAoAgAAKQIAACoCAAAAAAAAAAAAAAAAAAB9AAAAfgAAAAAAAAAAAAAAGwMAABwDAAAdAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABtAAAAbgAAAG0AAABuAAAAbQAAAG4AAAAAAAAAAAAAADIDAAAzAwAANAMAANsAAADcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAH4AAAB9AAAAfgAAAH0AAAB+AAAAAAAAAAAAAABJAwAASgMAAEsDAAA= 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /src/data/map/map03Intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/map/map03Intro.png -------------------------------------------------------------------------------- /src/data/map/map03Intro.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/map/map03Intro.xcf -------------------------------------------------------------------------------- /src/data/sfx/arrow_shoot.aac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/sfx/arrow_shoot.aac -------------------------------------------------------------------------------- /src/data/sfx/boss_death.aac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/sfx/boss_death.aac -------------------------------------------------------------------------------- /src/data/sfx/cannon_shoot.aac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/sfx/cannon_shoot.aac -------------------------------------------------------------------------------- /src/data/sfx/footman_death.aac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/sfx/footman_death.aac -------------------------------------------------------------------------------- /src/data/sfx/goblin_death.aac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/sfx/goblin_death.aac -------------------------------------------------------------------------------- /src/data/sfx/imp_death.aac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/sfx/imp_death.aac -------------------------------------------------------------------------------- /src/data/sfx/sell_item.aac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/sfx/sell_item.aac -------------------------------------------------------------------------------- /src/data/sfx/slow_shoot.aac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/sfx/slow_shoot.aac -------------------------------------------------------------------------------- /src/data/sfx/tower_drop.aac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/sfx/tower_drop.aac -------------------------------------------------------------------------------- /src/data/sfx/upgrade.aac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/data/sfx/upgrade.aac -------------------------------------------------------------------------------- /src/icons/touch-icon-ipad-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/icons/touch-icon-ipad-76x76.png -------------------------------------------------------------------------------- /src/icons/touch-icon-ipad-retina-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/icons/touch-icon-ipad-retina-152x152.png -------------------------------------------------------------------------------- /src/icons/touch-icon-iphone-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/icons/touch-icon-iphone-60x60.png -------------------------------------------------------------------------------- /src/icons/touch-icon-iphone-retina-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/icons/touch-icon-iphone-retina-120x120.png -------------------------------------------------------------------------------- /src/icons/touch-icon-marketplace-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/icons/touch-icon-marketplace-128x128.png -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #000; 3 | color: #fff; 4 | 5 | /* Allow mouse dragging. */ 6 | -moz-user-select: none; 7 | -ms-user-select: none; 8 | -o-user-select: none; 9 | -webkit-user-select: none; 10 | user-select: none; 11 | 12 | /* disable touch panning/zooming */ 13 | -ms-touch-action: none; 14 | touch-action: none; 15 | 16 | /* Allow canvas to hit the edges of the browser viewport. */ 17 | margin: 0; 18 | } 19 | 20 | #screen canvas { 21 | margin: auto; 22 | 23 | /* Hide the gap for font descenders. */ 24 | display: block; 25 | 26 | /* disable scaling interpolation */ 27 | image-rendering: optimizeSpeed; 28 | image-rendering: -moz-crisp-edges; 29 | image-rendering: -o-crisp-edges; 30 | image-rendering: -webkit-optimize-contrast; 31 | image-rendering: optimize-contrast; 32 | image-rendering: pixelated; 33 | -ms-interpolation-mode: nearest-neighbor; 34 | } 35 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | OctansTD: Development Build 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /src/js/entities/HUD.js: -------------------------------------------------------------------------------- 1 | game.HUD = game.HUD || {}; 2 | 3 | 4 | game.HUD.Container = me.Container.extend({ 5 | 6 | init: function() { 7 | // call the constructor 8 | this._super(me.Container, 'init'); 9 | 10 | this.isPersistent = true; 11 | this.floating = true; 12 | this.name = "HUD"; 13 | me.game.world.addChild(new game.HUD.ResourceBar(0, 0)); 14 | this.addChild(new game.HUD.ResourcesDisplay(0, 0)); 15 | me.game.world.addChild(new game.HUD.PauseMenuButton(1200, 5)); 16 | } 17 | }); 18 | 19 | game.HUD.ResourceBar = me.Sprite.extend({ 20 | init: function(x,y){ 21 | var settings = {}; 22 | settings.image = "HUD_bar"; 23 | settings.width = settings.framewidth = 1280; 24 | settings.height = settings.frameheight = 64; 25 | settings.anchorPoint = {x:0.0, y:0.0}; 26 | this._super(me.Sprite, 'init', [x, y, settings]); 27 | 28 | }, 29 | update: function(dt){ 30 | return false; 31 | } 32 | }), 33 | 34 | game.HUD.PauseMenuButton = me.GUI_Object.extend({ 35 | init: function(x, y){ 36 | 37 | var settings = {}; 38 | settings.image = "pause_menu"; 39 | settings.frameheight = 50; 40 | settings.framewidth = 50; 41 | settings.width = 150; 42 | settings.height = 50; 43 | 44 | this._super(me.GUI_Object, 'init', [x, y, settings]); 45 | this.alwaysUpdate = true; 46 | this.settings = settings; 47 | //set images for switching between play and paused 48 | this.addAnimation("button", [0]); 49 | this.addAnimation("hover", [1]); 50 | this.addAnimation("clicked", [2]); 51 | this.setCurrentAnimation("button"); 52 | this.updateWhenPaused = true; 53 | 54 | //Music options 55 | this.musicStopsWhilePaused = true; 56 | 57 | this.anchorPoint.set(0.0, 0.0); 58 | this.pos.z = Infinity; 59 | this.x = x; 60 | this.y = y; 61 | this.updateWhenPaused = true; 62 | 63 | }, 64 | onOver: function(e){ 65 | if(me.state.isPaused() == false){ 66 | this.setCurrentAnimation("hover"); 67 | } 68 | 69 | }, 70 | onOut: function(e){ 71 | this.setCurrentAnimation("button"); 72 | }, 73 | onClick(e){ 74 | if(me.state.isPaused() == false){ 75 | this.setCurrentAnimation("clicked"); 76 | //menu_settings will determine what is displayed on menu 77 | var menu_settings = {}; 78 | menu_settings.pauseMenu = true; 79 | menu_settings.levelPassed = undefined; 80 | menu_settings.width = 640; 81 | menu_settings.height = 360; 82 | 83 | this.optionMenu = new game.OptionMenu.Container(menu_settings); 84 | me.game.world.addChild(this.optionMenu); 85 | me.state.pause(this.musicStopsWhilePaused); 86 | } 87 | }, 88 | update: function(dt){ 89 | if(me.state.isPaused() == true && !this.isCurrentAnimation("clicked")){ 90 | this.setCurrentAnimation("clicked"); 91 | }else if(me.state.isPaused() == false && this.isCurrentAnimation("clicked")){ 92 | this.setCurrentAnimation("button"); 93 | } 94 | return true; 95 | } 96 | 97 | }); 98 | 99 | game.HUD.ResourcesDisplay = me.Renderable.extend({ 100 | init: function(x, y) { 101 | this._super(me.Renderable, 'init', [x, y, 10, 10]); 102 | this.font = new me.BitmapFont( 103 | me.loader.getBinary('font'), 104 | me.loader.getImage('font')); 105 | 106 | // local copy of the global score 107 | this.gold = game.data.gold; 108 | }, 109 | update : function () { 110 | if (this.gold !== game.data.gold) { 111 | this.gold = game.data.gold; 112 | return true; 113 | } 114 | return false; 115 | }, 116 | draw : function (renderer) { 117 | this.font.draw(renderer, game.data.gold, 540, 10); 118 | this.font.draw(renderer, game.data.wave, 670, 10); 119 | this.font.draw(renderer, game.data.playerLives, 765, 10); 120 | 121 | } 122 | 123 | }); 124 | -------------------------------------------------------------------------------- /src/js/entities/archerTower.js: -------------------------------------------------------------------------------- 1 | var ARCHER_TOWER_COST = 50; 2 | var ARCHER_TOWER_RADIUS = 160; //4 tile attack radius 3 | 4 | 5 | game.ArcherTowerEntity = me.Entity.extend({ 6 | init: function (x,y,settings) { 7 | //offset entity so that center is where TowerLocationEntity was 8 | x = x - (ARCHER_TOWER_RADIUS - 64); 9 | y = y - (ARCHER_TOWER_RADIUS - 48); 10 | 11 | settings.image = "archer_tower"; 12 | 13 | //set image width to actual image sizes 14 | settings.framewidth = 64; 15 | settings.frameheight = 64; 16 | //set width and height to attack radius 17 | settings.width = ARCHER_TOWER_RADIUS * 2; 18 | settings.height = ARCHER_TOWER_RADIUS * 2; 19 | 20 | this._super(me.Entity, "init", [x,y,settings]); 21 | //set anchor point and image location to center of entity(hitbox) 22 | this.anchorPoint.set(0.5,0.5); 23 | 24 | //Towers are PLAYER_OBJECTS 25 | //These interact with walking enemies (ENEMY_OBJECT) 26 | this.body.collisionType = me.collision.types.PLAYER_OBJECT; 27 | this.body.setCollisionMask(me.collision.types.ENEMY_OBJECT); 28 | 29 | //Define Tower Defense Variables. These may be updated with the upgrade system 30 | this.fireDelay = Math.floor(me.sys.updatesPerSecond*60/60); //Value added to rofCooldown after firing 31 | this.arrowCooldown = 0; //This must be 0 to fire 32 | this.numProjectiles = 1; //Number of projectiles to shoot 33 | this.bleedArrows = false; //Default to normal arrows 34 | this.bleedChance = 0; //Chance to start bleeding 35 | this.bleedDot = 0; //Damage per bleed update 36 | this.arrowDamage = 10; //Damage upon arrow delivery 37 | this.arrowDistance = ARCHER_TOWER_RADIUS; //Distance an arrow will travel before despawn 38 | this.arrowVelocity = 400; //Velocity the arrow travels at 39 | this.targets = []; //List of possible targets 40 | this.currentTarget = null; //Currently targeted enemy object 41 | this.upgradeLevel = 0; //default to level 0 tower 42 | this.name = "archer_tower"; //used to produce proper upgrade menu 43 | this.value = ARCHER_TOWER_COST; //Store current value of tower 44 | 45 | //Upgrade logic 46 | this.upgradesInstalled = [false, false]; //Upgrades Installed 47 | 48 | }, 49 | upgrade: function (index) { 50 | //Don't install if already installed, else mark as installed 51 | if(this.upgradesInstalled[index]) 52 | return false; 53 | this.upgradesInstalled[index] = true; //Flag upgrade as installed 54 | this.value += Math.floor(ARCHER_TOWER_COST*game.data.upgradeCostFactor[this.upgradeLevel]); //Update value 55 | this.upgradeLevel++; //Update upgradeLevel 56 | 57 | //Update variables associated with upgrade 58 | //2 arrows shooting different targets at slightly reduced damage 59 | if(index == 0){ 60 | this.numProjectiles += 1; 61 | this.arrowDamage = Math.floor(this.arrowDamage*.8); 62 | } 63 | 64 | //Give bleed effect to arrows. 65 | else if(index == 1){ 66 | this.bleedArrows = true; 67 | this.bleedChance = 0.5; 68 | this.bleedDot = 2; 69 | } 70 | 71 | //Return true if upgrade successful 72 | return true; 73 | }, 74 | 75 | update: function (dt) { 76 | //Process Arrow Cooldown if necessary 77 | if(this.arrowCooldown > 0){ 78 | this.arrowCooldown--; 79 | return false; 80 | } 81 | else if(this.arrowCooldown < 0){ 82 | this.arrowCooldown = 0; 83 | return false; 84 | } 85 | 86 | //Remove targets that are out of range 87 | var i = 0; 88 | while(i < this.targets.length){ 89 | if(this.targets[i].alive == false || (this.distanceTo(this.targets[i]) > 150)){ 90 | this.targets = this.targets.slice(0,i).concat(this.targets.slice(i+1,this.targets.length)); 91 | continue; 92 | } 93 | i++; 94 | } 95 | var fired = false; 96 | 97 | //If bleed arrows, sort the targets so that the ones that aren't bleeding come first in the list 98 | if(this.bleedArrows){ 99 | this.targets.sort(function(a,b){return a.bleeding - b.bleeding}); 100 | } 101 | 102 | //Fire a projectile at each unique target until we run out of projectiles 103 | for(i = 0; i < this.numProjectiles; i++) 104 | { 105 | //Set target 106 | if(this.targets.length > i) 107 | this.currentTarget = this.targets[i]; 108 | else 109 | break; 110 | //Shoot arrow 111 | var arrowSettings = {}; 112 | arrowSettings.targetAng = -1*this.angleTo(this.currentTarget).radToDeg(); 113 | arrowSettings.parent = this; //For calculating distance the arrow has flown. 114 | arrowSettings.arrowDamage = this.arrowDamage; 115 | arrowSettings.arrowDistance = this.arrowDistance; 116 | arrowSettings.arrowVelocity = this.arrowVelocity; 117 | arrowSettings.arrowTarget = this.currentTarget; 118 | if(this.bleedArrows && Math.random()= ARCHER_TOWER_COST){ 32 | this.setOpacity(1.0); 33 | } 34 | var atkRadObj = me.game.world.getChildByProp("tag", "attackRadius"); 35 | for(i = 0; i < atkRadObj.length; i++){ 36 | me.game.world.removeChild(atkRadObj[i]); 37 | } 38 | 39 | me.game.world.addChild(new game.Menu.AttackRadius(this.towerEntity.pos.x, 40 | this.towerEntity.pos.y, ARCHER_TOWER_RADIUS), Infinity); 41 | }, 42 | onOut: function(e){ 43 | this.setOpacity(0.75); 44 | this.confirm = false; 45 | 46 | var atkRadObj = me.game.world.getChildByProp("tag", "attackRadius"); 47 | for(i = 0; i < atkRadObj.length; i++){ 48 | me.game.world.removeChild(atkRadObj[i]); 49 | } 50 | }, 51 | onClick(e){ 52 | if(game.data.gold >= ARCHER_TOWER_COST && this.confirm == false){ 53 | this.confirm = true; 54 | } 55 | else if(game.data.gold >= ARCHER_TOWER_COST && this.confirm == true){ 56 | this.towerEntity.towerPlaced = true; 57 | me.audio.play("tower_drop"); 58 | game.data.gold -= ARCHER_TOWER_COST; 59 | 60 | //Place archer tower on map 61 | this.towerEntity.currentTower = me.game.world.addChild( 62 | new game.ArcherTowerEntity(this.parentMenu.pos.x, this.parentMenu.pos.y, 63 | {width: 0, height: 0})); 64 | 65 | //Remove menu and buttons 66 | game.functions.removeTowerMenu(); 67 | 68 | } 69 | }, 70 | update: function(dt){ 71 | if(this.confirm == true){ 72 | this.setCurrentAnimation("arrow_confirm"); 73 | } 74 | else{ 75 | this.setCurrentAnimation("arrow"); 76 | } 77 | }, 78 | 79 | }); 80 | 81 | game.Menu.arrow_multi_button = me.GUI_Object.extend({ 82 | init: function(x, y, settings){ 83 | settings.image = "arrow_multi_icons"; 84 | settings.frameheight = 32; 85 | settings.framewidth = 32; 86 | settings.width = 64; 87 | settings.height = 32; 88 | 89 | this._super(me.GUI_Object, 'init', [x, y, settings]); 90 | 91 | this.addAnimation("arrow_multi", [0]); 92 | this.addAnimation("arrow_multi_confirm", [1]); 93 | this.setCurrentAnimation("arrow_multi"); 94 | //set true if icon was initially clicked once and needs 95 | //to be clicked again to confirm 96 | this.confirm = false; 97 | 98 | this.anchorPoint.set(0.0, 0.0); 99 | this.setOpacity(0.75); 100 | this.pos.z = 500; 101 | this.parentMenu = settings.parentMenu; 102 | this.name = "tower_menu_object"; 103 | this.towerEntity = settings.towerEntity; 104 | //console.log(this.towerEntity); 105 | 106 | //Set this to the index that corresponds to the upgrade number in the archer tower file 107 | this.upgradeIndex = 0; 108 | //Cost for this upgrade 109 | this.upgradeCost = ARCHER_TOWER_COST*game.data.upgradeCostFactor[this.towerEntity.currentTower.upgradeLevel]; 110 | //Flag if this upgrade has been installed already 111 | this.upgradedAlready = this.towerEntity.currentTower.upgradesInstalled[this.upgradeIndex]; 112 | 113 | //display cost of current tower or upgrade 114 | me.game.world.addChild(new game.Menu.CostDisplay(this.pos.x, this.pos.y, this.upgradeCost), Infinity); 115 | 116 | 117 | }, 118 | onOver: function(e){ 119 | if(game.data.gold >= this.upgradeCost && !this.upgradedAlready){ 120 | this.setOpacity(1.0); 121 | } 122 | }, 123 | onOut: function(e){ 124 | this.setOpacity(0.75); 125 | this.confirm = false; 126 | }, 127 | onClick(e){ 128 | if(game.data.gold >= this.upgradeCost && !this.upgradedAlready && this.confirm == false){ 129 | this.confirm = true; 130 | } 131 | else if(game.data.gold >= this.upgradeCost && !this.upgradedAlready && this.confirm == true){ 132 | me.audio.play("upgrade"); 133 | 134 | game.data.gold -= this.upgradeCost; 135 | this.towerEntity.currentTower.upgrade(this.upgradeIndex); 136 | 137 | //Remove menu and buttons 138 | game.functions.removeTowerMenu(); 139 | 140 | } 141 | }, 142 | update: function(dt){ 143 | if(this.confirm == true){ 144 | this.setCurrentAnimation("arrow_multi_confirm"); 145 | } 146 | else{ 147 | this.setCurrentAnimation("arrow_multi"); 148 | } 149 | }, 150 | 151 | }); 152 | 153 | game.Menu.arrow_bleed_button = me.GUI_Object.extend({ 154 | init: function(x, y, settings){ 155 | settings.image = "arrow_bleed_icons"; 156 | settings.frameheight = 32; 157 | settings.framewidth = 32; 158 | settings.width = 64; 159 | settings.height = 32; 160 | 161 | this._super(me.GUI_Object, 'init', [x, y, settings]); 162 | 163 | this.addAnimation("arrow_bleed", [0]); 164 | this.addAnimation("arrow_bleed_confirm", [1]); 165 | this.setCurrentAnimation("arrow_bleed"); 166 | //set true if icon was initially clicked once and needs 167 | //to be clicked again to confirm 168 | this.confirm = false; 169 | 170 | this.anchorPoint.set(0.0, 0.0); 171 | this.setOpacity(0.75); 172 | this.pos.z = 500; 173 | this.parentMenu = settings.parentMenu; 174 | this.name = "tower_menu_object"; 175 | this.towerEntity = settings.towerEntity; 176 | 177 | //Set this to the index that corresponds to the upgrade number in the archer tower file 178 | this.upgradeIndex = 1; 179 | //Cost for this upgrade 180 | this.upgradeCost = ARCHER_TOWER_COST*game.data.upgradeCostFactor[this.towerEntity.currentTower.upgradeLevel]; 181 | //Flag if this upgrade has been installed already 182 | this.upgradedAlready = this.towerEntity.currentTower.upgradesInstalled[this.upgradeIndex]; 183 | 184 | //display cost of current tower or upgrade 185 | me.game.world.addChild(new game.Menu.CostDisplay(this.pos.x, this.pos.y, this.upgradeCost), Infinity); 186 | 187 | }, 188 | onOver: function(e){ 189 | if(game.data.gold >= this.upgradeCost && !this.upgradedAlready){ 190 | this.setOpacity(1.0); 191 | } 192 | }, 193 | onOut: function(e){ 194 | this.setOpacity(0.75); 195 | this.confirm = false; 196 | }, 197 | onClick(e){ 198 | if(game.data.gold >= this.upgradeCost && !this.upgradedAlready && this.confirm == false){ 199 | this.confirm = true; 200 | } 201 | else if(game.data.gold >= this.upgradeCost && !this.upgradedAlready && this.confirm == true){ 202 | me.audio.play("upgrade"); 203 | 204 | game.data.gold -= this.upgradeCost; 205 | this.towerEntity.currentTower.upgrade(this.upgradeIndex); 206 | 207 | //Remove menu and buttons 208 | game.functions.removeTowerMenu(); 209 | 210 | } 211 | }, 212 | update: function(dt){ 213 | if(this.confirm == true){ 214 | this.setCurrentAnimation("arrow_bleed_confirm"); 215 | } 216 | else{ 217 | this.setCurrentAnimation("arrow_bleed"); 218 | } 219 | }, 220 | 221 | }); 222 | -------------------------------------------------------------------------------- /src/js/entities/cannonTower.js: -------------------------------------------------------------------------------- 1 | var CANNON_TOWER_COST = 75; 2 | var CANNON_TOWER_RADIUS = 128; 3 | 4 | 5 | game.CannonTowerEntity = me.Entity.extend({ 6 | init: function (x,y,settings) { 7 | //offset entity so that center is where TowerLocationEntity was 8 | x = x - 64; 9 | y = y - 80; 10 | 11 | settings.image = "cannon_tower"; 12 | //set image width to actual image size 13 | settings.framewidth = 64; 14 | settings.frameheight = 64; 15 | //set width and height to attack radius 16 | settings.width = CANNON_TOWER_RADIUS * 2; 17 | settings.height = CANNON_TOWER_RADIUS * 2; 18 | 19 | 20 | this._super(me.Entity, "init", [x,y,settings]); 21 | //set anchor point and image location to center of entity(hitbox) 22 | this.anchorPoint.set(0.5,0.5); 23 | 24 | //Towers are PLAYER_OBJECTS 25 | //These interact with walking enemies (ENEMY_OBJECT) 26 | this.body.collisionType = me.collision.types.PLAYER_OBJECT; 27 | this.body.setCollisionMask(me.collision.types.ENEMY_OBJECT); 28 | 29 | //Define Tower Defense Variables. These may be updated with the upgrade system 30 | this.fireDelay = Math.floor(2*me.sys.updatesPerSecond*60/60); //Value added to rofCooldown after firing 31 | this.cannonCooldown = 0; //This must be 0 to fire 32 | this.cannonDamage = 20; //Damage upon cannonball delivery 33 | this.cannonDistance = CANNON_TOWER_RADIUS; //Distance an cannonball will travel before despawn 34 | this.cannonVelocity = 400; //Velocity the cannonball travels at 35 | this.cannonAoe = 80; //Cannonball area of effect distance 36 | this.cannonballScale = 0.75; //Scale factor for ball and explosion 37 | this.targets = []; //List of possible targets 38 | this.currentTarget = null; //Currently targeted enemy object 39 | this.upgradeLevel = 0; //default to level 0 tower 40 | this.name = "cannon_tower"; //used to produce proper upgrade menu 41 | this.value = CANNON_TOWER_COST; //Store current value of tower 42 | 43 | //Upgrade logic 44 | this.upgradesInstalled = [false, false]; //Upgrades Installed 45 | }, 46 | upgrade: function (index) { 47 | //Don't install if already installed, else mark as installed 48 | if(this.upgradesInstalled[index]) 49 | return false; 50 | this.upgradesInstalled[index] = true; //Flag upgrade as installed 51 | this.value += Math.floor(CANNON_TOWER_COST * game.data.upgradeCostFactor[this.upgradeLevel]); //Update value 52 | this.upgradeLevel++; //Update upgradeLevel 53 | 54 | //Update variables associated with upgrade 55 | //(Larger) cannonball has larger aoe and increased firing range 56 | if(index == 0){ 57 | this.cannonballScale = 1; 58 | this.cannonDistance = Math.floor(this.cannonDistance*4/3); 59 | this.cannonAoe = Math.floor(this.cannonAoe*4/3); 60 | } 61 | 62 | //Cannonball has upgraded damage 63 | else if(index == 1){ 64 | this.cannonDamage = Math.floor(this.cannonDamage*1.5); 65 | } 66 | 67 | //Return true if upgrade successful 68 | return true; 69 | }, 70 | 71 | update: function (dt) { 72 | //Process Cannon Cooldown if necessary 73 | if(this.cannonCooldown > 0){ 74 | this.cannonCooldown--; 75 | } 76 | else if(this.cannonCooldown < 0){ 77 | this.cannonCooldown = 0; 78 | } 79 | 80 | //Choose a new target if we don't have one, and there's one in the targets pool 81 | if(this.currentTarget == null && this.targets.length>0) 82 | this.currentTarget = this.targets[0]; 83 | 84 | //Update target if we already have one, and select an appropriate target when we find one 85 | if(this.currentTarget != null){ 86 | //if current target is dead or out of range set to null 87 | if(this.currentTarget.alive == false || (this.distanceTo(this.currentTarget) > 150)){ 88 | this.currentTarget = null; 89 | //Find a new target if possible 90 | while(this.currentTarget == null && this.targets.length>0){ 91 | if(this.targets[0].alive == false || (this.distanceTo(this.targets[0]) > 150)) 92 | this.targets = this.targets.slice(1,this.targets.length); 93 | else 94 | this.currentTarget = this.targets[0]; 95 | } 96 | } 97 | } 98 | 99 | //Fire at a target if we have one and we're off cooldown 100 | if(this.currentTarget != null && this.cannonCooldown == 0){ 101 | //JS Object with flight settings for the projectile 102 | var cannonSettings = {}; 103 | cannonSettings.targetAng = -1*this.angleTo(this.currentTarget).radToDeg(); 104 | cannonSettings.parent = this; //For calculating distance the cannonball has flown. 105 | cannonSettings.cannonDamage = this.cannonDamage; 106 | cannonSettings.cannonAoe = this.cannonAoe; 107 | cannonSettings.cannonballScale = this.cannonballScale; 108 | cannonSettings.cannonDistance = this.cannonDistance; 109 | cannonSettings.cannonVelocity = this.cannonVelocity; 110 | cannonSettings.cannonTargets = this.targets; 111 | cannonSettings.cannonTarget = this.currentTarget; 112 | //console.log("targetPosAng = " + cannonSettings.targetAng + "\n"); 113 | 114 | me.game.world.addChild(me.pool.pull("CannonballEntity", this.pos.x + this.width*7/16, this.pos.y + this.height*3/8, cannonSettings)); 115 | this.cannonCooldown += this.fireDelay; 116 | } 117 | return false; 118 | }, 119 | onCollision: function(response, other){ 120 | //Add this to the list of possible enemies if it isn't in the list already. 121 | if(response.aInB){ 122 | found = 0; 123 | for(i=0; i= CANNON_TOWER_COST){ 31 | this.setOpacity(1.0); 32 | } 33 | var atkRadObj = me.game.world.getChildByProp("tag", "attackRadius"); 34 | for(i = 0; i < atkRadObj.length; i++){ 35 | me.game.world.removeChild(atkRadObj[i]); 36 | } 37 | 38 | me.game.world.addChild(new game.Menu.AttackRadius(this.towerEntity.pos.x, 39 | this.towerEntity.pos.y, CANNON_TOWER_RADIUS), Infinity); 40 | }, 41 | onOut: function(e){ 42 | this.setOpacity(0.75); 43 | this.confirm = false; 44 | var atkRadObj = me.game.world.getChildByProp("tag", "attackRadius"); 45 | for(i = 0; i < atkRadObj.length; i++){ 46 | me.game.world.removeChild(atkRadObj[i]); 47 | } 48 | 49 | }, 50 | onClick(e){ 51 | if(game.data.gold >= CANNON_TOWER_COST && this.confirm == false){ 52 | this.confirm = true; 53 | }else if(game.data.gold >= CANNON_TOWER_COST && this.confirm == true){ 54 | this.towerEntity.towerPlaced = true; 55 | me.audio.play("tower_drop"); 56 | game.data.gold -= CANNON_TOWER_COST; 57 | 58 | //Place cannon tower on map 59 | this.towerEntity.currentTower = me.game.world.addChild( 60 | new game.CannonTowerEntity(this.parentMenu.pos.x, this.parentMenu.pos.y, 61 | {width: this.width, height: this.height})); 62 | 63 | //Remove menu and buttons 64 | game.functions.removeTowerMenu(); 65 | 66 | } 67 | }, 68 | update: function(dt){ 69 | if(this.confirm == true){ 70 | this.setCurrentAnimation("cannon_confirm"); 71 | } 72 | else{ 73 | this.setCurrentAnimation("cannon"); 74 | } 75 | }, 76 | 77 | }); 78 | 79 | game.Menu.cannon_aoe_button = me.GUI_Object.extend({ 80 | init: function(x, y, settings){ 81 | settings.image = "cannon_aoe_icons"; 82 | settings.frameheight = 32; 83 | settings.framewidth = 32; 84 | settings.width = 64; 85 | settings.height = 32; 86 | 87 | this._super(me.GUI_Object, 'init', [x, y, settings]); 88 | 89 | this.addAnimation("cannon_aoe", [0]); 90 | this.addAnimation("cannon_aoe_confirm", [1]); 91 | this.setCurrentAnimation("cannon_aoe"); 92 | //set true if icon was initially clicked once and needs 93 | //to be clicked again to confirm 94 | this.confirm = false; 95 | 96 | this.anchorPoint.set(0.0, 0.0); 97 | this.setOpacity(0.75); 98 | this.pos.z = 500; 99 | this.parentMenu = settings.parentMenu; 100 | this.name = "tower_menu_object"; 101 | this.towerEntity = settings.towerEntity; 102 | 103 | //Set this to the index that corresponds to the upgrade number in the cannon tower file 104 | this.upgradeIndex = 0; 105 | //Cost for this upgrade 106 | this.upgradeCost = CANNON_TOWER_COST*game.data.upgradeCostFactor[this.towerEntity.currentTower.upgradeLevel]; 107 | //Flag if this upgrade has been installed already 108 | this.upgradedAlready = this.towerEntity.currentTower.upgradesInstalled[this.upgradeIndex]; 109 | 110 | //display cost of current tower or upgrade 111 | me.game.world.addChild(new game.Menu.CostDisplay(this.pos.x, this.pos.y, this.upgradeCost), Infinity); 112 | 113 | 114 | }, 115 | onOver: function(e){ 116 | if(game.data.gold >= this.upgradeCost && !this.upgradedAlready){ 117 | this.setOpacity(1.0); 118 | } 119 | }, 120 | onOut: function(e){ 121 | this.setOpacity(0.75); 122 | this.confirm = false; 123 | }, 124 | onClick(e){ 125 | if(game.data.gold >= this.upgradeCost && !this.upgradedAlready && this.confirm == false){ 126 | this.confirm = true; 127 | } 128 | else if(game.data.gold >= this.upgradeCost && !this.upgradedAlready && this.confirm == true){ 129 | //Upgrade tower 130 | me.audio.play("upgrade"); 131 | game.data.gold -= this.upgradeCost; 132 | this.towerEntity.currentTower.upgrade(this.upgradeIndex); 133 | 134 | //Remove menu and buttons 135 | game.functions.removeTowerMenu(); 136 | 137 | } 138 | }, 139 | update: function(dt){ 140 | if(this.confirm == true){ 141 | this.setCurrentAnimation("cannon_aoe_confirm"); 142 | } 143 | else{ 144 | this.setCurrentAnimation("cannon_aoe"); 145 | } 146 | }, 147 | 148 | }); 149 | 150 | game.Menu.cannon_damage_button = me.GUI_Object.extend({ 151 | init: function(x, y, settings){ 152 | settings.image = "cannon_damage_icons"; 153 | settings.frameheight = 32; 154 | settings.framewidth = 32; 155 | settings.width = 64; 156 | settings.height = 32; 157 | 158 | this._super(me.GUI_Object, 'init', [x, y, settings]); 159 | 160 | this.addAnimation("cannon_damage", [0]); 161 | this.addAnimation("cannon_damage_confirm", [1]); 162 | this.setCurrentAnimation("cannon_damage"); 163 | //set true if icon was initially clicked once and needs 164 | //to be clicked again to confirm 165 | this.confirm = false; 166 | 167 | this.anchorPoint.set(0.0, 0.0); 168 | this.setOpacity(0.75); 169 | this.pos.z = 500; 170 | this.parentMenu = settings.parentMenu; 171 | this.name = "tower_menu_object"; 172 | this.towerEntity = settings.towerEntity; 173 | 174 | //Set this to the index that corresponds to the upgrade number in the cannon tower file 175 | this.upgradeIndex = 1; 176 | //Cost for this upgrade 177 | this.upgradeCost = CANNON_TOWER_COST*game.data.upgradeCostFactor[this.towerEntity.currentTower.upgradeLevel]; 178 | //Flag if this upgrade has been installed already 179 | this.upgradedAlready = this.towerEntity.currentTower.upgradesInstalled[this.upgradeIndex]; 180 | 181 | //display cost of current tower or upgrade 182 | me.game.world.addChild(new game.Menu.CostDisplay(this.pos.x, this.pos.y, this.upgradeCost), Infinity); 183 | 184 | 185 | }, 186 | onOver: function(e){ 187 | 188 | if(game.data.gold >= this.upgradeCost && !this.upgradedAlready){ 189 | this.setOpacity(1.0); 190 | } 191 | }, 192 | onOut: function(e){ 193 | this.setOpacity(0.75); 194 | this.confirm = false; 195 | }, 196 | onClick(e){ 197 | if(game.data.gold >= this.upgradeCost && !this.upgradedAlready && this.confirm == false){ 198 | this.confirm = true; 199 | } 200 | else if(game.data.gold >= this.upgradeCost && !this.upgradedAlready && this.confirm == true){ 201 | //Upgrade tower 202 | me.audio.play("upgrade"); 203 | game.data.gold -= this.upgradeCost; 204 | this.towerEntity.currentTower.upgrade(this.upgradeIndex); 205 | 206 | //Remove menu and buttons 207 | game.functions.removeTowerMenu(); 208 | 209 | } 210 | }, 211 | update: function(dt){ 212 | if(this.confirm == true){ 213 | this.setCurrentAnimation("cannon_damage_confirm"); 214 | } 215 | else{ 216 | this.setCurrentAnimation("cannon_damage"); 217 | } 218 | }, 219 | 220 | }); 221 | -------------------------------------------------------------------------------- /src/js/entities/entities.js: -------------------------------------------------------------------------------- 1 | /** 2 | * MapNode Entity 3 | * MapNodes store a property "moveDirection" that is passed to a colliding enemy entity. 4 | */ 5 | game.MapNode = me.Entity.extend({ 6 | init:function (x, y, settings) { 7 | settings.image = ""; 8 | var width = settings.width; 9 | var height = settings.height; 10 | settings.framewidth = width; 11 | settings.frameheight = height; 12 | settings.shapes[0] = new me.Rect(0,0, settings.width, settings.height); 13 | 14 | // Call the constructor 15 | this._super(me.Entity, 'init', [x, y , settings]); 16 | 17 | //Save the moveDirection property passed from Tiled 18 | this.moveDirection = settings.moveDirection; 19 | 20 | //Set collision type as WORLD_SHAPE. 21 | this.body.collisionType = me.collision.types.WORLD_SHAPE; 22 | 23 | }, 24 | update : function (dt) { 25 | // return true if we moved or if the renderable was updated 26 | return (this._super(me.Entity, 'update', [dt]) || this.body.vel.x !== 0 || this.body.vel.y !== 0); 27 | }, 28 | onCollision : function (response, other) { 29 | /* If true is returned, makes other objects solid 30 | * Return false because we don't want this behavior in a TD game*/ 31 | return false; 32 | } 33 | }); 34 | 35 | /** 36 | * KillNode Entity 37 | * KillNodes are similar to MapNodes but will kill an enemy entity on collision. 38 | * Ultimately, use this to process the TD logic associated with an enemy escaping through the gate. 39 | * Do not award bounty. Subtract enemy power from the player's lives. 40 | * Remove object that interacts with it. 41 | */ 42 | 43 | game.KillNode = me.Entity.extend({ 44 | 45 | init:function (x, y, settings) { 46 | settings.image = ""; 47 | var width = settings.width; 48 | var height = settings.height; 49 | settings.framewidth = width; 50 | settings.frameheight = height; 51 | settings.shapes[0] = new me.Rect(0,0, settings.width, settings.height); 52 | 53 | // Call the constructor 54 | this._super(me.Entity, 'init', [x, y , settings]); 55 | 56 | //Save the moveDirection property passed from Tiled 57 | this.moveDirection = settings.moveDirection; 58 | this.ended = false; 59 | 60 | //Set collision type as WORLD_SHAPE. 61 | this.body.collisionType = me.collision.types.WORLD_SHAPE; 62 | 63 | }, 64 | update : function (dt) { 65 | 66 | // return true if we moved or if the renderable was updated 67 | return (this._super(me.Entity, 'update', [dt]) || this.body.vel.x !== 0 || this.body.vel.y !== 0); 68 | }, 69 | onCollision : function (response, other) { 70 | if(response.a.health_points>0) 71 | { 72 | if(this.ended) 73 | return false; 74 | 75 | response.a.bounty = 0; 76 | 77 | //Return to title if player has too few lives. 78 | //Go to loss screen if player has too few lives. 79 | if(game.data.playerLives - response.a.power <= 0){ 80 | this.ended = true; 81 | me.state.pause(true); 82 | var menu_settings = {}; 83 | menu_settings.pauseMenu = false; 84 | menu_settings.levelPassed = false; 85 | menu_settings.width = 640; 86 | menu_settings.height = 360; 87 | var optionMenu = new game.OptionMenu.Container(menu_settings); 88 | me.game.world.addChild(optionMenu); 89 | return false; 90 | } 91 | game.data.playerLives -= response.a.power; 92 | game.data.enemyStrength -= response.a.power; 93 | if(game.data.level == 1) 94 | game.Level01PlayScreen.__methods__.checkEnemyStrength(); 95 | else if(game.data.level == 2) 96 | game.Level02PlayScreen.__methods__.checkEnemyStrength(); 97 | else 98 | game.Level03PlayScreen.__methods__.checkEnemyStrength(); 99 | response.a.pos._x += 2*response.a.width*Math.cos(response.a.moveDirection * Math.PI/180); 100 | response.a.pos._y -= 2*response.a.height*Math.sin(response.a.moveDirection * Math.PI/180); 101 | response.a.health_points = 0; 102 | response.a.bounty = 0; 103 | response.a.power = 0; 104 | } 105 | /* If true is returned, makes other objects solid 106 | * Return false because we don't want this behavior in a TD game*/ 107 | return false; 108 | } 109 | }); 110 | 111 | /** 112 | * ForkNode Entity 113 | * Used in level two to split the enemies above and below the fork 114 | */ 115 | game.ForkNode = me.Entity.extend({ 116 | init:function (x, y, settings) { 117 | settings.image = ""; 118 | var width = settings.width; 119 | var height = settings.height; 120 | settings.framewidth = width; 121 | settings.frameheight = height; 122 | settings.shapes[0] = new me.Rect(0,0, settings.width, settings.height); 123 | 124 | this._super(me.Entity, 'init', [x, y , settings]); 125 | this.name = "forkNode"; 126 | this.fork = true; 127 | this.enemiesDiverted = {}; 128 | 129 | //Set collision type as WORLD_SHAPE. 130 | this.body.collisionType = me.collision.types.WORLD_SHAPE; 131 | 132 | }, 133 | update : function (dt) { 134 | // return true if we moved or if the renderable was updated 135 | return (this._super(me.Entity, 'update', [dt]) || this.body.vel.x !== 0 || this.body.vel.y !== 0); 136 | }, 137 | onCollision : function (response, other) { 138 | var found = false; 139 | 140 | for(i = 0; i < this.enemiesDiverted.length; i++){ 141 | if(this.enemiesDiverted[i] === response.b){ 142 | found = true; 143 | } 144 | } 145 | if(found == false){ 146 | if(this.fork == true){ 147 | this.moveDirection = 45; 148 | this.fork = false; 149 | }else if(this.fork == false){ 150 | this.moveDirection = 315; 151 | this.fork = true; 152 | } 153 | } 154 | /* If true is returned, makes other objects solid 155 | * Return false because we don't want this behavior in a TD game*/ 156 | return false; 157 | } 158 | }); -------------------------------------------------------------------------------- /src/js/entities/option_menu.js: -------------------------------------------------------------------------------- 1 | var OPTION_MENU_WIDTH = 640; 2 | var OPTION_MENU_HEIGHT = 360; 3 | 4 | game.OptionMenu = game.OptionMenu || {}; 5 | 6 | game.OptionMenu.Container = me.Container.extend({ 7 | init: function(menu_settings){ 8 | var text = me.game.world.getChildByName("option_menu_text"); 9 | //close any open tower menus before pulling up pause menu 10 | var buttons = me.game.world.getChildByName("menu_button"); 11 | var buttonsLength = buttons.length; 12 | var menus = []; 13 | 14 | for(var i = 0; i < buttonsLength; i++){ 15 | me.game.world.removeChild(buttons[i]); 16 | var parentMenuFound = false; 17 | for(var j = 0; j < menus.length; j++) 18 | if(buttons[i].parentMenu === menus[j]) 19 | parentMenuFound = true; 20 | if(!parentMenuFound) 21 | menus.push(buttons[i].parentMenu); 22 | } 23 | 24 | for(var i = 0; i < menus.length; i++){ 25 | me.game.world.removeChild(menus[i]); 26 | } 27 | 28 | //Set up pause/end of level menu settings 29 | var settings = {}; 30 | this._super(me.Container, "init"); 31 | this.parentMenu = null; 32 | this.name = "option_menu"; 33 | this.floating = true; 34 | this.anchorPoint.set(0.0, 0.0); 35 | 36 | settings.parentMenu = this; 37 | settings.pauseMenu = menu_settings.pauseMenu; //true if this is pause menu, then no continue button 38 | settings.levelPassed = menu_settings.levelPassed; 39 | 40 | //close any tower menus before creating the menu 41 | game.functions.removeTowerMenu(); 42 | 43 | //set background and add buttons common to all menus 44 | this.bg = new game.OptionMenu.background(640, 360, settings); 45 | me.game.world.addChild(this.bg, 1499); 46 | me.game.world.addChild(new game.OptionMenu.mainMenu_button(750, 415, settings), 1500); 47 | me.game.world.addChild(new game.OptionMenu.restart_button(380, 415, settings), 1500); 48 | 49 | //if pause menu, setup resume button and button text 50 | //if failed level menu, no middle button 51 | //if passed level menu, set up continue button 52 | if(menu_settings.pauseMenu == false){ 53 | if(menu_settings.levelPassed == true){ 54 | settings.menuText = "level_passed"; 55 | me.game.world.addChild(new game.OptionMenu.continue_button(565, 415, settings), 1500); 56 | }else if(menu_settings.levelPassed == false){ 57 | settings.menuText = "level_failed"; 58 | }else{ 59 | console.log("Error: Not pause menu but no level indicator"); 60 | } 61 | }else{ 62 | settings.menuText = "level_paused"; 63 | me.game.world.addChild(new game.OptionMenu.continue_button(565, 415, settings), 1500); 64 | } 65 | 66 | //add the button text and menu message 67 | me.game.world.addChild(new game.OptionMenu.ButtonText(0, 0, settings), Infinity); 68 | me.game.world.addChild(new game.OptionMenu.message(650, 300, settings), Infinity); 69 | 70 | 71 | }, 72 | }); 73 | 74 | game.OptionMenu.background = me.Sprite.extend({ 75 | init: function(x, y, settings){ 76 | settings.image = "option_menu"; 77 | settings.anchorPoint = {x:0.5, y:0.5}; 78 | settings.width = settings.framewidth = 640; 79 | settings.height = settings.frameheight = 360; 80 | this._super(me.Sprite, 'init', [x, y, settings]); 81 | this.updateWhenPaused = true; 82 | this.name = "option_menu_bg"; 83 | this.parentMenu = settings.parentMenu; 84 | 85 | }, 86 | update: function(dt){ 87 | return true; 88 | } 89 | }); 90 | 91 | game.OptionMenu.message = me.Sprite.extend({ 92 | init: function(x, y, settings){ 93 | if(settings.menuText == "level_paused"){ 94 | settings.image = "pause_text"; 95 | settings.width = settings.framewidth = 450; 96 | settings.height = settings.frameheight = 80; 97 | 98 | }else if(settings.menuText == "level_passed"){ 99 | settings.image = "level_complete"; 100 | settings.width = settings.framewidth = 475; 101 | settings.height = settings.frameheight = 80; 102 | 103 | }else if(settings.menuText == "level_failed"){ 104 | settings.image = "level_failed"; 105 | settings.width = settings.framewidth = 370; 106 | settings.height = settings.frameheight = 80; 107 | 108 | }else{ 109 | console.log("Error: No valid menuText found" + settings.menuText); 110 | } 111 | settings.anchorPoint = {x:0.5, y:0.5}; 112 | this._super(me.Sprite, 'init', [x, y, settings]); 113 | this.updateWhenPaused = true; 114 | this.name = "option_menu_text"; 115 | }, 116 | update: function(dt){ 117 | return true; 118 | } 119 | 120 | }); 121 | 122 | game.OptionMenu.restart_button = me.GUI_Object.extend({ 123 | init: function(x, y, parentSettings){ 124 | var settings = {}; 125 | settings.image = "menu_button"; 126 | settings.frameheight = 75; 127 | settings.framewidth = 150; 128 | settings.width = 450; 129 | settings.height = 75; 130 | 131 | this._super(me.GUI_Object, 'init', [x, y, settings]); 132 | 133 | this.addAnimation("button", [0]); 134 | this.addAnimation("hover", [1]); 135 | this.addAnimation("confirm", [2]); 136 | this.setCurrentAnimation("button"); 137 | this.anchorPoint.set(0.0, 0.0); 138 | this.pos.z = Infinity; 139 | this.updateWhenPaused = true; 140 | this.name = "option_menu_button"; 141 | this.parentMenu = parentSettings.parentMenu; 142 | this.confirm = false; 143 | 144 | }, 145 | onOver: function(e){ 146 | this.setCurrentAnimation("hover"); 147 | }, 148 | onOut: function(e){ 149 | this.setCurrentAnimation("button"); 150 | this.confirm = false; 151 | }, 152 | onClick(e){ 153 | if(this.confirm == false){ 154 | this.confirm = true; 155 | }else{ 156 | me.state.resume(); 157 | me.state.change(me.state.LEVEL_INTRO); 158 | } 159 | }, 160 | 161 | update: function(dt){ 162 | if(this.confirm == true){ 163 | this.setCurrentAnimation("confirm") 164 | } 165 | return true; 166 | }, 167 | }); 168 | 169 | game.OptionMenu.continue_button = me.GUI_Object.extend({ 170 | init: function(x, y, parentSettings){ 171 | var settings = {}; 172 | 173 | settings.image = "menu_button"; 174 | settings.frameheight = 75; 175 | settings.framewidth = 150; 176 | settings.width = 450; 177 | settings.height = 75; 178 | 179 | this._super(me.GUI_Object, 'init', [x, y, settings]); 180 | 181 | this.addAnimation("button", [0]); 182 | this.addAnimation("hover", [1]); 183 | this.addAnimation("confirm", [2]); 184 | 185 | this.setCurrentAnimation("button"); 186 | this.anchorPoint.set(0.0, 0.0); 187 | this.pos.z = Infinity; 188 | this.parentMenu = parentSettings.parentMenu; 189 | this.name = "option_menu_button"; 190 | this.updateWhenPaused = true; 191 | this.currentLevel = game.data.level; //Store current level so we can't double click to skip a level. 192 | this.menuText = parentSettings.menuText; 193 | 194 | }, 195 | onOver: function(e){ 196 | this.setCurrentAnimation("hover"); 197 | }, 198 | onOut: function(e){ 199 | this.setCurrentAnimation("button"); 200 | }, 201 | 202 | onClick(e){ 203 | if(this.menuText == "level_passed"){ //if level passed then continue to next level 204 | game.data.level = this.currentLevel + 1; 205 | if(game.data.level<=3 && game.data.level>=1){ 206 | me.state.resume(); 207 | me.state.change(me.state.LEVEL_INTRO); 208 | } 209 | else if(game.data.level>3){ 210 | me.state.resume(); 211 | me.state.change(me.state.GAMEOVER); 212 | } 213 | else{ 214 | me.state.resume(); 215 | me.state.change(me.state.MENU); 216 | } 217 | }else if(this.menuText == "level_paused"){ //if pause_menu then close menu and resume game 218 | //Remove menu and buttons and resume game 219 | var text = me.game.world.getChildByName("option_menu_text"); 220 | var bg = me.game.world.getChildByName("option_menu_bg"); 221 | var buttons = me.game.world.getChildByName("option_menu_button"); 222 | var buttonsLength = buttons.length; 223 | var menus = []; 224 | 225 | me.game.world.removeChild(text[0]); 226 | me.game.world.removeChild(text[1]); 227 | me.game.world.removeChild(bg[0]); 228 | for(var i = 0; i < buttonsLength; i++){ 229 | me.game.world.removeChild(buttons[i]); 230 | var parentMenuFound = false; 231 | for(var j = 0; j < menus.length; j++) 232 | if(buttons[i].parentMenu === menus[j]) 233 | parentMenuFound = true; 234 | if(!parentMenuFound) 235 | menus.push(buttons[i].parentMenu); 236 | } 237 | for(var i = 0; i < menus.length; i++){ 238 | me.game.world.removeChild(menus[i]); 239 | } 240 | if(me.state.isPaused() == true){ 241 | me.state.resume(true); 242 | } 243 | } 244 | 245 | }, 246 | update: function(dt){ 247 | return true; 248 | }, 249 | }); 250 | 251 | 252 | game.OptionMenu.mainMenu_button = me.GUI_Object.extend({ 253 | init: function(x, y, parentSettings){ 254 | var settings = {}; 255 | 256 | settings.image = "menu_button"; 257 | settings.frameheight = 75; 258 | settings.framewidth = 150; 259 | settings.width = 450; 260 | settings.height = 75; 261 | 262 | this._super(me.GUI_Object, 'init', [x, y, settings]); 263 | 264 | this.addAnimation("button", [0]); 265 | this.addAnimation("hover", [1]); 266 | this.addAnimation("confirm", [2]); 267 | 268 | this.setCurrentAnimation("button"); 269 | this.anchorPoint.set(0.0, 0.0); 270 | this.pos.z = Infinity; 271 | this.parentMenu = parentSettings.parentMenu; 272 | this.name = "option_menu_button"; 273 | this.updateWhenPaused = true; 274 | this.confirm = false; 275 | 276 | }, 277 | onOver: function(e){ 278 | this.setCurrentAnimation("hover"); 279 | }, 280 | onOut: function(e){ 281 | this.setCurrentAnimation("button"); 282 | this.confirm = false; 283 | }, 284 | 285 | onClick(e){ 286 | if(this.confirm == false){ 287 | this.confirm = true; 288 | }else{ 289 | me.state.resume(); 290 | me.state.change(me.state.MENU); 291 | } 292 | return true; 293 | }, 294 | update: function(dt){ 295 | if(this.confirm == true){ 296 | this.setCurrentAnimation("confirm"); 297 | } 298 | return true; 299 | }, 300 | }); 301 | 302 | 303 | game.OptionMenu.ButtonText = me.Renderable.extend({ 304 | init: function(x, y, settings) { 305 | this._super(me.Renderable, 'init', [x, y, 10, 10]); 306 | this.font = new me.BitmapFont( 307 | me.loader.getBinary('font'), 308 | me.loader.getImage('font')); 309 | this.updateWhenPaused = true; 310 | this.name = "option_menu_text"; 311 | this.pauseMenu = settings.pauseMenu; 312 | this.levelPassed = settings.levelPassed; 313 | 314 | }, 315 | update : function () { 316 | 317 | return true; 318 | }, 319 | draw : function (renderer) { 320 | this.font.draw(renderer, "Restart", 415, 440); 321 | this.font.draw(renderer, "Menu", 790, 440); 322 | if(this.pauseMenu == false && this.levelPassed == true){ 323 | this.font.draw(renderer, "Continue", 590, 440); 324 | }else if(this.pauseMenu == true){ 325 | this.font.draw(renderer, "Resume", 590, 440) 326 | } 327 | 328 | } 329 | 330 | }); 331 | 332 | -------------------------------------------------------------------------------- /src/js/entities/projectiles.js: -------------------------------------------------------------------------------- 1 | game.ArrowEntity = me.Entity.extend({ 2 | init: function (x,y,settings) { 3 | //Define appearance 4 | settings.image = "arrows"; 5 | settings.width = 9; 6 | settings.height = 9; 7 | this._super(me.Entity, "init", [x,y,settings]); 8 | 9 | //Save information from settings 10 | this.damage = settings.arrowDamage; 11 | this.bleedEffect = settings.bleedEffect; 12 | this.bleedDot = settings.bleedDot; 13 | this.maxDistance = settings.arrowDistance; 14 | this.velocity = settings.arrowVelocity; 15 | this.moveDirection = settings.targetAng; 16 | if(this.moveDirection<0) 17 | this.moveDirection += 360; 18 | this.parent = settings.parent; 19 | this.currentTarget = settings.arrowTarget; 20 | 21 | //create the different animations 22 | this.renderable.addAnimation("left", [0]); 23 | this.renderable.addAnimation("right", [1]); 24 | this.renderable.addAnimation("up", [2]); 25 | this.renderable.addAnimation("down", [3]); 26 | this.renderable.addAnimation("downleft", [4]); 27 | this.renderable.addAnimation("upright", [5]); 28 | this.renderable.addAnimation("upleft", [6]); 29 | this.renderable.addAnimation("downright", [7]); 30 | 31 | //Assign animation based on flight angle 32 | this.moveDirection<=22.5?this.renderable.setCurrentAnimation("right"): 33 | this.moveDirection<=67.5?this.renderable.setCurrentAnimation("upright"): 34 | this.moveDirection<=112.5?this.renderable.setCurrentAnimation("up"): 35 | this.moveDirection<=157.5?this.renderable.setCurrentAnimation("upleft"): 36 | this.moveDirection<=202.5?this.renderable.setCurrentAnimation("left"): 37 | this.moveDirection<=247.5?this.renderable.setCurrentAnimation("downleft"): 38 | this.moveDirection<=292.5?this.renderable.setCurrentAnimation("down"): 39 | this.moveDirection<=337.5?this.renderable.setCurrentAnimation("downright"): 40 | this.renderable.setCurrentAnimation("right"); 41 | 42 | //Define types of collisions for projectiles 43 | this.body.collisionType = me.collision.types.PROJECTILE_OBJECT; 44 | this.body.setCollisionMask(me.collision.types.ENEMY_OBJECT); 45 | 46 | // Calculate velocity in x and y direction using trig 47 | this.velx = this.velocity * Math.cos(this.moveDirection * Math.PI/180); 48 | // Multiply this by negative 1 because down is positive, and the angle is Counter-Clockwise from positive X-axis 49 | this.vely = this.velocity * Math.sin(this.moveDirection * Math.PI/180) * -1; 50 | 51 | me.audio.play("arrow_shoot"); 52 | }, 53 | 54 | update: function (dt) { 55 | if(this.distanceTo(this.parent)>this.maxDistance){ 56 | me.game.world.removeChild(this); 57 | return false; 58 | } 59 | 60 | //Move the object 61 | this.pos.x += this.velx * dt / 1000; 62 | this.pos.y += this.vely * dt / 1000; 63 | 64 | return (this._super(me.Entity, 'update', [dt]) || this.body.vel.x !== 0 || this.body.vel.y !== 0); 65 | }, 66 | 67 | destroy: function(){ 68 | }, 69 | 70 | onCollision: function(response, other){ 71 | //only cause damage and disappear if target object 72 | if(other === this.currentTarget){ 73 | response.a.damageEntity(this.damage); 74 | if(this.bleedEffect) 75 | response.a.causeBleeding(this.bleedDot); 76 | me.game.world.removeChild(this); 77 | } 78 | return false; 79 | } 80 | }); 81 | 82 | game.CannonballEntity = me.Entity.extend({ 83 | init: function (x,y,settings) { 84 | //Define appearance 85 | settings.image = "cannonball"; 86 | settings.width = 32; 87 | settings.height = 32; 88 | this._super(me.Entity, "init", [x,y,settings]); 89 | this.anchorPoint.set(0.5,0.5); 90 | 91 | //Save information from settings 92 | this.damage = settings.cannonDamage; 93 | this.maxDistance = settings.cannonDistance; 94 | this.velocity = settings.cannonVelocity; 95 | this.cannonballScale = settings.cannonballScale; 96 | this.aoe_dist = settings.cannonAoe/2; 97 | this.moveDirection = settings.targetAng; 98 | if(this.moveDirection<0) 99 | this.moveDirection += 360; 100 | this.parent = settings.parent; 101 | this.targets = settings.cannonTargets; 102 | this.currentTarget = settings.cannonTarget; 103 | 104 | //Scale to the proper size 105 | this.renderable.scale(this.cannonballScale,this.cannonballScale); 106 | 107 | //create the different animations 108 | this.renderable.addAnimation("left", [4]); 109 | this.renderable.addAnimation("right", [0]); 110 | this.renderable.addAnimation("up", [2]); 111 | this.renderable.addAnimation("down", [6]); 112 | this.renderable.addAnimation("downleft", [5]); 113 | this.renderable.addAnimation("upright", [1]); 114 | this.renderable.addAnimation("upleft", [3]); 115 | this.renderable.addAnimation("downright", [7]); 116 | 117 | //Assign animation based on flight angle 118 | this.moveDirection<=22.5?this.renderable.setCurrentAnimation("right"): 119 | this.moveDirection<=67.5?this.renderable.setCurrentAnimation("upright"): 120 | this.moveDirection<=112.5?this.renderable.setCurrentAnimation("up"): 121 | this.moveDirection<=157.5?this.renderable.setCurrentAnimation("upleft"): 122 | this.moveDirection<=202.5?this.renderable.setCurrentAnimation("left"): 123 | this.moveDirection<=247.5?this.renderable.setCurrentAnimation("downleft"): 124 | this.moveDirection<=292.5?this.renderable.setCurrentAnimation("down"): 125 | this.moveDirection<=337.5?this.renderable.setCurrentAnimation("downright"): 126 | this.renderable.setCurrentAnimation("right"); 127 | 128 | //Define types of collisions for projectiles 129 | this.body.collisionType = me.collision.types.PROJECTILE_OBJECT; 130 | this.body.setCollisionMask(me.collision.types.ENEMY_OBJECT); 131 | 132 | // Calculate velocity in x and y direction using trig 133 | this.velx = this.velocity * Math.cos(this.moveDirection * Math.PI/180); 134 | // Multiply this by negative 1 because down is positive, and the angle is Counter-Clockwise from positive X-axis 135 | this.vely = this.velocity * Math.sin(this.moveDirection * Math.PI/180) * -1; 136 | 137 | //TODO update cannon audio 138 | me.audio.play("cannon_shoot",false, null, 0.15); 139 | }, 140 | 141 | update: function (dt) { 142 | //Explode, damage, then disappear (if at end of flight range, or if sufficiently close to target enemy) 143 | if((this.distanceTo(this.parent)>this.maxDistance) || this.distanceTo(this.currentTarget)<=this.aoe_dist*.75){ 144 | //Remove targets that are out of range 145 | var i = 0; 146 | while(i < this.targets.length){ 147 | //Remove out of range targets 148 | if(this.targets[i].alive == false || (this.distanceTo(this.targets[i]) > this.aoe_dist)){ 149 | //Always hit the cannon target if it's alive as long as the cannonball doesn't REALLY whiff 150 | if(this.targets[i].alive && this.targets[i] === this.currentTarget && this.distanceTo(this.currentTarget)<=this.aoe_dist*1.25){ 151 | i++; 152 | continue; 153 | } 154 | this.targets = this.targets.slice(0,i).concat(this.targets.slice(i+1,this.targets.length)); 155 | continue; 156 | } 157 | i++; 158 | } 159 | 160 | //Apply damage to remaining targets 161 | for(i = 0; i < this.targets.length; i++){ 162 | this.targets[i].damageEntity(this.damage); 163 | } 164 | 165 | //Generate graphical explosion 166 | var explosionSettings = {}; 167 | explosionSettings.lifetime = 180; 168 | explosionSettings.explosionScale = this.cannonballScale; 169 | me.game.world.addChild(me.pool.pull("ExplosionEntity", this.pos.x-32, this.pos.y-32, explosionSettings)); 170 | 171 | //Remove the cannonball object 172 | me.game.world.removeChild(this); 173 | return false; 174 | } 175 | 176 | //Move the object 177 | this.pos.x += this.velx * dt / 1000; 178 | this.pos.y += this.vely * dt / 1000; 179 | 180 | return (this._super(me.Entity, 'update', [dt]) || this.body.vel.x !== 0 || this.body.vel.y !== 0); 181 | }, 182 | 183 | destroy: function(){ 184 | }, 185 | 186 | onCollision: function(response, other){ 187 | //Add entities encountered to target list. 188 | var found = 0; 189 | for(i=0; i0) 231 | this.lifetime--; 232 | else{ 233 | me.game.world.removeChild(this); 234 | return false; 235 | } 236 | 237 | return (this._super(me.Entity, 'update', [dt])); 238 | }, 239 | 240 | destroy: function(){ 241 | }, 242 | 243 | onCollision: function(response, other){ 244 | return false; 245 | } 246 | }); 247 | 248 | //Only graphics and sound of tower's freeze effect 249 | game.FreezeExplosionEntity = me.Entity.extend({ 250 | init: function (x,y,settings) { 251 | //Define appearance 252 | settings.image = "freeze_exp"; 253 | settings.width = 160; 254 | settings.height = 160; 255 | this._super(me.Entity, "init", [x,y,settings]); 256 | //this.anchorPoint.set(0,0); 257 | 258 | //Ticks to live for 259 | this.lifetime = settings.lifetime; 260 | 261 | //Create freeze explosion animation 262 | this.renderable.setOpacity(0.5); 263 | this.animationSpeed = 100; 264 | this.renderable.addAnimation("freezeExplosion", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, {name: 11, delay: Infinity}], this.animationSpeed); 265 | this.renderable.setCurrentAnimation("freezeExplosion"); 266 | 267 | me.audio.play("slow_shoot", false, null, 0.25); 268 | }, 269 | 270 | update: function (dt) { 271 | //Countdown until lifetime expires, else, remove this object 272 | if(this.lifetime>0) 273 | this.lifetime--; 274 | else{ 275 | me.game.world.removeChild(this); 276 | return false; 277 | } 278 | 279 | return (this._super(me.Entity, 'update', [dt])); 280 | }, 281 | 282 | destroy: function(){ 283 | }, 284 | 285 | onCollision: function(response, other){ 286 | return false; 287 | } 288 | }); 289 | 290 | //Bleed Effect on enemy 291 | game.BleedEffectEntity = me.Entity.extend({ 292 | init: function (x,y,settings) { 293 | //Define appearance 294 | settings.image = "bleedEffect"; 295 | settings.width = 32; 296 | settings.height = 32; 297 | this._super(me.Entity, "init", [x,y,settings]); 298 | //this.anchorPoint.set(0,0); 299 | 300 | //Ticks to live for 301 | this.lifetime = settings.lifetime; 302 | 303 | //Create blood explosion animation 304 | this.renderable.setOpacity(0.5); 305 | this.animationSpeed = 100; 306 | this.renderable.addAnimation("bloodEffect", [0, 1, 2, 3, 4, {name: 5, delay: Infinity}], this.animationSpeed); 307 | this.renderable.setCurrentAnimation("bloodEffect"); 308 | }, 309 | 310 | update: function (dt) { 311 | //Countdown until lifetime expires, else, remove this object 312 | if(this.lifetime>0) 313 | this.lifetime--; 314 | else{ 315 | me.game.world.removeChild(this); 316 | return false; 317 | } 318 | 319 | return (this._super(me.Entity, 'update', [dt])); 320 | }, 321 | 322 | destroy: function(){ 323 | }, 324 | 325 | onCollision: function(response, other){ 326 | return false; 327 | } 328 | }); -------------------------------------------------------------------------------- /src/js/entities/slowTower.js: -------------------------------------------------------------------------------- 1 | var SLOW_TOWER_COST = 75; 2 | var SLOW_TOWER_RADIUS = 128; 3 | 4 | 5 | 6 | game.SlowTowerEntity = me.Entity.extend({ 7 | init: function (x,y,settings) { 8 | //offset entity so that center is where TowerLocationEntity was 9 | x = x - 64; 10 | y = y - 80; 11 | settings.image = "slow_tower"; 12 | //set image width to actual image size 13 | settings.framewidth = 64; 14 | settings.frameheight = 64; 15 | //set width and height to attack radius 16 | settings.width = SLOW_TOWER_RADIUS * 2; 17 | settings.height = SLOW_TOWER_RADIUS * 2; 18 | 19 | this._super(me.Entity, "init", [x,y,settings]); 20 | //set anchor point and image location to center of entity(hitbox) 21 | this.anchorPoint.set(0.5,0.5); 22 | 23 | //Towers are PLAYER_OBJECTS 24 | //These interact with walking enemies (ENEMY_OBJECT) 25 | this.body.collisionType = me.collision.types.PLAYER_OBJECT; 26 | this.body.setCollisionMask(me.collision.types.ENEMY_OBJECT); 27 | 28 | //Define Tower Defense Variables. These may be updated with the upgrade system 29 | this.fireDelay = Math.floor(me.sys.updatesPerSecond*250/60); //Value added to rofCooldown after firing 30 | this.slowCooldown = 0; //This must be 0 to fire 31 | this.slowDamage = 0; //Damage upon slow effect 32 | this.slowFactor = .35; //Percentage to slow a given enemy 33 | this.slowDuration = 500; //Ticks to apply slow effect for 34 | this.slowDistance = SLOW_TOWER_RADIUS; //Radius to affect enemies with slow 35 | this.targets = []; //List of possible targets 36 | this.upgradeLevel = 0; //Default to level 0 tower 37 | this.name = "slow_tower"; //used to produce proper upgrade menu 38 | this.value = SLOW_TOWER_COST; //Store current value of tower 39 | 40 | //Upgrade logic 41 | this.upgradesInstalled = [false, false]; //Upgrades Installed 42 | 43 | }, 44 | upgrade: function (index) { 45 | //Don't install if already installed, else mark as installed 46 | if(this.upgradesInstalled[index]) 47 | return false; 48 | this.upgradesInstalled[index] = true; //Flag upgrade as installed 49 | this.value += Math.floor(SLOW_TOWER_COST*game.data.upgradeCostFactor[this.upgradeLevel]); //Update value 50 | this.upgradeLevel++; //Update upgradeLevel 51 | 52 | //Update variables associated with upgrade 53 | //Slow effect does chill damage 54 | if(index == 0){ 55 | this.slowDamage += 8; 56 | } 57 | 58 | //Slow effect is "timesAsEffective" more effective, multiplicatively 59 | //(I promise this should work every time, at least 60% of the time :p ) 60 | else if(index == 1){ 61 | var timesAsEffective = 1.5; 62 | this.slowFactor = Math.floor((1 - Math.pow(1-this.slowFactor, timesAsEffective)) *100)/100.; 63 | } 64 | 65 | //Return true if upgrade successful 66 | return true; 67 | }, 68 | 69 | update: function (dt) { 70 | //Process Slow Cooldown if necessary 71 | if(this.slowCooldown > 0){ 72 | this.slowCooldown--; 73 | } 74 | else if(this.slowCooldown < 0){ 75 | this.slowCooldown = 0; 76 | } 77 | 78 | //Apply slow effect to targets if in range 79 | if(this.targets.length>0 && this.slowCooldown == 0){ 80 | //Remove targets that are out of range 81 | var i = 0; 82 | while(i < this.targets.length){ 83 | if(this.targets[i].alive == false || (this.distanceTo(this.targets[i]) > 150)){ 84 | this.targets = this.targets.slice(0,i).concat(this.targets.slice(i+1,this.targets.length)); 85 | continue; 86 | } 87 | i++; 88 | } 89 | 90 | //If no remaining targets then bail before applying slow 91 | if(this.targets.length == 0) 92 | return false; 93 | 94 | //Apply slow to remaining targets 95 | for(i = 0; i < this.targets.length; i++){ 96 | this.targets[i].applySlow(this.slowFactor, this.slowDuration); 97 | this.targets[i].damageEntity(this.slowDamage); 98 | } 99 | 100 | //Display freeze explosion effect 101 | var freezeSettings = {}; 102 | freezeSettings.lifetime = this.fireDelay; 103 | me.game.world.addChild(me.pool.pull("FreezeExplosionEntity", this.pos.x + 48, this.pos.y + 48, freezeSettings)); 104 | 105 | //Set cooldown 106 | this.slowCooldown += this.fireDelay; 107 | } 108 | return false; 109 | }, 110 | 111 | onCollision: function(response, other){ 112 | //Add this to the list of possible enemies if it isn't in the list already. 113 | if(response.aInB){ 114 | found = 0; 115 | for(i=0; i= SLOW_TOWER_COST){ 33 | this.setOpacity(1.0); 34 | } 35 | 36 | var atkRadObj = me.game.world.getChildByProp("tag", "attackRadius"); 37 | for(i = 0; i < atkRadObj.length; i++){ 38 | me.game.world.removeChild(atkRadObj[i]); 39 | } 40 | me.game.world.addChild(new game.Menu.AttackRadius(this.towerEntity.pos.x, 41 | this.towerEntity.pos.y, SLOW_TOWER_RADIUS), Infinity); 42 | }, 43 | onOut: function(e){ 44 | this.setOpacity(0.75); 45 | this.confirm = false; 46 | 47 | var atkRadObj = me.game.world.getChildByProp("tag", "attackRadius"); 48 | for(i = 0; i < atkRadObj.length; i++){ 49 | me.game.world.removeChild(atkRadObj[i]); 50 | } 51 | 52 | }, 53 | onClick(e){ 54 | 55 | if(game.data.gold >= SLOW_TOWER_COST && this.confirm == false){ 56 | this.confirm = true; 57 | }else if(game.data.gold >= SLOW_TOWER_COST && this.confirm == true){ 58 | this.towerEntity.towerPlaced = true; 59 | me.audio.play("tower_drop"); 60 | game.data.gold -= SLOW_TOWER_COST; 61 | 62 | //Place slow tower on map 63 | this.towerEntity.currentTower = me.game.world.addChild( 64 | new game.SlowTowerEntity(this.parentMenu.pos.x, this.parentMenu.pos.y, 65 | {width: this.width, height: this.height})); 66 | 67 | //Remove menu and buttons 68 | game.functions.removeTowerMenu(); 69 | 70 | } 71 | }, 72 | update: function(dt){ 73 | if(this.confirm == true){ 74 | this.setCurrentAnimation("slow_confirm"); 75 | } 76 | else{ 77 | this.setCurrentAnimation("slow"); 78 | } 79 | }, 80 | 81 | }); 82 | 83 | game.Menu.slow_damage_button = me.GUI_Object.extend({ 84 | init: function(x, y, settings){ 85 | settings.image = "slow_damage_icons"; 86 | settings.frameheight = 32; 87 | settings.framewidth = 32; 88 | settings.width = 64; 89 | settings.height = 32; 90 | 91 | this._super(me.GUI_Object, 'init', [x, y, settings]); 92 | 93 | this.addAnimation("slow_damage", [0]); 94 | this.addAnimation("slow_damage_confirm", [1]); 95 | this.setCurrentAnimation("slow_damage"); 96 | //set true if icon was initially clicked once and needs 97 | //to be clicked again to confirm 98 | this.confirm = false; 99 | 100 | this.anchorPoint.set(0.0, 0.0); 101 | this.setOpacity(0.75); 102 | this.pos.z = 500; 103 | this.parentMenu = settings.parentMenu; 104 | this.name = "tower_menu_object"; 105 | this.towerEntity = settings.towerEntity; 106 | 107 | //Set this to the index that corresponds to the upgrade number in the slow tower file 108 | this.upgradeIndex = 0; 109 | //Cost for this upgrade 110 | this.upgradeCost = SLOW_TOWER_COST*game.data.upgradeCostFactor[this.towerEntity.currentTower.upgradeLevel]; 111 | //Flag if this upgrade has been installed already 112 | this.upgradedAlready = this.towerEntity.currentTower.upgradesInstalled[this.upgradeIndex]; 113 | 114 | //display cost of current tower or upgrade 115 | me.game.world.addChild(new game.Menu.CostDisplay(this.pos.x, this.pos.y, this.upgradeCost), Infinity); 116 | 117 | 118 | }, 119 | onOver: function(e){ 120 | if(game.data.gold >= this.upgradeCost && !this.upgradedAlready){ 121 | this.setOpacity(1.0); 122 | } 123 | }, 124 | onOut: function(e){ 125 | this.setOpacity(0.75); 126 | this.confirm = false; 127 | }, 128 | onClick(e){ 129 | if(game.data.gold >= this.upgradeCost && !this.upgradedAlready && this.confirm == false){ 130 | this.confirm = true; 131 | } 132 | else if(game.data.gold >= this.upgradeCost && !this.upgradedAlready && this.confirm == true){ 133 | //Upgrade tower 134 | me.audio.play("upgrade"); 135 | game.data.gold -= this.upgradeCost; 136 | this.towerEntity.currentTower.upgrade(this.upgradeIndex); 137 | 138 | //Remove menu and buttons 139 | game.functions.removeTowerMenu(); 140 | 141 | } 142 | }, 143 | update: function(dt){ 144 | if(this.confirm == true){ 145 | this.setCurrentAnimation("slow_damage_confirm"); 146 | } 147 | else{ 148 | this.setCurrentAnimation("slow_damage"); 149 | } 150 | }, 151 | 152 | }); 153 | 154 | game.Menu.slow_slower_button = me.GUI_Object.extend({ 155 | init: function(x, y, settings){ 156 | settings.image = "slow_slower_icons"; 157 | settings.frameheight = 32; 158 | settings.framewidth = 32; 159 | settings.width = 64; 160 | settings.height = 32; 161 | 162 | this._super(me.GUI_Object, 'init', [x, y, settings]); 163 | 164 | this.addAnimation("slow_slower", [0]); 165 | this.addAnimation("slow_slower_confirm", [1]); 166 | this.setCurrentAnimation("slow_slower"); 167 | //set true if icon was initially clicked once and needs 168 | //to be clicked again to confirm 169 | this.confirm = false; 170 | 171 | this.anchorPoint.set(0.0, 0.0); 172 | this.setOpacity(0.75); 173 | this.pos.z = 500; 174 | this.parentMenu = settings.parentMenu; 175 | this.name = "tower_menu_object"; 176 | this.towerEntity = settings.towerEntity; 177 | 178 | //Set this to the index that corresponds to the upgrade number in the slow tower file 179 | this.upgradeIndex = 1; 180 | //Cost for this upgrade 181 | this.upgradeCost = SLOW_TOWER_COST * game.data.upgradeCostFactor[this.towerEntity.currentTower.upgradeLevel]; 182 | //Flag if this upgrade has been installed already 183 | this.upgradedAlready = this.towerEntity.currentTower.upgradesInstalled[this.upgradeIndex]; 184 | 185 | //display cost of current tower or upgrade 186 | me.game.world.addChild(new game.Menu.CostDisplay(this.pos.x, this.pos.y, this.upgradeCost), Infinity); 187 | 188 | 189 | }, 190 | onOver: function(e){ 191 | 192 | if(game.data.gold >= this.upgradeCost && !this.upgradedAlready){ 193 | this.setOpacity(1.0); 194 | } 195 | }, 196 | onOut: function(e){ 197 | this.setOpacity(0.75); 198 | this.confirm = false; 199 | }, 200 | onClick(e){ 201 | if(game.data.gold >= this.upgradeCost && !this.upgradedAlready && this.confirm == false){ 202 | this.confirm = true; 203 | } 204 | else if(game.data.gold >= this.upgradeCost && !this.upgradedAlready && this.confirm == true){ 205 | //Upgrade tower 206 | 207 | me.audio.play("upgrade"); 208 | game.data.gold -= this.upgradeCost; 209 | this.towerEntity.currentTower.upgrade(this.upgradeIndex); 210 | 211 | //Remove menu and buttons 212 | game.functions.removeTowerMenu(); 213 | 214 | } 215 | }, 216 | update: function(dt){ 217 | if(this.confirm == true){ 218 | this.setCurrentAnimation("slow_slower_confirm"); 219 | } 220 | else{ 221 | this.setCurrentAnimation("slow_slower"); 222 | } 223 | }, 224 | 225 | }); -------------------------------------------------------------------------------- /src/js/entities/tower_menu.js: -------------------------------------------------------------------------------- 1 | var TOWER_MENU_WIDTH = 128; 2 | var TOWER_MENU_HEIGHT = 128; 3 | 4 | game.Menu = game.Menu || {}; 5 | 6 | //Tower placement locations that appear on the map as concrete slabs 7 | game.TowerLocationEntity = me.GUI_Object.extend({ 8 | init: function(x, y, settings){ 9 | settings.image = "tower_location"; 10 | this._super(me.GUI_Object, "init", [x, y, settings]); 11 | 12 | this.x = x; 13 | this.y = y; 14 | this.anchorPoint.set(0,0); 15 | 16 | this.towerEntity = this; //used so menu can alter towerPlaced flag 17 | this.towerPlaced = false; //true if tower currently placed, determines menu to display 18 | this.currentTower = null; //holds tower object currently place, used for upgrading towers 19 | }, 20 | update:function(dt){ 21 | return false; 22 | }, 23 | onClick: function(event){ 24 | if(me.state.isPaused() == false){ 25 | //Close any open menus 26 | game.functions.removeTowerMenu(); 27 | 28 | var settings = {}; 29 | //set flag for settings used to pull up tower menu or upgrade menu 30 | if(this.towerPlaced == false){ 31 | settings.upgrade = false; 32 | }else if(this.towerPlaced == true && this.currentTower != null){ 33 | settings.upgrade = true; 34 | }else{ 35 | console.log("Error towerPlaced flag is set but not currentTower object"); 36 | } 37 | settings.towerEntity = this.towerEntity; 38 | //pull up menu container. passing (x,y,w,h, settings) 39 | this.Menu = new game.Menu.Container( 40 | this.x - ((TOWER_MENU_WIDTH / 2) - (this.width / 2)), 41 | this.y - ((TOWER_MENU_HEIGHT / 2) - (this.height / 2)), 42 | TOWER_MENU_WIDTH, TOWER_MENU_HEIGHT, settings); 43 | me.game.world.addChild(this.Menu); 44 | } 45 | } 46 | }); 47 | 48 | 49 | game.Menu.Container = me.Container.extend({ 50 | init: function(x, y, w, h, settings){ 51 | this._super(me.Container, "init", [x, y, w, h]); 52 | this.x = x; 53 | this.y = y; 54 | this.parentMenu = null; 55 | this.towerEntity = settings.towerEntity; 56 | this.name = "tower_menu"; 57 | this.floating = true; 58 | this.anchorPoint.set(0.5, 0.5); 59 | 60 | settings.parentMenu = this; 61 | 62 | //add circle image for popup menu 63 | this.addChild(new game.Menu.menu_circle(0, 0, 64 | {width: TOWER_MENU_WIDTH, height: TOWER_MENU_HEIGHT} ), 100); 65 | //add menu buttons 66 | if(settings.upgrade == false){ 67 | me.game.world.addChild(new game.Menu.arrow_button( 68 | this.x + 6, this.y + 6, settings), 500); 69 | me.game.world.addChild(new game.Menu.cannon_button( 70 | this.x + 90, this.y + 6, settings), 500); 71 | me.game.world.addChild(new game.Menu.slow_button( 72 | this.x + 6, this.y + 90, settings), 500); 73 | me.game.world.addChild(new game.Menu.cancel_button( 74 | this.x + 90, this.y + 90, settings), 500); 75 | //open upgrade menu 76 | }else if(settings.upgrade == true){ 77 | me.game.world.addChild(new game.Menu.sell_button( 78 | this.x + 6, this.y + 90, settings), 500); 79 | me.game.world.addChild(new game.Menu.cancel_button( 80 | this.x + 90, this.y + 90, settings), 500); 81 | if(this.towerEntity.currentTower.name == "archer_tower"){ 82 | me.game.world.addChild(new game.Menu.AttackRadius(this.towerEntity.pos.x, 83 | this.towerEntity.pos.y, ARCHER_TOWER_RADIUS), Infinity); 84 | if(this.towerEntity.currentTower.upgradesInstalled[0] == false){ 85 | me.game.world.addChild(new game.Menu.arrow_multi_button( 86 | this.x + 6, this.y + 6, settings), 500); 87 | }else{ 88 | me.game.world.addChild(new game.Menu.upgraded_button( 89 | this.x + 6, this.y + 6, settings), 500); 90 | } 91 | 92 | if(this.towerEntity.currentTower.upgradesInstalled[1] == false){ 93 | me.game.world.addChild(new game.Menu.arrow_bleed_button( 94 | this.x + 90, this.y + 6, settings), 500); 95 | }else{ 96 | me.game.world.addChild(new game.Menu.upgraded_button( 97 | this.x + 90, this.y + 6, settings), 500); 98 | } 99 | 100 | } 101 | 102 | if(this.towerEntity.currentTower.name == "cannon_tower"){ 103 | if(this.towerEntity.currentTower.upgradesInstalled[0] == false){ 104 | me.game.world.addChild(new game.Menu.AttackRadius(this.towerEntity.pos.x, 105 | this.towerEntity.pos.y, CANNON_TOWER_RADIUS), Infinity); 106 | 107 | me.game.world.addChild(new game.Menu.cannon_aoe_button( 108 | this.x + 6, this.y + 6, settings), 500); 109 | }else{ 110 | me.game.world.addChild(new game.Menu.AttackRadius(this.towerEntity.pos.x, 111 | this.towerEntity.pos.y, Math.floor(CANNON_TOWER_RADIUS * 4/3 )), Infinity); 112 | 113 | me.game.world.addChild(new game.Menu.upgraded_button( 114 | this.x + 6, this.y + 6, settings), 500); 115 | } 116 | 117 | if(this.towerEntity.currentTower.upgradesInstalled[1] == false){ 118 | me.game.world.addChild(new game.Menu.cannon_damage_button( 119 | this.x + 90, this.y + 6, settings), 500); 120 | }else{ 121 | me.game.world.addChild(new game.Menu.upgraded_button( 122 | this.x + 90, this.y + 6, settings), 500); 123 | } 124 | } 125 | 126 | if(this.towerEntity.currentTower.name == "slow_tower"){ 127 | me.game.world.addChild(new game.Menu.AttackRadius(this.towerEntity.pos.x, 128 | this.towerEntity.pos.y, SLOW_TOWER_RADIUS), Infinity); 129 | if(this.towerEntity.currentTower.upgradesInstalled[0] == false){ 130 | me.game.world.addChild(new game.Menu.slow_damage_button( 131 | this.x + 6, this.y + 6, settings), 500); 132 | }else{ 133 | me.game.world.addChild(new game.Menu.upgraded_button( 134 | this.x + 6, this.y + 6, settings), 500); 135 | } 136 | 137 | if(this.towerEntity.currentTower.upgradesInstalled[1] == false){ 138 | me.game.world.addChild(new game.Menu.slow_slower_button( 139 | this.x + 90, this.y + 6, settings), 500); 140 | }else{ 141 | me.game.world.addChild(new game.Menu.upgraded_button( 142 | this.x + 90, this.y + 6, settings), 500); 143 | } 144 | } 145 | } 146 | }, 147 | }); 148 | 149 | 150 | 151 | game.Menu.menu_circle = me.Sprite.extend({ 152 | init: function(x, y, settings){ 153 | settings.image = "menu_circle"; 154 | settings.anchorPoint = {x:0.0, y:0.0}; 155 | this._super(me.Sprite, 'init', [x, y, settings]); 156 | }, 157 | update: function(dt){ 158 | return true; 159 | } 160 | 161 | }); 162 | 163 | game.Menu.upgraded_button = me.GUI_Object.extend({ 164 | init: function(x, y, settings){ 165 | settings.image = "upgraded_icon"; 166 | settings.frameheight = settings.height = 32; 167 | settings.framewidth = settings.width = 32; 168 | this._super(me.GUI_Object, 'init', [x, y, settings]); 169 | this.anchorPoint.set(0.0, 0.0); 170 | this.parentMenu = settings.parentMenu; 171 | this.name = "tower_menu_object"; 172 | }, 173 | onClick(e){ 174 | 175 | } 176 | }); 177 | 178 | game.Menu.CostDisplay = me.Renderable.extend({ 179 | 180 | init: function(x, y, cost) { 181 | this._super(me.Renderable, 'init', [x, y, 10, 10]); 182 | this.cost = cost; 183 | this.parentMenu = null; 184 | this.name = "tower_menu_object"; 185 | this.font = new me.BitmapFont( 186 | me.loader.getBinary('moneyfont'), 187 | me.loader.getImage('moneyfont')); 188 | 189 | }, 190 | update : function () { 191 | return false; 192 | }, 193 | draw : function (renderer) { 194 | this.font.draw(renderer, this.cost, this.pos.x + 2, this.pos.y + 24); 195 | } 196 | 197 | }); 198 | 199 | game.Menu.AttackRadius = me.Renderable.extend({ 200 | 201 | init: function(x, y, r) { 202 | this._super(me.Renderable, 'init', [x, y, 0, 0]); 203 | this.anchorPoint.set(0.5, 0.5); 204 | this.name = "tower_menu_object"; 205 | this.tag = "attackRadius"; 206 | this.radius = r; 207 | }, 208 | update : function () { 209 | return false; 210 | }, 211 | draw : function (renderer) { 212 | renderer.setLineWidth(1); 213 | renderer.setColor("rgba(255, 0, 0, 1"); 214 | renderer.strokeArc(this.pos.x - this.radius + 32, this.pos.y - this.radius + 32, this.radius, 0, 2 * Math.PI) 215 | 216 | renderer.setColor("rgba(255, 0, 0, 0.2"); 217 | renderer.setLineWidth(this.radius / 2 - 16); 218 | renderer.strokeArc(this.pos.x - (this.radius / 2 + this.radius / 4 + 8) + 32, this.pos.y - (this.radius / 2 + this.radius / 4 + 8) + 32, (this.radius / 2 + this.radius / 4 + 8), 0, 2 * Math.PI) 219 | 220 | } 221 | }); 222 | 223 | game.Menu.cancel_button = me.GUI_Object.extend({ 224 | init: function(x, y, settings){ 225 | settings.image = "cancel_icon"; 226 | 227 | this._super(me.GUI_Object, 'init', [x, y, settings]); 228 | this.anchorPoint.set(0.0, 0.0); 229 | this.parentMenu = settings.parentMenu; 230 | this.name = "tower_menu_object"; 231 | }, 232 | onClick(e){ 233 | game.functions.removeTowerMenu(); 234 | } 235 | }); 236 | 237 | game.Menu.sell_button = me.GUI_Object.extend({ 238 | init: function(x, y, settings){ 239 | settings.image = "sell_icons"; 240 | settings.frameheight = 32; 241 | settings.framewidth = 32; 242 | settings.width = 64; 243 | settings.height = 32; 244 | 245 | this._super(me.GUI_Object, 'init', [x, y, settings]); 246 | 247 | this.addAnimation("sell", [0]); 248 | this.addAnimation("sell_confirm", [1]); 249 | this.setCurrentAnimation("sell"); 250 | this.confirm = false; 251 | 252 | 253 | this.anchorPoint.set(0.0, 0.0); 254 | this.parentMenu = settings.parentMenu; 255 | this.setOpacity(0.75); 256 | this.name = "tower_menu_object"; 257 | }, 258 | onOver: function(e){ 259 | this.setOpacity(1.0); 260 | }, 261 | onOut: function(e){ 262 | this.setOpacity(0.75); 263 | }, 264 | onClick(e){ 265 | 266 | if(this.confirm == false){ 267 | this.confirm = true; 268 | }else{ 269 | 270 | //Remove menu and buttons 271 | game.functions.removeTowerMenu(); 272 | me.audio.play("sell_item"); 273 | 274 | //Refund gold 275 | var tower = this.parentMenu.towerEntity.currentTower; 276 | var baseCost = tower.value; 277 | var refundFactor = .5 //Percentage of tower value to refund 278 | game.data.gold += Math.floor(baseCost * refundFactor); 279 | 280 | //remove actual tower 281 | me.game.world.removeChild(tower); 282 | this.parentMenu.towerEntity.currentTower = null; 283 | this.parentMenu.towerEntity.towerPlaced = false; 284 | } 285 | }, 286 | update: function(dt){ 287 | if(this.confirm == true){ 288 | this.setCurrentAnimation("sell_confirm"); 289 | } 290 | else{ 291 | this.setCurrentAnimation("sell"); 292 | } 293 | } 294 | }); 295 | 296 | -------------------------------------------------------------------------------- /src/js/game.js: -------------------------------------------------------------------------------- 1 | 2 | /* Game namespace */ 3 | var game = { 4 | 5 | // an object where to store game information 6 | data : { 7 | // Player Gold Amount 8 | gold : 125, 9 | // Bonus Gold Awarded per wave 10 | bonus_gold : 25, 11 | //Current Level Number 12 | level : 1, 13 | //Max or last game level 14 | lastLevel : 3, 15 | //Current Wave Number 16 | wave : 0, 17 | //Enemy Strength 18 | enemyStrength : 0, 19 | // Number of Player Lives Remaining 20 | playerLives : 10, 21 | 22 | upgradeCostFactor: [1, 2] //1x cost for first upgrade, 2x cost for second, extend if additional upgrades 23 | }, 24 | 25 | // Run on page load. 26 | "onload" : function () { 27 | // Initialize the video. 28 | if (!me.video.init(1280, 720, {wrapper : "screen", scale : "auto"})) { 29 | alert("Your browser does not support HTML5 canvas."); 30 | return; 31 | } 32 | 33 | // Initialize the audio. 34 | me.audio.init("aac"); 35 | 36 | // set and load all resources. 37 | // (this will also automatically switch to the loading screen) 38 | me.loader.preload(game.resources, this.loaded.bind(this)); 39 | me.state.change(me.state.LOADING); 40 | }, 41 | 42 | // Run on game resources loaded. 43 | "loaded" : function () { 44 | //Set User defined states 45 | me.state.LEVEL_COMPLETE= me.state.USER + 0; 46 | me.state.LEVEL01 = me.state.USER + 1; 47 | me.state.LEVEL02 = me.state.USER + 2; 48 | me.state.LEVEL03 = me.state.USER + 3; 49 | me.state.INSTRUCTIONS = me.state.USER + 4; 50 | 51 | me.state.transition("fade", "#000000", 500); 52 | me.state.set(me.state.MENU, new game.TitleScreen()); 53 | me.state.set(me.state.LEVEL01, new game.Level01PlayScreen()); 54 | me.state.set(me.state.LEVEL02, new game.Level02PlayScreen()); 55 | me.state.set(me.state.LEVEL03, new game.Level03PlayScreen()); 56 | me.state.set(me.state.GAMEOVER, new game.gameOverScreen()); 57 | me.state.set(me.state.LEVEL_INTRO, new game.levelIntroScreen()); 58 | me.state.set(me.state.INSTRUCTIONS, new game.InstructionScreen()); 59 | 60 | // Load Enemy Entities to pool 61 | me.pool.register("FootmanEntity", game.FootmanEntity); 62 | me.pool.register("GoblinEntity", game.GoblinEntity); 63 | me.pool.register("ImpEntity", game.ImpEntity); 64 | 65 | // Load Map Entities to pool 66 | me.pool.register("MapNode", game.MapNode); 67 | me.pool.register("KillNode", game.KillNode); 68 | me.pool.register("ForkNode", game.ForkNode); 69 | 70 | //Load Tower Entities to pool 71 | me.pool.register("TowerLocationEntity", game.TowerLocationEntity); 72 | me.pool.register("ArcherTowerEntity", game.ArcherTowerEntity); 73 | me.pool.register("CannonTowerEntity",game.CannonTowerEntity); 74 | me.pool.register("SlowTowerEntity", game.SlowTowerEntity); 75 | 76 | 77 | //Load Projectile Entities to pool 78 | me.pool.register("ArrowEntity", game.ArrowEntity); 79 | me.pool.register("CannonballEntity", game.CannonballEntity); 80 | me.pool.register("ExplosionEntity", game.ExplosionEntity); 81 | me.pool.register("FreezeExplosionEntity", game.FreezeExplosionEntity); 82 | me.pool.register("BleedEffectEntity",game.BleedEffectEntity); 83 | 84 | // display the title screen 85 | me.state.change(me.state.MENU); 86 | } 87 | }; 88 | -------------------------------------------------------------------------------- /src/js/gamefunctions.js: -------------------------------------------------------------------------------- 1 | game.functions = { 2 | 3 | //remove all object used to create the tower menu 4 | removeTowerMenu: function(){ 5 | var menuObjects = me.game.world.getChildByName("tower_menu_object"); 6 | var menuObjectsLength = menuObjects.length; 7 | var menus = []; 8 | 9 | for(var i = 0; i < menuObjectsLength; i++){ 10 | var parentMenuFound = false; 11 | for(var j = 0; j < menus.length; j++) 12 | if(menuObjects[i].parentMenu === menus[j]) 13 | parentMenuFound = true; 14 | if(!parentMenuFound){ 15 | if(menuObjects[i].parentMenu != null){ 16 | menus.push(menuObjects[i].parentMenu); 17 | } 18 | } 19 | //remove object from world 20 | me.game.world.removeChild(menuObjects[i]); 21 | } 22 | //remove menu container after objects removed 23 | for(var i = 0; i < menus.length; i++){ 24 | me.game.world.removeChild(menus[i]); 25 | } 26 | 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /src/js/screens/gameOver.js: -------------------------------------------------------------------------------- 1 | game.gameOverScreen = me.ScreenObject.extend({ 2 | 3 | onResetEvent: function() { 4 | // play game over music 5 | setTimeout(me.audio.playTrack("low_point",0),500); //Wait for previous track to finish before starting 6 | me.audio.fade("low_point", 0, 1, 500); 7 | 8 | var backgroundImage = new me.Sprite(0, 0, { 9 | image: me.loader.getImage('winscreen'), 10 | } 11 | ); 12 | 13 | // position image starting in upper left corner 14 | backgroundImage.anchorPoint.set(0,0); 15 | 16 | // resize image to fit viewport 17 | backgroundImage.scale(me.game.viewport.width / backgroundImage.width, me.game.viewport.height / backgroundImage.height); 18 | 19 | // add image to world container 20 | me.game.world.addChild(backgroundImage, 1); 21 | 22 | me.game.world.addChild(new (me.Renderable.extend ({ 23 | // constructor 24 | init : function () { 25 | this._super(me.Renderable, 'init', [0, 0, me.game.viewport.width, me.game.viewport.height]); 26 | }, 27 | 28 | update : function (dt) { 29 | return true; 30 | }, 31 | 32 | onDestroyEvent : function () { 33 | 34 | } 35 | })), 2); 36 | 37 | // change to play state on press Enter or click/tap 38 | me.input.bindKey(me.input.KEY.ENTER, "enter", true); 39 | me.input.bindPointer(me.input.pointer.LEFT, me.input.KEY.ENTER); 40 | this.handler = me.event.subscribe(me.event.KEYDOWN, function (action, keyCode, edge) { 41 | if (action === "enter") { 42 | me.state.change(me.state.MENU); 43 | } 44 | 45 | }); 46 | 47 | }, 48 | 49 | onDestroyEvent: function() { 50 | me.input.unbindKey(me.input.KEY.ENTER); 51 | me.input.unbindKey(me.input.KEY.M); 52 | me.input.unbindPointer(me.input.pointer.LEFT); 53 | me.audio.fade("low_point", 1, 0, 500); 54 | setTimeout(me.audio.stopTrack("low_point"),500); 55 | me.event.unsubscribe(this.handler); 56 | 57 | } 58 | }); 59 | -------------------------------------------------------------------------------- /src/js/screens/instructions.js: -------------------------------------------------------------------------------- 1 | game.InstructionScreen = me.ScreenObject.extend({ 2 | 3 | onResetEvent: function() { 4 | // play title music 5 | setTimeout(me.audio.playTrack("instruction_screen",0),500); //Wait for previous track to finish before starting 6 | me.audio.fade("instruction_screen", 0, .5, 500); 7 | 8 | var backgroundImage = new me.Sprite(0, 0, { 9 | image: me.loader.getImage('instructions1'), 10 | } 11 | ); 12 | 13 | // position image starting in upper left corner 14 | backgroundImage.anchorPoint.set(0,0); 15 | 16 | // resize image to fit viewport 17 | backgroundImage.scale(me.game.viewport.width / backgroundImage.width, me.game.viewport.height / backgroundImage.height); 18 | 19 | // Counter to count the number of instruction screens shown 20 | game.data.instructionsShown = 1; 21 | 22 | // add image to world container 23 | me.game.world.addChild(backgroundImage, 1); 24 | 25 | me.game.world.addChild(new (me.Renderable.extend ({ 26 | // constructor 27 | init : function () { 28 | this._super(me.Renderable, 'init', [0, 0, me.game.viewport.width, me.game.viewport.height]); 29 | }, 30 | 31 | update : function (dt) { 32 | return true; 33 | }, 34 | 35 | onDestroyEvent : function () { 36 | 37 | } 38 | })), 2); 39 | 40 | // change to play state on press Enter or click/tap 41 | me.input.bindKey(me.input.KEY.ENTER, "enter", true); 42 | me.input.bindPointer(me.input.pointer.LEFT, me.input.KEY.ENTER); 43 | this.handler = me.event.subscribe(me.event.KEYDOWN, function (action, keyCode, edge) { 44 | if (action === "enter") { 45 | if(game.data.instructionsShown == 1){ 46 | var backgroundImage = new me.Sprite(0, 0, { 47 | image: me.loader.getImage('instructions2'), 48 | } 49 | ); 50 | backgroundImage.anchorPoint.set(0,0); 51 | backgroundImage.scale(me.game.viewport.width / backgroundImage.width, me.game.viewport.height / backgroundImage.height); 52 | me.game.world.addChild(backgroundImage,2); 53 | game.data.instructionsShown++; 54 | } 55 | else if(game.data.instructionsShown == 2){ 56 | var backgroundImage = new me.Sprite(0, 0, { 57 | image: me.loader.getImage('instructions3'), 58 | } 59 | ); 60 | backgroundImage.anchorPoint.set(0,0); 61 | backgroundImage.scale(me.game.viewport.width / backgroundImage.width, me.game.viewport.height / backgroundImage.height); 62 | me.game.world.addChild(backgroundImage,3); 63 | game.data.instructionsShown++; 64 | } 65 | else if(game.data.instructionsShown == 3){ 66 | var backgroundImage = new me.Sprite(0, 0, { 67 | image: me.loader.getImage('instructions4'), 68 | } 69 | ); 70 | backgroundImage.anchorPoint.set(0,0); 71 | backgroundImage.scale(me.game.viewport.width / backgroundImage.width, me.game.viewport.height / backgroundImage.height); 72 | me.game.world.addChild(backgroundImage,4); 73 | game.data.instructionsShown++; 74 | } 75 | else if(game.data.instructionsShown == 4){ 76 | var backgroundImage = new me.Sprite(0, 0, { 77 | image: me.loader.getImage('instructions5'), 78 | } 79 | ); 80 | backgroundImage.anchorPoint.set(0,0); 81 | backgroundImage.scale(me.game.viewport.width / backgroundImage.width, me.game.viewport.height / backgroundImage.height); 82 | me.game.world.addChild(backgroundImage,5); 83 | game.data.instructionsShown++; 84 | } 85 | else if(game.data.instructionsShown == 5){ 86 | var backgroundImage = new me.Sprite(0, 0, { 87 | image: me.loader.getImage('instructions6'), 88 | } 89 | ); 90 | backgroundImage.anchorPoint.set(0,0); 91 | backgroundImage.scale(me.game.viewport.width / backgroundImage.width, me.game.viewport.height / backgroundImage.height); 92 | me.game.world.addChild(backgroundImage,6); 93 | game.data.instructionsShown++; 94 | } 95 | else{ 96 | me.state.change(me.state.MENU); 97 | } 98 | 99 | } 100 | }); 101 | 102 | }, 103 | 104 | onDestroyEvent: function() { 105 | me.input.unbindKey(me.input.KEY.ENTER); 106 | me.input.unbindPointer(me.input.pointer.LEFT); 107 | me.audio.fade("instruction_screen", .5, 0, 500); 108 | setTimeout(me.audio.stopTrack("instruction_screen"),500); 109 | me.event.unsubscribe(this.handler); 110 | 111 | } 112 | }); 113 | -------------------------------------------------------------------------------- /src/js/screens/level01.js: -------------------------------------------------------------------------------- 1 | game.Level01PlayScreen = me.ScreenObject.extend({ 2 | 3 | onResetEvent: function() { 4 | //Set audio track 5 | setTimeout(me.audio.playTrack("level01bgm",0),500); //Wait for previous track to finish before playing 6 | me.audio.fade("level01bgm",0,1,500); //Fade in 7 | 8 | 9 | // Reset Enemy settings so we'll save the proper settings for the new level 10 | me.game.footmanSettings = undefined; 11 | me.game.goblinSettings = undefined; 12 | me.game.impSettings = undefined; 13 | 14 | // Set level data 15 | game.data.gold = 125; 16 | game.data.playerLives = 10; 17 | game.data.wave = 0; 18 | game.data.enemyStrength = 0; 19 | 20 | //Define and populate an object holding the enemy spawn data for this level 21 | game.levelData = {}; 22 | game.levelData.waveDelay = Math.floor(me.sys.updatesPerSecond*500/60); 23 | //Number of footmen, footman tick seperation, number of goblins, goblin tick seperation, number of imps, imp tick seperation 24 | game.levelData.waveInfo = [[4, 150, 0, 0, 0, 0], 25 | [4, 100, 2, 150, 0, 0], 26 | [4, 100, 3, 150, 0, 0], 27 | [10, 100, 0, 0, 0, 0], 28 | [5, 100, 5, 150, 0, 0], 29 | [3, 100, 0, 0, 1, 0], 30 | [5, 100, 10, 100, 1, 0], 31 | [10, 100, 5, 100, 2, 200], 32 | [20, 75, 5, 75, 1, 0], 33 | [15, 50, 5, 75, 3, 100]]; 34 | 35 | //Power of Footman, Goblins, and Imps, respectively 36 | game.levelData.enemyPower = [1, 2, 3]; 37 | game.levelData.numberWaves = game.levelData.waveInfo.length; 38 | game.levelData.waveStrength = []; 39 | for(i = 0; i= game.levelData.numberWaves) 98 | { 99 | me.state.pause(true); 100 | //menu_settings will determine what is displayed on menu 101 | var menu_settings = {}; 102 | menu_settings.pauseMenu = false; 103 | menu_settings.levelPassed = true; 104 | menu_settings.width = 640; 105 | menu_settings.height = 360; 106 | var optionMenu = new game.OptionMenu.Container(menu_settings); 107 | me.game.world.addChild(optionMenu); 108 | return true; 109 | 110 | } 111 | }, 112 | spawnNewWave: function(nextWave) { 113 | //Add wave bonus gold (except for first wave) 114 | if(nextWave>0) 115 | game.data.gold += game.data.bonus_gold; 116 | 117 | //Add strength for next wave 118 | game.data.enemyStrength += game.levelData.waveStrength[nextWave]; 119 | 120 | //Reset tick delay 121 | me.game.goblinSettings.tickDelay = me.game.footmanSettings.tickDelay = me.game.impSettings.tickDelay = game.levelData.waveDelay; 122 | 123 | //Populate New Enemies 124 | for(i = 0; i < game.levelData.waveInfo[nextWave][0]; i++) 125 | { 126 | me.game.world.addChild(me.pool.pull("FootmanEntity")); 127 | me.game.footmanSettings.tickDelay += Math.floor(me.sys.updatesPerSecond*game.levelData.waveInfo[nextWave][1]/60); 128 | } 129 | for(i = 0; i < game.levelData.waveInfo[nextWave][2]; i++) 130 | { 131 | me.game.world.addChild(me.pool.pull("GoblinEntity")); 132 | me.game.goblinSettings.tickDelay += Math.floor(me.sys.updatesPerSecond*game.levelData.waveInfo[nextWave][3]/60); 133 | } 134 | for(i = 0; i < game.levelData.waveInfo[nextWave][4];i++) 135 | { 136 | me.game.world.addChild(me.pool.pull("ImpEntity")); 137 | me.game.impSettings.tickDelay += Math.floor(me.sys.updatesPerSecond*game.levelData.waveInfo[nextWave][5]/60); 138 | } 139 | }, 140 | onDestroyEvent: function() { 141 | // remove the HUD from the game world 142 | me.game.world.removeChild(this.HUD); 143 | me.game.footmanSettings = undefined; 144 | me.game.goblinSettings = undefined; 145 | me.game.impSettings = undefined; 146 | me.audio.fade("level01bgm", 1, 0, 500); 147 | setTimeout(me.audio.stopTrack("level01bgm"),500); 148 | } 149 | }); 150 | -------------------------------------------------------------------------------- /src/js/screens/level02.js: -------------------------------------------------------------------------------- 1 | game.Level02PlayScreen = me.ScreenObject.extend({ 2 | onResetEvent: function() { 3 | //Set audio track 4 | setTimeout(me.audio.playTrack("level01bgm",0),500); //Wait for previous track to finish before playing 5 | me.audio.fade("level01bgm",0,1,500); //Fade in 6 | 7 | // Reset Enemy settings so we'll save the proper settings for the new level 8 | me.game.footmanSettings = undefined; 9 | me.game.goblinSettings = undefined; 10 | me.game.impSettings = undefined; 11 | 12 | // Set level data 13 | game.data.gold = 175; 14 | game.data.playerLives = 10; 15 | game.data.wave = 0; 16 | game.data.enemyStrength = 0; 17 | 18 | //Define and populate an object holding the enemy spawn data for this level 19 | game.levelData = {}; 20 | game.levelData.waveDelay = Math.floor(me.sys.updatesPerSecond*500/60); 21 | //Number of footmen, footman tick seperation, number of goblins, goblin tick seperation, number of imps, imp tick seperation 22 | game.levelData.waveInfo = [[2, 250, 5, 75, 0, 0], 23 | [4, 100, 6, 75, 0, 0], 24 | [5, 50, 8, 150, 0, 0], 25 | [10, 100, 5, 25, 0, 0], 26 | [3, 200, 20, 50, 0, 0], 27 | [4, 100, 5, 50, 1, 0], 28 | [8, 100, 12, 100, 1, 0], 29 | [13, 100, 8, 75, 2, 200], 30 | [15, 75, 25, 50, 0, 0], 31 | [15, 50, 20, 75, 3, 100]]; 32 | 33 | //Power of Footman, Goblins, and Imps, respectively 34 | game.levelData.enemyPower = [1, 2, 3]; 35 | game.levelData.numberWaves = game.levelData.waveInfo.length; 36 | game.levelData.waveStrength = []; 37 | for(i = 0; i= game.levelData.numberWaves) 95 | { 96 | me.state.pause(true); 97 | //menu_settings will determine what is displayed on menu 98 | var menu_settings = {}; 99 | menu_settings.pauseMenu = false; 100 | menu_settings.levelPassed = true; 101 | menu_settings.width = 640; 102 | menu_settings.height = 360; 103 | var optionMenu = new game.OptionMenu.Container(menu_settings); 104 | me.game.world.addChild(optionMenu); 105 | return true; 106 | } 107 | }, 108 | spawnNewWave: function(nextWave) { 109 | //Add wave bonus gold (except for first wave) 110 | if(nextWave>0) 111 | game.data.gold += game.data.bonus_gold; 112 | 113 | //Add strength for next wave 114 | game.data.enemyStrength += game.levelData.waveStrength[nextWave]; 115 | 116 | //Reset tick delay 117 | me.game.goblinSettings.tickDelay = me.game.footmanSettings.tickDelay = me.game.impSettings.tickDelay = game.levelData.waveDelay; 118 | 119 | //Populate New Enemies 120 | for(i = 0; i < game.levelData.waveInfo[nextWave][0]; i++) 121 | { 122 | me.game.world.addChild(me.pool.pull("FootmanEntity")); 123 | me.game.footmanSettings.tickDelay += Math.floor(me.sys.updatesPerSecond*game.levelData.waveInfo[nextWave][1]/60); 124 | } 125 | for(i = 0; i < game.levelData.waveInfo[nextWave][2]; i++) 126 | { 127 | me.game.world.addChild(me.pool.pull("GoblinEntity")); 128 | me.game.goblinSettings.tickDelay += Math.floor(me.sys.updatesPerSecond*game.levelData.waveInfo[nextWave][3]/60); 129 | } 130 | for(i = 0; i < game.levelData.waveInfo[nextWave][4];i++) 131 | { 132 | me.game.world.addChild(me.pool.pull("ImpEntity")); 133 | me.game.impSettings.tickDelay += Math.floor(me.sys.updatesPerSecond*game.levelData.waveInfo[nextWave][5]/60); 134 | } 135 | }, 136 | onDestroyEvent: function() { 137 | // remove the HUD from the game world 138 | me.game.world.removeChild(this.HUD); 139 | me.game.footmanSettings = undefined; 140 | me.game.goblinSettings = undefined; 141 | me.game.impSettings = undefined; 142 | me.audio.fade("level01bgm", 1, 0, 500); 143 | setTimeout(me.audio.stopTrack("level01bgm"),500); 144 | } 145 | }); 146 | -------------------------------------------------------------------------------- /src/js/screens/level03.js: -------------------------------------------------------------------------------- 1 | game.Level03PlayScreen = me.ScreenObject.extend({ 2 | onResetEvent: function() { 3 | //Set audio track 4 | setTimeout(me.audio.playTrack("level01bgm",0),500); //Wait for previous track to finish before playing 5 | me.audio.fade("level01bgm",0,1,500); //Fade in 6 | 7 | // Reset Enemy settings so we'll save the proper settings for the new level 8 | me.game.footmanSettings = undefined; 9 | me.game.goblinSettings = undefined; 10 | me.game.impSettings = undefined; 11 | 12 | // Reset the score 13 | game.data.gold = 250; 14 | game.data.playerLives = 10; 15 | game.data.wave = 0; 16 | game.data.enemyStrength = 0; 17 | 18 | //Define and populate an object holding the enemy spawn data for this level 19 | game.levelData = {}; 20 | game.levelData.waveDelay = Math.floor(me.sys.updatesPerSecond*500/60); 21 | //Number of footmen, footman tick seperation, number of goblins, goblin tick seperation, number of imps, imp tick seperation 22 | game.levelData.waveInfo = [[3, 150, 4, 250, 0, 0], 23 | [4, 100, 2, 150, 0, 0], 24 | [4, 100, 3, 150, 0, 0], 25 | [10, 100, 0, 0, 0, 0], 26 | [5, 100, 5, 150, 0, 0], 27 | [3, 100, 0, 0, 1, 0], 28 | [5, 100, 10, 100, 1, 0], 29 | [10, 100, 5, 100, 2, 200], 30 | [20, 75, 5, 75, 1, 0], 31 | [15, 50, 5, 75, 3, 100]]; 32 | 33 | //Power of Footmen, Goblins, and Imps, respectively 34 | game.levelData.enemyPower = [1, 2, 3]; 35 | game.levelData.numberWaves = game.levelData.waveInfo.length; 36 | game.levelData.waveStrength = []; 37 | for(i = 0; i= game.levelData.numberWaves) 95 | { 96 | me.state.pause(true); 97 | //menu_settings will determine what is displayed on menu 98 | var menu_settings = {}; 99 | menu_settings.pauseMenu = false; 100 | menu_settings.levelPassed = true; 101 | menu_settings.width = 640; 102 | menu_settings.height = 360; 103 | var optionMenu = new game.OptionMenu.Container(menu_settings); 104 | me.game.world.addChild(optionMenu); 105 | return true; 106 | } 107 | }, 108 | spawnNewWave: function(nextWave) { 109 | //Add wave bonus gold (except for first wave) 110 | if(nextWave>0) 111 | game.data.gold += game.data.bonus_gold; 112 | 113 | //Add strength for next wave 114 | game.data.enemyStrength += game.levelData.waveStrength[nextWave]; 115 | 116 | //Reset tick delay 117 | me.game.goblinSettings.tickDelay = me.game.footmanSettings.tickDelay = me.game.impSettings.tickDelay = game.levelData.waveDelay; 118 | 119 | //Populate New Enemies 120 | for(i = 0; i < game.levelData.waveInfo[nextWave][0]; i++) 121 | { 122 | me.game.world.addChild(me.pool.pull("FootmanEntity")); 123 | me.game.footmanSettings.tickDelay += Math.floor(me.sys.updatesPerSecond*game.levelData.waveInfo[nextWave][1]/60); 124 | } 125 | for(i = 0; i < game.levelData.waveInfo[nextWave][2]; i++) 126 | { 127 | me.game.world.addChild(me.pool.pull("GoblinEntity")); 128 | me.game.goblinSettings.tickDelay += Math.floor(me.sys.updatesPerSecond*game.levelData.waveInfo[nextWave][3]/60); 129 | } 130 | for(i = 0; i < game.levelData.waveInfo[nextWave][4];i++) 131 | { 132 | me.game.world.addChild(me.pool.pull("ImpEntity")); 133 | me.game.impSettings.tickDelay += Math.floor(me.sys.updatesPerSecond*game.levelData.waveInfo[nextWave][5]/60); 134 | } 135 | }, 136 | onDestroyEvent: function() { 137 | // remove the HUD from the game world 138 | me.game.world.removeChild(this.HUD); 139 | me.game.footmanSettings = undefined; 140 | me.game.goblinSettings = undefined; 141 | me.game.impSettings = undefined; 142 | me.audio.fade("level01bgm", 1, 0, 500); 143 | setTimeout(me.audio.stopTrack("level01bgm"),500); 144 | } 145 | }); 146 | -------------------------------------------------------------------------------- /src/js/screens/levelIntro.js: -------------------------------------------------------------------------------- 1 | game.levelIntroScreen = me.ScreenObject.extend({ 2 | onResetEvent: function() { 3 | // play level complete music 4 | setTimeout(me.audio.playTrack("lost_island",0),500); //Wait for previous track to finish before starting 5 | me.audio.fade("lost_island", 0, 1, 500); 6 | 7 | if(game.data.level == 1) 8 | var backgroundImage = new me.Sprite(0, 0, { 9 | image: me.loader.getImage('introLevel01'), 10 | } 11 | ); 12 | else if(game.data.level == 2) 13 | var backgroundImage = new me.Sprite(0, 0, { 14 | image: me.loader.getImage('introLevel02'), 15 | } 16 | ); 17 | else if(game.data.level == 3) 18 | var backgroundImage = new me.Sprite(0, 0, { 19 | image: me.loader.getImage('introLevel03'), 20 | } 21 | ); 22 | else 23 | me.state.change(me.state.MENU); 24 | 25 | // position image starting in upper left corner 26 | backgroundImage.anchorPoint.set(0,0); 27 | 28 | // resize image to fit viewport 29 | backgroundImage.scale(me.game.viewport.width / backgroundImage.width, me.game.viewport.height / backgroundImage.height); 30 | 31 | // add image to world container 32 | me.game.world.addChild(backgroundImage, 1); 33 | 34 | me.game.world.addChild(new (me.Renderable.extend ({ 35 | // constructor 36 | init : function () { 37 | this._super(me.Renderable, 'init', [0, 0, me.game.viewport.width, me.game.viewport.height]); 38 | 39 | }, 40 | 41 | update : function (dt) { 42 | return true; 43 | }, 44 | 45 | onDestroyEvent : function () { 46 | 47 | } 48 | })), 2); 49 | 50 | // change to play state on press Enter or click/tap 51 | me.input.bindKey(me.input.KEY.ENTER, "enter", true); 52 | me.input.bindPointer(me.input.pointer.LEFT, me.input.KEY.ENTER); 53 | this.handler = me.event.subscribe(me.event.KEYDOWN, function (action, keyCode, edge) { 54 | if (action === "enter") { 55 | if(game.data.level == 1) 56 | me.state.change(me.state.LEVEL01); 57 | else if (game.data.level == 2) 58 | me.state.change(me.state.LEVEL02); 59 | else if (game.data.level == 3) 60 | me.state.change(me.state.LEVEL03); 61 | else if (game.data.level > 3){ 62 | //me.state.change(me.state.WINSCREEN); //TODO 63 | me.state.change(me.state.MENU); 64 | } 65 | else 66 | me.state.change(me.state.MENU); 67 | } 68 | }); 69 | 70 | }, 71 | onDestroyEvent: function() { 72 | me.input.unbindKey(me.input.KEY.ENTER); 73 | me.input.unbindPointer(me.input.pointer.LEFT); 74 | me.audio.fade("lost_island", 1, 0, 500); 75 | setTimeout(me.audio.stopTrack("lost_island"),500); 76 | me.event.unsubscribe(this.handler); 77 | 78 | } 79 | }); 80 | -------------------------------------------------------------------------------- /src/js/screens/title.js: -------------------------------------------------------------------------------- 1 | game.TitleScreen = me.ScreenObject.extend({ 2 | /** 3 | * action to perform on state change 4 | */ 5 | onResetEvent: function() { 6 | // play title music 7 | setTimeout(me.audio.playTrack("title_music",0),500); //Wait for previous track to finish before starting 8 | me.audio.fade("title_music", 0, 1, 500); 9 | 10 | var backgroundImage = new me.Sprite(0, 0, { 11 | image: me.loader.getImage('title3'), 12 | } 13 | ); 14 | 15 | // position image starting in upper left corner 16 | backgroundImage.anchorPoint.set(0,0); 17 | 18 | // resize image to fit viewport 19 | backgroundImage.scale(me.game.viewport.width / backgroundImage.width, me.game.viewport.height / backgroundImage.height); 20 | 21 | // add image to world container 22 | me.game.world.addChild(backgroundImage, 1); 23 | 24 | me.game.world.addChild(new (me.Renderable.extend ({ 25 | // constructor 26 | init : function () { 27 | this._super(me.Renderable, 'init', [0, 0, me.game.viewport.width, me.game.viewport.height]); 28 | }, 29 | 30 | update : function (dt) { 31 | return true; 32 | }, 33 | 34 | onDestroyEvent : function () { 35 | 36 | } 37 | })), 2); 38 | 39 | //reset level to level 1 40 | game.data.level = 1; 41 | 42 | // change to play state on press Enter or click/tap 43 | me.input.bindKey(me.input.KEY.ENTER, "enter", true); 44 | me.input.bindKey(me.input.KEY.I, "instructions", true); 45 | me.input.bindKey(me.input.KEY.NUM1, "gotolevel1", true); 46 | me.input.bindKey(me.input.KEY.NUM2, "gotolevel2", true); 47 | me.input.bindKey(me.input.KEY.NUM3, "gotolevel3", true); 48 | me.input.bindKey(me.input.KEY.NUMPAD1, "gotolevel1", true); 49 | me.input.bindKey(me.input.KEY.NUMPAD2, "gotolevel2", true); 50 | me.input.bindKey(me.input.KEY.NUMPAD3, "gotolevel3", true); 51 | me.input.bindKey(me.input.KEY.Q, "toggleQuality", true); 52 | me.input.bindPointer(me.input.pointer.LEFT, me.input.KEY.ENTER); 53 | this.handler = me.event.subscribe(me.event.KEYDOWN, function (action, keyCode, edge) { 54 | if (action === "enter") { 55 | me.state.change(me.state.LEVEL_INTRO); 56 | } 57 | else if(action === "gotolevel1"){ 58 | game.data.level = 1; 59 | me.state.change(me.state.LEVEL_INTRO); 60 | } 61 | else if(action === "gotolevel2"){ 62 | game.data.level = 2; 63 | me.state.change(me.state.LEVEL_INTRO); 64 | } 65 | else if(action === "gotolevel3"){ 66 | game.data.level = 3; 67 | me.state.change(me.state.LEVEL_INTRO); 68 | } 69 | else if(action === "instructions") { 70 | me.state.change(me.state.INSTRUCTIONS); 71 | } 72 | else if(action === "toggleQuality") { 73 | if(me.sys.fps == 60){ 74 | //Update image 75 | for(i = (me.game.world.children.length) -1; i >= 0; i--) 76 | if(me.game.world.children[i].name !== "me.debugPanel") 77 | me.game.world.removeChild(me.game.world.children[i]); 78 | var backgroundImage = new me.Sprite(0, 0, { 79 | image: me.loader.getImage('title3low'), 80 | }); 81 | backgroundImage.anchorPoint.set(0,0); 82 | backgroundImage.scale(me.game.viewport.width / backgroundImage.width, me.game.viewport.height / backgroundImage.height); 83 | me.game.world.addChild(backgroundImage, 0); 84 | 85 | //Update settings 86 | me.sys.fps = 30; 87 | me.sys.updatesPerSecond = 30; 88 | } 89 | else if(me.sys.fps == 30){ 90 | //Update image 91 | for(i = (me.game.world.children.length) -1; i >= 0; i--) 92 | if(me.game.world.children[i].name !== "me.debugPanel") 93 | me.game.world.removeChild(me.game.world.children[i]); 94 | var backgroundImage = new me.Sprite(0, 0, { 95 | image: me.loader.getImage('title3'), 96 | }); 97 | backgroundImage.anchorPoint.set(0,0); 98 | backgroundImage.scale(me.game.viewport.width / backgroundImage.width, me.game.viewport.height / backgroundImage.height); 99 | me.game.world.addChild(backgroundImage, 0); 100 | 101 | //Update settings 102 | me.sys.fps = 60; 103 | me.sys.updatesPerSecond = 60; 104 | } 105 | } 106 | }); 107 | 108 | }, 109 | onDestroyEvent: function() { 110 | me.input.unbindKey(me.input.KEY.ENTER); 111 | me.input.unbindKey(me.input.KEY.NUM1); 112 | me.input.unbindKey(me.input.KEY.NUM2); 113 | me.input.unbindKey(me.input.KEY.NUM3); 114 | me.input.unbindKey(me.input.KEY.NUMPAD1); 115 | me.input.unbindKey(me.input.KEY.NUMPAD2); 116 | me.input.unbindKey(me.input.KEY.NUMPAD3); 117 | me.input.unbindKey(me.input.KEY.Q); 118 | me.input.unbindPointer(me.input.pointer.LEFT); 119 | me.input.unbindKey(me.input.KEY.I); 120 | me.audio.fade("title_music", 1, 0, 500); 121 | setTimeout(me.audio.stopTrack("title_music"),500); 122 | me.event.unsubscribe(this.handler); 123 | 124 | } 125 | }); 126 | -------------------------------------------------------------------------------- /src/license/CCby3.0.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseakt/PixelDefense/5e40d5b2bf0cd4de3132f2f961a23301df5b0530/src/license/CCby3.0.PNG -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | const electron = require('electron'); 2 | const app = electron.app; // Module to control application life. 3 | const BrowserWindow = electron.BrowserWindow; // Module to create native browser window. 4 | 5 | const path = require('path'); 6 | const url = require('url'); 7 | 8 | // Keep a global reference of the window object, if you don't, the window will 9 | // be closed automatically when the javascript object is GCed. 10 | let mainWindow; 11 | 12 | // Quit when all windows are closed. 13 | app.on('window-all-closed', () => { 14 | if (process.platform != 'darwin') 15 | app.quit(); 16 | }); 17 | 18 | function createWindow() { 19 | // Create the browser window. 20 | mainWindow = new BrowserWindow({ width: 960, height: 660 }); 21 | 22 | // and load the index.html of the app. 23 | mainWindow.loadURL(url.format({ 24 | pathname: path.join(__dirname, 'index.html'), 25 | protocol: 'file:', 26 | slashes: true 27 | })); 28 | 29 | // Emitted when the window is closed. 30 | mainWindow.on('closed', () => { 31 | // Dereference the window object, usually you would store windows 32 | // in an array if your app supports multi windows, this is the time 33 | // when you should delete the corresponding element. 34 | mainWindow = null; 35 | }); 36 | } 37 | 38 | // This method will be called when atom-shell has done everything 39 | // initialization and ready for creating browser windows. 40 | app.on('ready', createWindow); 41 | 42 | app.on('activate', function () { 43 | // On OS X it's common to re-create a window in the app when the 44 | // dock icon is clicked and there are no other windows open. 45 | if (mainWindow === null) { 46 | createWindow(); 47 | } 48 | }); 49 | -------------------------------------------------------------------------------- /src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "melonJS Boilerplate", 3 | "name": "My melonJS Boilerplate Game", 4 | "orientation": "landscape", 5 | "developer": { 6 | "name": "melonjs", 7 | "url": "http://www.melonjs.org" 8 | }, 9 | "start_url": "./index.html", 10 | "display": "fullscreen", 11 | "icons": [{ 12 | "src": "/icons/touch-icon-iphone-60x60.png", 13 | "sizes": "60x60" 14 | },{ 15 | "src": "/icons/touch-icon-ipad-76x76.png", 16 | "sizes": "76x76" 17 | },{ 18 | "src": "/icons/touch-icon-iphone-retina-120x120", 19 | "sizes": "120x120" 20 | },{ 21 | "src": "/icons/touch-icon-marketplace-128x128", 22 | "sizes": "128x128" 23 | },{ 24 | "src": "/icons/touch-icon-ipad-retina-152x152", 25 | "sizes": "152x152" 26 | }] 27 | } 28 | -------------------------------------------------------------------------------- /src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "boilerplate", 3 | "version": "2.1.3", 4 | "main": "main.js", 5 | "devDependencies": { 6 | "grunt": "^1.0.1", 7 | "grunt-asar": "bwin/grunt-asar#update-asar", 8 | "grunt-contrib-clean": "^1.0.0", 9 | "grunt-contrib-concat": "^1.0.1", 10 | "grunt-contrib-connect": "^1.0.2", 11 | "grunt-contrib-copy": "^1.0.0", 12 | "grunt-contrib-uglify": "^2.0.0", 13 | "grunt-contrib-watch": "^1.0.0", 14 | "grunt-download-electron": "^2.1.4", 15 | "grunt-processhtml": "^0.4.1", 16 | "grunt-replace": "^1.0.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/tasks/grunt-resources.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | function task() { 3 | var path = require("path"), 4 | options = this.options({ 5 | "varname" : "game.resources" 6 | }); 7 | res = [], 8 | audio = {}; 9 | 10 | grunt.log.debug("options: " + JSON.stringify(options)); 11 | grunt.log.debug("files: " + JSON.stringify(this.files)); 12 | 13 | this.files.forEach(function (file) { 14 | file.src.forEach(function (src) { 15 | var name = path.basename(src, path.extname(src)); 16 | if ((file.type !== "audio") || (!audio.hasOwnProperty(name))) { 17 | if (file.type === "audio") { 18 | audio[name] = true; 19 | } 20 | res.push({ 21 | "name" : name, 22 | "type" : file.type, 23 | "src" : ( 24 | file.type === "audio" ? 25 | path.dirname(src) + "/" : 26 | src 27 | ) 28 | }); 29 | } 30 | }); 31 | }); 32 | 33 | grunt.log.debug(JSON.stringify(res)); 34 | 35 | grunt.file.write( 36 | options.dest, 37 | options.varname + " = " + JSON.stringify(res, null, 4) + ";" 38 | ); 39 | grunt.log.ok(options.dest) 40 | } 41 | 42 | grunt.registerMultiTask("resources", "Build melonJS resources.js", task); 43 | }; 44 | --------------------------------------------------------------------------------