/*
** j###t ########## #### ####
** j###t ########## #### ####
** j###T "###L J###"
** ######P' ########## #########
** ######k, ########## T######T
** ####~###L ####
** #### q###L ########## .#####
** #### \###L ########## #####"
**
** $Id$
**
** Class History
**
** Date Name Description
** ---------|------------|-----------------------------------------------
** 29Oct98 subtle created
**
*/
package key.commands;
import key.*;
import java.io.IOException;
import java.util.StringTokenizer;
import java.util.Enumeration;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
public class Verb extends Command
{
private static final long serialVersionUID = 7601571514137070656L;
public static final AtomicElement[] ELEMENTS =
{
AtomicElement.construct( Verb.class, Boolean.TYPE, "checkInventory",
AtomicElement.PUBLIC_FIELD,
"true iff the players inventory should be checked for the object" ),
AtomicElement.construct( Verb.class, Boolean.TYPE, "checkRoom",
AtomicElement.PUBLIC_FIELD,
"true iff the players current room should be checked for the object" ),
AtomicElement.construct( Verb.class, String.class, "verb",
AtomicElement.PUBLIC_ACCESSORS,
"the name of the method to call on the matched object" )
};
public static final AtomicStructure STRUCTURE = new AtomicStructure( Command.STRUCTURE, ELEMENTS );
public boolean checkInventory;
public boolean checkRoom;
protected String verb = Material.getDefaultVerb();
protected transient Method method;
public AtomicStructure getDeclaredStructure()
{
return( STRUCTURE );
}
public Verb()
{
setKey( "use" );
usage = "<object> [<option args>]";
method = Material.getMethod( verb );
}
/**
* @return true iff this was a keyword and we've done everything we need to
*/
protected boolean handleKeyword( Player p, StringTokenizer args, String fullLine, CategoryCommand caller, InteractiveConnection ic, Flags flags, String keyword ) throws IOException
{
if( keyword.equalsIgnoreCase( "all" ) )
{
Room r = p.getLocation();
Inventory i = p.getInventory();
int count = 0;
if( checkInventory )
{
for( Enumeration e = i.elements(); e.hasMoreElements(); )
{
Thing t = (Thing) e.nextElement();
doIt( p, args, fullLine, ic, flags, i, r, t );
count++;
}
}
if( checkRoom )
{
for( Enumeration e = r.elements(); e.hasMoreElements(); )
{
Thing t = (Thing) e.nextElement();
doIt( p, args, fullLine, ic, flags, i, r, t );
count++;
}
}
if( count == 0 )
{
if( checkRoom && checkInventory )
ic.sendFailure( "There aren't any objects in your inventory or this room." );
else if( checkRoom )
ic.sendFailure( "There aren't any objects in this room." );
else if( checkInventory )
ic.sendFailure( "There aren't any objects in your inventory." );
else
ic.sendFailure( "This command will never match any object, it is improperly set up." );
}
return true;
}
else
return( false );
}
protected void handleNoArgs( Player p, StringTokenizer args, String fullLine, CategoryCommand caller, InteractiveConnection ic, Flags flags ) throws IOException
{
usage( ic );
}
// We can't run with scissors, but we can run with items.
protected final void runWithItem( Player p, StringTokenizer args, String fullLine, CategoryCommand caller, InteractiveConnection ic, Flags flags, String nt ) throws IOException
{
if( !handleKeyword( p, args, fullLine, caller, ic, flags, nt ) )
{
Room r = p.getLocation();
Inventory i = p.getInventory();
Thing t = null;
if( checkInventory )
t = getObjectIn( p, i, ic, nt, null );
// if it wasn't in the inventory, get it from the room
// (ideally, a joint object collection would be best,
// but it probably isn't worth it. another way would
// be to just get the strength of the match from
// both, but it's added complexity that may not be necessary)
if( t == null && checkRoom )
t = getObjectIn( p, r, ic, nt, null );
if( t != null )
doIt( p, args, fullLine, ic, flags, i, r, t );
else if( checkRoom && checkInventory )
ic.sendFailure( "This object is not in your inventory or this room." );
else if( checkRoom )
ic.sendFailure( "This object is not in this room." );
else if( checkInventory )
ic.sendFailure( "This object is not in your inventory." );
else
ic.sendFailure( "This command will never match an object, it is improperly set up." );
}
}
public void run( Player p, StringTokenizer args, String fullLine, CategoryCommand caller, InteractiveConnection ic, Flags flags ) throws IOException
{
if( !args.hasMoreTokens() )
{
handleNoArgs( p, args, fullLine, caller, ic, flags );
return;
}
String nt = args.nextToken();
runWithItem( p, args, fullLine, caller, ic, flags, nt );
}
protected void doIt( Player p, StringTokenizer args, String fullLine, InteractiveConnection ic, Flags flags, Inventory i, Room r, Thing t )
{
if( verb != null && verb.length() != 0 )
{
if( method == null )
method = Material.getMethod( verb );
if( method != null )
{
Object[] params = new Object[ Material.verbParameters.length ];
params[0] = p;
params[1] = args;
params[2] = ic;
params[3] = flags;
params[4] = (Atom) t;
try
{
method.invoke( t, params );
}
catch( InvocationTargetException e )
{
Throwable x = e.getTargetException();
Log.error( "while invoking verb " + method.toString(), x );
if( p.isExpert() )
{
ic.sendFailure( x.toString() + "\nduring ^h" + method.toString() + "^-" );
ic.printStackTrace( x );
}
else
ic.sendFailure( "You may not do this." );
}
catch( Exception e )
{
Log.error( "while invoking verb " + method.toString(), e );
if( p.isExpert() )
{
ic.sendFailure( e.toString() + "\nduring ^h" + method.toString() + "^-" );
ic.printStackTrace( e );
}
else
ic.sendFailure( "You may not do this." );
}
}
else
ic.sendFailure( "Could not find method '" + verb + "'." );
}
else
ic.sendFailure( "This command is incorrectly set up" );
}
public String getVerb()
{
return( verb );
}
public void setVerb( String v )
{
Method m = Material.getMethod( v );
if( m != null )
{
verb = v;
method = m;
}
else
throw new InvalidSearchException( "Unknown verb '" + v + "'. Try one of: " + Material.getAvailableVerbs() );
}
}