/* 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 */ /* * Multibot.c * * Alex Lee , 97/98 Pumpkin Studios, Bath * Multiplay stuff relevant to droids only. */ #include "lib/framework/frame.h" #include "droid.h" // for droid sending and ordering. #include "droiddef.h" #include "base.h" // for sending WHOLE droids. #include "stats.h" #include "move.h" // for ordering droids #include "objmem.h" #include "power.h" // for powercalculated #include "order.h" #include "geometry.h" // for formations. #include "map.h" #include "group.h" #include "formation.h" #include "lib/netplay/netplay.h" // the netplay library. #include "multiplay.h" // warzone net stuff. #include "multijoin.h" #include "cmddroid.h" // command droids #include "action.h" #include "console.h" #include "mapgrid.h" #define ANYPLAYER 99 #define UNKNOWN 99 DROIDSTORE *tempDroidList = NULL; // //////////////////////////////////////////////////////////////////////////// // External Stuff. extern DROID_ORDER chooseOrderLoc(DROID *psDroid, UDWORD x,UDWORD y); extern DROID_ORDER chooseOrderObj(DROID *psDroid, BASE_OBJECT *psObj); // //////////////////////////////////////////////////////////////////////////// // Local Prototypes BOOL sendVtolRearm(DROID *psDroid,STRUCTURE *psStruct, UBYTE chosen); BOOL recvVtolRearm(NETMSG *pMsg); BOOL sendDroidSecondary (DROID *psDroid, SECONDARY_ORDER sec, SECONDARY_STATE state); BOOL recvDroidSecondary (NETMSG *pMsg); //BOOL SendSingleDroidWaypoint(DROID *psDroid, UDWORD x,UDWORD y); //BOOL SendDroidWaypoint (UBYTE player,UDWORD x, UDWORD y); //BOOL recvDroidWaypoint (NETMSG *pMsg); BOOL SendDroidMove (DROID *pDroid, UDWORD x, UDWORD y,BOOL bFormation); BOOL recvDroidMove (NETMSG *pMsg); BOOL SendDroid (DROID_TEMPLATE *pTemplate, UDWORD x, UDWORD y, UBYTE player, UDWORD id); BOOL recvDroid (NETMSG *pMsg); BOOL SendDroidInfo (DROID *pDroid, DROID_ORDER order, UDWORD x, UDWORD y, BASE_OBJECT *psObj); BOOL recvDroidInfo (NETMSG *pMsg); BOOL SendGroupOrderSelected (UBYTE player, UDWORD x, UDWORD y, BASE_OBJECT *psObj); BOOL SendGroupOrderGroup(DROID_GROUP *psGroup, DROID_ORDER order,UDWORD x,UDWORD y,BASE_OBJECT *psObj); BOOL SendCmdGroup (DROID_GROUP *group, UWORD x, UWORD y, BASE_OBJECT *psObj); BOOL recvGroupOrder (NETMSG *pMsg); static VOID ProcessDroidOrder (DROID *psDroid, DROID_ORDER order, UDWORD x, UDWORD y, OBJECT_TYPE desttype,UDWORD destid); BOOL SendDestroyDroid (DROID *pD); BOOL recvDestroyDroid (NETMSG *pMsg); BOOL sendWholeDroid (DROID *pD, DPID dest); BOOL receiveWholeDroid (NETMSG *pMsg); BOOL sendRequestDroid (UDWORD droidId); BOOL recvRequestDroid (NETMSG *pMsg); // //////////////////////////////////////////////////////////////////////////// // Command Droids. // sod em. // //////////////////////////////////////////////////////////////////////////// // vtol bits. // happy vtol = vtol ready to go back to attack. BOOL sendHappyVtol(DROID *psDroid) { NETMSG m; if(!myResponsibility(psDroid->player)) { return FALSE; } NetAdd(m,0,psDroid->player); NetAdd(m,1,psDroid->id); m.size =5; m.type =NET_VTOL; return NETbcast(&m,FALSE); } BOOL recvHappyVtol(NETMSG *pMsg) { DROID *pD; UBYTE player; UDWORD id; NetGet(pMsg,0,player); NetGet(pMsg,1,id); if(!IdToDroid(id,player,&pD)) //find droid. { return FALSE; } pD->sMove.iAttackRuns =0; // finish it for next time round. pD->body = pD->originalBody; pD->asWeaps[0].ammo = asWeaponStats[pD->asWeaps[0].nStat].numRounds; pD->asWeaps[0].lastFired = 0; return TRUE; } // vtol now needs to return to rearm. BOOL sendVtolRearm(DROID *psDroid,STRUCTURE *psStruct, UBYTE chosen) { NETMSG msg; UDWORD blank=0; UBYTE attackRuns, ammo; UBYTE player; if(!myResponsibility(psDroid->player)) { return FALSE; } player = psDroid->player; NetAdd(msg,0,player); NetAdd(msg,1,psDroid->id); NetAdd(msg,5,chosen); if(psStruct) { NetAdd(msg,6,psStruct->id); } else { NetAdd(msg,6,blank); } attackRuns = (UBYTE)(psDroid->sMove.iAttackRuns); ammo = (UBYTE)(psDroid->asWeaps[0].ammo); NetAdd(msg,10,attackRuns); NetAdd(msg,11,ammo); msg.size = 12; msg.type = NET_VTOLREARM; return TRUE; } // this is a complete rip from recvvtolrearm BOOL recvVtolRearm(NETMSG *pMsg) { DROID *psDroid; UBYTE player,chosen,aruns,amm; UDWORD id,ids; STRUCTURE *psStruct = NULL; NetGet(pMsg,0,player); NetGet(pMsg,1,id); NetGet(pMsg,5,chosen); NetGet(pMsg,6,ids); NetGet(pMsg,10,aruns); NetGet(pMsg,11,amm); if(!IdToDroid(id,player,&psDroid)) //find droid. { return FALSE; } if(ids) // find rearm pad. { psStruct = IdToStruct(id,psDroid->player); if(!psStruct) { return FALSE; } else { psDroid->psBaseStruct = psStruct; } } psDroid->sMove.iAttackRuns = aruns; psDroid->asWeaps[0].ammo = amm; turnOffMultiMsg(TRUE); switch(chosen) { case 1: psDroid->order = DORDER_NONE; orderDroidObj(psDroid, DORDER_REARM, (BASE_OBJECT *)psStruct); break; case 2: actionDroidObj(psDroid,DACTION_MOVETOREARM, (BASE_OBJECT *)psStruct); break; case 3: orderDroid( psDroid, DORDER_RTB ); break; default: break; } turnOffMultiMsg(FALSE); return TRUE; } // //////////////////////////////////////////////////////////////////////////// // Secondary Orders. // send BOOL sendDroidSecondary(DROID *psDroid, SECONDARY_ORDER sec, SECONDARY_STATE state) { NETMSG m; NetAdd(m,0,psDroid->id); NetAdd(m,4,sec); NetAdd(m,8,state); m.body[12] = (char) psDroid->player; m.size = 13; m.type = NET_SECONDARY; return NETbcast(&m,FALSE); } // recv BOOL recvDroidSecondary(NETMSG *pMsg) { DROID *psDroid; SECONDARY_ORDER sec; SECONDARY_STATE state; UDWORD id,player; NetGet(pMsg,0,id); NetGet(pMsg,4,sec); NetGet(pMsg,8,state); player = pMsg->body[12]; if(!IdToDroid(id,player,&psDroid)) //find droid. { return FALSE; } turnOffMultiMsg(TRUE); secondarySetState(psDroid,sec,state); // set order turnOffMultiMsg(FALSE); return TRUE; } BOOL sendDroidSecondaryAll(DROID *psDroid) { NETMSG m; NetAdd(m,0,psDroid->id); NetAdd(m,4,psDroid->secondaryOrder); m.body[8] = (char) psDroid->player; m.size = 9; m.type = NET_SECONDARY_ALL; return NETbcast(&m,FALSE); } BOOL recvDroidSecondaryAll(NETMSG *pMsg) { DROID *psDroid; UDWORD id,player,sorder; NetGet(pMsg,0,id); NetGet(pMsg,4,sorder); player = pMsg->body[8]; if(!IdToDroid(id,player,&psDroid)) //find droid. { return FALSE; } if(psDroid) { psDroid->secondaryOrder = sorder; } return TRUE; } BOOL sendDroidEmbark(DROID *psDroid) { NETMSG m; NetAdd(m,0,psDroid->id); m.body[4] = (char) psDroid->player; m.size = 5; m.type = NET_DROIDEMBARK; return NETbcast(&m,FALSE); } BOOL recvDroidEmbark(NETMSG *pMsg) { DROID *psDroid; UDWORD id,player; NetGet(pMsg,0,id); player = pMsg->body[4]; if(!IdToDroid(id,player,&psDroid)) //find droid. { return FALSE; } if(psDroid) { //take it out of the world without destroying it droidRemove(psDroid, apsDroidLists); //init the order for when disembark psDroid->order = DORDER_NONE; psDroid->psTarget = NULL; psDroid->psTarStats = NULL; } return TRUE; } BOOL sendDroidDisEmbark(DROID *psDroid) { NETMSG m; NetAdd(m,0,psDroid->id); NetAdd(m,4,psDroid->x); NetAdd(m,6,psDroid->y); m.body[8] = (char) psDroid->player; m.size = 9; m.type = NET_DROIDDISEMBARK; return NETbcast(&m,FALSE); } BOOL recvDroidDisEmbark(NETMSG *pMsg) { DROID *psDroid; UDWORD id,player; UWORD x, y; NetGet(pMsg,0,id); NetGet(pMsg,4,x); NetGet(pMsg,6,y); player = pMsg->body[8]; if(!IdToDroid(id,player,&psDroid)) //find droid. { return FALSE; } if(psDroid) { //add it back into the world at the x/y psDroid->x = x; psDroid->y = y; updateDroidOrientation(psDroid); //initialise the movement data initDroidMovement(psDroid); //reset droid orders orderDroid(psDroid, DORDER_STOP); gridAddObject((BASE_OBJECT *)psDroid); psDroid->cluster = 0; addDroid(psDroid, apsDroidLists); } return TRUE; } // //////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////// // Waypoints // send /* // occasionally need to send non seleceted waypoints. BOOL SendSingleDroidWaypoint(DROID *psDroid, UDWORD x,UDWORD y) { NETMSG m; UDWORD count =1; NetAdd(m,0,(psDroid->player)); // player NetAdd(m,1,x); // waypoint x NetAdd(m,5,y); // waypoint y NetAdd(m,9,count); NetAdd(m,13,psDroid->id); m.type = NET_WAYPOINT; m.size =17; return NETbcast(m,FALSE); } BOOL SendDroidWaypoint (UBYTE player,UDWORD x, UDWORD y) { NETMSG m; UDWORD count=0; DROID *psCurr; NetAdd(m,0,player); // player NetAdd(m,1,x); // waypoint x NetAdd(m,5,y); // waypoint y m.size = 13; m.type = NET_WAYPOINT; // find each droid under instruction for(psCurr = apsDroidLists[player]; psCurr; psCurr=psCurr->psNext) { if (psCurr->selected) { NetAdd(m,m.size,psCurr->id); count++; m.size += 4; } } NetAdd(m,9,count); if(count>0) { return NETbcast(m,FALSE); } else { return TRUE; } } // recv BOOL recvDroidWaypoint(NETMSG *pMsg) { UBYTE play; UDWORD x,y,count,i,id; DROID *psDroid; FORMATION *psFormation=NULL; DROID *psPrev=NULL; NetGet(pMsg,0,play); NetGet(pMsg,1,x); NetGet(pMsg,5,y); NetGet(pMsg,9,count); for(i=0;iaction) // look at the action. Some actions shouldn't be sent. { case DACTION_NONE: sendit = FALSE; // don't send if no action is taking place break; default: sendit = TRUE; break; } switch (pDroid->order) // next look at the order. { case DORDER_MOVE: sendit = FALSE; // dont bother sending if the order is just a move break; default: break; } if (!myResponsibility(pDroid->player)) // we may not be responsible, find out. { allow = FALSE; sendit = FALSE; } if(sendit) // send the mesg if required. { char player, formation; player = (char)pDroid->player; formation = (char)bFormation; NetAdd(m,0,pDroid->id); //droid to move NetAdd(m,4,x); //x pos NetAdd(m,8,y); //y pos NetAdd(m,12,player); //owner of droid(for speed!) NetAdd(m,13,formation); //use a formation? m.size = 14; m.type = NET_DROIDMOVE; NETbcast(&m,FALSE); } return allow; } // recv and updated droid position BOOL recvDroidMove(NETMSG *m) { UDWORD player,id,x,y; DROID *psDroid; UBYTE bFormation; NetGet(m,0,id); NetGet(m,4,x); NetGet(m,8,y); player = m->body[12]; NetGet(m,13,bFormation); if(!(IdToDroid(id,player,&psDroid))) // find the droid { sendRequestDroid(id); // if we can't find it, ask for it! return TRUE; } turnOffMultiMsg(TRUE); if(bFormation) { moveDroidTo(psDroid, x, y); // do the move } else { moveDroidToNoFormation(psDroid,x,y); // move, no form... } turnOffMultiMsg(FALSE); return TRUE; } // //////////////////////////////////////////////////////////////////////////// // Send a new Droid to the other players BOOL SendDroid(DROID_TEMPLATE *pTemplate, UDWORD x, UDWORD y, UBYTE player,UDWORD id) { NETMSG m; // if( ingame.localJoiningInProgress && (game.type != DMATCH) ) if( ingame.localJoiningInProgress ) { return TRUE; // dont send other droids during campaign setup. } if( !myResponsibility(player) ) // only send the droid if we are responsible { return FALSE; // dont' build if we are not responsible. } NetAdd(m,0,player); //ok since <255 players! NetAdd(m,1,x); //x pos of new droid NetAdd(m,5,y); //y pos of new droid NetAdd(m,9,id); //id of droid to create if(powerCalculated) { m.body[13] = 1; } else { m.body[13] = 0; } // new version NetAdd(m,14,pTemplate->multiPlayerID); m.size = 14+sizeof(pTemplate->multiPlayerID); m.type=NET_DROID; NETbcast(&m,FALSE); // send it. return TRUE; } // //////////////////////////////////////////////////////////////////////////// // receive droid creation information from other players BOOL recvDroid(NETMSG * m) { DROID_TEMPLATE *pT; UDWORD x,y,id; UDWORD player; UDWORD targetRef; DROID *d; player=m->body[0]; NetGet(m,1,x); // new droids x position NetGet(m,5,y); // new droids y position NetGet(m,9,id); // droid to build's id. NetGet(m,14,targetRef); pT = IdToTemplate(targetRef,player); if(!pT) { NETlogEntry("Couldn't find template to build recvd droid. val = player",0,player ); debug( LOG_NEVER, "Couldn't find template to build recvd droid" ); sendRequestDroid(id); // request the droid instead. return FALSE; } if(m->body[13] != 0) { if (!usePower(player,pT->powerPoints))// take the power. { // DBCONPRINTF(ConsoleString,(ConsoleString,"MULTIPLAYER: not enough power to build remote droid.")); NETlogEntry("not enough power to build recvd droid, val=player",0,player); // build anyway.. // return FALSE; } } turnOffMultiMsg(TRUE); d = buildDroid(pT,x,y,player, FALSE); // create that droid on this machine. turnOffMultiMsg(FALSE); if(d) { d->id = id; addDroid(d, apsDroidLists); // put droid in world } else { DBCONPRINTF(ConsoleString,(ConsoleString,"MULTIPLAYER: Couldn't build a remote droid, relying on checking to resync")); return FALSE; } return (TRUE); } // //////////////////////////////////////////////////////////////////////////// // Droid Group/selection orders. // minimises comms by sending orders for whole groups, rather than each droid BOOL SendCmdGroup(DROID_GROUP *psGroup, UWORD x, UWORD y, BASE_OBJECT *psObj) { //NETMSG m; //DROID *pDroid; //USHORT droidcount=0; return FALSE; //doesnt fukin work. return FALSE and use other msgs to cope with this (about 2 packet overhead) /* if (psObj == NULL) //it's a position order { NetAdd(m,0,x); NetAdd(m,4,y); m.body[8] = 0; // subtype flag } else // it's a object order { NetAdd(m,0, psObj->id); NetAdd(m,4, psObj->type); m.body[8]=1; // subtype flag } m.body[10]=1; // a cmd order. m.size=12; for (pDroid = psGroup->psList; pDroid; pDroid=pDroid->psGrpNext) { if (!orderState(pDroid, DORDER_RTR)) // CHANGE THIS BIT WHEN REQD!!! { NetAdd(m,m.size,pDroid->id); m.size += sizeof(UDWORD); droidcount ++; } } if( droidcount > 0 ) // return TRUE if it's worth using. { NetAdd(m,9,droidcount); // note how many in this message. m.type = NET_GROUPORDER; // send it NETbcast(&m,FALSE); return TRUE; } else { return FALSE; // didn't bother using it, so return false, to allow individiual orders. } */ } BOOL SendGroupOrderSelected(UBYTE player, UDWORD x, UDWORD y, BASE_OBJECT *psObj) { NETMSG m; DROID *pDroid; USHORT droidcount=0; if (psObj == NULL) //it's a position order { NetAdd(m,0,x); NetAdd(m,4,y); m.body[8] = 0; // subtype flag } else // it's a object order { NetAdd(m,0, psObj->id); NetAdd(m,4, psObj->type); m.body[8]=1; // subtype flag } m.body[10]=0; // not a cmd order. m.body[12] = UNKNOWN; // set the order. m.size=13; //now add the list of droid id's to order for(pDroid = apsDroidLists[player]; pDroid; pDroid=pDroid->psNext) { if (pDroid->selected) { NetAdd(m,m.size,pDroid->id); m.size += sizeof(UDWORD); droidcount ++; } } if( droidcount >1 ) // return TRUE if it's worth using. { NetAdd(m,9,droidcount); // note how many in this message. m.type = NET_GROUPORDER; // send it NETbcast(&m,FALSE); return TRUE; } else { // didn't bother using it, so return false, to allow individiual orders. return FALSE; } } BOOL SendGroupOrderGroup(DROID_GROUP *psGroup, DROID_ORDER order,UDWORD x,UDWORD y,BASE_OBJECT *psObj) { NETMSG m; DROID *pDroid; USHORT droidcount=0; if (psObj == NULL) //it's a position order { NetAdd(m,0,x); NetAdd(m,4,y); m.body[8] = 0; // subtype flag } else // it's a object order { NetAdd(m,0, psObj->id); NetAdd(m,4, psObj->type); m.body[8]=1; // subtype flag } // check this!!!!! m.body[10]=0; // not a cmd order. m.body[12] = order; // set the order. m.size=13; //now add the list of droid id's to order for(pDroid = psGroup->psList; pDroid; pDroid=pDroid->psGrpNext) { NetAdd(m,m.size,pDroid->id); m.size += sizeof(UDWORD); droidcount ++; } NetAdd(m,9,droidcount); // note how many in this message. m.type = NET_GROUPORDER; // send it NETbcast(&m,FALSE); return TRUE; } // //////////////////////////////////////////////////////////////////////////// // receive a group order. BOOL recvGroupOrder(NETMSG *pMsg) { UDWORD x,y,id,destid; DROID *psDroid=NULL; OBJECT_TYPE desttype; USHORT droidcount; // DROID *psPrev = NULL; // fomation vars. // FORMATION *psFormation = NULL; BOOL bCmdOr = FALSE; DROID_ORDER order; bCmdOr = pMsg->body[10]; order = pMsg->body[12]; NetGet(pMsg,9,droidcount); if(pMsg->body[8] == 1) // it's target is an object { NetGet(pMsg,0,destid); NetGet(pMsg,4,desttype); x=0; y=0; } else // it's target is a position { NetGet(pMsg,0,x); // x coord NetGet(pMsg,4,y); // y coord destid=0; desttype=0; } // for each droid while (droidcount > 0) { NetGet(pMsg,13+((droidcount-1) * sizeof(UDWORD)) ,id); IdToDroid(id, ANYPLAYER, &psDroid); // find the droid if (psDroid==NULL) { sendRequestDroid(id); //droid not found, request it. return (FALSE); } if(!bCmdOr) { if( (psDroid->droidType != DROID_COMMAND) && (psDroid->psGroup != NULL) && (psDroid->psGroup->type == GT_COMMAND) ) { grpLeave(psDroid->psGroup, psDroid); } } ProcessDroidOrder(psDroid,order,x,y,desttype,destid); // process the order. // no need to do formation stuff anymore. droidcount--; } return TRUE; } // //////////////////////////////////////////////////////////////////////////// // Droid update information BOOL SendDroidInfo(DROID *psDroid, DROID_ORDER order, UDWORD x, UDWORD y, BASE_OBJECT *psObj) { NETMSG m; if(!myResponsibility(psDroid->player)) { return TRUE; } NetAdd(m,0,psDroid->id); NetAdd(m,4,order); if((x==0) &&(y==0) && (psObj==NULL)) { NetAdd(m,8,x); //note: x,y not needed NetAdd(m,12,y); m.body[16] = 2; } else if (psObj == NULL) //it's a position order { NetAdd(m,8,x); NetAdd(m,12,y); m.body[16] = 0; // subtype flag } else // it's a object order { NetAdd(m,8, psObj->id); NetAdd(m,12,psObj->type); m.body[16]=1; // subtype flag } m.size=( 4*(sizeof(UDWORD)) )+1; m.type = NET_DROIDINFO; // set the type return( NETbcast(&m,FALSE)); // send it. } // //////////////////////////////////////////////////////////////////////////// // receive droid information form other players. BOOL recvDroidInfo(NETMSG *pMsg) { UDWORD x,y,id,destid; DROID_ORDER order; DROID *psDroid=NULL; OBJECT_TYPE desttype; NetGet(pMsg,0,id); //droid's id NetGet(pMsg,4,order); //droid's order if(!IdToDroid(id, ANYPLAYER, &psDroid)) { sendRequestDroid(id); //droid not found, request it. return (FALSE); } // now process the actual order.. if(pMsg->body[16] == 2) { turnOffMultiMsg(TRUE); orderDroid(psDroid, order); turnOffMultiMsg(FALSE); } else if(pMsg->body[16] == 1) // it's an object order { NetGet(pMsg,8,destid); NetGet(pMsg,12,desttype); ProcessDroidOrder(psDroid,order,0,0,desttype,destid); } else // it's a position order { NetGet(pMsg,8,x); // x coord NetGet(pMsg,12,y); // y coord ProcessDroidOrder(psDroid,order,x,y,0,0); } return TRUE; } // //////////////////////////////////////////////////////////////////////////// // process droid order static VOID ProcessDroidOrder(DROID *psDroid, DROID_ORDER order,UDWORD x, UDWORD y, OBJECT_TYPE desttype,UDWORD destid) { UDWORD i; DROID *pD; STRUCTURE *pS; FEATURE *pF; BASE_OBJECT *psObj= NULL; if(destid==0 && desttype==0) // target is a location { if( abs(psDroid->x - x )< (TILE_UNITS/2) && abs(psDroid->y - y )< (TILE_UNITS/2) ) // don't bother if close. { return; } if(order == UNKNOWN) // get the order to do if we didn't specify it. { order = chooseOrderLoc(psDroid, x,y); } turnOffMultiMsg(TRUE); orderDroidLoc(psDroid, order, x,y); turnOffMultiMsg(FALSE); } else // target is object { switch(desttype) { case OBJ_DROID: psObj = NULL; for (i=0; iid != destid);pD=pD->psNext); if(pD) { psObj = (BASE_OBJECT*)pD; } } break; case OBJ_STRUCTURE: psObj = NULL; pS = IdToStruct(destid,ANYPLAYER); if(pS) { psObj = (BASE_OBJECT*)pS; } break; case OBJ_FEATURE: psObj = NULL; pF = IdToFeature(destid,ANYPLAYER); if(pF) { psObj = (BASE_OBJECT*)pF; } break; case OBJ_BULLET: // shouldn't be getting this! debug( LOG_ERROR, "multibot: order specified destination as a bullet. what am i to do??" ); abort(); break; default: debug( LOG_ERROR, "unknown object type" ); abort(); } if(!psObj) // failed to find it; { return; } // if we didn't sepcify an order, then make one.. if(order == UNKNOWN) // get the order to do if we didn't specify it. { order = chooseOrderObj(psDroid,psObj); } turnOffMultiMsg(TRUE); orderDroidObj(psDroid, order, psObj); turnOffMultiMsg(FALSE); } } // //////////////////////////////////////////////////////////////////////////// // Inform other players that a droid has been destroyed BOOL SendDestroyDroid(DROID *pD) { NETMSG m; NetAdd(m,0,pD->id); // id of the droid to be destroyed m.size = sizeof(UDWORD); m.type = NET_DROIDDEST; return( NETbcast(&m,TRUE)); //guaranteed msg????? } // //////////////////////////////////////////////////////////////////////////// // Accept a droid which was destroyed on another machine BOOL recvDestroyDroid(NETMSG *pMsg) { DROID *pD; UDWORD r; NetGet(pMsg,0,r); // get the id of the droid. if( IdToDroid(r, ANYPLAYER, &pD) ) { if(!pD->died) { turnOffMultiMsg(TRUE); destroyDroid(pD); // remove the droid recvd from the remote players machine. turnOffMultiMsg(FALSE); } return (TRUE); } else { return FALSE; } } // //////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////// // stuff for sending the WHOLE of a droid! BOOL sendWholeDroid(DROID *pD, DPID dest) { NETMSG m; UDWORD sizecount=0; UDWORD noTarget =0; SDWORD asParts[DROID_MAXCOMP]; UDWORD asWeaps[DROID_MAXWEAPS]; if (pD->asWeaps[0].nStat > 0) // build some bits for the template. { asWeaps[0] = pD->asWeaps[0].nStat; } else { asWeaps[0] = 0; } asParts[COMP_BODY] = pD->asBits[COMP_BODY].nStat; //allocate the components asParts[COMP_BRAIN] = pD->asBits[COMP_BRAIN].nStat; asParts[COMP_PROPULSION]= pD->asBits[COMP_PROPULSION].nStat; asParts[COMP_SENSOR] = pD->asBits[COMP_SENSOR].nStat; asParts[COMP_ECM] = pD->asBits[COMP_ECM].nStat; asParts[COMP_REPAIRUNIT]= pD->asBits[COMP_REPAIRUNIT].nStat; asParts[COMP_CONSTRUCT] = pD->asBits[COMP_CONSTRUCT].nStat; asParts[COMP_WEAPON] = pD->asBits[COMP_WEAPON].nStat; NetAdd(m,sizecount,asParts); sizecount+=sizeof(asParts); NetAdd(m,sizecount,asWeaps); sizecount+=sizeof(asWeaps); // to build a template. NetAdd(m,sizecount,pD->x); sizecount+=sizeof(pD->x); NetAdd(m,sizecount,pD->y); sizecount+=sizeof(pD->y); NetAdd(m,sizecount,pD->z); sizecount+=sizeof(pD->z); NetAdd(m,sizecount,pD->player); sizecount+=sizeof(pD->player); NetAddSt(m,sizecount,pD->aName); sizecount+=strlen(pD->aName)+1; // that's enough to build a template, now the specific stuff! NetAdd(m,sizecount,pD->id); sizecount+=sizeof(pD->id); NetAdd(m,sizecount,pD->NameVersion); sizecount+=sizeof(pD->NameVersion); NetAdd(m,sizecount,pD->droidType); sizecount+=sizeof(pD->droidType); NetAdd(m,sizecount,pD->direction); sizecount+=sizeof(pD->direction); NetAdd(m,sizecount,pD->pitch); sizecount+=sizeof(pD->pitch); NetAdd(m,sizecount,pD->roll); sizecount+=sizeof(pD->roll); NetAdd(m,sizecount,pD->visible); sizecount+=sizeof(pD->visible); NetAdd(m,sizecount,pD->inFire); sizecount+=sizeof(pD->inFire); NetAdd(m,sizecount,pD->burnDamage); sizecount+=sizeof(pD->burnDamage); NetAdd(m,sizecount,pD->body); sizecount+=sizeof(pD->body); NetAdd(m,sizecount,pD->secondaryOrder); sizecount+=sizeof(pD->secondaryOrder); NetAdd(m,sizecount,pD->order); sizecount+=sizeof(pD->order); NetAdd(m,sizecount,pD->orderX); sizecount+=sizeof(pD->orderX); NetAdd(m,sizecount,pD->orderY); sizecount+=sizeof(pD->orderY); NetAdd(m,sizecount,pD->orderX2); sizecount+=sizeof(pD->orderX2); NetAdd(m,sizecount,pD->orderY2); sizecount+=sizeof(pD->orderY2); if (pD->psTarget) { NetAdd(m,sizecount,pD->psTarget->id); sizecount+=sizeof(pD->psTarget->id); } else { NetAdd(m,sizecount,noTarget); sizecount+=sizeof(noTarget); } if (pD->psTarStats) { NetAdd(m,sizecount,pD->psTarStats->ref); sizecount+=sizeof(pD->psTarStats->ref); } else { NetAdd(m,sizecount,noTarget); sizecount+=sizeof(noTarget); } m.type = NET_WHOLEDROID; m.size = (UWORD)sizecount; return NETsend(&m,dest,FALSE); } // //////////////////////////////////////////////////////////////////////////// // receive a whole droid!!!! BOOL receiveWholeDroid(NETMSG *m) { UDWORD sizecount=0; DROID_TEMPLATE dt; DROID *pD,*existingdroid; // BOOL temp= FALSE; DROIDSTORE *tempDroid; //UDWORD x,y,z,id; UWORD x,y,z; UDWORD id; UBYTE player; // get the stuff NetGet(m,sizecount,dt.asParts); sizecount+=sizeof(dt.asParts); // build a template // NetGet(m,sizecount,dt.powerPoints); sizecount+=sizeof(dt.powerPoints); NetGet(m,sizecount,dt.asWeaps); sizecount+=sizeof(dt.asWeaps); NetGet(m,sizecount,x); sizecount+=sizeof(x); // edit it. NetGet(m,sizecount,y); sizecount+=sizeof(y); NetGet(m,sizecount,z); sizecount+=sizeof(z); NetGet(m,sizecount,player); sizecount+=sizeof(player); dt.pName = (CHAR*)&dt.aName; strncpy(dt.aName, &(m->body[sizecount]), DROID_MAXNAME-1); dt.aName[DROID_MAXNAME-1]=0; // just in case. sizecount+=strlen(dt.pName)+1; // name is pointed at directly into the buffer. if(dt.asWeaps[0] == 0) { dt.numWeaps =0; } else { dt.numWeaps = 1; } dt.powerPoints = calcTemplatePower(&dt); NetGet(m,sizecount,id); sizecount+=sizeof(id); if(IdToDroid(id,ANYPLAYER,&existingdroid))// if a droid of id already exists then go no further. { return FALSE; } // could do usepower , but we usually do this in an emergency, so leave it! turnOffMultiMsg(TRUE); pD = buildDroid(&dt,x,y,player, FALSE); // make a droid turnOffMultiMsg(FALSE); if(!pD) // failed to build it, give up. { return FALSE; } // now the instance specific stuff. pD->id = id; pD->x = x; //correct builddroid to use exact pos, not tile center pD->y = y; pD->z = z; NetGet(m,sizecount,pD->NameVersion); sizecount+=sizeof(pD->NameVersion); NetGet(m,sizecount,pD->droidType); sizecount+=sizeof(pD->droidType); NetGet(m,sizecount,pD->direction); sizecount+=sizeof(pD->direction); NetGet(m,sizecount,pD->pitch); sizecount+=sizeof(pD->pitch); NetGet(m,sizecount,pD->roll); sizecount+=sizeof(pD->roll); NetGet(m,sizecount,pD->visible); sizecount+=sizeof(pD->visible); NetGet(m,sizecount,pD->inFire); sizecount+=sizeof(pD->inFire); NetGet(m,sizecount,pD->burnDamage); sizecount+=sizeof(pD->burnDamage); NetGet(m,sizecount,pD->body); sizecount+=sizeof(pD->body); NetGet(m,sizecount,pD->secondaryOrder); sizecount+=sizeof(pD->secondaryOrder); if(ingame.localJoiningInProgress) { NetGet(m,sizecount,pD->order); sizecount+=sizeof(pD->order); // processed laater NetGet(m,sizecount,pD->orderX); sizecount+=sizeof(pD->orderX); //later! NetGet(m,sizecount,pD->orderY); sizecount+=sizeof(pD->orderY); //later! NetGet(m,sizecount,pD->orderX2); sizecount+=sizeof(pD->orderX2); NetGet(m,sizecount,pD->orderY2); sizecount+=sizeof(pD->orderY2); NetGet(m,sizecount,pD->psTarget); sizecount+=sizeof(pD->psTarget); //later! NetGet(m,sizecount,pD->psTarStats); sizecount+=sizeof(pD->psTarStats); //later! //store the droid for later. tempDroid = MALLOC(sizeof(DROIDSTORE)); tempDroid->psDroid = pD; tempDroid->psNext = tempDroidList; tempDroidList = tempDroid; } else //don't bother setting the orders. they'll update sooner or later anywho. { pD->order = 0; pD->orderX = 0; pD->orderY = 0; pD->psTarget = 0; pD->psTarStats= 0; addDroid(pD, apsDroidLists); } return TRUE; } // //////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////// // Functions for cases where a machine receives a netmessage about a certain // droid. The droid is unknown, so the machine uses tese functions in order to // find out about it. BOOL sendRequestDroid(UDWORD droidId) { NETMSG msg; if(ingame.localJoiningInProgress) // dont worry if still joining. { return FALSE; } NetAdd(msg,0,droidId); NetAdd(msg,4,player2dpid[selectedPlayer] ); debug( LOG_NEVER, "multibot: unknown droid %d, requesting info\n", droidId ); msg.type = NET_REQUESTDROID; msg.size = sizeof(DPID)+sizeof(UDWORD); NETbcast(&msg,FALSE); return TRUE; } // //////////////////////////////////////////////////////////////////////////// BOOL recvRequestDroid(NETMSG *pMsg) { DROID *pDroid; UDWORD droidid,dpid; NetGet(pMsg,0,droidid); // get the droid's id NetGet(pMsg,4,dpid); // get the player who needs it. if(!(IdToDroid(droidid , ANYPLAYER,&pDroid) ) ) // find the droid { return TRUE; // can't find it, so ignore. } if(myResponsibility(pDroid->player)) // if resposible { sendWholeDroid(pDroid,dpid); // send the whole of the droid } return TRUE; }