/* * Copyright (C) 1999 Peter Amstutz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of *the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA */ #include #include #include #include #include #include #include "tcpcore.h" #include "ai.h" #include "relay.h" #include "terrain.h" #include "aihandlers.h" #include "game.h" #include "packets.h" #include "player.h" #include "log.h" #include "rnd.h" #include "weapons/weapon.h" #include "cfgfile.h" #include "../config.h" #define DEFAULT_PORT 8086 static RNDLIST *name_list; static char *name_array[] = { "Berserkley", "Big Bad Bob", "Bozzy Fear", "Brilton Madley", "C001 D00d!", "Droog", "Drooler", "Eyepop", "Fluffy", "Hairy", "HangOver", "Hercules", "Icky Poo", "Jupiter", "Mars", "Matt-el", "Mercury", "Mother Jones", "Plisher Fice", "RinTinTinBot", "Saga", "Saturn", "Snoopy", "Stuporman", "Terminated-3", "Venus", "WabbitSwayer", "Walkup Apt", "Xena", }; Relay_rl *relay; int svrid, gm_myid = -1; ItemStock_pl *gm_curitem; Player_pl *gm_myplstruct; Gamemode_gm gm_gamemode; char gm_quit = 0; char gm_activate_shots; char gm_stuff_happening; int gm_activeplayers; int gm_currentRound = -1; int gm_totalRounds = -1; char gm_tank_damaged = 0; Gametype_gm gm_gametype = SIMULTANEOUS; int gm_AS_queue[256] = { 0 }; int gm_AS_pos = 0; int gm_death_queue[256] = { 0 }; int gm_dq_pos = 0; int curShooterId=0; int gm_iAmServer = 0; /* total waste of mem */ Player_pl *gm_firing_order[10]; void aiInitialize(int argc, char **argv) { char buf[548]; int sock; char *server = "localhost"; int go; int port = DEFAULT_PORT; char *name = NULL; const char *helptext = " Options:\n \ -sSTR server to connect to (default localhost)\n \ -pINT server port\n \ -nSTR name to join with (otherwise selected from random list)\n \ -lSTR logging level"; char sset = 0, pset = 0, nset = 0, lset = 0; const char *log_str[] = { "critical", "interesting", "debug", "spam", NULL }; const Levels_log log_val[] = { CRITICAL, INTERESTING, DEBUG, SPAM }; logPrintf(INTERESTING, "King of the Hill (KOTH) Moron AI version %s\n", VERSION); logPrintf(INTERESTING, "Copyright (C) 1999 Peter Amstutz\n"); logPrintf(INTERESTING, "Copyright (C) 2002, 2003 Allan Douglas\n"); logPrintf(INTERESTING, "KOTH comes with ABSOLUTELY NO WARRANTY\n"); logPrintf(INTERESTING, "This is free software, and you are welcome to redistribute it\n"); logPrintf(INTERESTING, "under the conditions of the GNU GPL\n"); while(1) { go = getopt(argc, argv, "hs:n:p:l:"); if(go == EOF) break; switch (go) { case 's': server = strdup(optarg); sset = 1; break; case 'n': name = strdup(optarg); nset = 1; break; case 'p': port = atoi(optarg); pset = 1; break; case 'l': lset = 1; if(strcmp(optarg, "critical") == 0) log_level = CRITICAL; else if(strcmp(optarg, "interesting") == 0) log_level = INTERESTING; else if(strcmp(optarg, "debug") == 0) log_level = DEBUG; else if(strcmp(optarg, "spam") == 0) log_level = SPAM; else { lset = 0; logPrintf(CRITICAL, "Bad log level %s\n", optarg); } break; case 'h': logPrintf(INTERESTING, "%s\n", helptext); exit(0); break; default: logPrintf(INTERESTING, "%s\n", helptext); exit(-1); break; } } if(server == NULL) { logPrintf(INTERESTING, "%s\n", helptext); exit(-1); } cfg_configuration = cfgReadConfiguration(DEFAULT_CONFIGFILE); if(cfg_configuration != NULL) { if(!sset) { if(!cfgLoadConfigItemStr(cfg_configuration, "server.host", &server)) { logPrintf(CRITICAL, "No server name found in config file,\n" "trying default %s\n", server); } } if(!pset) { if(!cfgLoadConfigItemInt(cfg_configuration, "server.port", &port)) { logPrintf(CRITICAL, "No port number found in config file,\n" "trying default %d\n", port); } } if(!lset) cfgLoadConfigItemOption(cfg_configuration, "client.logging", log_str, (int *) log_val, (int *) &log_level); } if((sock = tcpDial(server, port)) < 0) { logPrintf(CRITICAL, "Server not responding\n"); exit(-1); } if(sset) free(server); if((relay = rlInit(-1)) == NULL) { logPrintf(CRITICAL, "Error initializing relay code"); exit(-1); } svrid = rlAddConnection(relay, sock); rlSend(relay, svrid, "NP", 2); memset(ter_data, 0, sizeof(ter_data)); rlRegisterHandler(relay, "UT", aihUpdateTerrain); /* chUpdateTerrain() */ rlRegisterHandler(relay, "NT", aihNewTerrain); /* chNewTerrain() */ rlRegisterHandler(relay, "GM", aihSetGameMode); /* chSetGameMode() */ rlRegisterHandler(relay, "MS", aihMessage); /* chMessage() */ rlRegisterHandler(relay, "MC", aihMessage); /* chMessage() */ rlRegisterHandler(relay, "UR", aihGetMyID); /* chGetMyID() */ rlRegisterHandler(relay, "NP", aihNewPlayer); /* chNewPlayer() */ rlRegisterHandler(relay, "ST", aihSetTank); /* chSetTank() */ rlRegisterHandler(relay, "SD", aihSetTank); /* chSetTank() */ rlRegisterHandler(relay, "SF", aihShotFired); /* chShotFired() */ rlRegisterHandler(relay, "CR", aihSetReadiness); /* chChangeReadiness() */ rlRegisterHandler(relay, "SN", aihSetName); /* chSetName() */ rlRegisterHandler(relay, "RP", aihRemovePlayer); /* chRemovePlayer() */ rlRegisterHandler(relay, "AS", aihActivateShots); /* chActivateShots() */ rlRegisterHandler(relay, "BW", aihBuyWeapon); /* chBuyWeapon() */ rlRegisterHandler(relay, "SW", aihSellWeapon); /* chBuyWeapon() */ rlRegisterHandler(relay, "SM", aihSetMoney); /* chSetMoney() */ rlRegisterHandler(relay, "PV", aihCheckProtocolVersion); /* chCheckProtocolVersion() */ rlRegisterHandler(relay, "WS", aiSetWindSpeed); /* chSetWindSpeed() */ rlRegisterHandler(relay, "WT", aiSetWallType); /* chSetWallType() */ rlRegisterHandler(relay, "US", aiUpdateScore); /* chUpdateScore() */ rlRegisterHandler(relay, "NR", aiUpdateRound); /* chUpdateRound() */ rlRegisterHandler(relay, "TR", aiUpdateTotalRounds); /* chUpdateTotalRounds() */ rlRegisterHandler(relay, "UF", aiUpdateFireInfo); rlSetDisconnectFunc(relay, aihQuit); wepInit(); rndInit(); name_list = rndNewList(NEL(name_array), (void **) name_array); if(!name) { name = rndList(name_list); } pl_tankwidth = ter_sizex / TANKSCREENRATIO_X; pl_tankheight = ter_sizey / TANKSCREENRATIO_Y; rlSend(relay, svrid, buf, sprintf(buf, "SN%s", name) + 1); if(nset) free(name); } void aiPregame() { char buf[256]; struct ChangeReady_pkt cr; /* pregame */ sleep(3); /* ** get rid of any weapons if the game is over ** ** check for either current round is 1 or total rounds to cover ** both possible cases of a race condition */ if(((gm_currentRound > gm_totalRounds) || (gm_currentRound == 1)) && gm_totalRounds>0) { plClearAllWeapon(gm_myid); } cr.type[0] = 'C'; cr.type[1] = 'R'; cr.id = gm_myid; cr.r = (ubyte_pkt)READY; rlSend(relay, svrid, buf, pktPackChangeReady(buf, &cr)); while(gm_gamemode == PREGAME && !gm_quit) { rlMain(relay, NULL); } } char time_to_fire = 0; void clTimeToFire(int x) { time_to_fire = 1; } void aiPlaygame() { int i, tcount = 0; char buf[512]; struct Projectilelist_bal *prj; struct FireCmd_pkt sht; struct itimerval it; for(gm_curitem = gm_myplstruct->itemstock; gm_curitem->count == 0; gm_curitem = gm_curitem->next) ; gm_myplstruct->fire_angle = random() % 181; gm_myplstruct->fire_velocity = random() % 1000 + 1; sht.type[0] = 'F'; sht.type[1] = 'S'; sht.a = gm_myplstruct->fire_angle; sht.v = gm_myplstruct->fire_velocity; strcpy(sht.shottype, ((Weapon_wep *) gm_curitem->info)->name); rlSend(relay, svrid, buf, pktPackFireCmd(buf, &sht)); while(((gm_gamemode == INGAME) || (gm_gamemode == POSTGAME && bal_Projectiles)) && !gm_quit) { rlMain(relay, NULL); if(time_to_fire && (gm_gametype == SIMULTANEOUS || curShooterId == gm_myid)) { gm_myplstruct->fire_angle = random() % 181; gm_myplstruct->fire_velocity = random() % 1000 + 1; sht.type[0] = 'F'; sht.type[1] = 'S'; sht.a = gm_myplstruct->fire_angle; sht.v = gm_myplstruct->fire_velocity; strcpy(sht.shottype, ((Weapon_wep *) gm_curitem->info)->name); rlSend(relay, svrid, buf, pktPackFireCmd(buf, &sht)); time_to_fire = 0; } if(gm_AS_pos > 0) { for(prj = bal_Projectiles; prj; prj = prj->next) { if(prj->stat == HOLDING) prj->stat = INITSHOT(prj); } tcount = 0; do { tcount++; gm_stuff_happening = terCalcDirtFall(); if(gm_stuff_happening) plCalcTankFall(); else gm_stuff_happening = plCalcTankFall(); if(gm_stuff_happening) balAdvanceProjectiles(); else gm_stuff_happening = balAdvanceProjectiles(); } while(gm_stuff_happening); signal(SIGALRM, clTimeToFire); it.it_interval.tv_sec = 0; it.it_interval.tv_usec = 0; it.it_value.tv_sec = 0; it.it_value.tv_usec = tcount * 100000; setitimer(ITIMER_REAL, &it, NULL); gm_AS_pos--; for(prj = bal_Projectiles; prj; prj = prj->next) { if(prj->stat == HOLDING && prj->gen == gm_AS_queue[0]) prj->stat = INITSHOT(prj); } for(i = 0; i < gm_AS_pos; i++) gm_AS_queue[i] = gm_AS_queue[i + 1]; } } usleep(tcount * 100000); } /* post game */ void aiPostgame() { char buf[256]; struct ChangeReady_pkt cr; if(gm_currentRound >= gm_totalRounds && gm_totalRounds > 0) { /* the game is over.... get rid of all the weapons */ plClearAllWeapon(gm_myid); } cr.type[0] = 'C'; cr.type[1] = 'R'; cr.id = gm_myid; cr.r = (ubyte_pkt)READY; rlSend(relay, svrid, buf, pktPackChangeReady(buf, &cr)); while(gm_gamemode == POSTGAME && !gm_quit) { logPrintf(DEBUG, "AI in postgame\n"); /* check for the server to change the gamemode */ rlMain(relay, NULL); } } void aiDriverloop() { while(gm_gamemode == NOTPLAYING || gm_myid == -1) rlMain(relay, NULL); gm_myplstruct = plLookupPlayer(gm_myid); while(!gm_quit) { if(gm_gamemode == PREGAME) { aiPregame(); } if(gm_gamemode == INGAME && !gm_quit) { aiPlaygame(); } if(gm_gamemode == POSTGAME && !gm_quit) { aiPostgame(); } } } void aiShutdown() { } /* * Some stub routines. */ void aihDamageReport(Player_pl * hit_pl, int srcid, int amt) { } void aihExplosionHook(Projectilepos_bal * prj) { } int main(int argc, char **argv) { aiInitialize(argc, argv); aiDriverloop(); aiShutdown(); return 0; }