int PlayerSelection(int numPlayers, GraphicsDevice *graphics) { int i; int hasInputDevice[MAX_PLAYERS]; PlayerSelectMenu menus[MAX_PLAYERS]; for (i = 0; i < numPlayers; i++) { PlayerSelectMenusCreate( &menus[i], numPlayers, i, &gCampaign.Setting.characters.players[i], &gPlayerDatas[i], &gInputDevices, graphics, &gConfig.Input); hasInputDevice[i] = 0; } KeyInit(&gInputDevices.keyboard); for (;;) { int cmds[MAX_PLAYERS]; int isDone = 1; InputPoll(&gInputDevices, SDL_GetTicks()); if (KeyIsPressed(&gInputDevices.keyboard, SDLK_ESCAPE)) { // TODO: destroy menus return 0; // hack to allow exit } GetPlayerCmds(&cmds, gPlayerDatas); for (i = 0; i < numPlayers; i++) { if (hasInputDevice[i] && !MenuIsExit(&menus[i].ms)) { MenuProcessCmd(&menus[i].ms, cmds[i]); } } for (i = 0; i < numPlayers; i++) { if (!MenuIsExit(&menus[i].ms)) { isDone = 0; } } if (isDone) { break; } AssignPlayerInputDevices( hasInputDevice, numPlayers, gPlayerDatas, &gInputDevices, &gConfig.Input); GraphicsBlitBkg(graphics); for (i = 0; i < numPlayers; i++) { if (hasInputDevice[i]) { MenuDisplay(&menus[i].ms); } else { Vec2i center; const char *prompt = "Press Fire to join..."; Vec2i offset = Vec2iScaleDiv(TextGetSize(prompt), -2); int w = graphics->cachedConfig.ResolutionWidth; int h = graphics->cachedConfig.ResolutionHeight; switch (numPlayers) { case 1: // Center of screen center = Vec2iNew(w / 2, h / 2); break; case 2: // Side by side center = Vec2iNew(i * w / 2 + w / 4, h / 2); break; case 3: case 4: // Four corners center = Vec2iNew( (i & 1) * w / 2 + w / 4, (i / 2) * h / 2 + h / 4); break; default: assert(0 && "not implemented"); break; } DrawTextString(prompt, graphics, Vec2iAdd(center, offset)); } } BlitFlip(graphics, &gConfig.Graphics); SDL_Delay(10); } for (i = 0; i < numPlayers; i++) { MenuSystemTerminate(&menus[i].ms); } return 1; }
static GameLoopResult PlayerSelectionUpdate(void *data) { PlayerSelectionData *pData = data; // Check if anyone pressed escape int cmds[MAX_LOCAL_PLAYERS]; memset(cmds, 0, sizeof cmds); GetPlayerCmds(&gEventHandlers, &cmds); if (EventIsEscape(&gEventHandlers, cmds, GetMenuCmd(&gEventHandlers))) { pData->IsOK = false; return UPDATE_RESULT_EXIT; } // Menu input int idx = 0; for (int i = 0; i < (int)gPlayerDatas.size; i++, idx++) { const PlayerData *p = CArrayGet(&gPlayerDatas, i); if (!p->IsLocal) { idx--; continue; } if (p->inputDevice != INPUT_DEVICE_UNSET && !MenuIsExit(&pData->menus[idx].ms) && cmds[idx]) { MenuProcessCmd(&pData->menus[idx].ms, cmds[idx]); } } // Conditions for exit: at least one player has selected "Done", // and no other players, if any, are still selecting their player // The "players" with no input device are turned into AIs bool hasAtLeastOneInput = false; bool isDone = true; idx = 0; for (int i = 0; i < (int)gPlayerDatas.size; i++, idx++) { const PlayerData *p = CArrayGet(&gPlayerDatas, i); if (!p->IsLocal) { idx--; continue; } if (p->inputDevice != INPUT_DEVICE_UNSET) { hasAtLeastOneInput = true; if (strcmp(pData->menus[idx].ms.current->name, "Done") != 0) { isDone = false; } } } if (isDone && hasAtLeastOneInput) { return UPDATE_RESULT_EXIT; } AssignPlayerInputDevices(&gEventHandlers); return UPDATE_RESULT_DRAW; }