//***************************************************************************** // void LASTMANSTANDING_TimeExpired( void ) { LONG lHighestHealth = 0; bool bTie = false; bool bFoundPlayer = false; LONG lWinner = -1; DHUDMessageFadeOut *pMsg; char szString[64]; // Don't end the level if we're not in a game. if ( LASTMANSTANDING_GetState( ) != LMSS_INPROGRESS ) return; // Try to find the player with the highest health. if ( lastmanstanding ) { TArray<ULONG> possibleWinners; for ( unsigned int i = 0; i < MAXPLAYERS; ++i ) possibleWinners.Push ( i ); // [BB] Find the player with the most lives left. PLAYER_SelectPlayersWithHighestValue ( PLAYER_GetLivesLeft, possibleWinners ); // [BB] If more than one player has the most lives left, select the player with the highest lives. if ( possibleWinners.Size() != 1 ) PLAYER_SelectPlayersWithHighestValue ( PLAYER_GetHealth, possibleWinners ); // [BB] If more then one player have the most lives and also the same health, then the game it a tie. if ( possibleWinners.Size() == 1 ) lWinner = possibleWinners[0]; else { lWinner = MAXPLAYERS; bTie = true; } } else if ( teamlms ) { if ( LASTMANSTANDING_TeamsWithAlivePlayersOn( ) == 1 ) { for ( ULONG i = 0; i < teams.Size( ); i++ ) { if ( TEAM_CountLivingAndRespawnablePlayers( i ) ) lWinner = i; } } else { lWinner = teams.Size( ); bTie = true; } } // If for some reason we don't have any players, just end the map like normal. if ( lWinner == -1 ) { if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVER_Printf( PRINT_HIGH, "%s\n", GStrings( "TXT_TIMELIMIT" )); else Printf( "%s\n", GStrings( "TXT_TIMELIMIT" )); GAME_SetEndLevelDelay( 5 * TICRATE ); return; } // If there was a tie, then go into sudden death! if ( bTie ) { // Only print the message the instant we reach sudden death. if ( level.time == (int)( timelimit * TICRATE * 60 )) { sprintf( szString, "\\cdSUDDEN DEATH!" ); V_ColorizeString( szString ); if ( NETWORK_GetState( ) != NETSTATE_SERVER ) { // Display the 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') ); } else { SERVERCOMMANDS_PrintHUDMessageFadeOut( szString, 160.4f, 75.0f, 320, 200, CR_RED, 3.0f, 2.0f, "BigFont", false, MAKE_ID('C','N','T','R') ); } } return; } // Also, do the win sequence for the player. LASTMANSTANDING_DoWinSequence( lWinner ); // Give the winner a win. if ( lastmanstanding ) PLAYER_SetWins( &players[lWinner], players[lWinner].ulWins + 1 ); // [BB] In a team game of course give the win to the winning team. if ( teamlms ) TEAM_SetWinCount( lWinner, TEAM_GetWinCount( lWinner ) + 1, false ); if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVER_Printf( PRINT_HIGH, "%s\n", GStrings( "TXT_TIMELIMIT" )); else Printf( "%s\n", GStrings( "TXT_TIMELIMIT" )); GAME_SetEndLevelDelay( 5 * TICRATE ); }
//***************************************************************************** // void LASTMANSTANDING_Tick( void ) { // Not in LMS mode. if (( lastmanstanding == false ) && ( teamlms == false )) return; switch ( g_LMSState ) { case LMSS_WAITINGFORPLAYERS: if (( NETWORK_GetState( ) == NETSTATE_CLIENT ) || ( CLIENTDEMO_IsPlaying( ))) { 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_GetState( ) != NETSTATE_CLIENT ) && ( CLIENTDEMO_IsPlaying( ) == 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_GetState( ) == NETSTATE_CLIENT ) || ( CLIENTDEMO_IsPlaying( ))) { 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.netname ); else { Printf( "%s \\c-wins!\n", players[lWinner].userinfo.netname ); 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 JOINQUEUE_PopQueue( LONG lNumSlots ) { ULONG ulIdx; // Nothing to do if there's nobody waiting in the queue. if ( g_lJoinQueue[0].ulPlayer == MAXPLAYERS ) return; // [BB] Players are not allowed to join. if ( GAMEMODE_PreventPlayersFromJoining() ) return; // Try to find the next person in line. ulIdx = 0; while ( 1 ) { // Found end of list. if (( ulIdx == MAXPLAYERS ) || ( g_lJoinQueue[ulIdx].ulPlayer == MAXPLAYERS ) || ( lNumSlots == 0 )) { break; } // [BB] Since we possibly just let somebody waiting in line join, check if more persons are allowed to join now. if ( GAMEMODE_PreventPlayersFromJoining() ) break; // Found a player waiting in line. They will now join the game! if ( playeringame[g_lJoinQueue[ulIdx].ulPlayer] ) { // [K6] Reset their AFK timer now - they may have been waiting in the queue silently and we don't want to kick them. SERVER_GetClient( g_lJoinQueue[ulIdx].ulPlayer )->lLastActionTic = gametic; PLAYER_SpectatorJoinsGame ( &players[g_lJoinQueue[ulIdx].ulPlayer] ); // [BB/Spleen] The "lag interval" is only half of the "spectate info send" interval. Account for this here. if (( gametic - SERVER_GetClient( g_lJoinQueue[ulIdx].ulPlayer )->ulLastCommandTic ) <= 2*TICRATE ) SERVER_GetClient( g_lJoinQueue[ulIdx].ulPlayer )->ulClientGameTic += ( gametic - SERVER_GetClient( g_lJoinQueue[ulIdx].ulPlayer )->ulLastCommandTic ); if ( GAMEMODE_GetFlags( GAMEMODE_GetCurrentMode( )) & GMF_PLAYERSONTEAMS ) { if ( TEAM_CheckIfValid ( g_lJoinQueue[ulIdx].ulTeam ) ) PLAYER_SetTeam( &players[g_lJoinQueue[ulIdx].ulPlayer], g_lJoinQueue[ulIdx].ulTeam, true ); else PLAYER_SetTeam( &players[g_lJoinQueue[ulIdx].ulPlayer], TEAM_ChooseBestTeamForPlayer( ), true ); } // Begin the duel countdown. if ( duel ) { // [BB] Skip countdown and map reset if the map is supposed to be a lobby. if ( GAMEMODE_IsLobbyMap( ) ) DUEL_SetState( DS_INDUEL ); else if ( sv_duelcountdowntime > 0 ) DUEL_StartCountdown(( sv_duelcountdowntime * TICRATE ) - 1 ); else DUEL_StartCountdown(( 10 * TICRATE ) - 1 ); } // Begin the LMS countdown. else if ( lastmanstanding ) { if ( sv_lmscountdowntime > 0 ) LASTMANSTANDING_StartCountdown(( sv_lmscountdowntime * TICRATE ) - 1 ); else LASTMANSTANDING_StartCountdown(( 10 * TICRATE ) - 1 ); } else { if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVER_Printf( PRINT_HIGH, "%s \\c-joined the game.\n", players[g_lJoinQueue[ulIdx].ulPlayer].userinfo.netname ); else Printf( "%s \\c-joined the game.\n", players[g_lJoinQueue[ulIdx].ulPlayer].userinfo.netname ); } JOINQUEUE_RemovePlayerAtPosition ( ulIdx ); if ( lNumSlots > 0 ) lNumSlots--; } else ulIdx++; } // If we're the server, tell everyone their new position in line. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVERCOMMANDS_SetQueuePosition( ); }
//***************************************************************************** // void JOINQUEUE_PlayerLeftGame( bool bWantPop ) { bool bPop = true; // If we're in a duel, revert to the "waiting for players" state. // [BB] But only do so if there are less then two duelers left (probably JOINQUEUE_PlayerLeftGame was called mistakenly). if ( duel && ( DUEL_CountActiveDuelers( ) < 2 ) ) DUEL_SetState( DS_WAITINGFORPLAYERS ); // If only one (or zero) person is left, go back to "waiting for players". if ( lastmanstanding ) { // Someone just won by default! if (( GAME_CountLivingAndRespawnablePlayers( ) == 1 ) && ( LASTMANSTANDING_GetState( ) == LMSS_INPROGRESS )) { LONG lWinner; lWinner = LASTMANSTANDING_GetLastManStanding( ); if ( lWinner != -1 ) { if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVER_Printf( PRINT_HIGH, "%s \\c-wins!\n", players[lWinner].userinfo.netname ); else { Printf( "%s \\c-wins!\n", players[lWinner].userinfo.netname ); 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 ); } // Join queue will be popped upon state change. bPop = false; GAME_SetEndLevelDelay( 5 * TICRATE ); } else if ( SERVER_CalcNumNonSpectatingPlayers( MAXPLAYERS ) <= 1 ) LASTMANSTANDING_SetState( LMSS_WAITINGFORPLAYERS ); } if ( teamlms ) { // Someone just won by default! if (( LASTMANSTANDING_GetState( ) == LMSS_INPROGRESS ) && 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 ); // Pause for five seconds for the win sequence. LASTMANSTANDING_DoWinSequence( lWinner ); } // Join queue will be popped upon state change. bPop = false; GAME_SetEndLevelDelay( 5 * TICRATE ); } else if ( TEAM_TeamsWithPlayersOn( ) <= 1 ) LASTMANSTANDING_SetState( LMSS_WAITINGFORPLAYERS ); } // If we're in possession mode, revert to the "waiting for players" state // [BB] when there are less than two players now. if ( possession && ( SERVER_CalcNumNonSpectatingPlayers( MAXPLAYERS ) < 2 )) POSSESSION_SetState( PSNS_WAITINGFORPLAYERS ); if ( teampossession && ( TEAM_TeamsWithPlayersOn( ) <= 1 ) ) POSSESSION_SetState( PSNS_WAITINGFORPLAYERS ); // If we're in invasion mode, revert to the "waiting for players" state. if ( invasion && ( SERVER_CalcNumNonSpectatingPlayers( MAXPLAYERS ) < 1 )) INVASION_SetState( IS_WAITINGFORPLAYERS ); // If we're in survival co-op mode, revert to the "waiting for players" state. if ( survival && ( SERVER_CalcNumNonSpectatingPlayers( MAXPLAYERS ) < 1 )) SURVIVAL_SetState( SURVS_WAITINGFORPLAYERS ); // Potentially let one person join the game. if ( bPop && bWantPop ) JOINQUEUE_PopQueue( 1 ); }
//***************************************************************************** // bool CALLVOTE_VoteNo( ULONG ulPlayer ) { ULONG ulIdx; ULONG ulNumYes; ULONG ulNumNo; // Don't allow the vote unless we're in the middle of a vote. if ( g_VoteState != VOTESTATE_INVOTE ) return ( false ); // [RC] If this is our vote, hide the vote screen soon. if (( NETWORK_GetState( ) == NETSTATE_CLIENT ) && ( static_cast<LONG>(ulPlayer) == consoleplayer ) ) g_ulShowVoteScreenTicks = 1 * TICRATE; // [RC] Vote callers can cancel their votes by voting "no". if ( ulPlayer == g_ulVoteCaller && ( NETWORK_GetState( ) == NETSTATE_SERVER )) { // [BB] If a player canceled his own vote, don't prevent others from making this type of vote again. g_PreviousVotes.back( ).ulVoteType = NUM_VOTECMDS; SERVER_Printf( PRINT_HIGH, "Vote caller cancelled the vote.\n" ); g_bVoteCancelled = true; g_bVotePassed = false; callvote_EndVote( ); return ( true ); } // Also, don't allow spectator votes if the server has them disabled. if (( NETWORK_GetState( ) == NETSTATE_SERVER ) && ( sv_nocallvote == 2 && players[ulPlayer].bSpectating )) { SERVER_PrintfPlayer( PRINT_HIGH, ulPlayer, "This server requires spectators to join the game to vote.\n" ); return false; } // If this player has already voted, ignore his vote. for ( ulIdx = 0; ulIdx < ( MAXPLAYERS / 2 ) + 1; ulIdx++ ) { if ( g_ulPlayersWhoVotedYes[ulIdx] == ulPlayer ) return ( false ); if ( g_ulPlayersWhoVotedNo[ulIdx] == ulPlayer ) return ( false ); // If this person matches the IP of a person who already voted, don't let him vote. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) { if ( g_ulPlayersWhoVotedYes[ulIdx] < MAXPLAYERS ) { if ( NETWORK_CompareAddress( SERVER_GetClient( g_ulPlayersWhoVotedYes[ulIdx] )->Address, SERVER_GetClient( ulPlayer )->Address, true )) return ( false ); } if ( g_ulPlayersWhoVotedNo[ulIdx] < MAXPLAYERS ) { if ( NETWORK_CompareAddress( SERVER_GetClient( g_ulPlayersWhoVotedNo[ulIdx] )->Address, SERVER_GetClient( ulPlayer )->Address, true )) return ( false ); } } } // Add this player's vote. for ( ulIdx = 0; ulIdx < ( MAXPLAYERS / 2 ) + 1; ulIdx++ ) { if ( g_ulPlayersWhoVotedNo[ulIdx] == MAXPLAYERS ) { g_ulPlayersWhoVotedNo[ulIdx] = ulPlayer; break; } } // Display the message in the console. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) Printf( "%s\\c- (%s) votes \"no\".\n", players[ulPlayer].userinfo.netname, NETWORK_AddressToString( SERVER_GetClient( ulPlayer )->Address )); else Printf( "%s\\c- votes \"no\".\n", players[ulPlayer].userinfo.netname ); // Nothing more to do here for clients. if (( NETWORK_GetState( ) == NETSTATE_CLIENT ) || ( CLIENTDEMO_IsPlaying( ))) { return ( true ); } SERVERCOMMANDS_PlayerVote( ulPlayer, false ); ulNumYes = callvote_CountPlayersWhoVotedYes( ); ulNumNo = callvote_CountPlayersWhoVotedNo( ); // If more than half of the total eligible voters have voted, we must have a majority! if ( MAX( ulNumYes, ulNumNo ) > ( CALLVOTE_CountNumEligibleVoters( ) / 2 )) { g_bVotePassed = ( ulNumYes > ulNumNo ); callvote_EndVote( ); } return ( true ); }
void cht_Give (player_t *player, const char *name, int amount) { enum { ALL_NO, ALL_YES, ALL_YESYES } giveall; int i; const PClass *type; if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVER_Printf( PRINT_HIGH, "%s is a cheater: give %s\n", player->userinfo.netname, name ); else if (player != &players[consoleplayer]) Printf ("%s is a cheater: give %s\n", player->userinfo.netname, name); if (player->mo == NULL || player->health <= 0) { return; } giveall = ALL_NO; if (stricmp (name, "all") == 0) { giveall = ALL_YES; } else if (stricmp (name, "everything") == 0) { giveall = ALL_YESYES; } if (stricmp (name, "health") == 0) { if (amount > 0) { if (player->mo) { player->mo->health += amount; player->health = player->mo->health; } else { player->health += amount; } } else { if (player->mo != NULL) { player->health = player->mo->health = player->mo->GetMaxHealth(); } else { player->health = deh.GodHealth; } } // [BB]: The server has to inform the clients that this player's health has changed. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) { ULONG playerIdx = static_cast<ULONG> ( player - players ); SERVERCOMMANDS_SetPlayerHealth( playerIdx ); } } if (giveall || stricmp (name, "backpack") == 0) { // Select the correct type of backpack based on the game type = PClass::FindClass(gameinfo.backpacktype); if (type != NULL) { GiveSpawner (player, type, 1); } if (!giveall) return; } if (giveall || stricmp (name, "ammo") == 0) { // Find every unique type of ammo. Give it to the player if // he doesn't have it already, and set each to its maximum. for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) { const PClass *type = PClass::m_Types[i]; if (type->ParentClass == RUNTIME_CLASS(AAmmo)) { AInventory *ammo = player->mo->FindInventory (type); if (ammo == NULL) { ammo = static_cast<AInventory *>(Spawn (type, 0, 0, 0, NO_REPLACE)); ammo->AttachToOwner (player->mo); ammo->Amount = ammo->MaxAmount; } else if (ammo->Amount < ammo->MaxAmount) { ammo->Amount = ammo->MaxAmount; } // [BB] This construction is more or less a hack, but at least the give cheats are now working. SERVER_GiveInventoryToPlayer( player, ammo ); } } if (!giveall) return; } if (giveall || stricmp (name, "armor") == 0) { if (gameinfo.gametype != GAME_Hexen) { ABasicArmorPickup *armor = Spawn<ABasicArmorPickup> (0,0,0, NO_REPLACE); armor->SaveAmount = 100*deh.BlueAC; armor->SavePercent = gameinfo.Armor2Percent > 0? gameinfo.Armor2Percent : FRACUNIT/2; if (!armor->CallTryPickup (player->mo)) { armor->Destroy (); } else { // [BB] This construction is more or less a hack, but at least the give cheats are now working. SERVER_GiveInventoryToPlayer( player, armor ); } } else { for (i = 0; i < 4; ++i) { AHexenArmor *armor = Spawn<AHexenArmor> (0,0,0, NO_REPLACE); armor->health = i; armor->Amount = 0; if (!armor->CallTryPickup (player->mo)) { armor->Destroy (); } else { // [BB] This construction is more or less a hack, but at least the give cheats are now working. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) { SERVER_GiveInventoryToPlayer( player, armor ); SERVERCOMMANDS_SyncHexenArmorSlots ( static_cast<ULONG> ( player - players ) ); } } } } if (!giveall) return; } if (giveall || stricmp (name, "keys") == 0) { for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) { if (PClass::m_Types[i]->IsDescendantOf (RUNTIME_CLASS(AKey))) { AKey *key = (AKey *)GetDefaultByType (PClass::m_Types[i]); if (key->KeyNumber != 0) { key = static_cast<AKey *>(Spawn (PClass::m_Types[i], 0,0,0, NO_REPLACE)); if (!key->CallTryPickup (player->mo)) { key->Destroy (); } else { // [BB] This construction is more or less a hack, but at least the give cheats are now working. SERVER_GiveInventoryToPlayer( player, key ); } } } } if (!giveall) return; } if (giveall || stricmp (name, "weapons") == 0 || stricmp (name, "stdweapons") == 0) { // [BB] Don't give the ST weapons if this it true. Useful if you want // to start a game in the middle of a Doom coop megawad for example. bool stdweapons = (stricmp (name, "stdweapons") == 0); AWeapon *savedpending = player->PendingWeapon; for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) { type = PClass::m_Types[i]; // Don't give replaced weapons unless the replacement was done by Dehacked. if (type != RUNTIME_CLASS(AWeapon) && type->IsDescendantOf (RUNTIME_CLASS(AWeapon)) && (type->ActorInfo->GetReplacement() == type->ActorInfo || type->ActorInfo->GetReplacement()->Class->IsDescendantOf(RUNTIME_CLASS(ADehackedPickup)))) { // Give the weapon only if it belongs to the current game or // is in a weapon slot. if (type->ActorInfo->GameFilter == GAME_Any || (type->ActorInfo->GameFilter & gameinfo.gametype) || player->weapons.LocateWeapon(type, NULL, NULL)) { if (stdweapons) { const char *WeaponName = type->TypeName.GetChars(); if ( !stricmp (WeaponName, "Railgun") || !stricmp (WeaponName, "Minigun") || !stricmp (WeaponName, "GrenadeLauncher") || !stricmp (WeaponName, "Bfg10K") ) continue; } AWeapon *def = (AWeapon*)GetDefaultByType (type); if (giveall == ALL_YESYES || !(def->WeaponFlags & WIF_CHEATNOTWEAPON)) { GiveSpawner (player, type, 1); } } } } player->PendingWeapon = savedpending; // [BB] If we're the server, also tell the client to restore the original weapon. if ( NETWORK_GetState( ) == NETSTATE_SERVER ) { // [BB] We need to make sure that the client has its old weapon up instantly. // Since there is no net command for this and I don't want to add another net command // just for this cheat, we use a workaround here. const bool playerHasInstantWeapSwitch = !!(player->cheats & CF_INSTANTWEAPSWITCH); const ULONG ulPlayer = static_cast<ULONG>( player - players ); if ( playerHasInstantWeapSwitch == false ) { player->cheats |= CF_INSTANTWEAPSWITCH; SERVERCOMMANDS_SetPlayerCheats( ulPlayer ); } SERVERCOMMANDS_WeaponChange( ulPlayer ); if ( playerHasInstantWeapSwitch == false ) { player->cheats &= ~CF_INSTANTWEAPSWITCH; SERVERCOMMANDS_SetPlayerCheats( ulPlayer ); } } if (!giveall) return; } if (giveall || stricmp (name, "artifacts") == 0) { for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) { type = PClass::m_Types[i]; if (type->IsDescendantOf (RUNTIME_CLASS(AInventory))) { AInventory *def = (AInventory*)GetDefaultByType (type); if (def->Icon.isValid() && def->MaxAmount > 1 && !type->IsDescendantOf (RUNTIME_CLASS(APuzzleItem)) && !type->IsDescendantOf (RUNTIME_CLASS(APowerup)) && !type->IsDescendantOf (RUNTIME_CLASS(AArmor))) { GiveSpawner (player, type, amount <= 0 ? def->MaxAmount : amount); } } } if (!giveall) return; } if (giveall || stricmp (name, "puzzlepieces") == 0) { for (unsigned int i = 0; i < PClass::m_Types.Size(); ++i) { type = PClass::m_Types[i]; if (type->IsDescendantOf (RUNTIME_CLASS(APuzzleItem))) { AInventory *def = (AInventory*)GetDefaultByType (type); if (def->Icon.isValid()) { GiveSpawner (player, type, amount <= 0 ? def->MaxAmount : amount); } } } if (!giveall) return; } if (giveall) return; type = PClass::FindClass (name); if (type == NULL || !type->IsDescendantOf (RUNTIME_CLASS(AInventory))) { if (player == &players[consoleplayer]) Printf ("Unknown item \"%s\"\n", name); } else { GiveSpawner (player, type, amount); } return; }
void cht_DoCheat (player_t *player, int cheat) { static const char * BeholdPowers[9] = { "PowerInvulnerable", "PowerStrength", "PowerInvisibility", "PowerIronFeet", "MapRevealer", "PowerLightAmp", "PowerShadow", "PowerMask", "PowerTargeter", }; const PClass *type; AInventory *item; const char *msg = ""; char msgbuild[32]; int i; switch (cheat) { case CHT_IDDQD: if (!(player->cheats & CF_GODMODE) && player->playerstate == PST_LIVE) { if (player->mo) player->mo->health = deh.GodHealth; player->health = deh.GodHealth; } // fall through to CHT_GOD case CHT_GOD: player->cheats ^= CF_GODMODE; if (gameinfo.gametype != GAME_Chex) { if (player->cheats & CF_GODMODE) msg = GStrings("STSTR_DQDON"); else msg = GStrings("STSTR_DQDOFF"); } else { if (player->cheats & CF_GODMODE) msg = GStrings("STSTR_CDQDON"); else msg = GStrings("STSTR_CDQDOFF"); } if ( NETWORK_GetState( ) != NETSTATE_SERVER ) SB_state = screen->GetPageCount (); break; case CHT_BUDDHA: player->cheats ^= CF_BUDDHA; if (player->cheats & CF_BUDDHA) msg = GStrings("TXT_BUDDHAON"); else msg = GStrings("TXT_BUDDHAOFF"); break; case CHT_NOCLIP: player->cheats ^= CF_NOCLIP; if (player->cheats & CF_NOCLIP) msg = GStrings("STSTR_NCON"); else msg = GStrings("STSTR_NCOFF"); break; case CHT_NOVELOCITY: player->cheats ^= CF_NOVELOCITY; if (player->cheats & CF_NOVELOCITY) msg = GStrings("TXT_LEADBOOTSON"); else msg = GStrings("TXT_LEADBOOTSOFF"); break; case CHT_FLY: if (player->mo != NULL) { player->cheats ^= CF_FLY; if (player->cheats & CF_FLY) { player->mo->flags |= MF_NOGRAVITY; player->mo->flags2 |= MF2_FLY; msg = GStrings("TXT_LIGHTER"); } else { player->mo->flags &= ~MF_NOGRAVITY; player->mo->flags2 &= ~MF2_FLY; msg = GStrings("TXT_GRAVITY"); } } break; case CHT_MORPH: msg = cht_Morph (player, PClass::FindClass (gameinfo.gametype == GAME_Heretic ? NAME_ChickenPlayer : NAME_PigPlayer), true); break; case CHT_NOTARGET: player->cheats ^= CF_NOTARGET; if (player->cheats & CF_NOTARGET) msg = "notarget ON"; else msg = "notarget OFF"; break; case CHT_ANUBIS: player->cheats ^= CF_FRIGHTENING; if (player->cheats & CF_FRIGHTENING) msg = "\"Quake with fear!\""; else msg = "No more ogre armor"; break; case CHT_CHASECAM: player->cheats ^= CF_CHASECAM; if (player->cheats & CF_CHASECAM) msg = "chasecam ON"; else msg = "chasecam OFF"; R_ResetViewInterpolation (); break; case CHT_CHAINSAW: if (player->mo != NULL && player->health >= 0) { type = PClass::FindClass ("Chainsaw"); if (player->mo->FindInventory (type) == NULL) { player->mo->GiveInventoryType (type); } if(gameinfo.gametype != GAME_Chex) msg = GStrings("STSTR_CHOPPERS"); else msg = GStrings("STSTR_CCHOPPERS"); } // [RH] The original cheat also set powers[pw_invulnerability] to true. // Since this is a timer and not a boolean, it effectively turned off // the invulnerability powerup, although it looks like it was meant to // turn it on. break; case CHT_POWER: if (player->mo != NULL && player->health >= 0) { item = player->mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2)); if (item != NULL) { item->Destroy (); msg = GStrings("TXT_CHEATPOWEROFF"); } else { player->mo->GiveInventoryType (RUNTIME_CLASS(APowerWeaponLevel2)); msg = GStrings("TXT_CHEATPOWERON"); } } break; case CHT_IDKFA: cht_Give (player, "backpack"); cht_Give (player, "weapons"); cht_Give (player, "ammo"); cht_Give (player, "keys"); cht_Give (player, "armor"); if(gameinfo.gametype != GAME_Chex) msg = GStrings("STSTR_KFAADDED"); else msg = GStrings("STSTR_CKFAADDED"); break; case CHT_IDFA: cht_Give (player, "backpack"); cht_Give (player, "weapons"); cht_Give (player, "ammo"); cht_Give (player, "armor"); if(gameinfo.gametype != GAME_Chex) msg = GStrings("STSTR_FAADDED"); else msg = GStrings("STSTR_CFAADDED"); break; case CHT_BEHOLDV: case CHT_BEHOLDS: case CHT_BEHOLDI: case CHT_BEHOLDR: case CHT_BEHOLDA: case CHT_BEHOLDL: case CHT_PUMPUPI: case CHT_PUMPUPM: case CHT_PUMPUPT: i = cheat - CHT_BEHOLDV; if (i == 4) { level.flags2 ^= LEVEL2_ALLMAP; } else if (player->mo != NULL && player->health >= 0) { item = player->mo->FindInventory (BeholdPowers[i]); if (item == NULL) { if (i != 0) { cht_Give(player, BeholdPowers[i]); if (cheat == CHT_BEHOLDS) { P_GiveBody (player->mo, -100); } } else { // Let's give the item here so that the power doesn't need colormap information. cht_Give(player, "InvulnerabilitySphere"); } } else { item->Destroy (); } } msg = GStrings("STSTR_BEHOLDX"); break; case CHT_MASSACRE: { int killcount = P_Massacre (); // killough 3/22/98: make more intelligent about plural // Ty 03/27/98 - string(s) *not* externalized mysnprintf (msgbuild, countof(msgbuild), "%d Monster%s Killed", killcount, killcount==1 ? "" : "s"); msg = msgbuild; } break; case CHT_HEALTH: if (player->mo != NULL && player->playerstate == PST_LIVE) { player->health = player->mo->health = player->mo->GetDefault()->health; msg = GStrings("TXT_CHEATHEALTH"); } break; case CHT_KEYS: cht_Give (player, "keys"); msg = GStrings("TXT_CHEATKEYS"); break; // [GRB] case CHT_RESSURECT: if (player->playerstate != PST_LIVE && player->mo != NULL) { if (player->mo->IsKindOf(RUNTIME_CLASS(APlayerChunk))) { Printf("Unable to resurrect. Player is no longer connected to its body.\n"); } else { player->playerstate = PST_LIVE; player->health = player->mo->health = player->mo->GetDefault()->health; player->viewheight = ((APlayerPawn *)player->mo->GetDefault())->ViewHeight; player->mo->flags = player->mo->GetDefault()->flags; player->mo->flags2 = player->mo->GetDefault()->flags2; player->mo->flags3 = player->mo->GetDefault()->flags3; player->mo->flags4 = player->mo->GetDefault()->flags4; player->mo->flags5 = player->mo->GetDefault()->flags5; player->mo->renderflags &= ~RF_INVISIBLE; player->mo->height = player->mo->GetDefault()->height; player->mo->special1 = 0; // required for the Hexen fighter's fist attack. // This gets set by AActor::Die as flag for the wimpy death and must be reset here. player->mo->SetState (player->mo->SpawnState); if (!(player->mo->flags2 & MF2_DONTTRANSLATE)) { player->mo->Translation = TRANSLATION(TRANSLATION_Players, BYTE(player-players)); } player->mo->DamageType = NAME_None; // player->mo->GiveDefaultInventory(); if (player->ReadyWeapon != NULL) { P_SetPsprite(player, ps_weapon, player->ReadyWeapon->GetUpState()); } if (player->morphTics > 0) { P_UndoPlayerMorph(player, player); } } } break; case CHT_GIMMIEA: cht_Give (player, "ArtiInvulnerability"); msg = "Valador's Ring of Invunerability"; break; case CHT_GIMMIEB: cht_Give (player, "ArtiInvisibility"); msg = "Shadowsphere"; break; case CHT_GIMMIEC: cht_Give (player, "ArtiHealth"); msg = "Quartz Flask"; break; case CHT_GIMMIED: cht_Give (player, "ArtiSuperHealth"); msg = "Mystic Urn"; break; case CHT_GIMMIEE: cht_Give (player, "ArtiTomeOfPower"); msg = "Tyketto's Tome of Power"; break; case CHT_GIMMIEF: cht_Give (player, "ArtiTorch"); msg = "Torch"; break; case CHT_GIMMIEG: cht_Give (player, "ArtiTimeBomb"); msg = "Delmintalintar's Time Bomb of the Ancients"; break; case CHT_GIMMIEH: cht_Give (player, "ArtiEgg"); msg = "Torpol's Morph Ovum"; break; case CHT_GIMMIEI: cht_Give (player, "ArtiFly"); msg = "Inhilicon's Wings of Wrath"; break; case CHT_GIMMIEJ: cht_Give (player, "ArtiTeleport"); msg = "Darchala's Chaos Device"; break; case CHT_GIMMIEZ: for (int i=0;i<16;i++) { cht_Give (player, "artifacts"); } msg = "All artifacts!"; break; case CHT_TAKEWEAPS: if (player->morphTics || player->mo == NULL || player->mo->health <= 0) { return; } { // Take away all weapons that are either non-wimpy or use ammo. AInventory **invp = &player->mo->Inventory, **lastinvp; for (item = *invp; item != NULL; item = *invp) { lastinvp = invp; invp = &(*invp)->Inventory; if (item->IsKindOf (RUNTIME_CLASS(AWeapon))) { AWeapon *weap = static_cast<AWeapon *> (item); if (!(weap->WeaponFlags & WIF_WIMPY_WEAPON) || weap->AmmoType1 != NULL) { item->Destroy (); invp = lastinvp; } } } } msg = GStrings("TXT_CHEATIDKFA"); break; case CHT_NOWUDIE: cht_Suicide (player); msg = GStrings("TXT_CHEATIDDQD"); break; case CHT_ALLARTI: for (int i=0;i<25;i++) { cht_Give (player, "artifacts"); } msg = GStrings("TXT_CHEATARTIFACTS3"); break; case CHT_PUZZLE: cht_Give (player, "puzzlepieces"); msg = GStrings("TXT_CHEATARTIFACTS3"); break; case CHT_MDK: if (player->mo == NULL) { Printf ("What do you want to kill outside of a game?\n"); } // else if (!deathmatch) { // Don't allow this in deathmatch even with cheats enabled, because it's // a very very cheap kill. // [Dusk] <jino> and summoning 5000 bfg balls isn't? P_LineAttack (player->mo, player->mo->angle, PLAYERMISSILERANGE, P_AimLineAttack (player->mo, player->mo->angle, PLAYERMISSILERANGE), TELEFRAG_DAMAGE, NAME_MDK, NAME_BulletPuff); } break; case CHT_DONNYTRUMP: cht_Give (player, "HealthTraining"); msg = GStrings("TXT_MIDASTOUCH"); break; case CHT_LEGO: if (player->mo != NULL && player->health >= 0) { int oldpieces = ASigil::GiveSigilPiece (player->mo); item = player->mo->FindInventory (RUNTIME_CLASS(ASigil)); if (item != NULL) { if (oldpieces == 5) { item->Destroy (); } else { player->PendingWeapon = static_cast<AWeapon *> (item); } } } break; case CHT_PUMPUPH: cht_Give (player, "MedPatch"); cht_Give (player, "MedicalKit"); cht_Give (player, "SurgeryKit"); msg = GStrings("TXT_GOTSTUFF"); break; case CHT_PUMPUPP: cht_Give (player, "AmmoSatchel"); msg = GStrings("TXT_GOTSTUFF"); break; case CHT_PUMPUPS: cht_Give (player, "UpgradeStamina", 10); cht_Give (player, "UpgradeAccuracy"); msg = GStrings("TXT_GOTSTUFF"); break; case CHT_CLEARFROZENPROPS: player->cheats &= ~(CF_FROZEN|CF_TOTALLYFROZEN); msg = "Frozen player properties turned off"; break; /* [BB] Skulltag doesn't use this. case CHT_FREEZE: bglobal.changefreeze ^= 1; if (bglobal.freeze ^ bglobal.changefreeze) { msg = GStrings("TXT_FREEZEON"); } else { msg = GStrings("TXT_FREEZEOFF"); } break; */ } if (!*msg) // [SO] Don't print blank lines! return; if( ( cheat != CHT_CHASECAM ) || ( !( GAMEMODE_GetFlags( GAMEMODE_GetCurrentMode( )) & GMF_COOPERATIVE ) && ( player->bSpectating == false ) && !(dmflags2 & DF2_CHASECAM))){ if ( NETWORK_GetState( ) == NETSTATE_SERVER ) SERVER_Printf( PRINT_HIGH, "%s is a cheater: %s\n", player->userinfo.netname, msg ); else if ( player == &players[consoleplayer] || CLIENTDEMO_IsFreeSpectatorPlayer( player ) ) Printf ("%s\n", msg); // [BB] The server already ensures that all clients see the cheater message. else if ( NETWORK_GetState( ) != NETSTATE_CLIENT ) Printf ("%s is a cheater: %s\n", player->userinfo.netname, msg); } }