/* ....[@@@..[@@@..............[@.................. 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 };