/* Multiplayer TicTacToe NUI Game Created By: Daz */ #include "inc_nui" #include "inc_util" const string TTT_WINDOW_ID = "TTT_GAME"; const string TTT_WINDOW_JSON = "TTT_WINDOW_JSON"; const string TTT_WINDOW_GEOMETRY = "TTT_WINDOW_GEOMETRY"; const float TTT_WINDOW_WIDTH = 400.0f; const float TTT_WINDOW_HEIGHT = 340.0f; const float TTT_LINE_LENGTH = 50.0f; const float TTT_LINE_THICKNESS = 10.0f; const string TTT_GRID_LINE_LEFT = "ttt_ll"; const string TTT_GRID_LINE_RIGHT = "ttt_lr"; const string TTT_GRID_LINE_TOP = "ttt_lt"; const string TTT_GRID_LINE_BOTTOM = "ttt_lb"; const string TTT_GRID_LINE_CENTER = "ttt_lc"; const string TTT_GRID_LINE_VERTICAL = "ttt_lmv"; const string TTT_GRID_LINE_HORIZONTAL = "ttt_lmh"; const string TTT_BIND_HEADER_TEXT = "header_text"; const string TTT_BIND_PORTRAIT_ONE = "po_player1"; const string TTT_BIND_PORTRAIT_TWO = "po_player2"; const string TTT_BIND_INFO_TEXT = "info_text"; const string TTT_BIND_BUTTON_RESTART = "btn_restart"; const string TTT_IMAGE_BLANK = "ttt_blank"; const string TTT_IMAGE_CIRCLE = "ttt_circle"; const string TTT_IMAGE_CROSS = "ttt_cross"; const string TTT_CELL_PREFIX = "ttt_cell_"; const int TTT_NUM_CELLS = 9; const string TTT_CELL_VALUE_BLANK = ""; const string TTT_CELL_VALUE_CIRCLE = "O"; const string TTT_CELL_VALUE_CROSS = "X"; const string TTT_BOARD = "TTT_BOARD"; const string TTT_PLAYER_ID = "TTT_PLAYER_ID"; const string TTT_PLAYER_ONE = "TTT_PLAYER_ONE"; const string TTT_PLAYER_TWO = "TTT_PLAYER_TWO"; const string TTT_CURRENT_PLAYER = "TTT_CURRENT_PLAYER"; const string TTT_WIN_CONDITIONS = "TTT_WIN_CONDITIONS"; const string TTT_GRID_STATE = "TTT_GRID_STATE"; const string TTT_GAME_STATE = "TTT_GAME_STATE"; const int TTT_GAME_STATE_NONE = 0; const int TTT_GAME_STATE_WAITING = 1; const int TTT_GAME_STATE_PLAYING = 2; const int TTT_GAME_STATE_GAME_OVER = 3; string TTT_IntToCellString(int nCell); json TTT_InsertGridLine(json jCol, string sImage, float fWidth, float fHeight); json TTT_InsertGridCell(json jCol, int nCell); json TTT_GetTicTacToeGridJson(); json TTT_GetWindowJson(); void TTT_SetRestartButtonEnabled(object oGame, int bEnabled); int TTT_GetPlayerWindowToken(object oPlayer); void TTT_SetGame(object oPlayer, object oGame); object TTT_GetGame(object oPlayer); void TTT_DeleteGame(object oPlayer); void TTT_SetPlayerId(object oPlayer, string sPlayerId); string TTT_GetPlayerId(object oPlayer); void TTT_DeletePlayerId(object oPlayer); void TTT_SetPlayer(object oGame, string sPlayerId, object oPlayer); object TTT_GetPlayer(object oGame, string sPlayerId); void TTT_DeletePlayer(object oGame, string sPlayerId); void TTT_SetCurrentPlayer(object oGame, object oPlayer); object TTT_GetCurrentPlayer(object oGame); string TTT_GetCurrentPlayerSymbol(object oGame); object TTT_GetOpponent(object oGame); object TTT_GetValidatedPlayer(object oGame, string sPlayerId); int TTT_GetIsPlayerValid(object oGame, string sPlayerId); int TTT_GetNumPlayers(object oGame); string TTT_GetFreePlayerId(object oGame); object TTT_GetSinglePlayer(object oGame); void TTT_UpdateBind(object oPlayer, string sBindName, json jValue); void TTT_UpdateBindsForPlayers(object oGame, string sBindName, json jValue); int TTT_CreateGameWindow(object oPlayer); void TTT_UpdateStaticBinds(object oGame); void TTT_UpdateGridCellBind(object oGame, int nCell, json jImage); string TTT_GetImageFromSymbol(string sSymbol); void TTT_UpdateGridBinds(object oGame); void TTT_UpdateInfoTextBind(object oGame, string sText); void TTT_AddPlayerToGame(object oPlayer, object oGame = OBJECT_SELF); void TTT_HandleNUIEvents(object oPlayer, int nToken, string sType, string sElement, int nArrayIndex, json jPayload); json TTT_InsertWinCondition(json jWinConditions, int nValueA, int nValueB, int nValueC); json TTT_GetWinConditions(); json TTT_GetGridState(object oGame); void TTT_SetGridState(object oGame, json jGridState); void TTT_ClearGridState(object oGame); string TTT_GetGridStateCell(object oGame, int nCell); void TTT_SetGridStateCell(object oGame, int nCell, string sValue); int TTT_GetGameState(object oGame); void TTT_SetGameState(object oGame, int nGameState, string sInfoText); void TTT_UpdateGameState(object oGame); int TTT_GetIsDraw(object oGame); int TTT_GetIsWin(object oGame); void TTT_RestartGame(object oGame); void TTT_RemovePlayerFromGame(object oGame, object oPlayer); void TTT_HandlePlayerExit(object oPlayer); string TTT_IntToCellString(int nCell) { return TTT_CELL_PREFIX + IntToString(nCell); } json TTT_InsertGridLine(json jCol, string sImage, float fWidth, float fHeight) { json jImage = NuiImage(JsonString(sImage), JsonInt(NUI_ASPECT_EXACT), JsonInt(NUI_HALIGN_CENTER), JsonInt(NUI_VALIGN_MIDDLE)); jImage = NuiMargin(jImage, 0.0f); jImage = NuiWidth(jImage, fWidth); jImage = NuiHeight(jImage, fHeight); return JsonArrayInsert(jCol, NuiMargin(NuiRow(JsonArrayInsert(JsonArray(), jImage)), 0.0f)); } json TTT_InsertGridCell(json jCol, int nCell) { string sCell = TTT_IntToCellString(nCell); json jImage = NuiImage(NuiBind(sCell), JsonInt(NUI_ASPECT_EXACT), JsonInt(NUI_HALIGN_CENTER), JsonInt(NUI_VALIGN_MIDDLE)); jImage = NuiId(jImage, sCell); jImage = NuiMargin(jImage, 0.0f); jImage = NuiWidth(jImage, TTT_LINE_LENGTH); jImage = NuiHeight(jImage, TTT_LINE_LENGTH); return JsonArrayInsert(jCol, NuiMargin(NuiRow(JsonArrayInsert(JsonArray(), jImage)), 0.0f)); } json TTT_GetTicTacToeGridJson() { json jCol = JsonArray(), jRow; jRow = JsonArray(); { json jSubCol, jSubRow; jSubCol = JsonArray(); jSubCol = TTT_InsertGridCell(jSubCol, 0); jSubCol = TTT_InsertGridLine(jSubCol, TTT_GRID_LINE_LEFT, TTT_LINE_LENGTH, TTT_LINE_THICKNESS); jSubCol = TTT_InsertGridCell(jSubCol, 3); jSubCol = TTT_InsertGridLine(jSubCol, TTT_GRID_LINE_LEFT, TTT_LINE_LENGTH, TTT_LINE_THICKNESS); jSubCol = TTT_InsertGridCell(jSubCol, 6); jRow = JsonArrayInsert(jRow, NuiMargin(NuiCol(jSubCol), 0.0f)); jSubCol = JsonArray(); jSubCol = TTT_InsertGridLine(jSubCol, TTT_GRID_LINE_TOP, TTT_LINE_THICKNESS, TTT_LINE_LENGTH); jSubCol = TTT_InsertGridLine(jSubCol, TTT_GRID_LINE_CENTER, TTT_LINE_THICKNESS, TTT_LINE_THICKNESS); jSubCol = TTT_InsertGridLine(jSubCol, TTT_GRID_LINE_VERTICAL, TTT_LINE_THICKNESS, TTT_LINE_LENGTH); jSubCol = TTT_InsertGridLine(jSubCol,TTT_GRID_LINE_CENTER, TTT_LINE_THICKNESS, TTT_LINE_THICKNESS); jSubCol = TTT_InsertGridLine(jSubCol, TTT_GRID_LINE_BOTTOM, TTT_LINE_THICKNESS, TTT_LINE_LENGTH); jRow = JsonArrayInsert(jRow, NuiMargin(NuiCol(jSubCol), 0.0f)); jSubCol = JsonArray(); jSubCol = TTT_InsertGridCell(jSubCol, 1); jSubCol = TTT_InsertGridLine(jSubCol, TTT_GRID_LINE_HORIZONTAL, TTT_LINE_LENGTH, TTT_LINE_THICKNESS); jSubCol = TTT_InsertGridCell(jSubCol, 4); jSubCol = TTT_InsertGridLine(jSubCol, TTT_GRID_LINE_HORIZONTAL, TTT_LINE_LENGTH, TTT_LINE_THICKNESS); jSubCol = TTT_InsertGridCell(jSubCol, 7); jRow = JsonArrayInsert(jRow, NuiMargin(NuiCol(jSubCol), 0.0f)); jSubCol = JsonArray(); jSubCol = TTT_InsertGridLine(jSubCol, TTT_GRID_LINE_TOP, TTT_LINE_THICKNESS, TTT_LINE_LENGTH); jSubCol = TTT_InsertGridLine(jSubCol, TTT_GRID_LINE_CENTER, TTT_LINE_THICKNESS, TTT_LINE_THICKNESS); jSubCol = TTT_InsertGridLine(jSubCol, TTT_GRID_LINE_VERTICAL, TTT_LINE_THICKNESS, TTT_LINE_LENGTH); jSubCol = TTT_InsertGridLine(jSubCol, TTT_GRID_LINE_CENTER, TTT_LINE_THICKNESS, TTT_LINE_THICKNESS); jSubCol = TTT_InsertGridLine(jSubCol, TTT_GRID_LINE_BOTTOM, TTT_LINE_THICKNESS, TTT_LINE_LENGTH); jRow = JsonArrayInsert(jRow, NuiMargin(NuiCol(jSubCol), 0.0f)); jSubCol = JsonArray(); jSubCol = TTT_InsertGridCell(jSubCol, 2); jSubCol = TTT_InsertGridLine(jSubCol, TTT_GRID_LINE_RIGHT, TTT_LINE_LENGTH, TTT_LINE_THICKNESS); jSubCol = TTT_InsertGridCell(jSubCol, 5); jSubCol = TTT_InsertGridLine(jSubCol, TTT_GRID_LINE_RIGHT, TTT_LINE_LENGTH, TTT_LINE_THICKNESS); jSubCol = TTT_InsertGridCell(jSubCol, 8); jRow = JsonArrayInsert(jRow, NuiMargin(NuiCol(jSubCol), 0.0f)); } jCol = NuiInsertRow(jCol, jRow); return NuiCol(jCol); } json TTT_GetWindowJson() { json jWindow = GetLocalJson(GetModule(), TTT_WINDOW_JSON); if (jWindow == JsonNull()) { json jCol; json jRow; jCol = JsonArray(); jRow = JsonArray(); { json jHeader = NuiHeader(NuiBind(TTT_BIND_HEADER_TEXT)); jRow = JsonArrayInsert(jRow, jHeader); } jCol = NuiInsertRow(jCol, jRow); jRow = JsonArray(); { jRow = JsonArrayInsert(jRow, NuiSpacer()); json jPlayer1 = NuiImage(NuiBind(TTT_BIND_PORTRAIT_ONE), JsonInt(NUI_ASPECT_EXACT), JsonInt(NUI_HALIGN_CENTER), JsonInt(NUI_VALIGN_TOP)); jPlayer1 = NuiMargin(jPlayer1, 0.0f); jPlayer1 = NuiGroup(jPlayer1, TRUE, NUI_SCROLLBARS_NONE); jPlayer1 = NuiWidth(jPlayer1, 64.0f); jPlayer1 = NuiHeight(jPlayer1, 100.0f); jRow = JsonArrayInsert(jRow, jPlayer1); jRow = JsonArrayInsert(jRow, NuiSpacer()); json jTicTacToe = TTT_GetTicTacToeGridJson(); jTicTacToe = NuiGroup(jTicTacToe, FALSE, NUI_SCROLLBARS_NONE); jTicTacToe = NuiWidth(jTicTacToe, 182.0f); jTicTacToe = NuiHeight(jTicTacToe, 182.0f); jRow = JsonArrayInsert(jRow, jTicTacToe); jRow = JsonArrayInsert(jRow, NuiSpacer()); json jPlayer2 = NuiImage(NuiBind(TTT_BIND_PORTRAIT_TWO), JsonInt(NUI_ASPECT_EXACT), JsonInt(NUI_HALIGN_CENTER), JsonInt(NUI_VALIGN_TOP)); jPlayer2 = NuiMargin(jPlayer2, 0.0f); jPlayer2 = NuiGroup(jPlayer2, TRUE, NUI_SCROLLBARS_NONE); jPlayer2 = NuiWidth(jPlayer2, 64.0f); jPlayer2 = NuiHeight(jPlayer2, 100.0f); jRow = JsonArrayInsert(jRow, jPlayer2); jRow = JsonArrayInsert(jRow, NuiSpacer()); } jCol = NuiInsertRow(jCol, jRow); jRow = JsonArray(); { json jHeader = NuiHeader(NuiBind(TTT_BIND_INFO_TEXT)); jRow = JsonArrayInsert(jRow, jHeader); } jCol = NuiInsertRow(jCol, jRow); jRow = JsonArray(); { jRow = JsonArrayInsert(jRow, NuiSpacer()); json jButton = NuiButton(JsonString("Restart")); jButton = NuiId(jButton, TTT_BIND_BUTTON_RESTART); jButton = NuiEnabled(jButton, NuiBind(TTT_BIND_BUTTON_RESTART)); jButton = NuiHeight(jButton, 30.0f); jRow = JsonArrayInsert(jRow, jButton); jRow = JsonArrayInsert(jRow, NuiSpacer()); } jCol = NuiInsertRow(jCol, jRow); jRow = JsonArray(); { jRow = JsonArrayInsert(jRow, NuiSpacer()); } jCol = NuiInsertRow(jCol, jRow); json jRoot = NuiCol(jCol); jWindow = NuiWindow(jRoot, JsonString("TicTacToe"), NuiBind(NUI_WINDOW_GEOMETRY_BIND), JsonBool(FALSE), JsonNull(), JsonBool(TRUE), JsonBool(FALSE), JsonBool(TRUE)); SetLocalJson(GetModule(), TTT_WINDOW_JSON, jWindow); } return jWindow; } void TTT_SetRestartButtonEnabled(object oGame, int bEnabled) { TTT_UpdateBindsForPlayers(oGame, TTT_BIND_BUTTON_RESTART, JsonBool(bEnabled)); } int TTT_GetPlayerWindowToken(object oPlayer) { return NuiFindWindow(oPlayer, TTT_WINDOW_ID); } void TTT_SetGame(object oPlayer, object oGame) { SetLocalObject(oPlayer, TTT_BOARD, oGame); } object TTT_GetGame(object oPlayer) { return GetLocalObject(oPlayer, TTT_BOARD); } void TTT_DeleteGame(object oPlayer) { DeleteLocalObject(oPlayer, TTT_BOARD); } void TTT_SetPlayerId(object oPlayer, string sPlayerId) { SetLocalString(oPlayer, TTT_PLAYER_ID, sPlayerId); } string TTT_GetPlayerId(object oPlayer) { return GetLocalString(oPlayer, TTT_PLAYER_ID); } void TTT_DeletePlayerId(object oPlayer) { DeleteLocalString(oPlayer, TTT_PLAYER_ID); } void TTT_SetPlayer(object oGame, string sPlayerId, object oPlayer) { SetLocalObject(oGame, sPlayerId, oPlayer); } object TTT_GetPlayer(object oGame, string sPlayerId) { return GetLocalObject(oGame, sPlayerId); } void TTT_DeletePlayer(object oGame, string sPlayerId) { DeleteLocalObject(oGame, sPlayerId); } void TTT_SetCurrentPlayer(object oGame, object oPlayer) { SetLocalObject(oGame, TTT_CURRENT_PLAYER, oPlayer); } object TTT_GetCurrentPlayer(object oGame) { return GetLocalObject(oGame, TTT_CURRENT_PLAYER); } string TTT_GetCurrentPlayerSymbol(object oGame) { return TTT_GetPlayerId(TTT_GetCurrentPlayer(oGame)) == TTT_PLAYER_ONE ? TTT_CELL_VALUE_CROSS : TTT_CELL_VALUE_CIRCLE; } object TTT_GetOpponent(object oGame) { return TTT_GetPlayerId(TTT_GetCurrentPlayer(oGame)) == TTT_PLAYER_ONE ? TTT_GetPlayer(oGame, TTT_PLAYER_TWO) : TTT_GetPlayer(oGame, TTT_PLAYER_ONE); } object TTT_GetValidatedPlayer(object oGame, string sPlayerId) { return TTT_GetIsPlayerValid(oGame, sPlayerId) ? TTT_GetPlayer(oGame, sPlayerId) : OBJECT_INVALID; } int TTT_GetIsPlayerValid(object oGame, string sPlayerId) { object oPlayer = TTT_GetPlayer(oGame, sPlayerId); return GetIsObjectValid(oPlayer) && TTT_GetPlayerWindowToken(oPlayer); } int TTT_GetNumPlayers(object oGame) { return TTT_GetIsPlayerValid(oGame, TTT_PLAYER_ONE) + TTT_GetIsPlayerValid(oGame, TTT_PLAYER_TWO); } string TTT_GetFreePlayerId(object oGame) { if (!TTT_GetIsPlayerValid(oGame, TTT_PLAYER_ONE)) return TTT_PLAYER_ONE; else if (!TTT_GetIsPlayerValid(oGame, TTT_PLAYER_TWO)) return TTT_PLAYER_TWO; else return "IF_THIS_HAPPENS_YOU_DID_SOMETHING_WRONG"; } object TTT_GetSinglePlayer(object oGame) { object oPlayer = TTT_GetValidatedPlayer(oGame, TTT_PLAYER_ONE); if (oPlayer != OBJECT_INVALID) return oPlayer; else { oPlayer = TTT_GetValidatedPlayer(oGame, TTT_PLAYER_TWO); if (oPlayer != OBJECT_INVALID) return oPlayer; } return OBJECT_INVALID; } void TTT_UpdateBind(object oPlayer, string sBindName, json jValue) { if (GetIsObjectValid(oPlayer)) { int nToken = TTT_GetPlayerWindowToken(oPlayer); if (nToken) NuiSetBind(oPlayer, nToken, sBindName, jValue); } } void TTT_UpdateBindsForPlayers(object oGame, string sBindName, json jValue) { TTT_UpdateBind(TTT_GetValidatedPlayer(oGame, TTT_PLAYER_ONE), sBindName, jValue); TTT_UpdateBind(TTT_GetValidatedPlayer(oGame, TTT_PLAYER_TWO), sBindName, jValue); } int TTT_CreateGameWindow(object oPlayer) { int nToken = NuiCreate(oPlayer, TTT_GetWindowJson(), TTT_WINDOW_ID); json jGeometry = GetLocalJson(oPlayer, TTT_WINDOW_GEOMETRY); if (jGeometry == JsonNull()) jGeometry = NuiRect(100.0f, 100.0f, TTT_WINDOW_WIDTH, TTT_WINDOW_HEIGHT); NuiSetBindWatch(oPlayer, nToken, NUI_WINDOW_GEOMETRY_BIND, TRUE); NuiSetBind(oPlayer, nToken, NUI_WINDOW_GEOMETRY_BIND, jGeometry); return nToken; } void TTT_UpdateStaticBinds(object oGame) { object oPlayerOne = TTT_GetValidatedPlayer(oGame, TTT_PLAYER_ONE); object oPlayerTwo = TTT_GetValidatedPlayer(oGame, TTT_PLAYER_TWO); string sNamePlayerOne = oPlayerOne == OBJECT_INVALID ? "???" : GetName(oPlayerOne); string sNamePlayerTwo = oPlayerTwo == OBJECT_INVALID ? "???" : GetName(oPlayerTwo); string sHeader = sNamePlayerOne + " vs. " + sNamePlayerTwo; TTT_UpdateBindsForPlayers(oGame, TTT_BIND_HEADER_TEXT, JsonString(sHeader)); string sPortraitPlayerOne = oPlayerOne == OBJECT_INVALID ? "po_hu_m_99_m" : GetPortraitResRef(oPlayerOne) + "m"; string sPortraitPlayerTwo = oPlayerTwo == OBJECT_INVALID ? "po_hu_m_99_m" : GetPortraitResRef(oPlayerTwo) + "m"; TTT_UpdateBindsForPlayers(oGame, TTT_BIND_PORTRAIT_ONE, JsonString(sPortraitPlayerOne)); TTT_UpdateBindsForPlayers(oGame, TTT_BIND_PORTRAIT_TWO, JsonString(sPortraitPlayerTwo)); } void TTT_UpdateGridCellBind(object oGame, int nCell, json jImage) { TTT_UpdateBindsForPlayers(oGame, TTT_IntToCellString(nCell), jImage); } string TTT_GetImageFromSymbol(string sSymbol) { return sSymbol == TTT_CELL_VALUE_BLANK ? TTT_IMAGE_BLANK : sSymbol == TTT_CELL_VALUE_CIRCLE ? TTT_IMAGE_CIRCLE : TTT_IMAGE_CROSS; } void TTT_UpdateGridBinds(object oGame) { json jGridState = TTT_GetGridState(oGame); int nCell, nNumCells = JsonGetLength(jGridState); for (nCell = 0; nCell < nNumCells; nCell++) { string sImage = TTT_GetImageFromSymbol(JsonGetString(JsonArrayGet(jGridState, nCell))); TTT_UpdateGridCellBind(oGame, nCell, JsonString(sImage)); } } void TTT_UpdateInfoTextBind(object oGame, string sText) { TTT_UpdateBindsForPlayers(oGame, TTT_BIND_INFO_TEXT, JsonString(sText)); } void TTT_AddPlayerToGame(object oPlayer, object oGame = OBJECT_SELF) { if (TTT_GetPlayerWindowToken(oPlayer)) { FloatingTextStringOnCreature("TicTacToe: Player Already In Game", oPlayer, FALSE); return; } int nNumPlayers = TTT_GetNumPlayers(oGame); if (nNumPlayers == 2) { FloatingTextStringOnCreature("TicTacToe: Max Number Of Players Reached", oPlayer, FALSE); return; } if (!nNumPlayers) { TTT_ClearGridState(oGame); TTT_SetGameState(oGame, TTT_GAME_STATE_NONE, ""); TTT_DeletePlayer(oGame, TTT_PLAYER_ONE); TTT_DeletePlayer(oGame, TTT_PLAYER_TWO); } string sPlayerId = TTT_GetFreePlayerId(oGame); TTT_SetPlayer(oGame, sPlayerId, oPlayer); TTT_SetPlayerId(oPlayer, sPlayerId); TTT_SetGame(oPlayer, oGame); TTT_CreateGameWindow(oPlayer); TTT_UpdateStaticBinds(oGame); TTT_UpdateGridBinds(oGame); TTT_UpdateGameState(oGame); } void TTT_HandleNUIEvents(object oPlayer, int nToken, string sType, string sElement, int nArrayIndex, json jPayload) { if (sType == NUI_EVENT_MOUSEUP) { if (GetStringLeft(sElement, GetStringLength(TTT_CELL_PREFIX)) == TTT_CELL_PREFIX) { object oGame = TTT_GetGame(oPlayer); object oCurrentPlayer = TTT_GetCurrentPlayer(oGame); int nCell = StringToInt(GetStringRight(sElement, 1)); int nGameState = TTT_GetGameState(oGame); if (nGameState != TTT_GAME_STATE_PLAYING || oCurrentPlayer != oPlayer || TTT_GetGridStateCell(oGame, nCell) != TTT_CELL_VALUE_BLANK) return; string sSymbol = TTT_GetCurrentPlayerSymbol(oGame); TTT_SetGridStateCell(oGame, nCell, sSymbol); TTT_UpdateGridCellBind(oGame, nCell, JsonString(TTT_GetImageFromSymbol(sSymbol))); if (TTT_GetIsWin(oGame)) TTT_SetGameState(oGame, TTT_GAME_STATE_GAME_OVER, GetName(oCurrentPlayer) + " won!"); else if (TTT_GetIsDraw(oGame)) TTT_SetGameState(oGame, TTT_GAME_STATE_GAME_OVER, "Draw!"); else { object oOpponent = TTT_GetOpponent(oGame); TTT_SetGameState(oGame, TTT_GAME_STATE_PLAYING, GetName(oOpponent) + "'s turn!"); TTT_SetCurrentPlayer(oGame, oOpponent); } } } else if (sType == NUI_EVENT_CLICK) { if (sElement == TTT_BIND_BUTTON_RESTART) { object oGame = TTT_GetGame(oPlayer); if (TTT_GetGameState(oGame) == TTT_GAME_STATE_GAME_OVER) TTT_RestartGame(oGame); } } else if (sType == NUI_EVENT_CLOSE) { if (sElement == NUI_WINDOW_ROOT_GROUP) { object oGame = TTT_GetGame(oPlayer); TTT_RemovePlayerFromGame(oGame, oPlayer); TTT_RestartGame(oGame); } } else if (sType == NUI_EVENT_WATCH) { if (sElement == NUI_WINDOW_GEOMETRY_BIND) { SetLocalJson(oPlayer, TTT_WINDOW_GEOMETRY, NuiGetBind(oPlayer, nToken, NUI_WINDOW_GEOMETRY_BIND)); } } } json TTT_InsertWinCondition(json jWinConditions, int nValueA, int nValueB, int nValueC) { json jWinCondition = JsonArray(); jWinCondition = JsonArrayInsert(jWinCondition, JsonInt(nValueA)); jWinCondition = JsonArrayInsert(jWinCondition, JsonInt(nValueB)); jWinCondition = JsonArrayInsert(jWinCondition, JsonInt(nValueC)); return JsonArrayInsert(jWinConditions, jWinCondition); } json TTT_GetWinConditions() { json jWinConditions = GetLocalJson(GetModule(), TTT_WIN_CONDITIONS); if (jWinConditions == JsonNull()) { jWinConditions = JsonArray(); jWinConditions = TTT_InsertWinCondition(jWinConditions, 0, 1, 2); jWinConditions = TTT_InsertWinCondition(jWinConditions, 3, 4, 5); jWinConditions = TTT_InsertWinCondition(jWinConditions, 6, 7, 8); jWinConditions = TTT_InsertWinCondition(jWinConditions, 0, 3, 6); jWinConditions = TTT_InsertWinCondition(jWinConditions, 1, 4, 7); jWinConditions = TTT_InsertWinCondition(jWinConditions, 2, 5, 8); jWinConditions = TTT_InsertWinCondition(jWinConditions, 0, 4, 8); jWinConditions = TTT_InsertWinCondition(jWinConditions, 2, 4, 6); SetLocalJson(GetModule(), TTT_WIN_CONDITIONS, jWinConditions); } return jWinConditions; } json TTT_GetGridState(object oGame) { return GetLocalJson(oGame, TTT_GRID_STATE); } void TTT_SetGridState(object oGame, json jGridState) { SetLocalJson(oGame, TTT_GRID_STATE, jGridState); } void TTT_ClearGridState(object oGame) { json jGridState = JsonArray(); int nCell; for (nCell = 0; nCell < TTT_NUM_CELLS; nCell++) { jGridState = JsonArrayInsert(jGridState, JsonString(TTT_CELL_VALUE_BLANK)); } TTT_SetGridState(oGame, jGridState); } string TTT_GetGridStateCell(object oGame, int nCell) { json jGridState = TTT_GetGridState(oGame); return JsonGetString(JsonArrayGet(jGridState, nCell)); } void TTT_SetGridStateCell(object oGame, int nCell, string sValue) { json jGridState = TTT_GetGridState(oGame); jGridState = JsonArraySet(jGridState, nCell, JsonString(sValue)); TTT_SetGridState(oGame, jGridState); } int TTT_GetGameState(object oGame) { return GetLocalInt(oGame, TTT_GAME_STATE); } void TTT_SetGameState(object oGame, int nGameState, string sInfoText) { SetLocalInt(oGame, TTT_GAME_STATE, nGameState); TTT_UpdateInfoTextBind(oGame, sInfoText); if (nGameState == TTT_GAME_STATE_GAME_OVER) TTT_SetRestartButtonEnabled(oGame, TRUE); else TTT_SetRestartButtonEnabled(oGame, FALSE); } void TTT_UpdateGameState(object oGame) { int nNumPlayers = TTT_GetNumPlayers(oGame); if (nNumPlayers == 1) { TTT_SetGameState(oGame, TTT_GAME_STATE_WAITING, "Waiting for opponent..."); TTT_SetCurrentPlayer(oGame, TTT_GetSinglePlayer(oGame)); } else if (nNumPlayers == 2) { TTT_SetGameState(oGame, TTT_GAME_STATE_PLAYING, GetName(TTT_GetCurrentPlayer(oGame)) + "'s turn!"); } } int TTT_GetIsDraw(object oGame) { json jGridState = TTT_GetGridState(oGame); int nCell, nNumCells = JsonGetLength(jGridState); for (nCell = 0; nCell < nNumCells; nCell++) { if (JsonGetString(JsonArrayGet(jGridState, nCell)) == TTT_CELL_VALUE_BLANK) return FALSE; } return TRUE; } int TTT_GetIsWin(object oGame) { json jGridState = TTT_GetGridState(oGame); json jWinConditions = TTT_GetWinConditions(); int nWinCondition, nNumWinConditions = JsonGetLength(jWinConditions); for(nWinCondition = 0; nWinCondition < nNumWinConditions; nWinCondition++) { json jWinCondition = JsonArrayGet(jWinConditions, nWinCondition); string sValueA = JsonGetString(JsonArrayGet(jGridState, JsonGetInt(JsonArrayGet(jWinCondition, 0)))); string sValueB = JsonGetString(JsonArrayGet(jGridState, JsonGetInt(JsonArrayGet(jWinCondition, 1)))); string sValueC = JsonGetString(JsonArrayGet(jGridState, JsonGetInt(JsonArrayGet(jWinCondition, 2)))); if (sValueA == TTT_CELL_VALUE_BLANK || sValueB == TTT_CELL_VALUE_BLANK ||sValueC == TTT_CELL_VALUE_BLANK) continue; if (sValueA == sValueB && sValueB == sValueC) return TRUE; } return FALSE; } void TTT_RestartGame(object oGame) { TTT_SetGameState(oGame, TTT_GAME_STATE_NONE, ""); TTT_ClearGridState(oGame); TTT_UpdateStaticBinds(oGame); TTT_UpdateGridBinds(oGame); TTT_UpdateGameState(oGame); } void TTT_RemovePlayerFromGame(object oGame, object oPlayer) { NuiDestroy(oPlayer, TTT_GetPlayerWindowToken(oPlayer)); TTT_DeletePlayer(oGame, TTT_GetPlayerId(oPlayer)); TTT_DeleteGame(oPlayer); TTT_DeletePlayerId(oPlayer); } void TTT_HandlePlayerExit(object oPlayer) { if (TTT_GetPlayerWindowToken(oPlayer)) { object oGame = TTT_GetGame(oPlayer); TTT_RemovePlayerFromGame(oGame, oPlayer); TTT_RestartGame(oGame); } }