📄 npccgi.c
字号:
#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <time.h>#include <string.h>#include <ctype.h>#include "gameutil.h"#include "npcEngine.h"#include "dndconst.h"#include "dndutil.h"#include "grammar.h"#include "npcHistory.h"#include "pcgen_interface.h"#include "writetem.h"#include "wtstream.h"#include "qDecoder.h"#define TEMPATH "tem/"#ifdef WIN32#define CGINAME "npc.exe"#else#define CGINAME "npc.cgi"#endifstatic char url[512];static struct { char* name; int id;} racetypes[] = { { "any", raceANY }, { "anycore", raceANY_CORE }, { "anydmg", raceANY_DMG }, { "anymm", raceANY_MM }, { "anycc", raceANY_CC }, { "dwarf", rcDWARF_HILL }, { "elf", rcELF_HIGH }, { "gnome", rcGNOME_ROCK }, { "halfelf", rcHALFELF }, { "halfling", rcHALFLING_LIGHTFOOT }, { "halforc", rcHALFORC }, { "human", rcHUMAN }, { "aasimar", rcAASIMAR }, { "aranea", rcARANEA }, { "azer", rcAZER }, { "bugbear", rcBUGBEAR }, { "centaur", rcCENTAUR }, { "dopple", rcDOPPLEGANGER }, { "drider", rcDRIDER }, { "deepdwarf", rcDWARF_DEEP }, { "derro", rcDWARF_DERRO }, { "duergar", rcDWARF_DUERGAR }, { "mtndwarf", rcDWARF_MOUNTAIN }, { "aqelf", rcELF_AQUATIC }, { "drow", rcELF_DROW }, { "grayelf", rcELF_GRAY }, { "wildelf", rcELF_WILD }, { "woodelf", rcELF_WOOD }, { "ettin", rcETTIN }, { "hillg", rcGIANT_HILL }, { "stoneg", rcGIANT_STONE }, { "frostg", rcGIANT_FROST }, { "fireg", rcGIANT_FIRE }, { "cloudg", rcGIANT_CLOUD }, { "stormg", rcGIANT_STORM }, { "gnoll", rcGNOLL }, { "frstgnome", rcGNOME_FOREST }, { "svirf", rcGNOME_SVIRFNEBLIN }, { "goblin", rcGOBLIN }, { "grimlock", rcGRIMLOCK }, { "hags", rcHAG_SEA }, { "haga", rcHAG_ANNIS }, { "hagg", rcHAG_GREEN }, { "deephalf", rcHALFLING_DEEP }, { "tallflw", rcHALFLING_TALLFELLOW }, { "harpy", rcHARPY }, { "hobgob", rcHOBGOBLIN }, { "kobold", rcKOBOLD }, { "kuotoa", rcKUOTOA }, { "lizard", rcLIZARDFOLK }, { "locathah", rcLOCATHAH }, { "medusa", rcMEDUSA }, { "mindflayer", rcMINDFLAYER }, { "minotaur", rcMINOTAUR }, { "ogre", rcOGRE }, { "ogremage", rcOGREMAGE }, { "orc", rcORC }, { "sahuagin", rcSAHUAGIN }, { "tiefling", rcTIEFLING }, { "troglodyte", rcTROGLODYTE }, { "troll", rcTROLL }, { "yuantip", rcYUANTI_PUREBLOOD }, { "yuantih", rcYUANTI_HALFBLOOD }, { "yuantia", rcYUANTI_ABOMINATION }, { "abandoned", rcCC_ABANDONED }, { "asaath", rcCC_ASAATH }, { "batdevil", rcCC_BATDEVIL }, { "pwretch", rcCC_PLAGUEWRETCH }, { "charduni", rcCC_CHARDUNI }, { "cgoblin", rcCC_COALGOBLIN }, { "fdwarf", rcCC_DWARF_FORSAKEN }, { "felf", rcCC_ELF_FORSAKEN }, { "iceghoul", rcCC_ICE_GHOUL }, { "mcora", rcCC_MANTICORA }, { "morgaunt", rcCC_MORGAUNT }, { "proud", rcCC_PROUD }, { "ratman", rcCC_RATMAN }, { "bgratman", rcCC_RATMAN_BROWNGORGER }, { "dratman", rcCC_RATMAN_DISEASED }, { "fratman", rcCC_RATMAN_FOAMER }, { "rwratman", rcCC_RATMAN_REDWITCH }, { "skindev", rcCC_SKINDEVIL }, { "segoblin", rcCC_SPIDEREYEGOBLIN }, { "stroll", rcCC_STEPPETROLL }, { "selement", rcCC_STRIFEELEMENTAL }, { "tokal", rcCC_TOKALTRIBESMAN }, { "ubantu", rcCC_UBANTUTRIBESMAN }, { 0, 0 }};typedef struct __lf__ LOOKANDFEEL;struct __lf__ { char* name; char* main; char* config; char* printable; char* longdesc;};LOOKANDFEEL lookAndFeel[] = { { "standard", TEMPATH "npc_main.tem", TEMPATH "npc_statconfig.tem", TEMPATH "npc_printable.tem", TEMPATH "npc_longdesc.tem" }, { "snipe", TEMPATH "snipe_npc_main.tem", TEMPATH "snipe_npc_config.tem", TEMPATH "npc_printable.tem", TEMPATH "npc_longdesc.tem" }, { 0, 0, 0, 0, 0 }};/* logs access to the CGI */void logAccess( long seed, char* alignment, char* gender, char* race, char* cls, char* level, char* cls2, char* level2, char* cls3, char* level3, int count ) {#ifdef USE_LOG FILE *f; char buffer[512]; time_t t; char *host; f = fopen( LOGLOCATION, "at" ); if( f == NULL ) { printf( "content-type: text/html\r\n\r\n" ); printf( "could not open log file: %d (%s)\n", errno, strerror( errno ) ); return; } t = time( NULL ); strftime( buffer, sizeof( buffer ), "[%d %b %Y %H:%M:%S]", localtime( &t ) ); host = getenv( "REMOTE_ADDR" ); fprintf( f, "%s %s ", buffer, host ); if( alignment == 0 ) { fprintf( f, "start\n" ); } else { fprintf( f, "%s:%s:%s:%s:%s:%s:%s:%s:%s:%d (%d)\n", alignment, gender, race, cls, level, cls2, level2, cls3, level3, count, seed ); } fclose( f );#endif}int getCounter() {#ifdef USE_COUNTER FILE *f; char buffer[32]; int count; f = fopen( CTRLOCATION, "r+t" ); if( f == NULL ) { f = fopen( CTRLOCATION, "w+t" ); if( f == NULL ) { return 0; } } fgets( buffer, sizeof( buffer ), f ); count = atoi( buffer ) + 1; rewind( f ); fprintf( f, "%d", count ); fclose( f ); return count;#else return -1;#endif}LOOKANDFEEL* getLookAndFeel( char* name ) { int i; for( i = 0; lookAndFeel[ i ].name != 0; i++ ) { if( strcmp( name, lookAndFeel[ i ].name ) == 0 ) { return &(lookAndFeel[i]); } } return &(lookAndFeel[0]);}static int icomp( const void* x, const void* y ) { int ix = *(int*)x; int iy = *(int*)y; if( ix < iy ) return 1; if( ix > iy ) return -1; return 0;}void heroicAbilities( int* scores, void* data ) { int i; npcAbScoreStrategy_BestOf4d6( scores, data ); scores[0] = 18; scores[1] = 18; for( i = 2; i < 6; i++ ) { if( scores[i] < 12 ) { scores[ i ] = 12; } }}void straight18s( int* scores, void* data ) { int i; for( i = 0; i < 6; i++ ) { scores[ i ] = 18; }}void averageAbilities( int* scores, void* data ) { int i; for( i = 0; i < 6; i++ ) { scores[i] = 10 + ( rand() % 2 ); }}NPCABSCOREGENFUNC strategies[] = { 0, npcAbScoreStrategy_BestOf4d6, npcAbScoreStrategy_Straight3d6, heroicAbilities, averageAbilities, straight18s};static void strrepl( char* buf, char* srch, char* repl ) { char* p; int slen; int rlen; slen = strlen( srch ); rlen = strlen( repl ); p = strstr( buf, srch ); while( p != NULL ) { memmove( p+rlen, p+slen, strlen( p + slen ) + 1 ); strncpy( p, repl, rlen ); p = strstr( p+rlen, srch ); }}int displayFeats( wtSTREAM_t* stream, wtTAG_t** tags, wtGENERIC_t data, char* other ) { NPCFEAT* feat; char buffer[100]; NPCFEATWEAPON* nfw; NPCFEATSKILL* nfs; NPCFEATSCHOOL* nfsch; NPCFEATSPELLS* nfsp; int i; wtPrint( stream, "<TR><TD CLASS=\"NORMAL\" COLSPAN=2>\n" ); wtPrint( stream, "<UL>\n" ); feat = (NPCFEAT*)data; while( feat != 0 ) { strcpy( buffer, dndGetFeatName( feat->type ) ); buffer[0] = toupper( buffer[0] ); if( feat->autoAdd ) { wtPrintf( stream, "<LI><I>%s", buffer ); } else { wtPrintf( stream, "<LI>%s", buffer ); } switch( feat->type ) { case ftSPELLMASTERY: nfsp = feat->data; wtPrint( stream, " (" ); for( i = 0; i < 3; i++ ) { wtPrintf( stream, "%s%s", ( i > 0 ? ", " : "" ), dndGetSpellName( nfsp->spells[ i ] ) ); } wtPrint( stream, ")" ); break; case ftSPELLFOCUS: nfsch = feat->data; wtPrintf( stream, " (%s)", dndGetSchoolOfMagicName( nfsch->school ) ); break; case ftWEAPONPROFICIENCY_SIMPLE: case ftWEAPONPROFICIENCY_MARTIAL: case ftWEAPONPROFICIENCY_EXOTIC: case ftIMPROVEDCRITICAL: case ftWEAPONFOCUS: case ftWEAPONFINESSE: case ftWEAPONSPECIALIZATION: nfw = feat->data; wtPrintf( stream, " (%s)", dndGetWeaponName( nfw->weapon ) ); break; case ftSKILLFOCUS: nfs = feat->data; wtPrintf( stream, " (%s)", dndGetSkillName( nfs->skill ) ); break; } if( feat->autoAdd ) { wtPrintf( stream, "</I>\n" ); } else { wtPrintf( stream, "\n" ); } feat = feat->next; } wtPrint( stream, "</UL>\n" ); wtPrint( stream, "</TD></TR>\n" ); return 0;}int displayClasses( wtSTREAM_t* stream, wtTAG_t** tags, wtGENERIC_t data, char* other ) { NPCCLASS* cls; char buffer[100]; int totalLevel; wtPrint( stream, "<TR><TD CLASS=\"NORMAL\" COLSPAN=2>\n" ); wtPrint( stream, "<UL>\n" ); cls = (NPCCLASS*)data; while( cls != 0 ) { strcpy( buffer, dndGetClassName( cls->type ) ); buffer[0] = toupper( buffer[0] ); wtPrintf( stream, "<LI>%s %d\n", buffer, cls->level ); cls = cls->next; } wtPrint( stream, "</UL>\n" ); wtPrint( stream, "</TD></TR>\n" ); return 0;}int displaySkills( wtSTREAM_t* stream, wtTAG_t** tags, wtGENERIC_t data, char* other ) { NPCSKILL* skill; NPC* npc; char buffer[512]; npc = (NPC*)data; wtPrint( stream, "<TR><TD CLASS=\"NORMAL\" COLSPAN=2>\n" ); wtPrint( stream, "<TABLE BORDER=0 WIDTH=\"100%\">\n" ); for( skill = npc->skills; skill != 0; skill = skill->next ) { float total; NPCCOMPBREAKDOWN* breakdown; char skillName[100]; strcpy( skillName, dndGetSkillName( skill->type ) ); skillName[0] = toupper( skillName[0] ); total = npcComputeActualSkillBonus( npc, skill->type, &breakdown ); wtPrintf( stream, "<TR><TD CLASS=\"NORMAL\">%s</TD><TD CLASS=\"NORMAL\"><B>%+g</B></TD><TD CLASS=\"NORMAL\">%s</TD></TR>\n", skillName, total, npcBuildComponentBreakdownDescription( breakdown, buffer, sizeof( buffer ) ) ); } wtPrint( stream, "</TABLE>\n" ); wtPrint( stream, "</TD></TR>\n" ); return 0;}int displaySpells( wtSTREAM_t *stream, wtTAG_t** tags, wtGENERIC_t data, char* other ) { NPC* npc; NPCCLASS* cls; NPCSPELL** list; NPCSPELL* spell; char buffer[100]; int i; int count; int bonus; int hasPlus; int relevantAbility; int total; int maxLevel; npc = (NPC*)data; for( cls = npc->classes; cls != 0; cls = cls->next ) { list = 0; hasPlus = 0; switch( cls->type ) { case pcBARD: list = ((NPCBARDDATA*)cls->data)->spells; relevantAbility = npc->charisma; break; case pcCLERIC: hasPlus = 1; relevantAbility = npc->wisdom; wtPrint( stream, "<TR><TD CLASS=\"DIVIDER\" COLSPAN=2><IMG SRC=\"/img/blank.gif\" WIDTH=1 HEIGHT=1></TD></TR>" ); wtPrint( stream, "<TR><TD CLASS=\"HEADER\" COLSPAN=2>Cleric Domains:</TD></TR>\n" ); wtPrint( stream, "<TR><TD CLASS=\"NORMAL\" COLSPAN=2>\n<UL>\n" ); for( i = 0; i < 2; i++ ) { strcpy( buffer, dndGetDomainName( ((NPCCLERICDATA*)cls->data)->domain[i] ) ); buffer[ 0 ] = toupper( buffer[ 0 ] ); wtPrintf( stream, "<LI>%s\n", buffer ); } wtPrint( stream, "</UL>\n</TD></TR>\n" ); break; case pcDRUID: relevantAbility = npc->wisdom; break; case pcPALADIN: relevantAbility = npc->wisdom; break; case pcRANGER: relevantAbility = npc->wisdom; break; case pcSORCERER: list = ((NPCSORCERERDATA*)cls->data)->spells; relevantAbility = npc->charisma; break; case pcWIZARD: list = ((NPCWIZARDDATA*)cls->data)->spells; relevantAbility = npc->intelligence; break; case npcADEPT: relevantAbility = npc->wisdom; break; default: continue; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -