// Time-stamp: <rpg_lib.js 2007-01-06 04:31:08 Motika>
/* This notice must be untouched at all times.

http://www.wtfrpg.com/front/rpg_lib.js    v. 1.0

Copyright (c) wtfrpg.com. All rights reserved.
*/

var gcommonalityNames=new Array("Poor","Common","Uncommon","Rare","Epic");

function ttW(tag,itemname,desc,level,equip,slot,commonality,bonus,unique,equipstate,damdef,price,skills,requirements) {
	var itxt="";
	var isshield=("Shield"==equip);
	initBasicHoverTag(tag);

	if("Equipped Weapon"==slot)
		slot="Weapon";
	itxt+="<div class=item-name-"+commonality+">"+itemname+"</div>";
	itxt+="<div class=item-level>Level "+level+"</div>";

	if (equipstate) {
		if ("Equipped"==equipstate)
			itxt+="<div class=item-equip-2>Equipped</div>";
		else if ("Equippable"==equipstate)
			itxt+="<div class=item-equip-1>Equippable</div>";
		else
			itxt+="<div class=item-equip-0>Cannot Equip: " + equipstate + "</div>";
	}

	itxt+="<div class=item-commonality-"+unique+">"+(unique!=0?"Unique ":"")+gcommonalityNames[commonality]+((bonus>0&&bonus>=commonality)?(" (+"+(bonus+1-commonality)+" Bonus)"):"")+"</div>";
	if ( "Armor"==equip||"Cloth Armor"==equip||"Mail Armor"==equip||isshield) {
		itxt+="<div class=item-equipment>"+(isshield?equip:slot)+"</div>";
		itxt+="<div class=item-damage-armor>"+damdef+" "+(equip=="Shield"?"Armor":equip)+"</div>";
	} else if ("Weapon"==slot&&!isshield){
		itxt+="<div class=item-equipment>"+equip+"</div>";
		itxt+="<div class=item-damage-armor>"+damdef+" Damage</div>";
	} else {
		itxt+="<div class=item-equipment>"+equip+"</div>";
	}

	itxt=appendRequirements(itxt,requirements,"item");
	itxt=appendSkills(itxt,skills,"item");

	itxt+="<div class=item-price>Merchant Retail Value: <span class=item-price-"+commonality+">"+price+" Gold</span><br/>"
	itxt+="<span class=item-price-wholesale>Street Wholesale Value: ~"+(Math.max(Math.round(price/4),1))+" Gold</span></div>";

	if (desc)
		itxt+= "<div class=item-description-"+unique+">"+desc+"</div>";

//	alert("toolTipWeapon "+itemname+","+equip+","+slot+","+commonality+": "+itxt);
	return itxt;
}

function ttM(tag,name,desc,group) {
	var itxt="";
	initBasicHoverTag(tag);

	itxt+="<div class=metric-name>"+name+"</div>";
	itxt+="<div class=metric-group>"+group+"</div>";

	if (desc)
		itxt+= "<div class=metric-description>"+desc+"</div>";

//	alert("ttM "+name+","+group+": "+itxt);
	return itxt;
}

function ttG(tag,classprefix,name,desc,group,skill,attributes,requirements) {
	var itxt="";
	initBasicHoverTag(tag);

	itxt+="<div class="+classprefix+"-name>"+name+"</div>";
	itxt+="<div class="+classprefix+"-group>"+group+"</div>";

	if (skill)
		itxt+="<div class="+classprefix+"-skill>Focus: <span class="+classprefix+"-skill-value>"+skill+"</span></div>";

	itxt=appendAttributes(itxt,attributes,classprefix);
	itxt=appendRequirements(itxt,requirements,classprefix);

	if (desc)
	{
		dtxt = desc;
		dflavor = null;
		fpi = desc.indexOf( '(' );

		if ( fpi >= 0 )
		{
			fpe=desc.indexOf(')',fpi)
			dflavor=desc.substring(0,fpi);
			dtxt=desc.substring(fpi+1,fpe<0?desc.length:fpe);
		}
		
		itxt+="<div class="+classprefix+"-description>"+dtxt+"</div>";

		if (dflavor)
			itxt+="<div class="+classprefix+"-description-flavor>"+dflavor+"</div>";
	}
//	alert("ttM "+name+","+group+": "+itxt);

	return itxt;
}

function initBasicHoverTag(tag) {
	tag.T_WIDTH=340;
	tag.T_SHADOWWIDTH = 2; 
	tag.T_SHADOWCOLOR="#888888"; 
	tag.T_BGCOLOR="#000000"; 
	tag.T_FONTCOLOR="#ffffff"; 
	tag.T_FONTSIZE="13.5px";
	tag.T_STATIC=true;

	return tag;
}

function initBasicSubmenuTag(tag) {
	tag.T_BGCOLOR="#ddddb0"; 
	tag.T_FONTCOLOR="#000000"; 
	tag.T_FONTSIZE="12px";
	tag.T_STATIC=true;
	tag.T_STICKY=true;
	tag.T_TEMP=50000;

	return tag;
}

var	ENTITY_SUBMENU_ELEMENTS = 8;
var ENTITY_MENU=new Array(
		"entity/", 0, "View", "", " ", null, null, "View",
		"entity-stats/", 1, "Stats", "Character skills and stats", null, null, "Skills and Stats", "View",
		"entity-edit/", 1, "Edit", "Edit description and interests", null, "local", null, "View",
		"entity-edit-friends/", 1, "Friends", "Keep track of friends and local jerkwads", null, "local", null, "View",
		"entity-edit-inventory/", 1, "Stuff", "Manage ", "'s inventory", "local", "Inventory", "View",
		"entity-edit-image/", 1, "Image", "Select Image", null, "local", "Select Image", "View",
		"entity-blog/view/", 0, "Blog", "Read ", "'s scandalous blog", null, "Read Blog", "Blog",
		"entity-blog/post/", 1, "Post", "Make a new blog post ", null, "local", "Make a Post", "Blog",
		"entity-news/", 0, "News", "Read ", "'s recent exploits", null, null, "News",
		"entity-spells/Combat_Skill/", 0, "Spells", "", "'s Combat Spells", null, "Combat Spells", "Spells",
		"entity-spells/Equipment/", 0, null, "Weapon Skills and Strikes", null, null, "Weapon Skills", "Spells",
		"entity-spells/General_Skill/", 0, null, "General Spells and abilities", null, null, "General Spells", "Spells",
		"entity-mail/Send/", 0, "Mail", "Send mail", null, "foreign", "Send Mail", "Mail",
		"entity-mail/Inbox/", 0, "Mail", "Read ", "'s mail", "local", "Read Mail", "Mail",
		"entity-mail/Send/", 1, "Send", "Send mail", null, "local", "Compose Mail", "Mail",
		"entity-duel/", 0, "Duel", "Start some trouble ", null, null, null, "Duel",
		"entity-quests/Combat_Skill/", 0, "Quests", "Pick combat quests for ", " ", "local", "Combat Quests", "Quests",
		"entity-quests/General_Skill/", 1, null, "Pick General Skill quests", null, "local", "General Quests", "Quests",
		"entity-quests/Current_List/", 1, "List", "Current quest schedule", null, "local", "Quest Schedule", "Quests",
		"entity-shop/", 0, "Shop", "Shop for ", " ", "local", null, "Shop"
	);

function ttEMenu(tag,charname,title,current,scope,urlgrouponly,entryflags,width1,totalwidth,subonly) {
	initBasicSubmenuTag(tag);
	if (totalwidth>0)
		tag.T_WIDTH=totalwidth;
	if (!title&&subonly) {
		tag.T_OFFSETX=-20;
		tag.T_OFFSETY=15;
	} else if ("local"==scope) {
		tag.T_OFFSETX=70;
		tag.T_OFFSETY=-20;
	} else if ("foreign"==scope) {
		tag.T_OFFSETX=30;
		tag.T_OFFSETY=title?-90:-20;
	}
	var itxt="";
	var currententrygroup=null;
	var showannotations=(entryflags && entryflags.indexOf && entryflags.indexOf("show-annotations")>=0);
	var horizontal=(entryflags && entryflags.indexOf && entryflags.indexOf("show-horizontal")>=0);
	var	entrytag=(horizontal?"span":"div");
	var	entryclass=(horizontal?"tooltip-menu-h":"tooltip-menu");
	if (title)
		itxt+="<div class=\"tooltip-title\"><span class=\"tooltip-title-name\">"+charname+"</span>: <span class=\"tooltip-title-text\">"+title+"</span></div>";
	for (i=0;i<ENTITY_MENU.length;i+=ENTITY_SUBMENU_ELEMENTS){
		mnflags=ENTITY_MENU[i+5];
		if (mnflags&&mnflags.indexOf(scope)<0)
			continue;
		entrygroup=subonly?0:ENTITY_MENU[i+1];
		if (!entrygroup)
			currententrygroup=entrygroup;
		if (!urlgrouponly&&!ENTITY_MENU[i+2]&&!subonly)
			continue;
		if (urlgrouponly&&currententrygroup!=urlgrouponly)
			continue;
		if (subonly&&subonly!=ENTITY_MENU[i+7])
			continue;
		mnurl=ENTITY_MENU[i+0];

		isloc=(current.indexOf(mnurl)==0);
		itxt+="<"+entrytag+" class=\""+entryclass+(isloc?"-selected":"")+"\"><a class=\"tooltip-link\" href=\"/"+mnurl+charname+".html\">";

		itxt+="<span class=\"tooltip-menu-"+entrygroup+"\">";
		itxt+=((urlgrouponly||subonly)&&ENTITY_MENU[i+6])?ENTITY_MENU[i+6]:ENTITY_MENU[i+2];
		if (showannotations) {
			mntitle2=ENTITY_MENU[i+4];
			itxt+="</span><span class=\"tooltip-ann\" style=\"left: "+width1+"\">"+ENTITY_MENU[i+3]+(mntitle2?(charname+mntitle2):'')+"";
		}
		itxt+="</span>";
		itxt+="</a></"+entrytag+">";
	}

	return itxt;
}

function appendSkills(stxt,skills,classprefix) {
	if(skills && skills.length>0) {
		stxt+="<div class="+classprefix+"-skill-bonus-section>";
		for(i=0;i<skills.length;i+=2) {
			stxt+="<div class="+classprefix+"-skill-bonus>"+(skills[i]>0?"+":"")+skills[i]+" "+skills[i+1]+"</div>";
		}
		stxt+="</div>";
	}

	return stxt;
}

function appendRequirements(stxt,requirements,classprefix) {
	if(requirements && requirements.length>0) {
		stxt+="<div class="+classprefix+"-requirement-section>";
		for(i=0;i<requirements.length;i+=2) {
			stxt+="<div><span class="+classprefix+"-requirement-name>"+requirements[i]+"</span>: <span class="+classprefix+"-requirement-value>"+requirements[i+1]+"</span></div>";
		}
		stxt+="</div>";
	}

	return stxt;
}

function appendAttributes(stxt,atts,classprefix) {
	if(atts && atts.length>0) {
		stxt+="<div class="+classprefix+"-attribute-section>";
		for(i=0;i<atts.length;i+=2) {
			stxt+="<div><span class="+classprefix+"-attribute-name>"+atts[i]+"</span>: <span class="+classprefix+"-attribute-value>"+atts[i+1]+"</span></div>";
		}
		stxt+="</div>";
	}

	return stxt;
}

function constrainTextArea(txarea,msgtag,maxchars){
  sz=txarea.value.length;
  msg=sz;
  if(sz>maxchars){
    msg="<span style='color: #ff0000; font-weight: bold;'>[Warning: Oversized] "+sz+"</span>";
  }
  msgtag.innerHTML=msg;
}

var STYLE_MATCHES = new Array( /[_][*](\w)/, /(\w)[*][_]/, "<i><b>$1", "$1</b></i>",
							   /[*](\w)/, /(\w)[*]/, "<b>$1", "$1</b>",
							   /[_](\w)/, /(\w)[_]/, "<i>$1", "$1</i>" );
function styleify(tag) {
	// with "var d" below it crashes IE.  ?!?
	var	s = "<div>" + tag.innerHTML + "</div>";
	var origs = s;

	// IE bug drops PRE formatting at tag content replacement.
	if (true || document.all) {
		s = s.replace( /\r\n/g, "</div><div>" );
		s = s.replace( /[ ][ ]/g, "&nbsp; " );
	}

	for ( i = 0; i < STYLE_MATCHES.length; i += 4 ) {
		var	rb1 = STYLE_MATCHES[ i ];
		var	rb2 = STYLE_MATCHES[ i + 1 ];

		while ( s.match( rb1 ) && s.match( rb2 ) ) {
			s = s.replace( rb1, STYLE_MATCHES[ i + 2 ] );
			s = s.replace( rb2, STYLE_MATCHES[ i + 3 ] );
		}
	}

	// alert( "Replaced \"" + origs + "\" -> \"" + s + "\"." );

	tag.innerHTML = s;
}


// ---------- Combat ---------

BAR_WIDTH=180;
BAR_HEIGHT=12;
STAT_WIDTH=30;
var	gtime;

function Effect(cast,effid,ename,etype,stylepfx,stage,dur,damage,bonusdamage,resisted,crit){
	this.caster=cast;
	this.eid=effid;
	this.name=ename;
	this.type=etype;
	this.styleprefix=stylepfx;
	this.stagename=stage;
	this.duration=dur;
	this.timestart=gtime;
	this.timeend=gtime+dur;
	this.iscrit=(crit);
	this.magnitude=0;
	this.damage=damage;
	this.bonusdamage=bonusdamage;
	this.resisted=resisted;

	this.isDone=isDone;
}

function isDone(){
	return (gtime<=this.timeend);
}

function Combatant(combid,arenaside,cname,health,mana,armor,csummonspell){
	this.cid=combid;
	this.side=arenaside;
	this.name=cname;
	this.hp=this.maxhp=this.basehp=health;
	this.mp=this.maxmp=this.basemp=mana;
	this.ap=this.maxap=armor;
	this.currentspell=null;
	this.summonspell=csummonspell;
	this.effects=new Array();

	// methods-- .prototype seems to invoke the functions at construction on FF?
	this.addHP=addHP;
	this.addMP=addMP;
	this.addAP=addAP;
	this.addMaxHP=addMaxHP;
	this.addMaxMP=addMaxMP;
	this.updateStatBar=updateStatBar;
	this.setCurrentSpell=setCurrentSpell;
	this.setCurrentSpellDefinition=setCurrentSpellDefinition;
	this.setCurrentSpellDuration=setCurrentSpellDuration;
	this.setCurrentSpellStage=setCurrentSpellStage;
	this.clearCurrentSpell=clearCurrentSpell;
	this.addEffect=addEffect;
	this.setEffect=setEffect;
	this.removeEffect=removeEffect;

//	alert("new Combatant("+this.cid+","+this.side+",'"+this.name+"')" );
}

function addHP(diff){
	v=this.hp+diff;
	v=v<0?0:(v>this.maxhp?this.maxhp:v);
	this.hp=v;
	this.updateStatBar("hp",v,(v*BAR_WIDTH/Math.max(this.basehp,this.maxhp)));

//	alert("addHP("+this.cid+","+this.side+",'"+this.name+"')" );
}

function addMP(diff){
	v=this.mp+diff;
	v=v<0?0:(v>this.maxmp?this.maxmp:v);
	this.mp=v;
	this.updateStatBar("mp",v,(v*BAR_WIDTH/Math.max(this.basemp,this.maxmp)));
}

function addAP(diff){
	v=this.ap+diff;
	v=v<0?0:v;
	diff=this.ap-v;
	this.ap=v;
	this.updateStatBar("ap",v,(v*BAR_WIDTH/this.maxap));
}

function addMaxHP(diff){
	v=this.maxhp+diff;
	this.maxhp=v<0?0:v;
	if (diff>0)
		this.hp+=diff;
	else
		this.hp=Math.min(this.hp,this.maxhp);
	addHP(0);
}

function addMaxMP(diff){
	v=this.maxmp+diff;
	this.maxmp=v<0?0:v;
	if (diff>0)
		this.mp+=diff;
	else
		this.mp=Math.min(this.mp,this.maxmp);
	addMP(0);
}

function updateStatBar(pfx,val,barval){
	ttag=document.getElementById(pfx+"text-"+this.cid);
	imtag=document.getElementById(pfx+"bar-"+this.cid);

	if (imtag)
		imtag.style.width=""+barval+"px";
	if (ttag)
		ttag.innerHTML=""+val;
//	alert("updateStatBar "+pfx+"text-"+this.cid+" val="+v+" imtag="+imtag+" ttag="+ttag);
}

function setCurrentSpellDefinition(name,typeidx,note,plusdamage,iscrit){
	nametag=document.getElementById("spellname-"+this.cid);

	// Changing the style by name was causing no browser effect.
	// Also multiple updates often get dropped.  So this is one update.
	if (nametag){
		nametag.innerHTML='<div class=\"combat-'+typeidx+'-spell-type\">'+name+(iscrit?('<span class=\"combat-crit\">&nbsp;Crit!</span>'):'')+'</div><div class=\"combat-spell-note\">'+note+'</div>';
		// +(plusdamage>0?(' (+'+plusdamage+' bonus)'):(plusdamage<-1?(' ('+(-plusdamage)+' decrease)'):''))
	}
}

function setCurrentSpellDuration(duration){
	return;
	durationtag=document.getElementById("spellduration-"+this.cid);
	if (durationtag)
		durationtag.innerHTML=(duration>=0)?(duration+"s"):"";
}

function setCurrentSpellStage(stagename){
	stagetag=document.getElementById("spellstage-"+this.cid);
	if (stagetag)
		stagetag.innerHTML=(stagename)?(stagename+":&nbsp;"):"";
}

function clearCurrentSpell(){
	setCurrentSpell(-1,"&nbsp;",0,"&nbsp; &nbsp;","&nbsp; &nbsp;",-1,0,0,0);
}

function setCurrentSpell(eid,name,typeidx,note,stagename,duration,damage,bonusdamage,iscrit){
	this.setCurrentSpellDefinition(name,typeidx,note,bonusdamage,iscrit);
	this.setCurrentSpellDuration(duration);
	this.setCurrentSpellStage(stagename);
}

function addEffect(eid,name,typeidx,note,stagename,duration,damage,bonusdamage,resisted){
	divtag=document.getElementById("spelleffect-"+this.cid);
	ch=document.createElement("div");
	ch.setAttribute("id","eff-"+this.cid+"-"+eid);

	ch.innerHTML='<div class=\"combat-'+typeidx+'-spell-type\">'+name+'</div><div class=\"combat-spell-note\">'+note+'</div>';

	if (divtag)
		divtag.appendChild(ch);
}

function setEffect(eid,name,typeidx,note,damage,bonusdamage,resisted){
	ch=document.getElementById("eff-"+this.cid+"-"+eid);
	ch.innerHTML='<div class=\"combat-'+typeidx+'-spell-type\">'+name+'</div><div class=\"combat-spell-note\">'+note+'</div>';
}

function removeEffect(eid){
	ch=document.getElementById("eff-"+this.cid+"-"+eid);

	if (ch){
		ch.style.display='none';
		ch.innerHTML='';
	}
}


// From: http://www.webreference.com/programming/javascript/ncz/
/**
 * An autosuggest textbox control.
 * @class
 * @scope public
 */
function AutoSuggestControl(oTextbox /*:HTMLInputElement*/, 
                            oProvider /*:SuggestionProvider*/) {
    this.provider /*:SuggestionProvider*/ = oProvider;
    this.textbox /*:HTMLInputElement*/ = oTextbox;
    
    //initialize the control
    this.init();
}

/**
 * Autosuggests one or more suggestions for what the user has typed.
 * If no suggestions are passed in, then no autosuggest occurs.
 * @scope private
 * @param aSuggestions An array of suggestion strings.
 */
AutoSuggestControl.prototype.autosuggest = function (aSuggestions /*:Array*/) {
    //make sure there's at least one suggestion
    if (aSuggestions.length > 0) {
        this.typeAhead(aSuggestions[0]);
    }
};


/**
 * Handles keyup events.
 * @scope private
 * @param oEvent The event object for the keyup event.
 */
AutoSuggestControl.prototype.handleKeyUp = function (oEvent /*:Event*/) {
    var iKeyCode = oEvent.keyCode;

    //make sure not to interfere with non-character keys
    if (iKeyCode < 32 || (iKeyCode >= 33 && iKeyCode <= 46) || (iKeyCode >= 112 && iKeyCode <= 123)) {
        //ignore
    } else {
        //request suggestions from the suggestion provider
        this.provider.requestSuggestions(this);
    }
};

/**
 * Initializes the textbox with event handlers for
 * auto suggest functionality.
 * @scope private
 */
AutoSuggestControl.prototype.init = function () {
    //save a reference to this object
    var oThis = this;
    
    //assign the onkeyup event handler
    this.textbox.onkeyup = function (oEvent) {
    
        //check for the proper location of the event object
        if (!oEvent) {
            oEvent = window.event;
        }    
        
        //call the handleKeyUp() method with the event object
        oThis.handleKeyUp(oEvent);
    };
    
};

/**
 * Selects a range of text in the textbox.
 * @scope public
 * @param iStart The start index (base 0) of the selection.
 * @param iLength The number of characters to select.
 */
AutoSuggestControl.prototype.selectRange = function (iStart /*:int*/, iLength /*:int*/) {
    //use text ranges for Internet Explorer
    if (this.textbox.createTextRange) {
        var oRange = this.textbox.createTextRange(); 
        oRange.moveStart("character", iStart); 
        oRange.moveEnd("character", iLength - this.textbox.value.length);      
        oRange.select();
        
    //use setSelectionRange() for Mozilla
    } else if (this.textbox.setSelectionRange) {
        this.textbox.setSelectionRange(iStart, iLength);
    }     

    //set focus back to the textbox
    this.textbox.focus();      
}; 

/**
 * Inserts a suggestion into the textbox, highlighting the 
 * suggested part of the text.
 * @scope private
 * @param sSuggestion The suggestion for the textbox.
 */
AutoSuggestControl.prototype.typeAhead = function (sSuggestion /*:String*/) {
    //check for support of typeahead functionality
    if (this.textbox.createTextRange || this.textbox.setSelectionRange){
        var iLen = this.textbox.value.length; 
        this.textbox.value = sSuggestion; 
        this.selectRange(iLen, sSuggestion.length);
    }
};
