void EnergyGaugeRenderer::render(S32 energy) { // Create fade static const F32 colors[] = { Colors::blue.r, Colors::blue.g, Colors::blue.b, 1, // Fade from Colors::blue.r, Colors::blue.g, Colors::blue.b, 1, Colors::cyan.r, Colors::cyan.g, Colors::cyan.b, 1, // Fade to Colors::cyan.r, Colors::cyan.g, Colors::cyan.b, 1, }; GaugeRenderer::render(energy, Ship::EnergyMax, colors, GaugeBottomMargin, GaugeHeight, Ship::EnergyCooldownThreshold); #ifdef SHOW_SERVER_SITUATION ServerGame *serverGame = GameManager::getServerGame(); if((serverGame && serverGame->getClientInfo(0)->getConnection()->getControlObject())) { S32 actDiff = static_cast<Ship *>(serverGame->getClientInfo(0)->getConnection()->getControlObject())->getEnergy(); S32 p = F32(actDiff) / Ship::EnergyMax * GaugeWidth; glColor(Colors::magenta); drawVertLine(xul + p, yul - SafetyLineExtend - 1, yul + GaugeHeight + SafetyLineExtend); //Or, perhaps, just this: //renderGauge(energy, Ship::EnergyMax, Colors::blue, Colors::cyan, GaugeBottomMargin, GaugeHeight); } #endif }
// Scenario 11 -- Player is editing loadout when level changes --> TEST NOT COMPLETE!!!! static void doScenario11(GamePair &gamePair) { ClientGame *clientGame = gamePair.getClient(0); ServerGame *serverGame = gamePair.server; serverGame->setGameTime(.5); // 30 seconds GameUserInterface *gameUI = clientGame->getUIManager()->getUI<GameUserInterface>(); ASSERT_FALSE(gameUI->isHelperActive(HelperMenu::LoadoutHelperType)); gameUI->activateHelper(HelperMenu::LoadoutHelperType); ASSERT_TRUE(gameUI->isHelperActive(HelperMenu::LoadoutHelperType)); ASSERT_EQ("", serverGame->getClientInfo(0)->getOnDeckLoadout().toString(true)); // Prove there's no on deck loadout // See static const OverlayMenuItem loadoutModuleMenuItems[] in loadoutHelper.cpp // Feed the UI some keys... like we're configuring a loadout! gameUI->onKeyDown(KEY_1); gameUI->onKeyDown(KEY_3); // First 2 modules... gameUI->onKeyDown(KEY_1); gameUI->onKeyDown(KEY_2); gameUI->onKeyDown(KEY_3); // ...then 3 weapons ASSERT_FALSE(gameUI->isHelperActive(HelperMenu::LoadoutHelperType)); gamePair.idle(10, 10); // Check the on deck loadout on server -- does not get set on the client ASSERT_EQ("Turbo,Repair,Phaser,Bouncer,Triple", serverGame->getClientInfo(0)->getOnDeckLoadout().toString(true)); gameUI->activateHelper(HelperMenu::LoadoutHelperType); ASSERT_TRUE(gameUI->isHelperActive(HelperMenu::LoadoutHelperType)); gamePair.idle(100, 350); // Idle until game ends gameUI->onKeyDown(KEY_1); gameUI->onKeyDown(KEY_4); gameUI->onKeyDown(KEY_1); gameUI->onKeyDown(KEY_2); gameUI->onKeyDown(KEY_3); ASSERT_FALSE(gameUI->isHelperActive(HelperMenu::LoadoutHelperType)); gamePair.idle(10, 10); ASSERT_EQ("Turbo,Sensor,Phaser,Bouncer,Triple", serverGame->getClientInfo(0)->getOnDeckLoadout().toString(true)); }
// Scenario 1: Player is idle and gets suspended -- no other players in game static void doScenario1(GamePair &gamePair) { ClientGame *clientGame = gamePair.getClient(0); ServerGame *serverGame = gamePair.server; // Idle for a while -- ship should become spawn delayed. GameConnection::SPAWN_DELAY_TIME is measured in ms. gamePair.idle(10, GameConnection::SPAWN_DELAY_TIME / 10); ASSERT_TRUE(serverGame->getClientInfo(0)->isPlayerInactive()); // No input from player, should be flagged as inactive // Note that spawn delay does not get set until the delayed ship tries to spawn, even if player is marked as inactive // Kill the ship again -- should be delayed when it tries to respawn because client has been inactive fillVector.clear(); serverGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); EXPECT_EQ(1, fillVector.size()); // Should only be one ship Ship *ship = static_cast<Ship *>(fillVector[0]); // Server's copy of the ship killShip(ship); gamePair.idle(10, GameType::RespawnDelay / 10 + 5); // Since server has received no input from client for GameConnection::SPAWN_DELAY_TIME ms, and ship has attempted to respawn, should be spawn-delayed ASSERT_TRUE(serverGame->getClientInfo(0)->isSpawnDelayed()); ASSERT_TRUE(clientGame->isSpawnDelayed()); // Status should have propagated to client by now // At this point, client and server are both aware that the spawn is delayed due to player inactivity gamePair.idle(10, 10); // Idle 10x // If spawn were not delayed, ship would have respawned. Check for it on the server. // (Dead ship may linger on client while exploding, so we won't check there.) fillVector.clear(); serverGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(0, fillVector.size()); // Ship is spawn delayed and won't spawn... hence no ships ASSERT_EQ(0, serverGame->getClientInfo(0)->getReturnToGameTime()); // No returnToGamePenalty in this scenario ASSERT_EQ(0, clientGame->getReturnToGameDelay()); ASSERT_FALSE(static_cast<FullClientInfo *>(serverGame->getClientInfo(0))->hasReturnToGamePenalty()); // No penalty in the works // Undelay spawn clientGame->undelaySpawn(); // This is what gets run when player presses a key gamePair.idle(10, 5); // Idle 5x; give things time to propagate ASSERT_FALSE(serverGame->getClientInfo(0)->isSpawnDelayed()); // Player should no longer be spawn delayed ASSERT_FALSE(clientGame->inReturnToGameCountdown()); fillVector.clear(); serverGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(1, fillVector.size()); // Ship should have spawned and be available on client and server fillVector.clear(); clientGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(1, fillVector.size()); // Ship should have spawned and be available on client and server }
/** * @luafunc table Team::getPlayers() * * @brief Get a table containing all players on a team. * * @code * local players = team:getPlayers() * for i, v in ipairs(players) do * print(v:getName()) * end * @endcode * * @return A table of \link LuaPlayerInfo LuaPlayerInfos \endlink currently on this * team. */ S32 Team::lua_getPlayers(lua_State *L) { ServerGame *game = GameManager::getServerGame(); TNLAssert(game->getPlayerCount() == game->getClientCount(), "Mismatched player counts!"); S32 pushed = 0; lua_newtable(L); // Create a table, with no slots pre-allocated for our data for(S32 i = 0; i < game->getClientCount(); i++) { ClientInfo *clientInfo = game->getClientInfo(i); if(clientInfo->getTeamIndex() == mTeamIndex) { clientInfo->getPlayerInfo()->push(L); pushed++; // Increment pushed before using it because Lua uses 1-based arrays lua_rawseti(L, 1, pushed); } } for(S32 i = 0; i < game->getRobotCount(); i ++) { if(game->getBot(i)->getTeam() == mTeamIndex) { game->getBot(i)->getPlayerInfo()->push(L); pushed++; // Increment pushed before using it because Lua uses 1-based arrays lua_rawseti(L, 1, pushed); } } return 1; }
/** * @luafunc table LuaGameInfo::getPlayers() * * @brief Get a list of the players in the game. * * @return A table containing the LuaPlayerInfo for each player (and robot) in * the game */ S32 LuaGameInfo::lua_getPlayers(lua_State *L) { ServerGame *game = mServerGame; S32 pushed = 0; // Count of pushed objects lua_newtable(L); // Create a table, with no slots pre-allocated for our data for(S32 i = 0; i < game->getClientCount(); i++) { ClientInfo *clientInfo = game->getClientInfo(i); if(clientInfo->getPlayerInfo() == NULL || clientInfo->isRobot()) // Skip defunct players and bots continue; clientInfo->getPlayerInfo()->push(L); pushed++; // Increment pushed before using it because Lua uses 1-based arrays lua_rawseti(L, 1, pushed); } for(S32 i = 0; i < game->getRobotCount(); i ++) { game->getBot(i)->getPlayerInfo()->push(L); pushed++; // Increment pushed before using it because Lua uses 1-based arrays lua_rawseti(L, 1, pushed); } return 1; }
void GamePair::addBotClientAndSetTeam(const string &name, S32 teamIndex) { ServerGame *server = GameManager::getServerGame(); server->addBot(Vector<string>(), ClientInfo::ClassRobotAddedByAutoleveler); // Get most recently added clientInfo ClientInfo *clientInfo = server->getClientInfo(server->getClientInfos()->size() - 1); ASSERT_TRUE(clientInfo->isRobot()) << "This is supposed to be a robot!"; // Normally, in a game, a ship or bot would be destroyed and would respawn when their team changes, and upon // respawning the BfObject representing that ship would be on the correct team. Not so here (where we are // taking lots of shortcuts); here we need to manually assign a new team to the robot object in addition to // it's more "official" setting on the ClientInfo. clientInfo->setTeamIndex(teamIndex); clientInfo->getShip()->setTeam(teamIndex); }
TEST(GameUserInterfaceTest, Engineer) { InputCodeManager::initializeKeyNames(); GamePair gamePair(getLevelCodeForTestingEngineer1(), 3); // See def for description of level ServerGame *serverGame = GameManager::getServerGame(); const Vector<ClientGame *> *clientGames = GameManager::getClientGames(); GameSettings *clientSettings = clientGames->first()->getSettings(); GameUserInterface *gameUI = clientGames->first()->getUIManager()->getUI<GameUserInterface>(); DEFINE_KEYS_AND_EVENTS(clientSettings); // Idle for a while, let things settle GamePair::idle(10, 5); // Verify that engineer is enabled ASSERT_TRUE(serverGame->getGameType()->isEngineerEnabled()) << "Engineer should be enabled on server!"; for(S32 i = 0; i < clientGames->size(); i++) { SCOPED_TRACE("i = " + itos(i)); ASSERT_TRUE(clientGames->get(i)->getGameType()) << "Clients should have a GameType by now!"; ASSERT_TRUE(clientGames->get(i)->getGameType()->isEngineerEnabled()) << "Engineer mode not propagating to clients!"; } ASSERT_TRUE(serverGame->getClientInfo(0)->getShip()->isInZone(LoadoutZoneTypeNumber)); // Check level is as we expected // Add engineer to current loadout ASSERT_FALSE(gameUI->isHelperActive(HelperMenu::LoadoutHelperType)); gameUI->activateHelper(HelperMenu::LoadoutHelperType); ASSERT_TRUE(gameUI->isHelperActive(HelperMenu::LoadoutHelperType)); gameUI->onKeyDown(LOADOUT_KEY_ENGR); gameUI->onKeyDown(LOADOUT_KEY_REPAIR); // First 2 modules... gameUI->onKeyDown(LOADOUT_KEY_PHASER); gameUI->onKeyDown(LOADOUT_KEY_BOUNCE); gameUI->onKeyDown(LOADOUT_KEY_TRIPLE); // ...then 3 weapons // On this level, the ship spawn is inside a loadout zone, so loadout should take effect immediately GamePair::idle(10, 5); ASSERT_EQ("Engineer,Repair,Phaser,Bouncer,Triple", serverGame->getClientInfo(0)->getShip()->getLoadoutString()); for(S32 i = 0; i < clientGames->size(); i++) { SCOPED_TRACE("i = " + itos(i)); ASSERT_EQ("Engineer,Repair,Phaser,Bouncer,Triple", clientGames->get(0)->getLocalPlayerShip()->getLoadoutString()); } // Fly down to pick up resource item -- to get flying to work, need to create events at a very basic level ClientGame *clientGame = clientGames->get(0); Point startPos = clientGame->getLocalPlayerShip()->getActualPos(); Event::onEvent(clientGame, &EventDownPressed); GamePair::idle(100, 5); Event::onEvent(clientGame, &EventDownReleased); Point endPos = clientGame->getLocalPlayerShip()->getActualPos(); ASSERT_TRUE(startPos.distSquared(endPos) > 0) << "Ship did not move!!"; for(S32 i = 0; i < clientGames->size(); i++) { SCOPED_TRACE("i = " + itos(i)); ASSERT_TRUE(clientGames->get(0)->getLocalPlayerShip()->isCarryingItem(ResourceItemTypeNumber)); } // Time to engineer! gameUI->onKeyDown(KEY_MOD1); ASSERT_TRUE(gameUI->isHelperActive(HelperMenu::EngineerHelperType)) << "Expect engineer helper menu to be active!"; InputCode key = EngineerHelper::getInputCodeForOption(EngineeredTeleporterEntrance, true); gameUI->onKeyDown(key); ASSERT_FALSE(static_cast<const EngineerHelper *>(gameUI->getActiveHelper())->isMenuBeingDisplayed()); gameUI->onKeyDown(KEY_MOD1); // Place entrance gameUI->onKeyDown(KEY_MOD1); // Place exit GamePair::idle(100, 5); // Let things mellow for(S32 i = 0; i < clientGames->size(); i++) { SCOPED_TRACE("i = " + itos(i)); Vector<DatabaseObject *> fillVector; clientGames->get(i)->getLevel()->findObjects(TeleporterTypeNumber, fillVector); EXPECT_EQ(1, fillVector.size()) << "Expected a teleporter!"; } }
// Scenario 2: Player enters idle command, other players, so server does not suspend itself. Since // player used idle command, a 5 second penalty will be levied against them. static void doScenario2(GamePair &gamePair) { ServerGame *serverGame = gamePair.server; string player1Name = "TestPlayer0"; ASSERT_EQ(1, gamePair.getClientCount()); // Should have had a client here when we arrived ASSERT_EQ(player1Name, gamePair.getClient(0)->getPlayerName()); // With this name string player2Name = "TestUser2"; gamePair.addClientAndSetTeam(player2Name.c_str(), 0); ClientGame *client1 = gamePair.getClient(0); ClientGame *client2 = gamePair.getClient(1); // Make sure the names are what we think they are... can't move on unless they are ASSERT_EQ(player1Name, client1->getPlayerName()); ASSERT_EQ(player2Name, client2->getPlayerName()); // Should now be 2 ships in the game -- one belonging to client1 and another belonging to client2 gamePair.idle(10, 5); // Idle 5x; give things time to propagate fillVector.clear(); serverGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(2, fillVector.size()); fillVector.clear(); client1->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(2, fillVector.size()); fillVector.clear(); client2->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(2, fillVector.size()); Vector<string> words; ChatCommands::idleHandler(client1, words); // Make client 1 go /idle gamePair.idle(Ship::KillDeleteDelay / 15, 30); // Give things time to propagate, timers to time out, etc. ASSERT_TRUE(serverGame->getClientInfo(0)->isSpawnDelayed()); ASSERT_TRUE(client1->isSpawnDelayed()); // Status should have propagated to client by now fillVector.clear(); serverGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(1, fillVector.size()); // Ship should have been killed off -- only 2nd player ship should be left fillVector.clear(); client1->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(0, fillVector.size()); // Suspended players don't see remote objects fillVector.clear(); client2->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); //ASSERT_EQ(1, fillVector.size()); // Player 2 should see self ASSERT_TRUE(client2->findClientInfo(client1->getPlayerName())->isSpawnDelayed()); // Check that other player knows our status // ReturnToGame penalty has been set, but won't start to count down until ship attempts to spawn ASSERT_FALSE(client1->inReturnToGameCountdown()); ASSERT_TRUE(static_cast<FullClientInfo *>(serverGame->getClientInfo(0))->hasReturnToGamePenalty()); // Penalty has been primed ASSERT_EQ(0, serverGame->getClientInfo(0)->getReturnToGameTime()); // Player presses a key to rejoin the game; there should be a SPAWN_UNDELAY_TIMER_DELAY ms penalty incurred for using /idle ASSERT_FALSE(serverGame->isSuspended()) << "Game is suspended -- subsequent tests will fail"; client1->undelaySpawn(); // Simulate effects of key press gamePair.idle(10, 10); // Idle; give things time to propagate ASSERT_TRUE(serverGame->getClientInfo(0)->getReturnToGameTime() > 0); // Timers should be set and counting down ASSERT_TRUE(client1->inReturnToGameCountdown()); // Check to ensure ship didn't spawn -- spawn should be delayed until penalty period has expired fillVector.clear(); serverGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(1, fillVector.size()); // (one ship for client2) // Client 1 won't see spawning ship while he is suspended fillVector.clear(); client1->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(0, fillVector.size()); // Client 2 should see that client 1 has been delayed ASSERT_TRUE(client2->findClientInfo(player1Name.c_str())->isSpawnDelayed()); // After some time has passed -- no longer in returnToGameCountdown period, ship should have appeared on server and client gamePair.idle(ClientInfo::SPAWN_UNDELAY_TIMER_DELAY / 100, 105); // More time than SPAWN_UNDELAY_TIMER_DELAY ASSERT_FALSE(client1->inReturnToGameCountdown()); fillVector.clear(); serverGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(2, fillVector.size()); fillVector.clear(); client1->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(2, fillVector.size()); gamePair.removeClient(1); }
// Scenario 3, 4 -- Player enters /idle command, no other players, so server suspends itself // In this case, no returnToGame penalty should be levied // In this scenario 3, player un-idles during the suspend game timer countdown (there is a 2 second delay after all players are idle) // In scenario 4, player enters full suspend mode before unidling static void doScenario34(GamePair &gamePair, bool letGameSlipIntoFullSuspendMode) { ClientGame *clientGame = gamePair.getClient(0); ServerGame *serverGame = gamePair.server; // Make sure we start off in a "normal" state ASSERT_FALSE(serverGame->isOrIsAboutToBeSuspended()); ASSERT_FALSE(clientGame->isSpawnDelayed()); gamePair.idle(Ship::KillDeleteDelay / 15, 20); // Idle; give things time to propagate fillVector.clear(); serverGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(1, fillVector.size()); // Now that player 2 has left, should only be one ship fillVector.clear(); clientGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(1, fillVector.size()); Vector<string> words; ChatCommands::idleHandler(clientGame, words); gamePair.idle(10, 10); // Idle; give things time to propagate, timers to time out, etc. ASSERT_TRUE(serverGame->getClientInfo(0)->isSpawnDelayed()); ASSERT_TRUE(serverGame->isOrIsAboutToBeSuspended()); EXPECT_FALSE(serverGame->isSuspended()); ASSERT_TRUE(clientGame->isSpawnDelayed()); // Status should have propagated to client by now EXPECT_FALSE(clientGame->isSuspended()); fillVector.clear(); serverGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(0, fillVector.size()); // No ships remaining in game -- don't check client as it may have exploding ship there fillVector.clear(); // ReturnToGame penalty has been set, but won't start to count down until ship attempts to spawn ASSERT_FALSE(clientGame->inReturnToGameCountdown()); ASSERT_TRUE(static_cast<FullClientInfo *>(serverGame->getClientInfo(0))->hasReturnToGamePenalty()); // Penalty has been primed ASSERT_EQ(0, serverGame->getClientInfo(0)->getReturnToGameTime()); if(letGameSlipIntoFullSuspendMode) gamePair.idle(ServerGame::PreSuspendSettlingPeriod / 20, 25); // Player presses a key to rejoin the game; since game was suspended, player can resume without penalty ASSERT_TRUE(serverGame->isOrIsAboutToBeSuspended()) << "Game should be suspended"; if(letGameSlipIntoFullSuspendMode) { // In here, game is suspended EXPECT_TRUE(serverGame->isSuspended()); EXPECT_TRUE(clientGame->isSuspended()); // Check if server clocks are still counting down... should be stopped S32 snow = serverGame->getGameType()->getRemainingGameTimeInMs(); S32 cnow = clientGame->getGameType()->getRemainingGameTimeInMs(); gamePair.idle(10, 10); S32 slater = serverGame->getGameType()->getRemainingGameTimeInMs(); S32 clater = clientGame->getGameType()->getRemainingGameTimeInMs(); EXPECT_EQ(snow, slater) << "Looks like server clock is still running (should be stopped)!"; EXPECT_EQ(cnow, clater) << "Looks like client clock is still running (should be stopped)!"; } else { // In here, game is not (yet) suspended, but is in the 2 second cooldown period that comes after // all players have left or are idle, but before full suspension EXPECT_FALSE(serverGame->isSuspended()); EXPECT_FALSE(clientGame->isSuspended()); // Check if clocks are still counting down... should be still running S32 snow = serverGame->getGameType()->getRemainingGameTimeInMs(); S32 cnow = clientGame->getGameType()->getRemainingGameTimeInMs(); gamePair.idle(10, 10); S32 slater = serverGame->getGameType()->getRemainingGameTimeInMs(); S32 clater = clientGame->getGameType()->getRemainingGameTimeInMs(); EXPECT_NE(snow, slater) << "Looks like server clock is stopped (should be running)!"; EXPECT_NE(cnow, clater) << "Looks like client clock is stopped (should be running)!"; } clientGame->undelaySpawn(); // Simulate effects of key press gamePair.idle(10, 5); // Idle; give things time to propagate ASSERT_FALSE(serverGame->isOrIsAboutToBeSuspended()); ASSERT_EQ(0, serverGame->getClientInfo(0)->getReturnToGameTime()); // No returnToGame penalty ASSERT_FALSE(clientGame->inReturnToGameCountdown()); gamePair.idle(Ship::KillDeleteDelay / 15, 20); // Idle; give dead ships time to be cleaned up // Check to ensure ship spawned fillVector.clear(); serverGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(1, fillVector.size()); fillVector.clear(); clientGame->getLevel()->findObjects(PlayerShipTypeNumber, fillVector); ASSERT_EQ(1, fillVector.size()); ASSERT_FALSE(serverGame->isOrIsAboutToBeSuspended()); ASSERT_FALSE(clientGame->isSpawnDelayed()); }