// check whether current status (connected/joined etc. ) matches the desired one // void BOT_ClientSide::_CheckStatus() { BOT_Goal* pGoal = m_State.GetCurGoal(); // check whether to connect if ( ( NetConnected == NETWORK_GAME_OFF ) && m_bWantToBeConnected ) { pGoal->SetTargetObject(NULL); if ( strlen( m_szServer ) > 0 ) { // connect NET_CommandConnect( m_szServer ); // set the timeout for the next connection attempt if ( !NetConnected ) { m_NextStatusCheckRefFrame = SYSs_GetRefFrameCount() + ( 5 * BOT_STATUS_CHECK_TIMEOUT ); } return; } else { #ifdef BOT_LOGFILES BOT_MsgOut( "Error: BOT_ClientSide::_CheckStatus(): missing servername for connect !" ); #endif // BOT_LOGFILES } // check whether to disconnect } else if ( ( NetConnected == NETWORK_GAME_ON ) && !m_bWantToBeConnected ) { // disconnect NET_CommandDisconnect(); return; } if ( NetConnected ) { // check for join if ( !NetJoined && m_bWantToBeJoined ) { if(botwait == 1) { botwait = 0; } else { botwait = 1; } // join pGoal->SetTargetObject(NULL); if(botwait == 0) { MENU_FloatingMenuEnterGame(); } if(!NetJoined) { m_NextStatusCheckRefFrame = SYSs_GetRefFrameCount() + ( 5 * BOT_STATUS_CHECK_TIMEOUT ); } return; // check for unjoin } else if ( NetJoined && !m_bWantToBeJoined ) { // unjoin pGoal->SetTargetObject(NULL); ExitGameLoop = 1; } } }
// fade the background alpha to a specified target ---------------------------- // PRIVATE int DoStatusWindowFading() { if ( status_fadepos == status_fadetarget ) { status_lastref = REFFRAME_INVALID; // skip drawing code if status window is completely faded out #if ( STATUS_ALPHA_LOW == 0 ) return ( status_fadepos != STATUS_ALPHA_LOW ); #else return TRUE; #endif } if ( status_fadepos < status_fadetarget ) { // fade in refframe_t refframecount = SYSs_GetRefFrameCount(); if ( status_lastref == REFFRAME_INVALID ) { status_lastref = refframecount; } else { refframe_t delta = refframecount - status_lastref; for ( ; delta >= STATUS_FADE_SPEED; delta -= STATUS_FADE_SPEED ) { status_fadepos += STATUS_FADE_QUANTUM; if ( status_fadepos >= status_fadetarget ) { status_fadepos = status_fadetarget; status_lastref = REFFRAME_INVALID; break; } status_lastref += STATUS_FADE_SPEED; } } } else { // fade out refframe_t refframecount = SYSs_GetRefFrameCount(); if ( status_lastref == REFFRAME_INVALID ) { status_lastref = refframecount; } else { refframe_t delta = refframecount - status_lastref; for ( ; delta >= STATUS_FADE_SPEED; delta -= STATUS_FADE_SPEED ) { status_fadepos -= STATUS_FADE_QUANTUM; if ( status_fadepos <= status_fadetarget ) { status_fadepos = status_fadetarget; status_lastref = REFFRAME_INVALID; break; } status_lastref += STATUS_FADE_SPEED; } } } return TRUE; }
// overwritten think method to allow special client-side things --------------- // void BOT_ClientSide::DoThink() { // do status checking ? if ( SYSs_GetRefFrameCount() >= m_NextStatusCheckRefFrame ) { m_NextStatusCheckRefFrame = SYSs_GetRefFrameCount() + BOT_STATUS_CHECK_TIMEOUT; _CheckStatus(); } // AI only active if connected & joined & we have the full state received from the server if ( NetConnected && NetJoined & HaveFullPlayerState ) { BOT_AI::DoThink(); } }
// draw cloud ------------------------------------------------------------ // int DrawSmokeCloud( void *param ) { if ( !AUX_ENABLE_VOLUMETRIC_CLOUDS ) return FALSE; refframe_t cur_refframes = SYSs_GetRefFrameCount(); if ( ( cur_refframes - prev_refframes ) > mod_interval ) { #ifdef MODULATE_DISTANCE ModulateDistance(); #endif #ifdef MODULATE_COLOR ModulateColor(); #endif #ifdef MODULATE_ALPHA ModulateAlpha(); #endif int num_intervals = ( cur_refframes - prev_refframes ) / mod_interval; prev_refframes += ( mod_interval * num_intervals ); } return DrawCloudLayers(); }
// check for no user activity in too long a time ------------------------------ // INLINE void User_CheckActivity() { #define BORED_WAIT_REFFRAMES_FIRST ( FRAME_MEASURE_TIMEBASE * 30 ) #define BORED_WAIT_REFFRAMES_OTHER ( FRAME_MEASURE_TIMEBASE * 10 ) ASSERT( BORED_WAIT_REFFRAMES_FIRST >= BORED_WAIT_REFFRAMES_OTHER ); if ( user_action_occurred || DEMO_ReplayActive() ) { user_action_occurred = FALSE; bored_base = REFFRAME_INVALID; } else { refframe_t absref = SYSs_GetRefFrameCount(); if ( bored_base == REFFRAME_INVALID ) { bored_base = absref; } else if ( ( absref - bored_base ) > BORED_WAIT_REFFRAMES_FIRST ) { bored_base = absref - BORED_WAIT_REFFRAMES_FIRST + BORED_WAIT_REFFRAMES_OTHER; AUD_JimCommenting( JIM_COMMENT_BORED ); } } }
// slide the ring to its specifed target x position --------------------------- // PRIVATE void DoObjectsRingSliding() { if ( scv_ring_slidepos == scv_ring_slidetarget ) { scv_ring_lastref = REFFRAME_INVALID; return; } if ( scv_ring_slidepos < scv_ring_slidetarget ) { // slide right refframe_t refframecount = SYSs_GetRefFrameCount(); if ( scv_ring_lastref == REFFRAME_INVALID ) { scv_ring_lastref = refframecount; } else { refframe_t delta = refframecount - scv_ring_lastref; for ( ; delta >= RING_SLIDE_SPEED; delta -= RING_SLIDE_SPEED ) { scv_ring_slidepos++; if ( scv_ring_slidepos >= scv_ring_slidetarget ) { scv_ring_slidepos = scv_ring_slidetarget; scv_ring_lastref = REFFRAME_INVALID; break; } scv_ring_lastref += RING_SLIDE_SPEED; } } } else { // slide left refframe_t refframecount = SYSs_GetRefFrameCount(); if ( scv_ring_lastref == REFFRAME_INVALID ) { scv_ring_lastref = refframecount; } else { refframe_t delta = refframecount - scv_ring_lastref; for ( ; delta >= RING_SLIDE_SPEED; delta -= RING_SLIDE_SPEED ) { scv_ring_slidepos--; if ( scv_ring_slidepos <= scv_ring_slidetarget ) { scv_ring_slidepos = scv_ring_slidetarget; scv_ring_lastref = REFFRAME_INVALID; break; } scv_ring_lastref += RING_SLIDE_SPEED; } } } }
// fade the background alpha to a specified target ---------------------------- // PRIVATE void DoViewerFading() { if ( scv_bg_fadepos == scv_bg_fadetarget ) { scv_bg_lastref = REFFRAME_INVALID; return; } if ( scv_bg_fadepos < scv_bg_fadetarget ) { // fade in refframe_t refframecount = SYSs_GetRefFrameCount(); if ( scv_bg_lastref == REFFRAME_INVALID ) { scv_bg_lastref = refframecount; } else { refframe_t delta = refframecount - scv_bg_lastref; for ( ; delta >= SCV_BG_FADE_SPEED; delta -= SCV_BG_FADE_SPEED ) { scv_bg_fadepos += SCV_BG_FADE_QUANTUM; if ( scv_bg_fadepos >= scv_bg_fadetarget ) { scv_bg_fadepos = scv_bg_fadetarget; scv_bg_lastref = REFFRAME_INVALID; break; } scv_bg_lastref += SCV_BG_FADE_SPEED; } } } else { // fade out refframe_t refframecount = SYSs_GetRefFrameCount(); if ( scv_bg_lastref == REFFRAME_INVALID ) { scv_bg_lastref = refframecount; } else { refframe_t delta = refframecount - scv_bg_lastref; for ( ; delta >= SCV_BG_FADE_SPEED; delta -= SCV_BG_FADE_SPEED ) { scv_bg_fadepos -= SCV_BG_FADE_QUANTUM; if ( scv_bg_fadepos <= scv_bg_fadetarget ) { scv_bg_fadepos = scv_bg_fadetarget; scv_bg_lastref = REFFRAME_INVALID; break; } scv_bg_lastref += SCV_BG_FADE_SPEED; } } } }
// slide the ship to its specifed target x position --------------------------- // PRIVATE void DoSpacecraftSliding() { if ( scv_ship_slidepos == scv_ship_slidetarget ) { scv_ship_lastref = REFFRAME_INVALID; return; } if ( scv_ship_slidepos < scv_ship_slidetarget ) { // slide right refframe_t refframecount = SYSs_GetRefFrameCount(); if ( scv_ship_lastref == REFFRAME_INVALID ) { scv_ship_lastref = refframecount; } else { refframe_t delta = refframecount - scv_ship_lastref; for ( ; delta >= SCV_SHIP_SLIDE_SPEED; delta -= SCV_SHIP_SLIDE_SPEED ) { scv_ship_slidepos++; if ( scv_ship_slidepos >= scv_ship_slidetarget ) { scv_ship_slidepos = scv_ship_slidetarget; scv_ship_lastref = REFFRAME_INVALID; break; } scv_ship_lastref += SCV_SHIP_SLIDE_SPEED; } } } else { // slide left refframe_t refframecount = SYSs_GetRefFrameCount(); if ( scv_ship_lastref == REFFRAME_INVALID ) { scv_ship_lastref = refframecount; } else { refframe_t delta = refframecount - scv_ship_lastref; for ( ; delta >= SCV_SHIP_SLIDE_SPEED; delta -= SCV_SHIP_SLIDE_SPEED ) { scv_ship_slidepos--; if ( scv_ship_slidepos <= scv_ship_slidetarget ) { scv_ship_slidepos = scv_ship_slidetarget; scv_ship_lastref = REFFRAME_INVALID; break; } scv_ship_lastref += SCV_SHIP_SLIDE_SPEED; } } } }
// activate timedemo demo replay if it is enabled ----------------------------- // PRIVATE void DEMO_EnableTimedemo() { // activate if enabled timedemo_active = timedemo_enabled; // store absolute time demo was started at timedemo_start_time = SYSs_GetRefFrameCount(); }
// 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; }
// write packet to stream file ------------------------------------------------ // PRIVATE void SaveLocalPacket( NetPacketExternal* pExtPkt ) { ASSERT( pExtPkt != NULL ); if ( pcktfp == NULL ) { if ( ( pcktfp = fopen( PACKET_STREAM_FILENAME, "wb" ) ) == NULL ) { PANIC( 0 ); } } // save timecode (little-endian) if ( start_timecode == 0 ) { start_timecode = SYSs_GetRefFrameCount(); } refframe_t current_refframes = SWAP_32( SYSs_GetRefFrameCount() - start_timecode ); fwrite( ¤t_refframes, 1, sizeof( int ), pcktfp ); // save packet fwrite( pExtPkt, 1, NET_UDP_DATA_LENGTH, pcktfp ); }
// add an event --------------------------------------------------------------- // size_t EVT_AddEvent( event_s *event ) { // check whether any other event of same type is to be deleted if ( event->flags & EVENT_PARAM_ONE_PER_TYPE ) { for ( event_s* otherevent = eventlist_head; otherevent; ) { event_s* nextevent = otherevent->next; if ( otherevent->type == event->type ) { EVT_RemoveEvent( (size_t)otherevent ); } otherevent = nextevent; } } // add the event to the list if ( eventlist_tail != NULL ) { eventlist_tail->next = event; event->prec = eventlist_tail; } else { event->prec = NULL; } event->next = NULL; eventlist_tail = event; if ( eventlist_head == NULL ) { eventlist_head = event; } // increase the number of events num_events++; if ( event->flags & EVENT_PARAM_AUTOTRIGGER ) { // set the trigger time to the current refframe event->refframe_trigger = SYSs_GetRefFrameCount(); } else { // set to not-triggered event->refframe_trigger = EVENT_UNTRIGGERED; } return (size_t)event; }
// check if challenge is correct ---------------------------------------------- // int E_ConnManager::_IsChallengeCorrect( E_ClientConnectInfo* pClientConnectInfo, E_ClientChallengeInfo** pFoundChallengeInfo ) { ASSERT( pClientConnectInfo != NULL ); node_t* client_node = &pClientConnectInfo->m_node; int client_challenge = pClientConnectInfo->m_challenge; // linear search from newest challenge for( int cid = ( m_nCurChallengeInfo - 1 ); cid != m_nCurChallengeInfo; cid-- ) { // check for wraparound if ( cid == -1 ) cid = ( m_nMaxNumChallengeInfos - 1 ); E_ClientChallengeInfo* pChallengeInfo = &m_ChallengInfos[ cid ]; // check if we have a challenge from this node if ( NODE_AreSame( client_node, &pChallengeInfo->m_node ) ) { // check whether the challenge is the same we sent to the client if ( pChallengeInfo->m_challenge == client_challenge ) { // check whether challenge has not yet timed out //FIXME: CHALLENGE_TIMEOUT_FRAMES should be server configurable if ( pChallengeInfo->m_frame_generated >= ( SYSs_GetRefFrameCount() - CHALLENGE_TIMEOUT_FRAMES ) ) { // set the found challenge info *pFoundChallengeInfo = &m_ChallengInfos[ cid ]; return TRUE; } else { return FALSE; } } } } return FALSE; }
// request a challenge for a client ------------------------------------------- // int E_ConnManager::RequestChallenge( node_t* clientnode ) { ASSERT( clientnode != NULL ); E_ClientChallengeInfo* pCurChallengeInfo = &m_ChallengInfos[ m_nCurChallengeInfo ]; // generate a new unique challenge pCurChallengeInfo->m_challenge = RAND(); pCurChallengeInfo->m_frame_generated = SYSs_GetRefFrameCount(); NODE_Copy( &pCurChallengeInfo->m_node, clientnode ); // point to next challenge info m_nCurChallengeInfo++; // wrap around if ( m_nCurChallengeInfo == m_nMaxNumChallengeInfos ) { m_nCurChallengeInfo = 0; } // send the response back to the client ThePacketHandler->SendChallengeResponse( pCurChallengeInfo, clientnode ); return TRUE; }
// display results of timedemo demo replay ------------------------------------ // PRIVATE void DisplayTimedemoResults() { // determine replay time and recorded time refframe_t deltatime = SYSs_GetRefFrameCount() - timedemo_start_time; float demotime = (float)deltatime / FRAME_MEASURE_TIMEBASE; float recdtime = (float)demoinfo_curtime / FRAME_MEASURE_TIMEBASE; // determine number of frames replayed and average frame rate int frames = demoinfo_curtime / DEMO_GetTimedemoBase() + 1; float frmrate = frames / demotime; CON_AddLineFeed(); CON_DisableLineFeed(); // display info MSGOUT( "- timedemo results -------------------------" ); MSGOUT( "total playback time: %.2f", demotime ); MSGOUT( "total recorded time: %.2f", recdtime ); MSGOUT( "rendered frames: %d", frames ); MSGOUT( "recorded frames: %d", demoinfo_curframe ); MSGOUT( "average frame rate: %.2f", frmrate ); MSGOUT( "--------------------------------------------" ); }
// 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; }
// maintain the list of events to be triggered/fired -------------------------- // void EVT_Maintain() { //FIXME: introduce a frequency for issueing events (e.g. 100Hz = 6 Refframes) event_s* nextevent; for ( event_s* event = eventlist_head; event; event = nextevent ) { // store the next event nextevent = event->next; if ( event->refframe_trigger == EVENT_UNTRIGGERED ) continue; // check whether event is triggered refframe_t refframecount = SYSs_GetRefFrameCount(); if ( event->refframe_trigger > refframecount ) continue; // check whether the event is to be fired if ( ( event->refframe_trigger + event->refframe_delay ) > refframecount ) continue; // check whether the event depends on another event that must be triggered if ( event->flags & EVENT_PARAM_DEPENDENT ) { event_s* parentevent = (event_s*)event->dependent_on; //Unused but I think someday it was meant to be? //FIXME: in order to have this work properly we must first // go through all the events, resolve all dependencies // and then check all the triggered events ASSERT( FALSE ); } ASSERT( event->callback != NULL ); // save the current event pointer current_event = event; // call the callback function int keepalive = event->callback( event->callback_params ); // remove the current event pointer current_event = NULL; // might have been changed implicitly by callback function nextevent = event->next; // check whether event is to be looped dword loops = event->flags & EVENT_PARAM_LOOP_MASK; switch ( loops ) { case EVENT_PARAM_ONESHOT: event->loopcount = 0; break; case EVENT_PARAM_LOOP_COUNT: if ( event->loopcount > 0 ) event->loopcount--; event->refframe_trigger = refframecount; break; case EVENT_PARAM_LOOP_INDEFINITE: event->loopcount = 1; event->refframe_trigger = refframecount; break; default: ASSERT(FALSE); } // remove event if specified by callback or loopcount exceeded if ( !keepalive || ( event->loopcount == 0 ) ) { EVT_RemoveEvent( (size_t)event ); } } }
// mark the client alive ------------------------------------------------------ // void E_ClientInfo::MarkAlive() { m_nAliveCounter = SYSs_GetRefFrameCount() + MAX_ALIVE_COUNTER; }
// check whether the client is alive ------------------------------------------ // int E_ClientInfo::IsAlive() { return ( m_nAliveCounter >= SYSs_GetRefFrameCount() ); }
// create swarm missiles ------------------------------------------------------ // void OBJ_LaunchSwarmMissiles( ShipObject *shippo, dword targetid ) { ASSERT( shippo != NULL ); //NOTE: // this function is called by // INP_USER::User_CheckMissileLaunch(). // check if enough space in RE_List if ( !NET_RmEvAllowed( RE_CREATESWARM ) ) return; if ( !AUX_CHEAT_DISABLE_AMMO_CHECKS ) { // check ammo if ( shippo->NumPartMissls <= 0 ) { if ( shippo == MyShip ) ShowMessage( no_swarm_str ); return; } } // check if any target locked if ( !TargetLocked && ( shippo == MyShip ) ) { ShowMessage( no_target_str ); return; } // fetch target from ship list ShipObject *targetpo = (ShipObject *) FetchFirstShip(); while ( targetpo && ( targetpo->HostObjNumber != TargetObjNumber ) ) targetpo = (ShipObject *) targetpo->NextObj; if ( targetpo == NULL ) { ShowMessage( no_target_sel_str ); return; } if ( !AUX_CHEAT_DISABLE_AMMO_CHECKS ) { shippo->NumPartMissls--; // play the voice sample for the missile countdown AUD_Countdown( shippo->NumPartMissls ); } dword randseed = SYSs_GetRefFrameCount(); Vertex3 origin; origin.X = shippo->ObjPosition[ 0 ][ 3 ]; origin.Y = shippo->ObjPosition[ 1 ][ 3 ]; origin.Z = shippo->ObjPosition[ 2 ][ 3 ]; GenObject *dummyobj = SWARM_Init( LocalPlayerId, &origin, targetpo, randseed ); if ( NetConnected ) { dword targethostobjid = targetid; GenObject *targetpo = FetchFirstShip(); // search for target with current TargetObjNumber in list of ships while ( targetpo && ( targetpo->HostObjNumber != targetid ) ) targetpo = targetpo->NextObj; // if target doesn't exist anymore, use no target if ( targetpo == NULL ) targethostobjid = TARGETID_NO_TARGET; // swarm remote event NET_RmEvCreateSwarm( &origin, targethostobjid, randseed ); } //TODO: // Record_SwarmMissilesCreation( ... ); AUD_SwarmMissiles( &origin, dummyobj ); }