/*
* (c) 2000-2009 Carlos G�mez Rodr�guez, todos los derechos reservados / all rights reserved.
* Licencia en license/bsd.txt / License in license/bsd.txt
*/
package eu.irreality.age;
//package AetheriaAWT;
import java.util.*;
import java.io.*;
import eu.irreality.age.debug.Debug;
import eu.irreality.age.debug.ExceptionPrinter;
import eu.irreality.age.messages.Messages;
import eu.irreality.age.scripting.ScriptException;
import eu.irreality.age.util.VersionComparator;
public class Room extends Entity implements Descriptible , SupportingCode, UniqueNamed
{
//al final claudicamos
private World mundo;
//////////////////////
//INSTANCE VARIABLES//
//////////////////////
/**ID de la habitaci�n que se usa para referirse a ella.*/
/*01*/ private int idnumber;
/**ID de la habitaci�n de que se hereda.*/
/*02*/ private int inheritsFrom;
/*03*/ // inherited protected int state;
// inherited protected long timeunitsleft;
/**Nombre sint�tico de la habitaci�n.*/
/*04*/ protected String title;
/**Lista din�mica de descripciones.*/
/*10*/ protected Description[] descriptionList;
/**Lista din�mica de salidas est�ndar.*/
/*11*/ protected Path[] standardExits;
/**Lista din�mica de otras salidas.*/
/*12*/ protected Path[] otherExits;
/**Lista din�mica de objetos.*/
//no s�, tal vez mejor vector, por aquello de din�mica.
/*20*/ protected Inventory itemsInRoom; //item vector
/**Lista din�mica de bichos.*/
/*21*/ protected MobileList mobsInRoom;
/**Lista din�mica de personajes.*/
/**Descripciones de cosas de la habitaci�n.*/
/*30*/ protected String extraDescriptions; //OLD
protected List extraDescriptionArrays; /*List of Description Arrays*/
protected List extraDescriptionNameArrays; /*List of String Arrays*/
/**Restricciones de acceso y otras.*/
/*31*/ protected Vector onlyRestrictions;
/**C�digo en Ensamblador Virtual Aetheria (EVA)*/
/*80*/ protected ObjectCode itsCode;
private NaturalLanguage lenguaje;
private java.util.Random aleat;
///////////
//METHODS//
///////////
/**
* Este constructor solo llama a constructRoom, que es el constructor de verdad. Esta dualidad se debe a las llamadas recursivas que debe hacer constructRoom para soportar herencia dinamica (habitaciones que copian datos de otras)
*
*/
public Room ( World mundo , String roomfile ) throws IOException , FileNotFoundException
{
constructRoom ( mundo , roomfile );
}
public Room ( World mundo , org.w3c.dom.Node n ) throws XMLtoWorldException
{
constructRoom ( mundo , n , true );
}
/**
* El pedazo de constructor que lee una habitaci�n de un fichero.
* <nota: random number seed se setea despu�s>
*/
public void constructRoom ( World mundo , String roomfile ) throws IOException, FileNotFoundException
{
this.mundo = mundo;
/*este metodo nos dice cuando ya hemos realizado una llamada recursiva al constructor para la herencia (la herencia ha terminado)*/
boolean inheritance_done = false;
String linea;
String id_linea;
lenguaje = mundo.getLanguage();
// aleat = mundo.getRandom();
// Debug.println("Random number generator set to " + aleat );
FileInputStream fp = new FileInputStream ( roomfile );
BufferedReader filein = new BufferedReader ( Utility.getBestInputStreamReader ( fp ) );
for ( int line = 1 ; line < 100 ; line++ )
{
linea = filein.readLine();
id_linea = StringMethods.getTok( linea , 1 , ' ' );
linea = StringMethods.getToks( linea , 2 , StringMethods.numToks( linea , ' ' ) , ' ' );
if ( id_linea != null ) switch ( Integer.valueOf(id_linea).intValue() )
{
case 1:
idnumber = Integer.valueOf(linea).intValue(); break;
case 2:
inheritsFrom = Integer.valueOf(linea).intValue();
if ( inheritsFrom < idnumber && !inheritance_done ) /*la habitacion de la que heredamos debe tener ID menor*/
{
/*construimos segun constructor de la habitacion de que heredamos*/
constructRoom ( mundo , Utility.roomFile(mundo,inheritsFrom) );
/*no haremos mas llamadas recursivas de estas*/
inheritance_done = true;
/*overrideamos lo que tengamos que overridear*/
constructRoom ( mundo , roomfile );
return;
}
break;
case 3:
setNewState( Integer.valueOf(linea).intValue() ); break;
case 4:
title = linea; break;
case 10:
//room description list line
{
//descriptionList = new Description[ StringMethods.numToks(linea,'&')/3 ];
//for ( int i = 0 ; i+3 <= StringMethods.numToks(linea,'&') ; i+=3 )
//{
// descriptionList[i/3] = new Description ( StringMethods.getTok( linea,i+3,'&' ) , Integer.valueOf(StringMethods.getTok( linea,i+1,'&' )).intValue() , Integer.valueOf(StringMethods.getTok( linea,i+2,'&' )).intValue() );
//comparando:token i+1
//mascara:token i+2
//texto:token i+3
//}
descriptionList=Utility.loadDescriptionListFromString( linea );
//Debug.print(descriptionList[0].getText());
break;
}
case 11:
//standard exit line
{
standardExits = new Path[10];
if ( StringMethods.numToks( linea , '@' ) < 10 )
System.out.println("[SINTAXIS] l�nea 10 (" + roomfile + ") insuficientes tokens con @");
for ( int i = 0 ; i < 10 ; i++ )
{
String curToken = StringMethods.getTok( linea , i+1 , '@' );
standardExits[i] = new Path ( mundo , true , curToken ); //el true indica que es est�ndar.
}
break;
}
case 12:
//non-standard exit line
{
otherExits = new Path[StringMethods.numToks( linea , '@' )];
for ( int i = 0 ; i < otherExits.length ; i++ )
{
String curToken = StringMethods.getTok( linea , i+1 , '@' );
otherExits[i] = new Path ( mundo , false , curToken ); //false = non-standard exit
}
break;
}
case 20:
//item references line
{
int nObjects = StringMethods.numToks(linea,'$');
itemsInRoom = new Inventory ( 1000000,1000000,nObjects );
//Item[nObjects];
for ( int i = 0 ; i < nObjects ; i++ )
{
try
{
itemsInRoom.addItem ( mundo.getItem(StringMethods.getTok(linea,i+1,'$')) );
}
catch (WeightLimitExceededException exc)
{
mundo.write("Item too heavy for room");
}
catch (VolumeLimitExceededException exc2)
{
mundo.write("Item too big for room");
}
}
break;
}
case 21:
//mobile references line
{
//System.out.println("Veintiuno");
int nObjects = StringMethods.numToks(linea,'$');
//System.out.println(nObjects + " in " + idnumber );
mobsInRoom = new MobileList();
for ( int i = 0 ; i < nObjects ; i++ )
{
Mobile ourMob = mundo.getMob(StringMethods.getTok(linea,i+1,'$'));
mobsInRoom.addElement ( ourMob );
ourMob.setRoom(this);
ourMob.setRoom(this); //actual y anterior
}
break;
}
case 30:
//extra description line
{
extraDescriptions = linea;
break;
}
case 80:
//begin EVA code line
{
String EVACodeString = linea;
boolean terminamos = false;
while ( !terminamos )
{
linea = filein.readLine();
id_linea = StringMethods.getTok(linea,1,' ');
int intval;
try
{
intval = Integer.valueOf(id_linea).intValue();
}
catch ( NumberFormatException e )
{
intval=0;
}
if ( intval == 81 ) terminamos=true; //EVA code termination line
else
{
EVACodeString += "\n";
EVACodeString += linea;
}
}
itsCode = new ObjectCode ( EVACodeString , "EVA" , mundo );
break;
} //end case 80
case 84:
//begin BeanShell code line
{
String bshCodeString = linea;
boolean terminamos = false;
while ( !terminamos )
{
linea = filein.readLine();
id_linea = StringMethods.getTok(linea,1,' ');
int intval;
try
{
intval = Integer.valueOf(id_linea).intValue();
}
catch ( NumberFormatException e )
{
intval=0;
}
if ( intval == 85 ) terminamos=true; //EVA code termination line
else
{
bshCodeString += "\n";
bshCodeString += linea;
}
}
itsCode = new ObjectCode ( bshCodeString , "BeanShell" , mundo );
break;
} //end case 84
} //end case switch
} //end for
//poner bien la id
if ( getID() < 10000000 )
idnumber += 10000000; //prefijo de habitacion
}
public void constructRoom ( World mundo , org.w3c.dom.Node n , boolean allowInheritance ) throws XMLtoWorldException
{
this.mundo = mundo;
lenguaje = mundo.getLanguage();
if ( ! ( n instanceof org.w3c.dom.Element ) )
{
throw ( new XMLtoWorldException ( "Room node not Element" ) );
}
//{n is an Element}
org.w3c.dom.Element e = (org.w3c.dom.Element) n;
//weak inheritance?
if ( e.hasAttribute("extends") && !e.getAttribute("extends").equals("0") && !e.getAttribute("extends").equals("null") && allowInheritance )
{
//item must extend from existing item.
//clonamos ese item y overrideamos lo overrideable
//(n�tese que la ID del item extendido ha de ser menor).
//por eso los associated nodes de los items quedan guardados [por ref] en el World hasta que
//haya concluido la construccion del mundo
//1. overrideamos el super-item usando su associated node para construirlo
constructRoom ( mundo , mundo.getRoomNode( e.getAttribute("extends") ) , true );
//2. overrideamos lo que debamos overridear
constructRoom ( mundo , n , false );
}
//mandatory XML-attribs exceptions
/*as of 03.09.15, ID no longer mandatory*/
//if ( !e.hasAttribute("id") )
// throw ( new XMLtoWorldException ( "Room node lacks attribute id" ) );
if ( !e.hasAttribute("name") )
throw ( new XMLtoWorldException ( "Room node lacks attribute name" ) );
//mandatory XML-attribs parsing
try
{
//id no longer mandatory
if ( e.hasAttribute("id") )
idnumber = Integer.valueOf ( e.getAttribute("id") ).intValue();
//Debug.println("Room id " + idnumber);
}
catch ( NumberFormatException nfe )
{
throw ( new XMLtoWorldException ( "Bad number format at attribute id in mobile node" ) );
}
title = e.getAttribute("name");
//Entity parsing
readPropListFromXML ( mundo , n );
//description list
descriptionList = Utility.loadDescriptionListFromXML ( mundo , e , "DescriptionList" , true );
//path lists: standardExits[10] and otherExits[..]
org.w3c.dom.NodeList pathListNodes = e.getElementsByTagName ( "PathList" );
if ( pathListNodes.getLength() > 0 )
{
org.w3c.dom.Element pathListNode = (org.w3c.dom.Element) pathListNodes.item(0);
org.w3c.dom.NodeList pathNodes = pathListNode.getElementsByTagName ( "Path" );
//count non-standard exits to init array
int nNonStandard = 0;
for ( int i = 0 ; i < pathNodes.getLength() ; i++ )
{
org.w3c.dom.Element curNode = (org.w3c.dom.Element) pathNodes.item(i);
//check if there are custom commands defined for the exit
boolean hasCommands = false;
if ( curNode.getElementsByTagName("CommandList").getLength() > 0 )
{
org.w3c.dom.Element commandListNode = (org.w3c.dom.Element) curNode.getElementsByTagName("CommandList").item(0);
if ( commandListNode.getElementsByTagName("Command").getLength() > 0 )
hasCommands = true;
}
if ( ! ( Boolean.valueOf ( curNode.getAttribute("standard") ).booleanValue() ) || hasCommands )
nNonStandard++;
}
//init arrays
standardExits = new Path[10];
otherExits = new Path[nNonStandard];
//parse path nodes
int nonStandardExitCounter = 0; //numero de nonstandard por la que vamos
for ( int i = 0 ; i < pathNodes.getLength() ; i++ )
{
//Debug.println("Path node " + i);
org.w3c.dom.Element curNode = (org.w3c.dom.Element)pathNodes.item(i);
Path p = new Path ( mundo , curNode );
Debug.println("Path " + i + " for room " + getID());
if ( p.isStandard() )
{
int direccion = Path.nameToDirection( curNode.getAttribute("direction") );
standardExits[direccion] = p;
//la salida puede tener comandos aunque sea estandar
if ( p.isExtended() )
{
otherExits[nonStandardExitCounter] = p;
nonStandardExitCounter++;
}
}
else
{
otherExits[nonStandardExitCounter] = p;
nonStandardExitCounter++;
}
}
}
else
{
standardExits = new Path[10];
otherExits = new Path[0];
}
//Debug.println("Will null-fill exits");
//now fill standard exits with invalid exits on nulls
for ( int i = 0 ; i < standardExits.length ; i++ )
{
if ( standardExits[i] == null )
{
standardExits[i] = new Path ( mundo , true , "0" ); //el true indica que es est�ndar.
//el 0 har� que produzca una salida inv�lida
}
}
//Debug.println("Will parse inventory");
//no need for cargas diferidas for inventory and mobile list: items and mobiles load
//before rooms!
org.w3c.dom.NodeList inventoryNodes = e.getElementsByTagName ( "Inventory" );
//solo nos interesan los hijos DIRECTOS
List realInventoryNodes = new ArrayList();
for ( int i = 0 ; i < inventoryNodes.getLength() ; i++ )
if ( inventoryNodes.item(i).getParentNode() == e ) realInventoryNodes.add ( inventoryNodes.item(i) );
if ( realInventoryNodes.size() < 1 )
{
//Debug.println("No inventory nodes, inventory will be left null.");
itemsInRoom = null;
}
else
{
//Debug.println("Inventory nodes present.");
itemsInRoom = new Inventory ( mundo , (org.w3c.dom.Node)realInventoryNodes.get(0) );
//Debug.println("Inventory size: " + inventory.size() );
//Debug.println("Inventory node: " + inventoryNodes.item(0) );
//Debug.println("Inventory's parent: " + inventoryNodes.item(0).getParentNode() );
//Debug.println(inventory);
}
//add room refs to items
if ( itemsInRoom != null )
for ( int i = 0 ; i < itemsInRoom.size() ; i++ )
{
Item cur = itemsInRoom.elementAt(i);
cur.addRoomReference(this);
}
//Debug.println("Will parse moblist");
org.w3c.dom.NodeList moblistNodes = e.getElementsByTagName ( "MobileList" );
if ( moblistNodes.getLength() < 1 )
mobsInRoom = new MobileList();
else
{
mobsInRoom = new MobileList ( mundo , moblistNodes.item(0) );
if ( mobsInRoom == null )
mobsInRoom = new MobileList();
//la guardamos porque el hacer setRoom() puede alterar el orden de la MobileList
MobileList copiaMobsInRoom = new MobileList ( mundo , moblistNodes.item(0) );
//set current room var in mobiles
for ( int i = 0 ; i < copiaMobsInRoom.size() ; i++ )
{
//Debug.println("Mobs in Room: " + mobsInRoom.size() );
//Debug.println("Actually: " + mobsInRoom);
Mobile ourMob = copiaMobsInRoom.elementAt(i);
Debug.println("i= " + i + ": Setting room on mob " + ourMob + " to " + this);
ourMob.setRoom(this);
ourMob.setRoom(this); //actual y anterior
}
}
//Debug.println("Will parse extrades");
//extra descriptions
//extraDescriptions = Utility.loadExtraDescriptionsFromXML ( e , "ExtraDescriptionList" , true );
//extraDescriptionList = Utility.loadExtraDescriptionsFromXML ( mundo , e , "ExtraDescriptionList" , true );
List temp = Utility.loadExtraDescriptionsFromXML ( mundo , e , "ExtraDescriptionList" , true );
if ( temp == null || temp.size() < 2 )
{
extraDescriptionArrays = new ArrayList();
extraDescriptionNameArrays = new ArrayList();
}
else
{
extraDescriptionArrays = (List) temp.get(1);
extraDescriptionNameArrays = (List) temp.get(0);
}
//Debug.println("Will parse code");
//code
org.w3c.dom.NodeList codeNodes = e.getElementsByTagName ( "Code" );
if ( codeNodes.getLength() > 0 )
{
try
{
itsCode = new ObjectCode ( mundo , codeNodes.item(0) );
}
catch ( XMLtoWorldException ex )
{
throw ( new XMLtoWorldException ( "Exception at Code node: " + ex.getMessage() ) );
}
}
//Debug.println("Will correct ID");
//poner bien la id
if ( getID() == 0 )
{
//no se especific� id, la asignar� el mundo.
;
}
else if ( getID() < 10000000 )
idnumber += 10000000; //prefijo de habitacion
//from 2014-10-22, onInit() is not executed when loading states, see issue #310
if ( !mundo.comesFromLoadedState() )
{
//eventos onInit()
try
{
boolean ejecutado = execCode ( "onInit" ,
new Object[]
{
}
);
}
catch ( ScriptException te )
{
mundo.writeError(ExceptionPrinter.getExceptionReport(te));
te.printStackTrace();
}
}
}
public void setID ( int newid )
{
if ( newid < Utility.room_summand )
idnumber = newid + Utility.room_summand;
else
idnumber = newid;
}
public boolean isValidExit( boolean isStandard , int exitn )
{
if ( isStandard )
return standardExits[exitn].isValid();
else
{
Debug.println("Other Exits: " + otherExits);
Debug.println(""+exitn);
Debug.println("Len " + otherExits.length);
for ( int i = 0 ; i < otherExits.length ; i++ )
Debug.println(otherExits[i]);
return otherExits[exitn].isValid();
}
}
public Path[] getValidExits ( )
{
List caminos = new ArrayList();
for ( int i = 0 ; i < standardExits.length ; i++ )
{
if ( standardExits[i].isValid() )
caminos.add ( standardExits[i] );
}
for ( int i = 0 ; i < otherExits.length ; i++ )
{
if ( otherExits[i].isValid() )
caminos.add ( otherExits[i] );
}
Path[] caminos_ar = new Path[caminos.size()];
for ( int i = 0 ; i < caminos_ar.length; i++ )
{
caminos_ar[i] = (Path) caminos.get(i);
}
return caminos_ar;
}
public Path getExit ( boolean isStandard , int exitn )
{
if ( isStandard ) return standardExits[exitn];
else return otherExits[exitn];
}
public Path getPath ( boolean isStandard , int exitn )
{
return getExit ( isStandard , exitn );
}
public Path[] getStandardExits ( )
{
return standardExits;
}
public Path[] getNonStandardExits ( )
{
return otherExits;
}
public int getRandomValidExitAsNumber ( )
{
int nvalid_standard = 0 , nvalid_nonstandard = 0;
for ( int i = 0 ; i < standardExits.length ; i++ )
{
if ( isValidExit( true , i ) ) nvalid_standard++;
}
for ( int i = 0 ; i < otherExits.length ; i++ )
{
if ( isValidExit( false , i ) ) nvalid_nonstandard++;
}
//Debug.println("nvalid = " + nvalid_standard + " + " + nvalid_nonstandard );
if ( nvalid_standard + nvalid_nonstandard < 1 ) return -1; //ninguna salida v�lida
int numsalida = aleat.nextInt( nvalid_standard + nvalid_nonstandard );
int i,j;
i = 0;
//System.err.println("Room " + this + " numsal " + numsalida);
for ( int k = 0 ; k < standardExits.length && k < numsalida ; k++ )
{
if ( isValidExit( true , i ) ) i++;
if ( i == numsalida )
{
return i-1;
}
}
for ( j = i ; j-i < otherExits.length && j < numsalida ; )
{
if ( isValidExit(false,j-i) ) j++;
}
//return otherExits[j-i-1];
return 10 /*nstandardexits*/ + j - i - 1;
}
public Path getRandomValidExit ( )
{
int nsal = getRandomValidExitAsNumber();
if ( nsal < 0 ) return null;
if ( nsal < 10 )
return standardExits[nsal];
else
return otherExits[10-nsal];
}
/**
* Obtains the non-standard path from this room that best matches the given arguments.
* @param arguments
* @return
*/
public Path getNonStandardExitMatchingArguments ( String arguments )
{
Path result = null;
if ( new VersionComparator().compare(mundo.getParserVersion(),"1.3.0") < 0 )
{
//old behaviour: only matches with the end of the command
//not sure if there is really any point on maintaining this. I can't really think of a case where going with the new behaviour in an old game could
//be problematic.
//Mirar las salidas personalizadas
for ( int i=0 ; i < otherExits.length ; i++ )
{
if ( isValidExit(false,i) && getExit(false,i).matchExitCommand( arguments , false ) >= 0 )
{
result = getExit ( false , i );
}
}
}
else
{
//new behaviour: matches with any part of the command, returning the longest path name that is contained in it
int bestMatch = -1;
for ( int i=0 ; i < otherExits.length ; i++ )
{
if ( isValidExit(false,i) )
{
int lengthMatched = getExit(false,i).matchExitCommand( arguments , true );
if ( lengthMatched > bestMatch )
{
result = getExit ( false , i );
bestMatch = lengthMatched;
}
}
}
}
return result;
}
/**
* Obtains the standard path from this room that best matches the given arguments, if there's any.
* @param arguments
* @return
*/
public Path getStandardExitMatchingArguments ( String arguments )
{
Path standardPath = null;
int direction = mundo.argumentsToDirection(arguments);
if ( direction != Path.NO_DIRECTION )
standardPath = getExit ( true , direction );
//this logic is now moved to world: argumentsToDirection (which calls getNamesForDirection).
/*
if ( StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase(mundo.getMessages().getMessage("direction.n"))
|| StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase("n") )
{
//mentions.setLastMentionedVerb(command);
//return go (getExit( true,Path.NORTE ));
standardPath = getExit ( true , Path.NORTE );
}
else if ( StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase(mundo.getMessages().getMessage("direction.s"))
|| StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase("s") )
{
//mentions.setLastMentionedVerb(command);
//return go (getExit( true,Path.SUR ));
standardPath = getExit ( true , Path.SUR );
}
else if ( StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase(mundo.getMessages().getMessage("direction.w"))
|| StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase("o") )
{
//mentions.setLastMentionedVerb(command);
//return go (getExit( true,Path.OESTE ));
standardPath = getExit ( true , Path.OESTE );
}
else if ( StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase(mundo.getMessages().getMessage("direction.e"))
|| StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase("e") )
{
//mentions.setLastMentionedVerb(command);
//return go (getExit( true,Path.ESTE ));
standardPath = getExit ( true , Path.ESTE );
}
else if ( StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase("sudeste")
|| StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase("se")
|| StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase("sureste") )
{
//mentions.setLastMentionedVerb(command);
//return go (getExit( true,Path.ESTE ));
standardPath = getExit ( true , Path.SUDESTE );
}
else if ( StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase("sudoeste")
|| StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase("so")
|| StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase("suroeste") )
{
//mentions.setLastMentionedVerb(command);
//return go (getExit( true,Path.ESTE ));
standardPath = getExit ( true , Path.SUROESTE );
}
else if ( StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase("nordeste")
|| StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase("noreste")
|| StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase("ne") )
{
//mentions.setLastMentionedVerb(command);
//return go (getExit( true,Path.ESTE ));
standardPath = getExit ( true , Path.NORDESTE );
}
else if ( StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase("noroeste")
|| StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase("no") )
{
//mentions.setLastMentionedVerb(command);
//return go (getExit( true,Path.ESTE ));
standardPath = getExit ( true , Path.NOROESTE );
}
else if ( StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase("arriba")
|| StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase("ar") )
{
//mentions.setLastMentionedVerb(command);
//return go (getExit( true,Path.ARRIBA ));
standardPath = getExit ( true , Path.ARRIBA );
}
else if ( StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase("abajo")
|| StringMethods.getTok( arguments , StringMethods.numToks( arguments,' ' ) , ' ' ).equalsIgnoreCase("ab") )
{
//mentions.setLastMentionedVerb(command);
//return go (getExit( true,Path.ABAJO ));
standardPath = getExit ( true , Path.ABAJO );
}
*/
return standardPath;
}
/**
* Gets the best exit from this room that matches the given arguments, period.
* Encapsulates all the standard vs. nonstandard exit nonsense. Works with every kind of exit paths.
* @param arguments
* @return
*/
public Path getExitMatchingArguments ( String arguments )
{
Path standardPath = getStandardExitMatchingArguments ( arguments );
if ( standardPath == null || !standardPath.isValid() )
return getNonStandardExitMatchingArguments ( arguments );
else
return standardPath;
}
public String getExitName ( boolean isStandard , int exitn )
{
if ( isStandard )
{
switch ( exitn )
{
case Path.NORTE: return mundo.getMessages().getMessage("direction.full.n");
case Path.SUR: return mundo.getMessages().getMessage("direction.full.s");
case Path.ESTE: return mundo.getMessages().getMessage("direction.full.e");
case Path.OESTE: return mundo.getMessages().getMessage("direction.full.w");
case Path.NORDESTE: return mundo.getMessages().getMessage("direction.full.ne");
case Path.NOROESTE: return mundo.getMessages().getMessage("direction.full.nw");
case Path.SUDESTE: return mundo.getMessages().getMessage("direction.full.se");
case Path.SUROESTE: return mundo.getMessages().getMessage("direction.full.sw");
case Path.ARRIBA: return mundo.getMessages().getMessage("direction.full.u");
case Path.ABAJO: return mundo.getMessages().getMessage("direction.full.d");
//a�adir resto
default: return "alg�n lado";
}
}
else return otherExits[exitn].getNonStandardName();
}
//new as of 03.11.24
public String getExitName ( Path p )
{
if ( p.isStandard() )
{
int exitn;
for ( exitn = 0 ; exitn < standardExits.length ; exitn++ )
{
if ( standardExits[exitn] == p ) break;
}
return getExitName ( true , exitn );
}
else
return p.getNonStandardName();
}
public List getExitNames ( Path p )
{
ArrayList result = new ArrayList();
if ( p.isStandard() )
{
int exitn;
for ( exitn = 0 ; exitn < standardExits.length ; exitn++ )
{
if ( standardExits[exitn] == p ) break;
}
result.add (getExitName ( true , exitn ));
}
String[] moreNames = p.getNonStandardNames();
if ( moreNames != null )
{
for ( int i = 0 ; i < moreNames.length ; i++ )
result.add(moreNames[i]);
}
return result;
}
public Room getPathDestination ( Path p , World w )
{
return w.getRoom(p.getDestinationID());
}
public int getID ( )
{
return idnumber;
}
public int getItsID()
{
return idnumber;
}
/**
* @deprecated Use {@link #getUniqueName()} instead
*/
public String getTitle ( )
{
return getUniqueName();
}
public String getUniqueName ( )
{
return title;
}
public String getDescription ( long comparand )
{
//std. room description
String desString="";
for ( int i = 0 ; i < descriptionList.length ; i++ )
{
if ( descriptionList[i].matches(comparand) )
{
//desString += "\n";
desString += descriptionList[i].getText();
}
}
//object description
if ( itemsInRoom != null && !itemsInRoom.isEmpty() && !itemsInRoom.toString(mundo).equals(mundo.getMessages().getMessage("nothing")+".") ) //lo del "nada" es porque puede haber items; pero que sean invisibles.
{
/*luego aqu� poner en hab. par�metro "laying objs": "Sobre el duro suelo, sobre el blando suelo, sobre el puente..."*/
desString+="\nAqu� hay ";
desString+=itemsInRoom.toString();
}
if ( mobsInRoom != null && !mobsInRoom.isEmpty() && !mobsInRoom.toString(mundo).equals(mundo.getMessages().getMessage("nothing")+".") )
{
if ( mobsInRoom.size() > 1 )
desString += "\nAqu� est�n ";
else
desString += "\nAqu� est� ";
desString+=mobsInRoom.toString(mundo);
}
return desString;
}
/*code flags exec example
boolean ejecutado = false;
//room text reaction evt
try
{
ejecutado = execCode ( "onRoomText" ,
new Object[]
{
text
}
);
}
catch ( bsh.TargetError te )
{
escribir(""+te);
te.printStackTrace();
}
if ( ejecutado ) return;
*/
//in order for bsh getDescription() to be able to use native getDescription()
//without falling in infinite recursivity
transient boolean getDescription_bsh_call = false;
public String getDescription ( Entity viewer )
{
if ( !getDescription_bsh_call ) //avoid infinite recursivity if bsh calls this method
{
boolean ejecutado = false;
ReturnValue retval = new ReturnValue ( null );
try
{
getDescription_bsh_call = true;
ejecutado = execCode ( "getDescription" ,
new Object[]
{
viewer
}
, retval
);
}
catch ( ScriptException te )
{
mundo.writeError(ExceptionPrinter.getExceptionReport(te));
te.printStackTrace();
}
finally
{
getDescription_bsh_call = false;
}
if ( retval.getRetVal() != null )
return (String)retval.getRetVal();
else if ( ejecutado ) //sobreescribe comportamiento por defecto
return null;
}
//std. room description
String desString="";
boolean quitado=false;
for ( int i = 0 ; i < descriptionList.length ; i++ )
{
if ( descriptionList[i].matchesConditions(this,viewer) )
{
//desString += "\n";
desString += descriptionList[i].getText();
}
}
//object description
if ( itemsInRoom != null && !itemsInRoom.isEmpty() && !itemsInRoom.toString( viewer , mundo ).equals(mundo.getMessages().getMessage("nothing")+".") ) //lo del "nada" es porque puede haber items; pero que sean invisibles.
{
/*luego aqu� poner en hab. par�metro "laying objs": "Sobre el duro suelo, sobre el blando suelo, sobre el puente..."*/
//old. remove.
/*
desString+="\nAqu� hay ";
desString+=itemsInRoom.toString( viewer );
*/
desString+="\n"+getLayingObjectString(viewer);
}
if ( mobsInRoom != null && viewer instanceof Mobile ) quitado = mobsInRoom.removeElement((Mobile)viewer);
if ( mobsInRoom != null && !mobsInRoom.isEmpty() && !mobsInRoom.toString( viewer , mundo ).equals(mundo.getMessages().getMessage("nothing")+".") )
{
/*
if ( mobsInRoom.size() > 1 )
desString += "\nAqu� est�n ";
else
desString += "\nAqu� est� ";
desString+=mobsInRoom.toString( viewer );
*/
if ( mobsInRoom.size() > 1 )
desString += "\n" + getPresentMobilesPluralString ( viewer );
else
desString += "\n" + getPresentMobilesSingularString ( viewer );
}
if ( quitado ) mobsInRoom.addElement((Mobile)viewer);
return desString;
}
//returns string to describe things laying on floor of this room (like "Aqu� hay una espada y un escudo.")
private String getLayingObjectString ( Entity viewer )
{
String customMessage = this.getPropertyValueAsString("itemsHereMessage");
String itemsString = itemsInRoom.toString( viewer , mundo );
String rawString = itemsString.substring(0,itemsString.length()-1);
if ( customMessage != null )
return mundo.getLanguage().correctMorphology(Messages.buildMessage(customMessage,
"$dotinventory", itemsString,
"$inventory", rawString));
else
return mundo.getLanguage().correctMorphology(mundo.getMessages().getMessage("items.here",
"$dotinventory",itemsString,
"$inventory", rawString,
new Object[]{this}));
}
//returns string to describe a mobile on a room (like "Aqu� est� Juan.")
private String getPresentMobilesSingularString ( Entity viewer )
{
String customMessage = this.getPropertyValueAsString("mobileHereMessage");
String mobsString = mobsInRoom.toString( viewer , mundo );
String rawString = mobsString.substring(0,mobsString.length()-1);
if ( customMessage != null )
return Messages.buildMessage(customMessage, "$dotlist", mobsString , "$list" , rawString );
else
return mundo.getMessages().getMessage("mobile.here", "$dotlist", mobsString , "$list" , rawString , new Object[]{this});
}
//returns string to describe several mobiles on a room (like "Aqu� est�n Pedro y Juan.")
private String getPresentMobilesPluralString ( Entity viewer )
{
String customMessage = this.getPropertyValueAsString("mobilesHereMessage");
String mobsString = mobsInRoom.toString( viewer , mundo );
String rawString = mobsString.substring(0,mobsString.length()-1);
if ( customMessage != null )
return Messages.buildMessage(customMessage, "$dotlist", mobsString , "$list" , rawString );
else
return mundo.getMessages().getMessage("mobiles.here", "$dotlist", mobsString, "$list", rawString, new Object[]{this});
}
public String getDescription ( long comparand , Mobile toExclude )
{
//excluye al jugador, al yo.
//std. room description
String desString="";
for ( int i = 0 ; i < descriptionList.length ; i++ )
{
if ( descriptionList[i].matches(comparand) )
{
//desString += "\n";
desString += descriptionList[i].getText();
}
}
//object description
if ( itemsInRoom != null && !itemsInRoom.isEmpty() && !itemsInRoom.toString(mundo).equals(mundo.getMessages().getMessage("nothing")+".") ) //lo del "nada" es porque puede haber items; pero que sean invisibles.
{
desString+="\nAqu� hay ";
desString+=itemsInRoom.toString();
}
boolean quitado = false;
if ( mobsInRoom != null ) quitado = mobsInRoom.removeElement(toExclude);
if ( mobsInRoom != null && !mobsInRoom.isEmpty() && !mobsInRoom.toString(mundo).equals(mundo.getMessages().getMessage("nothing")+".") )
{
if ( mobsInRoom.size() > 1 )
desString += "\nAqu� est�n ";
else
desString += "\nAqu� est� ";
desString+=mobsInRoom.toString();
}
if ( quitado ) mobsInRoom.addElement(toExclude);
return desString;
}
//updated to use matchesConditions instead of comparands and such.
/*Legacy. Ahora el getDescription que solo coge viewer ya excluye al viewer.
public String getDescription ( Entity viewer , Mobile toExclude )
{
//excluye al jugador, al yo.
//std. room description
String desString="";
for ( int i = 0 ; i < descriptionList.length ; i++ )
{
if ( descriptionList[i].matchesConditions(this,viewer) )
{
//desString += "\n";
desString += descriptionList[i].getText();
}
}
//object description
if ( itemsInRoom != null && !itemsInRoom.isEmpty() && !itemsInRoom.toString(viewer).equals("nada.") ) //lo del "nada" es porque puede haber items; pero que sean invisibles.
{
desString+="\nAqu� hay ";
desString+=itemsInRoom.toString(viewer);
}
boolean quitado = false;
if ( mobsInRoom != null ) quitado = mobsInRoom.removeElement(toExclude);
Debug.println("Mobs In Roome: " + mobsInRoom);
Debug.println("Mobs In Roome Seez " + mobsInRoom.size() );
if ( mobsInRoom != null && !mobsInRoom.isEmpty() && !mobsInRoom.toString(viewer).equals("nada.") )
{
if ( mobsInRoom.size() > 1 )
desString += "\nAqu� est�n ";
else
desString += "\nAqu� est� ";
desString+=mobsInRoom.toString(viewer);
}
if ( quitado ) mobsInRoom.addElement(toExclude);
return desString;
}
*/
//as of 02.09.28, extra descriptions MAY be stated,
//using dynlists as in std. descriptions, with room state.
//in this case, no &'s in an extra description means 0&0&...
/*
public String getExtraDescription ( String thingieName , long comparand )
{
int nTokens = StringMethods.numToks(extraDescriptions,'@');
for ( int i = 1 ; i <= nTokens ; i++ )
{
String curToken = StringMethods.getTok(extraDescriptions,i,'@');
int nTokens2 = StringMethods.numToks(curToken,'$');
for ( int j = 1 ; j < nTokens2 ; j++ )
{
//si la ultima palabra de lo que pone despues de "mirar" coincide con uno de los nTokens2-1 primeros tokens (es decir, comandos que activan extrades)
if ( StringMethods.getTok(thingieName,StringMethods.numToks(thingieName,' '),' ').equalsIgnoreCase(StringMethods.getTok(curToken,j,'$')) )
{
String theDescription = StringMethods.getTok(curToken,nTokens2,'$');
//puede ser stateful o stateless. Vamos a verlo.
if ( theDescription.indexOf('&') < 0 )
return theDescription; //sin depender de estados
else
{
//depende de estados (es una description list con comparandos y m�scaras)
//procesar comparandos y m�scaras como en getDescription
Description[] dList = Utility.loadDescriptionListFromString ( theDescription );
String desString="";
for ( int k = 0 ; k < dList.length ; k++ )
{
if ( dList[k].matches(comparand) ) //or general comparand?
{
desString += "\n";
desString += dList[k].getText();
}
}
if ( desString.length() > 0 )
return desString;
else
return null;
}
}
}
}
return null;
}
*/
/**
* Obtains an extra description, representing a description of a particular component, feature or aspect of this Room.
* This method's implementation has been changed as of 2012-12-01 to match in a more useful way, similar to the Entity moderateMatchesCommand() method.
* @param requestedName The name to match against descriptions (e.g. typed by the player)
* @param viewer The Entity for which the description will be customized.
* @return A description for the component/feature/aspect named requestedName, or null if no such component exists.
*/
public String getExtraDescription ( String requestedName , Entity viewer )
{
if ( requestedName == null || requestedName.length() == 0 ) return null;
for ( int i = 0 ; i < extraDescriptionNameArrays.size() ; i++ )
{
String[] curNameArray = (String[]) extraDescriptionNameArrays.get(i);
Description[] curDesArray = (Description[]) extraDescriptionArrays.get(i);
for ( int j = 0 ; j < curNameArray.length ; j++ )
{
String currentReferenceName = curNameArray[j];
int position = requestedName.toLowerCase().indexOf(currentReferenceName.toLowerCase());
if ( position < 0 ) //does not match
continue;
if ( position != 0 && !Character.isWhitespace(requestedName.charAt(position-1)) ) //matches but starts at a place other than beginning/whitespace
continue;
if ( position+currentReferenceName.length() != requestedName.length() && !Character.isWhitespace(requestedName.charAt(position+currentReferenceName.length())) ) //matches but ends at a place other than end/whitespace
continue;
//if we have reached this point, the match is acceptable
String desString="";
for ( int k = 0 ; k < curDesArray.length ; k++ )
{
if ( curDesArray[k].matchesConditions(this,viewer) ) //or general comparand?
{
desString += "\n";
desString += curDesArray[k].getText();
}
}
if ( desString.length() > 0 )
return desString.substring(1); //quitamos primer \n
else
return null;
}
}
//nothing found
return null;
}
//as of 03.09.03, extra descriptions are regular descriptions.
//Parallel lists of Description[] and String[].
/*
public String getExtraDescription ( String thingieName , Entity viewer )
{
if ( thingieName == null || thingieName.length() == 0 ) return null;
for ( int i = 0 ; i < extraDescriptionNameArrays.size() ; i++ )
{
String[] curNameArray = (String[]) extraDescriptionNameArrays.get(i);
Description[] curDesArray = (Description[]) extraDescriptionArrays.get(i);
// Modern Extra Description Support! On items as of 05-07-14!
// Pasted to rooms as of 05-09-27! Let's Rock It!
for ( int j = 0 ; j < curNameArray.length ; j++ )
{
if ( thingieName.toLowerCase().endsWith(curNameArray[j].toLowerCase()) )
{
String desString="";
for ( int k = 0 ; k < curDesArray.length ; k++ )
{
if ( curDesArray[k].matchesConditions(this,viewer) ) //or general comparand?
{
desString += "\n";
desString += curDesArray[k].getText();
}
}
if ( desString.length() > 0 )
return desString.substring(1); //quitamos primer \n
else
return null;
}
}
//Ancient Extra Description Support. Buuuh! Buuuh!
for ( int j = 0 ; j < curNameArray.length ; j++ )
{
//si la ultima palabra de lo que pone despues de "mirar" coincide con el nombre actual
if ( StringMethods.getTok(thingieName,StringMethods.numToks(thingieName,' '),' ').equalsIgnoreCase(curNameArray[j]) )
{
String desString="";
for ( int k = 0 ; k < curDesArray.length ; k++ )
{
if ( curDesArray[k].matchesConditions(this,viewer) ) //or general comparand?
{
desString += "\n";
desString += curDesArray[k].getText();
}
}
if ( desString.length() > 0 )
return desString.substring(1); //quitamos primer \n
else
return null;
}
}
}
return null;
}
*/
//updated in order to use matchesConditions, instead of comparands and such.
/*
public String getExtraDescription ( String thingieName , Entity viewer )
{
int nTokens = StringMethods.numToks(extraDescriptions,'@');
for ( int i = 1 ; i <= nTokens ; i++ )
{
String curToken = StringMethods.getTok(extraDescriptions,i,'@');
int nTokens2 = StringMethods.numToks(curToken,'$');
for ( int j = 1 ; j < nTokens2 ; j++ )
{
//si la ultima palabra de lo que pone despues de "mirar" coincide con uno de los nTokens2-1 primeros tokens (es decir, comandos que activan extrades)
if ( StringMethods.getTok(thingieName,StringMethods.numToks(thingieName,' '),' ').equalsIgnoreCase(StringMethods.getTok(curToken,j,'$')) )
{
String theDescription = StringMethods.getTok(curToken,nTokens2,'$');
//puede ser stateful o stateless. Vamos a verlo.
if ( theDescription.indexOf('&') < 0 )
return theDescription; //sin depender de estados
else
{
//depende de estados (es una description list con comparandos y m�scaras)
//procesar comparandos y m�scaras como en getDescription
Description[] dList = Utility.loadDescriptionListFromString ( theDescription );
String desString="";
for ( int k = 0 ; k < dList.length ; k++ )
{
if ( dList[k].matchesConditions(this,viewer) ) //or general comparand?
{
desString += "\n";
desString += dList[k].getText();
}
}
if ( desString.length() > 0 )
return desString;
else
return null;
}
}
}
}
return null;
}
*/
//Hay que definir el changeState.
public void changeState ( World mundo ) { }
public void addItem ( Item nuevo ) throws WeightLimitExceededException,VolumeLimitExceededException
{
if ( itemsInRoom == null ) itemsInRoom = new Inventory(100000,100000,1);
itemsInRoom.addItem(nuevo);
nuevo.addRoomReference(this);
}
public boolean removeItem ( Item viejo )
{
if ( itemsInRoom == null ) return false;
else
{
viejo.removeRoomReference(this);
return itemsInRoom.removeItem(viejo);
}
}
public void addMob ( Mobile nuevo )
{
if ( mobsInRoom == null ) mobsInRoom = new MobileList();
mobsInRoom.addElement(nuevo);
}
public boolean removeMob ( Mobile viejo )
{
if ( mobsInRoom == null ) return false;
return mobsInRoom.removeElement(viejo);
}
/*ejecuta el codigo de la habitacion correspondiente a la rutina dada si existe.
Si no existe, simplemente no ejecuta nada y devuelve false.*/
public boolean execCode ( String routine , String dataSegment ) throws EVASemanticException
{
if ( itsCode != null )
return itsCode.run ( routine , dataSegment );
else return false;
}
/*ejecuta el codigo bsh del objeto correspondiente a la rutina dada si existe.
Si no existe, simplemente no ejecuta nada y devuelve false.*/
public boolean execCode ( String routine , Object[] args ) throws ScriptException
{
if ( itsCode != null )
return itsCode.run ( routine , this , args );
else return false;
}
/*ejecuta el codigo bsh del objeto correspondiente a la rutina dada si existe.
Si no existe, simplemente no ejecuta nada y devuelve false.*/
public boolean execCode ( String routine , Object[] args , ReturnValue retval ) throws ScriptException
{
//S/ystem.out.println("Mobile code runnin'.");
//Debug.println("Its Code: " + itsCode);
if ( itsCode != null )
return itsCode.run ( routine , this , args , retval );
else return false;
}
//sustituye $1 por el nombre de source y $2 por el de target. De momento son mobiles, luego ya ser�n Entitys generales, o Referenciables, m�s bien.
public String personalizeDescription ( String des , Mobile source , Mobile target )
{
String s = des;
if ( source != null )
{
String nombre = source.constructName2(1,null); //personalize more (subjetivize) later!
if ( nombre == null ) nombre = mundo.getMessages().getMessage("unnamed.mobile");
s = StringMethods.textualSubstitution ( s , "$1" , nombre );
}
if ( target != null )
{
String nombre = target.constructName2(1,null); //personalize more (subjetivize) later!
if ( nombre == null ) nombre = mundo.getMessages().getMessage("unnamed.mobile");
s = StringMethods.textualSubstitution ( s , "$2" , nombre );
}
return s;
}
//funci�n gen�rica que sustituye los $'s en las descripciones por los nombres de las cosas en funci�n de quien las ve (viewer).
public String personalizeDescription ( String des , Entity viewer , Nameable[] dollarEntities )
{
String s = des;
//sustituir $1 por el nombre de dollarEntities[0] seg�n viewer, $2 por el nombre de dollarEntities[1] seg�n viewer, etc. etc.
for ( int i = 0 ; i < dollarEntities.length ; i++ )
{
if ( dollarEntities[i] != null )
{
String nombre = dollarEntities[i].constructName2(1,viewer);
if ( nombre == null || dollarEntities[i].isInvisible(viewer) )
{
if ( dollarEntities[i] instanceof Mobile )
nombre = mundo.getMessages().getMessage("unnamed.mobile");
else
nombre = mundo.getMessages().getMessage("unnamed.item");
}
s = StringMethods.textualSubstitution ( s , "$" + (i+1) , nombre );
}
}
return lenguaje.correctMorphologyWithoutTrimming(s);
}
//the new, subjective inform action
//warning: may throw ClassCastException if non-nameable entities are passed!
/**
* @deprecated Use {@link #reportAction(Entity,Entity,Entity[],String,String,String,boolean)} instead
*/
public void informAction ( Entity source /*$1*/ , Entity target /*$2*/ , Entity[] objects /*$3..$n*/ , String thirdPersonDes , String sufferDes , String execDes , boolean self_included )
{
reportAction(source, target, objects, thirdPersonDes, sufferDes,
execDes, self_included);
}
/**
* calls version with style parameter.
* @param source
* @param target
* @param objects
* @param thirdPersonDes
* @param sufferDes
* @param execDes
* @param self_included
*/
public void reportAction ( Entity source /*$1*/ , Entity target /*$2*/ , Entity[] objects /*$3..$n*/ , String thirdPersonDes , String sufferDes , String execDes , boolean self_included )
{
reportAction ( source , target , objects , thirdPersonDes , sufferDes , execDes , null , self_included );
}
//the new, subjective report action
//warning: may throw ClassCastException if non-nameable entities are passed!
public void reportAction ( Entity source /*$1*/ , Entity target /*$2*/ , Entity[] objects /*$3..$n*/ , String thirdPersonDes , String sufferDes , String execDes , String style , boolean self_included )
{
//Debug.println("INFORMACTION BEGIN");
Nameable[] dollarEntities;
if ( objects == null ) dollarEntities = new Nameable[2];
else dollarEntities = new Nameable[2+objects.length];
//Debug.println("INFORMACTION INTERMEDIATE CIRCUS RELOADING STEP");
dollarEntities[0]=(Nameable)source;
//Debug.println("NO, No, No. MY FISH'S NAME IS ERIC. ERIC THE FISH.");
dollarEntities[1]=(Nameable)target;
//Debug.println("INFORMACTION NULLCHECK");
if ( objects != null )
{
for ( int i = 0 ; i < objects.length ; i++ )
dollarEntities[2+i]=(Nameable)objects[i];
}
//Debug.println("INFORMACTION CALLED" + thirdPersonDes);
//informar a cada bicho de la habitaci�n.
for ( int i = 0 ; i < mobsInRoom.size() ; i++ )
{
Mobile actual = mobsInRoom.elementAt(i);
if ( ( actual == source ) && ( execDes != null ) && ( self_included ) )
{
if ( actual instanceof Informador )
actual.writeWithTemplate ( style , personalizeDescription(execDes,actual,dollarEntities) );
}
else if ( actual == target && sufferDes != null )
{
if ( actual instanceof Informador )
actual.writeWithTemplate ( style , personalizeDescription(sufferDes,actual,dollarEntities) );
}
else if ( thirdPersonDes != null && actual != source && actual != target )
{
if ( actual instanceof Informador )
actual.writeWithTemplate ( style , personalizeDescription(thirdPersonDes,actual,dollarEntities) );
}
}
//hacer que los bichos reaccionen.
//nota: �por qu� lo hacemos en otro bucle y no en el mismo que lo anterior?
//porque nos interesa que la informaci�n salga primero y despu�s todos los bichos reaccionen.
//si lo meti�ramos todo a ca��n, podr�a haber bichos que reaccionaran antes de salir la informaci�n.
for ( int i = 0 ; i < mobsInRoom.size() ; i++ )
{
Mobile actual = mobsInRoom.elementAt(i);
if ( actual == source && execDes != null && self_included )
{
actual.reactToRoomText ( personalizeDescription(execDes,actual,dollarEntities) );
}
else if ( actual == target && sufferDes != null )
{
actual.reactToRoomText ( personalizeDescription(sufferDes,actual,dollarEntities) );
}
else if ( thirdPersonDes != null )
{
actual.reactToRoomText ( personalizeDescription(thirdPersonDes,actual,dollarEntities) );
}
}
//room text reaction evt
try
{
execCode ( "onRoomText" ,
new Object[]
{
personalizeDescription(thirdPersonDes,null,dollarEntities)
}
);
}
catch ( ScriptException te )
{
System.err.println(te);
mundo.writeError(ExceptionPrinter.getExceptionReport(te));
te.printStackTrace();
}
//does nothing with the BshCodeExecutedOKException: irrelevant here.
}
//the new inform action auto: automatically obtain suffer and exec descriptions, then call
//the new inform action.
/**
* @deprecated Use {@link #reportActionAuto(Entity,Entity,Entity[],String,boolean)} instead
*/
public void informActionAuto ( Entity source /*$1*/ , Entity target /*$2*/ , Entity[] objects /*$3..$n*/ , String thirdPersonDes , boolean self_included )
{
reportActionAuto(source, target, objects, thirdPersonDes, self_included);
}
/**
* The new reportActionAuto, without colour code parameter.
* @param source
* @param target
* @param objects
* @param thirdPersonDes
* @param self_included
*/
public void reportActionAuto ( Entity source /*$1*/ , Entity target /*$2*/ , Entity[] objects /*$3..$n*/ , String thirdPersonDes , boolean self_included )
{
reportActionAuto ( source , target , objects , thirdPersonDes , null , self_included );
}
//the new report action auto: automatically obtain suffer and exec descriptions, then call
//the new report action.
public void reportActionAuto ( Entity source /*$1*/ , Entity target /*$2*/ , Entity[] objects /*$3..$n*/ , String thirdPersonDes , String style , boolean self_included )
{
Debug.println("Autoinforming " + thirdPersonDes + " at roome " + getID() + ":" + getUniqueName());
//intentar obtener autom�ticamente execdes
StringTokenizer st = new StringTokenizer ( thirdPersonDes , " " , true );
String execDes = "";
while ( st.hasMoreTokens() )
{
String tok = st.nextToken();
if ( tok.equals("$1") )
{
if ( st.hasMoreTokens() )
{
//el separador
execDes += st.nextToken();
if ( st.hasMoreTokens() )
{
String posibleVerbo = st.nextToken();
String segundaPers = lenguaje.terceraASegunda ( posibleVerbo );
if ( segundaPers != null )
{
execDes += segundaPers;
}
else
{
execDes += posibleVerbo;
}
}
}
}
else
{
execDes += tok;
}
}
//trim left only
execDes = execDes+"a";
execDes = execDes.trim();
execDes = execDes.substring(0,execDes.length()-1);
//hacerlo con el sufferdes, de momento no hay.
String sufferDes = null;
Debug.println("Gonna deft'ly call informAction");
//llamar a informAction
reportAction ( source , target , objects , thirdPersonDes , sufferDes , execDes , style , self_included );
}
//old method's redirect
/**
* @deprecated Use {@link #reportAction(Mobile,Mobile,String,String,String,boolean)} instead
*/
public void informAction ( Mobile source , Mobile target , String thirdPersonDes , String sufferDes , String execDes , boolean self_included )
{
reportAction(source, target, thirdPersonDes, sufferDes, execDes,
self_included);
}
//old method's redirect
/**
* @deprecated Use {@link #reportAction(Entity,Entity,Entity[],String,String,String,boolean)} instead
*/
public void reportAction ( Mobile source , Mobile target , String thirdPersonDes , String sufferDes , String execDes , boolean self_included )
{
reportAction ( source , target , null , thirdPersonDes , sufferDes , execDes, self_included );
}
//old method's redirect
/**
* @deprecated Use {@link #reportActionAuto(Mobile,Mobile,String,boolean)} instead
*/
public void informActionAuto ( Mobile source , Mobile target , String thirdPersonDes , boolean self_included )
{
reportActionAuto(source, target, thirdPersonDes, self_included);
}
//old method's redirect
/**
* @deprecated Use {@link #reportActionAuto(Entity,Entity,Entity[],String,boolean)} instead
*/
public void reportActionAuto ( Mobile source , Mobile target , String thirdPersonDes , boolean self_included )
{
reportActionAuto ( source , target , null , thirdPersonDes , self_included );
}
/*informa de algo que ha sucedido a todos los jugadores / Informadores.*/
/*Novedad 03.03.26: puede haber descripciones null (no se escribe nada)*/
/*de hecho me parece que self_included equivale a hacer final_execDes != null*/
/*
public void informAction ( Mobile source , Mobile target , String thirdPersonDes , String sufferDes , String execDes , boolean self_included )
{
//notese que gramaticalizar puede manejar null
String final_thirdPersonDes = lenguaje.gramaticalizarSinTrimear ( personalizeDescription ( thirdPersonDes , source , target ) );
String final_sufferDes = lenguaje.gramaticalizarSinTrimear ( personalizeDescription ( sufferDes , source , target ) );
String final_execDes = lenguaje.gramaticalizarSinTrimear ( personalizeDescription ( execDes , source , target ) );
if ( mobsInRoom == null ) return;
for ( int i = 0 ; i < mobsInRoom.size() ; i++ )
{
if ( mobsInRoom.elementAt(i) instanceof Informador )
{
if ( source == mobsInRoom.elementAt(i) )
{
if ( self_included && final_execDes != null )
((Informador)mobsInRoom.elementAt(i)).escribir ( final_execDes );
}
else if ( target == mobsInRoom.elementAt(i) && final_sufferDes != null )
{
((Informador)mobsInRoom.elementAt(i)).escribir ( final_sufferDes );
}
else if ( final_thirdPersonDes != null )
{
((Informador)mobsInRoom.elementAt(i)).escribir ( final_thirdPersonDes );
}
}
}
for ( int i = 0 ; i < mobsInRoom.size() ; i++ )
{
if ( !(mobsInRoom.elementAt(i) instanceof Informador) )
{
if ( source == mobsInRoom.elementAt(i) )
{
if ( self_included )
(mobsInRoom.elementAt(i)).reactToRoomText ( final_execDes );
}
else if ( target == mobsInRoom.elementAt(i) )
{
(mobsInRoom.elementAt(i)).reactToRoomText ( final_sufferDes );
}
else
{
(mobsInRoom.elementAt(i)).reactToRoomText ( final_thirdPersonDes );
}
}
}
}
*/
/*description not nullifiable. (de momento)*/
/*
public void informActionAuto ( Mobile source , Mobile target , String thirdPersonDes , boolean self_included )
{
//descripci�n 3� pers: trivial.
String final_thirdPersonDes = lenguaje.gramaticalizarSinTrimear ( personalizeDescription ( thirdPersonDes , source , target ) );
Debug.println("Two times: " + final_thirdPersonDes + final_thirdPersonDes );
//obtener descripci�n 1� pers: cambiamos todas las apariciones de "$1 [verbo en 3�]" por [verbo en 2�]
//ej. "$1 dice" por "dices".
StringTokenizer st = new StringTokenizer ( thirdPersonDes , " " , true );
String final_execDes = "";
while ( st.hasMoreTokens() )
{
String tok = st.nextToken();
if ( tok.equals("$1") )
{
if ( st.hasMoreTokens() )
{
//el separador
final_execDes += st.nextToken();
if ( st.hasMoreTokens() )
{
String posibleVerbo = st.nextToken();
//Debug.println("Posible verbo: " + posibleVerbo );
String segundaPers = lenguaje.terceraASegunda ( posibleVerbo );
if ( segundaPers != null )
{
final_execDes += segundaPers;
}
else
{
final_execDes += posibleVerbo;
}
}
}
}
else
{
final_execDes += tok;
}
}
//hacemos el personalize para sustituir $2, que puede quedar por ahi.
Debug.println("Personalized: [" + personalizeDescription ( final_execDes , source , target ) + "]");
Debug.println("Gramaticized: [" + lenguaje.gramaticalizar ( personalizeDescription ( final_execDes , source , target ) ) + "]");
final_execDes = lenguaje.gramaticalizarSinTrimear ( personalizeDescription ( final_execDes , source , target ) );
//ya tenemos final_execDes. Queda final_sufferDes.
//informamos
if ( mobsInRoom == null ) return;
for ( int i = 0 ; i < mobsInRoom.size() ; i++ )
{
if ( mobsInRoom.elementAt(i) instanceof Informador )
{
if ( source == mobsInRoom.elementAt(i) )
{
if ( self_included )
((Informador)mobsInRoom.elementAt(i)).escribir ( final_execDes );
}
// else if ( target == mobsInRoom.elementAt(i) )
// {
// ((Informador)mobsInRoom.elementAt(i)).escribir ( final_sufferDes );
// } [de momento no tratamos descripci�n de acciones que sufre el jugador]
else
{
((Informador)mobsInRoom.elementAt(i)).escribir ( final_thirdPersonDes );
}
}
}
for ( int i = 0 ; i < mobsInRoom.size() ; i++ )
{
if ( ! ( mobsInRoom.elementAt(i) instanceof Informador ) )
{
if ( source == mobsInRoom.elementAt(i) )
{
if ( self_included )
(mobsInRoom.elementAt(i)).reactToRoomText ( final_execDes );
}
//else if ( target == mobsInRoom.elementAt(i) )
//{
// ((Informador)mobsInRoom.elementAt(i)).escribir ( final_sufferDes );
//} [de momento no tratamos descripci�n de acciones que sufre el jugador]
else
{
(mobsInRoom.elementAt(i)).reactToRoomText ( final_thirdPersonDes );
}
}
}
} //end method
*/
public void loadNumberGenerator ( World mundo )
{
aleat = mundo.getRandom();
}
public boolean hasItem ( Item it )
{
return itemsInRoom.contains(it);
}
public boolean hasMobile ( Mobile m )
{
return mobsInRoom.contains(m);
}
public Inventory getInventory ( )
{
if ( itemsInRoom == null )
itemsInRoom = new Inventory(10000,10000);
return itemsInRoom;
}
public Inventory getContents()
{
return getInventory();
}
public MobileList getMobiles ( )
{
if ( mobsInRoom == null )
mobsInRoom = new MobileList();
return mobsInRoom;
}
public org.w3c.dom.Node getXMLRepresentation ( org.w3c.dom.Document doc )
{
org.w3c.dom.Element suElemento = doc.createElement( "Room" );
suElemento.setAttribute ( "id" , String.valueOf( idnumber ) );
suElemento.setAttribute ( "name" , String.valueOf ( title ) );
suElemento.setAttribute ( "extends" , String.valueOf ( inheritsFrom ) );
suElemento.appendChild ( getPropListXMLRepresentation(doc) );
suElemento.appendChild ( getRelationshipListXMLRepresentation(doc) );
org.w3c.dom.Element listaDesc = doc.createElement("DescriptionList");
//Debug.println("Room id " + idnumber);
for ( int i = 0 ; i < descriptionList.length ; i++ )
{
Description nuestraDescripcion = descriptionList[i];
listaDesc.appendChild ( nuestraDescripcion.getXMLRepresentation(doc) );
}
suElemento.appendChild(listaDesc);
org.w3c.dom.Element listaSal = doc.createElement("PathList");
if ( standardExits != null )
{
for ( int i = 0 ; i < standardExits.length ; i++ )
{
if ( standardExits[i] != null && standardExits[i].getDestinationID() != 0 /*zeroes are non-valid exits*/ )
listaSal.appendChild ( standardExits[i].getXMLRepresentation(doc , Path.directionName(i)) );
}
}
if ( otherExits != null )
{
for ( int i = 0 ; i < otherExits.length ; i++ )
{
if ( otherExits[i] != null )
{
if ( !otherExits[i].isExtended() ) //extended exits are put in standard list
listaSal.appendChild ( otherExits[i].getXMLRepresentation(doc) );
}
}
}
suElemento.appendChild(listaSal);
//inventario
if ( itemsInRoom != null )
suElemento.appendChild(itemsInRoom.getXMLRepresentation(doc));
//mobile list
if ( mobsInRoom != null )
{
//Debug.println("Mobile List Saving: " + mobsInRoom);
suElemento.appendChild(mobsInRoom.getXMLRepresentation(doc));
//Debug.println("Node is: " + mobsInRoom.getXMLRepresentation(doc));
}
//extra descriptions (temp XML representation) -> obsolete. Change.
if ( extraDescriptions != null )
{
org.w3c.dom.Element extraDes = doc.createElement("ExtraDescriptionList");
StringTokenizer st1 = new StringTokenizer ( extraDescriptions, "@" );
while ( st1.hasMoreTokens() )
{
String desActual = st1.nextToken();
org.w3c.dom.Element unaDescripcion = doc.createElement("ExtraDescription");
StringTokenizer st2 = new StringTokenizer ( desActual , "$" );
while ( st2.hasMoreTokens() )
{
String wordActual = st2.nextToken();
if ( st2.hasMoreTokens() )
{
org.w3c.dom.Element comando = doc.createElement("Name");
org.w3c.dom.Text contenido = doc.createTextNode(wordActual);
comando.appendChild(contenido);
unaDescripcion.appendChild(comando);
}
else
{
org.w3c.dom.Text texto = doc.createTextNode(wordActual);
unaDescripcion.appendChild(texto);
}
}
extraDes.appendChild ( unaDescripcion );
}
//org.w3c.dom.Text extraDesContent = doc.createTextNode(extraDescriptions);
//extraDes.appendChild(extraDesContent);
suElemento.appendChild(extraDes);
}
//new extra description support
if ( extraDescriptionNameArrays != null && extraDescriptionArrays != null )
{
suElemento.appendChild(Utility.getExtraDescriptionXMLRepresentation(extraDescriptionNameArrays, extraDescriptionArrays, doc));
}
//only restrictions: not at the moment
//object code
if ( itsCode != null )
suElemento.appendChild(itsCode.getXMLRepresentation(doc));
return suElemento;
}
//devuelve un Inventory formado por el contenido, el contenido del contenido, etc. etc.
public Inventory getFlattenedInventory()
{
if ( itemsInRoom == null ) return new Inventory(1,1);
Inventory result = new Inventory(itemsInRoom.getWeightLimit(),itemsInRoom.getVolumeLimit());
for ( int i = 0 ; i < itemsInRoom.size() ; i++ )
{
Item thisPart = itemsInRoom.elementAt(i);
Inventory subInv = thisPart.getFlattenedInventory();
//add part's flattened parts inventory
try
{
result.setVolumeLimit ( result.getVolumeLimit() + subInv.getVolumeLimit() );
result.setWeightLimit ( result.getWeightLimit() + subInv.getWeightLimit() );
}
catch ( Exception e )
{
Debug.println("Impossible exception thrown: " + e);
e.printStackTrace();
}
for ( int j = 0 ; j < subInv.size() ; j++ )
{
try
{
result.addItem ( subInv.elementAt(j) );
}
catch ( Exception e )
{
Debug.println("Impossible exception thrown: " + e);
e.printStackTrace();
}
}
//add this part
try
{
result.addItem ( thisPart );
}
catch ( Exception e )
{
Debug.println("Impossible exception thrown: " + e);
e.printStackTrace();
}
}
return result;
}
//for clone()'s and similars!
//notaci�n un poco inconsistente con la de Entity::copyEntityFields; pero bueno
public void copyRoomFieldsTo ( Room r )
{
r.copyEntityFields(this); //estados, propiedades, etc.
//Debug.println("Random from SOURCE item: " + getRandom());
r.mundo = mundo;
r.aleat = getRandom();
r.extraDescriptions = extraDescriptions;
r.idnumber = idnumber; //will have to change the ID later!
//it.inheritsFrom = 0; //creates an identical (strong inherit) item -> No weak inherit
//nay, identical copy
r.inheritsFrom = inheritsFrom;
if ( itemsInRoom != null )
r.itemsInRoom = (Inventory) itemsInRoom.clone();
else r.itemsInRoom = null;
//it.isInstanceOf = idnumber; //creates an identical (strong inherit) item
//nay, identical copy
//r.isInstanceOf = isInstanceOf;
if ( itsCode != null )
r.itsCode = itsCode.cloneIfNecessary();
r.title = title;
r.descriptionList = new Description[descriptionList.length];
for ( int i = 0 ; i < r.descriptionList.length ; i++ )
{
r.descriptionList[i] = (Description) descriptionList[i].clone();
}
//mob refs and only restrictions are obsolete, do not copy
r.lenguaje = lenguaje;
if ( mobsInRoom != null )
r.mobsInRoom = (MobileList) mobsInRoom.clone();
else r.mobsInRoom = null;
r.standardExits = new Path[ this.standardExits.length ];
for ( int i = 0 ; i < this.standardExits.length ; i++ )
{
if ( this.standardExits[i] != null )
r.standardExits[i] = (Path) this.standardExits[i].clone();
else
r.standardExits[i] = null;
}
r.otherExits = new Path[ this.otherExits.length ];
for ( int i = 0 ; i < this.otherExits.length ; i++ )
{
if ( this.otherExits[i] != null )
r.otherExits[i] = (Path) this.otherExits[i].clone();
else
r.otherExits[i] = null;
}
//shallow!
r.extraDescriptionArrays = extraDescriptionArrays;
r.extraDescriptionNameArrays = extraDescriptionNameArrays;
}
public java.util.Random getRandom()
{
return aleat;
}
public Room createNewInstance ( World mundo , boolean cloneContents )
{
return createNewInstance ( mundo , cloneContents , null );
}
public Room createNewInstance( World mundo , boolean cloneContents , String uniqueName )
{
Room r = (Room) this.clone();
r.inheritsFrom = idnumber;
if ( uniqueName == null ) r.title = mundo.generateUnusedUniqueName(this.getUniqueName());
else r.title = uniqueName;
mundo.addRoomAssigningID(r);
return r;
}
public Object clone( )
{
//do it!
Room r = new Room();
copyRoomFieldsTo(r);
return r;
}
//for clones
public Room ()
{
;
}
public ObjectCode getAssociatedCode()
{
return itsCode;
}
/**
* Builds a list with all the extra description names and returns it.
* Careful, each call to this method builds the list!
* @return
*/
public List getExtraDescriptionNames()
{
List result = new ArrayList();
for ( int i = 0 ; i < extraDescriptionNameArrays.size() ; i++ )
{
String[] ar = (String[]) extraDescriptionNameArrays.get(i);
for ( int j = 0 ; j < ar.length ; j++ )
{
result.add(ar[j]);
}
}
return result;
}
/**
* Returns true if this room (directly) contains the specified item.
* @param it
* @return
*/
public boolean contains ( Item it )
{
return getContents().contains(it);
}
/**
* Returns true if this room (directly) contains the specified mobile.
* @param it
* @return
*/
public boolean contains ( Mobile m )
{
return getMobiles().contains(m);
}
}