/* 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 */ /* * Multistruct.c * * Alex Lee 98, Pumpkin Studios. * * files to cope with multiplayer structure related stuff.. */ #include "lib/framework/frame.h" #include "droid.h" #include "droiddef.h" #include "base.h" #include "power.h" #include "geometry.h" // for gettilestructure #include "anim_id.h" #include "stats.h" #include "map.h" #include "console.h" #include "action.h" #include "order.h" #include "projectile.h" #include "lib/netplay/netplay.h" // the netplay library. #include "multiplay.h" #include "multigifts.h" #include "audio_id.h" // //////////////////////////////////////////////////////////////////////////// // External Variables extern UDWORD objID; // unique ID creation thing.. // //////////////////////////////////////////////////////////////////////////// // Local Functions //BOOL levelGround (UDWORD atx, UDWORD aty, UDWORD atz, UDWORD baseWidth,UDWORD baseBreadth); BOOL sendBuildStarted (STRUCTURE *psStruct,DROID *psDroid); BOOL recvBuildStarted (NETMSG *m); BOOL SendBuildFinished (STRUCTURE *psStruct); BOOL recvBuildFinished (NETMSG *m); BOOL SendDestroyStructure (STRUCTURE *s); BOOL RecvDestroyStructure (NETMSG * m); BOOL sendLasSat (UBYTE player,STRUCTURE *psStruct, BASE_OBJECT *psObj); BOOL recvLasSat (NETMSG *pMsg); // //////////////////////////////////////////////////////////////////////////// // Level ground. A small function for updating the ground below a structure. // if and when this gets broken the code was pinched from droidupdatefoundation(); /*BOOL levelGround(UDWORD atx, UDWORD aty, UDWORD atz, UDWORD baseWidth,UDWORD baseBreadth) { UDWORD x = atx >> TILE_SHIFT; UDWORD y = aty >> TILE_SHIFT; UBYTE width, breadth; for (breadth=0; breadth < (UBYTE)(baseBreadth + 1); breadth++) { for (width=0; width < (UBYTE)(baseWidth + 1); width++) { while((x+width-1)<0)width++; while((y+breadth-1)<0)breadth++; setTileHeight(x + width-1, y + breadth-1, atz); } } return TRUE; } */ // //////////////////////////////////////////////////////////////////////////// // structures // //////////////////////////////////////////////////////////////////////////// // INFORM others that a building has been started, and base plate should be put down. BOOL sendBuildStarted(STRUCTURE *psStruct,DROID *psDroid) { NETMSG msg; UDWORD zero=0; UWORD player,order; player = (UBYTE)psDroid->player; order = (UBYTE)psDroid->order; NetAdd(msg,0,player); //player NetAdd(msg,1,psDroid->psTarStats->ref); //id of thing to build NetAdd(msg,5,psDroid->orderX); // x NetAdd(msg,7,psDroid->orderY); // y NetAdd(msg,11,psDroid->id); // droid to order to build it NetAdd(msg,15,psStruct->id); // building id to create NetAdd(msg,19,order); // building id to create if(psDroid->psTarget && (psDroid->psTarget->type == OBJ_STRUCTURE)) { NetAdd(msg,20,((STRUCTURE*)psDroid->psTarget)->id); } else { NetAdd(msg,20,zero); } NetAdd(msg,24,psStruct->z); msg.size =28; msg.type = NET_BUILD; return (NETbcast(&msg,FALSE)); } // //////////////////////////////////////////////////////////////////////////// // put down a base plate and start droid building it! BOOL recvBuildStarted(NETMSG *pMsg) { //UDWORD targetId,order,droidId,structId,x,z,y,structStat,player; UDWORD targetId,order,droidId,structId,structStat; UWORD x,z,y,player; STRUCTURE_STATS *psStats; DROID *psDroid; UDWORD typeindex,actionX,actionY; player = pMsg->body[0]; // decode message. NetGet(pMsg,1,structStat); NetGet(pMsg,5,x); NetGet(pMsg,7,y); NetGet(pMsg,11,droidId); NetGet(pMsg,15,structId); order = pMsg->body[19]; NetGet(pMsg,20,targetId); NetGet(pMsg,24,z); for(typeindex=0; // find structure target (typeindexorder = order; if(psDroid->order == DORDER_LINEBUILD) { psDroid->order = DORDER_BUILD; } psDroid->orderX = x; psDroid->orderY = y; psDroid->psTarStats = (BASE_STATS *) psStats; if(targetId) { psDroid->psTarget = IdToPointer(targetId,ANYPLAYER); } else { psDroid->psTarget = 0; } if (IsStatExpansionModule(psStats)) { setUpBuildModule(psDroid); } else { droidStartBuild(psDroid); psDroid->action = DACTION_BUILD; } } if (psDroid->psTarget) //sync id's { ((STRUCTURE*)psDroid->psTarget)->id = structId; } } // order droid to start building it. return TRUE; } // //////////////////////////////////////////////////////////////////////////// // INFORM others that a building has been completed. BOOL SendBuildFinished(STRUCTURE *psStruct) { NETMSG m; NetAdd(m,0,psStruct->id); //id of finished struct // also enough info to build it if we don't already know about it. NetAdd(m,4,psStruct->pStructureType->ref); // kind of building. NetAdd(m,8,psStruct->x); // x pos NetAdd(m,10,psStruct->y); // y pos NetAdd(m,12,psStruct->z); // y pos m.body[14] =(char) psStruct->player; // player m.size =15; m.type =NET_BUILDFINISHED; return (NETbcast(&m,FALSE)); } // //////////////////////////////////////////////////////////////////////////// BOOL recvBuildFinished(NETMSG *m) { UDWORD strId;//,i; STRUCTURE *psStr; UWORD x,y,z; UDWORD type,typeindex; UBYTE player; NetGet(m,0,strId); // get the struct id. psStr = IdToStruct(strId,ANYPLAYER); if(psStr) { // make it complete. psStr->currentBuildPts = psStr->pStructureType->buildPoints+1; if(psStr->status != SS_BUILT) { psStr->status = SS_BUILT; buildingComplete(psStr); } NETlogEntry("building finished ok." ,0,0); return TRUE; } // the building wasn't started, so we'll have to just plonk it down in the map. NetGet(m,4,type); // kind of building. NetGet(m,8,x); // x pos NetGet(m,10,y); // y pos NetGet(m,12,z); // z pos player = m->body[14]; // player for(typeindex=0; // find structure target (typeindex>TILE_SHIFT,y>>TILE_SHIFT)) ) { // get structure; psStr = getTileStructure(x>>TILE_SHIFT, y>>TILE_SHIFT); if(asStructureStats[typeindex].type == psStr->pStructureType->type) { // correct type, correct location, just rename the id's to sync it.. (urgh) psStr->id = strId; psStr->status = SS_BUILT; buildingComplete(psStr); NETlogEntry("structure id modified" ,0,player); return TRUE; } } psStr = buildStructure(&(asStructureStats[typeindex]), // build the structure. x,y, player,TRUE); if (psStr) { psStr->id = strId; psStr->status = SS_BUILT; buildingComplete(psStr); DBCONPRINTF(ConsoleString,(ConsoleString,"MultiPlayer: Struct not found on recvbuildcomplete :%d",strId )); NETlogEntry("had to plonk down a building" ,0,player); } else { DBCONPRINTF(ConsoleString,(ConsoleString,"MultiPlayer: Struct not found on recvbuildcomplete BUILDIT FAILED TOO!:%d",strId )); NETlogEntry("had to plonk down a building, BUT FAILED OH S**T." ,0,player); } return FALSE; } // //////////////////////////////////////////////////////////////////////////// // demolish message. BOOL SendDemolishFinished( STRUCTURE *psStruct,DROID *psDroid) { NETMSG m; NetAdd(m,0,psStruct->id); NetAdd(m,4,psDroid->id); m.size = 2*sizeof(UDWORD); m.type = NET_DEMOLISH; return( NETbcast(&m,FALSE)); } BOOL recvDemolishFinished(NETMSG *m) { STRUCTURE *psStruct; UDWORD s,d; DROID *psDroid; NetGet(m,0,s); NetGet(m,4,d); psStruct = IdToStruct(s,ANYPLAYER); IdToDroid(d,ANYPLAYER,&psDroid); if(psStruct) { removeStruct( psStruct, TRUE ); // demolish it. if(psDroid && psDroid->psTarStats) { psDroid->psTarStats = NULL; // update droid if reqd. } } return TRUE; } // //////////////////////////////////////////////////////////////////////////// // Inform others that a structure has been destroyed BOOL SendDestroyStructure(STRUCTURE *s) { NETMSG m; technologyGiveAway(s); NetAdd(m,0,s->id); // struct to destroy m.size =sizeof(UDWORD); m.type=NET_STRUCTDEST; return( NETbcast(&m,FALSE)); } // //////////////////////////////////////////////////////////////////////////// // acknowledge the destruction of a structure, from another player. BOOL recvDestroyStructure(NETMSG * m) { UDWORD s; STRUCTURE *psStr; NetGet(m,0,s); // struct to destory psStr = IdToStruct(s,ANYPLAYER); if (psStr) { turnOffMultiMsg(TRUE); destroyStruct(psStr); // remove the struct from remote players machine. turnOffMultiMsg(FALSE); technologyGiveAway(psStr); return (TRUE); } return (TRUE); } // //////////////////////////////////////////////////////////////////////////// //lassat is firing BOOL sendLasSat(UBYTE player,STRUCTURE *psStruct, BASE_OBJECT *psObj) { NETMSG msg; UBYTE p; NetAdd(msg,0,player); NetAdd(msg,1,psStruct->id); NetAdd(msg,5,psObj->id); p = psObj->player; NetAdd(msg,9,p); msg.size = 10; msg.type = NET_LASSAT; return (NETbcast(&msg,FALSE) ); } // recv lassat info on the receiving end. BOOL recvLasSat(NETMSG *pMsg) { BASE_OBJECT *psObj; UBYTE player,targetplayer; STRUCTURE *psStruct; UDWORD id,tid; NetGet(pMsg,0,player); NetGet(pMsg,1,id); NetGet(pMsg,5,tid); NetGet(pMsg,9,targetplayer); psStruct = IdToStruct (id ,player); psObj = IdToPointer(tid,targetplayer); if(psStruct && psObj) { proj_SendProjectile(&psStruct->asWeaps[0], NULL, player, psObj->x, psObj->y, psObj->z, psObj, TRUE); //play 5 second countdown message audio_QueueTrackPos( ID_SOUND_LAS_SAT_COUNTDOWN, psObj->x, psObj->y, psObj->z ); } return TRUE; }