[Opentnl-cvs] tnl/zap CTFGame.cpp,NONE,1.1 CTFGame.h,NONE,1.1 Makefile,NONE,1.1 SweptEllipsoid.cpp,N
Brought to you by:
mark_frohnmayer,
s_alanet
Update of /cvsroot/opentnl/tnl/zap In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31063/zap Added Files: CTFGame.cpp CTFGame.h Makefile SweptEllipsoid.cpp SweptEllipsoid.h UI.cpp UI.h UIGame.cpp UIGame.h UIMenus.cpp UIMenus.h UINameEntry.cpp UINameEntry.h UIQueryServers.cpp UIQueryServers.h ZAP.vcproj barrier.cpp barrier.h game.cpp game.h gameConnection.cpp gameConnection.h gameLoader.cpp gameLoader.h gameNetInterface.cpp gameNetInterface.h gameObject.cpp gameObject.h gameType.cpp gameType.h gridDB.cpp gridDB.h item.cpp item.h main.cpp masterConnection.cpp masterConnection.h moveObject.cpp moveObject.h point.h projectile.cpp projectile.h sfx.cpp sfx.h ship.cpp ship.h sparkManager.cpp sparkManager.h teleporter.cpp teleporter.h winmain.cpp zap.dsp Log Message: Initial commit. --- NEW FILE: main.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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 "../tnl/tnl.h" #include "../tnl/tnlRandom.h" #include "../tnl/tnlGhostConnection.h" #include "../tnl/tnlNetInterface.h" #include "glutInclude.h" #include <stdarg.h> using namespace TNL; #include "UI.h" #include "UIGame.h" #include "UINameEntry.h" #include "UIMenus.h" #include "game.h" #include "gameNetInterface.h" #include "masterConnection.h" #include "sfx.h" namespace Zap { bool gQuit = false; bool gIsServer = false; const char *gHostName = "ZAP Game"; U32 gMaxPlayers = 128; Address gMasterAddress("127.0.0.1:28999"); void reshape(int nw, int nh) { UserInterface::windowWidth = nw; UserInterface::windowHeight = nh; } void motion(int x, int y) { if(UserInterface::current) UserInterface::current->onMouseDragged(x, y); } void passivemotion(int x, int y) { if(UserInterface::current) UserInterface::current->onMouseMoved(x, y); } void key(unsigned char key, int x, int y) { if(UserInterface::current) UserInterface::current->onKeyDown(key); } void keyup(unsigned char key, int x, int y) { if(UserInterface::current) UserInterface::current->onKeyUp(key); } void mouse(int button, int state, int x, int y) { static int mouseState=0; logprintf("button=%d state=%d", button, state); if(UserInterface::current) if(state==1 && !mouseState) { UserInterface::current->onMouseUp(x, y); mouseState = 0; } else { mouseState = state; UserInterface::current->onMouseDown(x, y); } } void specialkey(int key, int x, int y) { if(UserInterface::current) UserInterface::current->onSpecialKeyDown(key); } void specialkeyup(int key, int x, int y) { if(UserInterface::current) UserInterface::current->onSpecialKeyUp(key); } void idle() { static S64 lastTimer = Platform::getHighPrecisionTimerValue(); static F64 unusedFraction = 0; S64 currentTimer = Platform::getHighPrecisionTimerValue(); F64 timeElapsed = Platform::getHighPrecisionMilliseconds(currentTimer - lastTimer) + unusedFraction; U32 integerTime = timeElapsed; if(integerTime >= 10) { lastTimer = currentTimer; unusedFraction = timeElapsed - integerTime; if(UserInterface::current) UserInterface::current->idle(integerTime); if(gClientGame) gClientGame->idle(integerTime); if(gServerGame) gServerGame->idle(integerTime); if(gClientGame) glutPostRedisplay(); } // Sleep a bit so we don't saturate the system. Platform::sleep(1); } void dedicatedServerLoop() { for(;;) idle(); } void display(void) { if(UserInterface::current) UserInterface::current->render(); glFlush(); glutSwapBuffers(); } #include <stdio.h> class StdoutLogConsumer : public LogConsumer { public: void logString(const char *string) { printf("%s\r\n", string); } } gStdoutLogConsumer; void hostGame(bool dedicated, Address bindAddress) { gServerGame = new ServerGame(bindAddress, gMaxPlayers, gHostName); if(!dedicated) joinGame(Address(), false, true); } void joinGame(Address remoteAddress, bool isFromMaster, bool local) { if(isFromMaster && gClientGame->getConnectionToMaster()) { gClientGame->getConnectionToMaster()->requestArrangedConnection(remoteAddress); gGameUserInterface.activate(); } else { GameConnection *theConnection = new GameConnection(gClientGame); gClientGame->setConnectionToServer(theConnection); const char *name = gNameEntryUserInterface.getText(); if(!name[0]) name = "Playa"; theConnection->setPlayerName(name); if(local) theConnection->connectLocal(gClientGame->getNetInterface(), gServerGame->getNetInterface()); else theConnection->connect(gClientGame->getNetInterface(), remoteAddress); gGameUserInterface.activate(); } } void endGame() { if(gClientGame && gClientGame->getConnectionToMaster()) gClientGame->getConnectionToMaster()->cancelArrangedConnectionAttempt(); if(gClientGame && gClientGame->getConnectionToServer()) gClientGame->getConnectionToServer()->disconnect(""); delete gServerGame; gServerGame = NULL; } void onExit() { endGame(); SFXObject::shutdown(); } }; using namespace Zap; int main(int argc, char **argv) { TNLLogEnable(LogNetInterface, true); bool hasClient = true; bool hasServer = false; bool connectLocal = false; bool connectRemote = false; bool nameSet = false; Address connectAddress; Address bindAddress(IPProtocol, Address::Any, 28000); U32 maxPlayers = 128; for(S32 i = 1; i < argc;i+=2) { bool hasAdditionalArg = (i != argc - 1); if(!stricmp(argv[i], "-server")) { hasServer = true; connectLocal = true; if(hasAdditionalArg) bindAddress.set(argv[i+1]); } else if(!stricmp(argv[i], "-connect")) { connectRemote = true; if(hasAdditionalArg) connectAddress.set(argv[i+1]); } else if(!stricmp(argv[i], "-master")) { if(hasAdditionalArg) gMasterAddress.set(argv[i+1]); } else if(!stricmp(argv[i], "-dedicated")) { hasClient = false; hasServer = true; if(hasAdditionalArg) bindAddress.set(argv[i+1]); } else if(!stricmp(argv[i], "-name")) { if(hasAdditionalArg) { nameSet = true; gNameEntryUserInterface.setText(argv[i+1]); } } else if(!stricmp(argv[i], "-hostname")) { if(hasAdditionalArg) gHostName = argv[i+1]; } else if(!stricmp(argv[i], "-maxplayers")) { if(hasAdditionalArg) gMaxPlayers = atoi(argv[i+1]); } } if(hasClient) gClientGame = new ClientGame(Address()); if(hasServer) hostGame(hasClient == false, bindAddress); else if(connectRemote) joinGame(connectAddress, false); if(!connectLocal && !connectRemote) { if(!nameSet) gNameEntryUserInterface.activate(); else gMainMenuUserInterface.activate(); } if(hasClient) { SFXObject::init(); glutInitWindowSize(800, 600); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB); glutCreateWindow("ZAP II - The Return"); glutDisplayFunc(display); glutReshapeFunc(reshape); glutPassiveMotionFunc(passivemotion); glutMotionFunc(passivemotion); glutKeyboardFunc(key); glutKeyboardUpFunc(keyup); glutSpecialFunc(specialkey); glutSpecialUpFunc(specialkeyup); glutMouseFunc(mouse); glutIdleFunc(idle); glutSetCursor(GLUT_CURSOR_NONE); glMatrixMode(GL_PROJECTION); glOrtho(0, 800, 600, 0, 0, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(400, 300, 0); atexit(endGame); glutMainLoop(); } else { dedicatedServerLoop(); } return 0; } --- NEW FILE: gameType.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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 "gameType.h" #include "ship.h" #include "UIGame.h" #include "gameNetInterface.h" namespace Zap { TNL_IMPLEMENT_NETOBJECT(GameType); GameType::GameType() { mNetFlags.set(Ghostable); } void GameType::processArguments(S32 argc, const char **argv) { } void GameType::onAddedToGame(Game *theGame) { theGame->setGameType(this); setInterface(theGame->getNetInterface()); if(!isGhost()) setScopeAlways(); } bool GameType::processLevelItem(S32 argc, const char **argv) { if(!stricmp(argv[0], "Team")) { if(argc < 5) return false; Team t; t.numPlayers = 0; t.name.set(argv[1]); t.color.read(argv + 2); mTeams.push_back(t); } else if(!stricmp(argv[0], "Spawn")) { if(argc < 4) return false; S32 teamIndex = atoi(argv[1]); Point p; p.read(argv + 2); p *= getGame()->getGridSize(); if(teamIndex >= 0 && teamIndex < mTeams.size()) mTeams[teamIndex].spawnPoints.push_back(p); } else return false; return true; } S32 GameType::findClientIndexByConnection(GameConnection *theConnection) { for(S32 clientIndex = 0; clientIndex < mClientList.size(); clientIndex++) if(mClientList[clientIndex].clientConnection == theConnection) return clientIndex; return -1; } S32 GameType::findClientIndexById(U32 clientId) { for(S32 clientIndex = 0; clientIndex < mClientList.size(); clientIndex++) if(mClientList[clientIndex].clientId == clientId) return clientIndex; return -1; } void GameType::spawnShip(GameConnection *theClient) { S32 clientIndex = findClientIndexByConnection(theClient); S32 teamIndex = mClientList[clientIndex].teamId; Point spawnPoint; S32 spawnIndex = Random::readI() % mTeams[teamIndex].spawnPoints.size(); spawnPoint = mTeams[teamIndex].spawnPoints[spawnIndex]; Ship *newShip = new Ship(spawnPoint, mTeams[teamIndex].color); newShip->addToGame(getGame()); theClient->setControlObject(newShip); } void GameType::serverAddClient(GameConnection *theClient) { ClientRef cref; cref.clientId = theClient->mClientId; cref.name = theClient->playerName; cref.clientConnection = theClient; U32 minPlayers = mTeams[0].numPlayers; S32 minTeamIndex = 0; for(S32 i = 1; i < mTeams.size(); i++) { if(mTeams[i].numPlayers < minPlayers) { minTeamIndex = i; minPlayers = mTeams[i].numPlayers; } } cref.teamId = minTeamIndex; mClientList.push_back(cref); mTeams[cref.teamId].numPlayers++; s2cAddClient(cref.clientId, cref.name, false); s2cClientJoinedTeam(cref.clientId, cref.teamId); spawnShip(theClient); } void GameType::controlObjectForClientKilled(GameConnection *theClient) { spawnShip(theClient); } void GameType::addClientGameMenuOptions(Vector<const char *> &menuOptions) { if(mTeams.size() > 1) menuOptions.push_back("CHANGE TEAMS"); } void GameType::processClientGameMenuOption(U32 index) { if(index == 0) c2sChangeTeams(); } TNL_IMPLEMENT_NETOBJECT_RPC(GameType, s2cAddClient, (U32 id, StringTableEntry name, bool isMyClient), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhost, 0) { ClientRef cref; cref.clientId = id; cref.name = name; cref.teamId = 0; mClientList.push_back(cref); if(isMyClient) mThisClientId = id; gGameUserInterface.displayMessage(Color(0.6f, 0.6f, 0.8f), "%s joined the game.", name.getString()); } void GameType::serverRemoveClient(GameConnection *theClient) { S32 clientIndex = findClientIndexByConnection(theClient); mTeams[mClientList[clientIndex].teamId].numPlayers--; mClientList.erase(clientIndex); GameObject *theControlObject = theClient->getControlObject(); if(theControlObject) delete theControlObject; s2cRemoveClient(theClient->mClientId); } TNL_IMPLEMENT_NETOBJECT_RPC(GameType, s2cRemoveClient, (U32 id), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhost, 0) { S32 clientIndex = findClientIndexById(id); mClientList.erase(clientIndex); } TNL_IMPLEMENT_NETOBJECT_RPC(GameType, s2cAddTeam, (StringTableEntry teamName, F32 r, F32 g, F32 b), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhost, 0) { Team team; team.name = teamName; team.color.r = r; team.color.g = g; team.color.b = b; mTeams.push_back(team); } TNL_IMPLEMENT_NETOBJECT_RPC(GameType, s2cSetTeamScore, (U32 teamIndex, U32 score), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhost, 0) { mTeams[teamIndex].score = score; } TNL_IMPLEMENT_NETOBJECT_RPC(GameType, s2cClientJoinedTeam, (U32 clientId, U32 teamIndex), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhost, 0) { S32 clientIndex = findClientIndexById(clientId); mClientList[clientIndex].teamId = teamIndex; gGameUserInterface.displayMessage(Color(0.6f, 0.6f, 0.8f), "%s joined team %s.", mClientList[clientIndex].name.getString(), mTeams[teamIndex].name.getString()); } TNL_IMPLEMENT_NETOBJECT_RPC(GameType, c2sChangeTeams, (), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhostParent, 0) { if(mTeams.size() <= 1) return; GameConnection *source = (GameConnection *) NetObject::getRPCSourceConnection(); S32 clientIndex = findClientIndexByConnection(source); // destroy the old ship GameObject *co = source->getControlObject(); if(co) getGame()->deleteObject(co); U32 newTeamId = (mClientList[clientIndex].teamId + 1) % mTeams.size(); mClientList[clientIndex].teamId = newTeamId; s2cClientJoinedTeam(mClientList[clientIndex].clientId, newTeamId); spawnShip(source); } void GameType::onGhostAvailable(GhostConnection *theConnection) { NetObject::setRPCDestConnection(theConnection); for(S32 i = 0; i < mTeams.size(); i++) { s2cAddTeam(mTeams[i].name, mTeams[i].color.r, mTeams[i].color.g, mTeams[i].color.b); s2cSetTeamScore(i, mTeams[i].score); } // add all the client and team information for(S32 i = 0; i < mClientList.size(); i++) { s2cAddClient(mClientList[i].clientId, mClientList[i].name, mClientList[i].clientConnection == theConnection); s2cClientJoinedTeam(mClientList[i].clientId, mClientList[i].teamId); } NetObject::setRPCDestConnection(NULL); } TNL_IMPLEMENT_NETOBJECT_RPC(GameType, c2sSendChat, (bool global, const char *message), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhostParent, 0) { GameConnection *source = (GameConnection *) getRPCSourceConnection(); RefPtr<NetEvent> theEvent = TNL_RPC_CONSTRUCT_NETEVENT(this, s2cDisplayChatMessage, (global, source->playerName, message)); for(S32 i = 0; i < mClientList.size(); i++) mClientList[i].clientConnection->postNetEvent(theEvent); } extern Color gGlobalChatColor; extern Color gTeamChatColor; TNL_IMPLEMENT_NETOBJECT_RPC(GameType, s2cDisplayChatMessage, (bool global, StringTableEntry clientName, const char *message), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhost, 0) { Color theColor = global ? gGlobalChatColor : gTeamChatColor; gGameUserInterface.displayMessage(theColor, "%s: %s", clientName.getString(), message); } }; --- NEW FILE: gameLoader.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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 "gameLoader.h" #include "../tnl/tnlPlatform.h" #include <stdio.h> namespace Zap { enum { MaxArgc = 128, MaxArgLen = 100, }; static char *argv[MaxArgc]; static char argv_buffer[MaxArgc][MaxArgLen]; static int argc; static int argLen = 0; static const char *argString; inline char getNextChar() { while(*argString == '\r') argString++; return *argString++; } inline void addCharToArg(char c) { if(argc < MaxArgc && argLen < MaxArgLen-1) { argv[argc][argLen] = c; argLen++; } } inline void addArg() { if(argc < MaxArgc) { argv[argc][argLen] = 0; argc++; argLen = 0; } } int parseArgs(const char *string, ServerGame *g) { int numObjects = 0; argc = 0; argLen = 0; argString = string; char c; for(U32 i = 0; i < MaxArgc; i++) argv[i] = argv_buffer[i]; stateEatingWhitespace: c = getNextChar(); if(c == ' ' || c == '\t') goto stateEatingWhitespace; if(c == '\n' || !c) goto stateLineParseDone; if(c == '\"') goto stateReadString; if(c == '#') goto stateEatingComment; stateAddCharToIdent: addCharToArg(c); c = getNextChar(); if(c == ' ' || c == '\t') { addArg(); goto stateEatingWhitespace; } if(c == '\n' || !c) { addArg(); goto stateLineParseDone; } if(c == '\"') { addArg(); goto stateReadString; } goto stateAddCharToIdent; stateReadString: c = getNextChar(); if(c == '\"') { addArg(); goto stateEatingWhitespace; } if(c == '\n' || !c) { addArg(); goto stateLineParseDone; } if(c == '\\') { c = getNextChar(); if(c == 'n') { addCharToArg('\n'); goto stateReadString; } if(c == 't') { addCharToArg('\t'); goto stateReadString; } if(c == '\\') { addCharToArg('\\'); goto stateReadString; } if(c == '\n' || !c) { addArg(); goto stateLineParseDone; } } addCharToArg(c); goto stateReadString; stateEatingComment: c = getNextChar(); if(c != '\n' && c) goto stateEatingComment; stateLineParseDone: if(argc) g->processLevelLoadLine(argc, (const char **) argv); argc = 0; argLen = 0; if(c) goto stateEatingWhitespace; return numObjects; } void GameLoader::initGameFromFile(ServerGame *g, const char *file) { FILE *f = fopen(file, "r"); if(!f) return; char fileData[32768]; size_t bytesRead = fread(fileData, 1, sizeof(fileData), f); fileData[bytesRead] = 0; parseArgs(fileData, g); fclose(f); } }; --- NEW FILE: UI.h --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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 // //------------------------------------------------------------------------------------ #ifndef _UI_H_ #define _UI_H_ #include "../tnl/tnl.h" using namespace TNL; namespace Zap { class UserInterface { public: static UserInterface *current; static F32 windowWidth, windowHeight, canvasWidth, canvasHeight; virtual void render(); virtual void idle(U32 timeDelta); virtual void onActivate(); void activate(); virtual void onMouseDown(S32 x, S32 y); virtual void onMouseUp(S32 x, S32 y); virtual void onMouseMoved(S32 x, S32 y); virtual void onMouseDragged(S32 x, S32 y); virtual void onKeyDown(U32 key); virtual void onKeyUp(U32 key); virtual void onSpecialKeyDown(U32 key); virtual void onSpecialKeyUp(U32 key); static void drawString(S32 x, S32 y, S32 size, const char *string); static void drawCenteredString(S32 y, S32 size, const char *string); static void drawStringf(S32 x, S32 y, S32 size, const char *fmt, ...); static U32 getStringWidth(S32 size, const char *string, U32 len = 0); }; }; #endif --- NEW FILE: UIQueryServers.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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 "UIQueryServers.h" #include "UIMenus.h" #include "tnlRandom.h" #include "masterConnection.h" #include "gameNetInterface.h" #include "glutInclude.h" #include "game.h" namespace Zap { QueryServersUserInterface gQueryServersUserInterface; void QueryServersUserInterface::onActivate() { servers.clear(); sortColumn = 0; pendingPings = 0; pendingQueries = 0; sortAscending = true; mNonce.getRandom(); logprintf("pinging broadcast servers..."); Address broadcastAddress(IPProtocol, Address::Broadcast, 28000); broadcastPingSendTime = Platform::getRealMilliseconds(); gClientGame->getNetInterface()->sendPing(broadcastAddress, mNonce); if(gClientGame->getConnectionToMaster()) gClientGame->getConnectionToMaster()->startGameTypesQuery(); } void QueryServersUserInterface::addPingServers(const Vector<IPAddress> &ipList) { for(S32 i = 0; i < ipList.size(); i++) { ServerRef s; s.state = ServerRef::Start; s.id = ++lastUsedServerId; s.sendNonce.getRandom(); s.serverAddress.set(ipList[i]); s.sendCount = 0; s.pingTime = 9999; s.playerCount = s.maxPlayers = -1; s.isFromMaster = true; strcpy(s.serverName, "Internet Server"); servers.push_back(s); } } void QueryServersUserInterface::gotPingResponse(const Address &theAddress, const Nonce &theNonce, U32 clientIdentityToken) { // see if this ping is a server from the local broadcast ping: if(mNonce == theNonce) { for(S32 i = 0; i < servers.size(); i++) if(servers[i].sendNonce == theNonce && servers[i].serverAddress == theAddress) return; // it was from a local ping ServerRef s; s.pingTime = Platform::getRealMilliseconds() - broadcastPingSendTime; s.state = ServerRef::ReceivedPing; s.id = ++lastUsedServerId; s.sendNonce = theNonce; s.identityToken = clientIdentityToken; s.serverAddress = theAddress; s.sendCount = 0; s.playerCount = -1; s.maxPlayers = -1; s.isFromMaster = false; strcpy(s.serverName, "LAN Server"); servers.push_back(s); return; } // see if this ping is in the list: for(S32 i = 0; i < servers.size(); i++) { ServerRef &s = servers[i]; if(s.sendNonce == theNonce && s.serverAddress == theAddress && s.state == ServerRef::SentPing) { s.pingTime = Platform::getRealMilliseconds() - s.lastSendTime; s.state = ServerRef::ReceivedPing; s.identityToken = clientIdentityToken; pendingPings--; break; } } shouldSort = true; } void QueryServersUserInterface::gotQueryResponse(const Address &theAddress, const Nonce &clientNonce, const char *serverName, U32 playerCount, U32 maxPlayers) { for(S32 i = 0; i < servers.size(); i++) { ServerRef &s = servers[i]; if(s.sendNonce == clientNonce && s.serverAddress == theAddress && s.state == ServerRef::SentQuery) { s.playerCount = playerCount; s.maxPlayers = maxPlayers; dSprintf(s.serverName, sizeof(s.serverName), "%s", serverName); s.state = ServerRef::ReceivedQuery; pendingQueries--; } } shouldSort = true; // find this } void QueryServersUserInterface::idle(U32 t) { U32 time = Platform::getRealMilliseconds(); for(S32 i = 0; i < servers.size(); i++) { ServerRef &s = servers[i]; if(s.state == ServerRef::SentPing && (time - s.lastSendTime) > PingQueryTimeout) { s.state = ServerRef::Start; pendingPings--; } else if(s.state == ServerRef::SentQuery && (time - s.lastSendTime) > PingQueryTimeout) { s.state = ServerRef::ReceivedPing; pendingQueries--; } } if(pendingPings < MaxPendingPings) { for(S32 i = 0; i < servers.size() ; i++) { ServerRef &s = servers[i]; if(s.state == ServerRef::Start) { s.sendCount++; if(s.sendCount > PingQueryRetryCount) { s.pingTime = 999; strcpy(s.serverName, "PingTimedOut"); s.playerCount = 0; s.maxPlayers = 0; s.state = ServerRef::ReceivedQuery; shouldSort = true; } else { s.state = ServerRef::SentPing; s.lastSendTime = time; s.sendNonce.getRandom(); gClientGame->getNetInterface()->sendPing(s.serverAddress, s.sendNonce); pendingPings++; if(pendingPings >= MaxPendingPings) break; } } } } if(pendingPings == 0 && (pendingQueries < MaxPendingQueries)) { for(S32 i = 0; i < servers.size(); i++) { ServerRef &s = servers[i]; if(s.state == ServerRef::ReceivedPing) { s.sendCount++; if(s.sendCount > PingQueryRetryCount) { strcpy(s.serverName, "QueryTimedOut"); s.playerCount = s.maxPlayers = 0; s.state = ServerRef::ReceivedQuery; shouldSort = true; } else { s.state = ServerRef::SentQuery; s.lastSendTime = time; gClientGame->getNetInterface()->sendQuery(s.serverAddress, s.sendNonce, s.identityToken); pendingQueries++; if(pendingQueries >= MaxPendingQueries) break; } } } } } QueryServersUserInterface::QueryServersUserInterface() { /* for(U32 i = 0;i < 512; i++) { ServerRef s; dSprintf(s.serverName, MaxServerNameLen, "Svr%8x", Random::readI()); s.id = i; s.pingTime = Random::readF() * 512; s.serverAddress.port = 28000; s.serverAddress.netNum[0] = Random::readI(); s.maxPlayers = Random::readF() * 16 + 8; s.playerCount = Random::readF() * s.maxPlayers; servers.push_back(s); }*/ lastUsedServerId = 0; sortColumn = 0; lastSortColumn = 0; sortAscending = true; columns.push_back(ColumnInfo("SERVER NAME", 3)); columns.push_back(ColumnInfo("PING", 300)); columns.push_back(ColumnInfo("PLAYERS", 420)); columns.push_back(ColumnInfo("ADDRESS", 550)); selectedId = 0xFFFFFF; sort(); shouldSort = false; } S32 QueryServersUserInterface::findSelectedIndex() { for(S32 i = 0; i < servers.size(); i++) if(servers[i].id == selectedId) return i; return -1; } void QueryServersUserInterface::render() { if(shouldSort) { shouldSort = false; sort(); } glViewport(0, 0, windowWidth, windowHeight); glClearColor(0, 0, 0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glColor3f(1,1,1); drawCenteredString(0, 25, "CHOOSE A SERVER TO JOIN:"); drawCenteredString(560, 18, "UP, DOWN, PAGEUP, PAGEDOWN to select, ENTER to join."); drawCenteredString(580, 18, "LEFT, RIGHT select sort column, SPACE to sort. ESC exits."); for(S32 i = 0; i < columns.size(); i++) { drawString(columns[i].xStart, 35, 24, columns[i].name); } S32 x1 = columns[sortColumn].xStart - 2; S32 x2; if(sortColumn == columns.size() - 1) x2 = 799; else x2 = columns[sortColumn+1].xStart - 6; glBegin(GL_LINE_LOOP); glVertex2f(x1, 33); glVertex2f(x2, 33); glVertex2f(x2, 61); glVertex2f(x1, 61); glEnd(); if(servers.size()) { S32 selectedIndex = findSelectedIndex(); if(selectedIndex == -1) selectedIndex = 0; S32 firstServer = selectedIndex - ServersAboveBelow; S32 lastServer = selectedIndex + ServersAboveBelow; if(firstServer < 0) { lastServer -= firstServer; firstServer = 0; } if(lastServer >= servers.size()) { lastServer = servers.size() - 1; } for(S32 i = firstServer; i <= lastServer; i++) { U32 y = 65 + (i - firstServer) * 23; U32 fontSize = 20; if(i == selectedIndex) { glColor3f(0,0,0.4); glBegin(GL_POLYGON); glVertex2f(0, y); glVertex2f(799, y); glVertex2f(799, y + 22); glVertex2f(0, y + 22); glEnd(); glColor3f(0,0,1.0); glBegin(GL_LINE_LOOP); glVertex2f(0, y); glVertex2f(799, y); glVertex2f(799, y + 22); glVertex2f(0, y + 22); glEnd(); } glColor3f(1,1,1); drawString(columns[0].xStart, y, fontSize, servers[i].serverName); if(servers[i].pingTime < 100) glColor3f(0,1,0); else if(servers[i].pingTime < 250) glColor3f(1,1,0); else glColor3f(1,0,0); drawStringf(columns[1].xStart, y, fontSize, "%d", servers[i].pingTime); if(servers[i].playerCount == servers[i].maxPlayers) glColor3f(1,0,0); else if(servers[i].playerCount == 0) glColor3f(1,1,0); else glColor3f(0,1,0); if(servers[i].playerCount < 0) drawString(columns[2].xStart, y, fontSize, "?? / ??"); else drawStringf(columns[2].xStart, y, fontSize, "%d / %d", servers[i].playerCount, servers[i].maxPlayers); glColor3f(1,1,1); drawString(columns[3].xStart, y, fontSize, servers[i].serverAddress.toString()); } } glColor3f(0.7, 0.7, 0.7); for(S32 i = 1; i < columns.size(); i++) { glBegin(GL_LINES); glVertex2f(columns[i].xStart - 4, 35); glVertex2f(columns[i].xStart - 4, 550); glEnd(); } glBegin(GL_LINES); glVertex2f(0, 62); glVertex2f(800, 62); glEnd(); } void QueryServersUserInterface::onKeyDown(U32 key) { switch(key) { case ' ': if(lastSortColumn == sortColumn) sortAscending = !sortAscending; else { lastSortColumn = sortColumn; sortAscending = true; } sort(); break; case '\r': { S32 currentIndex = findSelectedIndex(); if(currentIndex == -1) currentIndex = 0; if(servers.size() > currentIndex) { // join the selected game joinGame(servers[currentIndex].serverAddress, servers[currentIndex].isFromMaster, false); // and clear out the servers, so that we don't do any more pinging servers.clear(); } } break; case 27: gMainMenuUserInterface.activate(); break; } } void QueryServersUserInterface::onSpecialKeyDown(U32 key) { if(!servers.size()) return; S32 currentIndex = findSelectedIndex(); if(currentIndex == -1) currentIndex = 0; switch(key) { case GLUT_KEY_PAGE_UP: currentIndex -= ServersPerScreen - 1; break; case GLUT_KEY_PAGE_DOWN: currentIndex += ServersPerScreen - 1; break; case GLUT_KEY_UP: currentIndex--; break; case GLUT_KEY_DOWN: currentIndex++; break; case GLUT_KEY_LEFT: sortColumn--; if(sortColumn < 0) sortColumn = 0; break; case GLUT_KEY_RIGHT: sortColumn++; if(sortColumn >= columns.size()) sortColumn = columns.size() - 1; break; } if(currentIndex < 0) currentIndex = 0; if(currentIndex >= servers.size()) currentIndex = servers.size() - 1; selectedId = servers[currentIndex].id; } static S32 QSORT_CALLBACK compareFuncName(const void *a, const void *b) { return stricmp(((QueryServersUserInterface::ServerRef *) a)->serverName, ((QueryServersUserInterface::ServerRef *) b)->serverName); } static S32 QSORT_CALLBACK compareFuncPing(const void *a, const void *b) { return S32(((QueryServersUserInterface::ServerRef *) a)->pingTime - ((QueryServersUserInterface::ServerRef *) b)->pingTime); } static S32 QSORT_CALLBACK compareFuncPlayers(const void *a, const void *b) { S32 pc = S32(((QueryServersUserInterface::ServerRef *) a)->playerCount - ((QueryServersUserInterface::ServerRef *) b)->playerCount); if(pc) return pc; return S32(((QueryServersUserInterface::ServerRef *) a)->maxPlayers - ((QueryServersUserInterface::ServerRef *) b)->maxPlayers); } static S32 QSORT_CALLBACK compareFuncAddress(const void *a, const void *b) { return S32(((QueryServersUserInterface::ServerRef *) a)->serverAddress.netNum[0] - ((QueryServersUserInterface::ServerRef *) b)->serverAddress.netNum[0]); } void QueryServersUserInterface::sort() { switch(sortColumn) { case 0: qsort(servers.address(), servers.size(), sizeof(ServerRef), compareFuncName); break; case 1: qsort(servers.address(), servers.size(), sizeof(ServerRef), compareFuncPing); break; case 2: qsort(servers.address(), servers.size(), sizeof(ServerRef), compareFuncPlayers); break; case 3: qsort(servers.address(), servers.size(), sizeof(ServerRef), compareFuncAddress); break; } if(!sortAscending) { S32 size = servers.size() / 2; S32 totalSize = servers.size(); for(S32 i = 0; i < size; i++) { ServerRef temp = servers[i]; servers[i] = servers[totalSize - i - 1]; servers[totalSize - i - 1] = temp; } } } }; --- NEW FILE: UIGame.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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 "gameConnection.h" #include "game.h" #include "UIGame.h" #include "UIMenus.h" #include "gameType.h" #include <stdarg.h> #include "glutInclude.h" namespace Zap { GameUserInterface gGameUserInterface; Color gGlobalChatColor(0.9, 0.9, 0.9); Color gTeamChatColor(0, 1, 0); GameUserInterface::GameUserInterface() { mCurrentMode = PlayMode; mChatLastBlinkTime = 0; memset(mChatBuffer, 0, sizeof(mChatBuffer)); mChatBlink = false; for(U32 i = 0; i < 4; i++) mDisplayMessage[i][0] = 0; } void GameUserInterface::displayMessage(Color theColor, const char *format, ...) { for(S32 i = MessageDisplayCount - 1; i > 0; i--) { strcpy(mDisplayMessage[i], mDisplayMessage[i-1]); mDisplayMessageColor[i] = mDisplayMessageColor[i-1]; } va_list args; va_start(args, format); dVsprintf(mDisplayMessage[0], sizeof(mDisplayMessage[0]), format, args); mDisplayMessageColor[0] = theColor; mDisplayMessageTimer = DisplayMessageTimeout; } void GameUserInterface::idle(U32 timeDelta) { if(timeDelta > mDisplayMessageTimer) { mDisplayMessageTimer = DisplayMessageTimeout; for(S32 i = MessageDisplayCount - 1; i > 0; i--) { strcpy(mDisplayMessage[i], mDisplayMessage[i-1]); mDisplayMessageColor[i] = mDisplayMessageColor[i-1]; } mDisplayMessage[0][0] = 0; } else mDisplayMessageTimer -= timeDelta; if(mCurrentMode == ChatMode) { mChatLastBlinkTime += timeDelta; if(mChatLastBlinkTime > ChatBlinkTime) { mChatBlink = !mChatBlink; mChatLastBlinkTime = 0; } } } void GameUserInterface::render() { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glColor3f(0.0, 0.0, 0.0); glViewport(0, 0, windowWidth, windowHeight); glClearColor(0, 0, 0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if(!gClientGame->isConnectedToServer()) { glColor3f(1,1,1); drawCenteredString(290, 30, "Connecting to server..."); drawCenteredString(330, 20, "Press <ESC> to abort"); } glTranslatef(400, 300, 0); if(gClientGame) gClientGame->render(); // draw the reticle glPushMatrix(); glTranslatef(mMousePoint.x, mMousePoint.y, 0); glColor3f(1, 0, 0); glBegin(GL_LINE_LOOP); glVertex2f(-8, -6); glVertex2f(-6, -8); glVertex2f(-3, -3); glEnd(); glBegin(GL_LINE_LOOP); glVertex2f( 8, 6); glVertex2f( 6, 8); glVertex2f( 3, 3); glEnd(); glBegin(GL_LINE_LOOP); //glColor3f(1, 0, 0); glVertex2f(8, -6); glVertex2f(6, -8); glVertex2f(3, -3); glEnd(); glBegin(GL_LINE_LOOP); glVertex2f(-8, 6); glVertex2f(-6, 8); glVertex2f(-3, 3); glEnd(); glPopMatrix(); //glMatrixMode(GL_PROJECTION); //glOrtho(0, windowWidth, windowHeight, 0, 0, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glColor3f(1,1,1); U32 y = 5; for(S32 i = 3; i >= 0; i--) { if(mDisplayMessage[i][0]) { glColor3f(mDisplayMessageColor[i].r, mDisplayMessageColor[i].g, mDisplayMessageColor[i].b); drawString(5, y, 20, mDisplayMessage[i]); y += 24; } } GameType *theGameType = gClientGame->getGameType(); if(theGameType) theGameType->renderInterfaceOverlay(); if(mCurrentMode == ChatMode) { const char *promptStr; if(mCurrentChatType == TeamChat) { glColor3f(gTeamChatColor.r, gTeamChatColor.g, gTeamChatColor.b); promptStr = "(Team): "; } else { glColor3f(gGlobalChatColor.r, gGlobalChatColor.g, gGlobalChatColor.b); promptStr = "(Global): "; } U32 width = getStringWidth(20, promptStr); drawString(5, 100, 20, promptStr); drawString(5 + width, 100, 20, mChatBuffer); if(mChatBlink) drawString(5 + width + getStringWidth(20, mChatBuffer, mChatCursorPos), 100, 20, "_"); } #if 0 // some code for outputting the RTT for the connection // useful for testing lag code GameConnection *con = gClientGame->getConnectionToServer(); if(con) { drawStringf(10, 550, 30, "%0.2g", con->getRoundTripTime()); } #endif } void GameUserInterface::onMouseDragged(S32 x, S32 y) { onMouseMoved(x, y); } void GameUserInterface::onMouseMoved(S32 x, S32 y) { mMousePoint = Point(x - windowWidth / 2, y - windowHeight / 2); mMousePoint.x *= canvasWidth / windowWidth; mMousePoint.y *= canvasHeight / windowHeight; mCurrentMove.angle = atan2(mMousePoint.x, mMousePoint.y); } void GameUserInterface::onMouseDown(S32 x, S32 y) { mCurrentMove.fire = true; } void GameUserInterface::onMouseUp(S32 x, S32 y) { mCurrentMove.fire = false; } void GameUserInterface::onKeyDown(U32 key) { if(mCurrentMode == PlayMode) { mCurrentChatType = GlobalChat; switch(key) { case 'w': case 'W': mCurrentMove.up = 1.0; break; case 'a': case 'A': mCurrentMove.left = 1.0; break; case 's': case 'S': mCurrentMove.down = 1.0; break; case 'd': case 'D': mCurrentMove.right = 1.0; break; case 27: if(!gClientGame->isConnectedToServer()) { endGame(); gMainMenuUserInterface.activate(); } else gGameMenuUserInterface.activate(); break; case 't': case 'T': mCurrentChatType = TeamChat; case 'g': case 'G': mChatLastBlinkTime = 0; mChatBlink = true; mCurrentMode = ChatMode; mCurrentMove.up = mCurrentMove.left = mCurrentMove.right = mCurrentMove.down = 0; break; } } else if(mCurrentMode == ChatMode) { if(key == '\r') issueChat(); else if(key == 8) { // backspace key if(mChatCursorPos > 0) { mChatCursorPos--; for(U32 i = mChatCursorPos; mChatBuffer[i]; i++) mChatBuffer[i] = mChatBuffer[i+1]; } } else if(key == 27) { cancelChat(); } else { for(U32 i = sizeof(mChatBuffer) - 2; i > mChatCursorPos; i--) mChatBuffer[i] = mChatBuffer[i-1]; if(mChatCursorPos < sizeof(mChatBuffer) - 2) { mChatBuffer[mChatCursorPos] = key; mChatCursorPos++; } } } } Move *GameUserInterface::getCurrentMove() { if(!OptionsMenuUserInterface::controlsRelative) return &mCurrentMove; else { mTransformedMove = mCurrentMove; Point moveDir(mCurrentMove.right - mCurrentMove.left, mCurrentMove.up - mCurrentMove.down); Point angleDir(sin(mCurrentMove.angle), cos(mCurrentMove.angle)); Point rightAngleDir(-angleDir.y, angleDir.x); Point newMoveDir = angleDir * moveDir.y + rightAngleDir * moveDir.x; if(newMoveDir.x > 0) { mTransformedMove.right = newMoveDir.x; mTransformedMove.left = 0; } else { mTransformedMove.right = 0; mTransformedMove.left = -newMoveDir.x; } if(newMoveDir.y > 0) { mTransformedMove.down = newMoveDir.y; mTransformedMove.up = 0; } else { mTransformedMove.down = 0; mTransformedMove.up = -newMoveDir.y; } if(mTransformedMove.right > 1) mTransformedMove.right = 1; if(mTransformedMove.left > 1) mTransformedMove.left = 1; if(mTransformedMove.up > 1) mTransformedMove.up = 1; if(mTransformedMove.down > 1) mTransformedMove.down = 1; return &mTransformedMove; } } void GameUserInterface::cancelChat() { memset(mChatBuffer, 0, sizeof(mChatBuffer)); mChatCursorPos = 0; mCurrentMode = PlayMode; } void GameUserInterface::issueChat() { if(mChatBuffer[0]) { GameType *gt = gClientGame->getGameType(); if(gt) gt->c2sSendChat(mCurrentChatType == GlobalChat, mChatBuffer); } cancelChat(); } void GameUserInterface::onKeyUp(U32 key) { if(mCurrentMode == PlayMode) { switch(key) { case 'w': case 'W': mCurrentMove.up = 0; break; case 'a': case 'A': mCurrentMove.left = 0; break; case 's': case 'S': mCurrentMove.down = 0; break; case 'd': case 'D': mCurrentMove.right = 0; break; } } else if(mCurrentMode == ChatMode) { } } }; --- NEW FILE: SweptEllipsoid.h --- // Example code for: Collision Detection with Swept Spheres and Ellipsoids // See: http://www.three14.demon.nl/sweptellipsoid/SweptEllipsoid.pdf // // Copyright (C) 2003 Jorrit Rouwe // // 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. // // This is free software, you can do with it what you want. // // This file contains the main swept sphere / ellipsoid intersection tests. // // Please have a look at the notes. They indicate obvious places for optimization // if you are using a swept ellipsoid against a large number of polygons. // this file has been modified by Mark Frohnmayer: // removed swept ellipsoid routine // removed swept sphere // removed references to vector2 and replaced with Point // added in prototypes for circle collisions #ifndef _SWEPT_ELLIPSOID_H_ #define _SWEPT_ELLIPSOID_H_ namespace Zap { //#include "Vector2.h" //#include "Plane.h" // Test between a polygon and a swept sphere with radius inRadius moving from inBegin to inBegin + inDelta // If there is an intersection the intersection position is returned in outPoint and the center of the // sphere is at inBegin + outFraction * inDelta when it collides //bool PolygonSweptSphereIntersect(const Plane &inPlane, const Vector2 *inVertices, int inNumVertices, const Vector3 &inBegin, const Vector3 &inDelta, float inRadius, Vector3 &outPoint, float &outFraction); // Test intersection with a swept ellipsoid with principal axis inAxis1, inAxis2, inAxis3 moving from inBegin to inBegin + inDelta // If there is an intersection the intersection position is returned in outPoint and the center of the // sphere is at inBegin + outFraction * inDelta when it collides //bool PolygonSweptEllipsoidIntersect(const Plane &inPlane, const Vector2 *inVertices, int inNumVertices, const Vector3 &inBegin, const Vector3 &inDelta, const Vector3 &inAxis1, const Vector3 &inAxis2, const Vector3 &inAxis3, Vector3 &outPoint, float &outFraction); bool PolygonSweptCircleIntersect(const Point *inVertices, int inNumVertices, const Point &inBegin, const Point &inDelta, Point::member_type inRadius, Point &outPoint, Point::member_type &outFraction); }; #endif // _SWEPT_ELLIPSOID_H_ --- NEW FILE: gameLoader.h --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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 // //------------------------------------------------------------------------------------ #ifndef _GAMELOADER_H_ #define _GAMELOADER_H_ #include "../tnl/tnl.h" #include "game.h" #include "gameObject.h" namespace Zap { class GameLoader { public: static void initGameFromFile(ServerGame *g, const char *file); }; }; #endif --- NEW FILE: CTFGame.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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 "CTFGame.h" #include "ship.h" #include "UIGame.h" #include "sfx.h" #include "glutInclude.h" namespace Zap { static void renderFlag(Point pos, Color c) { glPushMatrix(); glTranslatef(pos.x, pos.y, 0); glColor3f(c.r, c.g, c.b); glBegin(GL_LINES); glVertex2f(-15, -15); glVertex2f(15, -5); glVertex2f(15, -5); glVertex2f(-15, 5); glVertex2f(-15, -10); glVertex2f(10, -5); glVertex2f(10, -5); glVertex2f(-15, 0); glColor3f(1,1,1); glVertex2f(-15, -15); glVertex2f(-15, 15); glEnd(); glPopMatrix(); } TNL_IMPLEMENT_NETOBJECT(CTFGameType); void CTFGameType::renderInterfaceOverlay() { for(S32 i = 0; i < mTeams.size(); i++) { Point pos(750, 550 - i * 38); renderFlag(pos + Point(-20, 18), mTeams[i].color); glColor3f(1,1,1); UserInterface::drawStringf(pos.x, pos.y, 32, "%d", mTeams[i].score); } } void CTFGameType::shipTouchFlag(Ship *theShip, CTFFlagItem *theFlag) { GameConnection *controlConnection = theShip->getControllingClient(); S32 clientIndex = findClientIndexByConnection(controlConnection); if(clientIndex == -1) return; ClientRef &cl = mClientList[clientIndex]; if(cl.teamId == theFlag->getTeamIndex()) { if(!theFlag->isAtHome()) { s2cCTFMessage(CTFMsgReturnFlag, cl.clientId, theFlag->getTeamIndex()); theFlag->sendHome(); } else { // check if this client has an enemy flag mounted for(S32 i = 0; i < theShip->mMountedItems.size(); i++) { Item *theItem = theShip->mMountedItems[i]; CTFFlagItem *mountedFlag = dynamic_cast<CTFFlagItem *>(theItem); if(mountedFlag) { mTeams[cl.teamId].score++; s2cSetTeamScore(cl.teamId, mTeams[cl.teamId].score); s2cCTFMessage(CTFMsgCaptureFlag, cl.clientId, mountedFlag->getTeamIndex()); // score the flag for the client's team... mountedFlag->dismount(); mountedFlag->sendHome(); } } } } else { s2cCTFMessage(CTFMsgTakeFlag, cl.clientId, theFlag->getTeamIndex()); theFlag->mountToShip(theShip); } } static const char *CTFMessages[] = { "%s returned the %s flag.", "%s captured the %s flag!", "%s took the %s flag!", }; static U32 CTFFlagSounds[] = { SFXFlagReturn, SFXFlagCapture, SFXFlagSnatch, }; TNL_IMPLEMENT_NETOBJECT_RPC(CTFGameType, s2cCTFMessage, (U32 messageIndex, U32 clientId, U32 teamIndex), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhost, 0) { S32 clientIndex = findClientIndexById(clientId); gGameUserInterface.displayMessage(Color(0.6f, 1.0f, 0.8f), CTFMessages[messageIndex], mClientList[clientIndex].name.getString(), mTeams[teamIndex].name.getString()); SFXHandle h = new SFXObject(CTFFlagSounds[messageIndex]); h->play(); } TNL_IMPLEMENT_NETOBJECT(CTFFlagItem); CTFFlagItem::CTFFlagItem(Point pos) : Item(pos, false, 20) { teamIndex = 0; mNetFlags.set(Ghostable); } void CTFFlagItem::processArguments(S32 argc, const char **argv) { if(argc < 3) return; teamIndex = atoi(argv[0]); Parent::processArguments(argc-1, argv+1); initialPos = mMoveState[ActualState].pos; } U32 CTFFlagItem::packUpdate(GhostConnection *connection, U32 updateMask, BitStream *stream) { if(stream->writeFlag(updateMask & InitialMask)) stream->writeInt(teamIndex, 4); return Parent::packUpdate(connection, updateMask, stream); } void CTFFlagItem::unpackUpdate(GhostConnection *connection, BitStream *stream) { if(stream->readFlag()) teamIndex = stream->readInt(4); Parent::unpackUpdate(connection, stream); } bool CTFFlagItem::isAtHome() { return mMoveState[ActualState].pos == initialPos; } void CTFFlagItem::sendHome() { mMoveState[ActualState].pos = mMoveState[RenderState].pos = initialPos; setMaskBits(PositionMask); updateExtent(); } void CTFFlagItem::renderItem(Point pos) { Point offset; if(mIsMounted) offset.set(15, -15); Color c; GameType *gt = getGame()->getGameType(); c = gt->mTeams[teamIndex].color; renderFlag(pos + offset, c); } bool CTFFlagItem::collide(GameObject *hitObject) { if(isGhost() || mIsMounted) return false; if(!(hitObject->getObjectTypeMask() & ShipType)) return false; CTFGameType *theGameType = dynamic_cast<CTFGameType *>(getGame()->getGameType()); if(theGameType) theGameType->shipTouchFlag((Ship *) hitObject, this); return false; } }; --- NEW FILE: point.h --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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 // //------------------------------------------------------------------------------------ #ifndef _POINT_H_ #define _POINT_H_ #include <math.h> namespace Zap { struct Point { typedef float member_type; member_type x; member_type y; Point() { x = 0; y = 0; } Point(const Point& pt) { x = pt.x; y = pt.y; } Point(member_type in_x, member_type in_y) { x = in_x; y = in_y; } ... [truncated message content] |