diff options
Diffstat (limited to 'src/parsec/net_rmev.cpp')
| -rw-r--r-- | src/parsec/net_rmev.cpp | 1284 |
1 files changed, 1284 insertions, 0 deletions
diff --git a/src/parsec/net_rmev.cpp b/src/parsec/net_rmev.cpp new file mode 100644 index 0000000..db18794 --- /dev/null +++ b/src/parsec/net_rmev.cpp @@ -0,0 +1,1284 @@ +/* + * PARSEC - Remote Events + * + * $Author: uberlinuxguy $ - $Date: 2004/09/26 03:43:40 $ + * + * Orginally written by: + * Copyright (c) Clemens Beer <cbx@parsec.org> 2001-2002 + * Copyright (c) Markus Hadwiger <msh@parsec.org> 1996-2000 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +// C library +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// compilation flags/debug support +#include "config.h" +#include "linkinfo.h" +#include "debug.h" + +// general definitions +#include "general.h" +#include "objstruc.h" +#include "od_class.h" + +// global externals +#include "globals.h" + +// subsystem headers +#include "aud_defs.h" +#include "net_defs.h" +#include "sys_defs.h" + +// network code config +#include "net_conf.h" + +// local module header +#include "net_rmev.h" + +// proprietary module headers +#include "con_aux.h" +#include "con_say.h" +#include "h_supp.h" +#include "net_game.h" +#include "obj_creg.h" +#include "obj_ctrl.h" +#include "obj_xtra.h" +#include "g_sfx.h" +#include "g_wfx.h" +#include "g_emp.h" +#include "g_swarm.h" + + + +// string scratchpad +#define PASTE_STR_LEN 1023 +static char paste_str[ PASTE_STR_LEN + 1 ]; + +// external flag +int name_change_notification = TRUE; + + + +// table of remote event sizes ------------------------------------------------ +// +static size_t re_sizes[] = { + + sizeof( RE_Header ), + sizeof( RE_Header ), + sizeof( RE_CreateObject ), + sizeof( RE_CreateLaser ), + sizeof( RE_CreateMissile ), + sizeof( RE_CreateExtra ), + sizeof( RE_KillObject ), + sizeof( RE_SendText ), + sizeof( RE_PlayerName ), + sizeof( RE_ParticleObject ), + sizeof( RE_PlayerList ), + sizeof( RE_ConnectQueue ), + sizeof( RE_WeaponState ), + sizeof( RE_StateSync ), + sizeof( RE_CreateSwarm ), + sizeof( RE_CreateEmp ), + sizeof( RE_OwnerSection ), + sizeof( RE_PlayerStatus ), + sizeof( RE_PlayerAndShipStatus ), + sizeof( RE_KillStats ), + sizeof( RE_GameState ), + sizeof( RE_CommandInfo ), + sizeof( RE_ClientInfo ), + sizeof( RE_CreateExtra2 ), + sizeof( RE_IPv4ServerInfo ), + sizeof( RE_ServerLinkInfo ), + sizeof( RE_MapObject ), + sizeof( RE_Stargate ), + sizeof( RE_CreateMine ), +}; + + +// check if enough space in RE_List for specified remote event ---------------- +// +int NET_RmEvAllowed( int re_type ) +{ + if ( NetConnected != NETWORK_GAME_ON ) + return TRUE; + + ASSERT( re_type > RE_DELETED ); + ASSERT( re_type < RE_NUMEVENTS ); + ASSERT( re_type != RE_SENDTEXT ); + ASSERT( re_type != RE_PLAYERLIST ); + ASSERT( re_type != RE_CONNECTQUEUE ); + ASSERT( re_type != RE_OWNERSECTION ); + + if ( NetConnected && ( (size_t)RE_List_Avail < re_sizes[ re_type ] ) ) + return FALSE; + + //NOTE: + // if the connection is down the check need not be performed since + // all insertion functions will skip the insertion in that case. + + return TRUE; +} + + +// determine size of remote event --------------------------------------------- +// +size_t NET_RmEvGetSize( RE_Header *relist ) +{ + ASSERT( relist != NULL ); + byte retype = relist->RE_Type; + + // use stored size for remote-events of variable size + if ( ( retype == RE_DELETED ) || ( retype == RE_SENDTEXT ) || ( retype == RE_COMMANDINFO ) ) { + ASSERT( relist->RE_BlockSize != RE_BLOCKSIZE_INVALID ); + return relist->RE_BlockSize; + } + + ASSERT( retype > RE_DELETED ); + ASSERT( retype < RE_NUMEVENTS ); + + return re_sizes[ retype ]; +} + + +// insert playername into RE_List --------------------------------------------- +// +int NET_RmEvPlayerName( const char *name ) +{ + //NOTE: + // calling NET_RmEvAllowed() is NOT mandatory + // before calling this function. + + ASSERT( name != NULL ); + + if ( NetConnected == NETWORK_GAME_ON ) { + + // this is no fault condition + if ( (size_t)RE_List_Avail < sizeof( RE_PlayerName ) ) + return 0; + + RE_PlayerName *re_playername = (RE_PlayerName *) RE_List_CurPos; + re_playername->RE_Type = RE_PLAYERNAME; + re_playername->RE_BlockSize = sizeof( RE_PlayerName ); + CopyRemoteName( re_playername->PlayerName, name ); + + re_playername++; + re_playername->RE_Type = RE_EMPTY; + + RE_List_CurPos = (char *) re_playername; + RE_List_Avail -= sizeof( RE_PlayerName ); + + // this has to be done here although it is also done + // by NET_UTIL::NET_SetPlayerName() later on, because + // NET_ServerUpdateName() already needs the new name. + strcpy( Player_Name[ LocalPlayerId ], name ); + + // update name on server if playing with a server-based protocol + if ( !NETs_UpdateName() ) { + + // restore old name if name change on server + // not possible or forbidden. PlayerName has + // not been altered by NETs_UpdateName()! + strcpy( Player_Name[ LocalPlayerId ], LocalPlayerName ); + return 0; + } + } + + return 1; +} + + +// insert text to send into RE_List ------------------------------------------- +// +int NET_RmEvSendText( const char *text ) +{ + //NOTE: + // calling NET_RmEvAllowed() is NOT mandatory + // before calling this function. + + //NOTE: + // the maximum transmitted text-length is 252. + // (excluding the terminating zero-byte.) + + ASSERT( text != NULL ); + if(strlen(text) == 0) + return 1; + if ( NetConnected == NETWORK_GAME_ON ) { + + // make copy of text + strncpy( paste_str, LocalPlayerName, MAX_PLAYER_NAME); + strncat( paste_str," ",1); + strncat( paste_str, text, (PASTE_STR_LEN - MAX_PLAYER_NAME - 1)); + paste_str[ PASTE_STR_LEN ] = 0; + + int textlen = strlen( text ) + strlen(LocalPlayerName) + 1; //Name + space(1) + text + int blocksiz = sizeof( RE_SendText ) + textlen; + // terminating zero-byte is included in sizeof( RE_SendText ) + + // this is no fault condition + if ( RE_List_Avail < blocksiz ) + return 0; + + // cut text if blocksize doesn't fit in one byte + ASSERT( blocksiz > 2 ); + if ( blocksiz > 255 ) { + blocksiz = 255; + paste_str[ 255 - sizeof( RE_SendText ) ] = 0; + } + + RE_SendText *re_sendtext = (RE_SendText *) RE_List_CurPos; + re_sendtext->RE_Type = RE_SENDTEXT; + re_sendtext->RE_BlockSize = blocksiz; + strcpy( re_sendtext->TextStart, paste_str ); + + re_sendtext = (RE_SendText *) ( (char *)re_sendtext + blocksiz ); + re_sendtext->RE_Type = RE_EMPTY; + RE_List_CurPos = (char *) re_sendtext; + RE_List_Avail -= blocksiz; + } + + return 1; +} + + +// insert generic object into RE_List ----------------------------------------- +// +int NET_RmEvObject( const GenObject *objpo ) +{ + //NOTE: + // calling NET_RmEvAllowed() is mandatory + // before calling this function. + + ASSERT( objpo != NULL ); + + if ( NetConnected == NETWORK_GAME_ON ) { + + if ( (size_t)RE_List_Avail < sizeof( RE_CreateObject ) ) { + ASSERT( 0 ); + return 0; + } + + RE_CreateObject *re_createobject = (RE_CreateObject *) RE_List_CurPos; + re_createobject->RE_Type = RE_CREATEOBJECT; + re_createobject->RE_BlockSize = sizeof( RE_CreateObject ); + re_createobject->ObjectClass = objpo->ObjectClass; + re_createobject->HostObjId = objpo->HostObjNumber; + memcpy( &re_createobject->ObjPosition, &objpo->ObjPosition, sizeof( Xmatrx ) ); + re_createobject->Flags = 0x00000000; + + re_createobject++; + re_createobject->RE_Type = RE_EMPTY; + + RE_List_CurPos = (char *) re_createobject; + RE_List_Avail -= sizeof( RE_CreateObject ); + } + + return 1; +} + + +// insert laser into RE_List -------------------------------------------------- +// +int NET_RmEvLaser( const LaserObject *laserpo ) +{ + //NOTE: + // calling NET_RmEvAllowed() is mandatory + // before calling this function. + + ASSERT( laserpo != NULL ); + + if ( NetConnected == NETWORK_GAME_ON ) { + + if ( (size_t)RE_List_Avail < sizeof( RE_CreateLaser ) ) { + ASSERT( 0 ); + return 0; + } + + RE_CreateLaser *re_createlaser = (RE_CreateLaser *) RE_List_CurPos; + re_createlaser->RE_Type = RE_CREATELASER; + re_createlaser->RE_BlockSize = sizeof( RE_CreateLaser ); + re_createlaser->ObjectClass = laserpo->ObjectClass; + re_createlaser->HostObjId = laserpo->HostObjNumber; + memcpy( &re_createlaser->ObjPosition, &laserpo->ObjPosition, sizeof( Xmatrx ) ); + re_createlaser->DirectionVec = laserpo->DirectionVec; + + re_createlaser++; + re_createlaser->RE_Type = RE_EMPTY; + + RE_List_CurPos = (char *) re_createlaser; + RE_List_Avail -= sizeof( RE_CreateLaser ); + } + + return 1; +} + + +// insert missile into RE_List ------------------------------------------------ +// +int NET_RmEvMissile( const MissileObject *missilepo, dword targetobjid ) +{ + //NOTE: + // calling NET_RmEvAllowed() is mandatory + // before calling this function. + + ASSERT( missilepo != NULL ); + + if ( NetConnected == NETWORK_GAME_ON ) { + + if ( (size_t)RE_List_Avail < sizeof( RE_CreateMissile ) ) { + ASSERT( 0 ); + return 0; + } + + RE_CreateMissile *re_createmissl = (RE_CreateMissile *) RE_List_CurPos; + re_createmissl->RE_Type = RE_CREATEMISSILE; + re_createmissl->RE_BlockSize = sizeof( RE_CreateMissile ); + re_createmissl->ObjectClass = missilepo->ObjectClass; + re_createmissl->HostObjId = missilepo->HostObjNumber; + re_createmissl->TargetHostObjId = targetobjid; + memcpy( &re_createmissl->ObjPosition, &missilepo->ObjPosition, sizeof( Xmatrx ) ); + re_createmissl->DirectionVec = missilepo->DirectionVec; + + re_createmissl++; + re_createmissl->RE_Type = RE_EMPTY; + + RE_List_CurPos = (char *) re_createmissl; + RE_List_Avail -= sizeof( RE_CreateMissile ); + } + + return 1; +} + +// insert extra into RE_List -------------------------------------------------- +// +int NET_RmEvMine( const ExtraObject *extrapo ) +{ + //NOTE: + // calling NET_RmEvAllowed() is mandatory + // before calling this function. + + ASSERT( extrapo != NULL ); + + // DSEXC( return 1 ); + + if ( NetConnected == NETWORK_GAME_ON ) { + + if ( (size_t)RE_List_Avail < sizeof( RE_CreateExtra ) ) { + ASSERT( 0 ); + return 0; + } + + int extraindex = ObjClassExtraIndex[ extrapo->ObjectClass ]; + ASSERT( extraindex != EXTRAINDEX_NO_EXTRA ); + + RE_CreateExtra *re_createextra = (RE_CreateExtra *) RE_List_CurPos; + re_createextra->RE_Type = RE_CREATEMINE; + re_createextra->RE_BlockSize = sizeof( RE_CreateExtra ); + re_createextra->ExtraIndex = extraindex; + re_createextra->HostObjId = extrapo->HostObjNumber; + memcpy( &re_createextra->ObjPosition, &extrapo->ObjPosition, sizeof( Xmatrx ) ); + + re_createextra++; + re_createextra->RE_Type = RE_EMPTY; + + RE_List_CurPos = (char *) re_createextra; + RE_List_Avail -= sizeof( RE_CreateExtra ); + } + + return 1; +} + +// insert extra into RE_List -------------------------------------------------- +// +int NET_RmEvExtra( const ExtraObject *extrapo ) +{ + //NOTE: + // calling NET_RmEvAllowed() is mandatory + // before calling this function. + + ASSERT( extrapo != NULL ); + +// DSEXC( return 1 ); + + if ( NetConnected == NETWORK_GAME_ON ) { + + if ( (size_t)RE_List_Avail < sizeof( RE_CreateExtra ) ) { + ASSERT( 0 ); + return 0; + } + + int extraindex = ObjClassExtraIndex[ extrapo->ObjectClass ]; + ASSERT( extraindex != EXTRAINDEX_NO_EXTRA ); + + RE_CreateExtra *re_createextra = (RE_CreateExtra *) RE_List_CurPos; + re_createextra->RE_Type = RE_CREATEEXTRA; + re_createextra->RE_BlockSize = sizeof( RE_CreateExtra ); + re_createextra->ExtraIndex = extraindex; + re_createextra->HostObjId = extrapo->HostObjNumber; + memcpy( &re_createextra->ObjPosition, &extrapo->ObjPosition, sizeof( Xmatrx ) ); + + re_createextra++; + re_createextra->RE_Type = RE_EMPTY; + + RE_List_CurPos = (char *) re_createextra; + RE_List_Avail -= sizeof( RE_CreateExtra ); + } + + return 1; +} + +// insert particle object into RE_List ---------------------------------------- +// +int NET_RmEvParticleObject( int type, const Vertex3& origin ) +{ + //NOTE: + // calling NET_RmEvAllowed() is mandatory + // before calling this function. + +// DSEXC( return 1 ); + + if ( NetConnected == NETWORK_GAME_ON ) { + + if ( (size_t)RE_List_Avail < sizeof( RE_ParticleObject ) ) { + ASSERT( 0 ); + return 0; + } + + RE_ParticleObject *re_particleobject = (RE_ParticleObject *) RE_List_CurPos; + re_particleobject->RE_Type = RE_PARTICLEOBJECT; + re_particleobject->RE_BlockSize = sizeof( RE_ParticleObject ); + re_particleobject->ObjectType = type; + re_particleobject->Origin = origin; + + re_particleobject++; + re_particleobject->RE_Type = RE_EMPTY; + + RE_List_CurPos = (char *) re_particleobject; + RE_List_Avail -= sizeof( RE_ParticleObject ); + } + + return 1; +} + + +// insert weapon state update into RE_List ------------------------------------ +// +int NET_RmEvWeaponState( dword weapon, byte state, int energy, dword specials ) +{ + //NOTE: + // calling NET_RmEvAllowed() is mandatory + // before calling this function. + + if ( NetConnected == NETWORK_GAME_ON ) { + + if ( (size_t)RE_List_Avail < sizeof( RE_WeaponState ) ) { + ASSERT( 0 ); + return 0; + } + + RE_WeaponState *re_weaponstate = (RE_WeaponState *) RE_List_CurPos; + re_weaponstate->RE_Type = RE_WEAPONSTATE; + re_weaponstate->RE_BlockSize = sizeof( RE_WeaponState ); + re_weaponstate->State = state; + re_weaponstate->WeaponMask = weapon; + // re_weaponstate->Specials = specials; //CrazySpence changed this, this comment is so he knows to change it back if it bites him in the ass + re_weaponstate->CurEnergy = energy; + re_weaponstate->SenderId = LocalPlayerId; + re_weaponstate++; + re_weaponstate->RE_Type = RE_EMPTY; + + RE_List_CurPos = (char *) re_weaponstate; + RE_List_Avail -= sizeof( RE_WeaponState ); + } + + return 1; +} + + +// insert state sync into RE_List --------------------------------------------- +// +int NET_RmEvStateSync( dword statekey, dword stateval ) +{ + //NOTE: + // calling NET_RmEvAllowed() is mandatory + // before calling this function. + + if ( NetConnected == NETWORK_GAME_ON ) { + + if ( (size_t)RE_List_Avail < sizeof( RE_StateSync ) ) { + ASSERT( 0 ); + return 0; + } + + RE_StateSync *re_statesync = (RE_StateSync *) RE_List_CurPos; + re_statesync->RE_Type = RE_STATESYNC; + re_statesync->RE_BlockSize = sizeof( RE_StateSync ); + re_statesync->StateKey = (word)statekey; + re_statesync->StateValue = stateval; + + re_statesync++; + re_statesync->RE_Type = RE_EMPTY; + + RE_List_CurPos = (char *) re_statesync; + RE_List_Avail -= sizeof( RE_StateSync ); + } + + return 1; +} + + +// insert swarm into RE_List -------------------------------------------------- +// +int NET_RmEvCreateSwarm( Vertex3 *origin, dword targetobjid, dword seed ) +{ + //NOTE: + // calling NET_RmEvAllowed() is mandatory + // before calling this function. + + if ( NetConnected == NETWORK_GAME_ON ) { + + if ( (size_t)RE_List_Avail < sizeof( RE_CreateSwarm ) ) { + ASSERT( 0 ); + return 0; + } + + RE_CreateSwarm *re_createswarm = (RE_CreateSwarm *) RE_List_CurPos; + re_createswarm->RE_Type = RE_CREATESWARM; + re_createswarm->RE_BlockSize = sizeof( RE_CreateSwarm ); + re_createswarm->Origin = *origin; + re_createswarm->TargetHostObjId = targetobjid; + re_createswarm->RandSeed = seed; + re_createswarm->SenderId = LocalPlayerId; + re_createswarm++; + re_createswarm->RE_Type = RE_EMPTY; + + RE_List_CurPos = (char *) re_createswarm; + RE_List_Avail -= sizeof( RE_CreateSwarm ); + } + + return 1; +} + + +// insert emp into RE_List ---------------------------------------------------- +// +int NET_RmEvCreateEmp( int upgradelevel ) +{ + //NOTE: + // calling NET_RmEvAllowed() is mandatory + // before calling this function. + + if ( NetConnected == NETWORK_GAME_ON ) { + + if ( (size_t)RE_List_Avail < sizeof( RE_CreateEmp ) ) { + ASSERT( 0 ); + return 0; + } + + RE_CreateEmp *re_createemp = (RE_CreateEmp *) RE_List_CurPos; + re_createemp->RE_Type = RE_CREATEEMP; + re_createemp->RE_BlockSize = sizeof( RE_CreateEmp ); + re_createemp->Upgradelevel = upgradelevel; + re_createemp->SenderId = LocalPlayerId; + + re_createemp++; + re_createemp->RE_Type = RE_EMPTY; + + RE_List_CurPos = (char *) re_createemp; + RE_List_Avail -= sizeof( RE_CreateEmp ); + } + + return 1; +} + + +// insert object kill event into RE_List -------------------------------------- +// +int NET_RmEvKillObject( dword objid, byte listno ) +{ + //NOTE: + // calling NET_RmEvAllowed() is NOT mandatory + // before calling this function. + +#ifdef NO_PROJECTILE_KILL_MESSAGES + + // for projectiles depend on local client lifetime expiration + if ( ( listno == LASER_LIST ) || ( listno == MISSL_LIST ) ) { + return 1; + } + ASSERT( listno == EXTRA_LIST ); + +#endif + +#ifdef SEND_KILL_MESSAGES + + if ( NetConnected == NETWORK_GAME_ON ) { + + if ( (size_t)RE_List_Avail < sizeof( RE_KillObject ) ) + return 0; + + RE_KillObject *re_killobject = (RE_KillObject *) RE_List_CurPos; + re_killobject->RE_Type = RE_KILLOBJECT; + re_killobject->RE_BlockSize = sizeof( RE_KillObject ); + re_killobject->HostObjId = objid; + re_killobject->ListId = listno; + + re_killobject++; + re_killobject->RE_Type = RE_EMPTY; + + RE_List_CurPos = (char *) re_killobject; + RE_List_Avail -= sizeof( RE_KillObject ); + } + +#endif + + return 1; +} + +// insert RE_PlayerStatus event into RE_List ---------------------------------- +// +RE_PlayerStatus* NET_RmEvPlayerStatus( byte last_unjoin_flag ) +{ + //NOTE: + // calling NET_RmEvAllowed() is mandatory + // before calling this function. + + if ( NetConnected == NETWORK_GAME_ON ) { + + if ( (size_t)RE_List_Avail < sizeof( RE_PlayerStatus ) ) { + ASSERT( 0 ); + return NULL; + } + + RE_PlayerStatus* re_playerstatus = (RE_PlayerStatus*) RE_List_CurPos; + re_playerstatus->RE_Type = RE_PLAYERSTATUS; + re_playerstatus->RE_BlockSize = sizeof( RE_PlayerStatus ); + + re_playerstatus->senderid = LocalPlayerId; + re_playerstatus->objectindex = ObjClassShipIndex[ MyShip->ObjectClass ]; + + // set desired player status + re_playerstatus->player_status = Player_Status[ LocalPlayerId ]; + + //FIXME: only send "normal" unjoin to server + // send last unjoin to server ( include killer ) + if ( Player_Status[ LocalPlayerId ] == PLAYER_CONNECTED ) { + + // store reason for last unjoin + re_playerstatus->params[ 0 ] = last_unjoin_flag; + + // enable remote player to determine who killed us if ( param1 == SHIP_DOWNED ) + if ( last_unjoin_flag == SHIP_DOWNED ) { + ASSERT( ( CurKiller >= KILLERID_UNKNOWN ) && ( CurKiller < MAX_NET_PROTO_PLAYERS + KILLERID_BIAS ) ); + ASSERT( ( CurKiller >= 0 ) && ( CurKiller < 128 ) ); + re_playerstatus->params[ 3 ] = CurKiller; + } + } + + // store the refframe for serverside movement checks + re_playerstatus->RefFrame = SYSs_GetRefFrameCount(); + + RE_PlayerStatus* re = re_playerstatus; + + re_playerstatus++; + re_playerstatus->RE_Type = RE_EMPTY; + + RE_List_CurPos = (char *) re_playerstatus; + RE_List_Avail -= sizeof( RE_PlayerStatus ); + + // return the remote event added + return re; + } + + return NULL; +} + + +// insert PlayerAndShipStatus event into RE_List ------------------------------ +// +RE_PlayerAndShipStatus* NET_RmEvPlayerAndShipStatus ( byte last_unjoin_flag ) +{ + //NOTE: + // calling NET_RmEvAllowed() is mandatory + // before calling this function. + + if ( NetConnected == NETWORK_GAME_ON ) { + + if ( (size_t)RE_List_Avail < sizeof( RE_PlayerAndShipStatus ) ) { + ASSERT( 0 ); + return NULL; + } + + RE_PlayerAndShipStatus* re_pas_status = (RE_PlayerAndShipStatus*) RE_List_CurPos; + re_pas_status->RE_Type = RE_PLAYERANDSHIPSTATUS; + re_pas_status->RE_BlockSize = sizeof( RE_PlayerAndShipStatus ); + + re_pas_status->senderid = LocalPlayerId; + re_pas_status->objectindex = ObjClassShipIndex[ MyShip->ObjectClass ]; + + // set remote player's damage and speed from ship-object structure + re_pas_status->CurDamage = MyShip->CurDamage; + re_pas_status->CurShield = MyShip->CurShield; + re_pas_status->CurSpeed = MyShip->CurSpeed; + + // store current position of player + memcpy( &re_pas_status->ObjPosition, &MyShip->ObjPosition, sizeof( Xmatrx ) ); + + // store speeds for interpolation + re_pas_status->CurYaw = CurYaw; + re_pas_status->CurPitch = CurPitch; + re_pas_status->CurRoll = CurRoll; + re_pas_status->CurSlideHorz = CurSlideHorz; + re_pas_status->CurSlideVert = CurSlideVert; + + // set desired player status + re_pas_status->player_status = Player_Status[ LocalPlayerId ]; + + //FIXME: only send "normal" unjoin to server + // send last unjoin to server ( include killer ) + if ( Player_Status[ LocalPlayerId ] == PLAYER_CONNECTED ) { + + // store reason for last unjoin + re_pas_status->params[ 0 ] = last_unjoin_flag; + + // enable remote player to determine who killed us if ( param1 == SHIP_DOWNED ) + if ( last_unjoin_flag == SHIP_DOWNED ) { + ASSERT( ( CurKiller >= KILLERID_UNKNOWN ) && ( CurKiller < MAX_NET_PROTO_PLAYERS + KILLERID_BIAS ) ); + ASSERT( ( CurKiller >= 0 ) && ( CurKiller < 128 ) ); + re_pas_status->params[ 3 ] = CurKiller; + } + } + + // store the refframe for serverside movement checks + re_pas_status->RefFrame = SYSs_GetRefFrameCount(); + + RE_PlayerAndShipStatus* re = re_pas_status; + + re_pas_status++; + re_pas_status->RE_Type = RE_EMPTY; + + RE_List_CurPos = (char *) re_pas_status; + RE_List_Avail -= sizeof( RE_PlayerAndShipStatus ); + + // return the remote event added + return re; + } + + return NULL; +} + + +// execute received remote event: create object ------------------------------- +// +void NET_ExecRmEvCreateObject( RE_Header *rmev, int ownerid ) +{ + ASSERT( rmev != NULL ); + ASSERT( rmev->RE_Type == RE_CREATEOBJECT ); + ASSERT( ( ownerid >= 0 ) && ( ownerid < MAX_NET_PROTO_PLAYERS ) ); + + RE_CreateObject *re_co = (RE_CreateObject *) rmev; + + GenObject *objpo = CreateObject( re_co->ObjectClass, re_co->ObjPosition ); + ASSERT( objpo != NULL ); + objpo->HostObjNumber = re_co->HostObjId; + //TODO: + // re_co->Flags + + RMEVTXT( MSGOUT( "--executing RE_CREATEOBJECT: %d (%d).", re_co->ObjectClass, ownerid ); ); +} + + +// execute received remote event: create laser -------------------------------- +// +void NET_ExecRmEvCreateLaser( RE_Header *rmev, int ownerid ) +{ + // get owner from RE + if ( NET_ProtocolGMSV() ) { + ownerid = GetOwnerFromHostOjbNumber( ( (RE_CreateLaser*)rmev )->HostObjId ); + } + + ASSERT( rmev != NULL ); + ASSERT( rmev->RE_Type == RE_CREATELASER ); + ASSERT( ( ownerid >= 0 ) && ( ownerid < MAX_NET_PROTO_PLAYERS ) ); + ASSERT( (dword)ownerid == GetOwnerFromHostOjbNumber( ( (RE_CreateLaser*)rmev )->HostObjId ) ); + + RE_CreateLaser *re_cl = (RE_CreateLaser *) rmev; + + LaserObject *laserpo = (LaserObject *) CreateObject( re_cl->ObjectClass, re_cl->ObjPosition ); + ASSERT( laserpo != NULL ); + laserpo->HostObjNumber = re_cl->HostObjId; + laserpo->DirectionVec = re_cl->DirectionVec; + laserpo->Owner = ownerid; + + AUD_Laser( laserpo ); + + RMEVTXT( MSGOUT( "--executing RE_CREATELASER: %d (%d).", re_cl->ObjectClass, ownerid ); ); +} + + +// execute received remote event: create missile ------------------------------ +// +void NET_ExecRmEvCreateMissile( RE_Header *rmev, int ownerid ) +{ + // get owner from RE + if ( NET_ProtocolGMSV() ) { + ownerid = GetOwnerFromHostOjbNumber( ( (RE_CreateMissile*)rmev )->HostObjId ); + } + + ASSERT( rmev != NULL ); + ASSERT( rmev->RE_Type == RE_CREATEMISSILE ); + ASSERT( ( ownerid >= 0 ) && ( ownerid < MAX_NET_PROTO_PLAYERS ) ); + + RE_CreateMissile *re_cm = (RE_CreateMissile *) rmev; + + MissileObject *missilepo = (MissileObject *) CreateObject( re_cm->ObjectClass, re_cm->ObjPosition ); + ASSERT( missilepo != NULL ); + missilepo->HostObjNumber = re_cm->HostObjId; + missilepo->DirectionVec = re_cm->DirectionVec; + missilepo->Owner = ownerid; + + if ( re_cm->ObjectClass == GUIDE_CLASS_1 ) { + TargetMissileObject *targetmisspo = (TargetMissileObject *) missilepo; + targetmisspo->TargetObjNumber = re_cm->TargetHostObjId; + } + + AUD_Missile( missilepo ); + + RMEVTXT( MSGOUT( "--executing RE_CREATEMISSILE: %d (%d).", re_cm->ObjectClass, ownerid ); ); +} + + +// execute received remote event: create particle object ---------------------- +// +void NET_ExecRmEvParticleObject( RE_Header *rmev, int ownerid ) +{ + ASSERT( rmev != NULL ); + ASSERT( rmev->RE_Type == RE_PARTICLEOBJECT ); + ASSERT( ( ownerid >= 0 ) && ( ownerid < MAX_NET_PROTO_PLAYERS ) ); + + RE_ParticleObject *re_po = (RE_ParticleObject *) rmev; + + switch ( re_po->ObjectType ) { + + case POBJ_ENERGYFIELD: + SFX_CreateEnergyField( re_po->Origin ); + break; + + case POBJ_MEGASHIELD: + SFX_RemoteEnableInvulnerabilityShield( ownerid ); + break; + + case POBJ_SPREADFIRE: + WFX_RemoteShootSpreadfire( ownerid ); + break; + } + + RMEVTXT( MSGOUT( "--executing RE_PARTICLEOBJECT: %d (%d).", re_po->ObjectType, ownerid ); ); +} + + +// execute received remote event: create extra -------------------------------- +// +void NET_ExecRmEvCreateExtra( RE_Header *rmev, int ownerid ) +{ + // get owner from RE + if ( NET_ProtocolGMSV() ) { + ownerid = GetOwnerFromHostOjbNumber( ( (RE_CreateExtra*)rmev )->HostObjId ); + } + + ASSERT( rmev != NULL ); + ASSERT( rmev->RE_Type == RE_CREATEEXTRA ); + ASSERT( ( ( ownerid >= 0 ) && ( ownerid < MAX_NET_PROTO_PLAYERS ) ) || ( ownerid == PLAYERID_SERVER ) ); + + RE_CreateExtra *re_ce = (RE_CreateExtra *) rmev; + + // resolve to class id + ASSERT( re_ce->ExtraIndex < NumExtraClasses ); + dword classid = ExtraClasses[ re_ce->ExtraIndex ]; + + // create object if extra available on this client + if ( classid != CLASS_ID_INVALID ) { + + ExtraObject *extrapo = (ExtraObject *) CreateObject( classid, re_ce->ObjPosition ); + ASSERT( extrapo != NULL ); + extrapo->HostObjNumber = re_ce->HostObjId; + if ( extrapo->ObjectType == MINE1TYPE ) { + ASSERT( ownerid != PLAYERID_SERVER ); + ((MineObject*)extrapo)->Owner = ownerid; + AUD_Mine( extrapo ); + } else { + OBJ_FillExtraMemberVars( extrapo ); + } + } + + RMEVTXT( MSGOUT( "--executing RE_CREATEEXTRA: %d (%d).", classid, ownerid ); ); +} + + +// execute received remote event: kill object --------------------------------- +// +void NET_ExecRmEvKillObject( RE_Header *rmev ) +{ + ASSERT( rmev != NULL ); + ASSERT( rmev->RE_Type == RE_KILLOBJECT ); + + RE_KillObject *re_ko = (RE_KillObject *) rmev; + + GenObject *objlistpo = NULL; + switch ( re_ko->ListId ) { + case LASER_LIST: + objlistpo = LaserObjects; + break; + case MISSL_LIST: + objlistpo = MisslObjects; + break; + case EXTRA_LIST: + objlistpo = ExtraObjects; + break; + case CUSTM_LIST: + objlistpo = CustmObjects; + break; + default: + ASSERT( FALSE ); + break; + } + if ( objlistpo != NULL ) { + KillSpecificHostObject( re_ko->HostObjId, objlistpo ); + } + + RMEVTXT( MSGOUT( "--executing RE_KILLOBJECT: obj %d, list %d.", re_ko->HostObjId, re_ko->ListId ); ); +} + + +// execute received remote event: send text ----------------------------------- +// +void NET_ExecRmEvSendText( RE_Header *rmev, int ownerid ) +{ + + ASSERT( rmev != NULL ); + ASSERT( rmev->RE_Type == RE_SENDTEXT ); + ASSERT( ( ownerid >= 0 ) && ( ownerid < MAX_NET_PROTO_PLAYERS ) ); + + RE_SendText *re_st = (RE_SendText *) rmev; + + char *s, *name, *brk; + s = strtok_r(re_st->TextStart," ",&brk); + name = s; + s = strtok_r(NULL,"\0",&brk); + char *textpo = s; + size_t textlen = strlen( textpo ); + if ( textlen <= ( MAX_MESSAGELEN - strlen( name ) - 3 ) ) { + ASSERT( ( 3 + strlen( name ) + textlen ) <= PASTE_STR_LEN ); + sprintf( paste_str, "-%s- %s", + name, textpo ); + ShowMessage( paste_str ); + } + ShowSentText( name, textpo, TALK_PUBLIC ); + + RMEVTXT( MSGOUT( "--executing RE_SENDTEXT: \"%s\" (%d).", textpo, ownerid ); ); +} + + +// execute received remote event: player name --------------------------------- +// +void NET_ExecRmEvPlayerName( RE_Header *rmev, int ownerid ) +{ + ASSERT( rmev != NULL ); + ASSERT( rmev->RE_Type == RE_PLAYERNAME ); + ASSERT( ( ownerid >= 0 ) && ( ownerid < MAX_NET_PROTO_PLAYERS ) ); + + RE_PlayerName *re_pn = (RE_PlayerName *) rmev; + + if ( name_change_notification ) { + ASSERT( ( 8 + strlen( Player_Name[ ownerid ] ) + strlen( re_pn->PlayerName ) ) <= PASTE_STR_LEN ); + sprintf( paste_str, "%s is now %s", + Player_Name[ ownerid ], re_pn->PlayerName ); + if ( strlen( paste_str ) <= MAX_MESSAGELEN ) + ShowMessage( paste_str ); + } + CopyRemoteName( Player_Name[ ownerid ], re_pn->PlayerName ); + + RMEVTXT( MSGOUT( "--executing RE_PLAYERNAME: \"%s\" (%d).", re_pn->PlayerName, ownerid ); ); +} + + +// execute received remote event: weapon state -------------------------------- +// +void NET_ExecRmEvWeaponState( RE_Header *rmev, int ownerid ) +{ + ASSERT( rmev != NULL ); + ASSERT( rmev->RE_Type == RE_WEAPONSTATE ); + //ASSERT( ( ownerid >= 0 ) && ( ownerid < MAX_NET_PROTO_PLAYERS ) ); + + //NOTE: + // if new duration weapons are added this function should be updated. + + RE_WeaponState *re_ws = (RE_WeaponState *) rmev; + + // must only change state of single weapon + ASSERT( ( re_ws->WeaponMask & ( re_ws->WeaponMask - 1 ) ) == 0 ); + + // fetch pointer to remote player's ship + ShipObject *shippo = NET_FetchOwnersShip( re_ws->SenderId ); + ASSERT( shippo != NULL ); + ASSERT( shippo != MyShip ); + + // update energy + shippo->CurEnergy = re_ws->CurEnergy; +// shippo->Specials = re_ws->Specials; + + // do weapon specific stuff + switch ( re_ws->WeaponMask ) { + + case WPMASK_CANNON_LIGHTNING: + if ( re_ws->State == WPSTATE_ON ) + WFX_RemoteActivateLightning( re_ws->SenderId ); + else + WFX_RemoteDeactivateLightning( re_ws->SenderId ); + break; + + case WPMASK_CANNON_HELIX: + if ( re_ws->State == WPSTATE_ON ) + WFX_RemoteActivateHelix( re_ws->SenderId ); + else + WFX_RemoteDeactivateHelix( re_ws->SenderId ); + break; + + case WPMASK_CANNON_PHOTON: + if ( re_ws->State == WPSTATE_ON ) + WFX_RemoteActivatePhoton( re_ws->SenderId ); + else + WFX_RemoteDeactivatePhoton(re_ws->SenderId ); + break; + + case WPMASK_DEVICE_EMP: + if ( re_ws->State == WPSTATE_ON ) + WFX_RemoteActivateEmp( re_ws->SenderId ); + else + WFX_RemoteDeactivateEmp( re_ws->SenderId ); + break; + + default: + // simply set/reset active flag + if ( re_ws->State == WPSTATE_ON ) + shippo->WeaponsActive |= re_ws->WeaponMask; + else + shippo->WeaponsActive &= ~re_ws->WeaponMask; + break; + } + + RMEVTXT( MSGOUT( "--executing RE_WEAPONSTATE: 0x%X, %d, %d (%d).", re_ws->WeaponMask, re_ws->State, re_ws->CurEnergy, re_ws->SenderId ); ); +} + + +// list of syncable remote states --------------------------------------------- +// +static dword *rmev_sync_states[ RMEVSTATE_NUMSTATES ] = { + + (dword*)&AUXDATA_BACKGROUND_NEBULA_ID, + (dword*)&ExtraProbability, + (dword*)&ProbHelixCannon, + (dword*)&ProbLightningDevice, + (dword*)&ProbPhotonCannon, + (dword*)&ProbProximityMine, + (dword*)&ProbRepairExtra, + (dword*)&ProbAfterburner, + (dword*)&ProbHoloDecoy, + (dword*)&ProbInvisibility, + (dword*)&ProbInvulnerability, + (dword*)&ProbEnergyField, + (dword*)&ProbLaserUpgrade, + (dword*)&ProbLaserUpgrade1, + (dword*)&ProbLaserUpgrade2, + (dword*)&ProbMissilePack, + (dword*)&ProbDumbMissPack, + (dword*)&ProbHomMissPack, + (dword*)&ProbSwarmMissPack, + (dword*)&ProbEmpUpgrade1, + (dword*)&ProbEmpUpgrade2, + (dword*)&AUXDATA_SKILL_AMAZING_TIME, + (dword*)&AUXDATA_SKILL_BRILLIANT_TIME, + (dword*)&AUX_KILL_LIMIT_FOR_GAME_END, + (dword*)&EnergyExtraBoost, + (dword*)&RepairExtraBoost, + (dword*)&DumbPackNumMissls, + (dword*)&HomPackNumMissls, + (dword*)&SwarmPackNumMissls, + (dword*)&ProxPackNumMines, +}; + +/* + int EnergyExtraBoost = ENERGY_EXTRA_BOOST; + int RepairExtraBoost = 0; + + int DumbPackNumMissls = DUMB_PACK_NUMMISSLS; + int HomPackNumMissls = HOM_PACK_NUMMISSLS; + int SwarmPackNumMissls = SWARM_PACK_NUMMISSLS; + int ProxPackNumMines = PROX_PACK_NUMMINES; + */ + +// execute received remote event: state sync ---------------------------------- +// +void NET_ExecRmEvStateSync( RE_Header *rmev, int ownerid ) +{ + ASSERT( rmev != NULL ); + ASSERT( rmev->RE_Type == RE_STATESYNC ); + //ASSERT( ( ownerid >= 0 ) && ( ownerid < MAX_NET_PROTO_PLAYERS ) ); + + RE_StateSync *re_ss = (RE_StateSync *) rmev; + + // sync state without checking the value + if ( re_ss->StateKey < RMEVSTATE_NUMSTATES ) { + + *rmev_sync_states[ re_ss->StateKey ] = re_ss->StateValue; + + // always display a sync message + MSGOUT( "state sync: %d=%d.", re_ss->StateKey, re_ss->StateValue ); + } + + RMEVTXT( MSGOUT( "--executing RE_STATESYNC: %d=%d (%d).", re_ss->StateKey, re_ss->StateValue, ownerid ); ); +} + + +// execute received remote event: swarm missile ------------------------------- +// +void NET_ExecRmEvCreateSwarm( RE_Header *rmev, int ownerid ) +{ + ASSERT( rmev != NULL ); + ASSERT( rmev->RE_Type == RE_CREATESWARM ); + ASSERT( ( ownerid >= 0 ) && ( ownerid < MAX_NET_PROTO_PLAYERS ) ); + + RE_CreateSwarm *re_cs = (RE_CreateSwarm *) rmev; + + // determine target ship via id + ShipObject *targetpo = MyShip; + if ( re_cs->TargetHostObjId != ShipHostObjId( LocalPlayerId ) ) { + // same as ?: +// targetpo = FetchSpecificHostObject( re_cs->TargetHostObjID, PShipObjects ); +// if ( targetpo == NULL ) return; + targetpo = (ShipObject *) FetchFirstShip(); + while ( targetpo && ( re_cs->TargetHostObjId != targetpo->HostObjNumber ) ) + targetpo = (ShipObject *) targetpo->NextObj; + if ( targetpo == NULL ) { + return; + } + } + + GenObject *dummyobj = SWARM_Init( re_cs->SenderId, &re_cs->Origin, targetpo, re_cs->RandSeed ); + + AUD_SwarmMissiles( &re_cs->Origin, dummyobj ); + + RMEVTXT( MSGOUT( "--executing RE_CREATESWARM: %d (%d).", re_cs->RandSeed, ownerid ); ); +} + + +// execute received remote event: create emp ---------------------------------- +// +void NET_ExecRmEvCreateEmp( RE_Header *rmev, int ownerid ) +{ + ASSERT( rmev != NULL ); + ASSERT( rmev->RE_Type == RE_CREATEEMP ); + ASSERT( ( ownerid >= 0 ) && ( ownerid < MAX_NET_PROTO_PLAYERS ) ); + // get owner from RE + RE_CreateEmp *re_ce = (RE_CreateEmp *) rmev; + if ( NET_ProtocolGMSV() ) { + ownerid = re_ce->SenderId; //GetOwnerFromHostOjbNumber( ( (RE_CreateLaser*)rmev )->HostObjId ); + } + + + // fetch pointer to remote player's ship + ShipObject *shippo = NET_FetchOwnersShip( ownerid ); + // ASSERT( shippo != NULL ); + //ASSERT( shippo != MyShip ); + // well,this happens sometimes... + if ( shippo == NULL ) { + return; + } + + WFX_RemoteEmpBlast( shippo, re_ce->Upgradelevel ); + + RMEVTXT( MSGOUT( "--executing RE_CREATEEMP: %d (%d).", re_ce->Upgradelevel, ownerid ); ); +} + +// execute RE that describes the current gamestate ( time, game running, etc. ) +// +void NET_ExecRmEvGameState( RE_GameState* gamestate ) +{ + ASSERT( gamestate != NULL ); + ASSERT( gamestate->RE_Type == RE_GAMESTATE ); + ASSERT( CurGameTime != GAME_PEERTOPEER ); + + // server sends RE_GameState to transmit current game state/time + CurGameTime = gamestate->GameTime; +} + +// execute RE containing latest killstats ------------------------------------- +// +void NET_ExecRmEvKillStats( RE_KillStats* killstats ) +{ + ASSERT( killstats != NULL ); + ASSERT( killstats->RE_Type == RE_KILLSTATS ); + + // handled different in PEER/GMSV mode + NETs_UpdateKillStats( killstats ); +} + + + +// determine total size of remote event list (including termination dword ) --- +// +size_t NET_RmEvList_GetSize( RE_Header* relist ) +{ + ASSERT( relist != NULL ); + + size_t relistsize = 0; + + // process remote event list + while ( relist->RE_Type != RE_EMPTY ) { + + // sum up size of all remote events + size_t resize = NET_RmEvGetSize( relist ); + relistsize += resize; + + // advance to next event + ASSERT( ( relist->RE_BlockSize == RE_BLOCKSIZE_INVALID ) || ( relist->RE_BlockSize == resize ) ); + relist = (RE_Header *) ( (char *) relist + resize ); + } + + // include size of remote event list termination + relistsize += sizeof( dword ); + + return relistsize; +} + +// check integrity of remote event list ( known types, type checks, length check ) +// +int NET_RmEvList_IsWellFormed( RE_Header* relist ) +{ + ASSERT( relist != NULL ); + + //FIXME: [1/30/2002] implement + //FIXME: check SVG_REList::IsWellFormed + + //RE_LIST_MAXAVAIL + + //ASSERT( FALSE ); + return TRUE; +} + |
