{ // OOP-Setup, thanks to Florian Rappl for this piece of Code // Source: // http://www.florian-rappl.de/Articles/Page/116/super-mario5-article var reflection = {}; (function(){ var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; // The base Class implementation (does nothing) this.Class = function(){ }; // Create a new Class that inherits from this class Class.extend = function(prop, ref_name) { if(ref_name) reflection[ref_name] = Class; var _super = this.prototype; // Instantiate a base class (but only create the instance, // don't run the init constructor) initializing = true; var prototype = new this(); initializing = false; // Copy the properties over onto the new prototype for (var name in prop) { // Check if we're overwriting an existing function prototype[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ? (function(name, fn) { return function() { var tmp = this._super; // Add a new ._super() method that is the same method // but on the super-class this._super = _super[name]; // The method only need to be bound temporarily, so we // remove it when we're done executing var ret = fn.apply(this, arguments); this._super = tmp; return ret; }; })(name, prop[name]) : prop[name]; } // The dummy class constructor function Class() { // All construction is actually done in the init method if ( !initializing && this.init ) this.init.apply(this, arguments); } // Populate our constructed prototype object Class.prototype = prototype; // Enforce the constructor to be what we expect Class.prototype.constructor = Class; // And make this class extendable Class.extend = arguments.callee; return Class; }; })(); // Helper-Funcs var clearoutput = function() { $('#output').empty(); }; var clearui = function() { $('#output').empty(); $('#ui').empty(); }; // Probe-Function: checks, whether a given "effort" is succesfull, according to the rules of DS // Not yet implemented: Tests for values larger than 20 var dice = function(probe) { var diceval = Math.floor(Math.random() * (21 - 1)) + 1; if ( diceval <= probe ) { return diceval; } else { if (diceval === 20) { alert ("Patzer!"); // We need alert here, because most "Patzer" // affect gameplay (dropping equipement and so on) }; return 0; }; }; // Own Classes for Creatures, derived from the Basic Object class from above // Creature is the base class for every "living" (or dead) "being" var Creature = Class.extend({ init: function(info,attributes,properties,drawinfo,battle){ /* info cotains basic information about a Creature: * pname (playername), experience, race, size (as a categorie) * * attributes are personal values that don't change very often: * body, agility and spirit * * properties may change more often, i.e. by weapon bonuses: * strength, hardness, movement, skill (in a crafty way), mind, aura * * drawinfo contains informations needed for graphical representation: * x,y,w,h,col,cx,cy (Coord. of center) */ this.info = {"pname": info["pname"]+"", "experience": info["experience"]*1, "race":info["race"]+"", "size":info["size"]*1}; this.attributes = {"body": attributes["body"]*1, "agility": attributes["agility"]*1, "spirit": attributes["spirit"]*1}; this.properties = {"strength": properties["strength"]*1 , "hardness": properties["hardness"]*1, "movement": properties["movement"]*1, "skill": properties["skill"]*1, "mind": properties["mind"]*1, "aura": properties["aura"]*1}; this.graphelement = Crafty.e("Creature").creature(this.info["pname"],drawinfo["x"],drawinfo["y"], drawinfo["w"],drawinfo["h"],drawinfo["col"]); /* Battle-info may either be set as an argument, or need to be calculated from attributes * and properties */ this.battle_base = {}; this.battle={}; if(battle) { this.battle_base={"life": battle["life"]*1, "defense": battle["defense"]*1,"ini":battle["ini"]*1, "walk": battle["walk"]*1, "melee": battle["melee"]*1, "shoot": battle["shoot"]*1, "chant": battle["chant"]*1, "shoot_chant": battle["shoot_chant"]*1}; } else { this.calc_battle_base(); }; for ( var i in this.battle_base ) { this.battle[i] = this.battle_base[i]; }; /* Some special attributes: We need two "life" variables, one to have the maximum value * (the one used within battle), the other to see whether a character is dead or unconscious. */ this.life = this.battle_base["life"]*1; /* Curent attack and whether it is defendible */ this.att = "melee"; this.defendible = true; }, /* Attack by now follows only basic rules, the gamemaster has to be sure that an attack is allowed * (distance), and that no modifier applies (distance-shot, other targets within range) */ attack: function(enem) { clearoutput(); var output=$('#output'); output.html(this.info.cname+" greift "+enem.info.cname+" an!<br>"); var attack_val = dice(this.battle[this.att]); if (! attack_val ) { output.append('Angriff Fehlgeschlagen!<br>'); } else { output.append(this.info.cname + " trifft mit " + attack_val + "<br>"); if ( this.defendible ) { var defense_val = dice(this.battle.defense); console.log(attack_val + ", " + defense_val); attack_val -= defense_val; attack_val = Math.max(attack_val, 0); if ( ! defense_val ) { output.append(enem.info.cname + " kann sich nicht wehren!<br>"); } else { output.append(enem.info.cname + " wehrt sich mit " + defense_val+".<br>"); } if ( attack_val === 0 ) { output.append("Vollständig Abgewehrt!<br>"); return; } } else { output.append("Nicht abwehrbar!<br>"); }; output.append("Schaden: "+attack_val+"<br>"); enem.life -= attack_val; // If an "enemie" dies, he should really die, a player-char should only get "unconcious" if( enem.life <= 0 ) { if ( enem.enem ){ output.append(enem.info.cname + " ist besiegt<br>"); enem.die(); } else { output.append(enem.info.cname + " ist bewusstlos<br>"); enem.unconsc(); }; } } }, calc_battle_base: function() { // This is given by DS-Rules this.battle_base["life"] = this.attributes.body + this.properties.strength + 10;; this.battle_base["defense"] = this.attributes.body + this.properties.hardness; this.battle_base["ini"] = this.attributes.agility + this.properties.movement; this.battle_base["walk"] = (this.attributes.agility / 2) +1; this.battle_base["melee"] = this.attributes.body + this.properties.strength; this.battle_base["shoot"] = this.attributes.agility + this.properties.mind; this.battle_base["chant"] = this.attributes.spirit + this.properties.aura; this.battle_base["shoot_chant"] = this.attributes.spirit + this.properties.skill; }, // The next three funcs are self-explaining die: function() { this.graphelement.destroy(); delete(player[this.info.pname]); }, unconsc: function() { this.graphelement.oldcolor = this.graphelement.color(); this.graphelement.color("#A0A0C0"); }, consc: function() { if ( this.graphelement.oldcolor ) { this.graphelement.color(this.graphelement.oldcolor); } }, // Write out the UI for attack-selection, including binding. sel_att: function() { var outstr="<p>"; outstr += "Angriffstyp?<br>"; outstr += "<select id='att'>"; outstr += "<option value='melee' id='melee'>Melee (" + this.battle["melee"] + ")</option>"; outstr += "<option value='shoot' id='shoot'>Schuss (" + this.battle["shoot"] + ")</option>"; outstr += "<option value='shoot_chant' id='shoot_chant'>Zielzauber (" +this.battle["shoot_chant"] +")</option>"; outstr += "</select><br>"; outstr += "Abwehrbar? "; outstr += "<select id='defendible'>"; outstr += "<option value=true selected=true>Ja</option>"; outstr += "<option value=false>Nein</option>"; outstr += "</p>"; $('#uiatt').html(outstr); $('#att').bind("change", function() { cur_sel.att=this.value; cur_sel.printoutput(); }); $('#defendible').bind("change", function() { cur_sel.defendible = (this.value === "true" ? true : false); cur_sel.printoutput(); }); $("#"+this.att).get(0).selected="true"; }, calc_dist: function() { var g = this.graphelement; g.calc_center(); var dx = Math.abs(g.cx - g.old_pos["cx"]); var dy = Math.abs(g.cy - g.old_pos.cy); var distpx= Math.sqrt(dx*dx + dy*dy); return (distpx/meters).toFixed(1); } }); // Maybe the most important class in here var Player = Creature.extend({ init: function(info,attributes,properties,drawinfo,battle){ // x,y,w,h,col) { /* Additional to Creature, Player has: * info: Charactername, Class (Human? Elve), Level * extern: for battle modifiers such as weapons * An info-function printing the basic informations */ this._super(info,attributes,properties,drawinfo,battle); this.info["cname"]= info["cname"]+""; this.info["class"]= info["class"]+""; this.info["level"]= info["level"]*1; // Set default battle-properties. this.extern = {"armor":0,"chant":0,"weapon_far":0,"weapon_near":0}; this.recalc_battle(); }, recalc_battle: function() { this.battle.defense = this.battle_base.defense + this.extern.armor; this.battle.melee = this.battle_base.melee + this.extern.weapon_near; this.battle.shoot = this.battle_base.shoot + this.extern.weapon_far; this.battle.chant = this.battle_base.chant + this.extern.chant - this.extern.armor; this.battle.shoot_chant = this.battle_base.chant + this.extern.chant - this.extern.armor; }, // Write out the UI for bonus-selection. sel_bon: function() { var outstr="<p>"; outstr += "Boni?<br>"; outstr += "Waffenbonus Nahkampf: <input id='wbn' type=numer step=1 min=0></input><br />"; outstr += "Waffenbonus Fernkampf: <input id='wbf' type=numer step=1 min=0></input><br>"; outstr += "Panzerungsbonus: <input id='pb' type=numer step=1 min=0></input><br>"; outstr += "Zauberbonus: <input id='zb' type=numer step=1 min=0></input><br>"; $('#uibon').html(outstr); $('#wbn').attr("value", cur_sel.extern.weapon_near+"") .bind("change", function() {cur_sel.extern.weapon_near = this.value*1; cur_sel.recalc_battle(); cur_sel.printoutput(); } ); $('#wbf').attr("value", cur_sel.extern.weapon_far) .bind("change", function() {cur_sel.extern.weapon_far = this.value*1; cur_sel.recalc_battle(); cur_sel.printoutput(); } ); $('#pb').attr("value",cur_sel.extern.armor) .bind("change", function() {cur_sel.extern.armor = this.value*1; cur_sel.recalc_battle(); cur_sel.printoutput(); } ); $('#zb').attr("value",cur_sel.extern.chant) .bind("change", function() {cur_sel.extern.chant = this.value*1; cur_sel.recalc_battle(); cur_sel.printoutput(); } ); }, printoutput: function() { outstr = "<p>"; outstr += this.info.cname + " (gespielt von "+this.info.pname +")<br>"; outstr += "Greift derzeit durch " + this.att + " mit einer Stärke von " + this.battle[this.att] + " an.<br>"; outstr += "Ist "+this.calc_dist()+"m von der alten Position entfernt (max ??)<br>"; outstr += "Verteidigungsstärke: " + this.battle.defense + "<br>"; outstr += "Kraftpunkte: " + this.life; outstr += "</p>"; $('#output').html(outstr); } }); var Beast = Creature.extend({ init: function(info,attributes,properties,drawinfo,battle){ /* Additional to Creature, a Beast has: * Cname for compability reasons in some functions, set to match pname * the "enem"-bool, specifying it as an enemy that really dies * A print-function as in Player */ this._super(info,attributes,properties,drawinfo,battle); this.info.cname=this.info.pname; this.enem = true; }, printoutput: function() { clearoutput(); outstr = "<p>"; outstr += "Ein "+ this.info.race + "<br>"; outstr += "Greift derzeit durch " + this.att + " mit einer Stärke von " + this.battle[this.att] + " an.<br>"; outstr += "Ist "+this.calc_dist()+"m von der alten Position entfernt (max ??)<br>"; outstr += "Verteidigungsstärke: " + this.battle.defense + "<br>"; outstr += "Kraftpunkte: " + this.life; outstr += "</p>"; $('#output').html(outstr); } }); }