/* ** j###t ########## #### #### ** j###t ########## #### #### ** j###T "###L J###" ** ######P' ########## ######### ** ######k, ########## T######T ** ####~###L #### ** #### q###L ########## .##### ** #### \###L ########## #####" */ package key; import key.collections.*; import key.util.MultiEnumeration; import java.util.Enumeration; import java.io.*; import java.util.StringTokenizer; public class Room extends Landscape { private static final long serialVersionUID = 2178840055236700139L; public static final int MAX_DESCRIPTION_LINES = Player.MAX_DESCRIPTION_LINES; public static final int MAX_DESCRIPTION_BYTES = Player.MAX_DESCRIPTION_BYTES; public static final AtomicElement[] ELEMENTS = { AtomicElement.construct( Room.class, String.class, "called", AtomicElement.PUBLIC_FIELD, "the title of this room" ), AtomicElement.construct( Room.class, TextParagraph.class, "description", "description", AtomicElement.PUBLIC_FIELD, "a description of this room", // these constants should be put elsewhere AtomicSpecial.TextParagraphLengthLimit( MAX_DESCRIPTION_BYTES, MAX_DESCRIPTION_LINES ) ), AtomicElement.construct( Room.class, String.class, "portrait", AtomicElement.PUBLIC_FIELD, "a short description of this room" ), AtomicElement.construct( Room.class, String.class, "relation", AtomicElement.PUBLIC_FIELD, "the type of room, such as 'in', 'on' or 'at'" ), AtomicElement.construct( Room.class, String.class, "fullPortrait", AtomicElement.PUBLIC_ACCESSORS | AtomicElement.READ_ONLY, "relation followed by portrait" ) }; public static final AtomicStructure STRUCTURE = new AtomicStructure( Landscape.STRUCTURE, ELEMENTS ); /** * what the room is called and the player * sees as a short description */ public String called; public TextParagraph description; public String portrait; public String relation; public static final int MAX_IN_ROOM = 20; public Room() { description = new TextParagraph( "" ); portrait = "somewhere"; called = ""; relation = "in"; setLimit( MAX_IN_ROOM ); // generally, its okay to go into a room permissionList.allow( enterAction ); // these would be permission problems if // we had user-coding: some system needs // to be set up here. permissionList.allow( addToAction ); permissionList.allow( removeFromAction ); setConstraint( Type.THING ); contained = new ObjectCollection(); } public Room( Object key ) { this(); setKey( key ); } public AtomicStructure getDeclaredStructure() { return( STRUCTURE ); } public void clearTransient() { Room backup = (Room) new Search( "landscape/void", Key.instance() ).result; if( backup == null || backup == this ) { Log.debug( this, "No voidroom in Room::clearTransient" ); throw new UnexpectedResult( "Cannot clear rooms when there is no void room." ); } String msg = getLoginMessage(); for( Enumeration e = players(); e.hasMoreElements(); ) { try { Player p = (Player) e.nextElement(); if( p.connected() ) { Room r = (Room) p.getProperty( "lastPublicRoomLocation" ); if( r == null || r == this ) r = backup; p.sendSystem( "\n\nThe room around you vanishes!\n\n" ); p.putCode( 'o', p.getName() ); p.moveTo( r, null, new key.effect.Enter( p, r, Grammar.substitute( msg, p.getCodes() ) ) ); } } catch( PlayerNotConnectedException ex ) { } } super.clearTransient(); } public void setCalled( String nc ) { permissionList.check( modifyAction ); called = nc; } /** A players aspect is its description when looked at */ public Paragraph aspect( Player l ) { MultiParagraph.Generator p = new MultiParagraph.Generator(); if( called != null && called.length() > 0 ) p.append( new TextParagraph( TextParagraph.CENTERALIGNED, called ) ); p.append( description ); p.append( BlankLineParagraph.BLANKLINE ); p.append( who( l ) ); p.append( exits() ); return( p.getParagraph() ); } // returns, for eg: "the courtyard", or // "a place belonging to subtle", or // "a small hill". public String portrait() { return( portrait ); } public String relation() { return( relation ); } // returns, for eg: "in the courtyard", where // 'in' is the prop, and 'the courtyard' is the portrait. // META: used to be called 'fullPortrait' public String getFullPortrait() { return( relation + " " + portrait ); } public Paragraph getDescription() { return( description ); } public String getLoginMessage() { return( (String) Key.instance().getConfig().getProperty( "loginMessage" ) ); } public String getLogoutMessage() { return( (String) Key.instance().getConfig().getProperty( "logoutMessage" ) ); } public String getCalled() { return( called ); } public String countPlayers( int np, boolean here ) { if( np == 0 ) return( "There is no-one in " + getId() ); else if( np == 1 && here ) return( "There is nobody here but you" ); else { StringBuffer w = new StringBuffer(); w.append( "There " ); if( here ) np--; w.append( Grammar.isAreCount( np ) ); if( here ) w.append( " other " ); else w.append( " " ); w.append( Grammar.personPeople( np ) ); w.append( " here" ); return( w.toString() ); } } public Paragraph who( Player l ) { boolean here=isCurrentHere(); int np = numberPlayers(); String cString = countPlayers( np, here ); if( np == 0 || (np == 1 && here) ) return( new TextParagraph( cString + "." ) ); else { // see how tolerate the user is to the titles they see if( np < l.titleTolerance ) // remember the orginator is included in the count { StringBuffer w = new StringBuffer( cString ); w.append( ":^@\n" ); for( Enumeration e = players(); e.hasMoreElements(); ) { Player p = (Player) e.nextElement(); if( l != p ) w.append( p.getTitledName() + "^$\n" ); } return( new TextParagraph( w.toString() ) ); } else { int i = 0; // allplayers is the total count of people in the scape String[] allplayers = new String[ np ]; // generate a string array of all the players for( Enumeration e = players(); e.hasMoreElements(); ) { Player p = (Player) e.nextElement(); if( l != p ) // don't include the observer in the list allplayers[i++] = p.getName(); } // META very inefficient: replace with bounded comma seperate // in grammar. // other players is all players - 1 String[] otherplayers = new String[ i ]; // copy from all players to other players (don't include the observer for( int j = 0; j < i; j++ ) otherplayers[j] = allplayers[j]; return( new TextParagraph( cString + ": " + Grammar.commaSeperate( otherplayers ) + ".\n" ) ); } } } public String withPlayers( int np, boolean here, Player o, Player targetPlayer ) { if( np == 0 ) return( "That's strange..." ); else if( np == 1 && !here ) return( targetPlayer.getProperty( "Prefix") + " " + targetPlayer.getProperty( "Name" ) + " is alone" ); else if( np == 1 && here ) return( "It's just you here." ); else if( np == 2 && here ) return( "Well, its just you and " + targetPlayer.prefix + " " + targetPlayer.getName() ); else { StringBuffer w = new StringBuffer(); w.append( "There " ); // take one off so the target player is not counted in the total... np--; w.append( Grammar.isAreCount( np ) ); if( here ) w.append( " other " ); else w.append( " " ); w.append( Grammar.personPeople( np ) ); w.append( " with " ); w.append( targetPlayer.prefix + " " + targetPlayer.getName() ); return( w.toString() ); } } private boolean isCurrentHere() { // start out by determining if observer is // a player, and then if the player is *in* // the room Player l = Player.getCurrent(); if( l != null && l.location == this ) return( true ); return( false ); } public String with( Player targetPlayer ) { Player l=null; boolean here=isCurrentHere(); int np = numberPlayers(); String cString = withPlayers( np, here, l, targetPlayer ); if( np == 0 || (np == 1 && !here) || (np == 1 && here) || (np == 2 && here) ) return( cString + "." ); else { StringBuffer w = new StringBuffer( cString ); w.append( ":\n" ); for( Enumeration e = players(); e.hasMoreElements(); ) { Player p = (Player) e.nextElement(); if( targetPlayer != p ) { if( p.hidden ) w.append( "Someone [hiding]" + "\n" ); else w.append( p.prefix + " " + p.getName() + "\n" ); } } return( w.toString() ); } } /** eventually make this a property that can change */ public Realm getRealm() { return( Key.instance().getDefaultRealm() ); } public Paragraph exits() { String[] exits = new String[ this.count() ]; String[] other = new String[ this.count() ]; int i = 0; int k = 0; // the first iteration is basically to count the number of exits // and create an array of exits only. for( Enumeration e = elements(); e.hasMoreElements(); ) { Object o = e.nextElement(); if( o instanceof Exit ) exits[i++] = ((Exit)o).getName(); else other[k++] = ((Atom)o).getName(); } // i is the number of objects that are actually exits if( i >= 1 || k >= 1 ) { MultiParagraph.Generator mp = new MultiParagraph.Generator(); if( i >= 1 ) { /* String[] actual = new String[ i ]; for( int j = 0; j < i; j++ ) actual[j] = exits[j]; */ mp.append( new TextParagraph( "Exits: " + Grammar.enumerate( exits, i ) + "." ) ); } if( k >= 1 ) { /* String[] actual = new String[ k ]; for( int j = 0; j < k; j++ ) actual[j] = other[j]; */ mp.append( new TextParagraph( "Objects: " + Grammar.enumerate( other, k ) + "." ) ); } return( mp.getParagraph() ); } else return( null ); } public void ejectPlayer( Player p, Effect enter, Effect leave ) { permissionList.check( ejectFromAction ); p.ejected( this, enter, leave ); } /** * Only stops a direct trans - not using an exit */ public boolean canMoveInto( Player p ) { return( permissionList.check( p.getThis(), enterAction ) ); } //--- actions ---// protected static StringKeyCollection staticActions; public static Action ejectFromAction; public static Action enterAction; public static Action setHomeAction; static { staticActions = new StringKeyCollection(); ejectFromAction = newAction( Room.class, staticActions, "ejectFrom", false, false ); enterAction = newAction( Room.class, staticActions, "enter", false, false ); setHomeAction = newAction( Room.class, staticActions, "setHome", false, false ); } public Enumeration getActions() { return( new MultiEnumeration( staticActions.elements(), super.getActions() ) ); } public boolean containsAction( Action a ) { return( staticActions.contains( a ) || super.containsAction( a ) ); } /** * Returns the action corresponding to the * supplied name. This routine will need to * be overriden by sub-classes using actions. */ public Action getAction( String name ) { Action a = (Action) staticActions.get( name ); if( a == null ) return( super.getAction( name ) ); else return( a ); } }