/*
....[@@@..[@@@..............[@.................. MUD++ is a written from
....[@..[@..[@..[@..[@..[@@@@@....[@......[@.... scratch multi-user swords and
....[@..[@..[@..[@..[@..[@..[@..[@@@@@..[@@@@@.. sorcery game written in C++.
....[@......[@..[@..[@..[@..[@....[@......[@.... This server is an ongoing
....[@......[@..[@@@@@..[@@@@@.................. development project. All
................................................ contributions are welcome.
....Copyright(C).1995.Melvin.Smith.............. Enjoy.
------------------------------------------------------------------------------
Melvin Smith (aka Fusion) msmith@hom.net
MUD++ development mailing list mudpp@van.ml.org
------------------------------------------------------------------------------
editroom.cc
*/
#include "config.h"
#include "string.h"
#include "llist.h"
#include "index.h"
#include "room.h"
#include "repop.h"
#include "hash.h"
#include "server.h"
#include "bit.h"
#include "edit.h"
#include "area.h"
#include "pc.h"
#include "object.h"
#include "global.h"
#include "trigs.h"
void RoomEditor::command( const String & arg )
{
String str;
String str2;
String arg1;
String arg2;
String arg3;
Area * pArea;
Exit *pExit;
struct TriggerData * td;
int val1;
int i;
// If in text editor, pass args on to text editor
if( text )
{
// If text editor is finished, do something with its content
// or cancel.
text->command( arg );
if( text->done() )
{
if( text->getState() == ED_CANCEL )
{
delete text;
text = 0;
state = ED_NONE;
return;
}
switch( state )
{
case ED_DESC: room->setDesc( text->asStr() );
room->getArea()->setDirtyBit();
delete text;
text = 0;
state = ED_NONE;
return;
default: delete text;
text = 0;
state = ED_NONE;
return;
}
}
return;
}
else if( (bool)filename )
{
char buf[ 8092 ];
InputFile inf( filename );
if( !inf )
{
pc->out( "System error. Can't read temp file.\n\r" );
filename.clr();
return;
}
inf.getstring( buf );
switch ( state )
{
case ED_DESC:
room->setDesc( buf );
room->getArea()->setDirtyBit();
state = ED_NONE;
break;
default:
state = ED_NONE;
break;
}
inf.close();
remove( filename.chars() );
filename.clr();
return;
}
if( !(bool)arg || arg == "\n" )
{
room->describeItself(str);
pc->out( str );
}
else
{
Index index1;
Index index2;
int dir;
int revdir;
Room *pRoom;
arg.startArgs();
arg1 = arg.getArg();
arg2 = arg.getArgRest();
area = room->getArea();
if( arg1 == "name" )
{
room->setName( arg2 );
pc->out( "Name set to '" );
pc->out( arg2 );
pc->out( "'\n\r" );
area->setDirtyBit();
return;
}
else if( arg1 == "desc" )
{
if( arg2[0] == '+' )
{
arg2.shiftLeft();
str << room->getDesc() << "\n\r" << arg2;
room->setDesc( str );
}
else if ( arg2 )
{
str << arg2 << "\n\r";
room->setDesc(str);
}
else
{
editText( room->getDesc() );
//state = ED_DESC;
return;
}
area->setDirtyBit();
return;
}
else if( arg1 == "index" )
{
area->removeRoom( room );
room->setKey( arg2 );
area->addRoom( room );
area->setDirtyBit();
return;
}
else if( arg1 == "bitmask" )
{
if( !(bool)arg2 )
{
pc->out( "Set which bit in bitmask?\n\r" );
return;
}
if( ( val1 = lookupRoomBit( arg2 ) ) )
{
SET_BIT( room_bits, val1 );
pc->out( "Bit toggled in default bitmask.\n\r" );
return;
}
}
else if( arg1 == "copy" )
{
if( !(bool)arg2 )
{
pc->out( "Copy which room?\n\r" );
return;
}
if( !( pRoom = lookupRoom( arg2 ) ) )
{
pc->out( "No such room to copy.\n\r" );
return;
}
room->setName( pRoom->getName() );
room->setDesc( pRoom->getDesc() );
area->setDirtyBit();
return;
}
else if( arg1 == "new" || arg1 == "create" )
{
if( !(bool)arg2 )
{
pc->out( "Usage: new <index>\n\r" );
return;
}
index = arg2.getArgRest();
if( (bool)index.getScope() )
{
if( !( pArea = lookupArea( index.getScope() ) ) )
{
pc->out( "No such area.\n\r" );
return;
}
}
else pArea = area;
if( !( pRoom = pArea->lookupRoom( index.getKey() ) ) )
{
pRoom = new Room( pArea );
pRoom->setName( "No name" );
pRoom->setDesc( "No description" );
pRoom->setKey( index.getKey() );
// Editor is a friend class of Room
memcpy( pRoom->room_bits, room_bits,
sizeof( room_bits[0] ) * MAX_ROOM_BIT_FIELDS );
pArea->addRoom( pRoom );
pc->out( "New room created.\n\r" );
pArea->setDirtyBit();
room->rmCharInv( pc );
pRoom->addCharInv( pc );
room = pRoom;
area = pArea;
}
else pc->out( "That room already exists.\n\r" );
return;
}
else if( arg1 == "save" )
{
area->save();
area->rmDirtyBit();
pc->out( "Zone saved.\n\r" );
return;
}
else if( arg1 == "goto" )
{
pc->do_goto( arg2 );
setRoom( pc->inRoom() );
return;
}
else if( arg1 == "repop" )
{
if( !(bool)arg2 || arg2 == "help" )
{
pc->out( "repop mob <npc-index> {chance}\n\r" );
pc->out( "repop <#> give <obj-index> {chance}\n\r" );
pc->out( "repop <#> eq <obj-index> {chance}\n\r" );
pc->out( "repop obj <obj-index> {chance}\n\r" );
pc->out( "repop <#> put <obj-index> {chance}\n\r" );
pc->out( "repop <#> nest <obj-index> {chance}\n\r" );
return;
}
else
if( arg2 == "list" || arg2 == "show" )
{
pc->do_repops( "list" );
return;
}
else
{
parseRepop( arg2 );
return;
}
}
else if( arg1 == "list" )
{
/*
Room * pRoom;
for_each( area->roomIndex, pRoom )
str.sprintfAdd( "%15s - %s\n\r", pRoom->getKey().chars(),
pRoom->getName().chars() );
pc->out( str );
*/
pc->do_rfind(arg2);
return;
}
else if( arg1 == "help" || arg1 == "?" )
{
pc->view( "../help/redit.hlp" );
pc->page( "" );
return;
}
else if( arg1 == "room-bits" )
{
pc->view( "../help/room-bits.hlp" );
pc->page( "" );
return;
}
else if ( arg1 == "trigadd" )
{
void * fun;
arg2.startArgs();
arg1 = arg2.getArg();
str2 = arg2.getArg();
val1 = lookupBit( rtrig_types, arg1 );
if ( val1 == 0 )
{
pc->out("No such bit.\n\r");
return;
}
fun = lookupRtrig( val1, str2.chars() );
if ( fun == NULL )
{
pc->out("No such function for that type of trigger.\n\r");
return;
}
for_each(room->triggers, td )
{
if ( td->type == val1 )
break;
}
if ( td != NULL )
{
pc->out("Replacing old trigger.\n\r");
room->removeTrigger(td);
}
td = new (struct TriggerData);
td->type = val1;
td->fun = fun;
room->addTrigger(td);
pc->out("Trigger added.\n\r");
return;
}
else if ( arg1 == "trigdel" )
{
val1 = lookupBit( rtrig_types, arg2 );
if ( val1 == 0 )
{
pc->out("No such bit.\n\r");
return;
}
for_each(room->triggers, td )
{
if ( td->type == val1 )
break;
}
if ( td == NULL )
{
pc->out("This room has no such trigger.\n\r");
return;
}
room->removeTrigger(td);
pc->out("Trigger removed.\n\r");
return;
}
else if ( arg1 == "triglist" )
{
if ( !(bool)arg2 )
{
// list types of triggers
str << "Trigger types for Rooms " <<endl;
for ( i=1; rtrig_types[i].name; i++ )
{
str << rtrig_types[i].name << endl;
}
pc->out(str);
return;
}
else
{
// list triggers for given type
const char * name;
val1 = lookupBit( rtrig_types, arg2 );
if ( val1 == 0 )
{
pc->out("No such bit.\n\r");
return;
}
str << "Triggers for type " << arg2 << ":" << endl;
for ( i = 0; ; i++ )
{
name = getRtrigName(val1, i);
if ( !name )
break;
str << name << endl;
}
pc->out(str);
return;
}
}
if( ( dir = getDir( (const char *)arg1 ) ) != DIR_UNDEFINED )
{
revdir = getRevDir( dir );
if( !(bool)arg2 )
{
if( !( pRoom = room->toRoom( dir ) ) )
{
pc->out( "No exit in that direction.\n\r" );
return;
}
pc->out( "Moving to room " );
pc->out( pRoom->getKey() );
pc->out( ".\n\r" );
room->rmCharInv( pc );
pRoom->addCharInv( pc );
room = pRoom;
area = pRoom->getArea();
return;
}
else
{
// Break into 3rd arg
arg2.startArgs();
arg3 = arg2.getArg();
if( arg3 == "dig" || arg3 == "room" )
{
if( ( pRoom = room->toRoom( dir ) ) )
{
pc->out( "Already an exit in that direction.\n\r" );
return;
}
if( !(bool)arg2.getArgRest() )
{
pc->out( "No room specified.\n\r" );
return;
}
index = arg2.getArgRest();
if( (bool)index.getScope()
&& !( pArea = lookupArea( index.getScope() ) ) )
{
pc->out( "No such area.\n\r" );
return;
}
else pArea = area;
index.setScope( pArea->getKey() );
if( !( pRoom = pArea->lookupRoom( index.getKey() ) ) )
{
pRoom = new Room( area );
pRoom->setName( "No name" );
pRoom->setDesc( "No description" );
pRoom->setKey( index.getKey() );
// RoomEditor is a friend class of Room
memcpy( pRoom->room_bits, room_bits,
sizeof( room_bits[0] ) * MAX_ROOM_BIT_FIELDS );
pArea->addRoom( pRoom );
pc->out( "New room created.\n\r" );
}
else if( arg3 == "room" )
{
pc->out( "Can't create, that room already exists.\n\r" );
return;
}
else if( pRoom->toRoom( revdir ) )
{
pc->out( "Exit exists on other side.\n\r" );
return;
}
// Convert what was 'e' to 'east' for constructor
//arg1 = lookupDirName( dir );
pExit = new Exit( "", index, "", 0, "" );
room->addExit( pExit, dir );
room->hardLink();
// Link reverse side
index.setScope( room->getArea()->getKey() );
index.setKey( room->getKey() );
pExit = new Exit( "", index, "", 0, "" );
pRoom->addExit( pExit, revdir );
pRoom->hardLink();
pc->out( "Exit linked.\n\r" );
area->setDirtyBit();
if( arg3 == "dig" )
{
room->rmCharInv( pc );
pRoom->addCharInv( pc );
room = pRoom;
area = pArea;
}
return;
}
if( arg3 == "link" || arg3 == "to" )
{
if( ( pRoom = room->toRoom( dir ) ) )
{
pc->out( "Already an exit in that direction.\n\r" );
return;
}
if( !(bool)arg2.getArgRest() )
{
pc->out( "No room specified.\n\r" );
return;
}
index = arg2.getArgRest();
if( (bool)index.getScope() )
{
if( !( pArea = lookupArea( index.getScope() ) ) )
{
pc->out( "No such area.\n\r" );
return;
}
}
else pArea = area;
index.setScope( pArea->getKey() );
if( !( pRoom = pArea->lookupRoom( index.getKey() ) ) )
{
pc->out( "No such room.\n\r" );
return;
}
if( pRoom->toRoom( revdir ) )
{
pc->out( "Exit exists on other side.\n\r" );
return;
}
pExit = new Exit( "", index, "", 0, "" );
room->addExit( pExit, dir );
room->hardLink();
// Link reverse side
index.setScope( room->getArea()->getKey() );
index.setKey( room->getKey() );
pExit = new Exit( "", index, "", 0, "" );
pRoom->addExit( pExit, revdir );
pRoom->hardLink();
pc->out( "Exit linked.\n\r" );
area->setDirtyBit();
return;
}
else if( arg3 == "delete" )
{
if( !room->getExit( dir ) )
{
pc->out( "No exit in that direction.\n\r" );
return;
}
room->toRoom( dir )->deleteExit( revdir );
room->deleteExit( dir );
pc->out( "Exit deleted.\n\r" );
area->setDirtyBit();
return;
}
else if( arg3 == "name" )
{
if( !room->getExit( dir ) )
{
pc->out( "No exit in that direction.\n\r" );
return;
}
room->getExit( dir )->setName( arg2.getArgRest() );
area->setDirtyBit();
pc->out( "Exit name set.\n\r" );
return;
}
else if( arg3 == "desc" || arg3 == "description" )
{
if( !room->getExit( dir ) )
{
pc->out( "No exit in that direction.\n\r" );
return;
}
room->getExit( dir )->setDesc( arg2.getArgRest() );
area->setDirtyBit();
pc->out( "Exit description set.\n\r" );
return;
}
if( ( val1 = lookupExitBit( arg3 ) ) )
{
if( !room->getExit( dir ) )
{
pc->out( "No exit in that direction.\n\r" );
return;
}
room->getExit( dir )->toggleExitBit( val1 );
area->setDirtyBit();
pc->out( "Exit bit toggled.\n\r" );
return;
}
}
}
if( ( val1 = lookupSector( arg1 ) ) )
{
room->setSector( val1 );
pc->out( "Sector type set.\n\r" );
area->setDirtyBit();
return;
}
if( ( val1 = lookupRoomBit( arg1 ) ) )
{
room->toggleRoomBit( val1 );
pc->out( "Room bit toggled.\n\r" );
area->setDirtyBit();
return;
}
pc->out( "Invalid command.\n\r" );
}
}
void RoomEditor::parseRepop( const String & arg )
{
String str;
String arg1;
String arg2;
String arg3;
int chance = 100;
int slot = 0;
Repop * ptrRepop;
arg.startArgs();
arg1 = arg.getArg();
arg2 = arg.getArg();
arg3 = arg.getArg();
if( arg1.isNumber() )
{
if( ( slot = arg1.asInt() ) <= 0 )
{
pc->out( "Repop slot must be a positive non-zero number.\n\r" );
return;
}
arg1 = arg2;
arg2 = arg3;
arg3 = arg.getArg();
if( !(bool)arg1 )
{
str << "Current repop slot set to " << slot << ".\n\r";
pc->out( str );
last_slot = slot;
return;
}
}
else slot = last_slot + 1;
if( arg1 == "del" || arg1 == "delete" || arg1 == "remove" )
{
if( !( ptrRepop = room->rmRepop( slot ) ) )
{
pc->out( "Invalid repop slot number.\n\r" );
return;
}
pc->out( "Deleting repop.\n\r" );
if( ptrRepop->getPtr() )
ptrRepop->getPtr()->setRepop( 0 );
ptrRepop->fordelete();
last_slot = slot - 1;
return;
}
if( arg1 == "mob" || arg1 == "mobile" || arg1 == "npc" )
{
if( !(bool)arg2 )
{
pc->out( "Repop which npc?\n\r" );
return;
}
if( (bool)arg3 )
chance = arg3.asInt();
ptrRepop = new Repop( 'M', arg2, chance );
room->addRepop( slot, ptrRepop );
area->setDirtyBit();
str << "Added NPC repop at slot " << slot << ".\n\r";
if( !lookupNPC( arg2 ) )
str << "WARNING: NPC prototype '" << arg2 << "' not in database.\n\r";
pc->out( str );
last_slot = slot;
return;
}
else if( arg1 == "give" )
{
if( !(bool)arg2 )
{
pc->out( "Give which object?\n\r" );
return;
}
if( (bool)arg3 )
chance = arg3.asInt();
ptrRepop = new Repop( 'G', arg2, chance );
room->addRepop( slot, ptrRepop );
area->setDirtyBit();
str << "Added 'give item to NPC' repop at slot " << slot << ".\n\r";
if( !lookupObj( arg2 ) )
str << "WARNING: Obj prototype '" << arg2 << "' not in database.\n\r";
pc->out( str );
last_slot = slot;
return;
}
else if( arg1 == "eq" || arg1 == "equip" )
{
if( !(bool)arg2 )
{
pc->out( "Equip which object?\n\r" );
return;
}
if( (bool)arg3 )
chance = arg3.asInt();
ptrRepop = new Repop( 'E', arg2, chance );
room->addRepop( slot, ptrRepop );
area->setDirtyBit();
str << "Added 'equip NPC with item' repop at slot " << slot << ".\n\r";
if( !lookupObj( arg2 ) )
str << "WARNING: Obj prototype '" << arg2 << "' not in database.\n\r";
pc->out( str );
last_slot = slot;
return;
}
else if( arg1 == "obj" || arg1 == "object" )
{
if( arg2.isNumber() )
{
slot = arg2.asInt();
arg2 = arg3;
arg3 = arg.getArg();
}
if( !(bool)arg2 )
{
pc->out( "Repop which object?\n\r" );
return;
}
if( (bool)arg3 )
chance = arg3.asInt();
ptrRepop = new Repop( 'O', arg2, chance );
room->addRepop( slot, ptrRepop );
area->setDirtyBit();
str << "Added Object repop at slot " << slot << ".\n\r";
if( !lookupObj( arg2 ) )
str << "WARNING: Obj prototype '" << arg2 << "' not in database.\n\r";
pc->out( str );
last_slot = slot;
return;
}
else if( arg1 == "put" )
{
if( !(bool)arg2 )
{
pc->out( "Put which object?\n\r" );
return;
}
if( (bool) arg3 )
chance = arg3.asInt();
ptrRepop = new Repop( 'P', arg2, chance );
room->addRepop( slot, ptrRepop );
area->setDirtyBit();
str << "Added 'put object in object' repop at slot " << slot << ".\n\r";
if( !lookupObj( arg2 ) )
str << "WARNING: Obj prototype '" << arg2 << "' not in database.\n\r";
pc->out( "str" );
last_slot = slot;
return;
}
else if( arg1 == "nest" )
{
if( !(bool)arg2 )
{
pc->out( "Nest which object?\n\r" );
return;
}
if( (bool) arg3 )
chance = arg3.asInt();
ptrRepop = new Repop( 'N', arg2, chance );
room->addRepop( slot, ptrRepop );
area->setDirtyBit();
str << "Added 'nest object in object' repop at slot " << slot << ".\n\r";
if( !lookupObj( arg2 ) )
str << "WARNING: Obj prototype '" << arg2 << "' not in database.\n\r";
pc->out( "str" );
last_slot = slot;
return;
}
pc->out( "Error parsing repop.\n\r" );
pc->out( "Type 'repop help' for syntax info.\n\r" );
}