/*
....[@@@..[@@@..............[@.................. 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@falcon.mercer.peachnet.edu
MUD++ development mailing list mudpp-list@spice.com
------------------------------------------------------------------------------
pc.cc
*/
#include "string.h"
#include "llist.h"
#include "indexable.h"
#include "server.h"
#include "room.h"
#include "bit.h"
#include "affect.h"
#include "screen.h"
#include "npc.h"
#include "pc.h"
#include "global.h"
void Nanny( PC *, String & str="" );
const bitType priv_bit_list[] =
{
{"undefined", NULLBIT },
{"superuser", SUPERUSER },
{"director", DIRECTOR },
{"admin", ADMIN },
{"operator", OPERATOR },
{"masterbuilder", MASTERBUILDER },
{"builder", BUILDER },
{"quester", QUESTER },
{"wizard", WIZARD }
};
const command_type PC::cmdlist[27][32] =
{
// A
{
{"areas", do_areas },
{0, 0 }
},
// B
{
{0, 0 }
},
// C
{
{"cast", do_cast },
{"chat", do_chat },
{"clear", do_clear },
{"close", do_close },
{"commands", do_commands },
{0, 0 }
},
// D
{
{"down", do_down },
{"drop", do_drop },
{0, 0 }
},
// E
{
{"east", do_east },
{"equipment", do_equipment },
{"exits", do_exits },
{0, 0 }
},
// F
{
{0, 0 }
},
// G
{
{"get", do_get },
{0, 0 }
},
// H
{
{"help", do_help },
{"hide", do_hide },
{0, 0 }
},
// I
{
{"inventory", do_inventory },
{0, 0 }
},
// J
{
{0, 0 }
},
// K
{
{"kill", do_kill },
{0, 0 }
},
// L
{
{"look", do_look },
{"list", do_list },
{"levels", do_levels },
{0, 0 }
},
// M
{
//{"mail", do_mail },
{0, 0 }
},
// N
{
{"north", do_north },
{0, 0 }
},
// O
{
{"open", do_open },
{0, 0 }
},
// P
{
{"password", do_password },
{"put", do_put },
{"practice", do_practice },
{"prompt", do_prompt },
{0, 0 }
},
// Q
{
{"quaff", do_quaff },
{"quit", do_quit },
{0, 0 }
},
// R
{
{"remove", do_remove },
{0, 0 }
},
// S
{
{"south", do_south },
{"say", do_say },
{"save", do_save },
{"score", do_score },
{"sneak", do_sneak },
{"study", do_study },
{0, 0 }
},
// T
{
{"tell", do_tell },
{"time", do_time },
{0, 0 }
},
// U
{
{"up", do_up },
{0, 0 }
},
// V
{
{0, 0 }
},
// W
{
{"west", do_west },
{"wear", do_wear },
{"weather", do_weather },
{"who", do_who },
{"wield", do_wield },
{0, 0 }
},
// X
{
{0, 0 }
},
// Y
{
{0, 0 }
},
// Z
{
{0, 0 }
},
// Other
{
{".", do_chat },
{":", do_immtalk },
{0, 0 }
}
};
const immcmd_type PC::immcmdlist[27][10] =
{
// A
{
{"advance", do_advance, 1, DIRECTOR },
{"aedit", do_aedit, 1, MASTERBUILDER },
{0, 0, 0, NULLBIT }
},
// B
{
{0, 0, 0, NULLBIT }
},
// C
{
{"cat", do_cat, 1, SUPERUSER },
{"cset", do_cset, 1, ADMIN },
{0, 0, 0, NULLBIT }
},
// D
{
{"debug", do_debug, 1, SUPERUSER },
//{"dbsave", do_dbsave, 1, MASTERBUILDER },
{0, 0, 0, NULLBIT }
},
// E
{
{"echo", do_echo, 1, WIZARD },
{0, 0, 0, NULLBIT }
},
// F
{
{0, 0, 0, NULLBIT }
},
// G
{
{"grant", do_grant, 1, SUPERUSER },
{"goto", do_goto, 1, WIZARD },
{0, 0, 0, NULLBIT }
},
// H
{
{0, 0, 0, NULLBIT }
},
// I
{
{"immtalk", do_immtalk, 1, WIZARD },
{"invis", do_invis, 1, WIZARD },
{"ident", do_ident, 1, ADMIN },
{0, 0, 0, NULLBIT }
},
// J
{
{0, 0, 0, NULLBIT }
},
// K
{
{0, 0, 0, NULLBIT }
},
// L
{
{0, 0, 0, NULLBIT }
},
// M
{
{"mfind", do_mfind, 1, BUILDER },
//{"medit", do_medit, 1, BUILDER },
{"mload", do_mload, 1, OPERATOR },
//{"mstat", do_mstat, 1, OPERATOR },
{0, 0, 0, NULLBIT }
},
// N
{
{0, 0, 0, NULLBIT }
},
// O
{
{"ofind", do_ofind, 1, BUILDER },
{"oedit", do_oedit, 1, BUILDER },
{"oload", do_oload, 1, OPERATOR },
{"owhere", do_owhere, 1, OPERATOR },
//{"ostat", do_ostat, 1, OPERATOR },
{0, 0, 0, NULLBIT }
},
// P
{
{"page", do_page, 1, WIZARD },
{"purge", do_purge, 1, BUILDER },
{0, 0, 0, NULLBIT }
},
// Q
{
{0, 0, 0, NULLBIT }
},
// R
{
{"reboot", do_reboot, 1, DIRECTOR },
{"revoke", do_revoke, 1, SUPERUSER },
{"rfind", do_rfind, 1, BUILDER },
{"repops", do_repops, 1, BUILDER },
{"redit", do_redit, 1, BUILDER },
{0, 0, 0, NULLBIT }
},
// S
{
{"shutdown", do_shutdown, 1, DIRECTOR },
{"slay", do_slay, 1, ADMIN },
{0, 0, 0, NULLBIT }
},
// T
{
{"transfer", do_transfer, 1, ADMIN },
{0, 0, 0, NULLBIT }
},
// U
{
{"users", do_users, 1, OPERATOR },
{0, 0, 0, NULLBIT }
},
// V
{
{0, 0, 0, NULLBIT }
},
// W
{
{"wizhelp", do_wizhelp, 1, WIZARD },
{0, 0, 0, NULLBIT }
},
// X
{
{0, 0, 0, NULLBIT }
},
// Y
{
{0, 0, 0, NULLBIT }
},
// Z
{
{0, 0, 0, NULLBIT }
},
// Other
{
{0, 0, 0, NULLBIT }
}
};
PC::PC( Server *serv, Socket *s, char * )
: Char(),server(serv), socket(s),
state(STATE_INIT),task(0),prompt(new char('\0')),
incommd(256),args(256),
inptr(inbuf),intop(inbuf),inceiling(inbuf+MAX_INBUF_SIZE-1),
outbuf(0),outptr(0),outsize(0),
pagebuf(0),pageptr(0),plr_flags(0),editor(0),
messages(0), exp(0),
energy(100), security(0)
{
classnow=0;
max_hp=max_mana=hp=mana=12;
memset( levels, 0, sizeof( levels[0] )*MAX_CLASS );
memset( learned, 0, sizeof( learned[0] )*MAX_SKILL );
strength=intel=wis=con=dex=13;
speed=0;
state_last=state=STATE_INIT;
*inbuf = '\0';
}
PC::~PC()
{
if( socket ) delete socket;
if( prompt ) delete [] prompt;
if( outbuf ) delete [] outbuf;
if( pagebuf ) delete [] pagebuf;
}
void PC::fromWorld()
{
pcs.remove( this );
}
void PC::toWorld()
{
pcs.add( this );
}
int PC::getState() const
{
return state;
}
void PC::setState( int s )
{
state_last = state;
state = s;
}
int PC::lastState() const
{
return state_last;
}
bool PC::isPlaying() const
{
if( editor || text )
return false;
else if( state == STATE_PLAYING )
return true;
return false;
}
void PC::setWindow( int t, int b )
{
char buf[ 256 ];
sprintf( buf, WINDOW( t, b ) );
out( buf );
}
void PC::out( const char *str )
{
char *newbuf;
int addsize = strlen( str );
if( count_lines( str ) > 23 )
{
// Put it on the pager
// Clobber the pagebuf if it exists - how it could I dont know
if( pagebuf )
delete [] pagebuf;
pagebuf = new char[ addsize+1 ];
strcpy( pagebuf, str );
pageptr = pagelast = pagebuf;
return;
}
else
{
// OK - just concatenate this chunk onto the outbuf which
// will get serviced every pulse.
int totsize = addsize + (outbuf ? strlen( outbuf ) : 0 ) +2;
// See if it exceeds outbuf size, if so reallocate,
// else strcat and return
if( outbuf && totsize < outsize )
{
strcat( outbuf, str );
return;
}
// Start with size 2048 and double until big enough
if( !outsize )
outsize = 2048;
while( outsize <= totsize )
outsize = outsize << 1;
newbuf = new char[ outsize ];
if( !newbuf )
{
error( "Can't allocate dynamic memory!" );
}
*newbuf = '\0';
// Get the old outbuf then free it and replace
if( outbuf )
{
strcpy( newbuf, outbuf );
delete [] outbuf;
}
strcat( newbuf, str );
outbuf = newbuf;
}
}
void PC::putPrompt()
{
char buf[BUF];
char *token = prompt;
char *ptr = buf;
*ptr++ = '\n'; *ptr++ = '\r';
if( task )
return;
if( state == STATE_PLAYING )
{
if( !*prompt )
sprintf( buf, "\n\r[set prompt]" );
else
{
while( *token )
{
if( *token == '%' )
switch( *(++token) )
{
case '\0': break;
case 'B':
sprintf( ptr, "%s%s",BOLD,BLUE);
while( *ptr ) ptr++;
token++;
continue;
case 'C':
sprintf( ptr, "%s%s",BOLD,CYAN);
while( *ptr ) ptr++;
token++;
continue;
case 'G':
sprintf( ptr, "%s%s",BOLD,GREEN);
while( *ptr ) ptr++;
token++;
continue;
case 'P':
sprintf( ptr, "%s%s",BOLD,PURPLE);
while( *ptr ) ptr++;
token++;
continue;
case 'R':
sprintf( ptr, "%s%s",BOLD,RED);
while( *ptr ) ptr++;
token++;
continue;
case 'Y':
sprintf( ptr, "%s%s",BOLD,YELLOW);
while( *ptr ) ptr++;
token++;
continue;
case 'h':
sprintf( ptr, "%d", hp );
while( *ptr ) ptr++;
token++;
continue;
case 'H':
sprintf( ptr, "%d", max_hp );
while( *ptr ) ptr++;
token++;
continue;
case 'm':
strcpy( ptr, itoa( mana ) );
while( *ptr ) ptr++;
token++;
continue;
case 'M':
strcpy( ptr, itoa( max_mana ) );
while( *ptr ) ptr++;
token++;
continue;
case 'n':
*(ptr++) = '\n';
*(ptr++) = '\r';
token++;
continue;
}
else
{
*(ptr++) = *(token++);
continue;
}
}
*ptr='\0';
}
sprintf( buf+strlen( buf ), "%s", NTEXT );
if( messages )
strcat( buf, "[EMAIL]" );
}
else if( state == STATE_EMAIL )
sprintf( buf, "\n\rEMAIL >" );
else if( state >= STATE_EDIT )
{
if( task == TASK_EDIT_APPEND )
sprintf( buf, "]" );
else
sprintf( buf, "\n\rEDITOR >" );
}
else if( state == STATE_BOOT )
sprintf( buf, "\n\r[ ** Seeya!! ** ]\n\r" );
else
sprintf( buf, "\n\r[Unknown connected state]" );
// short circuit the buffering - go straight to the socket
socket->write( buf );
return;
}
bool PC::outBuf() const
{
if( !*outbuf )
return false;
return true;
}
bool PC::inBuf() const
{
if( !*inptr )
return false;
return true;
}
void PC::readInput()
{
int err;
// If pending data, return.
if( intop < inceiling )
{
err = socket->read( intop, inceiling - intop );
if( err < 0 )
return;
else
{
intop += err;
*intop = '\0';
}
}
else
{
// Overflow, close connection
}
}
void PC::flush()
{
if( !outbuf || !*outbuf )
return;
if( socket->write( outbuf ) < 0 )
state = STATE_BOOT;
*outbuf = '\0';
}
char *PC::pagePending() const
{
return pagebuf;
}
void PC::page( char *arg )
{
if( !pagebuf )
return;
int lines = 0;
char *ptr = pageptr;
switch( toupper(*arg) )
{
default : break;
case 'Q':
delete [] pagebuf;
pagebuf = pageptr = pagelast = 0;
putPrompt();
return;
case 'R':
ptr = pageptr = pagelast;
break;
case 'B':
ptr = pagelast;
while( ptr != pagebuf && (lines < 23) )
if( *(ptr--) == '\n' )
lines++;
while( ptr != pagebuf && *(ptr-1) != '\n' && *(ptr-1) != '\r' )
ptr--;
pageptr = ptr;
break;
}
lines = 0;
pagelast = ptr;
while( *ptr && (lines < 23) )
{
if( *(ptr++) == '\n' )
lines++;
}
if( *ptr )
{
if( *(ptr+1) == '\r' )
ptr++;
if( *(ptr+1) == '\0' )
ptr++;
}
socket->write( pageptr, (ptr - pageptr) );
if( *ptr )
{
socket->write( INVERSE );
socket->write( "[ Type (q)uit (r)efresh (b)ack or RETURN for more ]" );
socket->write( NTEXT );
}
else if( state > STATE_INIT && state < STATE_PLAYING )
{
Nanny( this, "" );
}
else
putPrompt();
pageptr = ptr;
if( !*pageptr )
{
delete [] pagebuf;
pagebuf = pageptr = 0;
}
return;
}
int PC::setClass( int x )
{
classnow = x;
return classnow;
}
char *PC::className() const
{
static char *buf_mort[ MAX_CLASS ] =
{
"HER", "MAG", "CLE", "THI",
"WAR", "MNK", "PSI"
};
if( classnow )
return buf_mort[ classnow ];
return "WIZARD";
}
int PC::readFrom( InFile &in )
{
char buf[ BUF ];
if( !in )
return 0;
while( in && *in.getword( buf ) != '#' )
{
switch( *buf )
{
default : break;
case 'C':
if( !strcmp( "Class", buf ) )
{
classnow = in.getnum();
}
break;
case 'E':
if( !strcmp( "EqBits", buf ) )
{
int numfields = in.getnum();
for( int i = 0; i < numfields; i++ )
eq_bits[i] = in.getlong();
}
else if( !strcmp( "Exp", buf ) )
{
exp = in.getnum();
}
break;
case 'G':
if( !strcmp( "GSC", buf ) )
{
gold = in.getlong();
silver = in.getlong();
copper = in.getlong();
}
break;
case 'I':
break;
case 'L':
if( !strcmp( "Levels", buf ) )
{
levels[0] = in.getnum();
levels[1] = in.getnum();
levels[2] = in.getnum();
levels[3] = in.getnum();
levels[4] = in.getnum();
levels[5] = in.getnum();
break;
}
else if( !strcmp( "Long", buf ) )
{
in.getstring( buf );
setLong( buf );
break;
}
break;
case 'M':
if( !strcmp( "Messages", buf ) )
{
messages = in.getnum();
}
break;
case 'N':
if( !strcmp( "Name", buf ) )
{
in.getword( buf );
setName( buf );
}
break;
case 'P':
if( !strcmp( "Password", buf ) )
{
in.getstring( buf );
setPasswd( buf );
}
else if( !strcmp( "PrivBits", buf ) )
{
int numfields = in.getnum();
for( int i = 0; i < numfields; i++ )
priv[i] = in.getlong();
}
else if( !strcmp( "Prompt", buf ) )
{
in.getstring( buf );
prompt = new char[ strlen(buf) + 1 ];
strcpy( prompt, buf );
}
break;
case 'S':
if( !strcmp( "Short", buf ) )
{
in.getstring( buf );
setShort( buf );
break;
}
break;
}
}
Object *obj;
NPC *npc;
// ITEMS, NPCS, etc.
while( in && *in.getword( buf ) != '#' )
{
switch( toupper( *buf ) )
{
case 'A':
{
Affect *aff = new Affect;
if( ( aff->readFrom( in ) != -1 ) )
addAffect( aff );
else
delete aff;
}
break;
case 'O':
{
obj = new Object;
obj->readFrom( in );
obj->toWorld();
addObjInv( obj );
}
break;
case 'N':
{
npc = new NPC;
npc->readFrom( in );
out( "Loading NPC " );
out( npc->getShort() );
out( "\n\r" );
delete npc;
}
break;
}
continue;
}
return 1;
}
void PC::checkMail()
{
char buf[BUF];
sprintf( buf, "%s/%s", EMAIL_DIR, name.chars() );
InFile in( buf );
if( in )
{
messages = 1;
out( "\n\rYou have email.\n\r" );
}
else
messages = 0;
}
int PC::writeTo( OutFile &out ) const
{
if( ! out )
return 0;
out << "Name " << getName() << endl;
out << "Short " << getShort() << "~" << endl;
out << "Long " << getLong() << "~" << endl;
out << "Password " << getPasswd() << "~" << endl;
out << "Messages " << messages << endl;
out << "Class " << classnow << endl;
out << "Exp " << exp << endl;
out << "Levels " << levels[0] << " " << levels[1] << " "
<< levels[2] << " " << levels[3] << " "
<< levels[4] << " " << levels[5] << endl;
out << "Stats " << strength << " " << intel << " " << wis << " "
<< con << " " << dex << " " << speed << endl;
out << "MaxHpMana " << max_hp << " " << max_mana << endl;
out << "HpMana " << hp << " " << mana << endl;
out << "GSC " << gold << ' ' << silver << ' ' << copper << endl;
out << "Energy " << energy << endl;
out << "Prompt " << prompt << TERM_CHAR << endl;
out << "PrivBits ";
out.putbitfield( priv, MAX_PRIV_BIT_FIELDS );
out << endl;
out << "EqBits ";
out.putbitfield( eq_bits, MAX_EQ_BIT_FIELDS );
out << endl;
out << "#\n";
Affect *aff;
affects.reset();
while( ( aff = affects.peek() ) )
{
affects.next();
out << 'A';
aff->writeTo( out );
}
Object *obj;
inv.reset();
while( ( obj = inv.peek() ) )
{
inv.next();
out << "O" << endl;
obj->writeTo( out );
}
out << "#";
return 1;
}
void PC::look( Char *ch )
{
String str ( BUF );
Object *obj;
int i;
str << ch->getLong() << "\n\r";
// Add check for thief peek skill or imm.
ch->inv.reset();
i = 0;
if( ch->inv.peek() )
{
str << "Wearing:\n\r";
while( ( obj = ch->inv.peek() ) )
{
ch->inv.next();
if( !obj->wearPos() )
continue;
i++;
str.sprintfAdd( "%25s %-s\n\r", getWearPosName( obj->wearPos() ),
obj->getShort().chars() );
}
if( ch->isPC() && i == 0 )
str << ch->getShort() << " is naked. EEK!\n\r";
str << "\n\rYou peek at the inventory:\n\r";
ch->inv.reset();
while( ( obj = ch->inv.peek() ) )
{
ch->inv.next();
if( obj->wearPos() )
continue;
str << obj->getShort() << "\n\r";
}
}
out( str );
}
void PC::look( Object * )
{
}
void PC::advance( int increment )
{
String str;
if( !increment )
return;
if( increment < 0 )
{
if( levels[classnow] + increment < 1 )
increment = ( -1 - levels[classnow] ); // min level 1
str << "*** You lose " << increment << " level"
<< ( increment < -1 ? "s !!! ***\n\r" : "!!! ***\n\r" );
out( str );
// Add stat mods here.
levels[classnow] -= increment;
level -= increment;
}
else if( increment > 0 )
{
str << "*** You raise " << increment << " level"
<< ( increment > 1 ? "s !!! ***\n\r" : "!!! ***\n\r" );
out( str );
levels[classnow] += increment;
level += increment;
}
exp = 0;
}
// Now rewrite using the new memory mapped file class
void PC::view( const char *filename )
{
if( !*filename )
return;
char buf[BUF*8];
int fd;
fd = ::open( filename , O_RDONLY );
if( fd < 0 )
{
return;
}
int bytes = 0;
int size = 0;
while( (bytes = read( fd, buf+size, 1024 )) > 0 )
{
size += bytes;
if( BUF*8 - size <= 1024 )
{
sprintf( buf+size, "\n[** BUF EXCEEDED - TRUNCATED **]\n" );
size = strlen( buf );
break;
}
}
*(buf+size) = '\0';
out( buf );
}
void PC::do_exits( String & )
{
String str = "[Obvious Exits]";
for( int door=0; door < MAX_DIR; door++ )
{
if( in_room->getExit( door ) )
{
str << "\n\r" << getDirName( door ) << " - "
<< WHITE << in_room->toRoom( door )->getName() << NORMAL;
}
}
str += "\n\r";
out( str );
}
void PC::do_equipment( String & )
{
String str( BUF );
Object *obj;
str << "\n\rYou are wearing:\n\r";
for( int wear_pos = EQ_MIN; wear_pos <= EQ_MAX; wear_pos++ )
{
if( IS_SET( eq_bits, wear_pos ) )
{
obj = getObjWear( wear_pos );
if( obj )
str.sprintfAdd( "%25s - %s\n\r",
getWearPosName( wear_pos ),
obj->getShort().chars() );
else
str.sprintfAdd( "%25s - %s\n\r",
getWearPosName( wear_pos ),
"BUG!! NULL OBJECT EQ POSITION!!" );
}
}
out( str );
}
void PC::do_inventory( String & )
{
String str ( BUF * 2 );
Object *obj;
inv.reset();
str += "\n\rYou are carrying:\n\r";
while( ( obj = inv.peek() ) )
{
inv.next();
if( obj->wearPos() )
continue;
str << obj->getShort() << "\n\r";
}
str += "\n\r";
out( str );
}
void PC::do_tell( String & arg )
{
PC *ch;
String str;
String victimName;
String messg;
arg.startArgs();
victimName = arg.getArg();
messg = arg.getArg();
victimName.toProper();
ch = getPCWorld( victimName );
if( !ch )
{
out("Couldn't find anyone by that name.\n\r");
return;
}
if( ch == this )
{
out( "You mumble something to yourself.\n\r" );
return;
}
str << "\n\n\r" << name << " tells you '" << messg << "'\n\r";
ch->out( str );
str.clr();
str << "\n\rYou tell " << victimName << " '" << messg << "'\n\r";
out( str );
}
void PC::do_say( String & arg )
{
String str;
str << BCYAN << "\n\r" << name << " says '" << arg << "'\n\r" << NTEXT;
in_room->outAllCharExcept( str, this, 0 );
str.clr();
str << BCYAN << "You say '" << arg << "'\n\r" << NTEXT;
out( str );
}
void PC::do_chat( String & arg )
{
String str;
str << BPURPLE << "\n\r" << name << " chats '" << arg << "'\n\r" << NTEXT;
outAllCharExcept( str, this, 0 );
str.clr();
str << BPURPLE << "You chat '" << arg << "'\n\r" << NTEXT;
out( str );
}
void PC::do_quit( String & )
{
String str;
if( fighting )
{
out( "No way! Not in the middle of combat.\n\r" );
return;
}
str << PLAYER_DIR << '/' << name[0] << '/' << name.asProper();
writeTo( str );
out( "Goodbye, come back soon.\n\r" );
str.clr();
str << "\n\n\r" << name << " has left the game.\n\r";
in_room->out( str );
state = STATE_BOOT;
}
void PC::command( String & arg )
{
int ihash;
if( arg[0] == '\n' || arg[0] == '\r' || !arg )
return;
arg.startArgs();
incommd = arg.getArg();
incommd[0] = tolower( incommd[0] );
if( incommd == "!" )
{
if( ! inlast )
return;
// Check for command substitution like 'look Fusion ; ! Klepto'
// Looks at Fusion then looks at Klepto
incommd = inlast;
if( arg )
{
args = arg;
}
}
else
{
inlast = arg;
}
ihash = (int) ( incommd[0] - 'a' );
if( ihash < 0 || ihash > 25 )
ihash = 26;
int i;
for( i = 0; cmdlist[ihash][i].commd; i++ )
{
if( incommd[0] == *cmdlist[ihash][i].commd )
{
if( incommd.abbrev( cmdlist[ihash][i].commd ) )
{
(cmdlist[ihash][i].fun)( args );
return;
}
}
}
for( i = 0; immcmdlist[ihash][i].commd; i++ )
{
if( incommd[0] == *immcmdlist[ihash][i].commd )
{
if( incommd.abbrev( immcmdlist[ihash][i].commd ) )
{
if( authorized( immcmdlist[ihash][i].bit ) )
(immcmdlist[ihash][i].fun)( args );
else
out( "Huh?\n\r" );
return;
}
}
}
out( "Huh?\n\r" );
}
const String & PC::getCommand()
{
return incommd;
}
bool PC::getNextCommand()
{
int i;
char *save = inptr; // save in case we don't find a new line
if( !*inptr )
return false;
// Skip CRLF and telnet negotiations (response from ECHO ON/OFF for now)
if( *inptr == '\n' || *inptr == '\r' )
{
while( *inptr && isspace( *inptr ) )
inptr++;
if( !*inptr )
{
inptr = intop = inbuf;
*inptr = '\0';
}
incommd = "\n";
return true;
}
else if( *inptr == (char)IAC )
{
while( *inptr && *inptr != '\n' )
inptr++;
if( !*inptr )
{
inptr = intop = inbuf;
*inptr = '\0';
}
return false;
}
i = 0;
while( *inptr && !isspace( *inptr ) )
{
incommd[i] = *inptr;
i++; inptr++;
}
incommd[i] = '\0';
// See if there is a complete line
if( !*inptr )
{
inptr = save;
return false;
}
i = 0;
if( *inptr != '\n' && *inptr != '\r' )
{
// Skip the seperating ' ' which will always be there if there are args
inptr++;
while( *inptr && *inptr != '\n' && *inptr != '\r' )
{
args[i] = *inptr;
i++; inptr++;
}
}
args[i] = '\0';
// See if there is a complete line
if( !*inptr )
{
inptr = save;
return false;
}
while( *inptr && isspace( *inptr ) )
inptr++;
// If end of data reset input buffer queue and terminate it.
if( !*inptr )
{
inptr = intop = inbuf;
*inptr = '\0';
}
return true;
}
void PC::command()
{
// Check for \n only since I know what I put in incommd
if( !incommd || incommd[0] == '\n' )
return;
int ihash = (int) ( incommd[0] - 'a' );
if( ihash < 0 || ihash > 25 )
ihash = 26;
// int len = incommd.len();
int i;
for( i = 0; cmdlist[ihash][i].commd; i++ )
{
if( incommd[0] == *cmdlist[ihash][i].commd )
{
// if( !strncmp( cmdlist[ihash][i].commd, incommd, len ) )
if( incommd.abbrev( cmdlist[ihash][i].commd ) )
{
(cmdlist[ihash][i].fun)( args );
return;
}
}
}
for( i = 0; immcmdlist[ihash][i].commd; i++ )
{
if( incommd[0] == *immcmdlist[ihash][i].commd )
{
// if( !strncmp( immcmdlist[ihash][i].commd, incommd, len ) )
if( incommd.abbrev( immcmdlist[ihash][i].commd ) )
{
if( authorized( immcmdlist[ihash][i].bit ) )
(immcmdlist[ihash][i].fun)( args );
return;
}
}
}
out( "Huh?\n\r" );
}
void PC::setPrivBit( int bit )
{
SET_BIT( priv, bit );
}
void PC::rmPrivBit( int bit )
{
CLEAR_BIT( priv, bit );
}
int PC::authorized( int bit ) const
{
if( IS_SET( priv, bit ) )
return 1;
return 0;
}
void PC::pulse()
{
Char::pulse();
}
int PC::gainExp( int x )
{
// Calc exp caps, etc and return actual.
exp += x;
if( exp >= exp_table[ levels[ classnow ] ] )
advance( 1 );
return x;
}
// exp_table[i] = exp needed to get to level i+1
const int exp_table[MAX_PC_LEVEL+1] =
{
0,
1000, // 1
2500,
5000,
10000,
25000, // 5
50000,
100000,
250000,
500000,
400000, // 10
800000,
1500000,
2000000,
3000000,
4000000, // 15
5000000,
7000000,
10000000,
15000000,
10000000, // 20
20000000,
30000000,
40000000,
50000000,
70000000, // 25
100000000,
150000000,
200000000,
300000000,
200000000, // 30
0 // HERO
};