/*
** j###t ########## #### ####
** j###t ########## #### ####
** j###T "###L J###"
** ######P' ########## #########
** ######k, ########## T######T
** ####~###L ####
** #### q###L ########## .#####
** #### \###L ########## #####"
**
** $Id$
**
** Class History
**
** Date Name Description
** ---------|------------|-----------------------------------------------
** 19Aug98 subtle start of recorded history
**
*/
package key;
import key.collections.*;
import java.util.Enumeration;
import java.io.*;
import java.util.StringTokenizer;
/**
* Scape is a general way of saying 'players exist here for
* and communication can be sent to them all in a uniform
* way. The basis for all channels & rooms.
*
* Shouldn't be necessary to store players in the linkedTrie
* as Tags, as players can't be swapped out while they're online.
*
* *right*?
*/
public class Scape extends Container implements CommandContainer, PlayerGroup
{
private static final long serialVersionUID = -2480334989348845021L;
public static final AtomicElement[] ELEMENTS =
{
AtomicElement.construct( Scape.class, Integer.TYPE,
"numberPlayers",
AtomicElement.PUBLIC_ACCESSORS | AtomicElement.READ_ONLY,
"the number of online players in this scape" ),
AtomicElement.construct( Scape.class, String.class,
"allNames",
AtomicElement.PUBLIC_ACCESSORS | AtomicElement.READ_ONLY |
AtomicElement.GENERATED,
"all the names of the players in this scape" ),
AtomicElement.construct( Scape.class, CommandList.class,
"commands",
AtomicElement.PUBLIC_FIELD | AtomicElement.ATOMIC,
"the scapes custom command list" )
};
public static final AtomicStructure STRUCTURE = new AtomicStructure( Container.STRUCTURE, ELEMENTS );
transient PlayerGroup playergroup;
/**
* Commands that are specific for this particular
* atom. Examples might be custom commands in
* rooms, such as 'look' (if its overridden to
* give different messages each time you type
* it)
*/
public Reference commands = Reference.EMPTY;
public Scape()
{
this( false );
}
/**
* For the rare case of a reference scape -
* key baseclass only, atm
*/
Scape( boolean reference )
{
super( reference );
init();
}
private void init()
{
totalScapes++;
playergroup = new LWPlayerGroup();
setupPlayersCollection();
}
public void setupPlayersCollection()
{
playergroup.setCollection( new StringKeyCollection() );
}
public void setCollection( Collection c )
{
playergroup.setCollection( c );
}
public AtomicStructure getDeclaredStructure()
{
return( STRUCTURE );
}
public void loaded()
{
super.loaded();
init();
}
/**
* Add this player to the list of players
*
* @param p the player to add to the list
* @exception NonUniqueKeyException if there is already a player in with this name
* @exception BadKeyException if this players name is malformed somehow
*/
public void linkPlayer( Player p ) throws NonUniqueKeyException,BadKeyException
{
playergroup.linkPlayer( p );
p.linkToScape( this );
}
/**
* Take this player out of the list of players
*
* @param p the player to remove from the list
* @exception NoSuchElementException if the player is not in the list
* @exception BadKeyException if the players name is malformed somehow
*/
public void unlinkPlayer( Player p ) throws NonUniqueKeyException,java.util.NoSuchElementException,BadKeyException
{
playergroup.unlinkPlayer( p );
p.unlinkFromScape( this );
}
/**
* Returns the player matched, or, possibly, an instance of
* a Trie object that contains all the matching players.
* <p>
* A null is returned if no matches were found at all. The
* match string is searched until the end of the string or
* a non-alphabetical character is found.
* <p>
* If you specify a comma seperated list of players, a scape
* containing the players will be returned. Such a scape can
* also contain errors when individual multiple matches are
* caught
*
* @param match the start or whole string to match from
* @return A player object, referring to the sole match, or a Trie
*/
public final Object getPlayer( Player p, String match )
{
return( playergroup.getPlayer( p, match ) );
}
public final Object getPlayer( String match )
{
return( playergroup.getPlayer( match ) );
}
public final Enumeration players()
{
return( playergroup.players() );
}
public boolean containsPlayer( Player p )
{
return( playergroup.containsPlayer( p ) );
}
public void clearTransient()
{
for( Enumeration e = players(); e.hasMoreElements(); )
{
Player p = (Player) e.nextElement();
try
{
p.sendSystem( "You discern that " + getName() + " no longer exists." );
}
catch( PlayerNotConnectedException ex )
{
}
try
{
unlinkPlayer( p );
}
catch( NonUniqueKeyException t )
{
throw new UnexpectedResult( t.toString() );
}
catch( BadKeyException t )
{
throw new UnexpectedResult( t.toString() );
}
}
contained.deallocate();
super.clearTransient();
}
public final String allNames()
{
return( playergroup.allNames() );
}
/**
* All the names, except substitute 'you' for player p
*/
public final String allNames( Player p )
{
return( playergroup.allNames( p ) );
}
public final int numberPlayers()
{
return( playergroup.numberPlayers() );
}
public final int getNumberPlayers()
{
return( playergroup.getNumberPlayers() );
}
public String getAllNames() { return( playergroup.allNames() ); }
/**
* A general way of saying that the people in
* this scape should be notified of the
* supplied Effect.
*/
public void splash( Effect t, SuppressionList s )
{
super.splash( t, s );
Atom oldsplasher = t.getSplasher();
t.setSplasher( this );
playergroup.splash( t, s );
t.setSplasher( oldsplasher );
}
/**
* Sends the splash to everyone except the listed
* atom
*/
public void splashExcept( Effect t, Splashable except, SuppressionList sl )
{
super.splash( t, sl );
Atom oldsplasher = t.getSplasher();
t.setSplasher( this );
playergroup.splashExcept( t, except, sl );
t.setSplasher( oldsplasher );
}
/**
* Sends the splash to everyone except the listed
* atoms
*/
public void splashExcept( Effect t, Splashable[] except, SuppressionList sl )
{
super.splash( t, sl );
Atom oldsplasher = t.getSplasher();
t.setSplasher( this );
playergroup.splashExcept( t, except, sl );
t.setSplasher( oldsplasher );
}
/**
* A shortcut, since matching it from the
* string could be prohibitively slow
*/
public final CommandList getCommandList()
{
try
{
return( (CommandList) commands.get() );
}
catch( OutOfDateReferenceException e )
{
Log.debug( this, e.toString() + " in scape " + getName() + ":getCommandList()" );
commands = Reference.EMPTY;
return( null );
}
catch( ClassCastException e )
{
Log.error( getId() + ".commands", e );
commands = Reference.EMPTY;
return( null );
}
}
private static int totalScapes;
public static int getTotalScapes()
{
return( totalScapes );
}
protected void finalize() throws Throwable
{
super.finalize();
totalScapes--;
}
boolean canSwap()
{
return( numberPlayers() == 0 );
}
}