void ArenasScreen::init() { Screen::init(); buildTrackList(); DynamicRibbonWidget* w = this->getWidget<DynamicRibbonWidget>("tracks"); // select something by default for the game master assert( w != NULL ); w->setSelection(w->getItems()[0].m_code_name, PLAYER_ID_GAME_MASTER, true); } // init
/** * Callback handling events from the kart selection menu */ void KartSelectionScreen::eventCallback(Widget* widget, const std::string& name, const int player_id) { // don't allow changing group after someone confirmed if (name == "kartgroups" && !m_game_master_confirmed) { RibbonWidget* tabs = getWidget<RibbonWidget>("kartgroups"); assert(tabs != NULL); DynamicRibbonWidget* w = getWidget<DynamicRibbonWidget>("karts"); assert(w != NULL); setKartsFromCurrentGroup(); const std::string &selected_kart_group = tabs->getSelectionIDString(PLAYER_ID_GAME_MASTER); UserConfigParams::m_last_used_kart_group = selected_kart_group; RandomGenerator random; const int num_players = m_kart_widgets.size(); for (int n=0; n<num_players; n++) { // The game master is the one that can change the groups, leave // his focus on the tabs for others, remove focus from kart that // might no more exist in this tab. if (n != PLAYER_ID_GAME_MASTER) GUIEngine::focusNothingForPlayer(n); if (!m_kart_widgets[n].isReady()) { // try to preserve the same kart for each player (except for // game master, since it's the one that can change the // groups, so focus for this player must remain on the tabs) const std::string& selected_kart = m_kart_widgets[n].getKartInternalName(); if (!w->setSelection( selected_kart, n, n != PLAYER_ID_GAME_MASTER)) { // if we get here, it means one player "lost" his kart in // the tab switch if (UserConfigParams::logGUI()) Log::info("KartSelectionScreen", "Player %u" " lost their selection when switching tabs!!!",n); // Select a random kart in this case const int count = (int) w->getItems().size(); if (count > 0) { // FIXME: two players may be given the same kart by // the use of random const int random_id = random.get( count ); // select kart for players > 0 (player 0 is the one // that can change the groups, so focus for player 0 // must remain on the tabs) const bool success = w->setSelection( random_id, n, n != PLAYER_ID_GAME_MASTER ); if (!success) Log::warn("KartSelectionScreen", "setting kart of player %u failed"); } else { Log::warn("KartSelectionScreen", " 0 items " "in the ribbon"); } } } } // end for } else if (name == "karts") { if (m_kart_widgets.size() > unsigned(player_id)) playerConfirm(player_id); } else if (name == "back") { StateManager::get()->escapePressed(); } else { // Transmit to all subwidgets, maybe *they* care about this event const int amount = m_kart_widgets.size(); for (int n=0; n<amount; n++) { m_kart_widgets[n].transmitEvent(widget, name, player_id); } // those events may mean that a player selection changed, so // validate again validateIdentChoices(); validateKartChoices(); } } // eventCallback
void KartSelectionScreen::playerConfirm(const int player_id) { DynamicRibbonWidget* w = getWidget<DynamicRibbonWidget>("karts"); assert(w != NULL); const std::string selection = w->getSelectionIDString(player_id); if (StringUtils::startsWith(selection, ID_LOCKED) && !m_multiplayer) { unlock_manager->playLockSound(); return; } if (player_id == PLAYER_ID_GAME_MASTER) { UserConfigParams::m_default_kart = selection; } if (m_kart_widgets[player_id].getKartInternalName().size() == 0 || m_kart_widgets[player_id].getKartInternalName() == RibbonWidget::NO_ITEM_ID) { SFXManager::get()->quickSound( "anvil" ); return; } const int amount = m_kart_widgets.size(); // Check if we have enough karts for everybody. If there are more players // than karts then just allow duplicates const int available_kart_count = (int) w->getItems().size(); const bool will_need_duplicates = (amount > available_kart_count); // make sure no other player selected the same identity or kart for (int n=0; n<amount; n++) { if (n == player_id) continue; // don't check a kart against itself const bool player_ready = m_kart_widgets[n].isReady(); const bool ident_conflict = !m_kart_widgets[n].getAssociatedPlayer()->getProfile() ->isGuestAccount() && m_kart_widgets[n].getAssociatedPlayer()->getProfile() == m_kart_widgets[player_id].getAssociatedPlayer()->getProfile(); const bool kart_conflict = sameKart(m_kart_widgets[n], m_kart_widgets[player_id]); if (player_ready && (ident_conflict || kart_conflict) && !will_need_duplicates) { if (UserConfigParams::logGUI()) Log::warn("KartSelectionScreen", "You can't select this identity " "or kart, someone already took it!!"); SFXManager::get()->quickSound( "anvil" ); return; } // If two PlayerKart entries are associated to the same ActivePlayer, // something went wrong assert(m_kart_widgets[n].getAssociatedPlayer() != m_kart_widgets[player_id].getAssociatedPlayer()); } // Mark this player as ready to start m_kart_widgets[player_id].markAsReady(); if (player_id == PLAYER_ID_GAME_MASTER) { m_game_master_confirmed = true; RibbonWidget* tabs = getWidget<RibbonWidget>("kartgroups"); assert( tabs != NULL ); tabs->setActive(false); } // validate choices to notify player of duplicates const bool names_ok = validateIdentChoices(); const bool karts_ok = validateKartChoices(); if (!names_ok || !karts_ok) return; // check if all players are ready bool allPlayersReady = true; for (int n=0; n<amount; n++) { if (!m_kart_widgets[n].isReady()) { allPlayersReady = false; break; } } if (allPlayersReady && (!m_multiplayer || amount > 1)) allPlayersDone(); } // playerConfirm
bool KartSelectionScreen::validateKartChoices() { bool ok = true; const unsigned int amount = m_kart_widgets.size(); // reset all marks, we'll re-add them next if errors are still there for (unsigned int n=0; n<amount; n++) { m_kart_widgets[n].m_model_view->unsetBadge(BAD_BADGE); } // Check if we have enough karts for everybody. If there are more // players than karts then just allow duplicates DynamicRibbonWidget* w = getWidget<DynamicRibbonWidget>("karts"); assert( w != NULL ); const unsigned int availableKartCount = (unsigned int)w->getItems().size(); if (amount > availableKartCount) return true; // Check everyone for duplicates for (unsigned int n=0; n<amount; n++) { for (unsigned int m=n+1; m<amount; m++) { // check if 2 players took the same name if (sameKart(m_kart_widgets[n], m_kart_widgets[m])) { if (UserConfigParams::logGUI()) { Log::warn("KartSelectionScreen", "Kart conflict!!"); Log::warn("KartSelectionScreen", " Player %u chose %s",n, m_kart_widgets[n].getKartInternalName().c_str()); Log::warn("KartSelectionScreen", " Player %u chose %s",m, m_kart_widgets[m].getKartInternalName().c_str()); } // two players took the same kart. check if one is ready if (!m_kart_widgets[n].isReady() && m_kart_widgets[m].isReady()) { if (UserConfigParams::logGUI()) Log::info("KartSelectionScreen", " --> Setting red badge on player %u", n); // player m is ready, so player n should not choose // this name m_kart_widgets[n].m_model_view->setBadge(BAD_BADGE); } else if (m_kart_widgets[n].isReady() && !m_kart_widgets[m].isReady()) { if (UserConfigParams::logGUI()) Log::info("KartSelectionScreen", " --> Setting red badge on player %u",m); // player n is ready, so player m should not // choose this name m_kart_widgets[m].m_model_view->setBadge(BAD_BADGE); } else if (m_kart_widgets[n].isReady() && m_kart_widgets[m].isReady()) { // it should be impossible for two players to confirm // they're ready with the same kart assert(false); } // we know it's not ok (but don't stop right now, all bad // ones need red badges) ok = false; } } // end for } return ok; } // validateKartChoices
void KartSelectionScreen::allPlayersDone() { input_manager->setMasterPlayerOnly(true); RibbonWidget* tabs = getWidget<RibbonWidget>("kartgroups"); assert(tabs != NULL); std::string selected_kart_group = tabs->getSelectionIDString(PLAYER_ID_GAME_MASTER); UserConfigParams::m_last_used_kart_group = selected_kart_group; DynamicRibbonWidget* w = getWidget<DynamicRibbonWidget>("karts"); assert( w != NULL ); const PtrVector< StateManager::ActivePlayer, HOLD >& players = StateManager::get()->getActivePlayers(); // ---- Print selection (for debugging purposes) if(UserConfigParams::logGUI()) { Log::info("KartSelectionScreen", "players : %d",players.size()); for (unsigned int n=0; n<players.size(); n++) { Log::info("KartSelectionScreen", " Player %u is %s on %s",n, core::stringc( players[n].getConstProfile()->getName().c_str()).c_str(), players[n].getDevice()->getName().c_str()); } } for (unsigned int n=0; n<players.size(); n++) { StateManager::get()->getActivePlayer(n)->getProfile() ->incrementUseFrequency(); } // ---- Give player info to race manager race_manager->setNumPlayers(players.size()); // ---- Manage 'random kart' selection(s) RandomGenerator random; std::vector<ItemDescription> items = w->getItems(); // remove the 'random' item itself const int item_count = (int) items.size(); for (int n=0; n<item_count; n++) { if (items[n].m_code_name == RANDOM_KART_ID) { items[n].m_code_name = ID_DONT_USE; break; } } // pick random karts const int kart_count = m_kart_widgets.size(); for (int n = 0; n < kart_count; n++) { std::string selected_kart = m_kart_widgets[n].m_kartInternalName; if (selected_kart == RANDOM_KART_ID) { // don't select an already selected kart int random_id; // to prevent infinite loop in case they are all locked int count = 0; bool done = false; do { random_id = random.get(item_count); // valid kart if it can bt used, and is either not locked, // or it's a multiplayer race. if (items[random_id].m_code_name != ID_DONT_USE && (!StringUtils::startsWith(items[random_id].m_code_name, ID_LOCKED) || m_multiplayer) ) { selected_kart = items[random_id].m_code_name; done = true; } items[random_id].m_code_name = ID_DONT_USE; count++; if (count > 100) return; } while (!done); } else { // mark the item as taken for (int i=0; i<item_count; i++) { if (items[i].m_code_name == m_kart_widgets[n].m_kartInternalName) { items[i].m_code_name = ID_DONT_USE; break; } } } race_manager->setPlayerKart(n, selected_kart); // Set per player difficulty if needed if (m_multiplayer && UserConfigParams::m_per_player_difficulty && m_kart_widgets[n].isHandicapped()) race_manager->setPlayerDifficulty(n, PLAYER_DIFFICULTY_HANDICAP); } // ---- Switch to assign mode input_manager->getDeviceManager()->setAssignMode(ASSIGN); StateManager::ActivePlayer *ap = m_multiplayer ? NULL : StateManager::get()->getActivePlayer(0); input_manager->getDeviceManager()->setSinglePlayer(ap); // ---- Go to next screen or return to overworld if (m_from_overworld || m_go_to_overworld_next) { m_from_overworld = false; // valid once m_go_to_overworld_next = false; OverWorld::enterOverWorld(); } else { RaceSetupScreen::getInstance()->push(); } } // allPlayersDone
void ArenasScreen::buildTrackList() { DynamicRibbonWidget* w = this->getWidget<DynamicRibbonWidget>("tracks"); assert( w != NULL ); // Re-build track list everytime (accounts for locking changes, etc.) w->clearItems(); RibbonWidget* tabs = this->getWidget<RibbonWidget>("trackgroups"); assert( tabs != NULL ); const std::string curr_group_name = tabs->getSelectionIDString(0); bool soccer_mode = race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER; if (curr_group_name == ALL_ARENA_GROUPS_ID) { const int trackAmount = track_manager->getNumberOfTracks(); for (int n=0; n<trackAmount; n++) { Track* curr = track_manager->getTrack(n); if (soccer_mode) { if(!curr->isSoccer()) continue; } else { if(!curr->isArena()) continue; } if (PlayerManager::get()->getCurrentPlayer()->isLocked(curr->getIdent())) { w->addItem( _("Locked : solve active challenges to gain access to more!"), "locked", curr->getScreenshotFile(), LOCKED_BADGE ); } else { w->addItem( curr->getName(), curr->getIdent(), curr->getScreenshotFile(), 0, IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE ); } } } else { const std::vector<int>& currArenas = track_manager->getArenasInGroup(curr_group_name, soccer_mode); const int trackAmount = currArenas.size(); for (int n=0; n<trackAmount; n++) { Track* curr = track_manager->getTrack(currArenas[n]); if (soccer_mode) { if(!curr->isSoccer()) continue; } else { if(!curr->isArena()) continue; } if (PlayerManager::get()->getCurrentPlayer()->isLocked(curr->getIdent())) { w->addItem( _("Locked : solve active challenges to gain access to more!"), "locked", curr->getScreenshotFile(), LOCKED_BADGE ); } else { w->addItem( curr->getName(), curr->getIdent(), curr->getScreenshotFile(), 0, IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE ); } } } w->addItem(_("Random Arena"), "random_track", "/gui/track_random.png"); w->updateItemDisplay(); assert(w->getItems().size() > 0); }