/* * COMMAND1.C: * * Command handling/parsing routines. * * Copyright (C) 1991, 1992, 1993, 1997 Brooke Paul & Brett Vickers * */ #include "mstruct.h" #include "mextern.h" #include <ctype.h> #include <string.h> #ifdef DMALLOC #include "/usr/local/include/dmalloc.h" #endif /**********************************************************************/ /* login */ /**********************************************************************/ /* This function is the first function that gets input from a player when */ /* he logs in. It asks for the player's name and password, and performs */ /* the according function calls. */ void login(fd, param, str) int fd; int param; char *str; { int i, match=0; extern int Numplayers; char tempstr[20], str2[50], path[80], forbid[20]; long t; creature *ply_ptr; FILE *fp; switch(param) { case 0: if(strcmp(Ply[fd].extr->tempstr[0], str)) { disconnect(fd); return; } print(fd, "\nPlease enter name: "); RETURN(fd, login, 1); case 1: /* Doneval: Here I check the name of the player. If it's the same of one of the mail's boards, bad. Brooke, check the already made characters! * for(i=0;i<=BOARDS;i++) { if(!strcmp(boards[i], str)) { print(fd, "\nThis is the name of a mail board.\n"); ask_for(fd, "Please enter name: "); } } */ if(!isalpha(str[0])) { print(fd, "Please enter name: "); RETURN(fd, login, 1); } if(PARANOID) { /* Check for ident */ if((!strcmp(Ply[fd].io->userid, "no_port") || !strcmp(Ply[fd].io->userid, "unknown")) && (strcmp(Ply[fd].io->address, "moria.bio.uci.edu") || strcmp(Ply[fd].io->address, "128.200.21.101"))) { print(fd, "\n\nI am unable to get authorization from your server.\n"); print(fd, "Please try connecting from another host, or contact\n"); print(fd, "your system administrator to request RFC 931 auth/identd.\n\n"); print(fd, "If you have connected from this account in the past,\n"); print(fd, "try logging in more slowly.\n\n"); output_buf(); disconnect(fd); return; } } /* Check for double log */ for(i=0; i<Tablesize; i++) { if(!Ply[i].ply) continue; if(Ply[i].ply->fd < 0) continue; if(strcmp(Ply[i].io->userid, "no_port") || strcmp(Ply[i].io->userid, "unknown")) continue; if(!strcmp(Ply[i].io->userid, Ply[fd].io->userid)) { match += 1; if(match > 0){ print(fd, "\n\n%s\n", account_exists); print(fd, "Please only play one character at a time.\n\n"); output_buf(); disconnect(fd); return; } } } if(strlen(str) < 3) { print(fd, "Name must be at least 3 characters.\n\n"); print(fd, "Please enter name: "); RETURN(fd, login, 1); } if(strlen(str) >= 20) { print(fd, "Name must be less than 20 characters.\n\n"); print(fd, "Please enter name: "); RETURN(fd, login, 1); } for(i=0; i<strlen(str); i++) if(!isalpha(str[i])) { print(fd, "Name must be alphabetic.\n\n"); print(fd, "Please enter name: "); RETURN(fd, login, 1); } lowercize(str, 1); str[25]=0; /* check to see the name is allowed */ /* sprintf(path, "%s/forbidden_name", PLAYERPATH); fp=fopen(path, "r"); if(!fp) merror("ERROR - forbidden name", NONFATAL); else { while(!feof(fp)) { fscanf(fp, "%s", forbid); if(!strcmp(forbid, str)) { print(fd, "That name is not allowed.\n"); print(fd, "\nPlease enter name: "); RETURN(fd, login, 1); } } } */ if(load_ply(str, &ply_ptr) < 0) { strcpy(Ply[fd].extr->tempstr[0], str); print(fd, "\n%s? Did I get that right? ", str); RETURN(fd, login, 2); } else { ply_ptr->fd = -1; Ply[fd].ply = ply_ptr; if(CHECKDOUBLE) { if(checkdouble(ply_ptr->name)) { #ifdef WIN32 scwrite(fd, "No simultaneous playing.\n\r", 26); #else write(fd, "No simultaneous playing.\n\r", 26); #endif /* WIN32 */ disconnect(fd); return; } } /* CHECKDOUBLE */ print(fd, "%c%c%cPlease enter password: ", 255, 251, 1); RETURN(fd, login, 3); } case 2: if(str[0] != 'y' && str[0] != 'Y') { Ply[fd].extr->tempstr[0][0] = 0; print(fd, "Please enter name: "); RETURN(fd, login, 1); } else { print(fd, "\nHit return: "); RETURN(fd, create_ply, 1); } case 3: if(strcmp(str, Ply[fd].ply->password)) { #ifdef WIN32 scwrite(fd, "\255\252\1\n\rIncorrect.\n\r", 17); #else write(fd, "\255\252\1\n\rIncorrect.\n\r", 17); #endif /* WIN32 */ disconnect(fd); return; } else { print(fd, "%c%c%c\n\r", 255, 252, 1); strcpy(tempstr, Ply[fd].ply->name); for(i=0; i<Tablesize; i++) if(Ply[i].ply && i != fd) if(!strcmp(Ply[i].ply->name, Ply[fd].ply->name)) disconnect(i); free_crt(Ply[fd].ply); /* It used to cause a crash if a player suicided at the same time */ /* as creating a new charater, this fixes it. */ if(load_ply(tempstr, &Ply[fd].ply) < 0) { #ifdef WIN32 scwrite(fd, "Player no longer exists!\n\r", 25); #else write(fd, "Player no longer exists!\n\r", 25); #endif /* WIN32 */ t = time(0); strcpy(str2, (char *)ctime(&t)); str2[strlen(str2)-1] = 0; logn("sui_crash","%s: %s (%s) suicided.\n", str2, Ply[fd].ply->name, Ply[fd].io->address); disconnect(fd); return; } Ply[fd].ply->fd = fd; init_ply(Ply[fd].ply); RETURN(fd, command, 1); } } } /**********************************************************************/ /* create_ply */ /**********************************************************************/ /* This function allows a new player to create his or her character. */ void create_ply(fd, param, str) int fd; int param; char *str; { int i, k, l, n, sum, num[5], dm_need_pass=0; char ph, ph_str[10]; switch(param) { case 1: /* print(fd,"\n\n"); */ Ply[fd].ply = (creature *)malloc(sizeof(creature)); if(!Ply[fd].ply) merror("create_ply", FATAL); zero(Ply[fd].ply, sizeof(creature)); Ply[fd].ply->fd = -1; Ply[fd].ply->rom_num = 1; if((!strcmp(Ply[fd].extr->tempstr[0],dmname[0])) || (!strcmp(Ply[fd].extr->tempstr[0],dmname[1])) || (!strcmp(Ply[fd].extr->tempstr[0],dmname[2])) || (!strcmp(Ply[fd].extr->tempstr[0],dmname[3])) || (!strcmp(Ply[fd].extr->tempstr[0],dmname[4])) || (!strcmp(Ply[fd].extr->tempstr[0],dmname[5])) || (!strcmp(Ply[fd].extr->tempstr[0],dmname[6]))) { print(fd, "\nA password is required to create that character.\n"); print(fd, "Please enter password: "); output_buf(); RETURN(fd, create_ply, 2); } else goto no_pass; case 2: if(strcmp(dm_pass, str)) { disconnect(fd); return; } case 3: no_pass: if(ANSILINE) { clrscr(fd); ask_for(fd, "[M] Male or [F] Female: "); } else print(fd, "[M] Male or [F] Female: "); RETURN(fd, create_ply, 4); case 4: if(low(str[0]) != 'm' && low(str[0]) != 'f') { if(ANSILINE) ask_for(fd, "[M] Male or [F] Female: "); else print(fd, "[M] Male or [F] Female: "); RETURN(fd, create_ply, 4); } if(low(str[0]) == 'm') F_SET(Ply[fd].ply, PMALES); print(fd, "\nAvailable classes:"); print(fd, "\n /----- AVAILABLE CLASSES ------\\"); print(fd, "\n | |"); print(fd, "\n | [A] Assassin [B] Barbarian |"); print(fd, "\n | [C] Cleric [D] Fighter |"); print(fd, "\n | [E] Bard [F] Mage |"); print(fd, "\n | [G] Paladin [H] Ranger |"); print(fd, "\n | [I] Thief [J] Monk |"); print(fd, "\n | [K] Druid [L] Alchemist |"); print(fd, "\n \\------------------------------/"); if(ANSILINE) ask_for(fd, "Choose one: "); else print(fd, "\nChoose one: "); RETURN(fd, create_ply, 5); case 5: switch(low(str[0])) { case 'a': Ply[fd].ply->class = ASSASSIN; break; case 'b': Ply[fd].ply->class = BARBARIAN; break; case 'c': Ply[fd].ply->class = CLERIC; break; case 'd': Ply[fd].ply->class = FIGHTER; break; case 'e': Ply[fd].ply->class = BARD; break; case 'f': Ply[fd].ply->class = MAGE; break; case 'g': Ply[fd].ply->class = PALADIN; break; case 'h': Ply[fd].ply->class = RANGER; break; case 'i': Ply[fd].ply->class = THIEF; break; case 'j': Ply[fd].ply->class = MONK; break; case 'k': Ply[fd].ply->class = DRUID; break; case 'l': Ply[fd].ply->class = ALCHEMIST; break; default: { if(ANSILINE) ask_for(fd, "Choose one: "); else print(fd, "\nChoose one: "); RETURN(fd, create_ply, 5); } } if(!Ply[fd].ply->class) { print(fd, "Invalid selection: %s", str); if(ANSILINE) ask_for(fd, "Choose one: "); else print(fd, "\nChoose one: "); RETURN(fd, create_ply, 5); } print(fd, "\n ----- CHARACTER STATS -----"); print(fd, "\nYou have 54 points to distribute among your 5 stats. Please enter your 5"); print(fd, "\nnumbers in the following order: Strength, Dexterity, Constitution,"); print(fd, "\nIntelligence, Piety. No stat may be smaller than 3 or larger than 18.i"); print(fd, "\nUse the following format: ## ## ## ## ##\n\n"); if(ANSILINE) ask_for(fd, ": "); else print(fd, ": "); RETURN(fd, create_ply, 6); case 6: n = strlen(str); l = 0; k = 0; for(i=0; i<=n; i++) { if(str[i]==' ' || str[i]==0) { str[i] = 0; num[k++] = atoi(&str[l]); l = i+1; } if(k>4) break; } if(k<5) { print(fd, "Please enter all 5 numbers.\n"); if(ANSILINE) ask_for(fd, ": "); else print(fd, "\n: "); RETURN(fd, create_ply, 6); } sum = 0; for(i=0; i<5; i++) { if(num[i] < 3 || num[i] > 18) { print(fd, "No stats < 3 or > 18 please.\n"); print(fd, ": "); RETURN(fd, create_ply, 6); } sum += num[i]; } if(sum > 54) { print(fd, "Stat total may not exceed 54.\n"); print(fd, ": "); RETURN(fd, create_ply, 6); } Ply[fd].ply->strength = num[0]; Ply[fd].ply->dexterity = num[1]; Ply[fd].ply->constitution = num[2]; Ply[fd].ply->intelligence = num[3]; Ply[fd].ply->piety = num[4]; print(fd, "\n ----- WEAPON PROFICIENCIES -----"); print(fd, "\nChoose a weapons proficiency:"); print(fd, "\n[A] Sharp [B] Thrusting [C] Blunt"); print(fd, "\n[D] Pole [E] Missile\n\n"); if(ANSILINE) ask_for(fd, ": "); else print(fd, ": "); RETURN(fd, create_ply, 7); case 7: switch(low(str[0])) { case 'a': Ply[fd].ply->proficiency[0]=1024; break; case 'b': Ply[fd].ply->proficiency[1]=1024; break; case 'c': Ply[fd].ply->proficiency[2]=1024; break; case 'd': Ply[fd].ply->proficiency[3]=1024; break; case 'e': Ply[fd].ply->proficiency[4]=1024; break; default: print(fd, " <-- Try again."); if(ANSILINE) ask_for(fd, ": "); else print(fd, "\n: "); RETURN(fd, create_ply, 7); } print(fd, "\n ----- ALIGNMENT -----"); print(fd, "\nLawful players cannot attack or steal from other players, nor can they\nbe attacked or stolen from by other players."); print(fd, "\nChaotic players may attack or steal from other chaotic players, and they can\nbe attacked or stolen from by other chaotic players.\n\n"); if(ANSILINE) ask_for(fd, "Choose an alignment, [C] Chaotic or [L] Lawful: "); else print(fd, "\nChoose an alignment, [C] Chaotic or [L] Lawful: "); RETURN(fd, create_ply, 8); case 8: if(low(str[0]) == 'c') F_SET(Ply[fd].ply, PCHAOS); else if(low(str[0]) == 'l') F_CLR(Ply[fd].ply, PCHAOS); else { if(ANSILINE) ask_for(fd, "[C] Chaotic or [L] Lawful: "); else print(fd, "\n[C] Chaotic or [L] Lawful: "); RETURN(fd, create_ply, 8); } print(fd, "\nAvailable races:"); print(fd, "\n /----------------- ELF RACES ----------------\\"); print(fd, "\n | [A] Elf [B] Dark-Elf [C] Half-Elf |"); print(fd, "\n |----------------- ORC RACES ----------------|"); print(fd, "\n | [D] Orc [E] Half-Orc [F] Goblin |"); print(fd, "\n |----------------- BIG RACES ----------------|"); print(fd, "\n | [G] Troll [H] Ogre [I] Half-Giant |"); print(fd, "\n |-------------- LITTLE RACES ----------------|"); print(fd, "\n | [J] Dwarf [K] Hobbit [L] Gnome |"); print(fd, "\n |------------ HUMANOID RACES ----------------|"); print(fd, "\n | [M] Human |"); print(fd, "\n \\-------------------------------------------/\n\n"); if(ANSILINE) ask_for(fd, "Choose one: "); else print(fd, "\nChoose one: "); RETURN(fd, create_ply, 9); case 9: switch(low(str[0])) { case 'a': Ply[fd].ply->race = ELF; break; case 'b': Ply[fd].ply->race = DARKELF; break; case 'c': Ply[fd].ply->race = HALFELF; break; case 'd': Ply[fd].ply->race = ORC; break; case 'e': Ply[fd].ply->race = HALFORC; break; case 'f': Ply[fd].ply->race = GOBLIN; break; case 'g': Ply[fd].ply->race = TROLL; break; case 'h': Ply[fd].ply->race = OGRE; break; case 'i': Ply[fd].ply->race = HALFGIANT; break; case 'j': Ply[fd].ply->race = DWARF; break; case 'k': Ply[fd].ply->race = HOBBIT; break; case 'l': Ply[fd].ply->race = GNOME; break; case 'm': Ply[fd].ply->race = HUMAN; break; } if(!Ply[fd].ply->race) { if(ANSILINE) ask_for(fd, "Choose one: "); else print(fd, "\nChoose one: "); RETURN(fd, create_ply, 9); } switch(Ply[fd].ply->race) { case DARKELF: Ply[fd].ply->intelligence+=1; Ply[fd].ply->constitution+=1; Ply[fd].ply->piety-=2; break; case DWARF: Ply[fd].ply->strength++; Ply[fd].ply->piety--; break; case ELF: Ply[fd].ply->intelligence+=2; Ply[fd].ply->constitution--; Ply[fd].ply->strength--; break; case GOBLIN: Ply[fd].ply->intelligence-=2; Ply[fd].ply->constitution++; Ply[fd].ply->strength++; break; case GNOME: Ply[fd].ply->piety++; Ply[fd].ply->strength--; break; case HALFELF: Ply[fd].ply->intelligence++; Ply[fd].ply->constitution--; break; case HALFORC: Ply[fd].ply->constitution--; break; case HOBBIT: Ply[fd].ply->dexterity++; Ply[fd].ply->strength--; break; case HUMAN: Ply[fd].ply->constitution++; break; case OGRE: Ply[fd].ply->strength++; Ply[fd].ply->piety--; break; case ORC: Ply[fd].ply->strength++; Ply[fd].ply->constitution++; Ply[fd].ply->dexterity--; Ply[fd].ply->intelligence--; break; case TROLL: Ply[fd].ply->strength++; Ply[fd].ply->intelligence--; break; case HALFGIANT: Ply[fd].ply->strength+=2; Ply[fd].ply->intelligence--; Ply[fd].ply->piety--; break; } print(fd, "\nChoose a password (up to 14 chars): "); RETURN(fd, create_ply, 10); case 10: if(strlen(str) > 14) { print(fd, "Too long.\nChoose a password: "); RETURN(fd, create_ply, 10); } if(strlen(str) < 3) { print(fd, "Too short.\nChoose a password: "); RETURN(fd, create_ply, 10); } strncpy(Ply[fd].ply->password, str, 14); strcpy(Ply[fd].ply->name, Ply[fd].extr->tempstr[0]); up_level(Ply[fd].ply); Ply[fd].ply->fd = fd; init_ply(Ply[fd].ply); save_ply(Ply[fd].ply->name, Ply[fd].ply); print(fd, "\n"); F_SET(Ply[fd].ply, PNOAAT); print(fd, "Type 'welcome' at prompt to get more info on the game\nand help you get started.\n"); RETURN(fd, command, 1); } } /**********************************************************************/ /* command */ /**********************************************************************/ /* This function handles the main prompt commands, and calls the */ /* appropriate function, depending on what service is requested by the */ /* player. */ void command(fd, param, str) int fd; int param; char *str; { cmd cmnd; int n; unsigned char ch; /* this logn command will print out all the commands entered by players. It should be used in extreme cases when trying to isolate a players input which may be causing a crash. */ if(RECORD_ALL) logn("all_cmd","\n%s-%d (%d): %s\n",Ply[fd].ply->name,fd,Ply[fd].ply->rom_num,str); switch(param) { case 1: if(F_ISSET(Ply[fd].ply, PHEXLN)) { for(n=0;n<strlen(str);n++) { ch = str[n]; print(fd, "%02X", ch); } print(fd, "\n"); } if(!strcmp(str, "!")) strncpy(str, Ply[fd].extr->lastcommand, 79); if(str[0]) { for(n=0; str[n] && str[n] == ' '; n++) ; strncpy(Ply[fd].extr->lastcommand, &str[n], 79); } strncpy(cmnd.fullstr, str, 255); lowercize(str, 0); parse(str, &cmnd); n = 0; if(cmnd.num) n = process_cmd(fd, &cmnd); else n = PROMPT; if(n == DISCONNECT) { #ifdef WIN32 scwrite(fd, "Goodbye!\n\r\n\r", 11); #else write(fd, "Goodbye!\n\r\n\r", 11); #endif disconnect(fd); return; } else if(n == PROMPT) { ANSI(fd, MAGENTA); if(F_ISSET(Ply[fd].ply, PPROMP)) sprintf(str, "(%d H %d M): ", Ply[fd].ply->hpcur, Ply[fd].ply->mpcur); else strcpy(str, ": "); #ifdef WIN32 scwrite(fd, str, strlen(str)); #else write(fd, str, strlen(str)); #endif /* WIN32 */ ANSI(fd, WHITE); } if(n != DOPROMPT) { RETURN(fd, command, 1); } else return; } } /**********************************************************************/ /* parse */ /**********************************************************************/ /* This function takes the string in the first parameter and breaks it */ /* up into its component words, stripping out useless words. The */ /* resulting words are stored in a command structure pointed to by the */ /* second argument. */ void parse(str, cmnd) char *str; cmd *cmnd; { int i, j, l, m, n, o, art; char tempstr[25]; l = m = n = 0; j = strlen(str); for(i=0; i<=j; i++) { if(str[i] == ' ' || str[i] == '#' || str[i] == 0) { str[i] = 0; /* tokenize */ /* Strip extra white-space */ while((str[i+1] == ' ' || str[i] == '#') && i < j+1) str[++i] = 0; strncpy(tempstr, &str[l], 24); tempstr[24] = 0; l = i+1; if(!strlen(tempstr)) continue; /* Ignore article/useless words */ o = art = 0; while(article[o][0] != '@') { if(!strcmp(article[o++], tempstr)) { art = 1; break; } } if(art) continue; /* Copy into command structure */ if(n == m) { strncpy(cmnd->str[n++], tempstr, 20); cmnd->val[m] = 1L; } else if(isdigit(tempstr[0]) || (tempstr[0] == '-' && isdigit(tempstr[1]))) { cmnd->val[m++] = atol(tempstr); } else { strncpy(cmnd->str[n++], tempstr, 20); cmnd->val[m++] = 1L; } } if(m >= COMMANDMAX) { n = 5; break; } } if(n > m) cmnd->val[m++] = 1L; cmnd->num = n; } /**********************************************************************/ /* process_cmd */ /**********************************************************************/ /* This function takes the command structure of the person at the socket */ /* in the first parameter and interprets the person's command. */ int process_cmd(fd, cmnd) int fd; cmd *cmnd; { int match=0, cmdno=0, c=0; do { if(!strcmp(cmnd->str[0], cmdlist[c].cmdstr)) { match = 1; cmdno = c; break; } else if(!strncmp(cmnd->str[0], cmdlist[c].cmdstr, strlen(cmnd->str[0]))) { match++; cmdno = c; } c++; } while(cmdlist[c].cmdno); if(match == 0) { print(fd, "The command \"%s\" does not exist.\n", cmnd->str[0]); RETURN(fd, command, 1); } else if(match > 1) { print(fd, "Command is not unique.\n"); RETURN(fd, command, 1); } if(cmdlist[cmdno].cmdno < 0) return(special_cmd(Ply[fd].ply, 0-cmdlist[cmdno].cmdno, cmnd)); return((*cmdlist[cmdno].cmdfn)(Ply[fd].ply, cmnd)); } int checkdouble(name) char *name; { char path[128], tempname[80]; FILE *fp; int rtn=0; sprintf(path, "%s/simul/%s", PLAYERPATH, name); fp = fopen(path, "r"); if(!fp) return(0); while(!feof(fp)) { fgets(tempname, 80, fp); tempname[strlen(tempname)-1] = 0; if(!strcmp(tempname, name)) continue; if(find_who(tempname)) { rtn = 1; break; } } fclose(fp); return(rtn); }