/* This file is part of Warzone 2100. Copyright (C) 1999-2004 Eidos Interactive Copyright (C) 2005-2007 Warzone Resurrection Project Warzone 2100 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. Warzone 2100 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 Warzone 2100; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* * MultiOpt.c * * Alex Lee,97/98, Pumpkin Studios * * Routines for setting the game options and starting the init process. */ #include "lib/framework/frame.h" // for everything #include "map.h" #include "game.h" // for loading maps #include "message.h" // for clearing messages. #include "winmain.h" #include "display3d.h" // for changing the viewpoint #include "power.h" #include "lib/widget/widget.h" #include "lib/gamelib/gtime.h" #include "lib/netplay/netplay.h" #include "hci.h" #include "configuration.h" // lobby cfg. #include "clparse.h" #include "lib/ivis_common/piestate.h" #include "component.h" #include "console.h" #include "multiplay.h" #include "lib/sound/audio.h" #include "multijoin.h" #include "frontend.h" #include "levels.h" #include "multistat.h" #include "multiint.h" #include "multilimit.h" #include "multigifts.h" #include "aiexperience.h" //for beacon messages // //////////////////////////////////////////////////////////////////////////// // GUID for warzone lobby and MPATH stuff. i hate this stuff. #ifdef WIN32 //Not really (going to be) used. -Qamly #include //old guid {7B706E40-5A7E-11d1-94F6-006097B8260B}" DEFINE_GUID(WARZONEGUID,0x48ab0b01,0xfec0,0x11d1,0x98,0xc,0x0,0xa0,0x24,0x38,0x70,0xa8); // also change S_WARZONEGUID in multiplay.h #endif // //////////////////////////////////////////////////////////////////////////// // External Variables extern char MultiForcesPath[255]; extern char buildTime[8]; extern VOID stopJoining(void); // //////////////////////////////////////////////////////////////////////////// // Local Functions VOID sendOptions (DPID dest,UDWORD player); VOID recvOptions (NETMSG *pMsg); //static BOOL dMatchInit (VOID); static BOOL campInit (VOID); BOOL hostCampaign (STRING *sGame, STRING *sPlayer); BOOL joinCampaign (UDWORD gameNumber, STRING *playername); //BOOL hostArena (STRING *sGame, STRING *sPlayer); //BOOL joinArena (UDWORD gameNumber, STRING *playername); BOOL LobbyLaunched (VOID); VOID playerResponding (VOID); BOOL multiInitialise (VOID); //only once. BOOL lobbyInitialise (VOID); //only once. BOOL sendLeavingMsg (VOID); BOOL multiShutdown (VOID); BOOL addTemplate (UDWORD player, DROID_TEMPLATE *psNew); BOOL addTemplateSet (UDWORD from,UDWORD to); BOOL copyTemplateSet (UDWORD from,UDWORD to); BOOL multiGameInit (VOID); // every game BOOL multiGameShutdown (VOID); // //////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////// // send complete game info set! // dpid == 0 for no new players. VOID sendOptions(DPID dest,UDWORD play) { NETMSG m; UBYTE checkval; NetAdd(m,0,game); m.size = sizeof(game); NetAdd(m,m.size,player2dpid); //add dpid array m.size += sizeof(player2dpid); NetAdd(m,m.size,ingame.JoiningInProgress); m.size += sizeof(ingame.JoiningInProgress); checkval = NEThashVal(NetPlay.cryptKey[0]); // exe's hash val. DONT SEND THE VAL ITSELF! NetAdd(m,m.size,checkval); m.size += sizeof(checkval); NetAdd(m,m.size,dest); m.size += sizeof(dest); NetAdd(m,m.size,play); m.size += sizeof(play); NetAdd(m,m.size,PlayerColour); m.size += sizeof(PlayerColour); NetAdd(m,m.size,alliances); m.size += sizeof(alliances); NetAdd(m,m.size,ingame.numStructureLimits); m.size += sizeof(ingame.numStructureLimits); if(ingame.numStructureLimits) { memcpy(&(m.body[m.size]),ingame.pStructureLimits, ingame.numStructureLimits * (sizeof(UBYTE)+sizeof(UDWORD)) ); m.size = (UWORD)(m.size + ingame.numStructureLimits * (sizeof(UBYTE)+sizeof(UDWORD)) ); } // // now add the wdg files that are being used. // m.type = NET_OPTIONS; // send it. NETbcast(&m,TRUE); } // //////////////////////////////////////////////////////////////////////////// BOOL checkGameWdg(CHAR *nm) { LEVEL_DATASET *lev; // // now check the wdg files that are being used. // // game.map must be available in xxx list. lev = psLevels; while(lev) { if( strcmp(lev->pName, nm) == 0) { return TRUE; } lev=lev->psNext; } return FALSE; } // //////////////////////////////////////////////////////////////////////////// // options for a game. (usually recvd in frontend) void recvOptions(NETMSG *pMsg) { UDWORD pos=0,play,id; DPID newPl; UBYTE checkval; NetGet(pMsg,0,game); // get details. pos += sizeof(game); if(strncmp((CHAR*)game.version,buildTime,8) != 0) { #ifndef DEBUG debug( LOG_ERROR, "Host is running a different version of Warzone2100." ); abort(); #endif } if(ingame.numStructureLimits) // free old limits. { ingame.numStructureLimits = 0; FREE(ingame.pStructureLimits); } NetGet(pMsg,pos,player2dpid); pos += sizeof(player2dpid); NetGet(pMsg,pos,ingame.JoiningInProgress); pos += sizeof(ingame.JoiningInProgress); NetGet(pMsg,pos,checkval); pos += sizeof(checkval); /* // This was set to a fixed value in earlier versions of post-Pumpkin code. // Commenting out to avoid confusion. Should probably be removed. - Per if(checkval != NEThashVal(NetPlay.cryptKey[0])) { DBERROR(("Host Binary is different from this one. Cheating?")); } */ NetGet(pMsg,pos,newPl); pos += sizeof(newPl); NetGet(pMsg,pos,play); pos += sizeof(play); NetGet(pMsg,pos,PlayerColour); pos += sizeof(PlayerColour); NetGet(pMsg,pos,alliances); pos += sizeof(alliances); NetGet(pMsg,pos,ingame.numStructureLimits); pos += sizeof(ingame.numStructureLimits); if(ingame.numStructureLimits) { ingame.pStructureLimits = MALLOC(ingame.numStructureLimits*(sizeof(UDWORD)+sizeof(UBYTE))); // malloc some room memcpy(ingame.pStructureLimits, &(pMsg->body[pos]) ,ingame.numStructureLimits*(sizeof(UDWORD)+sizeof(UBYTE))); } // process if(newPl != 0) { if(newPl == NetPlay.dpidPlayer) { // it's us thats new selectedPlayer = play; // select player NETplayerInfo(); // get player info powerCalculated = FALSE; // turn off any power requirements. } else { // someone else is joining. setupNewPlayer( newPl, play); } } // do the skirmish slider settings if they are up, for(id=0;id1) { for(j = 0;j1) { for(j = 0;jpsNext; FREE(pF); } debug(LOG_MAIN, "free game data (structure limits)"); if(ingame.numStructureLimits) { ingame.numStructureLimits = 0; FREE(ingame.pStructureLimits); } return TRUE; } // //////////////////////////////////////////////////////////////////////////// // copy tempates from one player to another. BOOL addTemplate(UDWORD player, DROID_TEMPLATE *psNew) { DROID_TEMPLATE *psTempl; if (!HEAP_ALLOC(psTemplateHeap, (void*) &psTempl)) { return FALSE; } memcpy(psTempl, psNew, sizeof(DROID_TEMPLATE)); psTempl->pName = (CHAR*)&psTempl->aName; strncpy(psTempl->aName, psNew->aName,DROID_MAXNAME); psTempl->pName[DROID_MAXNAME-1]=0; psTempl->psNext = apsDroidTemplates[player]; apsDroidTemplates[player] = psTempl; return TRUE; } BOOL addTemplateSet(UDWORD from,UDWORD to) { DROID_TEMPLATE *psCurr; if(from == to) { return TRUE; } for(psCurr = apsDroidTemplates[from];psCurr;psCurr= psCurr->psNext) { addTemplate(to, psCurr); } return TRUE; } BOOL copyTemplateSet(UDWORD from,UDWORD to) { DROID_TEMPLATE *psTempl; if(from == to) { return TRUE; } while(apsDroidTemplates[to]) // clear the old template out. { psTempl = apsDroidTemplates[to]->psNext; HEAP_FREE(psTemplateHeap, apsDroidTemplates[to]); apsDroidTemplates[to] = psTempl; } return addTemplateSet(from,to); } // //////////////////////////////////////////////////////////////////////////// // setup templates BOOL multiTemplateSetup() { UDWORD player, pcPlayer = 0; CHAR sTemp[256]; if(game.type == CAMPAIGN && game.base == CAMP_WALLS) { strcpy(sTemp, MultiForcesPath); strcat(sTemp, sForceName); strcat(sTemp,".for"); loadForce(sTemp); // useTheForce(TRUE); } switch (game.type) { // case DMATCH: // for(player=0;playerpsNext; //if(psD->droidType != DROID_CONSTRUCT) if (!(psD->droidType == DROID_CONSTRUCT OR psD->droidType == DROID_CYBORG_CONSTRUCT)) { killDroid(psD); } psD = psD2; } break; case CAMP_BASE: //just structs, no walls psStruct = apsStructLists[player]; while(psStruct) { if ( (psStruct->pStructureType->type == REF_WALL) ||(psStruct->pStructureType->type == REF_WALLCORNER) ||(psStruct->pStructureType->type == REF_DEFENSE) ||(psStruct->pStructureType->type == REF_BLASTDOOR) ||(psStruct->pStructureType->type == REF_CYBORG_FACTORY) ||(psStruct->pStructureType->type == REF_COMMAND_CONTROL) ) { removeStruct(psStruct, TRUE); psStruct= apsStructLists[player]; //restart,(list may have changed). } else if( (psStruct->pStructureType->type == REF_FACTORY) ||(psStruct->pStructureType->type == REF_RESEARCH) ||(psStruct->pStructureType->type == REF_POWER_GEN)) { if(psStruct->pStructureType->type == REF_FACTORY ) { if(firstFact == TRUE) { firstFact = FALSE; removeStruct(psStruct, TRUE); psStruct= apsStructLists[player]; } else // don't delete, just rejig! { if(((FACTORY*)psStruct->pFunctionality)->capacity != 0) { ((FACTORY*)psStruct->pFunctionality)->capacity = 0; ((FACTORY*)psStruct->pFunctionality)->productionOutput = (UBYTE)((PRODUCTION_FUNCTION*)psStruct->pStructureType->asFuncList[0])->productionOutput; psStruct->sDisplay.imd = psStruct->pStructureType->pIMD; psStruct->body = (UWORD)(structureBody(psStruct)); } psStruct = psStruct->psNext; } } else if(psStruct->pStructureType->type == REF_RESEARCH) { if(firstRes == TRUE) { firstRes = FALSE; removeStruct(psStruct, TRUE); psStruct= apsStructLists[player]; } else { if(((RESEARCH_FACILITY*)psStruct->pFunctionality)->capacity != 0) { // downgrade research ((RESEARCH_FACILITY*)psStruct->pFunctionality)->capacity = 0; ((RESEARCH_FACILITY*)psStruct->pFunctionality)->researchPoints = ((RESEARCH_FUNCTION*)psStruct->pStructureType->asFuncList[0])->researchPoints; psStruct->sDisplay.imd = psStruct->pStructureType->pIMD; psStruct->body = (UWORD)(structureBody(psStruct)); } psStruct=psStruct->psNext; } } else if(psStruct->pStructureType->type == REF_POWER_GEN) { if(((POWER_GEN*)psStruct->pFunctionality)->capacity != 0) { // downgrade powergen. ((POWER_GEN*)psStruct->pFunctionality)->capacity = 0; ((POWER_GEN*)psStruct->pFunctionality)->power = ((POWER_GEN_FUNCTION*)psStruct->pStructureType->asFuncList[0])->powerOutput; ((POWER_GEN*)psStruct->pFunctionality)->multiplier += ((POWER_GEN_FUNCTION*)psStruct->pStructureType->asFuncList[0])->powerMultiplier; psStruct->sDisplay.imd = psStruct->pStructureType->pIMD; psStruct->body = (UWORD)(structureBody(psStruct)); } psStruct=psStruct->psNext; } } else { psStruct=psStruct->psNext; } } break; case CAMP_WALLS: //everything. break; default: debug( LOG_ERROR, "Unknown Campaign Style" ); abort(); break; } // rerev list to get back to normal. // reverseObjectList((BASE_OBJECT**)&apsStructLists[player]); bMultiPlayer = TRUE; return TRUE; } // //////////////////////////////////////////////////////////////////////////// // setup a deathmatch game. /* static BOOL dMatchInit() { UDWORD i; NETMSG msg; UDWORD player; BOOL resourceFound = FALSE; CHAR sTemp[256]; turnOffMultiMsg(TRUE); for(i =0 ; i