+ // shortcuts for animation
+ this.block = () => this.animate("block" );
+ this.cast = () => this.animate("cast" );
+ this.die = () => this.animate("die" );
+ this.hit = () => this.animate("hit" );
+ this.run = () => this.animate("run" );
+ this.shoot = () => this.animate("shoot" );
+ this.stance = () => this.animate("stance");
+ this.swing = () => this.animate("swing" );
+}
+
+function Controls(hero){
+ // processes keyboard / touch / mouse
+ // causes according player actions
+ // single player only, conrol will be assigned to server in multi player
+ var kbdmap = {
+ up: 87, altup: 38,
+ down: 83, altdown: 40,
+ left: 65, altleft: 37,
+ right: 68, altright: 39,
+ }
+ var keys = [];
+
+ window.addEventListener("keydown", e => keys[e.keyCode] = true );
+ window.addEventListener("keyup" , e => keys[e.keyCode] = false);
+ setInterval(() => input(), 33.33)
+
+ // cause player to walk, processes blocked terrain and player speed
+ // x/y are factors of speed and direction
+ // i.e. +/-1 for diagonal movement
+ // and +/-1.4 for horizontal/vertical movement
+ function translate(x, y){
+ var sx = map.info.header.tilewidth * hero.stats.speed / 33.33;
+ var sy = map.info.header.tileheight * hero.stats.speed / 33.33;
+ var dx = x * sx, hx = hero.position[0];
+ var dy = y * sy, hy = hero.position[1];
+ var f = 2.1;
+ const col = map.info.layer.find(l => l.type == "collision").data;
+
+ if (col[map.tileAt(hx + dx, hy + dy)] == 0 )
+ hero.place(hx + dx, hy + dy);
+ else if ( dy == 0 && col[map.tileAt(hx + dx / f, hy + sy / 1.5)] == 0 )
+ hero.place(hx + dx / f, hy + sy / 1.5);
+ else if ( dy == 0 && col[map.tileAt(hx + dx / f, hy - sy / 1.5)] == 0 )
+ hero.place(hx + dx / f, hy - sy / 1.5);
+ else if ( dx == 0 && col[map.tileAt(hx + sx / 1.5, hy + dy / f)] == 0 )
+ hero.place(hx + sx / 1.5, hy + dy / f);
+ else if ( dx == 0 && col[map.tileAt(hx - sx / 1.5, hy + dy / f)] == 0 )
+ hero.place(hx - sx / 1.5, hy + dy / f);
+ else player.stance();
+
+ map.center(hero.position[0], hero.position[1]);
+ events(hero.position[0], hero.position[1]);
+ }
+
+ function events(x, y) {
+ const i = map.tileAt(x,y); let ev, e, n;
+ if (map.events[i]) {
+ // intramap (teleporters)
+ if ( ev = map.events[i].find(e => (e.activate == "on_trigger" && e.intramap)) ){
+ ev = ev.intramap;
+ hero.place( map.xOf(ev[0], ev[1]), map.yOf(ev[0], ev[1]) );
+ map.center( map.xOf(ev[0], ev[1]), map.yOf(ev[0], ev[1]) );
+ }
+ // mapmod (e.g. opening doors, activating platforms, changing terrain, ...)
+ for (ev of map.events[i].filter(e => (e.activate == "on_trigger" && e.mapmod)) ){
+ for (ev of ev.mapmod)
+ map.info.layer.find(l => l.type == ev[0]).data[ev[2] * map.info.header.width + ev[1]] = ev[3];
+ }
+ // intermap (must be last because loading new map breaks further event search)
+ if ( ev = map.events[i].find(e => (e.activate == "on_trigger" && e.intermap)) ){
+ ev = ev.intermap;
+ map = new Map(ev[0]);
+ hero.place( map.xOf(ev[1], ev[2]), map.yOf(ev[1], ev[2]) );
+ map.center( map.xOf(ev[1], ev[2]), map.yOf(ev[1], ev[2]) );
+ }
+ }
+ }
+
+ // process input and decide on according action
+ function input(){
+ // facing directions, indexed by OR of key press combinations
+ const dir = [ -1, 0, 4, -1, 2, 1, 3, 2, 6, 7, 5, 6, -1, 0, 4, -1 ];
+ // translation speed and direction, indexed by facing direction of movement
+ const trans = [ [-1.4,0], [-1,-1], [0,-1.4], [1,-1], [1.4,0], [1,1], [0,1.4], [-1,1] ];
+ var k = 0;
+
+ // OR of direction key presses
+ k += (keys[kbdmap.left] || keys[kbdmap.altleft]) ? 1 : 0;
+ k += (keys[kbdmap.right] || keys[kbdmap.altright]) ? 2 : 0;
+ k += (keys[kbdmap.up] || keys[kbdmap.altup]) ? 4 : 0;
+ k += (keys[kbdmap.down] || keys[kbdmap.altdown]) ? 8 : 0;
+
+ if (~dir[k]) {
+ hero.direct(dir[k]).run();
+ translate(trans[dir[k]][0], trans[dir[k]][1]);
+ } else hero.stance();
+ }