void FMaskCVar::DoSet (UCVarValue value, ECVarType type) { int val = ToInt(value, type) << BitNum; // Server cvars that get changed by this need to use a special message, because // changes are not processed until the next net update. This is a problem with // exec scripts because all flags will base their changes off of the value of // the "master" cvar at the time the script was run, overriding any changes // another flag might have made to the same cvar earlier in the script. if ((ValueVar.GetFlags() & CVAR_SERVERINFO) && gamestate != GS_STARTUP && !demoplayback) { // [BB] netgame && !players[consoleplayer].settings_controller -> NETWORK_InClientMode( ) if ( NETWORK_InClientMode( ) ) { Printf ("Only setting controllers can change %s\n", Name); return; } // Ugh... for(int i = 0; i < 32; i++) { if (BitVal & (1<<i)) { D_SendServerFlagChange (&ValueVar, i, !!(val & (1<<i))); } } } else { int vval = *ValueVar; vval &= ~BitVal; vval |= val; ValueVar = vval; } }
// // I_SelectTimer // Sets up the timer function based on if we can use signals for efficent CPU // usage. // void I_SelectTimer() { SEMAPHORE_INIT(timerWait, 0, 0) #ifndef __sun signal(SIGALRM, I_HandleAlarm); #else struct sigaction alrmaction; sigaction(SIGALRM, NULL, &alrmaction); alrmaction.sa_handler = I_HandleAlarm; sigaction(SIGALRM, &alrmaction, NULL); #endif struct itimerval itv; itv.it_interval.tv_sec = itv.it_value.tv_sec = 0; itv.it_interval.tv_usec = itv.it_value.tv_usec = 1000000/TICRATE; // [BB] For now I_WaitForTicSignaled doesn't work on the client. if ( NETWORK_InClientMode() || ( setitimer(ITIMER_REAL, &itv, NULL) != 0 ) ) { I_GetTime = I_GetTimePolled; I_FreezeTime = I_FreezeTimePolled; I_WaitForTic = I_WaitForTicPolled; } else { I_GetTime = I_GetTimeSignaled; I_FreezeTime = I_FreezeTimeSignaled; I_WaitForTic = I_WaitForTicSignaled; } }
DEFINE_ACTION_FUNCTION(AActor, A_InquisitorCheckLand) { // [BC] This is handled server-side. if ( NETWORK_InClientMode() ) { return; } self->reactiontime--; if (self->reactiontime < 0 || self->velx == 0 || self->vely == 0 || self->z <= self->floorz) { // [BC] Set the thing's state. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_SetThingState( self, STATE_SEE ); self->SetState (self->SeeState); self->reactiontime = 0; self->flags &= ~MF_NOGRAVITY; S_StopSound (self, CHAN_ITEM); return; } if (!S_IsActorPlayingSomething (self, CHAN_ITEM, -1)) { S_Sound (self, CHAN_ITEM|CHAN_LOOP, "inquisitor/jump", 1, ATTN_NORM); } }
DEFINE_ACTION_FUNCTION(AActor, A_InquisitorDecide) { // [BC] This is handled server-side. if ( NETWORK_InClientMode() ) { return; } if (self->target == NULL) return; A_FaceTarget (self); if (!InquisitorCheckDistance (self)) { // [BC] Set the thing's state. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_SetThingFrame( self, self->FindState("Grenade") ); self->SetState (self->FindState("Grenade")); } if (self->target->z != self->z) { if (self->z + self->height + 54*FRACUNIT < self->ceilingz) { // [BC] Set the thing's state. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_SetThingFrame( self, self->FindState("Jump") ); self->SetState (self->FindState("Jump")); } } }
DEFINE_ACTION_FUNCTION(AActor, A_SpectreChunkLarge) { // [BB] Clients may not do this. if ( NETWORK_InClientMode() ) return; AActor *foo = Spawn("AlienChunkLarge", self->x, self->y, self->z + 10*FRACUNIT, ALLOW_REPLACE); if (foo != NULL) { int t; t = pr_spectrechunk() & 7; foo->velx = (t - (pr_spectrechunk() & 15)) << FRACBITS; t = pr_spectrechunk() & 7; foo->vely = (t - (pr_spectrechunk() & 15)) << FRACBITS; foo->velz = (pr_spectrechunk() & 7) << FRACBITS; // [BB] Tell clients to spawn the actor. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_SpawnThing( foo ); } }
//***************************************************************************** // bool NETWORK_IsConsolePlayerOrNotInClientMode( const player_t *pPlayer ) { // [BB] Not in client mode, so just return true. if ( NETWORK_InClientMode() == false ) return true; // [BB] A null pointer is obviously not the console player. if ( pPlayer == NULL ) return false; return ( pPlayer == &players[consoleplayer] ); }
//--------------------------------------------------------------------------- // // [TP] // //--------------------------------------------------------------------------- static bool ShouldDrawHealth( player_t* CPlayer ) { if ( CPlayer->bSpectating ) return false; if ( NETWORK_InClientMode() && ( SERVER_IsPlayerAllowedToKnowHealth( consoleplayer, CPlayer - players )) == false ) { return false; } return true; }
DEFINE_ACTION_FUNCTION(AActor, A_WizAtk3) { AActor *mo; CALL_ACTION(A_GhostOff, self); // [BB] This is server-side, the client only needs to run A_GhostOff. if ( NETWORK_InClientMode() ) { return; } if (!self->target) { return; } S_Sound (self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NORM); // [BB] If we're the server, tell the clients to play the sound. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_SoundActor( self, CHAN_WEAPON, S_GetName( self->AttackSound ), 1, ATTN_NORM ); if (self->CheckMeleeRange()) { int damage = pr_wizatk3.HitDice (4); int newdam = P_DamageMobj (self->target, self, self, damage, NAME_Melee); P_TraceBleed (newdam > 0 ? newdam : damage, self->target, self); return; } const PClass *fx = PClass::FindClass("WizardFX1"); mo = P_SpawnMissile (self, self->target, fx); if (mo != NULL) { AActor *missile1 = P_SpawnMissileAngle(self, fx, mo->angle-(ANG45/8), mo->velz); AActor *missile2 = P_SpawnMissileAngle(self, fx, mo->angle+(ANG45/8), mo->velz); // [BB] If we're the server, tell the clients to spawn the missiles. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) { SERVERCOMMANDS_SpawnMissile( mo ); if ( missile1 ) SERVERCOMMANDS_SpawnMissile( missile1 ); if ( missile2 ) SERVERCOMMANDS_SpawnMissile( missile2 ); } } }
//***************************************************************************** // void LASTMANSTANDING_DoFight( void ) { DHUDMessageFadeOut *pMsg; // The match is now in progress. if ( NETWORK_InClientMode() == false ) { LASTMANSTANDING_SetState( LMSS_INPROGRESS ); } // Make sure this is 0. Can be non-zero in network games if they're slightly out of sync. g_ulLMSCountdownTicks = 0; // Since the level time is being reset, also reset the last frag/excellent time for // each player. PLAYER_ResetAllPlayersSpecialCounters(); // 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" ); // Display "FIGHT!" HUD message. pMsg = new DHUDMessageFadeOut( BigFont, "FIGHT!", 160.4f, 75.0f, 320, 200, CR_RED, 2.0f, 1.0f ); StatusBar->AttachMessage( pMsg, MAKE_ID('C','N','T','R') ); } // Display a little thing in the server window so servers can know when matches begin. else Printf( "FIGHT!\n" ); // Reset the map. GAME_ResetMap( ); GAMEMODE_RespawnAllPlayers( BOTEVENT_LMS_FIGHT ); SCOREBOARD_RefreshHUD( ); }
int DThinker::TickThinkers (FThinkerList *list, FThinkerList *dest) { int count = 0; DThinker *node = list->GetHead(); if (node == NULL) { return 0; } while (node != list->Sentinel) { ++count; NextToThink = node->NextThinker; if (node->ObjectFlags & OF_JustSpawned) { // Leave OF_JustSpawn set until after Tick() so the ticker can check it. if (dest != NULL) { // Move thinker from this list to the destination list node->Remove(); dest->AddTail(node); } node->PostBeginPlay(); } else if (dest != NULL) { // Move thinker from this list to the destination list I_Error("There is a thinker in the fresh list that has already ticked.\n"); } if (!(node->ObjectFlags & OF_EuthanizeMe)) { // Only tick thinkers not scheduled for destruction // [BC] Don't tick the consoleplayer's actor in client // mode, because that's done in the main prediction function if (( NETWORK_InClientMode() == false ) || ( node->IsKindOf( RUNTIME_CLASS( AActor )) == false ) || ( static_cast<AActor *>( node ) != players[consoleplayer].mo )) { node->Tick(); } node->ObjectFlags &= ~OF_JustSpawned; GC::CheckGC(); } node = NextToThink; } return count; }
bool AArtiTeleportOther::Use (bool pickup) { AActor *mo; // [BC] Weapons are handled by the server. if ( NETWORK_InClientMode() ) { return ( true ); } mo = P_SpawnPlayerMissile (Owner, RUNTIME_CLASS(ATelOtherFX1)); if (mo) { mo->target = Owner; } return true; }
DEFINE_ACTION_FUNCTION(AActor, A_WraithMelee) { int amount; // [BB] This is server-side. if ( NETWORK_InClientMode() ) { return; } // Steal health from target and give to self if (self->CheckMeleeRange() && (pr_stealhealth()<220)) { amount = pr_stealhealth.HitDice (2); P_DamageMobj (self->target, self, self, amount, NAME_Melee); self->health += amount; } }
void A_SkullAttack(AActor *self, fixed_t speed) { AActor *dest; angle_t an; int dist; // [BC] This is handled server-side. if ( NETWORK_InClientMode() ) { return; } if (!self->target) return; dest = self->target; self->flags |= MF_SKULLFLY; S_Sound (self, CHAN_VOICE, self->AttackSound, 1, ATTN_NORM); // [BC] If we're the server, tell clients play this sound. // [BB] And tell them of MF_SKULLFLY. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) { SERVERCOMMANDS_SetThingFlags( self, FLAGSET_FLAGS ); SERVERCOMMANDS_SoundActor( self, CHAN_VOICE, S_GetName( self->AttackSound ), 1, ATTN_NORM ); } A_FaceTarget (self); an = self->angle >> ANGLETOFINESHIFT; self->velx = FixedMul (speed, finecosine[an]); self->vely = FixedMul (speed, finesine[an]); dist = P_AproxDistance (dest->x - self->x, dest->y - self->y); dist = dist / speed; if (dist < 1) dist = 1; self->velz = (dest->z + (dest->height>>1) - self->z) / dist; // [BC] Update the lost soul's momentum. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_MoveThingExact( self, CM_X|CM_Y|CM_Z|CM_MOMX|CM_MOMY|CM_MOMZ ); }
DEFINE_ACTION_FUNCTION(AActor, A_InquisitorJump) { fixed_t dist; fixed_t speed; angle_t an; // [BC] This is handled server-side. if ( NETWORK_InClientMode() ) { return; } if (self->target == NULL) return; S_Sound (self, CHAN_ITEM|CHAN_LOOP, "inquisitor/jump", 1, ATTN_NORM); self->z += 64*FRACUNIT; A_FaceTarget (self); an = self->angle >> ANGLETOFINESHIFT; speed = self->Speed * 2/3; self->velx += FixedMul (speed, finecosine[an]); self->vely += FixedMul (speed, finesine[an]); dist = P_AproxDistance (self->target->x - self->x, self->target->y - self->y); dist /= speed; if (dist < 1) { dist = 1; } self->velz = (self->target->z - self->z) / dist; self->reactiontime = 60; self->flags |= MF_NOGRAVITY; // [BC] If we're the server, update the thing's position. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) { SERVERCOMMANDS_MoveThingExact( self, CM_Z|CM_MOMX|CM_MOMY|CM_MOMZ ); // [CW] Also, set the flags to ensure the actor can fly. SERVERCOMMANDS_SetThingFlags( self, FLAGSET_FLAGS ); } }
DEFINE_ACTION_FUNCTION(AActor, A_SnoutAttack) { angle_t angle; int damage; int slope; player_t *player; AActor *puff; AActor *linetarget; if (NULL == (player = self->player)) { return; } damage = 3+(pr_snoutattack()&3); angle = player->mo->angle; slope = P_AimLineAttack(player->mo, angle, MELEERANGE, &linetarget); puff = P_LineAttack(player->mo, angle, MELEERANGE, slope, damage, NAME_Melee, "SnoutPuff", true); S_Sound(player->mo, CHAN_VOICE, "PigActive", 1, ATTN_NORM); // [Dusk] clients aren't properly aware of linetarget, thus they stop here. if (NETWORK_InClientMode()) return; if(linetarget) { AdjustPlayerAngle(player->mo, linetarget); // [Dusk] update angle if (NETWORK_GetState() == NETSTATE_SERVER) SERVERCOMMANDS_MoveThing(player->mo, CM_ANGLE); if(puff != NULL) { // Bit something S_Sound(player->mo, CHAN_VOICE, "PigAttack", 1, ATTN_NORM); // [Dusk] tell clients of the attack sound if (NETWORK_GetState() == NETSTATE_SERVER) SERVERCOMMANDS_SoundActor (player->mo, CHAN_VOICE, "PigAttack", 1, ATTN_NORM); } } }
//***************************************************************************** // void LASTMANSTANDING_StartCountdown( ULONG ulTicks ) { ULONG ulIdx; for ( ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ ) { if (( playeringame[ulIdx] ) && ( players[ulIdx].pSkullBot )) players[ulIdx].pSkullBot->PostEvent( BOTEVENT_LMS_STARTINGCOUNTDOWN ); } /* // First, reset everyone's fragcount. This must be done before setting the state to LMSS_COUNTDOWN // otherwise PLAYER_SetFragcount will ignore our request. for ( ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ ) { if ( playeringame[ulIdx] ) PLAYER_SetFragcount( &players[ulIdx], 0, false, false ); } */ /* for ( ULONG i = 0; i < teams.Size( ); i++ ) TEAM_SetFragCount( i, 0, false ); */ // Put the game in a countdown state. if ( NETWORK_InClientMode() == false ) { LASTMANSTANDING_SetState( LMSS_COUNTDOWN ); } // Set the LMS countdown ticks. LASTMANSTANDING_SetCountdownTicks( ulTicks ); // Announce that the fight will soon start. ANNOUNCER_PlayEntry( cl_announcer, "PrepareToFight" ); // Tell clients to start the countdown. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_DoGameModeCountdown( ulTicks ); }
DEFINE_ACTION_FUNCTION(AActor, A_InquisitorAttack) { AActor *proj; // [BC] This is handled server-side. if ( NETWORK_InClientMode() ) { return; } if (self->target == NULL) return; A_FaceTarget (self); self->z += 32*FRACUNIT; self->angle -= ANGLE_45/32; proj = P_SpawnMissileZAimed (self, self->z, self->target, PClass::FindClass("InquisitorShot")); if (proj != NULL) { proj->velz += 9*FRACUNIT; // [BC] Tell clients to spawn the missile. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_SpawnMissile( proj ); } self->angle += ANGLE_45/16; proj = P_SpawnMissileZAimed (self, self->z, self->target, PClass::FindClass("InquisitorShot")); if (proj != NULL) { proj->velz += 16*FRACUNIT; // [BC] Tell clients to spawn the missile. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_SpawnMissile( proj ); } self->z -= 32*FRACUNIT; }
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 (); }
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BrainSpit) { DSpotState *state = DSpotState::GetSpotState(); AActor *targ; AActor *spit; bool isdefault = false; // [BC] Brain spitting is server-side. if ( NETWORK_InClientMode() ) { return; } ACTION_PARAM_START(1); ACTION_PARAM_CLASS(spawntype, 0); // shoot a cube at current target targ = state->GetNextInList(PClass::FindClass("BossTarget"), G_SkillProperty(SKILLP_EasyBossBrain)); if (targ != NULL) { if (spawntype == NULL) { spawntype = PClass::FindClass("SpawnShot"); isdefault = true; } // spawn brain missile spit = P_SpawnMissile (self, targ, spawntype); if (spit != NULL) { // Boss cubes should move freely to their destination so it's // probably best to disable all collision detection for them. if (spit->flags & MF_NOCLIP) spit->flags5 |= MF5_NOINTERACTION; spit->target = targ; spit->master = self; // [RH] Do this correctly for any trajectory. Doom would divide by 0 // if the target had the same y coordinate as the spitter. if ((spit->velx | spit->vely) == 0) { spit->special2 = 0; } else if (abs(spit->vely) > abs(spit->velx)) { spit->special2 = (targ->y - self->y) / spit->vely; } else { spit->special2 = (targ->x - self->x) / spit->velx; } // [GZ] Calculates when the projectile will have reached destination spit->special2 += level.maptime; spit->flags6 |= MF6_BOSSCUBE; // [BC] If we're the server, tell clients to spawn the actor. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_SpawnMissile( spit ); } if (!isdefault) { S_Sound(self, CHAN_WEAPON, self->AttackSound, 1, ATTN_NONE); // [BC] If we're the server, tell clients create the sound. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_SoundPoint( self->x, self->y, self->z, CHAN_WEAPON, self->AttackSound, 1, ATTN_NONE ); } else { // compatibility fallback S_Sound (self, CHAN_WEAPON, "brain/spit", 1, ATTN_NONE); // [BC] If we're the server, tell clients create the sound. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_SoundPoint( self->x, self->y, self->z, CHAN_WEAPON, "brain/spit", 1, ATTN_NONE ); } } }
//***************************************************************************** // bool NETWORK_InClientModeAndActorNotClientHandled( const AActor *pActor ) { return ( NETWORK_InClientMode( ) && ( NETWORK_IsActorClientHandled ( pActor ) == false ) ); }
//***************************************************************************** // bool CAMPAIGN_AllowCampaign( void ) { return (( g_bDisableCampaign == false ) && ( NETWORK_GetState( ) != NETSTATE_SERVER ) && ( NETWORK_InClientMode() == false )); }
// The second half of random spawning. Now that the spawner is initialized, the // real actor can be created. If the following code were in BeginPlay instead, // missiles would not have yet obtained certain information that is absolutely // necessary to them -- such as their source and destination. void PostBeginPlay() { AActor * newmobj = NULL; bool boss = false; Super::PostBeginPlay(); if (Species == NAME_None) { Destroy(); return; } const PClass * cls = PClass::FindClass(Species); if (this->flags & MF_MISSILE && target && target->target) // Attempting to spawn a missile. { if ((tracer == NULL) && (flags2 & MF2_SEEKERMISSILE)) tracer = target->target; newmobj = P_SpawnMissileXYZ(x, y, z, target, target->target, cls, false); } else newmobj = Spawn(cls, x, y, z, NO_REPLACE); if (newmobj != NULL) { // copy everything relevant newmobj->SpawnAngle = newmobj->angle = angle; newmobj->SpawnPoint[2] = SpawnPoint[2]; newmobj->special = special; newmobj->args[0] = args[0]; newmobj->args[1] = args[1]; newmobj->args[2] = args[2]; newmobj->args[3] = args[3]; newmobj->args[4] = args[4]; newmobj->special1 = special1; newmobj->special2 = special2; newmobj->SpawnFlags = SpawnFlags; newmobj->HandleSpawnFlags(); newmobj->tid = tid; newmobj->AddToHash(); newmobj->velx = velx; newmobj->vely = vely; newmobj->velz = velz; newmobj->master = master; // For things such as DamageMaster/DamageChildren, transfer mastery. newmobj->target = target; newmobj->tracer = tracer; newmobj->CopyFriendliness(this, false); // This handles things such as projectiles with the MF4_SPECTRAL flag that have // a health set to -2 after spawning, for internal reasons. if (health != SpawnHealth()) newmobj->health = health; if (!(flags & MF_DROPPED)) newmobj->flags &= ~MF_DROPPED; // Handle special altitude flags if (newmobj->flags & MF_SPAWNCEILING) { newmobj->z = newmobj->ceilingz - newmobj->height - SpawnPoint[2]; } else if (newmobj->flags2 & MF2_SPAWNFLOAT) { fixed_t space = newmobj->ceilingz - newmobj->height - newmobj->floorz; if (space > 48*FRACUNIT) { space -= 40*FRACUNIT; newmobj->z = MulScale8 (space, pr_randomspawn()) + newmobj->floorz + 40*FRACUNIT; } newmobj->z += SpawnPoint[2]; } if (newmobj->flags & MF_MISSILE) P_CheckMissileSpawn(newmobj, 0); // Bouncecount is used to count how many recursions we're in. if (newmobj->IsKindOf(PClass::FindClass("RandomSpawner"))) newmobj->bouncecount = ++bouncecount; // If the spawned actor has either of those flags, it's a boss. if ((newmobj->flags4 & MF4_BOSSDEATH) || (newmobj->flags2 & MF2_BOSS)) boss = true; // If a replaced actor has either of those same flags, it's also a boss. AActor * rep = GetDefaultByType(GetClass()->ActorInfo->GetReplacee()->Class); if (rep && ((rep->flags4 & MF4_BOSSDEATH) || (rep->flags2 & MF2_BOSS))) boss = true; // [BB] If we're the server, tell clients to spawn the actor. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) { SERVERCOMMANDS_SpawnThing( newmobj ); // [BB] Also set the angle and momentum if necessary. SERVER_SetThingNonZeroAngleAndMomentum( newmobj ); } // [BB] The client did the spawning, so this has to be a client side only actor. else if ( NETWORK_InClientMode() ) newmobj->ulNetworkFlags |= NETFL_CLIENTSIDEONLY; } if (boss) this->tracer = newmobj; // [BB] Only destroy the actor if it's not needed for a map reset. Otherwise just hide it. else // "else" because a boss-replacing spawner must wait until it can call A_BossDeath. HideOrDestroyIfSafe(); // [BB] Workaround to ensure that the spawner is properly reset in GAME_ResetMap. this->ulSTFlags |= STFL_POSITIONCHANGED; }
//***************************************************************************** // void LASTMANSTANDING_Tick( void ) { // Not in LMS mode. if (( lastmanstanding == false ) && ( teamlms == false )) return; switch ( g_LMSState ) { case LMSS_WAITINGFORPLAYERS: if ( NETWORK_InClientMode() ) { break; } if ( lastmanstanding ) { // Two players are here now, being the countdown! if ( GAME_CountActivePlayers( ) >= 2 ) { if ( sv_lmscountdowntime > 0 ) LASTMANSTANDING_StartCountdown(( sv_lmscountdowntime * TICRATE ) - 1 ); else LASTMANSTANDING_StartCountdown(( 10 * TICRATE ) - 1 ); } } if ( teamlms ) { if ( TEAM_TeamsWithPlayersOn( ) > 1 ) { if ( sv_lmscountdowntime > 0 ) LASTMANSTANDING_StartCountdown(( sv_lmscountdowntime * TICRATE ) - 1 ); else LASTMANSTANDING_StartCountdown(( 10 * TICRATE ) - 1 ); } } break; case LMSS_COUNTDOWN: if ( g_ulLMSCountdownTicks ) { g_ulLMSCountdownTicks--; // FIGHT! if (( g_ulLMSCountdownTicks == 0 ) && ( NETWORK_InClientMode() == false )) { LASTMANSTANDING_DoFight( ); } // Play "3... 2... 1..." sounds. else if ( g_ulLMSCountdownTicks == ( 3 * TICRATE )) ANNOUNCER_PlayEntry( cl_announcer, "Three" ); else if ( g_ulLMSCountdownTicks == ( 2 * TICRATE )) ANNOUNCER_PlayEntry( cl_announcer, "Two" ); else if ( g_ulLMSCountdownTicks == ( 1 * TICRATE )) ANNOUNCER_PlayEntry( cl_announcer, "One" ); } break; case LMSS_INPROGRESS: if ( NETWORK_InClientMode() ) { break; } // Check to see how many men are left standing. if ( lastmanstanding ) { // If only one man is left standing, somebody just won! if ( GAME_CountLivingAndRespawnablePlayers( ) == 1 ) { LONG lWinner; lWinner = LASTMANSTANDING_GetLastManStanding( ); if ( lWinner != -1 ) { if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVER_Printf( PRINT_HIGH, "%s \\c-wins!\n", players[lWinner].userinfo.GetName() ); else { Printf( "%s \\c-wins!\n", players[lWinner].userinfo.GetName() ); if ( lWinner == consoleplayer ) ANNOUNCER_PlayEntry( cl_announcer, "YouWin" ); } // Give the winner a win. PLAYER_SetWins( &players[lWinner], players[lWinner].ulWins + 1 ); // Pause for five seconds for the win sequence. LASTMANSTANDING_DoWinSequence( lWinner ); GAME_SetEndLevelDelay( 5 * TICRATE ); } } // If NOBODY is left standing, it's a draw game! else if ( GAME_CountLivingAndRespawnablePlayers( ) == 0 ) { ULONG ulIdx; for ( ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ ) { if (( playeringame[ulIdx] ) && ( PLAYER_IsTrueSpectator( &players[ulIdx] ) == false )) break; } if ( ulIdx != MAXPLAYERS ) { if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVER_Printf( PRINT_HIGH, "DRAW GAME!\n" ); else Printf( "DRAW GAME!\n" ); // Pause for five seconds for the win sequence. LASTMANSTANDING_DoWinSequence( MAXPLAYERS ); GAME_SetEndLevelDelay( 5 * TICRATE ); } } } // Check to see how many men are left standing on each team. if ( teamlms ) { if ( LASTMANSTANDING_TeamsWithAlivePlayersOn( ) <= 1) { LONG lWinner; lWinner = LASTMANSTANDING_TeamGetLastManStanding( ); if ( lWinner != -1 ) { if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVER_Printf( PRINT_HIGH, "%s \\c-wins!\n", TEAM_GetName( lWinner )); else { Printf( "%s \\c-wins!\n", TEAM_GetName( lWinner )); if ( players[consoleplayer].bOnTeam && ( lWinner == (LONG)players[consoleplayer].ulTeam )) ANNOUNCER_PlayEntry( cl_announcer, "YouWin" ); } // Give the team a win. TEAM_SetWinCount( lWinner, TEAM_GetWinCount( lWinner ) + 1, false ); // [BB] Every player who is still alive also gets a win. for ( ULONG ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ ) { if ( playeringame[ulIdx] && ( players[ulIdx].bOnTeam ) && ( players[ulIdx].bSpectating == false ) && PLAYER_IsAliveOrCanRespawn ( &players[ulIdx] ) ) PLAYER_SetWins( &players[ulIdx], players[ulIdx].ulWins + 1 ); } // Pause for five seconds for the win sequence. LASTMANSTANDING_DoWinSequence( lWinner ); GAME_SetEndLevelDelay( 5 * TICRATE ); } // If NOBODY is left standing, it's a draw game! else { ULONG ulIdx; for ( ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ ) { if (( playeringame[ulIdx] ) && ( PLAYER_IsTrueSpectator( &players[ulIdx] ) == false )) break; } if ( ulIdx != MAXPLAYERS ) { if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVER_Printf( PRINT_HIGH, "DRAW GAME!\n" ); else Printf( "DRAW GAME!\n" ); // Pause for five seconds for the win sequence. LASTMANSTANDING_DoWinSequence( teams.Size( ) ); GAME_SetEndLevelDelay( 5 * TICRATE ); } } } } break; default: break; } }
//***************************************************************************** // void LASTMANSTANDING_DoWinSequence( ULONG ulWinner ) { ULONG ulIdx; // Put the game state in the win sequence state. if ( NETWORK_InClientMode() == false ) { LASTMANSTANDING_SetState( LMSS_WINSEQUENCE ); } // Tell clients to do the win sequence. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_DoGameModeWinSequence( ulWinner ); if ( NETWORK_GetState( ) != NETSTATE_SERVER ) { char szString[64]; DHUDMessageFadeOut *pMsg; if ( teamlms ) { if ( ulWinner == teams.Size( ) ) sprintf( szString, "\\cdDraw Game!" ); else sprintf( szString, "\\c%c%s Wins!", V_GetColorChar( TEAM_GetTextColor( ulWinner ) ), TEAM_GetName( ulWinner )); } else if ( ulWinner == MAXPLAYERS ) sprintf( szString, "\\cdDRAW GAME!" ); else sprintf( szString, "%s \\c-WINS!", players[ulWinner].userinfo.GetName() ); V_ColorizeString( szString ); // Display "%s WINS!" HUD message. pMsg = new DHUDMessageFadeOut( BigFont, szString, 160.4f, 75.0f, 320, 200, CR_RED, 3.0f, 2.0f ); StatusBar->AttachMessage( pMsg, MAKE_ID('C','N','T','R') ); szString[0] = 0; pMsg = new DHUDMessageFadeOut( SmallFont, szString, 0.0f, 0.0f, 0, 0, CR_RED, 3.0f, 2.0f ); StatusBar->AttachMessage( pMsg, MAKE_ID('F','R','A','G') ); pMsg = new DHUDMessageFadeOut( SmallFont, szString, 0.0f, 0.0f, 0, 0, CR_RED, 3.0f, 2.0f ); StatusBar->AttachMessage( pMsg, MAKE_ID('P','L','A','C') ); } // Award a victory or perfect medal to the winner. if (( lastmanstanding ) && ( NETWORK_InClientMode() == false )) { LONG lMedal; // If the winner has full health, give him a "Perfect!". if ( players[ulWinner].health == deh.MegasphereHealth ) lMedal = MEDAL_PERFECT; else lMedal = MEDAL_VICTORY; // Give the player the medal. MEDAL_GiveMedal( ulWinner, lMedal ); if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_GivePlayerMedal( ulWinner, lMedal ); } for ( ulIdx = 0; ulIdx < MAXPLAYERS; ulIdx++ ) { if (( playeringame[ulIdx] ) && ( players[ulIdx].pSkullBot )) players[ulIdx].pSkullBot->PostEvent( BOTEVENT_LMS_WINSEQUENCE ); } }