/* * 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 #include #include #include #include "tcpcore.h" #include "relay.h" #include "terrain.h" #include "gfx.h" #include "game.h" #include "player.h" #include "packets.h" #include "ballistics.h" #include "text.h" #include "ai.h" #include "log.h" char aih_weaponbuylock = 0; /* sets game mode from the server */ void aihSetGameMode(Relay_rl * rl, int id, char *pkt, int pktlen) { struct SetGameMode_pkt sgm; pktUnpackSetGameMode(&sgm, pkt); gm_gamemode = sgm.gamemode; } /* sets game type from the server */ void aiSetGameType(Relay_rl* rl, int id, char *pkt, int pktlen) { struct SetGameMode_pkt sgm; pktUnpackSetGameMode(&sgm, pkt); gm_gametype=sgm.gamemode; } /* gets this clients game mode from the server */ void aihGetMyID(Relay_rl * rl, int id, char *pkt, int pktlen) { struct PlayerID_pkt pid; pktUnpackPlayerID(&pid, pkt); gm_myid = pid.id; } /* adds a new player that has just logged on to the local player list */ void aihNewPlayer(Relay_rl * rl, int id, char *pkt, int pktlen) { struct NewPlayer_pkt nppkt; Player_pl *pl; pktUnpackNewPlayer(&nppkt, pkt); if(plLookupPlayer(nppkt.id)) /* yes, this can happen */ return; pl = plCreatePlayer(); pl->itemstock->activate = NULL; pl->id = nppkt.id; pl->ready = nppkt.ready; pl->name = strdup(nppkt.name); pl->tankcolor = nppkt.color; pl->score = 0; pl->roundScore = 0; } /* removes a player from the local list that has left */ void aihRemovePlayer(Relay_rl * rl, int id, char *pkt, int pktlen) { Player_pl *pcur; struct PlayerID_pkt pid; pktUnpackPlayerID(&pid, pkt); pcur = plLookupPlayer(pid.id); if(!pcur) /* not logged in yet */ return; if(gm_gamemode == INGAME && pcur->ready == READY && !gm_stuff_happening) { register struct Projectilelist_bal *prj; for(prj = bal_Projectiles; prj; prj = prj->next) { if(prj->prjpos.id == pid.id) { prj->stat = FREEING; } } } if(pl_begin == pcur) pl_begin = pcur->next; if(pl_end == pcur) pl_end = pcur->prev; if(pcur->prev) pcur->prev->next = pcur->next; if(pcur->next) pcur->next->prev = pcur->prev; free(pcur); } /* reads in new terrain data from the server */ void aihUpdateTerrain(Relay_rl * rl, int id, char *pkt, int pktlen) { TerrainSpans_ter *tmp = NULL; unsigned i, n; struct UpdateTerrain_pkt inpkt; pktUnpackUpdateTerrain(&inpkt, pkt); for(i = 0, n = inpkt.startpos; i < inpkt.length; i += 2) { if(inpkt.ter[i] == 0) tmp = &ter_data[n++]; terAddSpan(tmp, inpkt.ter[i], inpkt.ter[i + 1]); } } /* server has told the clients to request new terrain data. client acks by formally requesting the new terrain data (handled above) */ void aihNewTerrain(Relay_rl * rl, int id, char *pkt, int pktlen) { unsigned i; struct TerrainInfo_pkt ti; pktUnpackTerrainInfo(&ti, pkt); ter_sizex = ti.sizex; ter_sizey = ti.sizey; bal_lerp_tweak = ((double) ti.lerp_tweak) / ((double) 0xFFFF); bal_grav = ((double) ti.grav) / ((double) 0xFFFF); for(i = 0; i < ter_sizex; i++) terFreeCol(ter_data[i].nexthigher); memset(ter_data, 0, sizeof(ter_data)); rlSend(rl, id, "GT", 2); } /* general purpose system messages / aihatting */ void aihMessage(Relay_rl * rl, int id, char *pkt, int pktlen) { struct Message_pkt mspkt; struct ColoredMessage_pkt mcpkt; if(pkt[1] == 'S') { pktUnpackMessage(&mspkt, pkt); mcpkt.color = 0; strcpy(mcpkt.message, mspkt.message); } if(pkt[1] == 'C') pktUnpackColoredMessage(&mcpkt, pkt); } /* Sets some player's name. */ void aihSetName(Relay_rl * rl, int id, char *pkt, int pktlen) { struct SetName_pkt snpkt; Player_pl *pcur; pktUnpackSetName(&snpkt, pkt); pcur = plLookupPlayer(snpkt.id); if(!pcur) /* not logged in yet */ return; if(pcur->name) free(pcur->name); pcur->name = strdup(snpkt.name); } /* client lost connection to the server */ void aihQuit(Relay_rl * rl, int id) { logPrintf(CRITICAL, "Server disconnected\n"); gm_quit = 1; } /* sets some tank's position */ void aihSetTank(Relay_rl * rl, int id, char *pkt, int pktlen) { Player_pl *pcur; struct SetTank_pkt stpkt; pktUnpackSetTank(&stpkt, pkt); pcur = plLookupPlayer(stpkt.id); assert(pcur); pcur->x = stpkt.x; pcur->y = stpkt.y; pcur->ox = stpkt.x; pcur->oy = stpkt.y; if(stpkt.type[1] == 'T') { pcur->fire_angle = stpkt.a; pcur->fire_velocity = stpkt.v; } pcur->barreloff_x = pcur->fire_angle < 90 ? pcur->barreloff_right : pcur->barreloff_left; pcur->armor = stpkt.armor; if(stpkt.id == gm_myid) gm_tank_damaged = 1; } /* a shot has been fired; add this shot to the list of projectiles in the air (balNewShot()) */ void aihShotFired(Relay_rl * rl, int id, char *pkt, int pktlen) { Player_pl *pl; struct FireCmd_pkt sht; Weapon_wep *wp; pktUnpackFireCmd(&sht, pkt); wp = wepLookupWeapon(sht.shottype); if(wp) { pl = plLookupPlayer(sht.id); if(!pl) return; pl->fire_angle = sht.a; pl->barreloff_x = pl->fire_angle < 90 ? pl->barreloff_right : pl->barreloff_left; pl->fire_velocity = sht.v; balNewShotAV(sht.id, sht.gen, pl->x + pl->barreloff_x + pl_barrelen * cos((pl->fire_angle / 180.0) * M_PI), pl->y + pl->barreloff_y + pl_barrelen * sin((pl->fire_angle / 180.0) * M_PI), pl->fire_angle, pl->fire_velocity, wp); if(sht.id == gm_myid) { if(plUseWeaponInStock(plLookupPlayer(gm_myid), wp, 1) <= 1) { for(gm_curitem = gm_curitem->next; gm_curitem->count <= 0; gm_curitem = gm_curitem->next) ; } } } } /* changes the readiness of some tank in the local player list */ void aihSetReadiness(Relay_rl * rl, int id, char *pkt, int pktlen) { struct ChangeReady_pkt chpkt; Player_pl *pl; pktUnpackChangeReady(&chpkt, pkt); pl = plLookupPlayer(chpkt.id); if(!pl) /* not logged in yet */ return; pl->ready = chpkt.r; if(gm_gamemode == PREGAME && pl == gm_myplstruct && pl->ready != READY) { rlSend(rl, id, "RD", 2); } } void aihActivateShots(Relay_rl * rl, int id, char *pkt, int pktlen) { struct PlayerID_pkt gen; pktUnpackPlayerID(&gen, pkt); gm_AS_queue[gm_AS_pos++] = gen.id; } void aihBuyWeapon(Relay_rl * rl, int id, char *pkt, int pktlen) { struct BuyWeapon_pkt bw; pktUnpackBuyWeapon(&bw, pkt); if(bw.count > 0) plBuyWeapon(gm_myid, bw.weapontype, bw.count, NULL); aih_weaponbuylock = 0; } void aihSellWeapon(Relay_rl * rl, int id, char *pkt, int pktlen) { struct BuyWeapon_pkt bw; pktUnpackBuyWeapon(&bw, pkt); if(bw.count > 0) plSellWeapon(gm_myid, bw.weapontype, bw.count); aih_weaponbuylock = 0; } void aihSetMoney(Relay_rl * rl, int id, char *pkt, int pktlen) { struct PlayerID_pkt pid; pktUnpackPlayerID(&pid, pkt); plLookupPlayer(gm_myid)->money = pid.id; } void aihCheckProtocolVersion(Relay_rl * rl, int id, char *pkt, int pktlen) { struct PlayerID_pkt pid; pktUnpackPlayerID(&pid, pkt); if(pid.id != PROTOCOL_VERSION) { logPrintf(CRITICAL, "Error! Server is using version %i protocol\n", pid.id); logPrintf(CRITICAL, "and client speaks version %i protocol.\n", PROTOCOL_VERSION); logPrintf(CRITICAL, "Cannot connect to this server.\n"); exit(1); } } void aiUpdateScore(Relay_rl * rl, int id, char *pkt, int pktlen) { struct Score_pkt scpkt; Player_pl *pl; pktUnpackScore(&scpkt, pkt); pl = plLookupPlayer(scpkt.id); if(!pl) return; pl->score = scpkt.score; pl->roundScore = scpkt.roundScore; } /* sets round number from the server */ void aiUpdateRound(Relay_rl * rl, int id, char *pkt, int pktlen) { struct PlayerID_pkt nrpkt; pktUnpackPlayerID(&nrpkt, pkt); gm_currentRound = nrpkt.id; } /* sets total rounds from the server */ void aiUpdateTotalRounds(Relay_rl * rl, int id, char *pkt, int pktlen) { struct PlayerID_pkt nrpkt; pktUnpackPlayerID(&nrpkt, pkt); gm_totalRounds = nrpkt.id; } void aiSetWindSpeed(Relay_rl * rl, int id, char *pkt, int pktlen) { struct PlayerID_pkt ws; pktUnpackWindSpeed(&ws, pkt); bal_wind = ws.id; } void aiSetWallType(Relay_rl * rl, int id, char *pkt, int pktlen) { struct PlayerID_pkt ws; pktUnpackWallType(&ws, pkt); bal_wall = (WallTypes_bal) ws.id; } /* ** update fire info... sent by server when: ** simultaneous mode - everyone has fired ** turn mode - after each player fires */ void aiUpdateFireInfo(Relay_rl* rl, int id, char *pkt, int pktlen) { struct PlayerID_pkt nrpkt; Player_pl *pcur; pktUnpackPlayerID(&nrpkt, pkt); curShooterId=nrpkt.id; /* if in simultaneous mode */ if(gm_gametype == SIMULTANEOUS) { /* clear every player's fired data */ for(pcur=pl_begin; pcur; pcur=pcur->next) { pcur->fired=0; } } }