static GAMECODE renderLoop() { if (bMultiPlayer && !NetPlay.isHostAlive && NetPlay.bComms && !NetPlay.isHost) { intAddInGamePopup(); } int clearMode = 0; if(getDrawShadows()) { clearMode |= CLEAR_SHADOW; } if (loopMissionState == LMS_SAVECONTINUE) { pie_SetFogStatus(false); clearMode = CLEAR_BLACK; } pie_ScreenFlip(clearMode);//gameloopflip HandleClosingWindows(); // Needs to be done outside the pause case. audio_Update(); wzShowMouse(true); INT_RETVAL intRetVal = INT_NONE; if (!paused) { /* Run the in game interface and see if it grabbed any mouse clicks */ if (!rotActive && getWidgetsStatus() && dragBox3D.status != DRAG_DRAGGING && wallDrag.status != DRAG_DRAGGING) { intRetVal = intRunWidgets(); } //don't process the object lists if paused or about to quit to the front end if (!gameUpdatePaused() && intRetVal != INT_QUIT) { if( dragBox3D.status != DRAG_DRAGGING && wallDrag.status != DRAG_DRAGGING && ( intRetVal == INT_INTERCEPT || ( radarOnScreen && CoordInRadar(mouseX(), mouseY()) && getHQExists(selectedPlayer) ) ) ) { // Using software cursors (when on) for these menus due to a bug in SDL's SDL_ShowCursor() wzSetCursor(CURSOR_DEFAULT); intRetVal = INT_INTERCEPT; } #ifdef DEBUG // check all flag positions for duplicate delivery points checkFactoryFlags(); #endif //handles callbacks for positioning of DP's process3DBuilding(); //ajl. get the incoming netgame messages and process them. // FIXME Previous comment is deprecated. multiPlayerLoop does some other weird stuff, but not that anymore. if (bMultiPlayer) { multiPlayerLoop(); } for (unsigned i = 0; i < MAX_PLAYERS; i++) { for (DROID *psCurr = apsDroidLists[i]; psCurr; psCurr = psCurr->psNext) { // Don't copy the next pointer - if droids somehow get destroyed in the graphics rendering loop, who cares if we crash. calcDroidIllumination(psCurr); } } /* update animations */ animObj_Update(); } if (!consolePaused()) { /* Process all the console messages */ updateConsoleMessages(); } if (!scrollPaused() && !getWarCamStatus() && dragBox3D.status != DRAG_DRAGGING && intMode != INT_INGAMEOP ) { scroll(); } } else // paused { // Using software cursors (when on) for these menus due to a bug in SDL's SDL_ShowCursor() wzSetCursor(CURSOR_DEFAULT); if(dragBox3D.status != DRAG_DRAGGING) { scroll(); } if(InGameOpUp || isInGamePopupUp) // ingame options menu up, run it! { unsigned widgval = widgRunScreen(psWScreen); intProcessInGameOptions(widgval); if(widgval == INTINGAMEOP_QUIT_CONFIRM || widgval == INTINGAMEOP_POPUP_QUIT) { if(gamePaused()) { kf_TogglePauseMode(); } intRetVal = INT_QUIT; } } if(bLoadSaveUp && runLoadSave(true) && strlen(sRequestResult)) { debug( LOG_NEVER, "Returned %s", sRequestResult ); if(bRequestLoad) { loopMissionState = LMS_LOADGAME; NET_InitPlayers(); // otherwise alliances were not cleared sstrcpy(saveGameName, sRequestResult); } else { char msgbuffer[256]= {'\0'}; if (saveInMissionRes()) { if (saveGame(sRequestResult, GTYPE_SAVE_START)) { sstrcpy(msgbuffer, _("GAME SAVED: ")); sstrcat(msgbuffer, sRequestResult); addConsoleMessage( msgbuffer, LEFT_JUSTIFY, NOTIFY_MESSAGE); } else { ASSERT( false,"Mission Results: saveGame Failed" ); sstrcpy(msgbuffer, _("Could not save game!")); addConsoleMessage( msgbuffer, LEFT_JUSTIFY, NOTIFY_MESSAGE); deleteSaveGame(sRequestResult); } } else if (bMultiPlayer || saveMidMission()) { if (saveGame(sRequestResult, GTYPE_SAVE_MIDMISSION))//mid mission from [esc] menu { sstrcpy(msgbuffer, _("GAME SAVED: ")); sstrcat(msgbuffer, sRequestResult); addConsoleMessage( msgbuffer, LEFT_JUSTIFY, NOTIFY_MESSAGE); } else { ASSERT(!"saveGame(sRequestResult, GTYPE_SAVE_MIDMISSION) failed", "Mid Mission: saveGame Failed" ); sstrcpy(msgbuffer, _("Could not save game!")); addConsoleMessage( msgbuffer, LEFT_JUSTIFY, NOTIFY_MESSAGE); deleteSaveGame(sRequestResult); } } else { ASSERT( false, "Attempt to save game with incorrect load/save mode" ); } } } } /* Check for quit */ bool quitting = false; if (intRetVal == INT_QUIT) { if (!loop_GetVideoStatus()) { //quitting from the game to the front end //so get a new backdrop quitting = true; pie_LoadBackDrop(SCREEN_RANDOMBDROP); } } if (!loop_GetVideoStatus() && !quitting) { if (!gameUpdatePaused()) { if (dragBox3D.status != DRAG_DRAGGING && wallDrag.status != DRAG_DRAGGING) { ProcessRadarInput(); } processInput(); //no key clicks or in Intelligence Screen if (intRetVal == INT_NONE && !InGameOpUp && !isInGamePopupUp) { processMouseClickInput(); } displayWorld(); } /* Display the in game interface */ pie_SetDepthBufferStatus(DEPTH_CMP_ALWAYS_WRT_ON); pie_SetFogStatus(false); if(bMultiPlayer && bDisplayMultiJoiningStatus) { intDisplayMultiJoiningStatus(bDisplayMultiJoiningStatus); setWidgetsStatus(false); } if(getWidgetsStatus()) { intDisplayWidgets(); } pie_SetDepthBufferStatus(DEPTH_CMP_LEQ_WRT_ON); pie_SetFogStatus(true); } pie_GetResetCounts(&loopPieCount, &loopPolyCount, &loopStateChanges); if ((fogStatus & FOG_BACKGROUND) && (loopMissionState == LMS_SAVECONTINUE)) { pie_SetFogStatus(false); } if (!quitting) { /* Check for toggling display mode */ if ((keyDown(KEY_LALT) || keyDown(KEY_RALT)) && keyPressed(KEY_RETURN)) { screenToggleMode(); } } // deal with the mission state switch (loopMissionState) { case LMS_CLEAROBJECTS: missionDestroyObjects(); setScriptPause(true); loopMissionState = LMS_SETUPMISSION; break; case LMS_NORMAL: // default break; case LMS_SETUPMISSION: setScriptPause(false); if (!setUpMission(nextMissionType)) { return GAMECODE_QUITGAME; } break; case LMS_SAVECONTINUE: // just wait for this to be changed when the new mission starts break; case LMS_NEWLEVEL: //nextMissionType = MISSION_NONE; nextMissionType = LDS_NONE; return GAMECODE_NEWLEVEL; break; case LMS_LOADGAME: return GAMECODE_LOADGAME; break; default: ASSERT( false, "unknown loopMissionState" ); break; } if (quitting) { pie_SetFogStatus(false); pie_ScreenFlip(CLEAR_BLACK);//gameloopflip /* Check for toggling display mode */ if ((keyDown(KEY_LALT) || keyDown(KEY_RALT)) && keyPressed(KEY_RETURN)) { screenToggleMode(); } return GAMECODE_QUITGAME; } else if (loop_GetVideoStatus()) { audio_StopAll(); return GAMECODE_PLAYVIDEO; } return GAMECODE_CONTINUE; }
// Add the droid order screen. // Returns true if the form was displayed ok. // //changed to a BASE_OBJECT to accomodate the factories - AB 21/04/99 bool intAddOrder(BASE_OBJECT *psObj) { bool Animate = true; SECONDARY_STATE State; UWORD OrdIndex; UWORD Height, NumDisplayedOrders; UWORD NumButs; UWORD NumJustifyButs, NumCombineButs, NumCombineBefore; bool bLastCombine, bHidden; DROID *Droid; STRUCTURE *psStructure; if (bInTutorial) { // No RMB orders in tutorial!! return (false); } // Is the form already up? if (widgGetFromID(psWScreen, IDORDER_FORM) != NULL) { intRemoveOrderNoAnim(); Animate = false; } // Is the stats window up? if (widgGetFromID(psWScreen, IDSTAT_FORM) != NULL) { intRemoveStatsNoAnim(); Animate = false; } if (psObj) { if (psObj->type == OBJ_DROID) { Droid = (DROID *)psObj; psStructure = NULL; } else if (psObj->type == OBJ_STRUCTURE) { Droid = NULL; psStructure = (STRUCTURE *)psObj; psSelectedFactory = psStructure; ASSERT_OR_RETURN(false, StructIsFactory(psSelectedFactory), "Trying to select a %s as a factory!", objInfo((BASE_OBJECT *)psSelectedFactory)); } else { ASSERT(false, "Invalid object type"); Droid = NULL; psStructure = NULL; } } else { Droid = NULL; psStructure = NULL; } setWidgetsStatus(true); AvailableOrders.clear(); SelectedDroids.clear(); // Selected droid is a command droid? if ((Droid != NULL) && (Droid->droidType == DROID_COMMAND)) { // displaying for a command droid - ignore any other droids SelectedDroids.push_back(Droid); } else if (psStructure != NULL) { AvailableOrders = buildStructureOrderList(psStructure); if (AvailableOrders.empty()) { return false; } } // Otherwise build a list of selected droids. else if (!BuildSelectedDroidList()) { // If no droids selected then see if we were given a specific droid. if (Droid != NULL) { // and put it in the list. SelectedDroids.push_back(Droid); } } // Build a list of orders available for the list of selected droids. - if a factory has not been selected if (psStructure == NULL) { AvailableOrders = buildDroidOrderList(); if (AvailableOrders.empty()) { // If no orders then return; return false; } } WIDGET *parent = psWScreen->psForm; /* Create the basic form */ IntFormAnimated *orderForm = new IntFormAnimated(parent, Animate); // Do not animate the opening, if the window was already open. orderForm->id = IDORDER_FORM; orderForm->setGeometry(ORDER_X, ORDER_Y, ORDER_WIDTH, ORDER_HEIGHT); // Add the close button. W_BUTINIT sButInit; sButInit.formID = IDORDER_FORM; sButInit.id = IDORDER_CLOSE; sButInit.x = ORDER_WIDTH - CLOSE_WIDTH; sButInit.y = 0; sButInit.width = CLOSE_WIDTH; sButInit.height = CLOSE_HEIGHT; sButInit.pTip = _("Close"); sButInit.pDisplay = intDisplayImageHilight; sButInit.UserData = PACKDWORD_TRI(0, IMAGE_CLOSEHILIGHT , IMAGE_CLOSE); if (!widgAddButton(psWScreen, &sButInit)) { return false; } sButInit = W_BUTINIT(); sButInit.formID = IDORDER_FORM; sButInit.id = IDORDER_CLOSE + 1; sButInit.pDisplay = intDisplayButtonHilight; sButInit.y = ORDER_BUTY; Height = 0; NumDisplayedOrders = 0; for (unsigned j = 0; j < AvailableOrders.size() && NumDisplayedOrders < MAX_DISPLAYABLE_ORDERS; ++j) { OrdIndex = AvailableOrders[j].OrderIndex; // Get current order state. State = GetSecondaryStates(OrderButtons[OrdIndex].Order); // Get number of buttons. NumButs = OrderButtons[OrdIndex].NumButs; // Set actual number of buttons. OrderButtons[OrdIndex].AcNumButs = NumButs; // Handle special case for factory -> command droid assignment buttons. switch (OrderButtons[OrdIndex].Class) { case ORDBUTCLASS_FACTORY: NumButs = countAssignableFactories((UBYTE)selectedPlayer, FACTORY_FLAG); break; case ORDBUTCLASS_CYBORGFACTORY: NumButs = countAssignableFactories((UBYTE)selectedPlayer, CYBORG_FLAG); break; case ORDBUTCLASS_VTOLFACTORY: NumButs = countAssignableFactories((UBYTE)selectedPlayer, VTOL_FLAG); break; default: break; } sButInit.id = OrderButtons[OrdIndex].ButBaseID; NumJustifyButs = NumButs; bLastCombine = false; switch (OrderButtons[OrdIndex].ButJustify & ORD_JUSTIFY_MASK) { case ORD_JUSTIFY_LEFT: sButInit.x = ORDER_BUTX; break; case ORD_JUSTIFY_RIGHT: sButInit.x = orderForm->width() - ORDER_BUTX - (NumJustifyButs * GetImageWidth(IntImages, OrderButtons[OrdIndex].ButImageID[0]) + (NumJustifyButs - 1) * ORDER_BUTGAP); break; case ORD_JUSTIFY_CENTER: sButInit.x = (orderForm->width() - (NumJustifyButs * GetImageWidth(IntImages, OrderButtons[OrdIndex].ButImageID[0]) + (NumJustifyButs - 1) * ORDER_BUTGAP)) / 2; break; case ORD_JUSTIFY_COMBINE: // see how many are on this line before the button NumCombineBefore = 0; for (unsigned i = 0; i < j; ++i) { if ((OrderButtons[AvailableOrders[i].OrderIndex].ButJustify & ORD_JUSTIFY_MASK) == ORD_JUSTIFY_COMBINE) { NumCombineBefore += 1; } } NumCombineButs = (UWORD)(NumCombineBefore + 1); // now see how many in total for (unsigned i = j + 1; i < AvailableOrders.size(); ++i) { if ((OrderButtons[AvailableOrders[i].OrderIndex].ButJustify & ORD_JUSTIFY_MASK) == ORD_JUSTIFY_COMBINE) { NumCombineButs += 1; } } // get position on line NumCombineButs = (UWORD)(NumCombineButs - (NumCombineBefore - (NumCombineBefore % ORD_MAX_COMBINE_BUTS))); if (NumCombineButs >= ORD_MAX_COMBINE_BUTS) { // the buttons will fill the line sButInit.x = (SWORD)(ORDER_BUTX + (GetImageWidth(IntImages, OrderButtons[OrdIndex].ButImageID[0]) + ORDER_BUTGAP) * NumCombineBefore); } else { // center the buttons sButInit.x = orderForm->width() / 2 - (NumCombineButs * GetImageWidth(IntImages, OrderButtons[OrdIndex].ButImageID[0]) + (NumCombineButs - 1) * ORDER_BUTGAP) / 2; sButInit.x = (SWORD)(sButInit.x + (GetImageWidth(IntImages, OrderButtons[OrdIndex].ButImageID[0]) + ORDER_BUTGAP) * NumCombineBefore); } // see if need to start a new line of buttons if ((NumCombineBefore + 1) == (NumCombineButs % ORD_MAX_COMBINE_BUTS)) { bLastCombine = true; } break; } for (unsigned i = 0; i < OrderButtons[OrdIndex].AcNumButs; ++i) { sButInit.pTip = getDORDDescription(OrderButtons[OrdIndex].ButTips[i]); sButInit.width = (UWORD)GetImageWidth(IntImages, OrderButtons[OrdIndex].ButImageID[i]); sButInit.height = (UWORD)GetImageHeight(IntImages, OrderButtons[OrdIndex].ButImageID[i]); sButInit.UserData = PACKDWORD_TRI(OrderButtons[OrdIndex].ButGreyID[i], OrderButtons[OrdIndex].ButHilightID[i], OrderButtons[OrdIndex].ButImageID[i]); if (!widgAddButton(psWScreen, &sButInit)) { return false; } // Set the default state for the button. switch (OrderButtons[OrdIndex].ButType) { case ORD_BTYPE_RADIO: case ORD_BTYPE_BOOLEAN: if ((State & OrderButtons[OrdIndex].StateMask) == (UDWORD)OrderButtons[OrdIndex].States[i]) { widgSetButtonState(psWScreen, sButInit.id, WBUT_CLICKLOCK); } else { widgSetButtonState(psWScreen, sButInit.id, 0); } break; case ORD_BTYPE_BOOLEAN_DEPEND: if ((State & OrderButtons[OrdIndex].StateMask) == (UDWORD)OrderButtons[OrdIndex].States[i]) { widgSetButtonState(psWScreen, sButInit.id, WBUT_CLICKLOCK); } else { if (i == 0) { widgSetButtonState(psWScreen, sButInit.id, 0); } else { widgSetButtonState(psWScreen, sButInit.id, WBUT_DISABLE); } } break; case ORD_BTYPE_BOOLEAN_COMBINE: if (State & (UDWORD)OrderButtons[OrdIndex].States[i]) { widgSetButtonState(psWScreen, sButInit.id, WBUT_CLICKLOCK); } break; } // may not add a button if the factory doesn't exist bHidden = false; switch (OrderButtons[OrdIndex].Class) { case ORDBUTCLASS_FACTORY: if (!checkFactoryExists(selectedPlayer, FACTORY_FLAG, i)) { widgHide(psWScreen, sButInit.id); bHidden = true; } break; case ORDBUTCLASS_CYBORGFACTORY: if (!checkFactoryExists(selectedPlayer, CYBORG_FLAG, i)) { widgHide(psWScreen, sButInit.id); bHidden = true; } break; case ORDBUTCLASS_VTOLFACTORY: if (!checkFactoryExists(selectedPlayer, VTOL_FLAG, i)) { widgHide(psWScreen, sButInit.id); bHidden = true; } break; default: break; } if (!bHidden) { sButInit.x = (SWORD)(sButInit.x + sButInit.width + ORDER_BUTGAP); } sButInit.id++; } if (((OrderButtons[OrdIndex].ButJustify & ORD_JUSTIFY_MASK) != ORD_JUSTIFY_COMBINE) || bLastCombine) { sButInit.y = (SWORD)(sButInit.y + sButInit.height + ORDER_BUTGAP); Height = (UWORD)(Height + sButInit.height + ORDER_BUTGAP); } NumDisplayedOrders ++; } // Now we know how many orders there are we can resize the form accordingly. int newHeight = Height + CLOSE_HEIGHT + ORDER_BUTGAP; orderForm->setGeometry(orderForm->x(), ORDER_BOTTOMY - newHeight, orderForm->width(), newHeight); OrderUp = true; return true; }
static bool _intAddInGameOptions(void) { audio_StopAll(); //clear out any mission widgets - timers etc that may be on the screen clearMissionWidgets(); setWidgetsStatus(true); //if already open, then close! if (widgGetFromID(psWScreen,INTINGAMEOP)) { intCloseInGameOptions(false, true); return true; } intResetScreen(false); // Pause the game. if(!gamePaused()) { kf_TogglePauseMode(); } W_FORMINIT sFormInit; sFormInit.width = INTINGAMEOP_W; // add form sFormInit.formID = 0; sFormInit.id = INTINGAMEOP; sFormInit.style = WFORM_PLAIN; sFormInit.x = (SWORD)INTINGAMEOP_X; sFormInit.y = (SWORD)INTINGAMEOP_Y; sFormInit.height = INTINGAMEOP_H; if ((!bMultiPlayer || (NetPlay.bComms == 0)) && !bInTutorial) { } else { sFormInit.height = INTINGAMEOP_HS; } sFormInit.pDisplay = intOpenPlainForm; sFormInit.disableChildren= true; widgAddForm(psWScreen, &sFormInit); // add 'quit' text if ((!bMultiPlayer || (NetPlay.bComms == 0)) && !bInTutorial) { addIGTextButton(INTINGAMEOP_QUIT, INTINGAMEOP_5_Y, INTINGAMEOP_OP_W, _("Quit"), OPALIGN); } else { addIGTextButton(INTINGAMEOP_QUIT, INTINGAMEOP_3_Y, INTINGAMEOP_OP_W, _("Quit"), OPALIGN); } // add 'resume' addIGTextButton(INTINGAMEOP_RESUME, INTINGAMEOP_1_Y, INTINGAMEOP_OP_W, _("Resume Game"), OPALIGN); // add 'options' addIGTextButton(INTINGAMEOP_OPTIONS, INTINGAMEOP_2_Y, INTINGAMEOP_OP_W, _("Audio Options"), OPALIGN); if ((!bMultiPlayer || (NetPlay.bComms == 0)) && !bInTutorial) { // add 'load' addIGTextButton(INTINGAMEOP_LOAD, INTINGAMEOP_3_Y, INTINGAMEOP_OP_W, _("Load Game"), OPALIGN); // add 'save' addIGTextButton(INTINGAMEOP_SAVE, INTINGAMEOP_4_Y, INTINGAMEOP_OP_W, _("Save Game"), OPALIGN); } intMode = INT_INGAMEOP; // change interface mode. InGameOpUp = true; // inform interface. wzSetCursor(CURSOR_DEFAULT); return true; }
// // Quick hack to throw up a ingame 'popup' for when the host drops connection. // void intAddInGamePopup(void) { //clear out any mission widgets - timers etc that may be on the screen clearMissionWidgets(); setWidgetsStatus(true); intResetScreen(false); if (isInGamePopupUp) return; audio_StopAll(); if(!gamePaused()) { kf_TogglePauseMode(); // Pause the game. } W_FORMINIT sFormInit; sFormInit.formID = 0; sFormInit.id = INTINGAMEPOPUP; sFormInit.style = WFORM_PLAIN; sFormInit.width = 600; sFormInit.height = 160; sFormInit.x = (SWORD)(20+D_W); sFormInit.y = (SWORD)((240-(160/2))+D_H); sFormInit.pDisplay = intOpenPlainForm; sFormInit.disableChildren= true; widgAddForm(psWScreen, &sFormInit); // add the text "buttons" now W_BUTINIT sButInit; sButInit.formID = INTINGAMEPOPUP; sButInit.style = OPALIGN; sButInit.width = 600; sButInit.FontID = font_large; sButInit.x = 0; sButInit.height = 10; sButInit.pDisplay = displayTextOption; sButInit.id = INTINGAMEOP_POPUP_MSG2; sButInit.y = 20; sButInit.pText = _("Host has quit the game!"); widgAddButton(psWScreen, &sButInit); sButInit.id = INTINGAMEOP_POPUP_MSG1; sButInit.y = 60; sButInit.pText = _("The game can't continue without the host."); widgAddButton(psWScreen, &sButInit); sButInit.id = INTINGAMEOP_POPUP_QUIT; sButInit.y = 124; sButInit.pText = _("--> QUIT <--"); widgAddButton(psWScreen, &sButInit); intMode = INT_POPUPMSG; // change interface mode. isInGamePopupUp = true; }
// //////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////// // MultiPlayer main game loop code. bool multiPlayerLoop(void) { UDWORD i; UBYTE joinCount; joinCount =0; for(i=0;i<MAX_PLAYERS;i++) { if(isHumanPlayer(i) && ingame.JoiningInProgress[i] ) { joinCount++; } } if(joinCount) { setWidgetsStatus(false); bDisplayMultiJoiningStatus = joinCount; // someone is still joining! say So // deselect anything selected. selDroidDeselect(selectedPlayer); if(keyPressed(KEY_ESC) )// check for cancel { bDisplayMultiJoiningStatus = 0; setWidgetsStatus(true); setPlayerHasLost(true); } } else //everyone is in the game now! { if(bDisplayMultiJoiningStatus) { bDisplayMultiJoiningStatus = 0; setWidgetsStatus(true); } if (!ingame.TimeEveryoneIsInGame) { ingame.TimeEveryoneIsInGame = gameTime; debug(LOG_NET, "I have entered the game @ %d", ingame.TimeEveryoneIsInGame ); if (!NetPlay.isHost) { debug(LOG_NET, "=== Sending hash to host ==="); sendDataCheck(); } } if (NetPlay.bComms) { sendPing(); } // Only have to do this on a true MP game if (NetPlay.isHost && !ingame.isAllPlayersDataOK && NetPlay.bComms) { if (gameTime - ingame.TimeEveryoneIsInGame > GAME_TICKS_PER_SEC * 60) { // we waited 60 secs to make sure people didn't bypass the data integrity checks int index; for (index=0; index < MAX_PLAYERS; index++) { if (ingame.DataIntegrity[index] == false && isHumanPlayer(index) && index != NET_HOST_ONLY) { char msg[256] = {'\0'}; sprintf(msg, _("Kicking player %s, because they tried to bypass data integrity check!"), getPlayerName(index)); sendTextMessage(msg, true); addConsoleMessage(msg, LEFT_JUSTIFY, NOTIFY_MESSAGE); NETlogEntry(msg, SYNC_FLAG, index); #ifndef DEBUG kickPlayer(index, "invalid data!", ERROR_INVALID); #endif debug(LOG_WARNING, "Kicking Player %s (%u), they tried to bypass data integrity check!", getPlayerName(index), index); } } ingame.isAllPlayersDataOK = true; } } } // if player has won then process the win effects... if(testPlayerHasWon()) { multiplayerWinSequence(false); } return true; }