RATDOG/_module/nss/inc_tictactoe.nss
Jaysyn904 a005da6b51 Added Daz's persistent NUI storage
Added Daz's persistent NUI storage.  Added instanced player room at the Inn of the Flying Monkey.  Added PnP cockatrice & dire weasel.  Full compile.
2023-02-19 01:10:48 -05:00

661 lines
25 KiB
Plaintext

/*
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);
}
}