📄 npc_console.c
字号:
\n\ The -o options are for the stat-block output. They mean:\n\ a: ability bonuses\n\ c: AC breakdown\n\ i: initiative breakdown\n\ b: attack breakdown\n\ s: saving throw breakdown\n\ k: skill breakdown\n\ l: languages\n\ f: skills and feats\n\ p: posessions\n\ S: spells\n\\n\ The -w option is for determining the output format. It means:\n\ p: output in PCGen format.\n\ s: output in stat-block format.\n\\n\ <path>, when doing stat-block output (-ws), is the name of a file, in\n\ which case the output is all redirected to that file. When doing\n\ PCGen output (-wp), <path> is the name of a directory, in which case\n\ each NPC is created in a separate file in the given directory.\n\"static int usage() { puts( USAGE ); exit(0);}static int getLookup( char* parmName, char* arg, LOOKUP_TBL* list ) { int i; int found; i = lookup( arg, list, &found ); if( !found ) { printf( "Invalid %s: '%s'\n", parmName, arg ); usage(); } return i;}static void getHomeDirectory( char* home ) { uid_t uid; struct passwd *pwd; uid = geteuid(); pwd = getpwuid( uid ); strcpy( home, pwd->pw_dir ); if( home[ strlen( home ) - 1 ] != '/' ) { strcat( home, "/" ); }}static int parseCommandLine( int argc, char* argv[], NPC_OPTS* opts ) { int c; int i; int found; int class_count; int level_count; LOOKUP_TBL* list; memset( opts, 0, sizeof( *opts ) ); opts->race = raceANY_CORE; opts->classes[0] = classANY; opts->classes[1] = classNONE; opts->classes[2] = classNONE; opts->levels[0] = levelANY; opts->levels[1] = levelANY; opts->levels[2] = levelANY; opts->score_strategy = 1; opts->count = 1; opts->gender = gANY; opts->wrap = 0; getHomeDirectory( opts->data_path ); strcat( opts->data_path, ".npc/" ); class_count = 0; level_count = 0; srand( time( NULL ) ); while( ( c = getopt( argc, argv, "r:c:l:s:a:S:g:n:h::bo:p:w:W:d:" ) ) != -1 ) { switch( c ) { case 'r': opts->race = getLookup( "race", optarg, racetypes ); break; case 'c': opts->classes[ class_count++ ] = getLookup( "class", optarg, classtypes ); break; case 'l': opts->levels[ level_count ] = lookup( optarg, levels, &found ); if( !found ) { opts->levels[ level_count ] = atoi( optarg ); if( opts->levels[ level_count ] < 1 ) { printf( "Invalid level specification: %s\n", optarg ); usage(); } } level_count++; break; case 's': opts->score_strategy = getLookup( "strategy", optarg, strategies_lookup ); break; case 'a': opts->alignment = getLookup( "alignment", optarg, alignments ); break; case 'S': opts->seed = atoi( optarg ); srand( opts->seed ); break; case 'g': opts->gender = getLookup( "gender", optarg, genders ); break; case 'h': if( optarg == 0 ) { usage(); } else { i = lookup( optarg, help_lists, &found ); switch( i ) { case HELP_RACES: list = racetypes; break; case HELP_CLASSES: list = classtypes; break; case HELP_ALIGNMENTS: list = alignments; break; case HELP_GENDERS: list = genders; break; case HELP_STRATEGIES: list = strategies_lookup; break; default: usage(); } for( i = 0; list[ i ].name != 0; i++ ) { printf( " %s\n", list[ i ].name ); } printf( "\n" ); } exit( 0 ); case 'n': opts->count = atoi( optarg ); break; case 'b': opts->background = !opts->background; break; case 'o': for( i = 0; optarg[i]; i++ ) { switch( optarg[i] ) { case 'a': opts->opts.abilityBonuses = !opts->opts.abilityBonuses; break; case 'c': opts->opts.acBreakdown = !opts->opts.acBreakdown; break; case 'i': opts->opts.initBreakdown = !opts->opts.initBreakdown; break; case 'b': opts->opts.attackBreakdown = !opts->opts.attackBreakdown; break; case 's': opts->opts.saveBreakdown = !opts->opts.saveBreakdown; break; case 'k': opts->opts.skillBreakdown = !opts->opts.skillBreakdown; break; case 'l': opts->opts.languages = !opts->opts.languages; break; case 'f': opts->opts.skillsAndFeats = !opts->opts.skillsAndFeats; break; case 'p': opts->opts.possessions = !opts->opts.possessions; break; case 'S': opts->opts.spells = !opts->opts.spells; break; default: printf( "Invalid stat-block format specifier: %c\n", optarg[i] ); usage(); } } break; case 'w': for( i = 0; optarg[i]; i++ ) { switch( optarg[i] ) { case 's': opts->mode = MODE_STATBLOCK; break; case 'p': opts->mode = MODE_PCGEN; break; default: printf( "Invalid output mode specifier: %c\n", optarg[i] ); usage(); } } break; case 'p': strcpy( opts->path, optarg ); break; case 'W': opts->wrap = atoi( optarg ); break; case 'd': strcpy( opts->data_path, optarg ); if( opts->data_path[ strlen( opts->data_path )-1 ] != '/' ) { strcat( opts->data_path, "/" ); } break; default: usage(); } } return 0;}static void wrapLines( char* string, int width ) { int c; int count; int i; int last; if( width > 0 ) { count = width+1; last = 0; while( count < strlen( string ) ) { for( i = last; i < count; i++ ) { if( string[i] == '\n' ) break; } if( string[i] != '\n' ) { for( i = count; i > 0; i-- ) { c = string[i]; if( isspace( c ) ) { string[i] = '\n'; break; } } } last = i+1; count = i + width+1; } }}static int displayNPC_StatBlock( NPC_OPTS* opts, wtSTREAM_t *stream, NPC* npc ) { char statBlock[4096]; int count; int i; int doBg; char motivation1[ 1024 ]; char motivation2[ 1024 ]; grGRAMMAR* grammar; if( opts->background ) { grammar = openNPCMotivationGrammar( opts->data_path ); } npcBuildStatBlock( npc, &opts->opts, statBlock, sizeof( statBlock ) ); strrepl( statBlock, "~B", "" ); strrepl( statBlock, "~b", "" ); strrepl( statBlock, "~I", "" ); strrepl( statBlock, "~i", "" ); wrapLines( statBlock, opts->wrap ); wtPrint( stream, statBlock ); if( opts->background ) { grammar->startSymbol = "[motivation]"; getNPCMotivation( grammar, npc, motivation1, sizeof( motivation1 ) ); do { getNPCMotivation( grammar, npc, motivation2, sizeof( motivation1 ) ); } while( strcmp( motivation1, motivation2 ) == 0 ); strcpy( statBlock, "Primary motivation: " ); strcat( statBlock, motivation1 ); wrapLines( statBlock, opts->wrap ); wtPrintf( stream, "\n\n%s\n", statBlock ); strcpy( statBlock, "Secondary motivation: " ); strcat( statBlock, motivation2 ); wrapLines( statBlock, opts->wrap ); wtPrintf( stream, "\n%s\n", statBlock ); getNPCRecentPast( grammar, npc, motivation1, sizeof( motivation1 ) ); strcpy( statBlock, "Recent Past: " ); strcat( statBlock, motivation1 ); wrapLines( statBlock, opts->wrap ); wtPrintf( stream, "\n%s\n", statBlock ); } if( opts->background ) { grDestroyGrammar( grammar ); } wtPrintf( stream, "\n" ); return 0;}int main( int argc, char* argv[] ) { char buffer[512]; int i; wtSTREAM_t* stream; NPC* npc; NPCGENERATOROPTS opts; NPCGENERATOROPTS tempOpts; NPC_OPTS cmd_opts; if( parseCommandLine( argc, argv, &cmd_opts ) != 0 ) { return 0; } opts.raceType = cmd_opts.race; opts.gender = cmd_opts.gender; opts.alignment = cmd_opts.alignment; opts.level[0] = cmd_opts.levels[0]; opts.level[1] = cmd_opts.levels[1]; opts.level[2] = cmd_opts.levels[2]; opts.classType[0] = cmd_opts.classes[0]; opts.classType[1] = cmd_opts.classes[1]; opts.classType[2] = cmd_opts.classes[2]; opts.abilityScoreStrategy = strategies[ cmd_opts.score_strategy ]; opts.filePath = cmd_opts.data_path; if( cmd_opts.mode == MODE_STATBLOCK && cmd_opts.path[0] != 0 ) { stream = wtOpenFileStream( cmd_opts.path, "w" ); } else { stream = wtOpenFileStreamFromHandle( stdout ); } for( i = 0; i < cmd_opts.count; i++ ) { memcpy( &tempOpts, &opts, sizeof( tempOpts ) ); npc = npcGenerateNPC( &tempOpts ); if( cmd_opts.mode == MODE_STATBLOCK ) { displayNPC_StatBlock( &cmd_opts, stream, npc ); if( i+1 < cmd_opts.count ) { wtPrint( stream, "---------------------------\n" ); } } else if( cmd_opts.mode == MODE_PCGEN ) { if( cmd_opts.path[0] != 0 ) { wtCloseStream( stream ); strcpy( buffer, cmd_opts.path ); strcat( buffer, "/" ); strcat( buffer, npc->name ); strcat( buffer, ".pcg" ); stream = wtOpenFileStream( buffer, "w" ); } convertToPCGen( npc, stream ); wtPrint( stream, "\n" ); } npcDestroyNPC( npc ); } wtCloseStream( stream ); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -