public StringBuilder listQuests(Session viewerS)
	{
		final StringBuilder buf=new StringBuilder("");
		if(CMLib.quests().numQuests()==0)
			buf.append(L("No quests loaded."));
		else
		{
			buf.append("\n\r^xQuest Report:^.^N\n\r");
			final int COL_LEN1=CMLib.lister().fixColWidth(5.0,viewerS);
			final int COL_LEN2=CMLib.lister().fixColWidth(30.0,viewerS);
			buf.append("\n\r^x"+CMStrings.padRight("#",COL_LEN1)+CMStrings.padRight(L("Name"),COL_LEN2)+" Status^.^N\n\r");
			for(int i=0;i<CMLib.quests().numQuests();i++)
			{
				final Quest Q=CMLib.quests().fetchQuest(i);
				if(Q!=null)
				{
					buf.append(CMStrings.padRight(""+(i+1),COL_LEN1)+CMStrings.padRight("^<LSTQUEST^>"+Q.name()+"^</LSTQUEST^>",COL_LEN2)+" ");
					if(Q.running())
					{
						String minsLeft="("+Q.minsRemaining()+" mins left)";
						if(Q.duration()==0)
							minsLeft="(Eternal)";
						if(Q.isCopy())
							buf.append(L("copy running @x1",minsLeft));
						else
							buf.append("running "+minsLeft);
					}
					else
					if(Q.suspended())
						buf.append("disabled");
					else
					if(Q.waiting())
					{
						long min=Q.waitRemaining();
						if(min>0)
						{
							min=min*CMProps.getTickMillis();
							if(min>60000)
								buf.append(L("waiting (@x1 minutes left)",""+(min/60000)));
							else
								buf.append(L("waiting (@x1 seconds left)",""+(min/1000)));
						}
						else
							buf.append(L("waiting (@x1 minutes left)",""+min));
					}
					else
						buf.append("loaded");
					buf.append("^N\n\r");
				}
			}
		}
		return buf;
	}