/
com/planet_ink/coffee_mud/Abilities/
com/planet_ink/coffee_mud/Abilities/Common/
com/planet_ink/coffee_mud/Abilities/Diseases/
com/planet_ink/coffee_mud/Abilities/Druid/
com/planet_ink/coffee_mud/Abilities/Fighter/
com/planet_ink/coffee_mud/Abilities/Prayers/
com/planet_ink/coffee_mud/Abilities/Properties/
com/planet_ink/coffee_mud/Abilities/Skills/
com/planet_ink/coffee_mud/Abilities/Songs/
com/planet_ink/coffee_mud/Abilities/Spells/
com/planet_ink/coffee_mud/Abilities/Thief/
com/planet_ink/coffee_mud/Abilities/Traps/
com/planet_ink/coffee_mud/Areas/interfaces/
com/planet_ink/coffee_mud/Behaviors/
com/planet_ink/coffee_mud/Behaviors/interfaces/
com/planet_ink/coffee_mud/CharClasses/interfaces/
com/planet_ink/coffee_mud/Commands/
com/planet_ink/coffee_mud/Commands/interfaces/
com/planet_ink/coffee_mud/Exits/interfaces/
com/planet_ink/coffee_mud/Items/Armor/
com/planet_ink/coffee_mud/Items/Basic/
com/planet_ink/coffee_mud/Items/MiscMagic/
com/planet_ink/coffee_mud/Items/Software/
com/planet_ink/coffee_mud/Items/Weapons/
com/planet_ink/coffee_mud/Libraries/
com/planet_ink/coffee_mud/Libraries/interfaces/
com/planet_ink/coffee_mud/Locales/
com/planet_ink/coffee_mud/Locales/interfaces/
com/planet_ink/coffee_mud/MOBS/
com/planet_ink/coffee_mud/Races/
com/planet_ink/coffee_mud/Races/interfaces/
com/planet_ink/coffee_mud/WebMacros/
com/planet_ink/coffee_mud/WebMacros/interfaces/
com/planet_ink/coffee_mud/core/smtp/
com/planet_ink/coffee_mud/core/threads/
com/planet_ink/siplet/applet/
lib/
resources/fakedb/
resources/quests/holidays/
web/
web/admin.templates/
web/admin/grinder/
web/admin/images/
web/pub.templates/
web/pub/images/mxp/
web/pub/sounds/
package com.planet_ink.coffee_mud.Commands;
import com.planet_ink.coffee_mud.core.interfaces.*;
import com.planet_ink.coffee_mud.core.*;
import com.planet_ink.coffee_mud.Abilities.interfaces.*;
import com.planet_ink.coffee_mud.Areas.interfaces.*;
import com.planet_ink.coffee_mud.Behaviors.interfaces.*;
import com.planet_ink.coffee_mud.CharClasses.interfaces.*;
import com.planet_ink.coffee_mud.Commands.interfaces.*;
import com.planet_ink.coffee_mud.Common.interfaces.*;
import com.planet_ink.coffee_mud.Exits.interfaces.*;
import com.planet_ink.coffee_mud.Items.interfaces.*;
import com.planet_ink.coffee_mud.Locales.interfaces.*;
import com.planet_ink.coffee_mud.MOBS.interfaces.*;
import com.planet_ink.coffee_mud.Races.interfaces.*;

import java.util.*;

/* 
   Copyright 2000-2010 Bo Zimmerman

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
@SuppressWarnings("unchecked")
public class Stat  extends Skills
{
	public Stat(){}

	private String[] access={"STAT"};
	public String[] getAccessWords(){return access;}

    public static final int ABLETYPE_EQUIPMENT=-2;
    public static final int ABLETYPE_INVENTORY=-3;
    public static final int ABLETYPE_QUESTWINS=-4;
    public static final int ABLETYPE_TATTOOS=-5;
    public static final int ABLETYPE_COMBAT=-6;
    public static final int ABLETYPE_SCRIPTS=-7;
    public static final int ABLETYPE_TITLES=-8;
    
	public MOB getTarget(MOB mob, String targetName, boolean quiet)
	{
		MOB target=null;
		if(targetName.length()>0)
		{
			target=mob.location().fetchInhabitant(targetName);
			if(target==null)
			{
				Environmental t=mob.location().fetchFromRoomFavorItems(null,targetName,Item.WORNREQ_UNWORNONLY);
				if((t!=null)&&(!(t instanceof MOB)))
				{
					if(!quiet)
						mob.tell(mob,t,null,"You can't do that to <T-NAMESELF>.");
					return null;
				}
			}
		}
		return target;
	}

	public boolean showTableStats(MOB mob, int days, int scale, String rest)
	{
		Calendar ENDQ=Calendar.getInstance();
		ENDQ.add(Calendar.DATE,-days);
		ENDQ.set(Calendar.HOUR_OF_DAY,23);
		ENDQ.set(Calendar.MINUTE,59);
		ENDQ.set(Calendar.SECOND,59);
		ENDQ.set(Calendar.MILLISECOND,999);
		CMLib.coffeeTables().update();
		Vector V=CMLib.database().DBReadStats(ENDQ.getTimeInMillis()-1);
		if(V.size()==0){ mob.tell("No Stats?!"); return false;}
		StringBuffer table=new StringBuffer("");
        boolean skillUse=false;
        boolean questStats=false;
        if(rest.toUpperCase().trim().startsWith("SKILLUSE"))
        {
            skillUse=true;
            int x=rest.indexOf(' ');
            if(x>0) rest=rest.substring(x+1).trim();
            else rest="";
        }
        if(rest.toUpperCase().trim().startsWith("QUEST"))
        {
        	questStats=true;
            int x=rest.indexOf(' ');
            if(x>0) rest=rest.substring(x+1).trim();
            else rest="";
        }
		table.append("^xStatistics since "+CMLib.time().date2String(ENDQ.getTimeInMillis())+":^.^N\n\r\n\r");
        if(skillUse)
            table.append(CMStrings.padRight("Skill",25)+CMStrings.padRight("Uses",10)+CMStrings.padRight("Skill",25)+CMStrings.padRight("Uses",10)+"\n\r");
        else
        if(questStats)
            table.append(CMStrings.padRight("Quest",30)
	   					+CMStrings.padRight("STRT",5)
    					+CMStrings.padRight("TSRT",5)
    					+CMStrings.padRight("FLST",5)
    					+CMStrings.padRight("ACPT",5)
    					+CMStrings.padRight("WINS",5)
    					+CMStrings.padRight("FAIL",5)
    					+CMStrings.padRight("DROP",5)
    					+CMStrings.padRight("TSTP",5)
    					+CMStrings.padRight("STOP",5)
            		    +"\n\r");
        else
    		table.append(CMStrings.padRight("Date",25)
    					 +CMStrings.padRight("CONs",5)
    					 +CMStrings.padRight("HIGH",5)
    					 +CMStrings.padRight("ONLN",5)
    					 +CMStrings.padRight("AVGM",5)
    					 +CMStrings.padRight("NEWB",5)
    					 +CMStrings.padRight("DTHs",5)
    					 +CMStrings.padRight("PKDs",5)
    					 +CMStrings.padRight("CLAS",5)
    					 +CMStrings.padRight("PURG",5)
    					 +CMStrings.padRight("MARR",5)+"\n\r");
		table.append(CMStrings.repeat("-",75)+"\n\r");
		Calendar C=Calendar.getInstance();
		C.set(Calendar.HOUR_OF_DAY,23);
		C.set(Calendar.MINUTE,59);
		C.set(Calendar.SECOND,59);
		C.set(Calendar.MILLISECOND,999);
		long curTime=C.getTimeInMillis();
		String code="*";
		if(rest.length()>0) code=""+rest.toUpperCase().charAt(0);
		long lastCur=System.currentTimeMillis();
        if(skillUse)
        {
            CharClass CharC=CMClass.getCharClass(rest);
            Vector allSkills=new Vector();
            for(Enumeration e=CMClass.abilities();e.hasMoreElements();)
                allSkills.addElement(e.nextElement());
            long[][] totals=new long[allSkills.size()][CoffeeTableRow.STAT_TOTAL];
            while((V.size()>0)&&(curTime>(ENDQ.getTimeInMillis())))
            {
                lastCur=curTime;
                Calendar C2=Calendar.getInstance();
                C.setTimeInMillis(curTime);
                C2.add(Calendar.DATE,-(scale));
                curTime=C2.getTimeInMillis();
                C2.set(Calendar.HOUR_OF_DAY,23);
                C2.set(Calendar.MINUTE,59);
                C2.set(Calendar.SECOND,59);
                C2.set(Calendar.MILLISECOND,999);
                curTime=C2.getTimeInMillis();
                Vector set=new Vector();
                for(int v=V.size()-1;v>=0;v--)
                {
                    CoffeeTableRow T=(CoffeeTableRow)V.elementAt(v);
                    if((T.startTime()>curTime)&&(T.endTime()<=lastCur))
                    {
                        set.addElement(T);
                        V.removeElementAt(v);
                    }
                }
                for(int s=0;s<set.size();s++)
                {
                    CoffeeTableRow T=(CoffeeTableRow)set.elementAt(s);
                    for(int x=0;x<allSkills.size();x++)
                        T.totalUp("A"+((Ability)allSkills.elementAt(x)).ID().toUpperCase(),totals[x]);
                }
                if(scale==0) break;
            }
            boolean cr=false;
            for(int x=0;x<allSkills.size();x++)
            {
                Ability A=(Ability)allSkills.elementAt(x);
                if((CharC==null)||(CMLib.ableMapper().getQualifyingLevel(CharC.ID(),true,A.ID())<0))
                    continue;
                if(totals[x][CoffeeTableRow.STAT_SKILLUSE]>0)
                {
                    table.append(CMStrings.padRight(""+A.ID(),25)
                            +CMStrings.centerPreserve(""+totals[x][CoffeeTableRow.STAT_SKILLUSE],10));
                    if(cr) table.append("\n\r");
                    cr=!cr;
                }
                x++;
                if(x<allSkills.size())
                {
                    A=(Ability)allSkills.elementAt(x);
                    if(totals[x][CoffeeTableRow.STAT_SKILLUSE]>0)
                    {
                        
                        table.append(CMStrings.padRight(""+A.ID(),25)
                                +CMStrings.centerPreserve(""+totals[x][CoffeeTableRow.STAT_SKILLUSE],10));
                        if(cr) table.append("\n\r");
                        cr=!cr;
                    }
                }
            }
            if(cr)table.append("\n\r");
        }
        else
        if(questStats)
        {
            long[][] totals=new long[CMLib.quests().numQuests()][CoffeeTableRow.STAT_TOTAL];
            while((V.size()>0)&&(curTime>(ENDQ.getTimeInMillis())))
            {
                lastCur=curTime;
                Calendar C2=Calendar.getInstance();
                C.setTimeInMillis(curTime);
                C2.add(Calendar.DATE,-(scale));
                curTime=C2.getTimeInMillis();
                C2.set(Calendar.HOUR_OF_DAY,23);
                C2.set(Calendar.MINUTE,59);
                C2.set(Calendar.SECOND,59);
                C2.set(Calendar.MILLISECOND,999);
                curTime=C2.getTimeInMillis();
                Vector set=new Vector();
                for(int v=V.size()-1;v>=0;v--)
                {
                    CoffeeTableRow T=(CoffeeTableRow)V.elementAt(v);
                    if((T.startTime()>curTime)&&(T.endTime()<=lastCur))
                    {
                        set.addElement(T);
                        V.removeElementAt(v);
                    }
                }
                if(set.size()==0){ set.addAll(V); V.clear();}
                for(int s=0;s<set.size();s++)
                {
                    CoffeeTableRow T=(CoffeeTableRow)set.elementAt(s);
                    for(int x=0;x<CMLib.quests().numQuests();x++)
                        T.totalUp("U"+T.tagFix(CMLib.quests().fetchQuest(x).name()),totals[x]);
                }
                if(scale==0) break;
            }
            for(int x=0;x<CMLib.quests().numQuests();x++)
            {
                Quest Q=CMLib.quests().fetchQuest(x);
                table.append(
            		     CMStrings.padRight(Q.name(),30)
                        +CMStrings.centerPreserve(""+totals[x][CoffeeTableRow.STAT_QUESTSTARTATTEMPT],5)
		                +CMStrings.centerPreserve(""+totals[x][CoffeeTableRow.STAT_QUESTTIMESTART],5)
		                +CMStrings.centerPreserve(""+totals[x][CoffeeTableRow.STAT_QUESTFAILEDSTART],5)
		                +CMStrings.centerPreserve(""+totals[x][CoffeeTableRow.STAT_QUESTACCEPTED],5)
		                +CMStrings.centerPreserve(""+totals[x][CoffeeTableRow.STAT_QUESTSUCCESS],5)
		                +CMStrings.centerPreserve(""+totals[x][CoffeeTableRow.STAT_QUESTFAILED],5)
		                +CMStrings.centerPreserve(""+totals[x][CoffeeTableRow.STAT_QUESTDROPPED],5)
		                +CMStrings.centerPreserve(""+totals[x][CoffeeTableRow.STAT_QUESTTIMESTOP],5)
		                +CMStrings.centerPreserve(""+totals[x][CoffeeTableRow.STAT_QUESTSTOP],5));
                table.append("\n\r");
            }
            table.append("\n\r");
        }
        else
		while((V.size()>0)&&(curTime>(ENDQ.getTimeInMillis())))
		{
			lastCur=curTime;
            Calendar C2=Calendar.getInstance();
            C2.setTimeInMillis(curTime);
			C2.add(Calendar.DATE,-(scale));
			curTime=C2.getTimeInMillis();
			C2.set(Calendar.HOUR_OF_DAY,23);
			C2.set(Calendar.MINUTE,59);
			C2.set(Calendar.SECOND,59);
			C2.set(Calendar.MILLISECOND,999);
			curTime=C2.getTimeInMillis();
			Vector set=new Vector();
			for(int v=V.size()-1;v>=0;v--)
			{
				CoffeeTableRow T=(CoffeeTableRow)V.elementAt(v);
				if((T.startTime()>curTime)&&(T.endTime()<=lastCur))
				{
					set.addElement(T);
					V.removeElementAt(v);
				}
			}
			long[] totals=new long[CoffeeTableRow.STAT_TOTAL];
			long highestOnline=0;
			long numberOnlineTotal=0;
			long numberOnlineCounter=0;
			for(int s=0;s<set.size();s++)
			{
				CoffeeTableRow T=(CoffeeTableRow)set.elementAt(s);
				T.totalUp(code,totals);
				if(T.highestOnline()>highestOnline) highestOnline=T.highestOnline();
				numberOnlineTotal+=T.numberOnlineTotal();
				numberOnlineCounter+=T.numberOnlineCounter();
			}
			totals[CoffeeTableRow.STAT_TICKSONLINE]=(totals[CoffeeTableRow.STAT_TICKSONLINE]*Tickable.TIME_TICK)/scale/(1000*60);
			double avgOnline=(numberOnlineCounter>0)?CMath.div(numberOnlineTotal,numberOnlineCounter):0.0;
			avgOnline=CMath.div(Math.round(avgOnline*10.0),10.0);
			table.append(CMStrings.padRight(CMLib.time().date2DateString(curTime+1)+" - "+CMLib.time().date2DateString(lastCur-1),25)
						 +CMStrings.centerPreserve(""+totals[CoffeeTableRow.STAT_LOGINS],5)
						 +CMStrings.centerPreserve(""+highestOnline,5)
						 +CMStrings.centerPreserve(""+avgOnline,5)
						 +CMStrings.centerPreserve(""+totals[CoffeeTableRow.STAT_TICKSONLINE],5)
						 +CMStrings.centerPreserve(""+totals[CoffeeTableRow.STAT_NEWPLAYERS],5)
						 +CMStrings.centerPreserve(""+totals[CoffeeTableRow.STAT_DEATHS],5)
						 +CMStrings.centerPreserve(""+totals[CoffeeTableRow.STAT_PKDEATHS],5)
						 +CMStrings.centerPreserve(""+totals[CoffeeTableRow.STAT_CLASSCHANGE],5)
						 +CMStrings.centerPreserve(""+totals[CoffeeTableRow.STAT_PURGES],5)
						 +CMStrings.centerPreserve(""+totals[CoffeeTableRow.STAT_MARRIAGES],5)+"\n\r");
            if(scale==0) break;
        }
		mob.tell(table.toString());
		return false;
	}

	public boolean execute(MOB mob, Vector commands, int metaFlags)
		throws java.io.IOException
	{
		commands.removeElementAt(0);
		if(commands.size()==0) commands.addElement("TODAY");
		String s1=(commands.size()>0)?((String)commands.elementAt(0)).toUpperCase():"";
		String s2=(commands.size()>1)?((String)commands.elementAt(1)).toUpperCase():"";
		if(s1.equalsIgnoreCase("TODAY"))
			return showTableStats(mob,1,1,CMParms.combine(commands,1));
		else
		if(commands.size()>1)
		{
			String rest=(commands.size()>2)?CMParms.combine(commands,2):"";
			if(s2.equals("DAY")&&(CMath.isNumber(s1)))
				return showTableStats(mob,(CMath.s_int(s1)),1,rest);
			else
			if(s2.equals("DAYS")&&(CMath.isNumber(s1)))
				return showTableStats(mob,(CMath.s_int(s1)),1,rest);
			else
			if(s2.equals("WEEK")&&(CMath.isNumber(s1)))
				return showTableStats(mob,(CMath.s_int(s1)*7),7,rest);
			else
			if(s2.equals("WEEKS")&&(CMath.isNumber(s1)))
				return showTableStats(mob,(CMath.s_int(s1)*7),7,rest);
			else
			if(s2.equals("MONTH")&&(CMath.isNumber(s1)))
				return showTableStats(mob,(CMath.s_int(s1)*30),30,rest);
			else
			if(s2.equals("MONTHS")&&(CMath.isNumber(s1)))
				return showTableStats(mob,(CMath.s_int(s1)*30),30,rest);
			else
			if(s2.equals("YEAR")&&(CMath.isNumber(s1)))
				return showTableStats(mob,(CMath.s_int(s1)*365),365,rest);
			else
			if(s2.equals("YEARS")&&(CMath.isNumber(s1)))
				return showTableStats(mob,(CMath.s_int(s1)*365),365,rest);
		}
		
		int ableTypes=-1;
		if(commands.size()>1)
		{
			String s=((String)commands.elementAt(0)).toUpperCase();
			if("TATTOOS".equals(s)||"TATTOO".equals(s)||"TATT".equals(s))
			{
				ableTypes=ABLETYPE_TATTOOS;
				commands.removeElementAt(0);
			}
			else
			if("QUESTWINS".equals(s)||"QUESTS".equals(s)||"QUEST".equals(s)||"QUESTWIN".equals(s))
			{
				ableTypes=-ABLETYPE_QUESTWINS;
				commands.removeElementAt(0);
			}
			else
			if("TITLES".equals(s)||"TITLE".equals(s))
			{
				ableTypes=-ABLETYPE_TITLES;
				commands.removeElementAt(0);
			}
			else
			if("EQUIPMENT".equals(s)||"EQ".equals(s)||"EQUIP".equals(s))
			{
				ableTypes=ABLETYPE_EQUIPMENT;
				commands.removeElementAt(0);
			}
			else
			if("COMBAT".equals(s))
			{
				ableTypes=ABLETYPE_COMBAT;
				commands.removeElementAt(0);
			}
            else
            if("SCRIPTS".equals(s))
            {
                ableTypes=ABLETYPE_SCRIPTS;
                commands.removeElementAt(0);
            }
			else
			if("INVENTORY".equals(s)||"INVEN".equals(s)||"INV".equals(s))
			{
				ableTypes=ABLETYPE_INVENTORY;
				commands.removeElementAt(0);
			}
			else
			for(int a=0;a<Ability.ACODE_DESCS.length;a++)
			{
				if((Ability.ACODE_DESCS[a]+"S").equals(s)||(Ability.ACODE_DESCS[a]).equals(s))
				{
					ableTypes=a;
					commands.removeElementAt(0);
					break;
				}
			}
		}
		String MOBname=CMParms.combine(commands,0);
		MOB target=getTarget(mob,MOBname,true);
		if((target==null)||(!target.isMonster()))
			target=mob.location().fetchInhabitant(MOBname);
		if((target==null)||(!target.isMonster()))
		{
		    try
		    {
		    	Vector inhabs=CMLib.map().findInhabitants(CMLib.map().rooms(), mob,MOBname,100);
				for(Enumeration m=inhabs.elements();m.hasMoreElements();)
				{
					MOB mob2=(MOB)m.nextElement();
					Room R=mob2.location();
					if(CMSecurity.isAllowed(mob,R,"STAT"))
					{
						target=mob2;
						break;
					}
				}
		    }catch(NoSuchElementException nse){}
		}
		if(target==null)
			target=CMLib.players().getLoadPlayer(MOBname);
		if(target==null)
		{
			mob.tell("You can't stat '"+MOBname+"'  -- he doesn't exist.");
			return false;
		}

		StringBuffer str=new StringBuffer("");
		if(ableTypes>=0)
		{
			Vector V=new Vector();
			int mask=Ability.ALL_ACODES;
			V.addElement(Integer.valueOf(ableTypes));
			str=getAbilities(target,V,mask,false,-1);
		}
		else
		if(ableTypes==ABLETYPE_EQUIPMENT)
			str=CMLib.commands().getEquipment(mob,target);
		else
		if(ableTypes==ABLETYPE_INVENTORY)
			str=CMLib.commands().getInventory(mob,target);
		else
		if(ableTypes==ABLETYPE_QUESTWINS)
		{
			str.append("Quests won:");
			StringBuffer won=new StringBuffer("");
			for(int q=0;q<CMLib.quests().numQuests();q++)
			{
				Quest Q=CMLib.quests().fetchQuest(q);
				if(Q.wasWinner(target.Name()))
					won.append(" "+Q.name()+",");
			}
			if(won.length()==0)
				won.append(" None!");
			won.deleteCharAt(won.length()-1);
			str.append(won);
			str.append("\n\r");
		}
		else
		if(ableTypes==ABLETYPE_TITLES)
		{
			str.append("Titles:");
			StringBuffer ttl=new StringBuffer("");
			if(target.playerStats()!=null)
				for(int t=0;t<target.playerStats().getTitles().size();t++)
				{
					String title = (String)target.playerStats().getTitles().elementAt(t);
					ttl.append(" "+title+",");
				}
			if(ttl.length()==0)
				ttl.append(" None!");
			ttl.deleteCharAt(ttl.length()-1);
			str.append(ttl);
			str.append("\n\r");
		}
        else
        if(ableTypes==ABLETYPE_SCRIPTS)
        {
            str.append("Scripts covered:\n\r");
            for(int q=0;q<target.numScripts();q++)
            {
                ScriptingEngine E=target.fetchScript(q);
                str.append("Script #"+q+"\n\r");
                str.append("Quest: "+E.defaultQuestName()+"\n\r");
                str.append("Savable: "+E.isSavable()+"\n\r");
                str.append("Scope: "+E.getVarScope()+"\n\r");
                str.append("Vars: "+E.getLocalVarXML()+"\n\r");
                str.append("Script: "+E.getScript()+"\n\r");
                str.append("\n\r");
            }
            str.append("\n\r");
        }
		else
		if(ableTypes==ABLETYPE_TATTOOS)
		{
			str.append("Tattoos:");
			for(int q=0;q<target.numTattoos();q++)
				str.append(" "+target.fetchTattoo(q)+",");
			str.deleteCharAt(str.length()-1);
			str.append("\n\r");
		}
		else
		if(ableTypes==ABLETYPE_COMBAT)
		{
			str.append("Combat summary:\n\r\n\r");
			MOB M=CMClass.getMOB("StdMOB");
			M.setBaseCharStats((CharStats)target.baseCharStats().copyOf());
			M.setBaseEnvStats((EnvStats)target.baseEnvStats().copyOf());
			M.setBaseState((CharState)target.baseState().copyOf());
			recoverMOB(target);
			recoverMOB(M);
			int base=CMLib.combat().adjustedAttackBonus(M,null);
			str.append("^c"+CMStrings.padRight("Base Attack",40)+": ^W"+base+"\n\r");
			for(int i=0;i<target.inventorySize();i++)
			{
				Item I=target.fetchInventory(i);
				if((I!=null)&&(!I.amWearingAt(Item.IN_INVENTORY))){ recoverMOB(M); testMOB(target,M,I); int diff=CMLib.combat().adjustedAttackBonus(M,null)-base; reportOnDiffMOB(I,diff,str);}
			}
			recoverMOB(M);
			for(int i=0;i<target.numAllEffects();i++)
			{
				Ability A=target.fetchEffect(i);
				if(A!=null){ recoverMOB(M); testMOB(target,M,A); int diff=CMLib.combat().adjustedAttackBonus(M,null)-base; reportOnDiffMOB(A,diff,str);}
			}
			recoverMOB(target);
			recoverMOB(M);
			str.append("^W-------------------------\n\r");
			str.append("^C"+CMStrings.padRight("Total",40)+": ^W"+CMLib.combat().adjustedAttackBonus(target,null)+"\n\r");
			str.append("\n\r");
			base=CMLib.combat().adjustedArmor(M);
			str.append("^C"+CMStrings.padRight("Base Armor",40)+": ^W"+base+"\n\r");
			for(int i=0;i<target.inventorySize();i++)
			{
				Item I=target.fetchInventory(i);
				if(I!=null){ recoverMOB(M); testMOB(target,M,I); int diff=CMLib.combat().adjustedArmor(M)-base; reportOnDiffMOB(I,diff,str);}
			}
			recoverMOB(M);
			for(int i=0;i<target.numAllEffects();i++)
			{
				Ability A=target.fetchEffect(i);
				if(A!=null){ recoverMOB(M); testMOB(target,M,A); int diff=CMLib.combat().adjustedArmor(M)-base; reportOnDiffMOB(A,diff,str);}
			}
			recoverMOB(target);
			recoverMOB(M);
			str.append("^W-------------------------\n\r");
			str.append("^C"+CMStrings.padRight("Total",40)+": ^W"+CMLib.combat().adjustedArmor(target)+"\n\r");
			str.append("\n\r");
			base=CMLib.combat().adjustedDamage(M,null,null);
			str.append("^C"+CMStrings.padRight("Base Damage",40)+": ^W"+base+"\n\r");
			for(int i=0;i<target.inventorySize();i++)
			{
				Item I=target.fetchInventory(i);
				if(I!=null){ recoverMOB(M); testMOB(target,M,I); int diff=CMLib.combat().adjustedDamage(M,null,null)-base; reportOnDiffMOB(I,diff,str);}
			}
			recoverMOB(M);
			for(int i=0;i<target.numAllEffects();i++)
			{
				Ability A=target.fetchEffect(i);
				if(A!=null){ recoverMOB(M); testMOB(target,M,A); int diff=CMLib.combat().adjustedDamage(M,null,null)-base; reportOnDiffMOB(A,diff,str);}
			}
			recoverMOB(target);
			recoverMOB(M);
			str.append("^W-------------------------\n\r");
			str.append("^C"+CMStrings.padRight("Total",40)+": ^W"+CMLib.combat().adjustedDamage(target,null,null)+"\n\r");
			str.append("\n\r");
			base=(int)Math.round(M.envStats().speed()*100);
			str.append("^C"+CMStrings.padRight("Base Attacks%",40)+": ^W"+base+"\n\r");
			for(int i=0;i<target.inventorySize();i++)
			{
				Item I=target.fetchInventory(i);
				if(I!=null){ recoverMOB(M); testMOB(target,M,I); int diff=(int)Math.round(M.envStats().speed()*100)-base; reportOnDiffMOB(I,diff,str);}
			}
			recoverMOB(M);
			for(int i=0;i<target.numAllEffects();i++)
			{
				Ability A=target.fetchEffect(i);
				if(A!=null){ recoverMOB(M); testMOB(target,M,A); int diff=(int)Math.round(M.envStats().speed()*100)-base; reportOnDiffMOB(A,diff,str);}
			}
			recoverMOB(target);
			recoverMOB(M);
			str.append("^W-------------------------\n\r");
			str.append("^C"+CMStrings.padRight("Total",40)+": ^W"+(int)Math.round(target.envStats().speed()*100)+"\n\r");
			str.append("\n\r");
			base=M.maxState().getHitPoints();
			str.append("^C"+CMStrings.padRight("Base Hit Points",40)+": ^W"+base+"\n\r");
			for(int i=0;i<target.inventorySize();i++)
			{
				Item I=target.fetchInventory(i);
				if(I!=null){ recoverMOB(M); testMOB(target,M,I); int diff=M.maxState().getHitPoints()-base; reportOnDiffMOB(I,diff,str);}
			}
			recoverMOB(M);
			for(int i=0;i<target.numAllEffects();i++)
			{
				Ability A=target.fetchEffect(i);
				if(A!=null){ recoverMOB(M); testMOB(target,M,A); int diff=M.maxState().getHitPoints()-base; reportOnDiffMOB(A,diff,str);}
			}
			recoverMOB(M);
			str.append("^W-------------------------\n\r");
			str.append("^C"+CMStrings.padRight("Total",40)+": ^W"+target.maxState().getHitPoints()+"\n\r");
			recoverMOB(target);
		}
		else
			str=CMLib.commands().getScore(target);
		if(!mob.isMonster())
			mob.session().wraplessPrintln(str.toString());
		return false;
	}

	public void recoverMOB(MOB M)
	{
		M.recoverCharStats();
		M.recoverEnvStats();
		M.recoverMaxState();
		M.resetToMaxState();
	}
	public void testMOB(MOB target,MOB M, Environmental test)
	{
		test.affectCharStats(target,M.charStats());
		test.affectEnvStats(target,M.envStats());
		test.affectCharState(target,M.maxState());
	}
	public void reportOnDiffMOB(Environmental test, int diff, StringBuffer str)
	{
		if(diff>0)
			str.append("^C"+CMStrings.padRight(test.Name(),40)+": ^W+"+diff+"\n\r");
		else
		if(diff<0)
			str.append("^C"+CMStrings.padRight(test.Name(),40)+": ^W"+diff+"\n\r");
	}
	
	public boolean canBeOrdered(){return true;}
	public boolean securityCheck(MOB mob){return CMSecurity.isAllowed(mob,mob.location(),"STAT");}

	
}