/*
 * ProtoRPG game engine 0.1.1
 * Copyright Pierre Chassaing 2008 All Rights Reserved
 * This software is NOT free, see http://www.protorpg.com for licence
 */
if(!String.prototype.upperFirst){String.prototype.upperFirst=function(A){return(this.substr(0,1).toUpperCase()+this.substr(1))}}if(!String.prototype.stripArticle){String.prototype.stripArticle=function(A){return this.replace(/^(some|a|an|the)\s/,"")}}if(!Array.prototype.indexOfObject){Array.prototype.indexOfObject=function(C,B){var A=0;while(A<this.length&&this[A][C]!=B){A++}return(A<this.length)?A:-1}}if(!Number.prototype.limit){Number.prototype.limit=function(B,A){return Math.max(B,Math.min(this,A))}}if(!Math.throwDice){Math.throwDice=function(B,A,F){var E=0;if(B){if(F){var D=[],C;for(C=0;C<B;C++){D.push(1+Math.min(A-1,Math.floor(Math.random()*A)))}D.sort().reverse().splice(F);for(C=0;C<D.length;C++){E+=D[C]}}else{for(C=0;C<B;C++){E+=1+Math.min(A-1,Math.floor(Math.random()*A))}}}return E}}if(!Math.unique){Math.unique=function(){return Math.floor(Math.random()*10000)%1000}}if(!Math.toSignedString){Math.toSignedString=function(A){A=A||0;return(A>=0)?"+"+A:A}}if(!Object.deepClone){Object.deepClone=function(A){return Object.toJSON(A).evalJSON()}}function playSound(A){if(typeof Audio!="undefined"){new Audio(A).play()}}var PROTORPG={consts:{skillNames:{sword:"Sword",axe:"Axe",hammer:"Hammer",spear:"Spear",bow:"Bow",crossBow:"Crossbow",parry:"Parry",lightArmor:"Light armor",mediumArmor:"Medium armor",heavyArmor:"Heavy Armor"}},config:{saveScript:"/games/server.php"}};var GameBasicActor=Class.create({initialize:function(A){this.data=Object.deepClone(A);this.Map=null;this.orientation=2;if(typeof this.data.specs!="object"){this.data.specs={maxHit:10}}if(typeof this.data.specs.attributes!="object"){this.data.specs.attributes={STR:3,DEX:3,AGI:3,CON:3,INT:3,CHA:3}}if(typeof this.data.specs.skills!="object"){this.data.specs.skills={}}if(typeof this.data.specs.hit!="number"){this.data.specs.hit=this.data.specs.maxHit}if(typeof this.data.specs.maxMana!="number"){this.data.specs.maxMana=0}if(typeof this.data.specs.mana!="number"){this.data.specs.mana=this.data.specs.maxMana}if(typeof this.data.equipment!="object"){this.data.equipment={}}this.isDead=(this.data.specs.hit<=0)},bindMap:function(A){this.Map=A},setOrientation:function(A,B){if(typeof B=="undefined"){this.orientation=A}else{if(B<0){this.orientation=0}if(A>0){this.orientation=1}if(B>0){this.orientation=2}if(A<0){this.orientation=3}}return this.orientation},getEquipment:function(A){if(typeof A=="string"){return this.Map.Bundle.items[A]}if(typeof A=="object"){return A}},skillCheck:function(C,A){var D=this.data.specs;var B=D.attributes[C]+((typeof A=="string")?((D.skills[A]||-2)-1):0);return(B>0)?Math.throwDice(Math.floor(B/3),6,3)+(B%3):0},restoreHit:function(B){var A=this.data.specs;if(B=="+max"){A.hit=A.maxHit;document.fire("game:message",{title:this.data.name+" has been fully healed."});return A.hit}if(B=="-max"){A.hit=0;this.isDead=true;document.fire("game:message",{title:this.data.name+" has lost all life."});return 0}B=Number(B);document.fire("game:message",{title:this.data.name+((B>=0)?" gained ":" lost ")+Math.abs(B)+" hit points."});A.hit=(A.hit+B).limit(0,A.maxHit);this.isDead=(A.hit<=0);return A.hit},restoreMana:function(B){var A=this.data.specs;if(B=="+max"){A.mana=A.maxMana;document.fire("game:message",{title:this.data.name+" has regained full mana."});return A.mana}if(B=="-max"){A.mana=0;document.fire("game:message",{title:this.data.name+" has lost all mana."});return 0}B=Number(B);document.fire("game:message",{title:this.data.name+((B>=0)?" gained ":" lost ")+Math.abs(B)+" mana points."});A.mana=(A.mana+B).limit(0,A.maxMana);return A.mana},hit:function(E){this.setOrientation(E.x-this.x,E.y-this.y);var F=this.data.specs;var B=this.getEquipment(this.data.equipment.weapon)||{type:"weapon",skill:"martial",attackAttr:"AGI",attackBonus:0,damageAttr:"STR",damageBonus:0};var D=this.skillCheck(B.attackAttr,B.skill);if(!E.defend(D)){var C=F.attributes[B.damageAttr];var A=E.receiveHit(Math.throwDice(Math.floor(C/3),6)+(C%3)+(B.damageBonus||0));return A}else{document.fire("game:message",{title:this.data.name.stripArticle().upperFirst()+" missed."});return 0}},defend:function(D){if(this.data.attackedSchedule){this.data.schedule=this.data.attackedSchedule}var B=Math.random(),A;if(B<0.05){return true}if(B>0.95){return false}var E=this.data.specs;if(E.skills.parry){var C=this.getEquipment(this.data.equipment.shield)||{defenseBonus:0};A=this.skillCheck("DEX","parry")+C.defenseBonus}else{A=this.skillCheck("AGI")}return(D<=A)},receiveHit:function(B){var D=this.data.specs,C=this.getEquipment(this.data.equipment.armor),A;if(C&&D.skills[C.armorSkill]>0){A=this.skillCheck("AGI",C.armorSkill)+(C.defenseBonus||0)}else{A=this.skillCheck("CON")}damages=Math.ceil(B-A);if(damages>0){D.hit=Math.min(Math.max(0,D.hit-damages),D.maxHit);document.fire("game:message",{title:this.data.name.stripArticle().upperFirst()+" lost "+damages+" hit points."});this.isDead=(D.hit<=0);if(this.isDead){document.fire("game:message",{title:this.data.name.stripArticle().upperFirst()+" has been killed!"})}}else{document.fire("game:message",{title:this.data.name.stripArticle().upperFirst()+" did not sustain any damage."})}return damages}});var GameActor=Class.create(GameBasicActor,{initialize:function($super,C,B,A,D){$super(C);this.bindMap(B);if(typeof A=="undefined"||typeof D=="undefined"){this.x=this.data.schedule.x;this.y=this.data.schedule.y}else{this.x=A;this.y=D}},getFile:function(){if(typeof this.data.file=="object"&&this.data.file.length==4){return this.data.file[this.orientation]}else{return this.data.file}},getTalk:function(){return this.data.talk},moveTo:function(A,C,B){if(!B&&this.x!==null&&this.y!==null){this.setOrientation(A-this.x,C-this.y)}else{this.setOrientation(2)}this.x=A;this.y=C},goToward:function(B,F){var C=this.Map.distanceX(this.x,B);var A=this.Map.distanceY(this.y,F);var E=this.x,D=this.y;if(A<C){E=this.Map.checkX(E+((this.x>B)?-1:1))}else{D=this.Map.checkY(D+((this.y>F)?-1:1))}if(this.Map.isBlocking(E,D)>0){E=this.x;D=this.y;if(A>C){D=this.Map.checkY(D+((this.y>F)?-1:1))}else{E=this.Map.checkX(E+((this.x>B)?-1:1))}}if(this.Map.isBlocking(E,D)<=0){this.moveTo(E,D);return true}return false},goAway:function(B,F){var C=this.Map.distanceX(this.x,B);var A=this.Map.distanceY(this.y,F);var E=this.x,D=this.y;if(A<C){E=this.Map.checkX(E+((this.x>B)?1:-1))}else{D=this.Map.checkY(D+((this.y>F)?1:-1))}if(this.Map.isBlocking(E,D)>0){E=this.x;D=this.y;if(A>C){D=this.Map.checkY(D+((this.y>F)?1:-1))}else{E=this.Map.checkX(E+((this.x>B)?1:-1))}}if(!this.Map.isBlocking(E,D)<=0){this.moveTo(E,D);return true}return false},wander:function(){var C=Math.random();var B=Math.random();if(C<0.5){var A=this.Map.checkX(this.x+((B<0.33)?-1:((B<0.67)?0:1)));if(A!=null&&this.Map.isBlocking(A,this.y)<=0){this.moveTo(A,this.y)}}else{var D=this.Map.checkY(this.y+((B<0.33)?-1:((B<0.67)?0:1)));if(D!=null&&this.Map.isBlocking(this.x,D)<=0){this.moveTo(this.x,D)}}},hunt:function(A){var B=this.Map.Player.data.pos;var C=this.Map.getDistance(this.x,this.y,B.x,B.y,"moves");if(A>=C){if(C==1){document.fire("game:message",{title:this.data.name.stripArticle().upperFirst()+" attacks."});this.hit(this.Map.Player)}else{this.goToward(B.x,B.y)}}else{this.wander()}},doCycle:function(){if(!this.isDead){if(this.data.schedule.action=="wander"){this.wander()}if(this.data.schedule.action=="hunt"){this.hunt(11)}if(this.data.schedule.action=="flee"){var B=this.Map.Player.data.pos;var A=this.goAway(B.x,B.y);if(!A&&this.Map.getDistance(this.x,this.y,B.x,B.y,"moves")==1){this.hit(this.Map.Player)}}}}});var GameActorCollection=Class.create({initialize:function(A){this.tab=[];this.Map=A},get:function(A){if(typeof A=="number"){return this.tab[A]}else{var B=0;while(B<this.tab.length){if(this.tab[B].data&&this.tab[B].data.name&&this.tab[B].data.name==A){return this.tab[B]}B++}return }},set:function(B,A){if(typeof A=="number"){this.tab[A]=B}else{this.tab.push(B)}},size:function(){return this.tab.length},loadPopulation:function(C,A){for(var D=0;D<C.length;D++){var E=new GameActor(C[D],this.Map);var B=(typeof A=="object"&&A.length)?A.indexOfObject("name",C[D].name):-1;E.popIndex=D;if(B>=0){if(!A[B].dead){E.x=A[B].x;E.y=A[B].y;this.tab.push(E)}}else{this.tab.push(E)}}},savePopulation:function(){var A=[];for(var B=0;B<this.tab.length;B++){if(typeof this.tab[B].popIndex=="number"&&this.tab[B].data&&this.tab[B].data.name){A.push({name:this.tab[B].data.name,x:this.tab[B].x,y:this.tab[B].y,dead:this.tab[B].isDead})}}return A},find:function(C,G,A,E,F){if(E>G&&A>C){F=F||false;var B=[];this.tab.each(function(I,H){if(I.x>=C&&I.x<=A&&I.y>=G&&I.y<=E&&!(F&&I.isDead)){B.push(I)}});return B}else{F=A||false;var D=0;while(D<this.tab.length){if(this.tab[D].x==C&&this.tab[D].y==G&&!(F&&this.tab[D].isDead)){return this.tab[D]}D++}}},doCycle:function(){for(var A=0;A<this.tab.length;A++){this.tab[A].doCycle()}}});var GamePlayer=Class.create(GameBasicActor,{readyAble:["weapon","bodyArmor","ring","shield"],levels:[100,250,450,700,1000,1400,2000,2800,3800,5000,6500,8500,11000,14000,18000,23000,29000,36000,44000,54000,68000,84000,102000,125000,175000,250000,350000,500000,750000,1000000,1500000,2000000,3000000,4000000,5000000,7500000,15000000,25000000,50000000,75000000,100000000],initialize:function($super,A){if(!A.specs){A.specs={maxHit:50,hit:50,maxMana:10,mana:10,attributes:{},xp:0,level:1}}$super(A);if(!this.data.Maps){this.data.Maps={}}if(!this.data.inventory){this.data.inventory=[]}if(typeof this.data.specs.xp!="number"){this.data.specs.xp=0}if(typeof this.data.specs.competence!="number"){this.data.specs.competence=0}this.data.specs.level=this.data.specs.level||1},getFile:function(){if(this.Map){var A=this.Map.Bundle.data.graphics.player.file;if(typeof A=="object"&&A.length==4){return A[this.orientation]}else{return A}}},gainXp:function(A){this.data.specs.xp+=A;document.fire("game:message",{title:this.data.name+" gained "+A+" experience points."});if(this.data.specs.xp>=this.levels[this.data.specs.level-1]){this.data.specs.level++;this.data.specs.competence+=2;this.data.specs.maxHit+=this.data.specs.attributes.CON;this.data.specs.maxMana+=this.data.specs.attributes.INT;document.fire("game:message",{title:this.data.name+" has gained a level and 2 learning points!"})}document.fire("game:specsChange")},checkPulse:function(){if(this.isDead){new DialogQuestion(this.data.name.upperFirst()+" has been killed. This is the ends of the adventure...",false,function(){document.location.reload()})}},restoreHit:function($super,A){$super(A);document.fire("game:specsChange");this.checkPulse()},restoreMana:function($super,A){$super(A);document.fire("game:specsChange")},hit:function($super,A){if($super(A)&&A.isDead&&A.data.xp){this.gainXp(A.data.xp)}},receiveHit:function($super,A){if($super(A)){document.fire("game:specsChange")}this.checkPulse()},writeFlag:function(A,B,C){C=C||this.data.pos.map;if(typeof B=="undefined"){B=1}if(!this.data.Maps[C]){this.data.Maps[C]={flags:{}}}if(!this.data.Maps[C].flags[A]){this.data.Maps[C].flags[A]=0}if(typeof B=="string"&&B.substr(0,1)=="+"){this.data.Maps[C].flags[A]+=Number(B.substr(1))}else{if(typeof B=="string"&&B.substr(0,1)=="-"){this.data.Maps[C].flags[A]-=Number(B.substr(1))}else{this.data.Maps[C].flags[A]=B}}},readFlag:function(A,B){if(typeof B=="undefined"){B=this.data.pos.map}if(this.data.Maps[B]&&this.data.Maps[B].flags&&(typeof this.data.Maps[B].flags[A]!="undefined")){return this.data.Maps[B].flags[A]}},addInventory:function(B,C){C=C||1;var A=this.findInventory(B);if(A<0){this.data.inventory.push({name:B,qty:C});document.fire("game:inventoryChange");return C}else{if(typeof this.data.inventory[A].qty!="number"){this.data.inventory[A].qty=1}this.data.inventory[A].qty+=C;document.fire("game:inventoryChange");return this.data.inventory[A].qty}},removeInventory:function(B,C){C=C||1;var A=this.findInventory(B);if(A<0){return false}else{if(typeof this.data.inventory[A].qty!="number"){this.data.inventory[A].qty=1}if(this.data.inventory[A].qty>=C){if(this.data.inventory[A].qty==C){this.data.inventory.splice(A,1)}else{this.data.inventory[A].qty-=C}document.fire("game:inventoryChange");return true}else{return false}}},findInventory:function(C){var B=0,A=this.data.inventory.length;while(B<A&&this.data.inventory[B].name!=C){B++}return(B<A)?B:-1},ready:function(B){var A=this.Map.Bundle.items[B];if(A&&A.type){var C=this.data.equipment[A.type];if(this.removeInventory(B)){if(C){this.addInventory(C)}this.data.equipment[A.type]=B;return true}}return false}});var GameConversation=Class.create({initialize:function(B,A){this.person=B;this.consoleWrite=function(C){};this.consoleClose=function(){};this.next=null;this.talk=this.person.getTalk();this.action=A||function(C){}},bindConsole:function(B,A){this.consoleWrite=B;this.consoleClose=A},processItem:function(C){if(typeof C=="object"){if(Object.isArray(C)&&C.length){var B=0;while(B<C.length&&this.processItem(C[B])){B++}}else{if(C.text){this.consoleWrite('"'+C.text+'"')}if(C.action&&C.action!="say"){switch(C.action){case"exit":this.consoleClose();return true;case"fight":this.consoleClose();return true;default:var A=this.action(C);if(!A&&typeof C.onFail=="string"&&C.onFail.length){this.say(C.onFail)}return A}}else{if(C.next){if(typeof C.next=="object"){this.next=C.next}else{this.say(C.next)}}}}}else{this.consoleWrite('"'+C+'"')}return true},say:function(B){if(this.next){var A=(this.next[B])?this.next[B]:this.next["#any"];if(A){this.next=null;this.say(A)}return true}var C=(this.talk[B])?this.talk[B]:this.talk["#duh"];return C?this.processItem(C):true}});var GameMap=Class.create({initialize:function(A,B){this.Bundle=A;this.data=null;this.tileset=[];this.Actors=null;this.onEndLoad=null;if(typeof B=="object"){this.Player=B;this.Player.bindMap(this)}else{this.Player=null}},checkX:function(A){if(A<0){return((this.data.wrap)?(A%this.data.bitmap[0].length)+this.data.bitmap[0].length:null)}if(A>=this.data.bitmap[0].length){return((this.data.wrap)?A%this.data.bitmap[0].length:null)}return A},checkY:function(A){if(A<0){return((this.data.wrap)?(A%this.data.bitmap.length)+this.data.bitmap.length:null)}if(A>=this.data.bitmap.length){return((this.data.wrap)?A%this.data.bitmap.length:null)}return A},distanceX:function(C,A){var B=Math.abs(A-C);return(this.data.wrap)?Math.min(B,this.data.bitmap[0].length-B):B},distanceY:function(C,B){var A=Math.abs(B-C);return(this.data.wrap)?Math.min(A,this.data.bitmap.length-A):A},getDistance:function(C,F,B,D,E){var A=this.distanceX(C,B);var G=this.distanceY(F,D);if(E=="line"){return Math.sqrt(A*A+G*G)}if(E=="sideMoves"){return Math.max(A,G)}return A+G},copySection:function(B,E,A,I){var C=[];for(var D=0;D<I;D++){C[D]=[];for(var F=0;F<A;F++){var H=this.checkX(B+F);var G=this.checkY(E+D);C[D][F]=(H!=null&&G!=null)?this.data.bitmap[G][H]:((typeof this.data.defaultTile=="number")?this.data.defaultTile:-1)}}return C},getTile:function(A,C){if(typeof C!="number"){return this.tileset[A]}else{var B=this.data.bitmap[C][A];if(typeof B=="object"){B=B.last()}return this.tileset[B]}},getItem:function(B){var A=this.data.items[B].name;return this.Bundle.items[A]},searchCoordInArray:function(F,C,E,A,D){var B=[];if(Object.isArray(F)){if(A>C&&D>E){F.each(function(H,G){if(H.x>=C&&H.x<=A&&H.y>=E&&H.y<=D){B.push(G)}})}else{F.each(function(H,G){if(H.x==C&&H.y==E){B.push(G)}})}}return B},searchItems:function(B,D,A,C){return this.searchCoordInArray(this.data.items,B,D,A,C)},getEgg:function(A,C){if(this.data.eggs&&this.data.eggs.length){var B=0;while(B<this.data.eggs.length){if(this.data.eggs[B].x==A&&this.data.eggs[B].y==C){return this.data.eggs[B]}B++}}},compileOverlays:function(C,F,A,E){var H=[];var B=this.searchItems(C,F,A,E);for(var D=0;D<B.length;D++){var G=this.getItem(B[D]);if(G){H.push({x:this.data.items[B[D]].x,y:this.data.items[B[D]].y,file:G.file,priority:((G.blocking>0)?20:10)})}}var B=this.Actors.find(C,F,A,E,true);for(var D=0;D<B.length;D++){H.push({x:B[D].x,y:B[D].y,file:B[D].getFile(),priority:((B[D].isDead)?0:30)})}H.sort(function(J,I){return J.priority-I.priority});return H},isBlocking:function(A,E){if(this.Player.data.pos.x==A&&this.Player.data.pos.y==E){return 2}if(this.Actors.find(A,E,true)){return 2}var B=this.searchItems(A,E),C=0;while(C<B.length){if(this.getItem(B[C]).blocking>0){return this.getItem(B[C]).blocking}C++}var D=this.getTile(A,E);return(typeof D=="object")?(D.blocking||0):0},breedMonsters:function(E){if(this.Bundle&&typeof this.Bundle.monsters=="object"){for(var C=0;C<E.length;C++){var H=E[C];var D=this.data.bitmap.length*this.data.bitmap[0].length*((typeof H.density=="number")?H.density:0.001);D=Math.round(D*Math.random());for(var B=0;B<D;B++){var F=false,J=30;while(!F&&J>0){var I=Math.round((this.data.bitmap[0].length-1)*Math.random());var G=Math.round((this.data.bitmap.length-1)*Math.random());if(!H.habitat||H.habitat.indexOf(this.data.bitmap[G][I])>-1){if(this.isBlocking(I,G)<=0){var A=new GameActor(this.Bundle.monsters[H.name],this,I,G);this.Actors.set(A);F=true}}J++}}}}},loadFromUrl:function(A,B){document.fire("game:busy",{busy:true,title:"Loading map",mustWait:true});if(typeof B=="function"){this.onEndLoad=B}new Ajax.Request(this.Bundle.path+"maps/"+A,{method:"get",onSuccess:this.loadFromText.bind(this)})},loadFromText:function(C){try{this.data=((typeof C=="object")?C.responseText:C).evalJSON()}catch(B){document.fire("game:error",{type:"error",title:"Invalid or empty map file."})}var A=(this.data.name&&this.Player&&typeof this.Player.data.Maps[this.data.name]=="object")?this.Player.data.Maps[this.data.name]:{};this.Actors=new GameActorCollection(this);if(this.data.population&&this.data.population.length>0){this.Actors.loadPopulation(this.data.population,A.population)}if(this.data.monsters&&this.data.monsters.length>0){this.breedMonsters(this.data.monsters)}if(typeof A.items=="object"){this.data.items=A.items}if(this.data.tileset){this.loadTileset(this.Bundle.path+"tilesets/"+this.data.tileset)}else{if(this.onEndLoad){this.onEndLoad();this.onEndLoad=null}document.fire("game:busy",{busy:false})}},loadTileset:function(A){document.fire("game:busy",{busy:true,title:"Loading tileset",mustWait:true});new Ajax.Request(A,{method:"get",onSuccess:this.onTilesetLoaded.bind(this)})},onTilesetLoaded:function(B){try{this.tileset=B.responseText.evalJSON()}catch(A){document.fire("game:error",{type:"error",title:"Invalid or empty tileset file."})}if(this.onEndLoad){this.onEndLoad();this.onEndLoad=null}document.fire("game:busy",{busy:false})}});var FogOfWar=Class.create({initialize:function(A,B,C){this.Map=A;this.sWidth=B;this.sHeight=C},isOpaque:function(B){if(B<0){return 2}else{if(typeof B=="object"){B=B.last()}var A=this.Map.tileset[B];return((typeof A.opaque=="number")?A.opaque:((A.blocking>0)?2:0))}},compute:function(F){var B=this.Map.copySection(F.x-Math.floor(this.sWidth/2),F.y-Math.floor(this.sHeight/2),this.sWidth,this.sHeight);var J=[];for(var G=0;G<this.sHeight;G++){J[G]=[];for(var H=0;H<this.sWidth;H++){J[G][H]=(B[G][H]==-1)?-1:this.isOpaque(B[G][H])}}var D=[{x:Math.floor(this.sWidth/2),y:Math.floor(this.sHeight/2)}],C=0;J[D[0].y][D[0].x]=0;if(J[D[0].y-1][D[0].x]==1){J[D[0].y-1][D[0].x]=0}if(J[D[0].y+1][D[0].x]==1){J[D[0].y+1][D[0].x]=0}if(J[D[0].y][D[0].x-1]==1){J[D[0].y][D[0].x-1]=0}if(J[D[0].y][D[0].x+1]==1){J[D[0].y][D[0].x+1]=0}while(D.length){var A=D.pop();if(J[A.y][A.x]==0){var I=A.x,E=A.x;while(I>=0&&J[A.y][I]==0){I--}while(E<this.sWidth&&J[A.y][E]==0){E++}for(var C=Math.max(0,I);C<=Math.min(E,this.sWidth-1);C++){J[A.y][C]=100;if(A.y>0){if(J[A.y-1][C]==0){D.push({x:C,y:A.y-1})}else{J[A.y-1][C]=100}}if(A.y<this.sHeight-1){if(J[A.y+1][C]==0){D.push({x:C,y:A.y+1})}else{J[A.y+1][C]=100}}}}}for(var G=0;G<this.sHeight;G++){for(var H=0;H<this.sWidth;H++){if(J[G][H]!=100){B[G][H]=-1}}}return B}});var GameBundle=Class.create({initialize:function(){this.items={};this.monsters={};this.data=null;this.path="";this.onLoaded=null},load:function(B,A){this.path=B;this.onLoaded=A;document.fire("game:busy",{busy:true,title:"Loading game bundle",mustWait:true});new Ajax.Request(this.path+"bundle.txt",{method:"get",onSuccess:this.onBundleLoaded.bind(this)})},onBundleLoaded:function(B){try{this.data=B.responseText.evalJSON()}catch(A){document.fire("game:error",{type:"error",title:"Invalid or empty bundle file."})}if(this.data.itemFile||this.data.monsterFile){if(this.data.itemFile){document.fire("game:busy",{busy:true,title:"Loading items",mustWait:true});new Ajax.Request(this.path+this.data.itemFile,{method:"get",onSuccess:this.onItemLoaded.bind(this)})}else{document.fire("game:busy",{busy:true,title:"Loading monsters",mustWait:true});new Ajax.Request(this.path+this.data.itemFile,{method:"get",onSuccess:this.onMonsterLoaded.bind(this)})}}else{this.onLoadingComplete()}},onItemLoaded:function(B){try{this.items=B.responseText.evalJSON(true)}catch(A){document.fire("game:error",{type:"error",title:"Invalid or empty item file."})}if(this.data.monsterFile){document.fire("game:busy",{busy:true,title:"Loading monsters",mustWait:true});new Ajax.Request(this.path+this.data.monsterFile,{method:"get",onSuccess:this.onMonsterLoaded.bind(this)})}else{this.onLoadingComplete()}},onMonsterLoaded:function(B){try{this.monsters=B.responseText.evalJSON()}catch(A){document.fire("game:error",{type:"error",title:"Invalid or empty monster file."})}this.onLoadingComplete()},onLoadingComplete:function(){if(this.onLoaded){this.onLoaded();this.onLoaded=null}document.fire("game:busy",{busy:false})}});var GameLogic=Class.create({initialize:function(A){this.Display=A;this.Bundle=null;this.Control=null;this.Map=null;this.Player=null;this.busy=false;Event.observe(document,"game:busy",this.onBusy.bindAsEventListener(this))},onBusy:function(A){this.busy=A.memo.busy},changeMap:function(){this.Map=new GameMap(this.Bundle,this.Player);this.Map.loadFromUrl(this.Player.data.pos.map,this.onMapChanged.bind(this))},onMapChanged:function(){this.Display.bindMap(this.Map);this.Player.bindMap(this.Map);if(!this.Player.data.Maps[this.Player.data.pos.map]){this.Player.data.Maps[this.Player.data.pos.map]={flags:{}}}this.Display.drawPosition(this.Player.data.pos)},exitMap:function(){var A=this.Player.data.Maps[this.Player.data.pos.map];if(this.Map.data.mustSave.indexOf("items")>=0&&this.Map.data.items&&this.Map.data.items.length>0){A.items=this.Map.data.items}if(this.Map.data.mustSave.indexOf("population")>=0&&this.Map.data.population&&this.Map.data.population.length>0){A.population=this.Map.Actors.savePopulation()}},playerAct:function(A,E,B){this.Player.setOrientation(A,E);var D=this.Map.checkX(this.Player.data.pos.x+A);var C=this.Map.checkY(this.Player.data.pos.y+E);if(B==null){this.moveTo(D,C)}if(B=="l"){this.lookTo(D,C)}if(D!=null&&C!=null){if(B=="a"){this.attackTo(D,C)}if(B=="g"){this.getTo(D,C)}if(B=="p"){this.pushTo(D,C,A,E)}if(B=="t"){this.talkTo(D,C)}if(B=="u"){this.useTo(D,C)}}},gameEvent:function(B,A,E){var D=this.Map.getEgg(A,E);if(D&&D[B]){this.processActions(D[B],A,E);return true}var C=this.Map.getTile(A,E);if(C&&C[B]){this.processActions(C[B],A,E);return true}return false},attackTo:function(A,F){var B=this.Map.Actors.find(A,F,true);if(B){if(B.isDead){document.fire("game:message",{title:"Target is already dead."})}else{this.Player.hit(B);if(B.isDead&&B.data.corpse&&this.Bundle.items[B.data.corpse]){var D={name:B.data.corpse,x:B.x,y:B.y};if(this.Bundle.items[B.data.corpse].container){D.content=[];if(B.data.loot&&B.data.loot.length){for(var C=0;C<B.data.loot.length;C++){var E=B.data.loot[C];if(E.name&&E.qty&&(typeof E.chance!="number"||Math.random()<E.chance)){D.content.push({name:E.name,qty:(E.qty>0)?E.qty:Math.round(Math.random()*E.qty*-1)})}}}}this.Map.data.items.push(D)}this.doCycle()}}else{document.fire("game:message",{title:"Nobody to attack there."})}},moveTo:function(A,B){if((A==null||B==null)&&this.Map.data.defaultExit&&this.Map.data.defaultExit.length>=3){new DialogQuestion("Do you want to leave this area ?",[{key:"yes",value:1},{key:"no",value:0}],function(C){if(C>0){this.exitMap();this.Player.data.pos.map=this.Map.data.defaultExit[0];this.Player.data.pos.x=this.Map.data.defaultExit[1];this.Player.data.pos.y=this.Map.data.defaultExit[2];this.Player.setOrientation(2);this.changeMap()}}.bind(this))}else{if(this.Map.isBlocking(A,B)<=0){this.Player.data.pos.x=A;this.Player.data.pos.y=B;this.gameEvent("onWalk",A,B);this.doCycle()}else{document.fire("game:message",{title:"Blocked!"})}}},lookTo:function(B,F){var D="";if(B!=null&&F!=null){var C=this.Map.Actors.find(B,F,true);if(C){D=C.data.name}else{var A=this.Map.data.items;C=this.Map.searchItems(B,F);if(C.length){D=this.Map.getItem(C[0]).title;if(A[C[0]].content||this.Map.getItem(C[0]).container){var E=null;if(this.Map.getItem(C[0]).disappearEmpty){E=function(){if(!A[C[0]].content||!A[C[0]].content.length){this.Map.data.items.splice(C[0],1);this.Display.drawPosition(this.Player.data.pos)}}.bind(this)}new DialogContainer(this,A[C[0]],E)}}else{if(!this.gameEvent("onLook",B,F)){D=this.Map.getTile(B,F).title}}}}else{D=(typeof this.Map.data.defaultTile=="number")?this.Map.getTile(this.Map.data.defaultTile).title:"nothing"}if(D.length){document.fire("game:message",{title:"You see "+D})}this.doCycle();return D},useTo:function(A,B){if(A!=null&&B!=null){if(this.gameEvent("onUse",A,B)){this.doCycle()}else{document.fire("game:message",{title:"You cannot use this"})}}},useItem:function(B){var A=this.Bundle.items[B];if(A&&A.onUse){if(this.processActions(A.onUse,this.Player.data.pos.x,this.Player.data.pos.y)){this.Player.removeInventory(B);this.doCycle()}}},talkTo:function(A,D){var B=this.Map.Actors.find(A,D,true);if(B&&!B.isDead){B.setOrientation(this.Map.Player.data.pos.x-B.x,this.Map.Player.data.pos.y-B.y);this.Display.drawPosition(this.Player.data.pos);var C=new GameConversation(B,function(E){return this.processActions(E,A,D)}.bind(this));document.fire("game:message",{title:"Talking with "+B.data.name});new DialogConversation(C);C.say("#hello")}else{document.fire("game:message",{title:"Nobody to talk to there"})}},getTo:function(A,F){if(A!=null&&F!=null){var B=false;var C=this.Map.searchItems(A,F);if(C.length){var D=this.Map.data.items[C[0]];var E=(typeof this.Bundle.items[D.name].pickable=="undefined")||this.Bundle.items[D.name].pickable;if(E&&this.Player.addInventory(D.name,D.qty)){document.fire("game:message",{title:"Getting "+D.qty+" "+this.Bundle.items[D.name].title});this.Map.data.items.splice(C[0],1);if(D.onGet){this.processActions(D.onGet,A,F)}B=true}}if(!B){B=this.gameEvent("onGet",A,F)}if(B){this.doCycle()}else{document.fire("game:message",{title:"Nothing here"})}}},pushTo:function(H,F,B,A){var E=this.Map.searchItems(H,F),C=false,D=0;while(D<E.length&&!C){var J=this.Map.getItem(E[D]);if(typeof J.pushabled=="undefined"||J.pushable){var I=this.Map.checkX(H+B);var G=this.Map.checkY(F+A);if(I!=null&&G!=null&&this.Map.isBlocking(I,G)<=0){this.Map.data.items[E[D]].x=I;this.Map.data.items[E[D]].y=G;this.Player.data.pos.x=H;this.Player.data.pos.y=F}else{this.Map.data.items[E[D]].x=this.Player.data.pos.x;this.Map.data.items[E[D]].y=this.Player.data.pos.y;this.Player.data.pos.x=H;this.Player.data.pos.y=F}C=true}}if(!C){C=this.gameEvent("onPush",H,F)}if(C){this.doCycle()}else{document.fire("game:message",{title:"Nothing to push here"})}},processActions:function(B,K,J,I,F,C){if(Object.isArray(B)){var G=I||0,E=false,A=F||null;if(typeof C=="string"){G=B.indexOfObject("label",C)}while(G<B.length&&!E){this.resumeActions=this.processActions.bind(this,B,K,J,G+1);A=this.processActions(B[G],K,J,null,A);E=(A===null);if(E&&B[G].onFail&&B[G].action!="ask"){G=B.indexOfObject("label",B[G].onFail);E=(G>-1)}else{G++}}}else{var D=Object.deepClone(B);switch(D.action){case"replace":if(!D.x){D.x=K}if(!D.y){D.y=J}if(D.newTile){this.Map.data.bitmap[D.y][D.x]=D.newTile;this.Display.drawPosition(this.Player.data.pos);return true}document.fire("game:error",{type:"error",title:'Invalid "replace" action (missing tile ID).'});return null;case"move":if(typeof D.x!="undefined"&&typeof D.y!="undefined"){if(typeof D.map!="string"){this.moveTo(D.x,D.y)}else{this.exitMap();this.Player.data.pos.map=D.map;this.Player.data.pos.x=D.x;this.Player.data.pos.y=D.y;this.changeMap()}return true}document.fire("game:error",{type:"error",title:'Invalid "move" action (missing or invalid coordinates).'});return null;case"setflag":if(typeof D.name!="undefined"&&D.name.length){this.Player.writeFlag(D.name,D.value,D.map);return true}document.fire("game:error",{type:"error",title:'Invalid "setflag" action (missing flag name).'});return null;case"testflag":if(typeof D.name!="undefined"&&D.name.length){var H=this.Player.readFlag(D.name)||0;if(D.value){return(Number(H)>Number(D.value))?true:null}else{return(H>0)?true:null}}document.fire("game:error",{type:"error",title:'Invalid "testflag" action (missing flag name).'});return null;case"readflag":if(typeof D.name!="undefined"&&D.name.length){return(this.Player.readFlag(D.name)||0)}document.fire("game:error",{type:"error",title:'Invalid "readflag" action (missing flag name).'});return null;case"get":if(typeof D.item!="undefined"&&D.item.length){if(D.qty<0){return this.Player.removeInventory(D.item,Math.abs(D.qty))}else{this.Player.addInventory(D.item,D.qty)}return true}document.fire("game:error",{type:"error",title:'Invalid "get" action (missing item name).'});return null;case"say":if(D.text&&D.text.length){D.text=D.text.gsub("#result#",F||"");if(typeof D.modal!="undefined"&&!D.modal){document.fire("game:message",{title:D.text})}else{new DialogQuestion(D.text)}return true}document.fire("game:error",{type:"error",title:'Invalid "say" action (missing text).'});return null;case"ask":D.text=D.text.gsub("#result#",F||"");var L=null;if(this.resumeActions){L=(D.answers&&D.answers.length)?function(M){this.resumeActions(null,M)}.bind(this):this.resumeActions}if(D.form!="choice"){new DialogInput(D.text,D.answers,L)}else{new DialogQuestion(D.text,D.answers,L)}return null;case"specs":if(D.target&&D.target.length&&typeof D.delta!="undefined"){if(D.target=="hit"){this.Player.restoreHit(D.delta)}if(D.target=="mana"){this.Player.restoreMana(D.delta)}if(D.target=="xp"){this.Player.gainXp(Number(D.delta))}return true}document.fire("game:error",{type:"error",title:'Invalid "spec" action.'});return null;case"sound":if(typeof D.file=="string"&&D.file.length){playSound(this.Bundle.path+"sounds/"+D.file)}return true;case"fail":return null;default:document.fire("game:error",{type:"error",title:'Invalid action "'+D.action+'"'});return null}}},doCycle:function(A){A=A||1;if(this.Map.Actors){this.Map.Actors.doCycle()}if(A>1){this.doCycles(A-1)}else{this.Display.drawPosition(this.Player.data.pos)}},bindController:function(A){this.Control=A},loadBundle:function(A,B){this.Bundle=new GameBundle();this.Display.graphics=A+"graphics/";this.Bundle.load(A,B)},startGame:function(B){if(this.Bundle&&this.Bundle.data){this.Display.configure(this.Bundle.data);var A=(typeof B=="object")?B:Object.deepClone(this.Bundle.data.newGame);this.Player=new GamePlayer(A);document.fire("game:specsChange");document.fire("game:inventoryChange");this.changeMap()}},saveGame:function(A,B){this.exitMap();A.save(this.Player.data,B)},onLoadComplete:function(D,B){var A;if(B.length){var C;try{C=B.evalJSON()}finally{if(typeof C=="object"&&C.name&&C.pos&&C.specs){this.startGame(C);A="OK"}else{A="Savegame seems corrupt."}}}else{A="No savegame in this slot."}if(typeof D=="function"){D(A)}},loadGame:function(A,B){A.load(this.onLoadComplete.bind(this,B))}});var GameTip=Class.create({initialize:function(C,B){this.element=$(C);this.tipElement=null;this.deltaX=4;this.deltaY=6;this.tipClass=(typeof B=="string")?" "+B:"";if(!$("uniqueTooltip")){var A=new Element("div",{id:"uniqueTooltip","class":"tooltip",style:"z-index: 1000; position: absolute; left: 0px; top: 0px; display: none"});$(document.body).insert(A)}this.eventMouseOver=this.onMouseOver.bindAsEventListener(this);this.eventMouseOut=this.onMouseOut.bindAsEventListener(this);this.element.observe("mouseover",this.eventMouseOver);this.element.observe("mouseout",this.eventMouseOut)},getHtml:function(){document.fire("game:error",{type:"error",title:"Abstract GameTip::getHtml() function call. You must redefine this function in child class."})},destroy:function(){Event.stopObserving(this.element,"mouseover",this.eventMouseOver);Event.stopObserving(this.element,"mouseout",this.eventMouseOut);this.onMouseOut()},onMouseOver:function(E){if(!$("uniquePopupMenu")||!$("uniquePopupMenu").visible()){var D=$("uniqueTooltip");D.update(this.getHtml());var A=D.getDimensions();var C=document.viewport.getDimensions();var B={x:E.pointerX(),y:E.pointerY()};if((A.width+B.x)>=(C.width-this.deltaX)){B.x-=A.width-this.deltaX}else{B.x+=this.deltaX}if((A.height+B.y)>=(C.height-this.deltaY)){B.y-=A.height-this.deltaY}else{B.y+=this.deltaY}D.className="tooltip"+((this.tipClass)?" "+this.tipClass:"");D.setStyle({top:B.y+"px",left:B.x+"px"});D.show()}},onMouseOut:function(){$("uniqueTooltip").hide()}});var GameItemTip=Class.create(GameTip,{initialize:function($super,A,B){this.item=B;$super(A,"itemTooltip")},getHtml:function(){var A="";A+="<div><strong>"+this.item.title.upperFirst()+"</strong></div>";if(this.item.type){A+="<div>";switch(this.item.type){case"bodyArmor":A+="Body armor ("+Math.toSignedString(this.item.defenseBonus)+" "+this.item.defenseAttr+")";break;case"weapon":A+="Weapon ("+Math.toSignedString(this.item.attackBonus)+" "+this.item.attackAttr+", "+Math.toSignedString(this.item.damageBonus)+" "+this.item.damageAttr+" damages)";break;case"ring":A+="Ring";break}A+=((this.item.skill)?"<br/>Skill: "+PROTORPG.consts.skillNames[this.item.skill]:"")+"</div>"}if(this.item["abstract"]){A+="<p>"+this.item["abstract"]+"</p>"}return A}});var GamePopupMenu=Class.create({initialize:function(A,F,E,D){this.callbacks=D;document.fire("game:busy",{busy:true});this.menuElement=$("uniquePopupMenu");if(this.menuElement){this.menuElement.hide();this.menuElement.update();this.menuElement.setStyle({left:A+"px",top:F+"px"})}else{this.menuElement=new Element("ul",{id:"uniquePopupMenu","class":"popupMenu",style:"display: none; position: absolute; z-index: 1000; left:"+A+"px; top: "+F+"px"})}for(var B=0;B<E.length;B++){var C=new Element("li");C.update(E[B]);C.menuIndex=B;C.observe("click",this.choose.bindAsEventListener(this));this.menuElement.appendChild(C)}document.body.appendChild(this.menuElement);$(document.body).observe("click",this.cancel.bindAsEventListener(this));if(Effect){new Effect.BlindDown(this.menuElement,{duration:0.5})}else{this.menuElement.show()}},cancel:function(A){if(this.menuElement.visible()){document.fire("game:busy",{busy:false});if(Effect){new Effect.Fade(this.menuElement,{duration:0.5})}else{this.menuElement.hide()}A.stop();return false}},choose:function(B){var A=B.findElement("li");if(A&&typeof A.menuIndex!="undefined"){this.callbacks[A.menuIndex]()}this.cancel(B)}});var GameControl=Class.create({initialize:function(A){this.previousKey=null;this.Logic=A;this.Logic.bindController(this);this.bodyElement=$(document.body);Event.observe(document,"game:busy",this.onBusy.bindAsEventListener(this));Event.observe(document,"game:message",this.onMessage.bindAsEventListener(this));Event.observe(document,"game:inventoryChange",this.onInventoryChange.bindAsEventListener(this));Event.observe(document,"game:specsChange",this.onSpecsChange.bindAsEventListener(this));Event.observe(document,"keydown",this.keyboardHandler.bindAsEventListener(this));Event.observe(document,"game:error",this.onError.bindAsEventListener(this))},onInventoryChange:function(){var E=$("inventoryList");if(E){E.update()}else{var G=new Element("div",{"class":"statusWindow",id:"inventory",style:"overflow: auto"});G.update('<h6>Inventory</h6><table><tbody id="inventoryList"></tbody></table>');$("status").insert(G);Droppables.add(G,{accept:"item",onDrop:this.onReceiveItem.bind(this)});E=$("inventoryList")}var B=this.Logic.Player.data.inventory;var C=this.Logic.Bundle.items;for(var D=0;D<B.length;D++){var F=new Element("tr");var A=new Element("td");A.update(C[B[D].name].title.stripArticle().upperFirst());A.item=B[D].name;F.update(A);F.insert('<td class="number">'+(B[D].qty||1)+"</td>");E.insert(F);new GameItemTip(A,C[B[D].name]);if(C[B[D].name].onUse){A.observe("click",this.onInventoryClick.bindAsEventListener(this))}}},onInventoryClick:function(D){D.stop();var A=D.findElement("td");if(D.isLeftClick&&A&&A.item){var B=this.Logic.Bundle.items;var E=[],C=[];if(B[A.item].onUse){E.push('<img src="images/icons/cog.png" alt="Cog"/>Use');C.push(this.Logic.useItem.bind(this.Logic,A.item))}new GamePopupMenu(D.pointerX(),D.pointerY(),E,C)}},onReceiveItem:function(A){if(A.packet&&A.packet.item&&A.packet.qty){this.Logic.Player.addInventory(A.packet.item,A.packet.qty);document.fire("game:inventoryChange");if(typeof A.packet.onMove=="function"){A.packet.onMove(A)}}},onSpecsChange:function(){var C=$("specs");if(!C){C=new Element("div",{"class":"statusWindow",id:"specs"});C.setStyle({overflow:"auto"});$("status").insert(C)}var B=this.Logic.Player.data.specs,A="<h6>Player</h6>";A+='<div id="playerIconBar">';A+='<a href="#" id="showEquip" title="Equipment"><img src="images/icons/shield.png" alt="Equipment"/></a>';A+='<a href="#" id="showStats" title="Stats"><img src="images/icons/user.png" alt="Stats"/></a>';A+='<a href="#" id="gameLoad" title="Load"><img src="images/icons/folder.png" alt="Open"/></a>';A+='<a href="#" id="gameSave" title="Save"><img src="images/icons/disk.png" alt="Open"/></a>';A+"</div>";A+="<div><table><tbody>";if(B.hit<B.maxHit*0.1){A+='<tr><td>Hit points</td><td class="number"><span class="tooLow">'+B.hit+"</span>/"+B.maxHit+"</td></tr>"}else{A+='<tr><td>Hit points</td><td class="number">'+B.hit+"/"+B.maxHit+"</td></tr>"}A+='<tr><td>Mana</td><td class="number">'+B.mana+"/"+B.maxMana+"</td></tr>";A+="</tbody></table>";A+="<table><tbody>";A+='<tr><td>Level</td><td class="number">'+B.level+"</td></tr>";A+='<tr><td>Xp</td><td class="number">'+B.xp+"</td></tr>";A+="</tbody></table></div>";C.update(A);$("showEquip").observe("click",function(D){D.stop();new DialogEquip(this.Logic);return false}.bindAsEventListener(this));$("showStats").observe("click",function(D){D.stop();new DialogStats(this.Logic);return false}.bindAsEventListener(this));$("gameLoad").observe("click",function(D){D.stop();new DialogLoad(this.Logic);return false}.bindAsEventListener(this));$("gameSave").observe("click",function(D){D.stop();new DialogSave(this.Logic);return false}.bindAsEventListener(this))},onBusy:function(A){this.busy=A.memo.busy;if(A.memo.title){this.writeConsole(A.memo.title)}this.bodyElement.setStyle({cursor:(A.memo.mustWait)?"wait":""})},onError:function(A){if(A.memo&&A.memo.title){if(console&&console.log){if(A.memo.type=="error"){console.error(A.memo.title)}return }if(opera&&typeof opera.postError=="function"){opera.postError(A.memo.title);return }}},onMessage:function(A){this.writeConsole(A.memo.title)},writeConsole:function(D,B){var C=$("command");if(C.childNodes.length>400){var A=0;while(A<100&&C.childNodes.length>100){if(C.childNodes[0].tagName=="BR"){A++}C.removeChild(C.childNodes[0])}}C.insert(D+((typeof B!="undefined"&&!B)?"":"<br/>"));C.scrollTop=C.scrollHeight},keyboardHandler:function(B){if(!this.busy){var A=true;switch(B.keyCode){case Event.KEY_LEFT:if(this.previousKey){this.writeConsole("West")}this.Logic.playerAct(-1,0,this.previousKey);this.previousKey=null;break;case Event.KEY_RIGHT:if(this.previousKey){this.writeConsole("East")}this.Logic.playerAct(1,0,this.previousKey);this.previousKey=null;break;case Event.KEY_UP:if(this.previousKey){this.writeConsole("North")}this.Logic.playerAct(0,-1,this.previousKey);this.previousKey=null;break;case Event.KEY_DOWN:if(this.previousKey){this.writeConsole("South")}this.Logic.playerAct(0,1,this.previousKey);this.previousKey=null;break;case 32:this.Logic.doCycle();this.writeConsole("Pass...");break;case 65:this.previousKey="a";this.writeConsole("<em>A</em>ttack ",false);break;case 71:this.previousKey="g";this.writeConsole("<em>G</em>et ",false);break;case 76:this.previousKey="l";this.writeConsole("<em>L</em>ook ",false);break;case 80:this.previousKey="p";this.writeConsole("<em>P</em>ush ",false);break;case 84:this.previousKey="t";this.writeConsole("<em>T</em>alk ",false);break;case 85:this.previousKey="u";this.writeConsole("<em>U</em>se ",false);break;default:A=false}if(A){B.stop()}}}});var DialogBasic=Class.create({modalWindow:null,bodyElement:null,onClose:null,initialize:function(F,D,E,B){this.bodyElement=$(document.body);this.onClose=F;document.fire("game:busy",{busy:true});this.modalWindow=new Element("div",{"class":"modal"+((B)?" "+B:""),style:"position: absolute; display: none; z-index: 500"});this.modalWindow.update(((typeof E=="string"&&E.length)?'<h5 class="handle">'+E+"</h5>":"")+D);this.bodyElement.appendChild(this.modalWindow);var A=this.modalWindow.getDimensions();var C=document.viewport.getDimensions();this.modalWindow.setStyle({zIndex:100,left:Math.floor((C.width-A.width)/2)+"px",top:Math.floor((C.height-A.height)/2)+"px",display:""});if(Draggable&&E&&E.length){new Draggable(this.modalWindow,{handle:"handle"})}},close:function(){if(this.modalWindow){if(Effect){new Effect.Fade(this.modalWindow,{afterFinish:function(A){A.element.remove()}})}else{this.modalWindow.remove()}this.modalWindow=null;document.fire("game:busy",{busy:false})}}});var DialogContainer=Class.create(DialogBasic,{initialize:function($super,D,B,A){this.Logic=D;this.bag=B;if(typeof this.bag.content!="object"){this.bag.content=[]}var C=this.Logic.Bundle.items;$super(A,'<div id="itemList" class="content" style="overflow: auto"></div><div class="buttonRow"><button type="button" id="takeAll">Take All</button> <button type="button" id="closeButton">OK</button></div>',C[this.bag.name].title.upperFirst(),"bag");this.refresh();$("closeButton").observe("click",this.close.bindAsEventListener(this));$("takeAll").observe("click",this.takeAndClose.bindAsEventListener(this))},refresh:function(){var A=this.Logic.Bundle.items;var C=$("itemList");C.update();for(var B=0;B<this.bag.content.length;B++){var D=new Element("div",{"class":"handle item"});D.packet={item:this.bag.content[B].name,qty:(this.bag.content[B].qty||1),onMove:this.onItemMoved.bind(this)};if(typeof A[D.packet.item]=="object"){D.update(A[D.packet.item].title.stripArticle().upperFirst()+((D.packet.qty)?" ("+D.packet.qty+")":""));C.insert(D);D.tooltip=new GameItemTip(D,A[D.packet.item]);new Draggable(D,{revert:true,ghosting:true})}else{document.fire("game:error",{type:"error",title:'Invalid "'+D.packet.item+'" item, no description in item file.'})}}},onItemMoved:function(B){var A=0,C=this.bag.content;while(A<C.length&&C[A].name!=B.packet.item){A++}if(A<C.length){if(B.tooltip){B.tooltip.destroy();B.tooltip=null}C.splice(A,1);this.refresh()}},takeAndClose:function(){for(var A=0;A<this.bag.content.length;A++){this.Logic.Player.addInventory(this.bag.content[A].name,this.bag.content[A].qty||1)}this.bag.content=[];document.fire("game:inventoryChange");this.close()},close:function($super){$super();if(this.onClose){this.onClose()}}});var DialogQuestion=Class.create(DialogBasic,{initialize:function($super,A,D,E){this.unique=Math.unique();var C='<div class="content">';if(A&&A.length){C+="<p>"+A+"</p>"}if(D&&D.length>1){C+='<form method="get" action="" id="modalForm">';for(var B=0;B<D.length;B++){C+='<label><input type="radio" name="MCQ" value="'+D[B].value+'"'+((B==0)?' checked="checked"':"")+"/> "+D[B].key.upperFirst()+"</label><br/>"}C+="</form>"}C+='</div><div class="buttonRow"><button type="button" id="modalSubmitButton'+this.unique+'">OK</button></div>';$super(E,C,null,"question");window.setTimeout(function(){$("modalSubmitButton"+this.unique).observe("click",this.close.bindAsEventListener(this)).focus()}.bind(this),10)},close:function($super,C){C.stop();var A=null;if($("modalForm")){var B=$("modalForm").getInputs("radio","MCQ").find(function(D){return D.checked});if(B){var A=$F(B)}}$super();if(this.onClose){this.onClose(A)}}});var DialogInput=Class.create(DialogBasic,{initialize:function($super,A,C,D){this.answers=C;this.unique=Math.unique();var B='<div class="content">';if(A&&A.length){B+="<p>"+A+"</p>"}B+='</div><div class="buttonRow"><input type="text" name="reply" id="reply"/><button type="button" id="modalSubmitButton'+this.unique+'">OK</button></div>';$super(D,B,null,"question");$("reply").focus();$("reply").observe("keypress",function(E){if(E.keyCode==Event.KEY_RETURN){this.close(E)}}.bindAsEventListener(this));$("modalSubmitButton"+this.unique).observe("click",this.close.bindAsEventListener(this))},close:function($super,D){D.stop();var B=$F("reply").strip().toLowerCase();if(B.length){var A=null;if(!Object.isArray(this.answers)){A=B}else{var C=this.answers.indexOfObject("key",B);if(C<0){C=this.answers.indexOfObject("key","#any")}if(C>-1){A=this.answers[C].value}}if(A!==null){$super();if(this.onClose){this.onClose(A)}}else{$("reply").value="";$("reply").focus()}}}});var DialogConversation=Class.create(DialogBasic,{initialize:function($super,A){this.conv=A;$super(null,'<div style="overflow: auto" id="hear" class="content"></div><div class="buttonRow"><input type="text" id="say"/></div>',"Talking","talk");$("say").observe("keypress",this.listenTalk.bindAsEventListener(this));$("say").focus();this.conv.bindConsole(function(B){$("hear").insert('<p class="npc">'+B+"</p>");$("hear").scrollTop=$("hear").scrollHeight}.bind(this),this.endTalk.bind(this))},listenTalk:function(A){var B=$F("say");if(A.keyCode==Event.KEY_RETURN&&B.length){if(B.substr(0,1)!="#"){$("hear").insert('<p class="player">You say: <em>'+B.stripTags().strip()+"</em></p>");this.conv.say(B)}if($("say")){$("say").value=""}A.stop()}},endTalk:function(){var A=new Element("button",{type:"button"});A.update("Close");A.observe("click",function(B){this.close();B.stop()}.bindAsEventListener(this));$("say").replace(A);A.focus()}});var DialogEquip=Class.create(DialogBasic,{initialize:function($super,B){this.Logic=B;var A="";A+='<div id="allEquipment">';A+='<div id="availableEquipment" style="overflow: auto"></div>';A+='<div id="wornEquipment"></div>';A+="</div>";A+='<div class="buttonRow"><button type="submit" id="closeModal">Close</button></div>';$super(null,A,"Equipment","equipment");this.refreshItems();this.refreshEquip();Droppables.add("wornEquipment",{onDrop:this.dropEquipment.bind(this)});$("closeModal").observe("click",this.close.bindAsEventListener(this));$("closeModal").focus()},refreshItems:function(){var A=this.Logic.Player.data.inventory;$("availableEquipment").update("<h6>Available</h6>");for(var B=0;B<A.length;B++){var C=this.Logic.Bundle.items[A[B].name];if(C&&C.title&&this.Logic.Player.readyAble.indexOf(C.type)>-1){var D=new Element("div",{style:"overflow: visible","class":"handle"});D.update(C.title.stripArticle().upperFirst());D.item=A[B].name;$("availableEquipment").insert(D);new Draggable(D,{revert:true,ghosting:true});D.tooltip=new GameItemTip(D,C)}}},refreshEquip:function(){var C=this.Logic.Player.data.equipment;var A=this.Logic.Bundle.items;var B="<h6>Ready</h6><table><tbody>";B+='<tr><td>Weapon</td><td class="equip" id="weapon">'+((C.weapon)?A[C.weapon].title.stripArticle().upperFirst():"")+"</td></tr>";B+='<tr><td>Shield</td><td class="equip" id="shield">'+((C.shield)?A[C.shield].title.stripArticle().upperFirst():"")+"</td></tr>";B+='<tr><td>Armor</td><td class="equip" id="bodyArmor">'+((C.bodyArmor)?A[C.bodyArmor].title.stripArticle().upperFirst():"")+"</td></tr>";B+='<tr><td>Ring</td><td class="equip" id="ring">'+((C.ring)?A[C.ring].title.stripArticle().upperFirst():"")+"</td></tr>";B+="</tbody></table>";$("wornEquipment").update(B);$$("td.equip").each(function(D){if(C[D.id]){new GameItemTip(D,A[C[D.id]])}}.bind(this))},dropEquipment:function(A){if(this.Logic.Player.ready(A.item)){if(A.tooltip){A.tooltip.destroy();A.tooltip=null}this.refreshItems();this.refreshEquip()}}});var DialogStats=Class.create(DialogBasic,{initialize:function($super,B){this.Logic=B;var C=this.Logic.Player.data.specs;this.newSpecs=Object.deepClone(C);var A='<div class="content">';A+='<div>Learning points: <span id="compPoints">'+this.newSpecs.competence+'</span> (<a href="#" id="reset">reset</a>)</div>';A+='<div id="specsContent"><table><thead><tr><td></td><td>Cur.</td><td>Upg.</td><td></td></tr></thead><tbody id="attribList">';A+=this.refreshAttributes(true);A+="</tbody></table>";A+='<table><thead><tr><td></td><td>Cur.</td><td>Upg.</td><td></td></tr></thead><tbody id="skillList">';A+=this.refreshSkills(true);A+="</tbody></table></div>";A+='</div><div class="buttonRow">'+((C.competence>0)?'<button type="button" id="saveModal">Save changes</button> ':"")+'<button type="button" id="closeModal">Close</button></div>';$super(null,A,"Player stats","stats");this.setAttributesEvents();this.setSkillsEvents();$("closeModal").observe("click",this.close.bindAsEventListener(this));$("closeModal").focus();if(C.competence>0){$("saveModal").observe("click",this.save.bind(this))}$("reset").observe("click",function(D){D.stop();this.newSpecs=Object.deepClone(this.Logic.Player.data.specs);$("compPoints").update(this.newSpecs.competence);this.refreshAttributes();this.refreshSkills()}.bindAsEventListener(this))},save:function(A){this.Logic.Player.data.specs=this.newSpecs;document.fire("game:specsChange");this.close(A)},attrInc:function(B){var A=B.findElement("A").title;if(this.newSpecs.competence>=5){this.newSpecs.competence-=5;this.newSpecs.attributes[A]++;$("compPoints").update(this.newSpecs.competence);this.refreshAttributes()}B.stop()},skillInc:function(B){var A=B.findElement("A").title;if(this.newSpecs.competence>0){this.newSpecs.competence--;this.newSpecs.skills[A]=(this.newSpecs.skills[A]||0)+1;$("compPoints").update(this.newSpecs.competence);this.refreshSkills()}B.stop()},refreshSkills:function(D){var E=this.Logic.Player.data.specs;var B="";var C=Object.keys(PROTORPG.consts.skillNames);for(var A=0;A<C.length;A++){B+="<tr><td>"+PROTORPG.consts.skillNames[C[A]]+'</td><td class="number">'+(E.skills[C[A]]||0)+'</td><td class="number">'+(this.newSpecs.skills[C[A]]||0)+"</td><td>"+((this.newSpecs.competence>0)?'<a href="#" class="skillInc" title="'+C[A]+'">+1</a>':"")+"</td></tr>"}if(!D){$("skillList").update(B)}this.setSkillsEvents();return B},refreshAttributes:function(E){var F=this.Logic.Player.data.specs;var C="";var D=["STR","CON","AGI","DEX","INT","CHA"],A=["Strength","Constitution","Agility","Dexterity","Intelligence","Charisma"];for(var B=0;B<D.length;B++){C+="<tr><td>"+A[B]+'</td><td class="number">'+F.attributes[D[B]]+'</td><td class="number">'+this.newSpecs.attributes[D[B]]+"</td><td>"+((this.newSpecs.competence>=5)?'<a href="#" class="attrInc" title="'+D[B]+'">+1</a>':"")+"</td></tr>"}if(!E){$("attribList").update(C)}this.setAttributesEvents();return C},setSkillsEvents:function(){$$(".skillInc").invoke("observe","click",this.skillInc.bindAsEventListener(this))},setAttributesEvents:function(){$$(".attrInc").invoke("observe","click",this.attrInc.bindAsEventListener(this))}});var PersistentOverlayCollection=Class.create({stack:null,viewport:null,initialize:function(A){this.viewport=$(A);this.stack=new Hash()},add:function(A,B){if(!this.stack.get(A)){var C=new Element("div",{id:"pOver"+A});if(typeof B=="object"){C.setStyle(B)}this.viewport.insert(C);this.stack.set(A,C);return(C)}else{return(this.stack.get(A))}},change:function(A,B){this.stack.get(A).setStyle(B)},remove:function(A){this.stack.unset(A).remove()},clear:function(){this.stack.each(function(A){this.remove(A.key)}.bind(this))}});var GameDisplay=Class.create({initialize:function(B,A){this.viewport=$(B);this.graphics=A;this.tileSize=32;this.Map=null;this.pOverlays=new PersistentOverlayCollection(this.viewport)},cleanUp:function(){this.pOverlays.clear();this.player=null;if(this.viewport){this.viewport.update()}},configure:function(A){this.cleanUp();this.tileSize=A.graphics.tileSize;this.initViewport()},initViewport:function(){this.viewport.makePositioned();this.viewport.setStyle({backgroundColor:"#000"});this.tileWidth=Math.round(this.viewport.clientWidth/this.tileSize);this.tileHeight=Math.round(this.viewport.clientHeight/this.tileSize);for(var A=0;A<this.tileWidth*this.tileHeight;A++){var B=new Element("div",{id:"tile"+A,"class":"tile"});B.setStyle({position:"absolute",top:Math.floor(A/this.tileWidth)*this.tileSize+"px",left:(A%this.tileWidth)*this.tileSize+"px"});B.mapOffset=A;B.tileId=null;this.viewport.insert(B)}var C;if(document.createStyleSheet){C=document.createStyleSheet();C.addRule("div.tile","width: "+this.tileSize+"px; height: "+this.tileSize+"px; margin: 0; padding: 0; background-color: transparent")}else{C=new Element("style",{type:"text/css"});C.insert("div.tile { width: "+this.tileSize+"px; height: "+this.tileSize+"px; margin: 0; padding: 0; background-color: transparent }");document.getElementsByTagName("head")[0].appendChild(C)}},bindMap:function(A){this.Map=A},styleTile:function(A){if(typeof A=="object"){return{background:"url('"+this.graphics+A[0]+"') "+(A[1]*-32)+"px 0px"}}else{if(A){return{background:"url('"+this.graphics+A+"')"}}else{return{background:""}}}},drawPosition:function(E,A){if(typeof A!="number"){A=65535}if(A&4){if(!this.player){this.player=this.pOverlays.add("player",{width:this.tileSize+"px",height:this.tileSize+"px",position:"absolute",left:(Math.floor(this.tileWidth/2)*this.tileSize)+"px",top:(Math.floor(this.tileHeight/2)*this.tileSize)+"px",padding:0,margin:0})}this.player.setStyle(this.styleTile(this.Map.Player.getFile()))}var H;if(A&2){var B=new FogOfWar(this.Map,this.tileWidth,this.tileHeight);H=B.compute(E)}else{H=this.Map.copySection(E.x-Math.floor(this.tileWidth/2),E.y-Math.floor(this.tileHeight/2),this.tileWidth,this.tileHeight)}for(var G=0;G<this.tileHeight;G++){for(var I=0;I<this.tileWidth;I++){var D=H[G][I];this.drawTile(I,G,D)}}if(A&1){var K=E.x-Math.floor(this.tileWidth/2);var J=E.y-Math.floor(this.tileHeight/2);var F=this.Map.compileOverlays(K,J,K+this.tileWidth-1,J+this.tileHeight-1);for(var C=0;C<F.length;C++){if(H[F[C].y-J][F[C].x-K]!=-1){this.drawOverlay(F[C].x-K,F[C].y-J,F[C].file)}}}},drawOverlay:function(A,D,C){var B=new Element("div",{"class":"tile",style:"position: absolute"});B.setStyle(this.styleTile(C));document.getElementById("tile"+(A+D*this.tileWidth)).appendChild(B)},drawTile:function(A,G,F){var C=document.getElementById("tile"+(A+G*this.tileWidth));if(C.hasChildNodes()){C.update()}if(typeof F=="object"){C.setStyle(this.styleTile(this.Map.tileset[F[0]].file));C.tileId=F[0];for(var B=1;B<F.length;B++){var E=new Element("div",{"class":"tile",style:"position: absolute"});E.setStyle(this.styleTile(this.Map.tileset[F[B]].file));C.appendChild(E)}}else{var D=(F>=0)?this.Map.tileset[F].file:false;C.setStyle(this.styleTile(D));C.tileId=F}}});var DialogSave=Class.create(DialogBasic,{initialize:function($super,C,A){this.Logic=C;var B='<form method="post" action="" id="saveForm"><table><tbody><tr><td><label for="login">Login</label>:</td><td><input type="text" id="loginBox" name="login" value="'+(A||"")+'"/></td></tr><tr><td><label for="password">Password</label>:</td><td><input type="password" id="passwordBox" name="password" value=""/></td></tr><tr><td></td><td><button id="closeAndSaveButton" type="button">Save</button> <button id="closeButton" type="button">Cancel</button></td></tr><tr><td colspan="2" id="progressMessage"></td></tr>';"</tbody></table></form>";$super(null,B,"Save game","saveLogin");$("closeAndSaveButton").observe("click",this.closeAndSave.bindAsEventListener(this));$("closeButton").observe("click",this.close.bindAsEventListener(this))},closeAndSave:function(){$("saveForm").disable();$("progressMessage").update("Saving to slot 1...");var A=new GameHTTPSaver(PROTORPG.config.saveScript,$F("loginBox"),$F("passwordBox"),this.Logic.Bundle.data.title);this.Logic.saveGame(A,function(B){if(B=="OK"){this.close()}else{$("saveForm").enable();$("progressMessage").update(B)}}.bind(this))}});var DialogLoad=Class.create(DialogBasic,{initialize:function($super,C,A){this.Logic=C;var B='<form method="post" action="" id="loadForm"><table><tbody><tr><td><label for="login">Login</label>:</td><td><input type="text" id="loginBox" name="login" value="'+(A||"")+'"/></td></tr><tr><td><label for="password">Password</label>:</td><td><input type="password" id="passwordBox" name="password" value=""/></td></tr><tr><td></td><td><button id="closeAndLoadButton" type="button">Load</button> <button id="closeButton" type="button">Cancel</button></td></tr><tr><td colspan="2" id="progressMessage"></td></tr>';"</tbody></table></form>";$super(null,B,"Load game","loadLogin");$("closeAndLoadButton").observe("click",this.closeAndLoad.bindAsEventListener(this));$("closeButton").observe("click",this.close.bindAsEventListener(this))},closeAndLoad:function(){$("loadForm").disable();$("progressMessage").update("Loading from slot 1...");var A=new GameHTTPSaver(PROTORPG.config.saveScript,$F("loginBox"),$F("passwordBox"),this.Logic.Bundle.data.title);this.Logic.loadGame(A,function(B){if(B=="OK"){this.close()}else{$("loadForm").enable();$("progressMessage").update(B)}}.bind(this))}});var GameHTTPSaver=Class.create({initialize:function(A,C,D,B,E){this.url=A;this.login=C;this.password=D;this.slot=E||1;this.game=B},save:function(A,B){new Ajax.Request(this.url,{method:"post",parameters:{func:"save",login:this.login,password:this.password,slot:this.slot,game:this.game,packet:Object.toJSON(A)},onSuccess:function(C){B(C.responseText)}})},load:function(A){new Ajax.Request(this.url,{method:"get",parameters:{func:"load",login:this.login,password:this.password,slot:this.slot,game:this.game},onSuccess:function(B){A(B.responseText)}})}});