4 function Textfile(txtfile) {
5 var lines, fetch = new XMLHttpRequest();
6 fetch.open("GET", txtfile, false);
9 var line, key, value, ref = this, section;
10 for (line of fetch.responseText.split('\n')) switch(true) {
11 case /^\[.*\]$/.test(line):
12 section = line.split(/[\]\[]/)[1];
13 if (!this[section]) this[section] = {};
14 else if (!Array.isArray(this[section])) this[section] = [this[section],{}];
15 else if ( Array.isArray(this[section])) this[section].push({});
18 case /^frame=[0-9]+,[0-7](,[0-9-]+){6}$/.test(line):
19 key = line.split(/[=,]/).slice(1,3); value = line.split(/,/).slice(-6);
20 if (!ref.frame) ref.frame = [];
21 if (!ref.frame[key[0]]) ref.frame[key[0]] = [];
22 ref.frame[key[0]][key[1]] = value;
24 case /^layer=[0-9]+,/.test(line):
25 key = line.split(/[=,]/)[1]; value = line.split(/,/).slice(1);
26 if (!ref.layer) ref.layer = [];
27 ref.layer[key] = value;
29 case /^duration=[0-9]+ms$/.test(line):
30 ref["duration"] = parseInt(line.split(/=|ms$/)[1]);
32 case /^duration=[0-9]+s$/.test(line):
33 ref["duration"] = parseInt(line.split(/=|s$/)[1]) * 1000;
35 case /^[^#].*=.+$/.test(line):
36 key = line.split(/[=]/)[0]; value = line.split(/=/).slice(1).join("=");
37 if (!ref[key]) ref[key] = value;
38 else if (!Array.isArray(ref[key])) ref[key] = [ref[key],value];
39 else if ( Array.isArray(ref[key])) ref[key].push(value);
44 function Mob(textdef) {
45 if (! gamedata[textdef]) gamedata[textdef] = new Textfile(textdef);
46 this.info = gamedata[textdef];
48 this.position = [0, 0];
49 this.animation = "stance";
50 this.previous_animation = "";
51 this.frametime = performance.now();
52 if (! gfx[this.info.image]) {
53 gfx[this.info.image] = document.createElement("img");
54 gfx[this.info.image].setAttribute("src", this.info.image);
57 this.place = function(x, y) { this.position = [x, y]; return this; }
58 this.direct = function(d) { this.direction = d % 8; return this; }
59 this.animate = function(a) {
60 this.previous_animation = this.animation;
62 this.frametime = performance.now();
66 this.draw = function(){
67 var f, a = this.info[this.animation];
68 var frame = ( performance.now() - this.frametime ) * a.frames / a.duration | 0;
72 frame = frame % a.frames;
75 if ( frame >= a.frames ){
76 this.animation = this.previous_animation;
77 this.previous_animation = "";
78 this.frametime = performance.now();
79 a = this.info[this.animation];
84 frame = frame % (a.frames * 2 - 2);
85 if ( frame >= a.frames ){
86 frame = a.frames - frame % a.frames - 1;
91 f = a.frame[frame][this.direction];
93 canvas.drawImage(gfx[this.info.image], f[0], f[1], f[2], f[3],
94 this.position[0] - f[4], this.position[1] - f[5],
100 function Hero(gender = "female", hair = "short"){
101 this.position = [0,0]; this.direction = 0;
103 if (! gamedata["/engine/hero_layers.txt"])
104 gamedata["/engine/hero_layers.txt"] = new Textfile("/engine/hero_layers.txt");
106 head : (gender == "female")?new Mob("/animations/avatar/female/head_long.txt")
107 :new Mob("/animations/avatar/male/head_"+hair+".txt"),
108 chest: new Mob("/animations/avatar/"+gender+"/default_chest.txt"),
109 hands: new Mob("/animations/avatar/"+gender+"/default_hands.txt"),
110 legs : new Mob("/animations/avatar/"+gender+"/default_legs.txt"),
111 feet : new Mob("/animations/avatar/"+gender+"/default_feet.txt"),
112 main : new Mob("/animations/avatar/"+gender+"/dagger.txt"),
113 off : new Mob("/animations/avatar/"+gender+"/shield.txt")
116 this.place = function(x,y) {
117 this.position = [x,y];
118 for (var limb in this.limbs) this.limbs[limb].place(x,y);
121 this.direct = function(d) {
123 for (var limb in this.limbs) this.limbs[limb].direct(d);
126 this.animate = function(anim){
127 for (var limb in this.limbs) this.limbs[limb].animate(anim);
130 this.draw = function(){
131 gamedata["/engine/hero_layers.txt"].layer[this.direction].forEach(limb => this.limbs[limb].draw());
136 canvas = document.getElementById("view").getContext("2d");
137 player = new Hero().place(240, 160).direct(5);
139 setInterval( function() { canvas.clearRect(0,0, 480, 320); player.draw(); }, 50);