├── .gitignore
├── media
├── logo.xcf
├── pixel.png
├── pixel.xcf
└── logo-lg.png
├── lib
├── weltmeister
│ ├── arrow.png
│ ├── collisiontiles-64.png
│ ├── nopache-modules
│ │ ├── weltmeister-api-router.js
│ │ ├── weltmeister.js
│ │ └── weltmeister-api.js
│ ├── entities.js
│ ├── evented-input.js
│ ├── modal-dialogs.js
│ ├── select-file-dropdown.js
│ ├── config.js
│ ├── tile-select.js
│ ├── undo.js
│ ├── edit-map.js
│ ├── weltmeister.css
│ ├── edit-entities.js
│ ├── jquery-ui-1.8.1.custom.min.js
│ └── weltmeister.js
├── game
│ ├── levels
│ │ └── splash.js
│ ├── entities
│ │ ├── logo.js
│ │ ├── flames.js
│ │ └── particle.js
│ └── main.js
└── css
│ └── style.css
├── tools
├── bake.sh
├── bake.bat
├── bake.php
└── jsmin.php
├── package.json
├── views
├── index.html
└── weltmeister.html
├── server.js
├── LICENSE.txt
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .git
2 | node_modules
3 | lib/impact
4 | npm-debug.log
5 |
--------------------------------------------------------------------------------
/media/logo.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheMaverickProgrammer/flare-impact/HEAD/media/logo.xcf
--------------------------------------------------------------------------------
/media/pixel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheMaverickProgrammer/flare-impact/HEAD/media/pixel.png
--------------------------------------------------------------------------------
/media/pixel.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheMaverickProgrammer/flare-impact/HEAD/media/pixel.xcf
--------------------------------------------------------------------------------
/media/logo-lg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheMaverickProgrammer/flare-impact/HEAD/media/logo-lg.png
--------------------------------------------------------------------------------
/lib/weltmeister/arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheMaverickProgrammer/flare-impact/HEAD/lib/weltmeister/arrow.png
--------------------------------------------------------------------------------
/lib/weltmeister/collisiontiles-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/TheMaverickProgrammer/flare-impact/HEAD/lib/weltmeister/collisiontiles-64.png
--------------------------------------------------------------------------------
/lib/game/levels/splash.js:
--------------------------------------------------------------------------------
1 | ig.module( 'game.levels.splash' )
2 | .requires( 'impact.image','game.entities.logo' )
3 | .defines(function(){
4 | LevelSplash=/*JSON[*/{
5 | "entities": [
6 | {
7 | "type": "EntityLogo",
8 | "x": 280,
9 | "y": 116
10 | }
11 | ],
12 | "layer": []
13 | }/*]JSON*/;
14 | });
--------------------------------------------------------------------------------
/tools/bake.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Path to impact.js and your game's main .js
4 | IMPACT_LIBRARY=lib/impact/impact.js
5 | GAME=lib/game/main.js
6 |
7 | # Output file
8 | OUTPUT_FILE=game.min.js
9 |
10 |
11 | # Change CWD to Impact's base dir and bake!
12 | cd ..
13 | php tools/bake.php $IMPACT_LIBRARY $GAME $OUTPUT_FILE
--------------------------------------------------------------------------------
/lib/game/entities/logo.js:
--------------------------------------------------------------------------------
1 | ig.module(
2 | 'game.entities.logo'
3 | )
4 | .requires(
5 | 'impact.entity'
6 | )
7 | .defines(function(){
8 | EntityLogo = ig.Entity.extend({
9 | size: {x: 400, y: 300},
10 |
11 | animSheet: new ig.AnimationSheet( 'media/logo-lg.png', 400, 200 ),
12 |
13 | init: function( x, y, settings ) {
14 | this.parent( x, y, settings );
15 |
16 | // Add the animations
17 | this.addAnim( 'idle', 1, [0] );
18 | }
19 | });
20 | // end EntityLogo
21 | });
22 |
--------------------------------------------------------------------------------
/tools/bake.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | :: Path to impact.js and your game's main .js
4 | SET IMPACT_LIBRARY=lib/impact/impact.js
5 | SET GAME=lib/game/main.js
6 |
7 | :: Output file
8 | SET OUTPUT_FILE=game.min.js
9 |
10 |
11 | :: Change CWD to Impact's base dir
12 | cd ../
13 |
14 |
15 | :: Bake!
16 | php tools/bake.php %IMPACT_LIBRARY% %GAME% %OUTPUT_FILE%
17 |
18 | :: If you dont have the php.exe in your PATH uncomment the
19 | :: following line and point it to your php.exe
20 |
21 | ::c:/php/php.exe tools/bake.php %IMPACT_LIBRARY% %GAME% %OUTPUT_FILE%
22 |
23 | pause
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "flare-impact",
3 | "version": "0.0.1",
4 | "description": "Nodejs impact solution complete with weltmeister",
5 | "main": "server.js",
6 | "scripts": {
7 | "start": "nodemon ./server.js"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/TheMaverickProgrammer/flare-impact"
12 | },
13 | "author": "Maverick Peppers",
14 | "license": "BSD-2-Clause",
15 | "dependencies": {
16 | "body-parser": "^1.15.2",
17 | "braces": "^1.8.5",
18 | "chalk": "^1.1.3",
19 | "express": "~4.13.4",
20 | "glob": "^7.0.5",
21 | "nodemon": "~1.9.2"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/views/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | F L A R E
5 |
6 |
7 |
8 |
9 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | var express = require('express'),
2 | bodyParser = require('body-parser'),
3 | port = 8080,
4 | app = express();
5 |
6 | app.use(bodyParser.urlencoded({
7 | extended: true,
8 | limit: '50mb'
9 | }));
10 |
11 | app.use(bodyParser.json({limit: '50mb'}));
12 |
13 | // Use node-based weltmeister api
14 | var wm = require('./lib/weltmeister/nopache-modules/weltmeister');
15 | wm({rootDir: __dirname}, app);
16 |
17 | app.set('views', __dirname + '/views');
18 |
19 | app.use('/lib', express.static(__dirname + '/lib'));
20 | app.use('/media', express.static(__dirname + '/media'));
21 |
22 | app.get('/', function(req, res){
23 | res.sendFile(__dirname + '/views/index.html');
24 | });
25 |
26 | app.get('/wm', function(req, res){
27 | res.sendFile(__dirname + '/views/weltmeister.html');
28 | });
29 |
30 | app.listen(port);
31 |
32 | console.log('app listening on port', port);
33 |
--------------------------------------------------------------------------------
/lib/css/style.css:
--------------------------------------------------------------------------------
1 | html,body {
2 |
3 | background-color: #111;
4 | color: #fff;
5 | font-family: helvetica, arial, sans-serif;
6 | margin: 0;
7 | padding: 0;
8 | font-size: 12pt;
9 | }
10 |
11 | /*
12 | Canvas is confifugred to benefit the pixel art
13 | Anti-aliasing made the pixel art blurry as the canvas scaled
14 | to fit the device
15 | */
16 | #canvas {
17 | position: absolute;
18 | left: 0;
19 | top: 0;
20 | margin: auto;
21 | image-rendering: optimizeSpeed; /* Older versions of FF */
22 | image-rendering: -moz-crisp-edges; /* FF 6.0+ */
23 | image-rendering: -webkit-optimize-contrast; /* Webkit (non standard naming) */
24 | image-rendering: -o-crisp-edges; /* OS X & Windows Opera (12.02+) */
25 | image-rendering: crisp-edges; /* Possible future browsers. */
26 | -ms-interpolation-mode: nearest-neighbor; /* IE (non standard naming) */
27 | image-rendering: pixelated; /* Chrome 41 */
28 | }
29 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) [2016] [Maverick Peppers]
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/lib/weltmeister/nopache-modules/weltmeister-api-router.js:
--------------------------------------------------------------------------------
1 | /*
2 | Author: Maverick Peppers
3 | Github: TheMaverickProgrammer
4 | Webstite: maverickpeppers.com
5 | Module: Weltmeister-api-router
6 |
7 | This module exports an object that passes weltmeister configurations
8 | to the callback objects. Then it maps the objects to api endpoints.
9 | The endpoints return JSON object results.
10 |
11 | GET Browse -- /browse
12 | GET Glob -- /glob
13 | POST Save -- /save
14 | */
15 | module.exports = function(conf) {
16 | var express = require('express');
17 | var router = express.Router();
18 |
19 | // weltmeister api specific
20 | var wm = require('./weltmeister-api')(conf);
21 | var browse = wm.Browse;
22 | var glob = wm.Glob;
23 | var save = wm.Save;
24 |
25 | // Get Browse
26 | router.get('/browse', function(req, res) {
27 | res.send(browse(req));
28 | });
29 |
30 | // GET Glob
31 | router.get('/glob', function(req, res) {
32 | res.send(glob(req));
33 | });
34 |
35 | // POST Save
36 | router.post('/save', function(req, res) {
37 | res.send(save(req));
38 | });
39 |
40 | return router;
41 | }
42 |
--------------------------------------------------------------------------------
/lib/weltmeister/nopache-modules/weltmeister.js:
--------------------------------------------------------------------------------
1 | /*
2 | Author: Maverick Peppers
3 | Github: TheMaverickProgrammer
4 | Webstite: maverickpeppers.com
5 | Module: Weltmeister
6 | Dependencies:
7 | - glob
8 | - braces
9 | - chalk
10 | - fs
11 | - express
12 |
13 | This module exports an object that accepts weltmeister configurations
14 | and the express server application object. The object is set to use a specific
15 | endpoint '/wm/api' as found in the lib/weltmeister/config.js file.
16 |
17 | Further work can be done to make the configuration between the two files
18 | seemless.
19 | */
20 | module.exports = function(opts, app) {
21 | // Create a config object on the options
22 | var conf = {
23 | // Use the current file directory as the basis for fetching objects
24 | // Or, if supplied, use another directory as specified in the options object.
25 | WM_ROOT_DIR:(typeof opts.rootDir == 'undefined')? "" + __dirname + "/" : "" + opts.rootDir + "/"
26 | }
27 |
28 | // instantiate the router
29 | var wmRouter = require('./weltmeister-api-router')(conf);
30 |
31 | // Use the router
32 | app.use('/wm/api', wmRouter);
33 | }
34 |
--------------------------------------------------------------------------------
/lib/game/entities/flames.js:
--------------------------------------------------------------------------------
1 | ig.module(
2 | 'game.entities.flames'
3 | )
4 | .requires(
5 | 'impact.entity',
6 | 'game.entities.particle'
7 | )
8 | .defines(function(){
9 | Flames = EntityParticle.extend({
10 | // longer lifetime
11 | lifetime: 3.0,
12 | fadetime: 1.5,
13 |
14 | // velocity value to be set
15 | vel: null,
16 |
17 | gravityFactor: 0,
18 |
19 | // bounce a little less
20 | bounciness: 0.6,
21 |
22 | // add animation sheet of sprites
23 | animSheet: new ig.AnimationSheet('media/pixel.png',1,1),
24 |
25 | init: function( x, y, settings ){
26 | // add ember animation
27 | this.addAnim( 'idle', 0.3, [254, 127, 0] );
28 |
29 | // update random velocity to create starburst effect
30 | this.vel = { x: (Math.random() < 0.5 ? -1 : 1)*Math.random()*100,
31 | y: (Math.random() < 0.5 ? -1 : 1)*Math.random()*100 };
32 |
33 | // send to parent
34 | this.parent( x, y, settings );
35 | },
36 |
37 | update: function() {
38 | this.vel.y -= 10; // particles move up
39 | this.pos.x += Math.sin((this.pos.y*(22/7))/100); // make it swirl upwards
40 |
41 | this.parent();
42 | }
43 | });
44 | });
45 |
--------------------------------------------------------------------------------
/lib/game/entities/particle.js:
--------------------------------------------------------------------------------
1 | ig.module(
2 | 'game.entities.particle'
3 | )
4 | .requires(
5 | 'impact.entity'
6 | )
7 | .defines(function(){
8 | EntityParticle = ig.Entity.extend({
9 | // single pixel sprites
10 | size: { x:1, y:1 },
11 | offset: { x:0, y:0 },
12 |
13 | // particle will collide but not effect other entities
14 | type: ig.Entity.TYPE.NONE,
15 | checkAgainst: ig.Entity.TYPE.NONE,
16 | collides: ig.Entity.COLLIDES.LITE,
17 |
18 | // default particle lifetime & fadetime
19 | lifetime: 5,
20 | fadetime: 1,
21 |
22 | // particles will bounce off other entities when it collides
23 | minBounceVelocity: 0,
24 | bounciness: 1.0,
25 | friction: { x:0, y:0 },
26 |
27 | init: function( x, y, settings ){
28 | this.parent( x, y, settings );
29 |
30 | // take velocity and add randomness to vel
31 | var vx = this.vel.x; var vy = this.vel.y;
32 | this.vel.x = (Math.random()*2 - 1)*vx;
33 | this.vel.y = (Math.random()*2 - 1)*vy;
34 |
35 | // creates a flicker effect
36 | this.currentAnim.gotoRandomFrame();
37 |
38 | // init timer for fadetime
39 | this.idleTimer = new ig.Timer();
40 | },
41 |
42 | update: function(){
43 | // check if particle has existed past lifetime
44 | // if so, remove particle
45 | if(this.idleTimer.delta() > this.lifetime){
46 | this.kill();
47 | return;
48 | }
49 |
50 | // fade the particle effect using the aplha blend
51 | this.currentAnim.alpha = this.idleTimer.delta().map( this.lifetime - this.fadetime, this.lifetime, 1, 0 );
52 | this.parent();
53 | }
54 |
55 | });
56 | });
57 |
--------------------------------------------------------------------------------
/lib/weltmeister/entities.js:
--------------------------------------------------------------------------------
1 | ig.module(
2 | 'weltmeister.entityLoader'
3 | )
4 | .requires(
5 | 'weltmeister.config'
6 | )
7 | .defines(function(){ "use strict";
8 |
9 | // Load the list of entity files via AJAX PHP glob
10 | var path = wm.config.api.glob + '?',
11 | globs = typeof wm.config.project.entityFiles == 'string' ?
12 | [wm.config.project.entityFiles] :
13 | wm.config.project.entityFiles;
14 |
15 | for (var i = 0; i < globs.length; i++) {
16 | path += 'glob[]=' + encodeURIComponent(globs[i]) + '&';
17 | }
18 |
19 | path += 'nocache=' + Math.random();
20 |
21 | var req = $.ajax({
22 | url: path,
23 | method: 'get',
24 | dataType: 'json',
25 |
26 | // MUST load synchronous, as the engine would otherwise determine that it
27 | // can't resolve dependencies to weltmeister.entities when there are
28 | // no more files to load and weltmeister.entities is still not defined
29 | // because the ajax request hasn't finished yet.
30 | // FIXME FFS!
31 | async: false,
32 | success: function(files) {
33 |
34 | // File names to Module names
35 | var moduleNames = [];
36 | var modules = {};
37 | for( var i = 0; i < files.length; i++ ) {
38 | var name = files[i]
39 | .replace(new RegExp("^"+ig.lib+"|\\.js$", "g"), '')
40 | .replace(/\//g, '.');
41 | moduleNames.push( name );
42 | modules[name] = files[i];
43 | }
44 |
45 | // Define a Module that requires all entity Modules
46 | ig.module('weltmeister.entities')
47 | .requires.apply(ig, moduleNames)
48 | .defines(function(){ wm.entityModules = modules; });
49 | },
50 | error: function( xhr, status, error ){
51 | throw(
52 | "Failed to load entity list via glob.php: " + error + "\n" +
53 | xhr.responseText
54 | );
55 | }
56 | });
57 |
58 | });
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | updated 11/18/2017
3 |
4 | # README v0.0.2
5 | > A nopache (apache-free) nodejs server for [Impactjs](http://impactjs.com) complete with weltmeister support.
6 | Part of the F L A R E development suite.
7 |
8 |
9 |
10 | # Features
11 | - **NEW** BoomSheets sprite mapping and management tool
12 | - Easy installation
13 | - 100% nodejs
14 | - Scripts watch for any changes in project and relaunch server immediately
15 | - All server-side weltmeister exceptions are caught and printed in the console
16 | - Server body handles request up to **50 mb** of level data from the editor!
17 | - FREE
18 |
19 | ## Usage
20 | - Download and install [node](http://nodejs.org)
21 | - Close all ports running on ```8080```
22 | - Clone/fork/download this git project
23 | - ```npm install --save``` to install project dependencies
24 | - drop your purchased ```/impact``` source folder to ```flare-impact/lib```
25 | - ```npm start``` to launch server
26 | - **TO RUN GAME:** Navigate browser to ```localhost:8080/```
27 | - You should see the logo with flares swirling upward
28 | - **TO LAUNCH WELTMEISTER:** Navigate browser to ```localhost:8080/wm```
29 |
30 | ## Follow
31 | - [First announcement](http://impactjs.com/forums/code/f-l-a-r-e-development-suite-for-impact/page/1) for public use. Includes node weltmeister only.
32 | - [First release of BoomSheets](http://impactjs.com/forums/code/boomsheets-sprite-mapping-tool-for-impactjs) Includes Mac and Linux 64 binaries.
33 |
34 | ## Contribute
35 | Contributions are always welcome! Discovered a bug? Have an idea? File a [new issue](https://github.com/TheMaverickProgrammer/flare-impact/issues) on github.
36 |
37 | ## License
38 |
39 | 
40 |
--------------------------------------------------------------------------------
/lib/weltmeister/evented-input.js:
--------------------------------------------------------------------------------
1 | ig.module(
2 | 'weltmeister.evented-input'
3 | )
4 | .requires(
5 | 'impact.input'
6 | )
7 | .defines(function(){ "use strict";
8 |
9 | wm.EventedInput = ig.Input.extend({
10 | mousemoveCallback: null,
11 | keyupCallback: null,
12 | keydownCallback: null,
13 |
14 | delayedKeyup: {push:function(){},length: 0},
15 |
16 |
17 | keydown: function( event ) {
18 | var tag = event.target.tagName;
19 | if( tag == 'INPUT' || tag == 'TEXTAREA' ) { return; }
20 |
21 | var code = event.type == 'keydown'
22 | ? event.keyCode
23 | : (event.button == 2 ? ig.KEY.MOUSE2 : ig.KEY.MOUSE1);
24 | var action = this.bindings[code];
25 | if( action ) {
26 | if( !this.actions[action] ) {
27 | this.actions[action] = true;
28 | if( this.keydownCallback ) {
29 | this.keydownCallback( action );
30 | }
31 | }
32 | event.stopPropagation();
33 | event.preventDefault();
34 | }
35 | },
36 |
37 |
38 | keyup: function( event ) {
39 | var tag = event.target.tagName;
40 | if( tag == 'INPUT' || tag == 'TEXTAREA' ) { return; }
41 |
42 | var code = event.type == 'keyup'
43 | ? event.keyCode
44 | : (event.button == 2 ? ig.KEY.MOUSE2 : ig.KEY.MOUSE1);
45 | var action = this.bindings[code];
46 | if( action ) {
47 | this.actions[action] = false;
48 | if( this.keyupCallback ) {
49 | this.keyupCallback( action );
50 | }
51 | event.stopPropagation();
52 | event.preventDefault();
53 | }
54 | },
55 |
56 |
57 | mousewheel: function( event ) {
58 | var delta = event.wheelDelta ? event.wheelDelta : (event.detail * -1);
59 | var code = delta > 0 ? ig.KEY.MWHEEL_UP : ig.KEY.MWHEEL_DOWN;
60 | var action = this.bindings[code];
61 | if( action ) {
62 | if( this.keyupCallback ) {
63 | this.keyupCallback( action );
64 | }
65 | event.stopPropagation();
66 | event.preventDefault();
67 | }
68 | },
69 |
70 |
71 | mousemove: function( event ) {
72 | this.parent( event );
73 | if( this.mousemoveCallback ) {
74 | this.mousemoveCallback();
75 | }
76 | }
77 | });
78 |
79 | });
--------------------------------------------------------------------------------
/lib/game/main.js:
--------------------------------------------------------------------------------
1 | ig.module(
2 | 'game.main'
3 | )
4 | .requires(
5 | 'impact.game',
6 | 'impact.font',
7 | 'impact.debug.debug',
8 |
9 | // game specific dependencies
10 | 'game.entities.flames',
11 | 'game.levels.splash'
12 | )
13 | .defines(function(){
14 | MyGame = ig.Game.extend({
15 |
16 | // create a timer for lares
17 | fireTimer: new ig.Timer(),
18 |
19 | init: function() {
20 | this.loadLevel(LevelSplash);
21 | this.fireTimer.set(1);
22 | },
23 |
24 | update: function() {
25 | this.parent();
26 |
27 | // Use timer to spawn fireworks every second
28 | if( this.fireTimer.delta() > 0 ){
29 | for (var i = 0; i <= 2; i++){
30 | randPos = {x: Math.random()*150, y: Math.random()*50};
31 | randPos.x += (640-380);
32 | randPos.y += (480-210);
33 |
34 | ig.game.spawnEntity( Flames, randPos.x, randPos.y );
35 | }
36 | this.fireTimer.reset();
37 | }
38 | },
39 |
40 | draw: function() {
41 | // Draw all entities and backgroundMaps
42 | this.parent();
43 | }
44 | });
45 |
46 | var scale = (window.innerWidth < 640) ? 2 : 0.5;
47 |
48 |
49 | // We want to run the game in "fullscreen", so let's use the window's size
50 | // directly as the canvas' style size.
51 | var canvas = document.getElementById('canvas');
52 | canvas.style.width = window.innerWidth + 'px';
53 | canvas.style.height = window.innerHeight + 'px';
54 |
55 |
56 | // Listen to the window's 'resize' event and set the canvas' size each time
57 | // it changes.
58 | window.addEventListener('resize', function(){
59 | // If the game hasn't started yet, there's nothing to do here
60 | if( !ig.system ) { return; }
61 |
62 | // Resize the canvas style and tell Impact to resize the canvas itself;
63 | canvas.style.width = window.innerWidth + 'px';
64 | canvas.style.height = window.innerHeight + 'px';
65 | ig.system.resize( window.innerWidth * scale, window.innerHeight * scale );
66 |
67 | // Also repositon the touch buttons, if we have any
68 | if( window.myTouchButtons ) {
69 | window.myTouchButtons.align();
70 | }
71 | }, false);
72 |
73 |
74 | // Finally, start the game into MyGame and use the ImpactSplashLoader plugin
75 | // as our loading screen
76 | var width = window.innerWidth * scale,
77 | height = window.innerHeight * scale;
78 |
79 | ig.main( '#canvas', MyGame, 60, width, height, 1, ig.ImpactSplashLoader );
80 |
81 | });
82 |
--------------------------------------------------------------------------------
/lib/weltmeister/modal-dialogs.js:
--------------------------------------------------------------------------------
1 | ig.module(
2 | 'weltmeister.modal-dialogs'
3 | )
4 | .requires(
5 | 'weltmeister.select-file-dropdown'
6 | )
7 | .defines(function(){ "use strict";
8 |
9 | wm.ModalDialog = ig.Class.extend({
10 | onOk: null,
11 | onCancel: null,
12 |
13 | text: '',
14 | okText: '',
15 | cancelText: '',
16 |
17 | background: null,
18 | dialogBox: null,
19 | buttonDiv: null,
20 |
21 | init: function( text, okText, cancelText ) {
22 | this.text = text;
23 | this.okText = okText || 'OK';
24 | this.cancelText = cancelText || 'Cancel';
25 |
26 | this.background = $('', {'class':'modalDialogBackground'});
27 | this.dialogBox = $('', {'class':'modalDialogBox'});
28 | this.background.append( this.dialogBox );
29 | $('body').append( this.background );
30 |
31 | this.initDialog( text );
32 | },
33 |
34 |
35 | initDialog: function() {
36 | this.buttonDiv = $('', {'class': 'modalDialogButtons'} );
37 | var okButton = $('', {'type': 'button', 'class':'button', 'value': this.okText});
38 | var cancelButton = $('', {'type': 'button', 'class':'button', 'value': this.cancelText});
39 |
40 | okButton.bind( 'click', this.clickOk.bind(this) );
41 | cancelButton.bind( 'click', this.clickCancel.bind(this) );
42 |
43 | this.buttonDiv.append( okButton ).append( cancelButton );
44 |
45 | this.dialogBox.html('' + this.text + '
' );
46 | this.dialogBox.append( this.buttonDiv );
47 | },
48 |
49 |
50 | clickOk: function() {
51 | if( this.onOk ) { this.onOk(this); }
52 | this.close();
53 | },
54 |
55 |
56 | clickCancel: function() {
57 | if( this.onCancel ) { this.onCancel(this); }
58 | this.close();
59 | },
60 |
61 |
62 | open: function() {
63 | this.background.fadeIn(100);
64 | },
65 |
66 |
67 | close: function() {
68 | this.background.fadeOut(100);
69 | }
70 | });
71 |
72 |
73 |
74 | wm.ModalDialogPathSelect = wm.ModalDialog.extend({
75 | pathDropdown: null,
76 | pathInput: null,
77 | fileType: '',
78 |
79 | init: function( text, okText, type ) {
80 | this.fileType = type || '';
81 | this.parent( text, (okText || 'Select') );
82 | },
83 |
84 |
85 | setPath: function( path ) {
86 | var dir = path.replace(/\/[^\/]*$/, '');
87 | this.pathInput.val( path );
88 | this.pathDropdown.loadDir( dir );
89 | },
90 |
91 |
92 | initDialog: function() {
93 | this.parent();
94 | this.pathInput = $('', {'type': 'text', 'class': 'modalDialogPath'} );
95 | this.buttonDiv.before( this.pathInput );
96 | this.pathDropdown = new wm.SelectFileDropdown( this.pathInput, wm.config.api.browse, this.fileType );
97 | },
98 |
99 |
100 | clickOk: function() {
101 | if( this.onOk ) {
102 | this.onOk(this, this.pathInput.val());
103 | }
104 | this.close();
105 | }
106 | });
107 |
108 | });
--------------------------------------------------------------------------------
/lib/weltmeister/select-file-dropdown.js:
--------------------------------------------------------------------------------
1 | ig.module(
2 | 'weltmeister.select-file-dropdown'
3 | )
4 | .defines(function(){ "use strict";
5 |
6 | wm.SelectFileDropdown = ig.Class.extend({
7 | input: null,
8 | boundShow: null,
9 | div: null,
10 | filelistPHP: '',
11 | filetype: '',
12 |
13 | init: function( elementId, filelistPHP, filetype ) {
14 | this.filetype = filetype || '';
15 | this.filelistPHP = filelistPHP;
16 | this.input = $(elementId);
17 | this.boundHide = this.hide.bind(this);
18 | this.input.bind('focus', this.show.bind(this) );
19 |
20 | this.div = $('', {'class':'selectFileDialog'});
21 | this.input.after( this.div );
22 | this.div.bind('mousedown', this.noHide.bind(this) );
23 |
24 | this.loadDir( '' );
25 | },
26 |
27 |
28 | loadDir: function( dir ) {
29 | var path = this.filelistPHP + '?dir=' + encodeURIComponent( dir || '' ) + '&type=' + this.filetype;
30 | var req = $.ajax({
31 | url:path,
32 | dataType: 'json',
33 | async: false,
34 | success:this.showFiles.bind(this)
35 | });
36 | },
37 |
38 |
39 | selectDir: function( event ) {
40 | this.loadDir( $(event.target).attr('href') );
41 | return false;
42 | },
43 |
44 |
45 | selectFile: function( event ) {
46 | this.input.val( $(event.target).attr('href') );
47 | this.input.blur();
48 | this.hide();
49 | return false;
50 | },
51 |
52 |
53 | showFiles: function( data ) {
54 | this.div.empty();
55 | if( data.parent !== false ) {
56 | var parentDir = $('', {'class':'dir', href:data.parent, html: '…parent directory'});
57 | parentDir.bind( 'click', this.selectDir.bind(this) );
58 | this.div.append( parentDir );
59 | }
60 | for( var i = 0; i < data.dirs.length; i++ ) {
61 | var name = data.dirs[i].match(/[^\/]*$/)[0] + '/';
62 | var dir = $('', {'class':'dir', href:data.dirs[i], html: name, title: name});
63 | dir.bind( 'click', this.selectDir.bind(this) );
64 | this.div.append( dir );
65 | }
66 | for( var i = 0; i < data.files.length; i++ ) {
67 | var name = data.files[i].match(/[^\/]*$/)[0];
68 | var file = $('', {'class':'file', href:data.files[i], html: name, title: name});
69 | file.bind( 'click', this.selectFile.bind(this) );
70 | this.div.append( file );
71 | }
72 | },
73 |
74 |
75 | noHide: function(event) {
76 | event.stopPropagation();
77 | },
78 |
79 |
80 | show: function( event ) {
81 | var inputPos = this.input.position();//this.input.getPosition(this.input.getOffsetParent());
82 | var inputHeight = parseInt(this.input.innerHeight()) + parseInt(this.input.css('margin-top'));
83 | var inputWidth = this.input.innerWidth();
84 | $(document).bind( 'mousedown', this.boundHide );
85 | this.div.css({
86 | 'top': inputPos.top + inputHeight + 1,
87 | 'left': inputPos.left,
88 | 'width': inputWidth
89 | }).slideDown(100);
90 | },
91 |
92 |
93 | hide: function() {
94 | $(document).unbind( 'mousedown', this.boundHide );
95 | this.div.slideUp(100);
96 | }
97 | });
98 |
99 | });
--------------------------------------------------------------------------------
/views/weltmeister.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Weltmeister
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
93 |
94 |
1x
95 |
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/tools/bake.php:
--------------------------------------------------------------------------------
1 | \n";
4 | echo "e.g. bake.php lib/impact/impact.js lib/game/game.js mygame-baked.js\n";
5 | die;
6 | }
7 |
8 | $inFiles = array_slice( $argv, 1, -1 );
9 | $outFile = $argv[ count($argv)-1 ];
10 |
11 | $baker = new Baker( Baker::MINIFIED );
12 | $baker->bake( $inFiles, $outFile );
13 |
14 |
15 | class Baker {
16 | const PLAIN = 0;
17 | const MINIFIED = 1;
18 | const GZIPPED = 2;
19 |
20 | protected $base = 'lib/';
21 | protected $format = 0;
22 | protected $loaded = array();
23 | protected $currentInput = 'Command Line';
24 | protected $fileCount = 0, $bytesIn = 0, $bytesOut = 0;
25 |
26 | public function __construct( $format = 0 ) {
27 | $this->format = $format;
28 | if( $this->format & self::MINIFIED ) {
29 | require_once( 'jsmin.php' );
30 | }
31 | }
32 |
33 |
34 | public function bake( $inFiles, $outFile ) {
35 | $this->fileCount = 0;
36 | $this->bytesIn = 0;
37 | $out = "/*! Built with IMPACT - impactjs.com */\n\n";
38 |
39 | foreach( $inFiles as $f ) {
40 | $out .= $this->load( $f );
41 | }
42 |
43 | $bytesOut = strlen($out);
44 | $bytesOutZipped = 0;
45 |
46 | echo "writing $outFile\n";
47 | @file_put_contents( $outFile, $out ) or
48 | die("ERROR: Couldn't write to $outFile\n");
49 |
50 | if( $this->format & self::GZIPPED ) {
51 | $gzFile = "$outFile.gz";
52 | echo "writing $gzFile\n";
53 | $fh = gzopen( $gzFile, 'w9' ) or
54 | die("ERROR: Couldn't write to $gzFile\n");
55 |
56 | gzwrite( $fh, $out );
57 | gzclose( $fh );
58 | $bytesOutZipped = filesize( $gzFile );
59 | }
60 |
61 |
62 | echo
63 | "\nbaked {$this->fileCount} files: ".
64 | round($this->bytesIn/1024,1)."kb -> ".round($bytesOut/1024,1)."kb" .
65 | ( $this->format & self::GZIPPED
66 | ? " (".round($bytesOutZipped/1024,1)."kb gzipped)\n"
67 | : "\n"
68 | );
69 | }
70 |
71 |
72 | protected function load( $path ) {
73 | if( isset($this->loaded[$path]) ) {
74 | return '';
75 | }
76 |
77 | if( !file_exists($path) ) {
78 | die("ERROR: Couldn't load $path required from {$this->currentInput}\n");
79 | }
80 |
81 | echo "loading $path \n";
82 | $this->loaded[$path] = true;
83 | $this->currentInput = $path;
84 |
85 | $code = file_get_contents( $path );
86 | $this->bytesIn += strlen($code);
87 | $this->fileCount++;
88 | if( $this->format & self::MINIFIED ) {
89 | $code = trim(JSMin::minify($code));
90 | }
91 |
92 |
93 | // Naively probe the file for 'ig.module().requires().defines()' code;
94 | // the 'requries()' part will be handled by the regexp callback
95 | $this->definesModule = false;
96 | $code = preg_replace_callback(
97 | '/ig\s*
98 | \.\s*module\s*\((.*?)\)\s*
99 | (\.\s*requires\s*\((.*?)\)\s*)?
100 | \.\s*defines\s*\(
101 | /smx',
102 | array($this,'loadCallback'),
103 | $code
104 | );
105 |
106 | // All files should define a module; maybe we just missed it? Print a
107 | // friendly reminder :)
108 | if( !$this->definesModule ) {
109 | echo "WARNING: file $path seems to define no module!\n";
110 | }
111 |
112 | return $code;
113 | }
114 |
115 |
116 | protected function loadCallback( $matches ) {
117 | $currentInput = $this->currentInput;
118 | $this->definesModule = true;
119 |
120 | $moduleName = $matches[1];
121 | $requiredFiles = isset($matches[3]) ? $matches[3] : '';
122 | $requiredCode = '';
123 |
124 | if( $requiredFiles ) {
125 | // Explode the module names and map them to file names. Ignore the
126 | // dom.ready module if present
127 | $moduleFiles = array_diff(
128 | explode(
129 | ',',
130 | preg_replace(
131 | '/[\s\'"]|\/\/.*|\/\*.*\*\//', // strip quotes and spaces
132 | '',
133 | str_replace('.', '/', $requiredFiles ) // . to /
134 | )
135 | ),
136 | array('dom/ready')
137 | );
138 |
139 | foreach( $moduleFiles as $f ) {
140 | $requiredCode .= $this->load( $this->base . $f.'.js' );
141 | }
142 | }
143 |
144 | return
145 | $requiredCode .
146 | "\n\n// $currentInput\n" .
147 | 'ig.baked=true;' .
148 | 'ig.module('.$moduleName.')' .
149 | ( $requiredFiles
150 | ? '.requires('.$requiredFiles.')'
151 | : ''
152 | ) .
153 | '.defines(';
154 | }
155 | }
156 |
157 | ?>
--------------------------------------------------------------------------------
/lib/weltmeister/config.js:
--------------------------------------------------------------------------------
1 | ig.module(
2 | 'weltmeister.config'
3 | )
4 | .defines(function(){ "use strict";
5 |
6 | wm.config = {
7 |
8 | project: {
9 | // The prefix path of your game's source code. You only have to change
10 | // this if you use the 'ImpactPrefix' in your dev environment.
11 | 'modulePath': 'lib/',
12 |
13 | // This "glob" tells Weltmeister where to load the entity files
14 | // from. If you want to load entities from several directories,
15 | // you can specify an array here. E.g.:
16 | 'entityFiles': ['lib/game/entities/*.js'],
17 |
18 | // The default path for the level file selection box
19 | 'levelPath': 'lib/game/levels/',
20 |
21 | // Whether to save levels as plain JSON or wrapped in a module. If
22 | // you want to load levels asynchronously via AJAX, saving as plain
23 | // JSON can be helpful.
24 | 'outputFormat': 'module', // 'module' or 'json'
25 |
26 | // Whether to pretty print the JSON data in level files. If you have
27 | // any issues with your levels, it's usually a good idea to turn this
28 | // on and look at the saved level files with a text editor.
29 | 'prettyPrint': true
30 | },
31 |
32 |
33 | // Plugins for Weltmeister: an array of module names to load
34 | plugins: [],
35 |
36 |
37 | // Default settings when creating new layers in Weltmeister. Change these
38 | // as you like
39 | 'layerDefaults': {
40 | 'width': 30,
41 | 'height': 20,
42 | 'tilesize': 8
43 | },
44 |
45 | // Whether to ask before closing Weltmeister when there are unsaved changes
46 | 'askBeforeClose': true,
47 |
48 | // Whether to attempt to load the last opened level on startup
49 | 'loadLastLevel': true,
50 |
51 | // Size of the "snap" grid when moving entities
52 | 'entityGrid': 4,
53 |
54 | // Number of undo levels. You may want to increase this if you use 'undo'
55 | // frequently.
56 | 'undoLevels': 50,
57 |
58 | // Mouse and Key bindings in Weltmeister. Some function are bound to
59 | // several keys. See the documentation of ig.Input for a list of available
60 | // key names.
61 | 'binds': {
62 | 'MOUSE1': 'draw',
63 | 'MOUSE2': 'drag',
64 | 'SHIFT': 'select',
65 | 'CTRL': 'drag',
66 | 'SPACE': 'menu',
67 | 'DELETE': 'delete',
68 | 'BACKSPACE': 'delete',
69 | 'G': 'grid',
70 | 'C': 'clone',
71 | 'Z': 'undo',
72 | 'Y': 'redo',
73 | 'MWHEEL_UP': 'zoomin',
74 | 'PLUS': 'zoomin',
75 | 'MWHEEL_DOWN': 'zoomout',
76 | 'MINUS': 'zoomout'
77 | },
78 |
79 | // Whether to enable unidirectional scrolling for touchpads; this
80 | // automatically unbinds the MWHEEL_UP and MWHEEL_DOWN actions.
81 | 'touchScroll': false,
82 |
83 | // View settings. You can change the default Zoom level and whether
84 | // to show the grid on startup here.
85 | 'view': {
86 | 'zoom': 1,
87 | 'zoomMax': 4,
88 | 'zoomMin': 0.125,
89 | 'grid': false
90 | },
91 |
92 | // Font face and size for entity labels and the grid coordinates
93 | 'labels': {
94 | 'draw': true,
95 | 'step': 32,
96 | 'font': '10px Bitstream Vera Sans Mono, Monaco, sans-serif'
97 | },
98 |
99 | // Colors to use for the background, selection boxes, text and the grid
100 | 'colors': {
101 | 'clear': '#000000', // Background Color
102 | 'highlight': '#ceff36', // Currently selected tile or entity
103 | 'primary': '#ffffff', // Labels and layer bounds
104 | 'secondary': '#555555', // Grid and tile selection bounds
105 | 'selection': '#ff9933' // Selection cursor box on tile maps
106 | },
107 |
108 | // Settings for the Collision tiles. You shouldn't need to change these.
109 | // The tilesize only specifies the size in the image - resizing to final
110 | // size for each layer happens in Weltmeister.
111 | 'collisionTiles': {
112 | 'path': 'lib/weltmeister/collisiontiles-64.png',
113 | 'tilesize': 64
114 | },
115 |
116 | // API paths for saving levels and browsing directories. If you use a
117 | // different backend (i.e. not the official PHP backend), you may have
118 | // to change these.
119 |
120 | /** DEPRICATED **/
121 | /* 'api': {
122 | 'save': 'lib/weltmeister/api/save.php',
123 | 'browse': 'lib/weltmeister/api/browse.php',
124 | 'glob': 'lib/weltmeister/api/glob.php'
125 | } */
126 |
127 | // use flashly new nopache-impact weltmeister api
128 | 'api': {
129 | 'save': '/wm/api/save',
130 | 'browse': '/wm/api/browse',
131 | 'glob': '/wm/api/glob'
132 | }
133 | };
134 |
135 | });
136 |
--------------------------------------------------------------------------------
/lib/weltmeister/tile-select.js:
--------------------------------------------------------------------------------
1 | ig.module(
2 | 'weltmeister.tile-select'
3 | )
4 | .defines(function(){ "use strict";
5 |
6 | wm.TileSelect = ig.Class.extend({
7 |
8 | pos: {x:0, y:0},
9 |
10 | layer: null,
11 | selectionBegin: null,
12 |
13 | init: function( layer ) {
14 | this.layer = layer;
15 | },
16 |
17 |
18 | getCurrentTile: function() {
19 | var b = this.layer.brush;
20 | if( b.length == 1 && b[0].length == 1 ) {
21 | return b[0][0] - 1;
22 | }
23 | else {
24 | return -1;
25 | }
26 | },
27 |
28 |
29 | setPosition: function( x, y ) {
30 | this.selectionBegin = null;
31 | var tile = this.getCurrentTile();
32 | this.pos.x =
33 | Math.floor( x / this.layer.tilesize ) * this.layer.tilesize
34 | - Math.floor( tile * this.layer.tilesize ) % this.layer.tiles.width;
35 |
36 | this.pos.y =
37 | Math.floor( y / this.layer.tilesize ) * this.layer.tilesize
38 | - Math.floor( tile * this.layer.tilesize / this.layer.tiles.width ) * this.layer.tilesize
39 | - (tile == -1 ? this.layer.tilesize : 0);
40 |
41 | this.pos.x = this.pos.x.limit( 0, ig.system.width - this.layer.tiles.width - (ig.system.width % this.layer.tilesize) );
42 | this.pos.y = this.pos.y.limit( 0, ig.system.height - this.layer.tiles.height - (ig.system.height % this.layer.tilesize) );
43 | },
44 |
45 |
46 | beginSelecting: function( x, y ) {
47 | this.selectionBegin = {x:x, y:y};
48 | },
49 |
50 |
51 | endSelecting: function( x, y ) {
52 | var r = this.getSelectionRect( x, y);
53 |
54 | var mw = Math.floor( this.layer.tiles.width / this.layer.tilesize );
55 | var mh = Math.floor( this.layer.tiles.height / this.layer.tilesize );
56 |
57 | var brush = [];
58 | for( var ty = r.y; ty < r.y+r.h; ty++ ) {
59 | var row = [];
60 | for( var tx = r.x; tx < r.x+r.w; tx++ ) {
61 | if( tx < 0 || ty < 0 || tx >= mw || ty >= mh) {
62 | row.push( 0 );
63 | }
64 | else {
65 | row.push( ty * Math.floor(this.layer.tiles.width / this.layer.tilesize) + tx + 1 );
66 | }
67 | }
68 | brush.push( row );
69 | }
70 | this.selectionBegin = null;
71 | return brush;
72 | },
73 |
74 |
75 | getSelectionRect: function( x, y ) {
76 | var sx = this.selectionBegin ? this.selectionBegin.x : x,
77 | sy = this.selectionBegin ? this.selectionBegin.y : y;
78 |
79 | var
80 | txb = Math.floor( (sx - this.pos.x) / this.layer.tilesize ),
81 | tyb = Math.floor( (sy - this.pos.y) / this.layer.tilesize ),
82 | txe = Math.floor( (x - this.pos.x) / this.layer.tilesize ),
83 | tye = Math.floor( (y - this.pos.y) / this.layer.tilesize );
84 |
85 | return {
86 | x: Math.min( txb, txe ),
87 | y: Math.min( tyb, tye ),
88 | w: Math.abs( txb - txe) + 1,
89 | h: Math.abs( tyb - tye) + 1
90 | }
91 | },
92 |
93 |
94 | draw: function() {
95 | ig.system.clear( "rgba(0,0,0,0.8)" );
96 | if( !this.layer.tiles.loaded ) {
97 | return;
98 | }
99 |
100 | // Tileset
101 | ig.system.context.lineWidth = 1;
102 | ig.system.context.strokeStyle = wm.config.colors.secondary;
103 | ig.system.context.fillStyle = wm.config.colors.clear;
104 | ig.system.context.fillRect(
105 | this.pos.x * ig.system.scale,
106 | this.pos.y * ig.system.scale,
107 | this.layer.tiles.width * ig.system.scale,
108 | this.layer.tiles.height * ig.system.scale
109 | );
110 | ig.system.context.strokeRect(
111 | this.pos.x * ig.system.scale - 0.5,
112 | this.pos.y * ig.system.scale - 0.5,
113 | this.layer.tiles.width * ig.system.scale + 1,
114 | this.layer.tiles.height * ig.system.scale + 1
115 | );
116 |
117 | this.layer.tiles.draw( this.pos.x, this.pos.y );
118 |
119 | // Selected Tile
120 | var tile = this.getCurrentTile();
121 | var tx = Math.floor( tile * this.layer.tilesize ) % this.layer.tiles.width + this.pos.x;
122 | var ty =
123 | Math.floor( tile * this.layer.tilesize / this.layer.tiles.width )
124 | * this.layer.tilesize + this.pos.y
125 | + (tile == -1 ? this.layer.tilesize : 0);
126 |
127 | ig.system.context.lineWidth = 1;
128 | ig.system.context.strokeStyle = wm.config.colors.highlight;
129 | ig.system.context.strokeRect(
130 | tx * ig.system.scale - 0.5,
131 | ty * ig.system.scale - 0.5,
132 | this.layer.tilesize * ig.system.scale + 1,
133 | this.layer.tilesize * ig.system.scale + 1
134 | );
135 | },
136 |
137 |
138 | drawCursor: function( x, y ) {
139 | var cx = Math.floor( x / this.layer.tilesize ) * this.layer.tilesize;
140 | var cy = Math.floor( y / this.layer.tilesize ) * this.layer.tilesize;
141 |
142 | var r = this.getSelectionRect( x, y);
143 |
144 | ig.system.context.lineWidth = 1;
145 | ig.system.context.strokeStyle = wm.config.colors.selection;
146 | ig.system.context.strokeRect(
147 | (r.x * this.layer.tilesize + this.pos.x) * ig.system.scale - 0.5,
148 | (r.y * this.layer.tilesize + this.pos.y) * ig.system.scale - 0.5,
149 | r.w * this.layer.tilesize * ig.system.scale + 1,
150 | r.h * this.layer.tilesize * ig.system.scale + 1
151 | );
152 | }
153 | });
154 |
155 | });
--------------------------------------------------------------------------------
/lib/weltmeister/nopache-modules/weltmeister-api.js:
--------------------------------------------------------------------------------
1 | /*
2 | Author: Maverick Peppers
3 | Github: TheMaverickProgrammer
4 | Webstite: maverickpeppers.com
5 | Module: Weltmeister-api
6 |
7 | This module exports an object that contain the functions used at the endpoints
8 | at localhost/wm/api/browse, localhost/wm/api/glob, localhost/wm/api/save
9 | which are configured by the Welmeister-api-router module.
10 | */
11 | module.exports = function(conf) {
12 |
13 | // Make available for all functions
14 | var public = {conf: conf};
15 |
16 | // dependencies
17 | var glob = require('glob');
18 | var braces = require('braces');
19 | var fs = require('fs');
20 | var chalk = require('chalk');
21 |
22 | // aux function
23 | // references https://github.com/kvz/locutus/blob/master/src/php/var/empty.js
24 | function empty(mixedVar) {
25 | var undef
26 | var key
27 | var i
28 | var len
29 | var emptyValues = [undef, null, false, 0, '', '0']
30 |
31 | for (i = 0, len = emptyValues.length; i < len; i++) {
32 | if (mixedVar === emptyValues[i]) {
33 | return true
34 | }
35 | }
36 |
37 | if (typeof mixedVar === 'object') {
38 | for (key in mixedVar) {
39 | if (mixedVar.hasOwnProperty(key)) {
40 | return false
41 | }
42 | }
43 | return true
44 | }
45 |
46 | return false
47 | }
48 |
49 | /*
50 | Browse fetches all files within a directory and is filtered by type.
51 | The type is read from req.query.dir and can have one of the following values:
52 | 1 - images (.png, .gif, .jpg, .jpeg)
53 | 2 - scripts (.js)
54 | */
55 | this.Browse = function(req) {
56 | var dir = "";
57 | if(!empty(req.query.dir)) {
58 | req.query.dir = String(req.query.dir);
59 | dir = req.query.dir.replace( '..', '');
60 | }
61 |
62 | if( dir[dir.length-1] != '/' ) {
63 | dir += '/';
64 | }
65 |
66 | var find = '*.*';
67 | switch(req.query.type) {
68 | case 'images':
69 | find = braces('*.{png,gif,jpg,jpeg}');
70 | break;
71 | case 'scripts':
72 | find = ['*.js'];
73 | break;
74 | }
75 |
76 | var dirs = [];
77 | try {
78 | dirs = glob.sync(dir + "*/", {mark: true});
79 | } catch(e) {
80 | console.log(chalk.yellow("Welmeister caught an exception: ") + e);
81 | dirs = [];
82 | }
83 |
84 | var files = [];
85 | for(var f = 0; f < find.length; f++) {
86 | try {
87 | var matchingFiles = glob.sync(dir + find[f]);
88 | files = files.concat(matchingFiles);
89 | } catch(e) {
90 | console.log(chalk.yellow("Welmeister caught an exception: ") + e);
91 | files = [];
92 | }
93 | }
94 |
95 | /*
96 | var fileRootLength = public.conf.WM_ROOT_DIR.length;
97 | for(var i = 0; i < files.length; i++) {
98 | files[i] = files[i].substring(0,fileRootLength);
99 | }
100 | */
101 |
102 | for(var j = 0; j < dirs.length; j++) {
103 | // ! This is needed !
104 | dirs[j] = dirs[j].substr(0, dirs[j].length-1); // drop the '/' character
105 | }
106 |
107 | // substr at second-to-last '/'
108 | var parent = req.query.dir.substring(0, req.query.dir.lastIndexOf('/'));
109 |
110 | var result = {
111 | 'parent': empty(req.query.dir)? false : parent,
112 | 'dirs': dirs,
113 | 'files': files
114 | };
115 |
116 | return JSON.stringify(result);
117 | }
118 |
119 | /*
120 | Glob fetches the entity files used in the requested level
121 | */
122 | this.Glob = function(req) {
123 | var files = [];
124 |
125 | if(!empty(req.query.glob)) {
126 | var globs = Array.isArray(req.query.glob)? req.query.glob : [req.query.glob];
127 |
128 | for(var g = 0; g < globs.length; g++) {
129 | pattern = "" + globs[g].replace('..', '');
130 | try {
131 | var currentFiles = glob.sync(pattern); // glob returns array
132 | files = files.concat(currentFiles);
133 | } catch(e) {
134 | currentFiles = false;
135 | console.log(chalk.yellow("Welmeister caught an exception: ") + e);
136 | }
137 | }
138 | }
139 | //console.log("JSON.stringify(files): " + JSON.stringify(files));
140 | return JSON.stringify(files);
141 | }
142 |
143 | /*
144 | Save writes level data to a file. Will return errors if:
145 | 1 - The file failed to write (directory doesn't exist)
146 | 2 - File does not have a .js suffix
147 | 3 - No data is found in the level workspace
148 | 4 - No path was specified
149 | */
150 | this.Save = function(req) {
151 | result = {'error': 0};
152 |
153 | if( !empty(req.body.path) && !empty(req.body.data) ) {
154 | var path = public.conf.WM_ROOT_DIR + String(req.body.path).replace('..', '');
155 |
156 | if(path.match(/.*\.js/g)) {
157 | try {
158 | success = fs.writeFileSync( path, req.body.data );
159 | } catch(e) {
160 | success = false;
161 | console.log(chalk.yellow("Welmeister caught an exception: ") + e);
162 | }
163 |
164 | if(success === false) {
165 | result = {
166 | 'error': '2',
167 | 'msg': "Couldn't write to file: " + path
168 | };
169 | }
170 | } else { // end if match js
171 | result = {
172 | 'error': '3',
173 | 'msg': "File must have a .js suffix"
174 | };
175 | }
176 | } else { // end if path or data has value
177 | result = {
178 | 'error': '1',
179 | 'msg': "No Data or Path specified"
180 | };
181 | }
182 | return(JSON.stringify(result));
183 | }
184 | return this;
185 | }
186 |
--------------------------------------------------------------------------------
/lib/weltmeister/undo.js:
--------------------------------------------------------------------------------
1 | ig.module(
2 | 'weltmeister.undo'
3 | )
4 | .requires(
5 | 'weltmeister.config'
6 | )
7 | .defines(function(){ "use strict";
8 |
9 |
10 | wm.Undo = ig.Class.extend({
11 | levels: 10,
12 | chain: [],
13 | rpos: 0,
14 | currentAction: null,
15 |
16 | init: function( levels ) {
17 | this.levels = levels || 10;
18 | },
19 |
20 |
21 | clear: function() {
22 | this.chain = [];
23 | this.currentAction = null;
24 | },
25 |
26 |
27 | commit: function( action ) {
28 | if( this.rpos ) {
29 | this.chain.splice( this.chain.length - this.rpos, this.rpos );
30 | this.rpos = 0;
31 | }
32 | action.activeLayer = ig.game.activeLayer ? ig.game.activeLayer.name : '';
33 | this.chain.push( action );
34 | if( this.chain.length > this.levels ) {
35 | this.chain.shift();
36 | }
37 | },
38 |
39 |
40 | undo: function() {
41 | var action = this.chain[ this.chain.length - this.rpos - 1 ];
42 | if( !action ) {
43 | return;
44 | }
45 | this.rpos++;
46 |
47 |
48 | ig.game.setActiveLayer( action.activeLayer );
49 |
50 | if( action.type == wm.Undo.MAP_DRAW ) {
51 | for( var i = 0; i < action.changes.length; i++ ) {
52 | var change = action.changes[i];
53 | change.layer.setTile( change.x, change.y, change.old );
54 | }
55 | }
56 | else if( action.type == wm.Undo.ENTITY_EDIT ) {
57 | action.entity.pos.x = action.old.x;
58 | action.entity.pos.y = action.old.y;
59 | action.entity.size.x = action.old.w;
60 | action.entity.size.y = action.old.h;
61 | ig.game.entities.selectEntity( action.entity );
62 | ig.game.entities.loadEntitySettings();
63 | }
64 | else if( action.type == wm.Undo.ENTITY_CREATE ) {
65 | ig.game.entities.removeEntity( action.entity );
66 | ig.game.entities.selectEntity( null );
67 | }
68 | else if( action.type == wm.Undo.ENTITY_DELETE ) {
69 | ig.game.entities.entities.push( action.entity );
70 | if( action.entity.name ) {
71 | this.namedEntities[action.entity.name] = action.entity;
72 | }
73 | ig.game.entities.selectEntity( action.entity );
74 | }
75 |
76 | ig.game.setModified();
77 | },
78 |
79 |
80 | redo: function() {
81 | if( !this.rpos ) {
82 | return;
83 | }
84 |
85 | var action = this.chain[ this.chain.length - this.rpos ];
86 | if( !action ) {
87 | return;
88 | }
89 | this.rpos--;
90 |
91 |
92 | ig.game.setActiveLayer( action.activeLayer );
93 |
94 | if( action.type == wm.Undo.MAP_DRAW ) {
95 | for( var i = 0; i < action.changes.length; i++ ) {
96 | var change = action.changes[i];
97 | change.layer.setTile( change.x, change.y, change.current );
98 | }
99 | }
100 | else if( action.type == wm.Undo.ENTITY_EDIT ) {
101 | action.entity.pos.x = action.current.x;
102 | action.entity.pos.y = action.current.y;
103 | action.entity.size.x = action.current.w;
104 | action.entity.size.y = action.current.h;
105 | ig.game.entities.selectEntity( action.entity );
106 | ig.game.entities.loadEntitySettings();
107 | }
108 | else if( action.type == wm.Undo.ENTITY_CREATE ) {
109 | ig.game.entities.entities.push( action.entity );
110 | if( action.entity.name ) {
111 | this.namedEntities[action.entity.name] = action.entity;
112 | }
113 | ig.game.entities.selectEntity( action.entity );
114 | }
115 | else if( action.type == wm.Undo.ENTITY_DELETE ) {
116 | ig.game.entities.removeEntity( action.entity );
117 | ig.game.entities.selectEntity( null );
118 | }
119 |
120 | ig.game.setModified();
121 | },
122 |
123 |
124 | // -------------------------------------------------------------------------
125 | // Map changes
126 |
127 | beginMapDraw: function( layer ) {
128 | this.currentAction = {
129 | type: wm.Undo.MAP_DRAW,
130 | time: Date.now(),
131 | changes: []
132 | };
133 | },
134 |
135 | pushMapDraw: function( layer, x, y, oldTile, currentTile ) {
136 | if( !this.currentAction ) {
137 | return;
138 | }
139 |
140 | this.currentAction.changes.push({
141 | layer: layer,
142 | x: x,
143 | y: y,
144 | old: oldTile,
145 | current: currentTile
146 | });
147 | },
148 |
149 | endMapDraw: function() {
150 | if( !this.currentAction || !this.currentAction.changes.length ) {
151 | return;
152 | }
153 |
154 | this.commit( this.currentAction );
155 | this.currentAction = null;
156 | },
157 |
158 |
159 | // -------------------------------------------------------------------------
160 | // Entity changes
161 |
162 | beginEntityEdit: function( entity ) {
163 | this.currentAction = {
164 | type: wm.Undo.ENTITY_EDIT,
165 | time: Date.now(),
166 | entity: entity,
167 | old: {
168 | x: entity.pos.x,
169 | y: entity.pos.y,
170 | w: entity.size.x,
171 | h: entity.size.y
172 | },
173 | current: {
174 | x: entity.pos.x,
175 | y: entity.pos.y,
176 | w: entity.size.x,
177 | h: entity.size.y
178 | }
179 | };
180 | },
181 |
182 | pushEntityEdit: function( entity ) {
183 | if( !this.currentAction ) {
184 | return;
185 | }
186 |
187 | this.currentAction.current = {
188 | x: entity.pos.x,
189 | y: entity.pos.y,
190 | w: entity.size.x,
191 | h: entity.size.y
192 | };
193 | },
194 |
195 |
196 | endEntityEdit: function() {
197 | var a = this.currentAction;
198 |
199 | if( !a || (
200 | a.old.x == a.current.x && a.old.y == a.current.y &&
201 | a.old.w == a.current.w && a.old.h == a.current.h
202 | )) {
203 | return;
204 | }
205 |
206 | this.commit( this.currentAction );
207 | this.currentAction = null;
208 | },
209 |
210 |
211 | commitEntityCreate: function( entity ) {
212 | this.commit({
213 | type: wm.Undo.ENTITY_CREATE,
214 | time: Date.now(),
215 | entity: entity
216 | });
217 | },
218 |
219 |
220 | commitEntityDelete: function( entity ) {
221 | this.commit({
222 | type: wm.Undo.ENTITY_DELETE,
223 | time: Date.now(),
224 | entity: entity
225 | });
226 | }
227 | });
228 |
229 | wm.Undo.MAP_DRAW = 1;
230 | wm.Undo.ENTITY_EDIT = 2;
231 | wm.Undo.ENTITY_CREATE = 3;
232 | wm.Undo.ENTITY_DELETE = 4;
233 |
234 | });
--------------------------------------------------------------------------------
/tools/jsmin.php:
--------------------------------------------------------------------------------
1 |
41 | * @copyright 2002 Douglas Crockford (jsmin.c)
42 | * @copyright 2008 Ryan Grove (PHP port)
43 | * @license http://opensource.org/licenses/mit-license.php MIT License
44 | * @version 1.1.1 (2008-03-02)
45 | * @link http://code.google.com/p/jsmin-php/
46 | */
47 |
48 | class JSMin {
49 | const ORD_LF = 10;
50 | const ORD_SPACE = 32;
51 |
52 | protected $a = '';
53 | protected $b = '';
54 | protected $input = '';
55 | protected $inputIndex = 0;
56 | protected $inputLength = 0;
57 | protected $lookAhead = null;
58 | protected $output = '';
59 |
60 | // -- Public Static Methods --------------------------------------------------
61 |
62 | public static function minify($js) {
63 | $jsmin = new JSMin($js);
64 | return $jsmin->min();
65 | }
66 |
67 | // -- Public Instance Methods ------------------------------------------------
68 |
69 | public function __construct($input) {
70 | $this->input = str_replace("\r\n", "\n", $input);
71 | $this->inputLength = strlen($this->input);
72 | }
73 |
74 | // -- Protected Instance Methods ---------------------------------------------
75 |
76 | protected function action($d) {
77 | switch($d) {
78 | case 1:
79 | $this->output .= $this->a;
80 |
81 | case 2:
82 | $this->a = $this->b;
83 |
84 | if ($this->a === "'" || $this->a === '"') {
85 | for (;;) {
86 | $this->output .= $this->a;
87 | $this->a = $this->get();
88 |
89 | if ($this->a === $this->b) {
90 | break;
91 | }
92 |
93 | if (ord($this->a) <= self::ORD_LF) {
94 | throw new JSMinException('Unterminated string literal.');
95 | }
96 |
97 | if ($this->a === '\\') {
98 | $this->output .= $this->a;
99 | $this->a = $this->get();
100 | }
101 | }
102 | }
103 |
104 | case 3:
105 | $this->b = $this->next();
106 |
107 | if ($this->b === '/' && (
108 | $this->a === '(' || $this->a === ',' || $this->a === '=' ||
109 | $this->a === ':' || $this->a === '[' || $this->a === '!' ||
110 | $this->a === '&' || $this->a === '|' || $this->a === '?')) {
111 |
112 | $this->output .= $this->a . $this->b;
113 |
114 | for (;;) {
115 | $this->a = $this->get();
116 |
117 | if ($this->a === '/') {
118 | break;
119 | } elseif ($this->a === '\\') {
120 | $this->output .= $this->a;
121 | $this->a = $this->get();
122 | } elseif (ord($this->a) <= self::ORD_LF) {
123 | throw new JSMinException('Unterminated regular expression '.
124 | 'literal.');
125 | }
126 |
127 | $this->output .= $this->a;
128 | }
129 |
130 | $this->b = $this->next();
131 | }
132 | }
133 | }
134 |
135 | protected function get() {
136 | $c = $this->lookAhead;
137 | $this->lookAhead = null;
138 |
139 | if ($c === null) {
140 | if ($this->inputIndex < $this->inputLength) {
141 | $c = $this->input[$this->inputIndex];
142 | $this->inputIndex += 1;
143 | } else {
144 | $c = null;
145 | }
146 | }
147 |
148 | if ($c === "\r") {
149 | return "\n";
150 | }
151 |
152 | if ($c === null || $c === "\n" || ord($c) >= self::ORD_SPACE) {
153 | return $c;
154 | }
155 |
156 | return ' ';
157 | }
158 |
159 | protected function isAlphaNum($c) {
160 | return ord($c) > 126 || $c === '\\' || preg_match('/^[\w\$]$/', $c) === 1;
161 | }
162 |
163 | protected function min() {
164 | $this->a = "\n";
165 | $this->action(3);
166 |
167 | while ($this->a !== null) {
168 | switch ($this->a) {
169 | case ' ':
170 | if ($this->isAlphaNum($this->b)) {
171 | $this->action(1);
172 | } else {
173 | $this->action(2);
174 | }
175 | break;
176 |
177 | case "\n":
178 | switch ($this->b) {
179 | case '{':
180 | case '[':
181 | case '(':
182 | case '+':
183 | case '-':
184 | $this->action(1);
185 | break;
186 |
187 | case ' ':
188 | $this->action(3);
189 | break;
190 |
191 | default:
192 | if ($this->isAlphaNum($this->b)) {
193 | $this->action(1);
194 | }
195 | else {
196 | $this->action(2);
197 | }
198 | }
199 | break;
200 |
201 | default:
202 | switch ($this->b) {
203 | case ' ':
204 | if ($this->isAlphaNum($this->a)) {
205 | $this->action(1);
206 | break;
207 | }
208 |
209 | $this->action(3);
210 | break;
211 |
212 | case "\n":
213 | switch ($this->a) {
214 | case '}':
215 | case ']':
216 | case ')':
217 | case '+':
218 | case '-':
219 | case '"':
220 | case "'":
221 | $this->action(1);
222 | break;
223 |
224 | default:
225 | if ($this->isAlphaNum($this->a)) {
226 | $this->action(1);
227 | }
228 | else {
229 | $this->action(3);
230 | }
231 | }
232 | break;
233 |
234 | default:
235 | $this->action(1);
236 | break;
237 | }
238 | }
239 | }
240 |
241 | return $this->output;
242 | }
243 |
244 | protected function next() {
245 | $c = $this->get();
246 |
247 | if ($c === '/') {
248 | switch($this->peek()) {
249 | case '/':
250 | for (;;) {
251 | $c = $this->get();
252 |
253 | if (ord($c) <= self::ORD_LF) {
254 | return $c;
255 | }
256 | }
257 |
258 | case '*':
259 | $this->get();
260 |
261 | for (;;) {
262 | switch($this->get()) {
263 | case '*':
264 | if ($this->peek() === '/') {
265 | $this->get();
266 | return ' ';
267 | }
268 | break;
269 |
270 | case null:
271 | throw new JSMinException('Unterminated comment.');
272 | }
273 | }
274 |
275 | default:
276 | return $c;
277 | }
278 | }
279 |
280 | return $c;
281 | }
282 |
283 | protected function peek() {
284 | $this->lookAhead = $this->get();
285 | return $this->lookAhead;
286 | }
287 | }
288 |
289 | // -- Exceptions ---------------------------------------------------------------
290 | class JSMinException extends Exception {}
291 | ?>
--------------------------------------------------------------------------------
/lib/weltmeister/edit-map.js:
--------------------------------------------------------------------------------
1 | ig.module(
2 | 'weltmeister.edit-map'
3 | )
4 | .requires(
5 | 'impact.background-map',
6 | 'weltmeister.tile-select'
7 | )
8 | .defines(function(){ "use strict";
9 |
10 | wm.EditMap = ig.BackgroundMap.extend({
11 | name: '',
12 | visible: true,
13 | active: true,
14 | linkWithCollision: false,
15 |
16 | div: null,
17 | brush: [[0]],
18 | oldData: null,
19 | hotkey: -1,
20 | ignoreLastClick: false,
21 | tileSelect: null,
22 |
23 | isSelecting: false,
24 | selectionBegin: null,
25 |
26 | init: function( name, tilesize, tileset, foreground ) {
27 | this.name = name;
28 | this.parent( tilesize, [[0]], tileset || '' );
29 | this.foreground = foreground;
30 |
31 | this.div = $( '', {
32 | 'class': 'layer layerActive',
33 | 'id': ('layer_' + name),
34 | 'mouseup': this.click.bind(this)
35 | });
36 | this.setName( name );
37 | if( this.foreground ) {
38 | $('#layers').prepend( this.div );
39 | }
40 | else {
41 | $('#layerEntities').after( this.div );
42 | }
43 |
44 | this.tileSelect = new wm.TileSelect( this );
45 | },
46 |
47 |
48 | getSaveData: function() {
49 | return {
50 | name: this.name,
51 | width: this.width,
52 | height: this.height,
53 | linkWithCollision: this.linkWithCollision,
54 | visible: this.visible,
55 | tilesetName: this.tilesetName,
56 | repeat: this.repeat,
57 | preRender: this.preRender,
58 | distance: this.distance,
59 | tilesize: this.tilesize,
60 | foreground: this.foreground,
61 | data: this.data
62 | };
63 | },
64 |
65 |
66 | resize: function( newWidth, newHeight ) {
67 | var newData = new Array( newHeight );
68 | for( var y = 0; y < newHeight; y++ ) {
69 | newData[y] = new Array( newWidth );
70 | for( var x = 0; x < newWidth; x++ ) {
71 | newData[y][x] = (x < this.width && y < this.height) ? this.data[y][x] : 0;
72 | }
73 | }
74 | this.data = newData;
75 | this.width = newWidth;
76 | this.height = newHeight;
77 |
78 | this.resetDiv();
79 | },
80 |
81 | beginEditing: function() {
82 | this.oldData = ig.copy(this.data);
83 | },
84 |
85 | getOldTile: function( x, y ) {
86 | var tx = Math.floor( x / this.tilesize );
87 | var ty = Math.floor( y / this.tilesize );
88 | if(
89 | (tx >= 0 && tx < this.width) &&
90 | (ty >= 0 && ty < this.height)
91 | ) {
92 | return this.oldData[ty][tx];
93 | }
94 | else {
95 | return 0;
96 | }
97 | },
98 |
99 | setTileset: function( tileset ) {
100 | if( this.name == 'collision' ) {
101 | this.setCollisionTileset();
102 | }
103 | else {
104 | this.parent( tileset );
105 | }
106 | },
107 |
108 |
109 | setCollisionTileset: function() {
110 | var path = wm.config.collisionTiles.path;
111 | var scale = this.tilesize / wm.config.collisionTiles.tilesize;
112 | this.tiles = new ig.AutoResizedImage( path, scale );
113 | },
114 |
115 |
116 |
117 |
118 |
119 | // -------------------------------------------------------------------------
120 | // UI
121 |
122 | setHotkey: function( hotkey ) {
123 | this.hotkey = hotkey;
124 | this.setName( this.name );
125 | },
126 |
127 |
128 | setName: function( name ) {
129 | this.name = name.replace(/[^0-9a-zA-Z]/g, '_');
130 | this.resetDiv();
131 | },
132 |
133 |
134 | resetDiv: function() {
135 | var visClass = this.visible ? ' checkedVis' : '';
136 | this.div.html(
137 | '' +
138 | '' + this.name + '' +
139 | ' (' + this.width + 'x' + this.height + ')'
140 | );
141 | this.div.attr('title', 'Select Layer ('+this.hotkey+')' );
142 | this.div.children('.visible').bind('mousedown', this.toggleVisibilityClick.bind(this) );
143 | },
144 |
145 |
146 | setActive: function( active ) {
147 | this.active = active;
148 | if( active ) {
149 | this.div.addClass( 'layerActive' );
150 | } else {
151 | this.div.removeClass( 'layerActive' );
152 | }
153 | },
154 |
155 |
156 | toggleVisibility: function() {
157 | this.visible ^= 1;
158 | this.resetDiv();
159 | if( this.visible ) {
160 | this.div.children('.visible').addClass('checkedVis');
161 | } else {
162 | this.div.children('.visible').removeClass('checkedVis');
163 | }
164 | ig.game.draw();
165 | },
166 |
167 |
168 | toggleVisibilityClick: function( event ) {
169 | if( !this.active ) {
170 | this.ignoreLastClick = true;
171 | }
172 | this.toggleVisibility()
173 | },
174 |
175 |
176 | click: function() {
177 | if( this.ignoreLastClick ) {
178 | this.ignoreLastClick = false;
179 | return;
180 | }
181 | ig.editor.setActiveLayer( this.name );
182 | },
183 |
184 |
185 | destroy: function() {
186 | this.div.remove();
187 | },
188 |
189 |
190 |
191 | // -------------------------------------------------------------------------
192 | // Selecting
193 |
194 | beginSelecting: function( x, y ) {
195 | this.isSelecting = true;
196 | this.selectionBegin = {x:x, y:y};
197 | },
198 |
199 |
200 | endSelecting: function( x, y ) {
201 | var r = this.getSelectionRect( x, y);
202 |
203 | var brush = [];
204 | for( var ty = r.y; ty < r.y+r.h; ty++ ) {
205 | var row = [];
206 | for( var tx = r.x; tx < r.x+r.w; tx++ ) {
207 | if( tx < 0 || ty < 0 || tx >= this.width || ty >= this.height ) {
208 | row.push( 0 );
209 | }
210 | else {
211 | row.push( this.data[ty][tx] );
212 | }
213 | }
214 | brush.push( row );
215 | }
216 | this.isSelecting = false;
217 | this.selectionBegin = null;
218 | return brush;
219 | },
220 |
221 |
222 | getSelectionRect: function( x, y ) {
223 | var sx = this.selectionBegin ? this.selectionBegin.x : x,
224 | sy = this.selectionBegin ? this.selectionBegin.y : y;
225 |
226 | var
227 | txb = Math.floor( (sx + this.scroll.x) / this.tilesize ),
228 | tyb = Math.floor( (sy + this.scroll.y) / this.tilesize ),
229 | txe = Math.floor( (x + this.scroll.x) / this.tilesize ),
230 | tye = Math.floor( (y + this.scroll.y) / this.tilesize );
231 |
232 | return {
233 | x: Math.min( txb, txe ),
234 | y: Math.min( tyb, tye ),
235 | w: Math.abs( txb - txe) + 1,
236 | h: Math.abs( tyb - tye) + 1
237 | }
238 | },
239 |
240 |
241 |
242 |
243 | // -------------------------------------------------------------------------
244 | // Drawing
245 |
246 | draw: function() {
247 | // For performance reasons, repeated background maps are not drawn
248 | // when zoomed out
249 | if( this.visible && !(wm.config.view.zoom < 1 && this.repeat) ) {
250 | this.drawTiled();
251 | }
252 |
253 | // Grid
254 | if( this.active && wm.config.view.grid ) {
255 |
256 | var x = -ig.system.getDrawPos(this.scroll.x % this.tilesize) - 0.5;
257 | var y = -ig.system.getDrawPos(this.scroll.y % this.tilesize) - 0.5;
258 | var step = this.tilesize * ig.system.scale;
259 |
260 | ig.system.context.beginPath();
261 | for( x; x < ig.system.realWidth; x += step ) {
262 | ig.system.context.moveTo( x, 0 );
263 | ig.system.context.lineTo( x, ig.system.realHeight );
264 | }
265 | for( y; y < ig.system.realHeight; y += step ) {
266 | ig.system.context.moveTo( 0, y );
267 | ig.system.context.lineTo( ig.system.realWidth, y );
268 | }
269 | ig.system.context.strokeStyle = wm.config.colors.secondary;
270 | ig.system.context.stroke();
271 | ig.system.context.closePath();
272 |
273 | // Not calling beginPath() again has some weird performance issues
274 | // in Firefox 5. closePath has no effect. So to make it happy:
275 | ig.system.context.beginPath();
276 | }
277 |
278 | // Bounds
279 | if( this.active ) {
280 | ig.system.context.lineWidth = 1;
281 | ig.system.context.strokeStyle = wm.config.colors.primary;
282 | ig.system.context.strokeRect(
283 | -ig.system.getDrawPos(this.scroll.x) - 0.5,
284 | -ig.system.getDrawPos(this.scroll.y) - 0.5,
285 | this.width * this.tilesize * ig.system.scale + 1,
286 | this.height * this.tilesize * ig.system.scale + 1
287 | );
288 | }
289 | },
290 |
291 | getCursorOffset: function() {
292 | var w = this.brush[0].length;
293 | var h = this.brush.length;
294 |
295 | //return {x:0, y:0};
296 | return {
297 | x: (w/2-0.5).toInt() * this.tilesize,
298 | y: (h/2-0.5).toInt() * this.tilesize
299 | }
300 | },
301 |
302 | drawCursor: function( x, y ) {
303 | if( this.isSelecting ) {
304 | var r = this.getSelectionRect( x, y);
305 |
306 | ig.system.context.lineWidth = 1;
307 | ig.system.context.strokeStyle = wm.config.colors.selection;
308 | ig.system.context.strokeRect(
309 | (r.x * this.tilesize - this.scroll.x) * ig.system.scale - 0.5,
310 | (r.y * this.tilesize - this.scroll.y) * ig.system.scale - 0.5,
311 | r.w * this.tilesize * ig.system.scale + 1,
312 | r.h * this.tilesize * ig.system.scale + 1
313 | );
314 | }
315 | else {
316 | var w = this.brush[0].length;
317 | var h = this.brush.length;
318 |
319 | var co = this.getCursorOffset();
320 |
321 | var cx = Math.floor( (x+this.scroll.x) / this.tilesize ) * this.tilesize - this.scroll.x - co.x;
322 | var cy = Math.floor( (y+this.scroll.y) / this.tilesize ) * this.tilesize - this.scroll.y - co.y;
323 |
324 | ig.system.context.lineWidth = 1;
325 | ig.system.context.strokeStyle = wm.config.colors.primary;
326 | ig.system.context.strokeRect(
327 | ig.system.getDrawPos(cx)-0.5,
328 | ig.system.getDrawPos(cy)-0.5,
329 | w * this.tilesize * ig.system.scale + 1,
330 | h * this.tilesize * ig.system.scale + 1
331 | );
332 |
333 | ig.system.context.globalAlpha = 0.5;
334 | for( var ty = 0; ty < h; ty++ ) {
335 | for( var tx = 0; tx < w; tx++ ) {
336 | var t = this.brush[ty][tx];
337 | if( t ) {
338 | var px = cx + tx * this.tilesize;
339 | var py = cy + ty * this.tilesize;
340 | this.tiles.drawTile( px, py, t-1, this.tilesize );
341 | }
342 | }
343 | }
344 | ig.system.context.globalAlpha = 1;
345 | }
346 | }
347 | });
348 |
349 |
350 | ig.AutoResizedImage = ig.Image.extend({
351 | internalScale: 1,
352 |
353 | staticInstantiate: function() {
354 | return null; // Never cache!
355 | },
356 |
357 | init: function( path, internalScale ) {
358 | this.internalScale = internalScale;
359 | this.parent( path );
360 | },
361 |
362 | onload: function( event ) {
363 | this.width = Math.ceil(this.data.width * this.internalScale);
364 | this.height = Math.ceil(this.data.height * this.internalScale);
365 |
366 | if( this.internalScale != 1 ) {
367 | var scaled = ig.$new('canvas');
368 | scaled.width = this.width;
369 | scaled.height = this.height;
370 | var scaledCtx = scaled.getContext('2d');
371 |
372 | scaledCtx.drawImage( this.data, 0, 0, this.data.width, this.data.height, 0, 0, this.width , this.height );
373 | this.data = scaled;
374 | }
375 |
376 | this.loaded = true;
377 | if( ig.system.scale != 1 ) {
378 | this.resize( ig.system.scale );
379 | }
380 |
381 | if( this.loadCallback ) {
382 | this.loadCallback( this.path, true );
383 | }
384 | }
385 | });
386 |
387 |
388 | });
--------------------------------------------------------------------------------
/lib/weltmeister/weltmeister.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #000;
3 | color: #fff;
4 | font-family: sans-serif;
5 | font-size: 10pt;
6 | margin: 0px;
7 | overflow: hidden;
8 | text-shadow: 0px 1px 1px rgba(0,0,0,0.5);
9 | -webkit-font-smoothing: antialiased;
10 | -webkit-user-select: none;
11 | }
12 |
13 | h2 {
14 | margin: 0 0 4px 0;
15 | padding: 4px 0 4px 6px;
16 | background-color: #000;
17 | font-size: 100%;
18 | color: #555;
19 | xtext-transform: uppercase;
20 | xborder-bottom: 1px solid #555;
21 | }
22 |
23 | h3 {
24 | margin: 0;
25 | font-size: 100%;
26 | display: block;
27 | }
28 |
29 | dt {
30 | margin: 0;
31 | padding: 4px 0 0 6px;
32 | display:inline;
33 | float:left;
34 | margin-right:5px;
35 | }
36 |
37 | dd {
38 | margin: 0;
39 | padding: 2px 0 8px 6px;
40 | }
41 |
42 | dl {
43 | margin:0;
44 | }
45 |
46 | div.clear {
47 | clear: both;
48 | }
49 |
50 | label {
51 | cursor: pointer;
52 | }
53 |
54 | /* --- Input ------------------------------------------------------------------ */
55 |
56 | input {
57 | background-color: rgba(0,0,0,0.5);
58 | border: 1px solid rgb(50,50,50);
59 | color: #fff;
60 | margin: 0;
61 | font-family: sans-serif;
62 | -webkit-font-smoothing: antialiased;
63 | font-size: 10pt;
64 | outline: none;
65 | text-shadow: 0px 1px 1px rgba(0,0,0,0.5);
66 |
67 | }
68 |
69 | input:focus{
70 | border: 1px solid rgb(200,200,200);
71 | }
72 |
73 | input.text {
74 | padding: 1px;
75 | margin: 0;
76 | }
77 |
78 | input.number {
79 | width: 30px;
80 | text-align: right;
81 | }
82 |
83 | input.button {
84 | font-size: 90%;
85 | padding-left: 13px;
86 | padding-right: 13px;
87 | padding-top: 5px;
88 | padding-bottom: 5px;
89 | color: #fff;
90 | font-weight: bold;
91 | background-color: rgba(255,255,255,0.1);
92 | border:none;
93 | border-top: 1px solid rgba(255,255,255,0.1);
94 | border-bottom: 1px solid rgba(0,0,0,0.1);
95 | cursor: pointer;
96 | -webkit-transition: 0.1s linear;
97 | }
98 |
99 | input.button:hover {
100 | background-color: rgba(255,255,255,0.2);
101 | }
102 |
103 | input.button:active {
104 | background-color: rgba(255,255,255,0.3);
105 | }
106 |
107 | input.text#layerName {
108 | width:140px;
109 | }
110 |
111 | input.text#layerTileset {
112 | width:138px;
113 | }
114 |
115 | input#levelSaveAs { margin-right: 10px; }
116 | input#levelLoad { margin-right: 10px; }
117 | input#reloadImages {margin-right: 10px;}
118 |
119 | input:disabled {
120 | background-color: #555;
121 | color: #888;
122 | }
123 |
124 | /* --- Layout ------------------------------------------------------------------ */
125 |
126 | #editor {
127 | margin: 0px;
128 | position: relative;
129 | }
130 |
131 | #canvas {
132 | image-rendering: optimizeSpeed;
133 | -webkit-interpolation-mode: nearest-neighbor;
134 | }
135 |
136 | #menu {
137 | width: 200px;
138 | float: right;
139 | position:absolute;
140 | top:0px;
141 | right:0px;
142 | }
143 |
144 | /* --- Layers ------------------------------------------------------------------ */
145 |
146 | #layerContainer {
147 | background-color: rgba(0,0,0,0.95);
148 | padding-right:2px;
149 | }
150 |
151 | #layers {
152 | max-height: 200px;
153 | overflow: auto;
154 | }
155 |
156 | #layerButtons div.button#buttonAddLayer {
157 | position:absolute;
158 | right: 0px;
159 | top:-5px;
160 | cursor: pointer;
161 | padding: 10px;
162 | color:rgba(255,255,255,0.5);
163 | font-weight: bold;
164 | font-size:110%;
165 | margin-left:1px;
166 | -webkit-transition: 0.1s linear;
167 | -webkit-font-smoothing: none;
168 | z-index:10;
169 | }
170 | #layerButtons div.button#buttonAddLayer:hover { color:rgba(255,255,255,1);}
171 | #layerButtons div.button#buttonAddLayer:active { color:rgba(255,255,255,1); text-shadow:none;}
172 |
173 | .layer {
174 | padding: 6px 4px;
175 | cursor: pointer;
176 | -webkit-transition: background-color 0.1s linear;
177 | border-top: 1px solid rgba(255,255,255,0);
178 | border-bottom: 1px solid rgba(255,255,255,0);
179 | }
180 |
181 | .layer:hover {
182 | background-color: rgba(255,255,255,0.1);
183 | border-top: 1px solid rgba(255,255,255,0.1);
184 | border-bottom: 1px solid rgba(255,255,255,0.1);
185 | }
186 |
187 | .layer:active {
188 | background-color: rgba(255,255,255,0.2);
189 | border-top: 1px solid rgba(255,255,255,0.2);
190 | border-bottom: 1px solid rgba(255,255,255,0.2);
191 | }
192 |
193 | .layerActive {
194 | background-color: rgba(255,255,255,0.1);
195 | border-top: 1px solid rgba(255,255,255,0.2);
196 | border-bottom: 1px solid rgba(255,255,255,0.2) !important;
197 | }
198 |
199 |
200 | #layerEntities { border-bottom: 1px solid #000; }
201 |
202 | .layer .visible {
203 | background-color: rgba(255,255,255,0.2);
204 | text-indent: -99999px;
205 | display: inline-block;
206 | width: 10px;
207 | height: 10px;
208 | margin-right: 7px;
209 | margin-left: 4px;
210 | -webkit-transition: 0.1s linear;
211 | }
212 |
213 | .layer .visible.specialVis{
214 | margin-right: 2px;
215 | }
216 |
217 | .layer .checkedVis{ background-color: rgba(255,255,255,1); }
218 | .layer span.size { font-size: 75%; color: rgba(255,255,255,0.7); }
219 |
220 | #layerSettings {
221 | background-color: rgba(0,0,0,0.95);
222 | padding-top: 5px;
223 | margin-top: 1px;
224 | display: none;
225 | }
226 |
227 | /* --- Entities ------------------------------------------------------------------ */
228 | h3#entityClass {
229 | border-bottom: 1px solid rgba(255,255,255,0.2);
230 | padding: 5px;
231 | padding-left: 10px;
232 | }
233 |
234 | #entitySettings {
235 | background-color: rgba(0,0,0,0.95);
236 | margin-top: 1px;
237 | display: none;
238 | }
239 |
240 | #entityDefinitions {
241 | max-height: 220px;
242 | overflow: auto;
243 | }
244 |
245 | div.entityDefinition {
246 | color: #aaa;
247 | padding: 2px 0;
248 | border-bottom: 1px solid rgba(255,255,255,0.2);
249 | cursor: pointer;
250 | }
251 |
252 | div.entityDefinition:hover {
253 | background-color: rgba(255,255,255,0.1);
254 | }
255 |
256 | div.entityDefinition .key {
257 | width: 50%;
258 | display: block;
259 | float: left;
260 | margin: 0 0px 0 0;
261 | padding: 0;
262 | text-align: right;
263 | color: #fff;
264 | overflow: hidden;
265 | }
266 |
267 | div.entityDefinition .value {
268 | padding: 0 0 0 2px;
269 | color: #fff;
270 | }
271 |
272 | dl#entityDefinitionInput {
273 | padding: 8px 0;
274 | }
275 |
276 | dl#entityDefinitionInput dt {
277 | width: 40px;
278 | display: block;
279 | float: left;
280 | margin: 0 4px 0 0;
281 | padding: 4px 0 0 0;
282 | text-align: right;
283 | }
284 |
285 | dl#entityDefinitionInput dd {
286 | display: block;
287 | margin: 0;
288 | padding: 2px 0;
289 | }
290 |
291 | #entityKey, #entityValue {
292 | }
293 |
294 | #entityMenu {
295 | background-color: rgba(0,0,0,0.9);
296 | display: none;
297 | position: absolute;
298 | min-width: 100px;
299 | max-height:300px;
300 | overflow-y: scroll;
301 | z-index: 1000;
302 | }
303 |
304 | #entityMenu div {
305 | padding: 3px;
306 | padding-left: 8px;
307 | color: #fff;
308 | cursor: pointer;
309 | border-top: 1px solid rgba(255,255,255,0);
310 | border-bottom: 1px solid rgba(255,255,255,0);
311 | -webkit-transition: 0.1s linear;
312 | }
313 |
314 | #entityMenu div:hover {
315 | background-color: rgba(255,255,255,0.2);
316 | border-top: 1px solid rgba(255,255,255,0.2);
317 | border-bottom: 1px solid rgba(255,255,255,0.2);
318 | }
319 |
320 | /* --- Dialogs ------------------------------------------------------------------ */
321 |
322 | .selectFileDialog {
323 | background-color: rgba(0,0,0,0.9);
324 | border: 1px solid white;
325 | border-top: 1px solid rgba(255,255,255,0.4);
326 | display: none;
327 | position: absolute;
328 | overflow: hidden;
329 | -webkit-box-shadow: 0px 0px 10px rgba(0,0,0,1);
330 |
331 | max-height: 300px;
332 | overflow-y: scroll;
333 | }
334 |
335 | .selectFileDialog a {
336 | padding: 4px;
337 | color: #fff;
338 | display: block;
339 | text-decoration: none;
340 | border-top: 1px solid rgba(255,255,255,0);
341 | border-bottom: 1px solid rgba(255,255,255,0);
342 | }
343 |
344 | .selectFileDialog a:hover {
345 | background-color: rgba(255,255,255,0.2);
346 | border-top: 1px solid rgba(255,255,255,0.2);
347 | border-bottom: 1px solid rgba(255,255,255,0.2);
348 | }
349 |
350 | div.modalDialogBackground {
351 | background-color: rgba(0,0,0,0.7);
352 | width: 100%;
353 | height: 100%;
354 | position: fixed;
355 | top: 0;
356 | left: 0;
357 | display: none;
358 | z-index: 100;
359 | }
360 |
361 | div.modalDialogBox {
362 | width: 300px;
363 | margin-left: -170px;
364 | background-color: rgba(0,0,0,0.9);
365 | border: 1px solid rgb(100,100,100);
366 | -webkit-box-shadow: 0px 0px 10px rgba(0,0,0,1);
367 | position: absolute;
368 | top: 20%;
369 | left: 50%;
370 | padding: 20px;
371 | }
372 |
373 | div.modalDialogText {
374 | font-size: 180%;
375 | font-weight: bold;
376 | }
377 |
378 | div.modalDialogButtons {
379 | margin-top: 20px;
380 | text-align: right;
381 | }
382 |
383 | div.modalDialogButtons input.button {
384 | min-width: 100px;
385 | text-align: center;
386 | margin-left: 10px;
387 | }
388 |
389 | input.modalDialogPath {
390 | margin-top: 20px;
391 | width: 100%;
392 | outline: none;
393 | }
394 |
395 | input.modalDialogPath:focus {
396 | outline: none;
397 | border: 1px solid rgb(100,100,100);
398 | }
399 |
400 | #headerMenu {
401 | position:relative;
402 | z-index:10;
403 | height:47px;
404 | width:100%;
405 | background: #131314;
406 | background: -webkit-gradient(linear, left bottom, left top, color-stop(0,#000000), color-stop(1,#2e3033));
407 | background: -moz-linear-gradient(center bottom, #000000 0%, #2e3033 100%);
408 | background: -o-linear-gradient(#2e3033, #000000);
409 | }
410 |
411 | #headerMenu span.headerTitle {
412 | display:inline-block;
413 | font-weight:bold;
414 | font-size:200%;
415 | padding-left:20px;
416 | padding-top:7px;
417 | color:rgba(0,0,0,0.1);
418 | text-shadow:0px -1px 0px rgba(255,255,255,0.4);
419 | }
420 |
421 | #headerMenu span.unsavedTitle {
422 | display:inline-block;
423 | font-weight:bold;
424 | font-size:240%;
425 | padding-left:0px;
426 | color:#cc0000;
427 | text-shadow:0px 1px 1px rgba(0,0,0,0.1);
428 | }
429 |
430 | #headerMenu span.headerFloat {
431 | float: right;
432 | }
433 |
434 | div#zoomIndicator {
435 | font-weight: bold;
436 | font-size: 300%;
437 | position: absolute;
438 | left: 50px;
439 | top: 30px;
440 | color: #fff;
441 | display: none;
442 | }
443 |
444 | input#toggleSidebar {
445 | width: 200px;
446 | height: 47px;
447 | text-indent: -99999px;
448 | background: url(arrow.png) 50% -37px no-repeat;
449 | -webkit-transition: 0s linear;
450 | opacity: 0.25;
451 | padding: 0px;
452 | }
453 |
454 | input#toggleSidebar.active{
455 | background-position: 50% 10px;
456 | }
457 |
458 | input[type="checkbox"] {
459 | position: relative;
460 | margin: 0;
461 | border: 0;
462 | width: 10px;
463 | height: 10px;
464 | display: inline-block;
465 | -webkit-appearance: none;
466 | -webkit-transition: 0.1s linear;
467 | }
468 | input[type="checkbox"] {
469 | background-color:rgba(255,255,255,0.2);
470 | }
471 | input[type="checkbox"]:checked {
472 | background-color: rgba(255,255,255,1);
473 | }
474 | input[type="checkbox"]:hover {
475 | cursor: pointer;
476 | }
477 | input[type="checkbox"]:disabled {
478 | background-color: rgba(255,255,255,0.1);
479 | }
480 |
481 | ::-webkit-scrollbar { width: 2px; }
482 | ::-webkit-scrollbar-button:start:decrement,
483 | ::-webkit-scrollbar-button:end:increment { display: block; height: 2px; }
484 | ::-webkit-scrollbar-button:vertical:increment { background-color: transparent; }
485 | ::-webkit-scrollbar-track-piece { background-color: rgba(0,0,0,0); }
486 | ::-webkit-scrollbar-thumb:vertical { background-color: rgba(255,255,255,1); }
487 |
--------------------------------------------------------------------------------
/lib/weltmeister/edit-entities.js:
--------------------------------------------------------------------------------
1 | ig.module(
2 | 'weltmeister.edit-entities'
3 | )
4 | .requires(
5 | 'impact.game',
6 | 'impact.background-map',
7 | 'weltmeister.config',
8 | 'weltmeister.tile-select',
9 | 'weltmeister.entities'
10 | )
11 | .defines(function(){ "use strict";
12 |
13 | wm.EditEntities = ig.Class.extend({
14 | visible: true,
15 | active: true,
16 |
17 | div: null,
18 | hotkey: -1,
19 | ignoreLastClick: false,
20 | name: 'entities',
21 |
22 | entities: [],
23 | namedEntities: {},
24 | selectedEntity: null,
25 | entityClasses: {},
26 | menuDiv: null,
27 | selector: {size:{x:2, y:2}, pos:{x:0,y:0}, offset:{x:0,y:0}},
28 | wasSelectedOnScaleBorder: false,
29 | gridSize: wm.config.entityGrid,
30 | entityDefinitions: null,
31 |
32 |
33 |
34 | init: function( div ) {
35 | this.div = div;
36 | div.bind( 'mouseup', this.click.bind(this) );
37 | this.div.children('.visible').bind( 'mousedown', this.toggleVisibilityClick.bind(this) );
38 |
39 | this.menu = $('#entityMenu');
40 | this.importEntityClass( wm.entityModules );
41 | this.entityDefinitions = $('#entityDefinitions');
42 |
43 | $('#entityKey').bind( 'keydown', function(ev){
44 | if( ev.which == 13 ){
45 | $('#entityValue').focus();
46 | return false;
47 | }
48 | return true;
49 | });
50 | $('#entityValue').bind( 'keydown', this.setEntitySetting.bind(this) );
51 | },
52 |
53 |
54 | clear: function() {
55 | this.entities = [];
56 | this.selectEntity( null );
57 | },
58 |
59 |
60 | sort: function() {
61 | this.entities.sort( ig.Game.SORT.Z_INDEX );
62 | },
63 |
64 |
65 |
66 |
67 | // -------------------------------------------------------------------------
68 | // Loading, Saving
69 |
70 |
71 | fileNameToClassName: function( name ) {
72 | var typeName = '-' + name.replace(/^.*\/|\.js/g,'');
73 | typeName = typeName.replace(/-(\w)/g, function( m, a ) {
74 | return a.toUpperCase();
75 | });
76 | return 'Entity' + typeName;
77 | },
78 |
79 |
80 | importEntityClass: function( modules ) {
81 | var unloadedClasses = [];
82 | for( var m in modules ) {
83 | var className = this.fileNameToClassName(modules[m]);
84 | var entityName = className.replace(/^Entity/, '');
85 |
86 | // ig.global[className] should be the actual class object
87 | if( className && ig.global[className] ) {
88 |
89 | // Ignore entities that have the _wmIgnore flag
90 | if( !ig.global[className].prototype._wmIgnore ) {
91 | var a = $( '', {
92 | 'id': className,
93 | 'href': '#',
94 | 'html': entityName,
95 | 'mouseup': this.newEntityClick.bind(this)
96 | });
97 | this.menu.append( a );
98 | this.entityClasses[className] = m;
99 | }
100 | }
101 | else {
102 | unloadedClasses.push( modules[m] + ' (expected name: ' + className + ')' );
103 | }
104 | }
105 |
106 | if( unloadedClasses.length > 0 ) {
107 | var warning = 'The following entity classes were not loaded due to\n'
108 | + 'file and class name mismatches: \n\n'
109 | + unloadedClasses.join( '\n' );
110 | alert( warning );
111 | }
112 | },
113 |
114 |
115 | getEntityByName: function( name ) {
116 | return this.namedEntities[name];
117 | },
118 |
119 |
120 | getSaveData: function() {
121 | var ents = [];
122 | for( var i = 0; i < this.entities.length; i++ ) {
123 | var ent = this.entities[i];
124 | var type = ent._wmClassName;
125 | var data = {type:type,x:ent.pos.x,y:ent.pos.y};
126 |
127 | var hasSettings = false;
128 | for( var p in ent._wmSettings ) {
129 | hasSettings = true;
130 | }
131 | if( hasSettings ) {
132 | data.settings = ent._wmSettings;
133 | }
134 |
135 | ents.push( data );
136 | }
137 | return ents;
138 | },
139 |
140 |
141 |
142 |
143 | // -------------------------------------------------------------------------
144 | // Selecting
145 |
146 |
147 | selectEntityAt: function( x, y ) {
148 | this.selector.pos = { x: x, y: y };
149 |
150 | // Find all possible selections
151 | var possibleSelections = [];
152 | for( var i = 0; i < this.entities.length; i++ ) {
153 | if( this.entities[i].touches(this.selector) ) {
154 | possibleSelections.push( this.entities[i] );
155 | }
156 | }
157 |
158 | // Nothing found? Early out.
159 | if( !possibleSelections.length ) {
160 | this.selectEntity( null );
161 | return false;
162 | }
163 |
164 | // Find the 'next' selection
165 | var selectedIndex = possibleSelections.indexOf(this.selectedEntity);
166 | var nextSelection = (selectedIndex + 1) % possibleSelections.length;
167 | var ent = possibleSelections[nextSelection];
168 |
169 | // Select it!
170 | this.selector.offset = {
171 | x: (x - ent.pos.x + ent.offset.x),
172 | y: (y - ent.pos.y + ent.offset.y)
173 | };
174 | this.selectEntity( ent );
175 | this.wasSelectedOnScaleBorder = this.isOnScaleBorder( ent, this.selector );
176 | return ent;
177 | },
178 |
179 |
180 | selectEntity: function( entity ) {
181 | if( entity && entity != this.selectedEntity ) {
182 | this.selectedEntity = entity;
183 | $('#entitySettings').fadeOut(100,(function(){
184 | this.loadEntitySettings();
185 | $('#entitySettings').fadeIn(100);
186 | }).bind(this));
187 | }
188 | else if( !entity ) {
189 | $('#entitySettings').fadeOut(100);
190 | $('#entityKey').blur();
191 | $('#entityValue').blur();
192 | }
193 |
194 | this.selectedEntity = entity;
195 | $('#entityKey').val('');
196 | $('#entityValue').val('');
197 | },
198 |
199 |
200 |
201 |
202 | // -------------------------------------------------------------------------
203 | // Creating, Deleting, Moving
204 |
205 |
206 | deleteSelectedEntity: function() {
207 | if( !this.selectedEntity ) {
208 | return false;
209 | }
210 |
211 | ig.game.undo.commitEntityDelete( this.selectedEntity );
212 |
213 | this.removeEntity( this.selectedEntity );
214 | this.selectEntity( null );
215 | return true;
216 | },
217 |
218 |
219 | removeEntity: function( ent ) {
220 | if( ent.name ) {
221 | delete this.namedEntities[ent.name];
222 | }
223 | this.entities.erase( ent );
224 | },
225 |
226 |
227 | cloneSelectedEntity: function() {
228 | if( !this.selectedEntity ) {
229 | return false;
230 | }
231 |
232 | var className = this.selectedEntity._wmClassName;
233 | var settings = ig.copy(this.selectedEntity._wmSettings);
234 | if( settings.name ) {
235 | settings.name = settings.name + '_clone';
236 | }
237 | var x = this.selectedEntity.pos.x + this.gridSize;
238 | var y = this.selectedEntity.pos.y;
239 | var newEntity = this.spawnEntity( className, x, y, settings );
240 | newEntity._wmSettings = settings;
241 | this.selectEntity( newEntity );
242 |
243 | ig.game.undo.commitEntityCreate( newEntity );
244 |
245 | return true;
246 | },
247 |
248 |
249 | dragOnSelectedEntity: function( x, y ) {
250 | if( !this.selectedEntity ) {
251 | return false;
252 | }
253 |
254 |
255 | // scale or move?
256 | if( this.selectedEntity._wmScalable && this.wasSelectedOnScaleBorder ) {
257 | this.scaleSelectedEntity( x, y );
258 | }
259 | else {
260 | this.moveSelectedEntity( x, y )
261 | }
262 |
263 | ig.game.undo.pushEntityEdit( this.selectedEntity );
264 | return true;
265 | },
266 |
267 |
268 | moveSelectedEntity: function( x, y ) {
269 | x =
270 | Math.round( (x - this.selector.offset.x ) / this.gridSize )
271 | * this.gridSize + this.selectedEntity.offset.x;
272 | y =
273 | Math.round( (y - this.selector.offset.y ) / this.gridSize )
274 | * this.gridSize + this.selectedEntity.offset.y;
275 |
276 | // new position?
277 | if( this.selectedEntity.pos.x != x || this.selectedEntity.pos.y != y ) {
278 | $('#entityDefinitionPosX').text( x );
279 | $('#entityDefinitionPosY').text( y );
280 |
281 | this.selectedEntity.pos.x = x;
282 | this.selectedEntity.pos.y = y;
283 | }
284 | },
285 |
286 |
287 | scaleSelectedEntity: function( x, y ) {
288 | var scale = this.wasSelectedOnScaleBorder;
289 |
290 | var w = Math.round( x / this.gridSize ) * this.gridSize - this.selectedEntity.pos.x;
291 |
292 | if( !this.selectedEntity._wmSettings.size ) {
293 | this.selectedEntity._wmSettings.size = {};
294 | }
295 |
296 | if( scale == 'n' ) {
297 | var h = this.selectedEntity.pos.y - Math.round( y / this.gridSize ) * this.gridSize;
298 | if( this.selectedEntity.size.y + h <= this.gridSize ) {
299 | h = (this.selectedEntity.size.y - this.gridSize) * -1;
300 | }
301 | this.selectedEntity.size.y += h;
302 | this.selectedEntity.pos.y -= h;
303 | }
304 | else if( scale == 's' ) {
305 | var h = Math.round( y / this.gridSize ) * this.gridSize - this.selectedEntity.pos.y;
306 | this.selectedEntity.size.y = Math.max( this.gridSize, h );
307 | }
308 | else if( scale == 'e' ) {
309 | var w = Math.round( x / this.gridSize ) * this.gridSize - this.selectedEntity.pos.x;
310 | this.selectedEntity.size.x = Math.max( this.gridSize, w );
311 | }
312 | else if( scale == 'w' ) {
313 | var w = this.selectedEntity.pos.x - Math.round( x / this.gridSize ) * this.gridSize;
314 | if( this.selectedEntity.size.x + w <= this.gridSize ) {
315 | w = (this.selectedEntity.size.x - this.gridSize) * -1;
316 | }
317 | this.selectedEntity.size.x += w;
318 | this.selectedEntity.pos.x -= w;
319 | }
320 | this.selectedEntity._wmSettings.size.x = this.selectedEntity.size.x;
321 | this.selectedEntity._wmSettings.size.y = this.selectedEntity.size.y;
322 |
323 | this.loadEntitySettings();
324 | },
325 |
326 |
327 | newEntityClick: function( ev ) {
328 | this.hideMenu();
329 | var newEntity = this.spawnEntity( ev.target.id, 0, 0, {} );
330 | this.selectEntity( newEntity );
331 | this.moveSelectedEntity( this.selector.pos.x, this.selector.pos.y );
332 | ig.editor.setModified();
333 |
334 | ig.game.undo.commitEntityCreate( newEntity );
335 | },
336 |
337 |
338 | spawnEntity: function( className, x, y, settings ) {
339 | settings = settings || {};
340 | var entityClass = ig.global[ className ];
341 | if( entityClass ) {
342 | var newEntity = new (entityClass)( x, y, settings );
343 | newEntity._wmInEditor = true;
344 | newEntity._wmClassName = className;
345 | newEntity._wmSettings = {};
346 | for( var s in settings ) {
347 | newEntity._wmSettings[s] = settings[s];
348 | }
349 | this.entities.push( newEntity );
350 | if( settings.name ) {
351 | this.namedEntities[settings.name] = newEntity;
352 | }
353 | this.sort();
354 | return newEntity;
355 | }
356 | return null;
357 | },
358 |
359 |
360 | isOnScaleBorder: function( entity, selector ) {
361 | var border = 2;
362 | var w = selector.pos.x - entity.pos.x;
363 | var h = selector.pos.y - entity.pos.y;
364 |
365 | if( w < border ) return 'w';
366 | if( w > entity.size.x - border ) return 'e';
367 |
368 | if( h < border ) return 'n';
369 | if( h > entity.size.y - border ) return 's';
370 |
371 | return false;
372 | },
373 |
374 |
375 |
376 |
377 | // -------------------------------------------------------------------------
378 | // Settings
379 |
380 |
381 | loadEntitySettings: function(ent) {
382 |
383 | if( !this.selectedEntity ) {
384 | return;
385 | }
386 | var html =
387 | 'x:'+this.selectedEntity.pos.x+'
'
388 | + 'y:'+this.selectedEntity.pos.y+'
';
389 |
390 | html += this.loadEntitySettingsRecursive( this.selectedEntity._wmSettings );
391 | this.entityDefinitions.html( html );
392 |
393 | var className = this.selectedEntity._wmClassName.replace(/^Entity/, '');
394 | $('#entityClass').text( className );
395 |
396 | $('.entityDefinition').bind( 'mouseup', this.selectEntitySetting );
397 | },
398 |
399 |
400 | loadEntitySettingsRecursive: function( settings, path ) {
401 | path = path || "";
402 | var html = "";
403 | for( var key in settings ) {
404 | var value = settings[key];
405 | if( typeof(value) == 'object' ) {
406 | html += this.loadEntitySettingsRecursive( value, path + key + "." );
407 | }
408 | else {
409 | html += ''+path+key+':'+value+'
';
410 | }
411 | }
412 |
413 | return html;
414 | },
415 |
416 |
417 | setEntitySetting: function( ev ) {
418 | if( ev.which != 13 ) {
419 | return true;
420 | }
421 | var key = $('#entityKey').val();
422 | var value = $('#entityValue').val();
423 | var floatVal = parseFloat(value);
424 | if( value == floatVal ) {
425 | value = floatVal;
426 | }
427 |
428 | if( key == 'name' ) {
429 | if( this.selectedEntity.name ) {
430 | delete this.namedEntities[this.selectedEntity.name];
431 | }
432 | this.namedEntities[ value ] = this.selectedEntity;
433 | }
434 |
435 | if( key == 'x' ) {
436 | this.selectedEntity.pos.x = Math.round(value);
437 | }
438 | else if( key == 'y' ) {
439 | this.selectedEntity.pos.y = Math.round(value);
440 | }
441 | else {
442 | this.writeSettingAtPath( this.selectedEntity._wmSettings, key, value );
443 | ig.merge( this.selectedEntity, this.selectedEntity._wmSettings );
444 | }
445 |
446 | this.sort();
447 |
448 | ig.game.setModified();
449 | ig.game.draw();
450 |
451 | $('#entityKey').val('');
452 | $('#entityValue').val('');
453 | $('#entityValue').blur();
454 | this.loadEntitySettings();
455 |
456 | $('#entityKey').focus();
457 | return false;
458 | },
459 |
460 |
461 | writeSettingAtPath: function( root, path, value ) {
462 | path = path.split('.');
463 | var cur = root;
464 | for( var i = 0; i < path.length; i++ ) {
465 | var n = path[i];
466 | if( i < path.length-1 && typeof(cur[n]) != 'object' ) {
467 | cur[n] = {};
468 | }
469 |
470 | if( i == path.length-1 ) {
471 | cur[n] = value;
472 | }
473 | cur = cur[n];
474 | }
475 |
476 | this.trimObject( root );
477 | },
478 |
479 |
480 | trimObject: function( obj ) {
481 | var isEmpty = true;
482 | for( var i in obj ) {
483 | if(
484 | (obj[i] === "") ||
485 | (typeof(obj[i]) == 'object' && this.trimObject(obj[i]))
486 | ) {
487 | delete obj[i];
488 | }
489 |
490 | if( typeof(obj[i]) != 'undefined' ) {
491 | isEmpty = false;
492 | }
493 | }
494 |
495 | return isEmpty;
496 | },
497 |
498 |
499 | selectEntitySetting: function( ev ) {
500 | $('#entityKey').val( $(this).children('.key').text() );
501 | $('#entityValue').val( $(this).children('.value').text() );
502 | $('#entityValue').select();
503 | },
504 |
505 |
506 |
507 |
508 |
509 |
510 | // -------------------------------------------------------------------------
511 | // UI
512 |
513 | setHotkey: function( hotkey ) {
514 | this.hotkey = hotkey;
515 | this.div.attr('title', 'Select Layer ('+this.hotkey+')' );
516 | },
517 |
518 |
519 | showMenu: function( x, y ) {
520 | this.selector.pos = {
521 | x: Math.round( (x + ig.editor.screen.x) / this.gridSize ) * this.gridSize,
522 | y: Math.round( (y + ig.editor.screen.y) / this.gridSize ) * this.gridSize
523 | };
524 | this.menu.css({top: (y * ig.system.scale + 2), left: (x * ig.system.scale + 2) });
525 | this.menu.show();
526 | },
527 |
528 |
529 | hideMenu: function( x, y ) {
530 | ig.editor.mode = ig.editor.MODE.DEFAULT;
531 | this.menu.hide();
532 | },
533 |
534 |
535 | setActive: function( active ) {
536 | this.active = active;
537 | if( active ) {
538 | this.div.addClass( 'layerActive' );
539 | } else {
540 | this.div.removeClass( 'layerActive' );
541 | }
542 | },
543 |
544 |
545 | toggleVisibility: function() {
546 | this.visible ^= 1;
547 | if( this.visible ) {
548 | this.div.children('.visible').addClass('checkedVis');
549 | } else {
550 | this.div.children('.visible').removeClass('checkedVis');
551 | }
552 | ig.game.draw();
553 | },
554 |
555 |
556 | toggleVisibilityClick: function( ev ) {
557 | if( !this.active ) {
558 | this.ignoreLastClick = true;
559 | }
560 | this.toggleVisibility()
561 | },
562 |
563 |
564 | click: function() {
565 | if( this.ignoreLastClick ) {
566 | this.ignoreLastClick = false;
567 | return;
568 | }
569 | ig.editor.setActiveLayer( 'entities' );
570 | },
571 |
572 |
573 | mousemove: function( x, y ) {
574 | this.selector.pos = { x: x, y: y };
575 |
576 | if( this.selectedEntity ) {
577 | if( this.selectedEntity._wmScalable && this.selectedEntity.touches(this.selector) ) {
578 | var scale = this.isOnScaleBorder( this.selectedEntity, this.selector );
579 | if( scale == 'n' || scale == 's' ) {
580 | $('body').css('cursor', 'n-resize');
581 | return;
582 | }
583 | else if( scale == 'e' || scale == 'w' ) {
584 | $('body').css('cursor', 'e-resize');
585 | return;
586 | }
587 | }
588 | }
589 |
590 | $('body').css('cursor', 'default');
591 | },
592 |
593 |
594 |
595 |
596 |
597 |
598 | // -------------------------------------------------------------------------
599 | // Drawing
600 |
601 |
602 | draw: function() {
603 | if( this.visible ) {
604 | for( var i = 0; i < this.entities.length; i++ ) {
605 | this.drawEntity( this.entities[i] );
606 | }
607 | }
608 | },
609 |
610 |
611 | drawEntity: function( ent ) {
612 |
613 | // entity itself
614 | ent.draw();
615 |
616 | // box
617 | if( ent._wmDrawBox ) {
618 | ig.system.context.fillStyle = ent._wmBoxColor || 'rgba(128, 128, 128, 0.9)';
619 | ig.system.context.fillRect(
620 | ig.system.getDrawPos(ent.pos.x - ig.game.screen.x),
621 | ig.system.getDrawPos(ent.pos.y - ig.game.screen.y),
622 | ent.size.x * ig.system.scale,
623 | ent.size.y * ig.system.scale
624 | );
625 | }
626 |
627 |
628 | if( wm.config.labels.draw ) {
629 | // description
630 | var className = ent._wmClassName.replace(/^Entity/, '');
631 | var description = className + (ent.name ? ': ' + ent.name : '' );
632 |
633 | // text-shadow
634 | ig.system.context.fillStyle = 'rgba(0,0,0,0.4)';
635 | ig.system.context.fillText(
636 | description,
637 | ig.system.getDrawPos(ent.pos.x - ig.game.screen.x),
638 | ig.system.getDrawPos(ent.pos.y - ig.game.screen.y + 0.5)
639 | );
640 |
641 | // text
642 | ig.system.context.fillStyle = wm.config.colors.primary;
643 | ig.system.context.fillText(
644 | description,
645 | ig.system.getDrawPos(ent.pos.x - ig.game.screen.x),
646 | ig.system.getDrawPos(ent.pos.y - ig.game.screen.y)
647 | );
648 | }
649 |
650 |
651 | // line to targets
652 | if( typeof(ent.target) == 'object' ) {
653 | for( var t in ent.target ) {
654 | this.drawLineToTarget( ent, ent.target[t] );
655 | }
656 | }
657 | },
658 |
659 |
660 | drawLineToTarget: function( ent, target ) {
661 | target = ig.game.getEntityByName( target );
662 | if( !target ) {
663 | return;
664 | }
665 |
666 | ig.system.context.strokeStyle = '#fff';
667 | ig.system.context.lineWidth = 1;
668 |
669 | ig.system.context.beginPath();
670 | ig.system.context.moveTo(
671 | ig.system.getDrawPos(ent.pos.x + ent.size.x/2 - ig.game.screen.x),
672 | ig.system.getDrawPos(ent.pos.y + ent.size.y/2 - ig.game.screen.y)
673 | );
674 | ig.system.context.lineTo(
675 | ig.system.getDrawPos(target.pos.x + target.size.x/2 - ig.game.screen.x),
676 | ig.system.getDrawPos(target.pos.y + target.size.y/2 - ig.game.screen.y)
677 | );
678 | ig.system.context.stroke();
679 | ig.system.context.closePath();
680 | },
681 |
682 |
683 | drawCursor: function( x, y ) {
684 | if( this.selectedEntity ) {
685 | ig.system.context.lineWidth = 1;
686 | ig.system.context.strokeStyle = wm.config.colors.highlight;
687 | ig.system.context.strokeRect(
688 | ig.system.getDrawPos(this.selectedEntity.pos.x - ig.editor.screen.x) - 0.5,
689 | ig.system.getDrawPos(this.selectedEntity.pos.y - ig.editor.screen.y) - 0.5,
690 | this.selectedEntity.size.x * ig.system.scale + 1,
691 | this.selectedEntity.size.y * ig.system.scale + 1
692 | );
693 | }
694 | }
695 | });
696 |
697 | });
--------------------------------------------------------------------------------
/lib/weltmeister/jquery-ui-1.8.1.custom.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * jQuery UI 1.8.1
3 | *
4 | * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
5 | * Dual licensed under the MIT (MIT-LICENSE.txt)
6 | * and GPL (GPL-LICENSE.txt) licenses.
7 | *
8 | * http://docs.jquery.com/UI
9 | */
10 | jQuery.ui||function(c){c.ui={version:"1.8.1",plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e=0;e0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a=0)&&c(a).is(":focusable")}})}(jQuery);
16 | ;/*!
17 | * jQuery UI Widget 1.8.1
18 | *
19 | * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
20 | * Dual licensed under the MIT (MIT-LICENSE.txt)
21 | * and GPL (GPL-LICENSE.txt) licenses.
22 | *
23 | * http://docs.jquery.com/UI/Widget
24 | */
25 | (function(b){var j=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add(this).each(function(){b(this).triggerHandler("remove")});return j.call(b(this),a,c)})};b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]=function(h){return!!b.data(h,a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend({},c.options);b[e][a].prototype=
26 | b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):d;if(e&&d.substring(0,1)==="_")return h;e?this.each(function(){var g=b.data(this,a),i=g&&b.isFunction(g[d])?g[d].apply(g,f):g;if(i!==g&&i!==undefined){h=i;return false}}):this.each(function(){var g=
27 | b.data(this,a);if(g){d&&g.option(d);g._init()}else b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){this.element=b(c).data(this.widgetName,this);this.options=b.extend(true,{},this.options,b.metadata&&b.metadata.get(c)[this.widgetName],a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();
28 | this._init()},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},widget:function(){return this.element},option:function(a,c){var d=a,e=this;if(arguments.length===0)return b.extend({},e.options);if(typeof a==="string"){if(c===undefined)return this.options[a];d={};d[a]=c}b.each(d,function(f,
29 | h){e._setOption(f,h)});return e},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",c);return this},enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=
30 | b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);
31 | ;/*!
32 | * jQuery UI Mouse 1.8.1
33 | *
34 | * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
35 | * Dual licensed under the MIT (MIT-LICENSE.txt)
36 | * and GPL (GPL-LICENSE.txt) licenses.
37 | *
38 | * http://docs.jquery.com/UI/Mouse
39 | *
40 | * Depends:
41 | * jquery.ui.widget.js
42 | */
43 | (function(c){c.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var a=this;this.element.bind("mousedown."+this.widgetName,function(b){return a._mouseDown(b)}).bind("click."+this.widgetName,function(b){if(a._preventClickEvent){a._preventClickEvent=false;b.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName)},_mouseDown:function(a){a.originalEvent=a.originalEvent||{};if(!a.originalEvent.mouseHandled){this._mouseStarted&&
44 | this._mouseUp(a);this._mouseDownEvent=a;var b=this,e=a.which==1,f=typeof this.options.cancel=="string"?c(a.target).parents().add(a.target).filter(this.options.cancel).length:false;if(!e||f||!this._mouseCapture(a))return true;this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){b.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a)){this._mouseStarted=this._mouseStart(a)!==false;if(!this._mouseStarted){a.preventDefault();
45 | return true}}this._mouseMoveDelegate=function(d){return b._mouseMove(d)};this._mouseUpDelegate=function(d){return b._mouseUp(d)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);c.browser.safari||a.preventDefault();return a.originalEvent.mouseHandled=true}},_mouseMove:function(a){if(c.browser.msie&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&
46 | this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=a.target==this._mouseDownEvent.target;this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-
47 | a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery);
48 | ;/*
49 | * jQuery UI Sortable 1.8.1
50 | *
51 | * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
52 | * Dual licensed under the MIT (MIT-LICENSE.txt)
53 | * and GPL (GPL-LICENSE.txt) licenses.
54 | *
55 | * http://docs.jquery.com/UI/Sortables
56 | *
57 | * Depends:
58 | * jquery.ui.core.js
59 | * jquery.ui.mouse.js
60 | * jquery.ui.widget.js
61 | */
62 | (function(d){d.widget("ui.sortable",d.ui.mouse,{widgetEventPrefix:"sort",options:{appendTo:"parent",axis:false,connectWith:false,containment:false,cursor:"auto",cursorAt:false,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:"original",items:"> *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){this.containerCache={};this.element.addClass("ui-sortable");
63 | this.refresh();this.floating=this.items.length?/left|right/.test(this.items[0].item.css("float")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData("sortable-item");return this},_setOption:function(a,b){if(a==="disabled"){this.options[a]=b;this.widget()[b?"addClass":"removeClass"]("ui-sortable-disabled")}else d.Widget.prototype._setOption.apply(self,
64 | arguments)},_mouseCapture:function(a,b){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(a);var c=null,e=this;d(a.target).parents().each(function(){if(d.data(this,"sortable-item")==e){c=d(this);return false}});if(d.data(a.target,"sortable-item")==e)c=d(a.target);if(!c)return false;if(this.options.handle&&!b){var f=false;d(this.options.handle,c).find("*").andSelf().each(function(){if(this==a.target)f=true});if(!f)return false}this.currentItem=
65 | c;this._removeCurrentsFromItems();return true},_mouseStart:function(a,b,c){b=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(a);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");d.extend(this.offset,
66 | {click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();b.containment&&this._setContainment();
67 | if(b.cursor){if(d("body").css("cursor"))this._storedCursor=d("body").css("cursor");d("body").css("cursor",b.cursor)}if(b.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",b.opacity)}if(b.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",b.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start",
68 | a,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!c)for(c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("activate",a,e._uiHash(this));if(d.ui.ddmanager)d.ui.ddmanager.current=this;d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(a);return true},_mouseDrag:function(a){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");
69 | if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var b=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-a.pageY=0;b--){c=this.items[b];var e=c.item[0],f=this._intersectsWithPointer(c);if(f)if(e!=this.currentItem[0]&&this.placeholder[f==1?"next":"prev"]()[0]!=e&&!d.ui.contains(this.placeholder[0],e)&&(this.options.type=="semi-dynamic"?!d.ui.contains(this.element[0],e):true)){this.direction=f==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(c))this._rearrange(a,
73 | c);else break;this._trigger("change",a,this._uiHash());break}}this._contactContainers(a);d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);this._trigger("sort",a,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(a,b){if(a){d.ui.ddmanager&&!this.options.dropBehaviour&&d.ui.ddmanager.drop(this,a);if(this.options.revert){var c=this;b=c.placeholder.offset();c.reverting=true;d(this.helper).animate({left:b.left-this.offset.parent.left-c.margins.left+(this.offsetParent[0]==
74 | document.body?0:this.offsetParent[0].scrollLeft),top:b.top-this.offset.parent.top-c.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(a)})}else this._clear(a,b);return false}},cancel:function(){var a=this;if(this.dragging){this._mouseUp();this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var b=this.containers.length-1;b>=0;b--){this.containers[b]._trigger("deactivate",
75 | null,a._uiHash(this));if(this.containers[b].containerCache.over){this.containers[b]._trigger("out",null,a._uiHash(this));this.containers[b].containerCache.over=0}}}this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();d.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});this.domPosition.prev?d(this.domPosition.prev).after(this.currentItem):
76 | d(this.domPosition.parent).prepend(this.currentItem);return this},serialize:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};d(b).each(function(){var e=(d(a.item||this).attr(a.attribute||"id")||"").match(a.expression||/(.+)[-=_](.+)/);if(e)c.push((a.key||e[1]+"[]")+"="+(a.key&&a.expression?e[1]:e[2]))});return c.join("&")},toArray:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};b.each(function(){c.push(d(a.item||this).attr(a.attribute||"id")||"")});return c},
77 | _intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,e=this.positionAbs.top,f=e+this.helperProportions.height,g=a.left,h=g+a.width,i=a.top,k=i+a.height,j=this.offset.click.top,l=this.offset.click.left;j=e+j>i&&e+jg&&b+la[this.floating?"width":"height"]?j:g0?"down":"up")},_getDragHorizontalDirection:function(){var a=
80 | this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a);this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(a){var b=[],c=[],e=this._connectWith();if(e&&a)for(a=e.length-1;a>=0;a--)for(var f=d(e[a]),g=f.length-1;g>=0;g--){var h=d.data(f[g],"sortable");if(h&&h!=this&&!h.options.disabled)c.push([d.isFunction(h.options.items)?
81 | h.options.items.call(h.element):d(h.options.items,h.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),h])}c.push([d.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):d(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(a=c.length-1;a>=0;a--)c[a][0].each(function(){b.push(this)});return d(b)},_removeCurrentsFromItems:function(){for(var a=this.currentItem.find(":data(sortable-item)"),
82 | b=0;b=0;f--)for(var g=d(e[f]),h=g.length-1;h>=0;h--){var i=d.data(g[h],"sortable");if(i&&i!=this&&!i.options.disabled){c.push([d.isFunction(i.options.items)?
83 | i.options.items.call(i.element[0],a,{item:this.currentItem}):d(i.options.items,i.element),i]);this.containers.push(i)}}for(f=c.length-1;f>=0;f--){a=c[f][1];e=c[f][0];h=0;for(g=e.length;h=0;b--){var c=this.items[b],e=this.options.toleranceElement?d(this.options.toleranceElement,
84 | c.item):c.item;if(!a){c.width=e.outerWidth();c.height=e.outerHeight()}e=e.offset();c.left=e.left;c.top=e.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(b=this.containers.length-1;b>=0;b--){e=this.containers[b].element.offset();this.containers[b].containerCache.left=e.left;this.containers[b].containerCache.top=e.top;this.containers[b].containerCache.width=this.containers[b].element.outerWidth();this.containers[b].containerCache.height=
85 | this.containers[b].element.outerHeight()}return this},_createPlaceholder:function(a){var b=a||this,c=b.options;if(!c.placeholder||c.placeholder.constructor==String){var e=c.placeholder;c.placeholder={element:function(){var f=d(document.createElement(b.currentItem[0].nodeName)).addClass(e||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!e)f.style.visibility="hidden";return f},update:function(f,g){if(!(e&&!c.forcePlaceholderSize)){g.height()||g.height(b.currentItem.innerHeight()-
86 | parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));g.width()||g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10))}}}}b.placeholder=d(c.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);c.placeholder.update(b,b.placeholder)},_contactContainers:function(a){for(var b=null,c=null,e=this.containers.length-1;e>=0;e--)if(!d.ui.contains(this.currentItem[0],
87 | this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(b&&d.ui.contains(this.containers[e].element[0],b.element[0]))){b=this.containers[e];c=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger("out",a,this._uiHash(this));this.containers[e].containerCache.over=0}if(b)if(this.containers.length===1){this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}else if(this.currentContainer!=this.containers[c]){b=
88 | 1E4;e=null;for(var f=this.positionAbs[this.containers[c].floating?"left":"top"],g=this.items.length-1;g>=0;g--)if(d.ui.contains(this.containers[c].element[0],this.items[g].item[0])){var h=this.items[g][this.containers[c].floating?"left":"top"];if(Math.abs(h-f)this.containment[2])f=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.topthis.containment[3])?g:!(g-this.offset.click.topthis.containment[2])?f:!(f-this.offset.click.left=0;e--)if(d.ui.contains(this.containers[e].element[0],this.currentItem[0])&&!b){c.push(function(f){return function(g){f._trigger("receive",g,this._uiHash(this))}}.call(this,this.containers[e]));c.push(function(f){return function(g){f._trigger("update",
104 | g,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){b||c.push(function(f){return function(g){f._trigger("deactivate",g,this._uiHash(this))}}.call(this,this.containers[e]));if(this.containers[e].containerCache.over){c.push(function(f){return function(g){f._trigger("out",g,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over=0}}this._storedCursor&&d("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",
105 | this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!b){this._trigger("beforeStop",a,this._uiHash());for(e=0;e 0 ? this.collisionSolid : 0;
844 |
845 | var oldCollisionTile = this.collisionLayer.getOldTile(mapx, mapy);
846 | this.collisionLayer.setTile( mapx, mapy, collisionLayerTile );
847 | this.undo.pushMapDraw( this.collisionLayer, mapx, mapy, oldCollisionTile, collisionLayerTile );
848 | }
849 | }
850 | }
851 |
852 | this.setModified();
853 | },
854 |
855 |
856 | // -------------------------------------------------------------------------
857 | // Drawing
858 |
859 | draw: function() {
860 | // The actual drawing loop is scheduled via ig.setAnimation() already.
861 | // We just set a flag to indicate that a redraw is needed.
862 | this.needsDraw = true;
863 | },
864 |
865 |
866 | drawIfNeeded: function() {
867 | // Only draw if flag is set
868 | if( !this.needsDraw ) { return; }
869 | this.needsDraw = false;
870 |
871 |
872 | ig.system.clear( wm.config.colors.clear );
873 |
874 | var entitiesDrawn = false;
875 | for( var i = 0; i < this.layers.length; i++ ) {
876 | var layer = this.layers[i];
877 |
878 | // This layer is a foreground layer? -> Draw entities first!
879 | if( !entitiesDrawn && layer.foreground ) {
880 | entitiesDrawn = true;
881 | this.entities.draw();
882 | }
883 | layer.draw();
884 | }
885 |
886 | if( !entitiesDrawn ) {
887 | this.entities.draw();
888 | }
889 |
890 |
891 | if( this.activeLayer ) {
892 | if( this.mode == this.MODE.TILESELECT ) {
893 | this.activeLayer.tileSelect.draw();
894 | this.activeLayer.tileSelect.drawCursor( ig.input.mouse.x, ig.input.mouse.y );
895 | }
896 |
897 | if( this.mode == this.MODE.DEFAULT ) {
898 | this.activeLayer.drawCursor( ig.input.mouse.x, ig.input.mouse.y );
899 | }
900 | }
901 |
902 | if( wm.config.labels.draw ) {
903 | this.drawLabels( wm.config.labels.step );
904 | }
905 | },
906 |
907 |
908 | drawLabels: function( step ) {
909 | ig.system.context.fillStyle = wm.config.colors.primary;
910 | var xlabel = this.screen.x - this.screen.x % step - step;
911 | for( var tx = Math.floor(-this.screen.x % step); tx < ig.system.width; tx += step ) {
912 | xlabel += step;
913 | ig.system.context.fillText( xlabel, tx * ig.system.scale, 0 );
914 | }
915 |
916 | var ylabel = this.screen.y - this.screen.y % step - step;
917 | for( var ty = Math.floor(-this.screen.y % step); ty < ig.system.height; ty += step ) {
918 | ylabel += step;
919 | ig.system.context.fillText( ylabel, 0, ty * ig.system.scale );
920 | }
921 | },
922 |
923 |
924 | getEntityByName: function( name ) {
925 | return this.entities.getEntityByName( name );
926 | }
927 | });
928 |
929 |
930 | wm.Weltmeister.getMaxWidth = function() {
931 | return $(window).width();
932 | };
933 |
934 | wm.Weltmeister.getMaxHeight = function() {
935 | return $(window).height() - $('#headerMenu').height();
936 | };
937 |
938 |
939 | // Custom ig.Image class for use in Weltmeister. To make the zoom function
940 | // work, we need some additional scaling behavior:
941 | // Keep the original image, maintain a cache of scaled versions and use the
942 | // default Canvas scaling (~bicubic) instead of nearest neighbor when
943 | // zooming out.
944 | ig.Image.inject({
945 | resize: function( scale ) {
946 | if( !this.loaded ) { return; }
947 | if( !this.scaleCache ) { this.scaleCache = {}; }
948 | if( this.scaleCache['x'+scale] ) {
949 | this.data = this.scaleCache['x'+scale];
950 | return;
951 | }
952 |
953 | // Retain the original image when scaling
954 | this.origData = this.data = this.origData || this.data;
955 |
956 | if( scale > 1 ) {
957 | // Nearest neighbor when zooming in
958 | this.parent( scale );
959 | }
960 | else {
961 | // Otherwise blur
962 | var scaled = ig.$new('canvas');
963 | scaled.width = Math.ceil(this.width * scale);
964 | scaled.height = Math.ceil(this.height * scale);
965 | var scaledCtx = scaled.getContext('2d');
966 | scaledCtx.drawImage( this.data, 0, 0, this.width, this.height, 0, 0, scaled.width, scaled.height );
967 | this.data = scaled;
968 | }
969 |
970 | this.scaleCache['x'+scale] = this.data;
971 | }
972 | });
973 |
974 |
975 |
976 | // Create a custom loader, to skip sound files and the run loop creation
977 | wm.Loader = ig.Loader.extend({
978 | end: function() {
979 | if( this.done ) { return; }
980 |
981 | clearInterval( this._intervalId );
982 | this.done = true;
983 | ig.system.clear( wm.config.colors.clear );
984 | ig.game = new (this.gameClass)();
985 | },
986 |
987 | loadResource: function( res ) {
988 | if( res instanceof ig.Sound ) {
989 | this._unloaded.erase( res.path );
990 | }
991 | else {
992 | this.parent( res );
993 | }
994 | }
995 | });
996 |
997 |
998 | // Define a dummy module to load all plugins
999 | ig.module('weltmeister.loader').requires.apply(ig, wm.config.plugins).defines(function(){
1000 | // Init!
1001 | ig.system = new ig.System(
1002 | '#canvas', 1,
1003 | Math.floor(wm.Weltmeister.getMaxWidth() / wm.config.view.zoom),
1004 | Math.floor(wm.Weltmeister.getMaxHeight() / wm.config.view.zoom),
1005 | wm.config.view.zoom
1006 | );
1007 |
1008 | ig.input = new wm.EventedInput();
1009 | ig.soundManager = new ig.SoundManager();
1010 | ig.ready = true;
1011 |
1012 | var loader = new wm.Loader( wm.Weltmeister, ig.resources );
1013 | loader.load();
1014 | });
1015 |
1016 | });
1017 |
--------------------------------------------------------------------------------