/* * main.c */ #include "copyright.h" #include #include #include #include #include #include #include #include #ifdef hpux #include #else /* hpux */ #include #endif /* hpux */ #ifndef hpux #include #endif /* hpux */ #include "defs.h" #include "struct.h" #include "data.h" #include "packets.h" #include "robot.h" #define TIMEOUT1 50 #define TIMEOUT2 50 char revision[] = "$Revision: 1.3 $"; static int first = 1; jmp_buf env; char *commfile = NULL; main(argc, argv) int argc; char **argv; { int intrupt(), noargs = 0; int team = 1, s_type = CRUISER; int usage = 0; int err = 0; char *name, *ptr, *cp, *rindex(); int dcore(), resetRobot(); void reaper(int), kill_rwatch(int), exitRobot(int); int passive = 0; char *defaultsFile = NULL; register i; int rwatch=0; static int switchedteams=0; char password[64]; int timer2 = 0, tryudp=1; char **_argv = argv; int _argc = argc; if(argc == 1) printUsage(argv[0]); password[0] = '\0'; login[0] = '\0'; strncpy(pseudo, "Marvin", sizeof(pseudo)); pseudo[sizeof(pseudo) - 1] = '\0'; srand(getpid() * time((long *) 0)); srandom(getpid() * time((long *) 0)); name = *argv++; argc--; if ((ptr = rindex(name, '/')) != NULL) name = ptr + 1; while (*argv) { if (**argv == '-') ++* argv; else break; argc--; ptr = *argv++; while (*ptr) { switch (*ptr) { case 'b': /* argv opt, -b : blind, don't read from stdin */ read_stdin = 0; break; case 'c': /* argv opt, -c[sdcbago] : ship type */ ptr++; switch (*ptr) { case 's': s_type = SCOUT; break; case 'd': s_type = DESTROYER; break; case 'c': s_type = CRUISER; break; case 'b': s_type = BATTLESHIP; break; case 'a': s_type = ASSAULT; break; case 'g': s_type = GALAXY; break; case 'o': s_type = STARBASE; break; default: s_type = CRUISER; break; } break; case 'C': /* argv opt, -C file : initial commands file */ commfile = *argv; argv++; argc--; break; case 'g': /* argv opt, -g : tell server we are a robot */ oggv_packet = 1; break; case 'h': /* argv opt, -h server : server host name or ip */ serverName = *argv; argc--; argv++; break; case 'i': /* argv opt, -i : set inl flag */ inl = 1; updates = 2.0; break; case 'I': /* argv opt, -I : ignore lack of t-mode */ ignoreTMode = 1; break; case 'l': /* argv opt, -l logfile : log into log file */ setlog(*argv); argv++; argc--; break; case 'n': /* argv opt, -n name : set robot player name */ strncpy(pseudo, *argv, sizeof(pseudo)); pseudo[sizeof(pseudo) - 1] = '\0'; argv++; argc--; break; case 'o': /* argv opt, -o : override decision making */ override = 1; break; case 'O': /* argv opt, -O : disable robot in-game control password */ nopwd = 1; break; case 'p': /* argv opt, -p port : connect to server port */ if (*argv) { xtrekPort = atoi(*argv); argv++; argc--; } break; case 'q': /* argv opt, -q : unknown */ noargs ++; break; case 'r': /* argv opt, -r file : read from defaults file */ defaultsFile = *argv; argv++; argc--; break; case 'R': /* argv opt, -R : doreserved = 1 */ #ifndef PUBLIC doreserved = 1; #endif break; case 's': /* argv opt, -s port : accept ntserv connection on port */ if (*argv) { xtrekPort = atoi(*argv); passive = 1; argv++; argc--; } break; case 'S': /* argv opt, -S : shmem = 1*/ shmem = 1; break; case 'T': /* argv opt, -T[frko] : set team to join */ ptr++; switch (*ptr) { case 'f': team = FED_N; break; case 'r': team = ROM_N; break; case 'k': team = KLI_N; break; case 'o': team = ORI_N; break; default: team = -1; break; } break; case 'u': /* argv opt, -u updates : set updates per second */ ptr++; mprintf("ptr: %s\n", ptr); sscanf(ptr, "%f", &updates); mprintf("updates at %g (%d per second)\n", updates, (int)(1000000./(updates * 100000.))); ptr += strlen(ptr)-1; break; case 'U': /* argv opt, -U[fs] : set UDP mode */ if(*(ptr+1)){ ptr++; switch(*ptr){ case 'f': udpClientRecv = 2; break; case 's': udpClientRecv = 1; break; } } tryudp++; mprintf("tryudp on, udp recv mode %d\n", udpClientRecv); break; case 'v': /* argv opt, -v : emit usage summary */ usage++; break; case 'w': /* argv opt, -w : trigger rwatch */ rwatch = 1; if(gethostname(rw_host, 80) < 0){ perror("gethostname"); exit(1); } break; #ifdef nodef case 'W': /* argv opt, -W host : set rwatch hostname */ rwatch = 2; strcpy(rw_host, *argv); argv++; argc--; break; #endif case 'x': /* argv opt, -x password : use login password */ strcpy(password, *argv); argv++; argc--; break; case 'X': /* argv opt, -X login : user login name */ strncpy(login, *argv, sizeof(login)); argv++; argc--; break; default: fprintf(stderr, "%s: unknown option '%c'\n", name, *ptr); err++; break; } ptr++; } } initDefaults(defaultsFile); if (usage || err) { printUsage(name); exit(err); } _udcounter = 100; /* should initialize elsewhere */ _udnonsync = 100; _cycleroundtrip = 0; _avsdelay = 0.0; reset_r_info(&team, &s_type, 1, login); /* this creates the necessary x windows for the game */ openmem(); if(rwatch == 1){ if(fork() == 0){ execl("./rwatch", "rwatch", 0); perror("execl"); } for(i=0; i< 10; i++){ sleep(3); if(connectToRWatch(rw_host, 2692) != 0) break; } if(i==10){ fprintf(stderr, "robot: Can't connect through port 2692\n"); exit(1); } } if (!passive) { callServer(xtrekPort, serverName); } else { connectToServer(xtrekPort); } if(noargs){ int pl = strlen(_argv[0]); for(i=0; i< _argc; i++) bzero(_argv[i], strlen(_argv[i])); strncpy(_argv[0], "aiupdate", pl); _argv[0][pl-1] = '\0'; } findslot(); lastm = mctl->mc_current; signal(SIGHUP, exitRobot); signal(SIGTERM, exitRobot); /* TMP signal(SIGBUS, exitRobot); signal(SIGSEGV, exitRobot); */ signal(SIGFPE, exitRobot); (void) signal(SIGCHLD, reaper); signal(SIGPIPE, kill_rwatch); if(!login[0]) strncpy(login, "r1h0", sizeof(login)); if(pseudo[0] == '\0'){ if ((cp = getdefault("name")) != 0) (void) strncpy(pseudo, cp, sizeof(pseudo)); pseudo[sizeof(pseudo) - 1] = '\0'; } mprintf("login ..."); fflush(stdout); if(password[0]) renter(pseudo, password, login); else renter(pseudo, "marvin", login); /* FLAW: cannot send an empty password */ mprintf("\n"); loggedIn = 1; showShields = booleanDefault("showshields", showShields); showStats = booleanDefault("showstats", showStats); keeppeace = 1; reportKills = booleanDefault("reportkills", reportKills); sendOptionsPacket(); if(shmem) shmem_open(); /* * Set p_hostile to hostile, so if keeppeace is on, the guy starts off * hating everyone (like a good fighter should) */ me->p_hostile = (FED | ROM | KLI | ORI); me->p_planets = 0; me->p_genoplanets = 0; me->p_armsbomb = 0; me->p_genoarmsbomb = 0; /* Set up a reasonable default */ me->p_whydead = KQUIT; me->p_team = ALLTEAM; #ifdef PING /* this will always be done once. If the server doesn't support ping packets it will ignore this request */ startPing(); #endif setjmp(env); /* Reentry point of game */ /* give the player the motd and find out which team he wants */ _state.lifetime = 0; if(!reset_r_info(&team, &s_type, first, login)){ sendByeReq(); sleep(1); exit(1); } timer2 = 0; mprintf("team ...\n"); if(!teamRequest(team, s_type)){ switchedteams = 1; mprintf("team or ship rejected.\n"); /* if base destroyed */ if(s_type == STARBASE){ s_type = CRUISER; if(inl){ _state.override = 0; } } showteams(); do { if(teamRequest(team, s_type)) break; if(read_stdin) process_stdin(); #ifdef ATM readFromServer(1); #else readFromServer(); #endif if(_state.command == C_QUIT || timer2 >= TIMEOUT2){ exitRobot(0); } timer2 ++; if(_state.team != -1){ team = getteam(); if(team == -1) timer2 = TIMEOUT2; /* must exit */ } if(team != _state.team && team != -1){ timer2 = 0; _state.team = team; if (!teamRequest(team, s_type)){ switchedteams = 1; mfprintf(stderr, "team or ship rejected.\n"); showteams(); } else break; } } while(1); } set_team(team); me->p_team = team_inttobit(team); getship(myship, s_type); if(!inl && s_type == STARBASE) req_dock_on(); else if(inl && s_type == STARBASE) req_dock_off(); /* til we figure out how to keep it from preempting home planet */ me->p_status = PALIVE; /* Put player in game */ me->p_ghostbuster = 0; if(first) send_initial(); first = 0; if((_state.try_udp || tryudp) && commMode != COMM_UDP){ sendUdpReq(COMM_UDP); } if (switchedteams) { switchedteams = 0; declare_intents(0); /* war and peace */ } else { declare_intents(1); /* peace only */ } input(); } printUsage(prog) char *prog; { static char *list[] = { "network connection options", " -h server : server host name or ip (critical)", " -p port : connect to server port", " -s port : accept ntserv connection on port", " -U[fs] : set UDP mode", "authentication and identification options", " -n name : set robot player name", " -X login : user login name", " -x password : use login password", " -g : tell server we are a robot", "team and ship selection options", " -T[frko] : set team to join", " -c[sdcbago] : ship type", "in-game behaviour options", " -b : blind, don't read from stdin", " -C file : initial commands file", " -I : ignore lack of t-mode", " -O : disable robot in-game control password", " -o : override decision making", " -u updates : set updates per second", "other options", " -i : set inl flag", " -l logfile : log into log file", " -q : unknown", " -r file : read from defaults file", " -R : doreserved = 1", " -S : shmem = 1", " -v : emit usage summary", " -w : trigger rwatch", " -W host : set rwatch hostname", NULL, }; char **s; fprintf(stderr, "usage: %s [options]\n", prog); for(s = list; *s; s++) fprintf(stderr, "%s\n", *s); exit(0); } void reaper(int sig) { #ifdef hpux wait((int *) 0); #else /* hpux */ /* SUPRESS 530 */ while (wait3((int *) 0, WNOHANG, NULL) > 0); #endif /* hpux */ signal(SIGCHLD, reaper); } void exitRobot(int sig) { fprintf(stderr, "robotd: exiting\n"); fflush(stderr); if(shmem) shmem_check(); sendByeReq(); if(sock) shutdown(sock, 2); if(udpSock) shutdown(udpSock, 2); sleep(1); switch(sig){ case SIGBUS: case SIGSEGV: case SIGFPE: abort(); default: exit(0); } } resetRobot() { fprintf(stderr, "BUS or SEGV\n"); _state.command = C_RESET; longjmp(env,0); } dcore() { abort(); } void kill_rwatch(int sig) { if(rsock != -1){ shutdown(rsock, 2); rsock = -1; } fprintf(stderr, "shutting down rwatch on SIGPIPE\n"); /* exit otherwise? */ } getteam() { int nf= -1, nk= -1, nr= -1, no= -1; if(tournMask & FED){ nf = realNumShips(FED); } if(tournMask & ROM){ nr = realNumShips(ROM); } if(tournMask & KLI){ nk = realNumShips(KLI); } if(tournMask & ORI){ no = realNumShips(ORI); } if(nf > -1 && nr > -1){ if(nf < nr) return FED_N; else return ROM_N; } if(nf > -1 && no > -1){ if(nf < no) return FED_N; else return ORI_N; } if(nk > -1 && nr > -1){ if(nk < nr) return KLI_N; else return ROM_N; } if(nk > -1 && no > -1){ if(nk < no) return KLI_N; else return ORI_N; } if(nf > 0) return FED_N; if(nr > 0) return ROM_N; if(nk > 0) return KLI_N; if(no > 0) return ORI_N; if(nf == 0) return FED_N; if(nr == 0) return ROM_N; if(nk == 0) return KLI_N; if(no == 0) return ORI_N; return -1; }