static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound) { AActor *newmobj; AActor *fog = NULL; AActor *eye = self->master; // The eye is the spawnshot's master, not the target! AActor *targ = self->target; // Unlike other projectiles, the target is the intended destination. int r; // [BC] Brain spitting is server-side. if ( NETWORK_InClientMode() ) { return; } // [GZ] Should be more viable than a countdown... if (self->special2 != 0) { if (self->special2 > level.maptime) return; // still flying } else { if (self->reactiontime == 0 || --self->reactiontime != 0) return; // still flying } if (spawntype != NULL) { fog = Spawn (spawntype, targ->x, targ->y, targ->z, ALLOW_REPLACE); if (fog != NULL) S_Sound (fog, CHAN_BODY, sound, 1, ATTN_NORM); } // [BC] If we're the server, spawn the fire, and tell clients to play the sound. if (( NETWORK_GetState( ) == NETSTATE_SERVER ) && ( fog )) { SERVERCOMMANDS_SpawnThing( fog ); SERVERCOMMANDS_SoundPoint( fog->x, fog->y, fog->z, CHAN_BODY, "brain/spawn", 1, ATTN_NORM ); } FName SpawnName; FDropItem *di; // di will be our drop item list iterator FDropItem *drop; // while drop stays as the reference point. int n = 0; // First see if this cube has its own actor list drop = self->GetDropItems(); // If not, then default back to its master's list if (drop == NULL && eye != NULL) drop = eye->GetDropItems(); if (drop != NULL) { for (di = drop; di != NULL; di = di->Next) { if (di->Name != NAME_None) { if (di->amount < 0) { di->amount = 1; // default value is -1, we need a positive value. } n += di->amount; // this is how we can weight the list. } } di = drop; n = pr_spawnfly(n); while (n >= 0) { if (di->Name != NAME_None) { n -= di->amount; // logically, none of the -1 values have survived by now. } if ((di->Next != NULL) && (n >= 0)) { di = di->Next; } else { n = -1; } } SpawnName = di->Name; } if (SpawnName == NAME_None) { // Randomly select monster to spawn. r = pr_spawnfly (); // Probability distribution (kind of :), // decreasing likelihood. if (r < 50) SpawnName = "DoomImp"; else if (r < 90) SpawnName = "Demon"; else if (r < 120) SpawnName = "Spectre"; else if (r < 130) SpawnName = "PainElemental"; else if (r < 160) SpawnName = "Cacodemon"; else if (r < 162) SpawnName = "Archvile"; else if (r < 172) SpawnName = "Revenant"; else if (r < 192) SpawnName = "Arachnotron"; else if (r < 222) SpawnName = "Fatso"; else if (r < 246) SpawnName = "HellKnight"; else SpawnName = "BaronOfHell"; } spawntype = PClass::FindClass(SpawnName); if (spawntype != NULL) { newmobj = Spawn (spawntype, targ->x, targ->y, targ->z, ALLOW_REPLACE); if (newmobj != NULL) { // Make the new monster hate what the boss eye hates if (eye != NULL) { newmobj->CopyFriendliness (eye, false); } // Make it act as if it was around when the player first made noise // (if the player has made noise). newmobj->LastHeard = newmobj->Sector->SoundTarget; if (newmobj->SeeState != NULL && P_LookForPlayers (newmobj, true, NULL)) { newmobj->SetState (newmobj->SeeState); } if (!(newmobj->ObjectFlags & OF_EuthanizeMe)) { // telefrag anything in this spot P_TeleportMove (newmobj, newmobj->x, newmobj->y, newmobj->z, true); // [BC] If we're the server, tell clients to spawn the new monster. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) { SERVERCOMMANDS_SpawnThing( newmobj ); if ( newmobj->state == newmobj->SeeState ) SERVERCOMMANDS_SetThingState( newmobj, STATE_SEE ); } } newmobj->flags4 |= MF4_BOSSSPAWNED; } } // [BC] Tell clients to destroy the cube. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_DestroyThing( self ); // remove self (i.e., cube). self->Destroy (); }
//***************************************************************************** // void DUEL_DoFight( void ) { ULONG ulIdx; DHUDMessageFadeOut *pMsg; // No longer waiting to duel. if ( NETWORK_GetState( ) != NETSTATE_CLIENT ) DUEL_SetState( DS_INDUEL ); // Make sure this is 0. Can be non-zero in network games if they're slightly out of sync. g_ulDuelCountdownTicks = 0; // Reset level time to 0. level.time = 0; for ( ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ ) { // Since the level time is being reset, also reset the last frag/excellent time for // each player. players[ulIdx].ulLastExcellentTick = 0; players[ulIdx].ulLastFragTick = 0; players[ulIdx].ulLastBFGFragTick = 0; players[ulIdx].ulDeathsWithoutFrag = 0; players[ulIdx].ulFragsWithoutDeath = 0; players[ulIdx].ulRailgunShots = 0; } // Tell clients to "fight!". if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_DoGameModeFight( 0 ); if ( NETWORK_GetState( ) != NETSTATE_SERVER ) { // Play fight sound. ANNOUNCER_PlayEntry( cl_announcer, "Fight" ); screen->SetFont( BigFont ); // Display "FIGHT!" HUD message. pMsg = new DHUDMessageFadeOut( "FIGHT!", 160.4f, 75.0f, 320, 200, CR_RED, 2.0f, 1.0f ); StatusBar->AttachMessage( pMsg, 'CNTR' ); screen->SetFont( SmallFont ); } // Display a little thing in the server window so servers can know when matches begin. else Printf( "FIGHT!\n" ); // Reset the map. if ( NETWORK_GetState( ) != NETSTATE_CLIENT ) GAME_ResetMap( ); if ( NETWORK_GetState( ) != NETSTATE_CLIENT ) { // Respawn the players. for ( ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ ) { if (( playeringame[ulIdx] ) && ( PLAYER_IsTrueSpectator( &players[ulIdx] ) == false )) { if ( players[ulIdx].mo ) { if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_DestroyThing( players[ulIdx].mo ); players[ulIdx].mo->Destroy( ); players[ulIdx].mo = NULL; } // Set the player's state to PST_REBORNNOINVENTORY so they everything is cleared (weapons, etc.) players[ulIdx].playerstate = PST_REBORNNOINVENTORY; G_DeathMatchSpawnPlayer( ulIdx, true ); if ( players[ulIdx].pSkullBot ) players[ulIdx].pSkullBot->PostEvent( BOTEVENT_DUEL_FIGHT ); } } } SCOREBOARD_RefreshHUD( ); }