From fb181bd148149168f5b6883831ce7a5d23477a72 Mon Sep 17 00:00:00 2001 From: Steven Howard Date: Tue, 11 Sep 2018 11:27:54 +0100 Subject: [PATCH] adding pool minigame (modular) --- .../irresistible/cnr/features/_features.pwn | 2 + gamemodes/irresistible/cnr/features/pool.pwn | 1165 +++++++++++++++++ 2 files changed, 1167 insertions(+) create mode 100644 gamemodes/irresistible/cnr/features/pool.pwn diff --git a/gamemodes/irresistible/cnr/features/_features.pwn b/gamemodes/irresistible/cnr/features/_features.pwn index 69b05e4..81a9428 100644 --- a/gamemodes/irresistible/cnr/features/_features.pwn +++ b/gamemodes/irresistible/cnr/features/_features.pwn @@ -35,3 +35,5 @@ // disabled // #include "irresistible\cnr\features\eastereggs.pwn" +// pool +#include "irresistible\cnr\features\pool.pwn" diff --git a/gamemodes/irresistible/cnr/features/pool.pwn b/gamemodes/irresistible/cnr/features/pool.pwn new file mode 100644 index 0000000..837d0cc --- /dev/null +++ b/gamemodes/irresistible/cnr/features/pool.pwn @@ -0,0 +1,1165 @@ +/* + * Irresistible Gaming (c) 2018 + * Developed by Steven Howard + * Module: cnr/features/minigames/pool.pwn + * Purpose: pool minigame + */ + +/* ** Includes ** */ +#include < YSI\y_hooks > +#include < physics > +#include < colandreas > +#include < progress2 > + +/* ** Marcos ** */ +#define IsPlayerPlayingPool(%0) (p_isPlayingPool{%0}) + +/* ** Definitions ** */ +#define POCKET_RADIUS 0.09 +#define POOL_TIMER_SPEED 30 +#define DEFAULT_AIM 0.38 +#define DEFAULT_POOL_STRING "{FFDC2E}Pool Table\n{FFFFFF}To begin pool use /pool" + +#define MAX_TABLES 100 +#define COL_POOL "{C0C0C0}" + +/* ** Variables ** */ + +enum E_POOL_BALL_DATA +{ + E_BALL_OBJECT[ 16 ], bool: E_EXISTS[ 16 ], bool: E_MOVING[ 16 ] +}; + +enum E_POOL_TABLE_DATA +{ + Float: E_X, Float: E_Y, Float: E_Z, + Float: E_ANGLE, E_WORLD, E_INTERIOR, + + E_TIMER, E_COUNTDOWN, E_PLAYER[ 2 ], + bool: E_STARTED, E_AIMER, E_AIMER_OBJECT, + E_LAST_SHOOTER, E_LAST_SCORE, Float: E_POWER, + E_DIRECTION, + + E_TABLE, Text3D: E_LABEL, +} + +new + g_poolTableData [ MAX_TABLES ][ E_POOL_TABLE_DATA ], + g_poolBallData [ MAX_TABLES ][ E_POOL_BALL_DATA ], + + p_PoolReciever [ MAX_PLAYERS ], + p_PoolSender [ MAX_PLAYERS ], + p_PoolID [ MAX_PLAYERS ], + + bool: p_isPlayingPool [ MAX_PLAYERS char], + bool: p_PoolChalk [ MAX_PLAYERS ], + p_PoolCamera [ MAX_PLAYERS ], + p_PoolScore [ MAX_PLAYERS ], + Float: p_PoolAngle [ MAX_PLAYERS ][ 2 ], + + PlayerBar: g_PoolPowerBar [ MAX_PLAYERS ], + PlayerText: g_PoolTextdraw [ MAX_PLAYERS ], + + Iterator:pooltables +; + +/* ** Hooks ** */ + +hook OnGameModeInit() +{ + //stock CreatePoolTable(Float: X, Float: Y, Float: Z, Float: A = 0.0, interior = 0, world = 0) + + CreatePoolTable(2048.5801, 1330.8917, 10.6719, 0, 0); + + + printf( "[POOL TABLES]: %d pool tables have been successfully loaded.", Iter_Count(pooltables) ); + return 1; +} + +hook OnPlayerDisconnect(playerid, reason) +{ + if (IsPlayerPlayingPool(playerid)) + { + gameEnd( p_PoolID[ playerid ] ); + + p_PoolSender[ playerid ] = INVALID_PLAYER_ID; + p_PoolReciever[ playerid ] = INVALID_PLAYER_ID; + p_isPlayingPool{ playerid } = false; + p_PoolID[ playerid ] = -1; + + p_PoolScore[ playerid ] = 0; + } + + return 1; +} + +hook OnPlayerConnect(playerid) +{ + g_PoolPowerBar[playerid] = CreatePlayerProgressBar(playerid, 530.000000, 233.000000, 61.000000, 6.199999, -1429936641, 100.0000, 0); + + g_PoolTextdraw[playerid] = CreatePlayerTextDraw(playerid, 529.000000, 218.000000, "Power~n~~n~Score: 0"); + PlayerTextDrawBackgroundColor(playerid, g_PoolTextdraw[playerid], 255); + PlayerTextDrawFont(playerid, g_PoolTextdraw[playerid], 1); + PlayerTextDrawLetterSize(playerid, g_PoolTextdraw[playerid], 0.300000, 1.299998); + PlayerTextDrawColor(playerid, g_PoolTextdraw[playerid], -1); + PlayerTextDrawSetOutline(playerid, g_PoolTextdraw[playerid], 1); + PlayerTextDrawSetProportional(playerid, g_PoolTextdraw[playerid], 1); + PlayerTextDrawSetSelectable(playerid, g_PoolTextdraw[playerid], 0); + + return 1; +} + +hook OnPlayerSpawn(playerid) +{ + p_PoolSender[ playerid ] = INVALID_PLAYER_ID; + p_PoolReciever[ playerid ] = INVALID_PLAYER_ID; + p_isPlayingPool{ playerid } = false; + p_PoolID[ playerid ] = -1; + p_PoolScore[ playerid ] = 0; + return 1; +} + +hook OnPlayerKeyStateChange(playerid, newkeys, oldkeys) +{ + new id = -1; + + if ((id = getNearestPoolTable(playerid)) != -1) + { + if (g_poolTableData[ id ][ E_STARTED ] && IsPlayerPlayingPool( playerid ) && p_PoolID[ playerid ] == id) + { + if (PRESSED(KEY_FIRE)) + { + ClearAnimations(playerid); + return 0; + } + else + { + // Not the players turn detection (player 1 and/or player 2) + if (IsKeyJustUp(KEY_SECONDARY_ATTACK, newkeys, oldkeys)) + { + if (IsPlayerPlayingPool( playerid ) && g_poolTableData[ id ][ E_AIMER ] != playerid && !p_PoolChalk[ playerid ]) + { + SetTimerEx("PlayPoolSound", 1400, false, "dd", id, 31807); + SetPlayerArmedWeapon(playerid, 0); + SetPlayerAttachedObject(playerid, 0, 338, 6, 0, 0.07, -0.85, 0, 0, 0); + ApplyAnimation(playerid, "POOL", "POOL_ChalkCue", 3.0, 0, 0, 0, 0, 0, 1); + + p_PoolChalk[ playerid ] = true; + + SetTimerEx("RestoreWeapon", 3500, false, "d", playerid); + } + } + + if (IsKeyJustUp(KEY_JUMP, newkeys, oldkeys)) + { + if (g_poolTableData[ id ][ E_AIMER ] == playerid) + { + if (p_PoolCamera[ playerid ] < 2) p_PoolCamera[ playerid ] ++; + else p_PoolCamera[ playerid ] = 0; + + new Float:poolrot = p_PoolAngle[ playerid ] [ 0 ], + Float:Xa, + Float:Ya, + Float:Za, + Float:x, + Float:y; + + GetObjectPos(g_poolBallData[ id ][ E_BALL_OBJECT ][ 0 ], Xa, Ya, Za); + + switch (p_PoolCamera[ playerid ]) + { + case 0: + { + GetXYBehindObjectInAngle(g_poolBallData[ id ][ E_BALL_OBJECT ][ 0 ], poolrot, x, y, 0.675); + SetPlayerCameraPos(playerid, x, y, g_poolTableData[ id ][ E_Z ] + DEFAULT_AIM); + SetPlayerCameraLookAt(playerid, Xa, Ya, Za + 0.170); + } + case 1..2: + { + SetPlayerCameraPos(playerid, g_poolTableData[ id ][ E_X ], g_poolTableData[ id ][ E_Y ], g_poolTableData[ id ][ E_Z ] + 2.0); + SetPlayerCameraLookAt(playerid, g_poolTableData[ id ][ E_X ], g_poolTableData[ id ][ E_Y ], g_poolTableData[ id ][ E_Z ]); + } + } + } + } + + if (IsKeyJustUp(KEY_HANDBRAKE, newkeys, oldkeys)) + { + if (AreAllBallsStopped(id)) + { + if (g_poolTableData[ id ][ E_AIMER ] != playerid) + { + if (!p_PoolChalk[ playerid ] && g_poolTableData[ id ][ E_AIMER ] == -1) + { + new Float:poolrot, + Float:X, Float:Y, Float:Z, + Float:Xa, Float:Ya, Float:Za, + Float:x, Float:y; + + GetPlayerPos(playerid, X, Y, Z); + GetObjectPos(g_poolBallData[id][E_BALL_OBJECT][0], Xa, Ya, Za); + + if (Is2DPointInRangeOfPoint(X, Y, Xa, Ya, 1.5) && Z < 999.5) + { + TogglePlayerControllable(playerid, false); + GetAngleToXY(Xa, Ya, X, Y, poolrot); + SetPlayerFacingAngle(playerid, poolrot); + + p_PoolAngle[ playerid ] [ 0 ] = poolrot; + p_PoolAngle[ playerid ] [ 1 ] = poolrot; + + SetPlayerArmedWeapon(playerid, 0); + GetXYInFrontOfPos(Xa, Ya, poolrot + 180, x, y, 0.085); + g_poolTableData[ id ][ E_AIMER_OBJECT ] = CreateObject(3004, x, y, Za, 7.0, 0, poolrot + 180); + + SetPlayerCameraPos(playerid, g_poolTableData[ id ][ E_X ], g_poolTableData[ id ][ E_Y ], g_poolTableData[ id ][ E_Z ] + 2.0); + + ApplyAnimation(playerid, "POOL", "POOL_Med_Start", 50.0, 0, 0, 0, 1, 1, 1); + + g_poolTableData[ id ][ E_AIMER ] = playerid; + g_poolTableData[ id ][ E_POWER ] = 1.0; + g_poolTableData[ id ][ E_DIRECTION ] = 0; + + PlayerTextDrawSetString(playerid, g_PoolTextdraw[playerid], sprintf("Power:~n~~n~Score: %d", p_PoolScore[ playerid ]) ); + PlayerTextDrawShow(playerid, g_PoolTextdraw[playerid]); + ShowPlayerProgressBar(playerid, g_PoolPowerBar[playerid]); + } + } + } + else + { + TogglePlayerControllable(playerid, true); + GivePlayerWeapon(playerid, 7, 1); + + ApplyAnimation(playerid, "CARRY", "crry_prtial", 1.0, 0, 0, 0, 0, 0, 1); + SetCameraBehindPlayer(playerid); + + g_poolTableData[ id ][ E_AIMER ] = -1; + DestroyObject(g_poolTableData[ id ][ E_AIMER_OBJECT ]); + + //TextDrawHideForPlayer(playerid, gPoolTD); + //HidePlayerProgressBar(playerid, g_PoolPowerBar[playerid]); + } + } + } + + if (IsKeyJustUp(KEY_FIRE, newkeys, oldkeys)) + { + if (g_poolTableData[ id ][ E_AIMER ] == playerid) + { + new Float: speed; + + ApplyAnimation(playerid, "POOL", "POOL_Med_Shot", 3.0, 0, 0, 0, 0, 0, 1); + + speed = 0.4 + (g_poolTableData[ id ][ E_POWER ] * 2.0) / 100.0; + PHY_SetObjectVelocity(g_poolBallData[id][E_BALL_OBJECT][0], speed * floatsin(-p_PoolAngle[ playerid ] [ 0 ], degrees), speed * floatcos(-p_PoolAngle[ playerid ] [ 0 ], degrees)); + + SetPlayerCameraPos(playerid, g_poolTableData[ id ][ E_X ], g_poolTableData[ id ][ E_Y ], g_poolTableData[ id ][ E_Z ] + 2.0); + SetPlayerCameraLookAt(playerid, g_poolTableData[ id ][ E_X ], g_poolTableData[ id ][ E_Y ], g_poolTableData[ id ][ E_Z ]); + + PlayPoolSound(id, 31810); + g_poolTableData[ id ][ E_AIMER ] = -1; + DestroyObject(g_poolTableData[ id ][ E_AIMER_OBJECT ]); + + GivePlayerWeapon(playerid, 7, 1); + + g_poolTableData[ id ][ E_LAST_SHOOTER ] = playerid; + g_poolTableData[ id ][ E_LAST_SCORE ] = 0; + } + else ClearAnimations(playerid); + } + } + } + } + + return 1; +} + +/* ** Functions ** */ + +stock getNearestPoolTable(playerid) +{ + for (new i = 0; i != MAX_TABLES; i ++) if ( IsPlayerInRangeOfPoint( playerid, 2.5, g_poolTableData[ i][ E_X ], g_poolTableData[ i][ E_Y ], g_poolTableData[ i][ E_Z ]) ) { + return i; + } + + return -1; +} + +stock GetPlayerFrontPos(playerid, &Float:x, &Float:y, &Float:z, Float:distance = 0.0) +{ + new Float: px, + Float: py, + Float: pz, + Float: pa; + + GetPlayerPos(playerid, px, py, pz); + GetPlayerFacingAngle(playerid, pa); + + x = px + (floatsin(-pa, degrees) * distance); + y = py + (floatcos(-pa, degrees) * distance); + + z = pz; +} + +stock CreatePoolTable(Float: X, Float: Y, Float: Z, Float: A = 0.0, interior = 0, world = 0) +{ + new + gID = Iter_Free(pooltables), Float: x_vertex[4], Float: y_vertex[4]; + + if ( gID != ITER_NONE ) + { + Iter_Add(pooltables, gID); + + g_poolTableData[ gID ][ E_X ] = X; + g_poolTableData[ gID ][ E_Y ] = Y; + g_poolTableData[ gID ][ E_Z ] = Z; + g_poolTableData[ gID ][ E_ANGLE ] = A; + + g_poolTableData[ gID ][ E_INTERIOR ] = interior; + g_poolTableData[ gID ][ E_WORLD ] = world; + + g_poolTableData[ gID][ E_TABLE ] = CreateDynamicObject( 2964, X, Y, Z - 1.0, 0.0, 0.0, 0.0, world, interior); + g_poolTableData[ gID][ E_LABEL ] = CreateDynamic3DTextLabel( DEFAULT_POOL_STRING, COLOR_GOLD, X, Y, (Z - 0.5), 10.0, INVALID_PLAYER_ID, INVALID_VEHICLE_ID, 0, world, interior); + + RotateXY( -0.96, -0.515, 0.0, x_vertex[0], y_vertex[0] ); + RotateXY( -0.96, 0.515, 0.0, x_vertex[1], y_vertex[1] ); + RotateXY( 0.96, -0.515, 0.0, x_vertex[2], y_vertex[2] ); + RotateXY( 0.96, 0.515, 0.0, x_vertex[3], y_vertex[3] ); + + PHY_CreateWall( x_vertex[0] + X, y_vertex[0] + Y, x_vertex[1] + X, y_vertex[1] + Y); + PHY_CreateWall( x_vertex[1] + X, y_vertex[1] + Y, x_vertex[3] + X, y_vertex[3] + Y); + PHY_CreateWall( x_vertex[2] + X, y_vertex[2] + Y, x_vertex[3] + X, y_vertex[3] + Y); + PHY_CreateWall( x_vertex[0] + X, y_vertex[0] + Y, x_vertex[2] + X, y_vertex[2] + Y); + } + + return gID; +} + +stock RespawnPoolBalls(poolid, mode = 0) +{ + for (new i = 0; i < 16; i ++) + { + DestroyObject(g_poolBallData[poolid][E_BALL_OBJECT][i]); + + if (g_poolBallData[i][E_EXISTS][i]) + { + PHY_DeleteObject(g_poolBallData[poolid][E_BALL_OBJECT][i]); + g_poolBallData[poolid][E_EXISTS][i] = false; + } + } + + if (g_poolTableData[ poolid][ E_AIMER ] != -1) + { + TogglePlayerControllable(g_poolTableData[ poolid][ E_AIMER ], 1); + //ClearAnimations(g_poolTableData[ poolid][ E_AIMER ]); + + //ApplyAnimation(g_poolTableData[ poolid][ E_AIMER ], "CARRY", "crry_prtial", 1.0, 0, 0, 0, 0, 0); + SetCameraBehindPlayer(g_poolTableData[ poolid][ E_AIMER ]); + DestroyObject(g_poolTableData[ poolid][ E_AIMER_OBJECT ]); + + //TextDrawHideForPlayer(g_poolTableData[ poolid][ E_AIMER ], gPoolTD); + //HidePlayerProgressBar(g_poolTableData[ poolid][ E_AIMER ], g_PoolPowerBar[g_poolTableData[ poolid][ E_AIMER ]]); + g_poolTableData[ poolid][ E_AIMER ] = -1; + } + + CreateBalls(poolid); + + if (mode) + { + KillTimer(g_poolTableData[ poolid][ E_TIMER ]); + g_poolTableData[ poolid][ E_TIMER ] = SetTimerEx("OnPoolUpdate", POOL_TIMER_SPEED, true, "d", poolid); + + for (new i = 0; i < 16; i ++) + { + InitBalls(poolid, i); + } + } +} + +stock InitBalls(poolid, ballid) +{ + PHY_InitObject(g_poolBallData[poolid][E_BALL_OBJECT][ballid], 3003, _, _, PHY_MODE_2D); + + PHY_SetObjectFriction(g_poolBallData[poolid][E_BALL_OBJECT][ballid], 0.08); + //PHY_SetObjectFriction(g_poolBallData[poolid][E_BALL_OBJECT][ballid], 0.10); + PHY_SetObjectAirResistance(g_poolBallData[poolid][E_BALL_OBJECT][ballid], 0.2); + PHY_RollObject(g_poolBallData[poolid][E_BALL_OBJECT][ballid]); + + g_poolBallData[poolid][E_EXISTS][ballid] = true; +} + +stock RotateXY(Float:xi, Float:yi, Float:angle, &Float:xf, &Float:yf) +{ + xf = xi * floatcos(angle, degrees) - yi * floatsin(angle, degrees); + yf = xi * floatsin(angle, degrees) + yi * floatcos(angle, degrees); + return 1; +} + +stock CreateBalls(poolid) +{ + new Float: x, + Float: y, + Float: pos[3], + Float: angle; + + pos[0] = g_poolTableData[ poolid][ E_X ]; + pos[1] = g_poolTableData[ poolid][ E_Y ]; + pos[2] = g_poolTableData[ poolid][ E_Z ]; + angle = g_poolTableData[ poolid][ E_ANGLE ]; + + RotateXY(0.5, 0.0, angle, x, y); + g_poolBallData[poolid][E_BALL_OBJECT][0] = CreateObject(3003, x + pos[0], y + pos[1], (pos[2] - 0.045), 0, 0, 0); + + RotateXY(-0.3, 0.0, angle, x, y); + g_poolBallData[poolid][E_BALL_OBJECT][1] = CreateObject(3002, x + pos[0], y + pos[1], (pos[2] - 0.045), 0, 0, 0); + + RotateXY(-0.525, - 0.040, angle, x, y); + g_poolBallData[poolid][E_BALL_OBJECT][2] = CreateObject(3100, x + pos[0], y + pos[1], (pos[2] - 0.045), 0, 0, 0); + + RotateXY(-0.375, 0.044, angle, x, y); + g_poolBallData[poolid][E_BALL_OBJECT][3] = CreateObject(3101, x + pos[0], y + pos[1], (pos[2] - 0.045), 0, 0, 0); + + RotateXY(-0.600, 0.079, angle, x, y); + g_poolBallData[poolid][E_BALL_OBJECT][4] = CreateObject(3102, x + pos[0], y + pos[1], (pos[2] - 0.045), 0, 0, 0); + + RotateXY(-0.525, 0.118, angle, x, y); + g_poolBallData[poolid][E_BALL_OBJECT][5] = CreateObject(3103, x + pos[0], y + pos[1], (pos[2] - 0.045), 0, 0, 0); + + RotateXY(-0.600, - 0.157, angle, x, y); + g_poolBallData[poolid][E_BALL_OBJECT][6] = CreateObject(3104, x + pos[0], y + pos[1], (pos[2] - 0.045), 0, 0, 0); + + RotateXY(-0.450, - 0.079, angle, x, y); + g_poolBallData[poolid][E_BALL_OBJECT][7] = CreateObject(3105, x + pos[0], y + pos[1], (pos[2] - 0.045), 0, 0, 0); + + RotateXY(-0.450, 0.0, angle, x, y); + g_poolBallData[poolid][E_BALL_OBJECT][8] = CreateObject(3106, x + pos[0], y + pos[1], (pos[2] - 0.045), 0, 0, 0); + + RotateXY(-0.375, - 0.044, angle, x, y); + g_poolBallData[poolid][E_BALL_OBJECT][9] = CreateObject(2995, x + pos[0], y + pos[1], (pos[2] - 0.045), 0, 0, 0); + + RotateXY(-0.450, 0.079, angle, x, y); + g_poolBallData[poolid][E_BALL_OBJECT][10] = CreateObject(2996, x + pos[0], y + pos[1], (pos[2] - 0.045), 0, 0, 0); + + RotateXY(-0.525, - 0.118, angle, x, y); + g_poolBallData[poolid][E_BALL_OBJECT][11] = CreateObject(2997, x + pos[0], y + pos[1], (pos[2] - 0.045), 0, 0, 0); + + RotateXY(-0.600, - 0.079, angle, x, y); + g_poolBallData[poolid][E_BALL_OBJECT][12] = CreateObject(2998, x + pos[0], y + pos[1], (pos[2] - 0.045), 0, 0, 0); + + RotateXY(-0.600, 0.0, angle, x, y); + g_poolBallData[poolid][E_BALL_OBJECT][13] = CreateObject(2999, x + pos[0], y + pos[1], (pos[2] - 0.045), 0, 0, 0); + + RotateXY(-0.600, 0.157, angle, x, y); + g_poolBallData[poolid][E_BALL_OBJECT][14] = CreateObject(3000, x + pos[0], y + pos[1], (pos[2] - 0.045), 0, 0, 0); + + RotateXY(-0.525, 0.040, angle, x, y); + g_poolBallData[poolid][E_BALL_OBJECT][15] = CreateObject(3001, x + pos[0], y + pos[1], (pos[2] - 0.045), 0, 0, 0); +} + +stock IsKeyJustUp(key, newkeys, oldkeys) +{ + if (!(newkeys & key) && (oldkeys & key)) return 1; + return 0; +} + +stock GetXYBehindObjectInAngle(objectid, Float:a, &Float:x2, &Float:y2, Float:distance) +{ + new Float:z; + GetObjectPos(objectid, x2, y2, z); + + x2 += (distance * floatsin(-a+180, degrees)); + y2 += (distance * floatcos(-a+180, degrees)); +} + +stock AreAllBallsStopped(poolid) +{ + new + Float: x, + Float: y, + Float: z; + + for (new i = 0; i < 16; i ++) + { + if (g_poolBallData[poolid][E_EXISTS][i]) + { + PHY_GetObjectVelocity(g_poolBallData[poolid][E_BALL_OBJECT][i], x, y, z); + + if (x != 0.0 || y != 0.0) + return 0; + } + } + + return 1; +} + +stock Is2DPointInRangeOfPoint(Float:x, Float:y, Float:x2, Float:y2, Float:range) +{ + x2 -= x; + y2 -= y; + return ((x2 * x2) + (y2 * y2)) < (range * range); +} + +stock GetAngleToXY(Float:X, Float:Y, Float:CurrX, Float:CurrY, &Float:angle) +{ + angle = atan2(Y-CurrY, X-CurrX); + angle = floatsub(angle, 90.0); + if(angle < 0.0) angle = floatadd(angle, 360.0); +} + +stock GetXYInFrontOfPos(Float:xx,Float:yy,Float:a, &Float:x2, &Float:y2, Float:distance) +{ + if (a > 360) { + a = a - 360; + } + + xx += (distance * floatsin(-a, degrees)); + yy += (distance * floatcos(-a, degrees)); + x2 = xx; + y2 = yy; +} + +stock GetMaxPoolScore(poolid) +{ + new score = -1; + + foreach (new i : Player) + { + if ( IsPlayerPlayingPool( i ) && p_PoolID[ i ] == poolid) + { + if (p_PoolScore[ i ] > score) + { + score = p_PoolScore[ i ]; + } + } + } + + return score; +} + +stock GetPoolBallsCount(poolid) +{ + new ball_count = 0; + + for (new i = 0; i < 16; i ++) + { + if (g_poolBallData[poolid][E_EXISTS][i] || i == 0) + ball_count ++; + } + + return ball_count; +} + +stock IsBallInHole(poolid, objectid) +{ + if (IsInBall(objectid, g_poolTableData[ poolid][ E_X ] + 0.955, g_poolTableData[ poolid][ E_Y ] + 0.510, g_poolTableData[ poolid][ E_Z ], POCKET_RADIUS)) return 1; + else if (IsInBall(objectid, g_poolTableData[ poolid][ E_X ] + 0.955, g_poolTableData[ poolid][ E_Y ] - 0.510, g_poolTableData[ poolid][ E_Z ], POCKET_RADIUS)) return 1; + else if (IsInBall(objectid, g_poolTableData[ poolid][ E_X ] + 0.000, g_poolTableData[ poolid][ E_Y ] + 0.550, g_poolTableData[ poolid][ E_Z ], POCKET_RADIUS)) return 1; + else if (IsInBall(objectid, g_poolTableData[ poolid][ E_X ] + 0.000, g_poolTableData[ poolid][ E_Y ] - 0.550, g_poolTableData[ poolid][ E_Z ], POCKET_RADIUS)) return 1; + else if (IsInBall(objectid, g_poolTableData[ poolid][ E_X ] - 0.955, g_poolTableData[ poolid][ E_Y ] + 0.510, g_poolTableData[ poolid][ E_Z ], POCKET_RADIUS)) return 1; + else if (IsInBall(objectid, g_poolTableData[ poolid][ E_X ] - 0.955, g_poolTableData[ poolid][ E_Y ] - 0.510, g_poolTableData[ poolid][ E_Z ], POCKET_RADIUS)) return 1; + + return 0; +} + +stock respawnCueBall(poolid) +{ + if (!g_poolBallData[poolid][E_EXISTS][0]) + { + DestroyObject(g_poolBallData[poolid][E_BALL_OBJECT][0]); + + new Float: x, + Float: y, + Float: pos[3], + Float: angle; + + pos[0] = g_poolTableData[ poolid][ E_X ]; + pos[1] = g_poolTableData[ poolid][ E_Y ]; + pos[2] = g_poolTableData[ poolid][ E_Z ]; + angle = g_poolTableData[ poolid][ E_ANGLE ]; + + RotateXY(0.5, 0.0, angle, x, y); + g_poolBallData[poolid][E_BALL_OBJECT][0] = CreateObject(3003, x + pos[0], y + pos[1], (pos[2]), 0, 0, 0); + + InitBalls(poolid, 0); + } + return 1; +} + +stock removePlayerWeapon(playerid, weaponid) +{ + SetPlayerArmedWeapon(playerid, weaponid); + + if (GetPlayerWeapon(playerid) != 0) + GivePlayerWeapon(playerid, weaponid, 0); + + return 1; +} + +stock gameEnd(poolid) +{ + foreach (new i : Player) + { + if (p_PoolID[ i ] == poolid) + { + p_isPlayingPool{ i } = false; + p_PoolScore[ i ] = -1; + p_PoolID[ i ] = -1; + + removePlayerWeapon(i, 7); + } + } + + g_poolTableData[ poolid][ E_STARTED ] = false; + + KillTimer(g_poolTableData[ poolid][ E_TIMER ]); + for (new i = 0; i < 16; i ++) + { + DestroyObject(g_poolBallData[poolid][E_BALL_OBJECT][i]); + + if (g_poolBallData[poolid][E_EXISTS][i]) + { + PHY_DeleteObject(g_poolBallData[poolid][E_BALL_OBJECT][i]); + g_poolBallData[poolid][E_EXISTS][i] = false; + } + } + + UpdateDynamic3DTextLabelText(g_poolTableData[ poolid ][ E_LABEL ], -1, DEFAULT_POOL_STRING); + + return 1; +} + +stock AngleInRangeOfAngle(Float:a1, Float:a2, Float:range) +{ + a1 -= a2; + if ((a1 < range) && (a1 > -range)) + return true; + + return false; +} + +stock IsInBall(objectid, Float:x, Float:y, Float:z, Float:radius) +{ + new Float:pos[3], Float:dis; + + GetObjectPos(objectid, pos[0], pos[1], pos[2]); + + dis = floatsqroot(floatpower(floatabs(floatsub(x, pos[0])), 2) + floatpower(floatabs(floatsub(y, pos[1])), 2) + floatpower(floatabs(floatsub(z, pos[2])), 2)); + + if (dis < radius) + return 1; + return 0; +} + +stock IsBallNearSide(poolid, objectid) +{ + new Float: x_vertex[4], + Float: y_vertex[4]; + + RotateXY(-0.96, -0.515, 0.0, x_vertex[0], y_vertex[0]); + RotateXY(-0.96, 0.515, 0.0, x_vertex[1], y_vertex[1]); + RotateXY(0.96, -0.515, 0.0, x_vertex[2], y_vertex[2]); + RotateXY(0.96, 0.515, 0.0, x_vertex[3], y_vertex[3]); + + if (IsInBall(objectid, x_vertex[0] + g_poolTableData[ poolid][ E_X ], y_vertex[0] + g_poolTableData[ poolid][ E_Y ], x_vertex[1] + g_poolTableData[ poolid][ E_X ], y_vertex[1] + g_poolTableData[ poolid][ E_Y ])) return 1; + if (IsInBall(objectid, x_vertex[1] + g_poolTableData[ poolid][ E_X ], y_vertex[1] + g_poolTableData[ poolid][ E_Y ], x_vertex[3] + g_poolTableData[ poolid][ E_X ], y_vertex[3] + g_poolTableData[ poolid][ E_Y ])) return 1; + if (IsInBall(objectid, x_vertex[2] + g_poolTableData[ poolid][ E_X ], y_vertex[2] + g_poolTableData[ poolid][ E_Y ], x_vertex[3] + g_poolTableData[ poolid][ E_X ], y_vertex[3] + g_poolTableData[ poolid][ E_Y ])) return 1; + if (IsInBall(objectid, x_vertex[0] + g_poolTableData[ poolid][ E_X ], y_vertex[0] + g_poolTableData[ poolid][ E_Y ], x_vertex[2] + g_poolTableData[ poolid][ E_X ], y_vertex[2] + g_poolTableData[ poolid][ E_Y ])) return 1; + + return 0; +} + +forward PlayPoolSound(poolid, soundid); +public PlayPoolSound(poolid, soundid) +{ + foreach (new playerid : Player) + { + if (p_PoolID[ playerid ] == poolid) + { + PlayerPlaySound(playerid, soundid, 0.0, 0.0, 0.0); + } + } +} + +forward OnPoolUpdate(poolid); +public OnPoolUpdate(poolid) +{ + if (!g_poolTableData[ poolid][ E_STARTED ]) + return 0; + + if (g_poolTableData[ poolid][ E_AIMER ] != -1) + { + new playerid = g_poolTableData[ poolid][ E_AIMER ], keys, ud, lr; + + GetPlayerKeys(playerid, keys, ud, lr); + + if (!(keys & KEY_FIRE)) + { + if (lr) + { + new Float: X, Float: Y, Float: Z, Float: Xa, Float: Ya, Float: Za, Float: x, Float: y, Float: newrot, Float: dist; + + GetPlayerPos(playerid, X, Y ,Z); + GetObjectPos(g_poolBallData[poolid][E_BALL_OBJECT][0], Xa, Ya, Za); + newrot = p_PoolAngle[ playerid ] [ 0 ] + (lr > 0 ? 0.9 : -0.9); + dist = GetPointDistanceToPoint(X, Y, Xa, Ya); + + if (AngleInRangeOfAngle(p_PoolAngle[ playerid ] [ 1 ], newrot, 30.0)) + { + p_PoolAngle[ playerid ] [ 0 ] = newrot; + switch (p_PoolCamera[ playerid ]) + { + case 0: + { + GetXYBehindObjectInAngle(g_poolBallData[poolid][E_BALL_OBJECT][0], newrot, x, y, 0.675); + + SetPlayerCameraPos(playerid, x, y, g_poolTableData[ poolid][ E_Z ] + DEFAULT_AIM); + SetPlayerCameraLookAt(playerid, Xa, Ya, Za + 0.170); + } + case 1: + { + SetPlayerCameraPos(playerid, g_poolTableData[ poolid][ E_X ], g_poolTableData[ poolid][ E_Y ], g_poolTableData[ poolid][ E_Z ] + 2.0); + SetPlayerCameraLookAt(playerid, g_poolTableData[ poolid][ E_X ], g_poolTableData[ poolid][ E_Y ], g_poolTableData[ poolid][ E_Z ]); + } + case 2: + { + SetPlayerCameraPos(playerid, g_poolTableData[ poolid][ E_X ], g_poolTableData[ poolid][ E_Y ], g_poolTableData[ poolid][ E_Z ] + 2.0); + SetPlayerCameraLookAt(playerid, g_poolTableData[ poolid][ E_X ], g_poolTableData[ poolid][ E_Y ], g_poolTableData[ poolid][ E_Z ]); + } + } + + GetXYInFrontOfPos(Xa, Ya, newrot + 180, x, y, 0.085); + SetObjectPos(g_poolTableData[ poolid][ E_AIMER_OBJECT ], x, y, Za); + SetObjectRot(g_poolTableData[ poolid][ E_AIMER_OBJECT ], 7.0, 0, p_PoolAngle[ playerid ] [ 0 ] + 180); + GetXYInFrontOfPos(Xa, Ya, newrot + 180, X, Y, dist); + SetPlayerPos(playerid, X, Y, Z); + SetPlayerFacingAngle(playerid, newrot); + } + } + } + else + { + if (g_poolTableData[ poolid][ E_DIRECTION ]) + { + g_poolTableData[ poolid][ E_POWER ] -= 2.0; + } + else + { + g_poolTableData[ poolid][ E_POWER ] += 2.0; + } + + if (g_poolTableData[ poolid][ E_POWER ] <= 0) + { + g_poolTableData[ poolid][ E_DIRECTION ] = 0; + g_poolTableData[ poolid][ E_POWER ] = 2.0; + } + else if (g_poolTableData[ poolid][ E_POWER ] > 100.0) + { + g_poolTableData[ poolid][ E_DIRECTION ] = 1; + g_poolTableData[ poolid][ E_POWER ] = 98.0; + } + + // TextDrawTextSize(g_PoolTextdraw[2], 501.0 + ((67.0 * g_poolTableData[ poolid][ E_POWER ])/100.0), 0.0); + // TextDrawShowForPlayer(playerid, g_PoolTextdraw[2]); + + // ShowPlayerPoolTextdraw(playerid); + + SetPlayerProgressBarMaxValue(playerid, g_PoolPowerBar[playerid], 67.0); + SetPlayerProgressBarValue(playerid, g_PoolPowerBar[playerid], ((67.0 * g_poolTableData[ poolid][ E_POWER ])/100.0)); + ShowPlayerProgressBar(playerid, g_PoolPowerBar[playerid]); + + PlayerTextDrawShow(playerid, g_PoolTextdraw[playerid]); + } + } + + if (g_poolTableData[ poolid][ E_LAST_SHOOTER ] != -1 && AreAllBallsStopped(poolid)) + { + SetTimerEx("RestoreCamera", 800, 0, "dd", g_poolTableData[ poolid][ E_LAST_SHOOTER ], poolid); + g_poolTableData[ poolid][ E_LAST_SHOOTER ] = -1; + } + + return 1; +} + +forward RestoreCamera(playerid, poolid); +public RestoreCamera(playerid, poolid) +{ + if (!g_poolBallData[poolid][E_EXISTS][0]) + { + DestroyObject(g_poolBallData[poolid][E_BALL_OBJECT][0]); + + new Float: x, Float: y, Float: pos[3], Float: angle; + + pos[0] = g_poolTableData[ poolid][ E_X ]; + pos[1] = g_poolTableData[ poolid][ E_Y ]; + pos[2] = g_poolTableData[ poolid][ E_Z ]; + angle = g_poolTableData[ poolid][ E_ANGLE ]; + + RotateXY(0.5, 0.0, angle, x, y); + g_poolBallData[poolid][E_BALL_OBJECT][0] = CreateObject(3003, x + pos[0], y + pos[1], (pos[2] - 0.045), 0, 0, 0); + + InitBalls(poolid, 0); + } + + if (g_poolTableData[ poolid][ E_AIMER ] == playerid) + return 0; + + PlayerTextDrawHide(playerid, g_PoolTextdraw[playerid]); + HidePlayerProgressBar(playerid, g_PoolPowerBar[playerid]); + + TogglePlayerControllable(playerid, 1); + return SetCameraBehindPlayer(playerid); +} + +Float:GetPointDistanceToPoint(Float:x1,Float:y1,Float:x2,Float:y2) +{ + new Float: x, Float: y; + x = x1 - x2; + y = y1 - y2; + return floatsqroot(x * x + y * y); +} + +forward deleteBall(poolid, ballid); +public deleteBall(poolid, ballid) +{ + if (g_poolBallData[poolid][E_MOVING][ballid]) + { + g_poolBallData[poolid][E_EXISTS][ballid] = false; + DestroyObject(g_poolBallData[poolid][E_BALL_OBJECT][ballid]); + PHY_DeleteObject(g_poolBallData[poolid][E_BALL_OBJECT][ballid]); + + g_poolBallData[poolid][E_MOVING][ballid] = false; + } + + return 1; +} + +forward RestoreWeapon(playerid); +public RestoreWeapon(playerid) +{ + RemovePlayerAttachedObject(playerid, 0); + + p_PoolChalk[ playerid ] = false; + + GivePlayerWeapon(playerid, 7, 1); + + ApplyAnimation(playerid, "CARRY", "crry_prtial", 1.0, 0, 0, 0, 0, 0, 1); + return 1; +} + +/** * Public Functions * **/ + +public PHY_OnObjectCollideWithObject(object1, object2) +{ + for (new id = 0; id < MAX_TABLES; id ++) if (g_poolTableData[ id ][ E_STARTED ]) + { + for (new i = 0; i < 16; i++) + { + if (object1 == g_poolBallData[id][E_BALL_OBJECT][i]) + { + PlayPoolSound(id, 31800 + random(3)); + return 1; + } + } + } + return 1; +} + +public PHY_OnObjectCollideWithWall(objectid, wallid) +{ + for (new id = 0; id < MAX_TABLES; id ++) if (g_poolTableData[ id ][ E_STARTED ]) + { + for (new i = 0; i < 16; i++) + { + if (objectid == g_poolBallData[id][E_BALL_OBJECT][i]) + { + PlayPoolSound(id, 31808); + return 1; + } + } + } + return 1; +} + +public PHY_OnObjectUpdate(objectid) +{ + foreach (new i : Player) + { + new + poolid = getNearestPoolTable( i ); + + if ( poolid == -1 ) + return 0; + + for (new j = 0; j < 16; j ++) + { + if ( IsBallInHole( poolid, objectid) ) + { + if ( objectid == g_poolBallData[ poolid ][ E_BALL_OBJECT ][ j ] && PHY_IsObjectMoving( g_poolBallData[ poolid ][ E_BALL_OBJECT ][ j ]) && !g_poolBallData[ poolid ][ E_MOVING ][ j ] ) + { + new pool_player = g_poolTableData[ poolid ][ E_LAST_SHOOTER ], + modelid = GetObjectModel( objectid ); + + if (modelid == 3003) + { + GameTextForPlayer(pool_player, "~n~~n~~n~~r~~h~You have pocketed the cue ball!", 10000, 4); + + respawnCueBall( poolid ); + } + else + { + p_PoolScore[ pool_player ] += 1; + GameTextForPlayer( pool_player, "~n~~n~~n~~w~Score: +1", 3000, 4); + + PlayerTextDrawSetString( pool_player, g_PoolTextdraw[ pool_player ], sprintf("Power:~n~~n~Score: %d", p_PoolScore[ pool_player ])); + PlayerTextDrawHide( pool_player, g_PoolTextdraw[ pool_player ] ); + PlayerTextDrawShow( pool_player, g_PoolTextdraw[ pool_player ] ); + + //ShowPlayerHelpDialog( pool_player, 10000, "~w~You have pocketed another ball!~n~~n~Score: %d", p_PoolScore[pool_player]); + + if (pool_player == g_poolTableData[ poolid ][ E_PLAYER ] [ 0 ]) + { + format(szNormalString, sizeof(szNormalString), "{FFDC2E}%s [%d] - [%d] %s", ReturnPlayerName(pool_player), p_PoolScore[ pool_player ], p_PoolScore[ g_poolTableData[ poolid ][ E_PLAYER ] [ 1 ] ], ReturnPlayerName(g_poolTableData[ poolid ][ E_PLAYER ] [ 1 ])); + } + else if (pool_player == g_poolTableData[ poolid ][ E_PLAYER ] [ 1 ]) + { + format(szNormalString, sizeof(szNormalString), "{FFDC2E}%s [%d] - [%d] %s", ReturnPlayerName(g_poolTableData[ poolid ][ E_PLAYER ] [ 0 ]), p_PoolScore[ g_poolTableData[ poolid ][ E_PLAYER ] [ 0 ] ], p_PoolScore[ pool_player ], ReturnPlayerName(pool_player)); + } + + UpdateDynamic3DTextLabelText(g_poolTableData[ poolid ][ E_LABEL ], -1, szNormalString); + } + + new Float: vx, + Float: vy, + Float: vz; + + GetObjectPos( g_poolBallData[ poolid ][ E_BALL_OBJECT ][ j ], vx, vy, vz); + MoveObject( g_poolBallData[ poolid ][ E_BALL_OBJECT ][ j ], vx, vy, vz - 1.25, 1); + + g_poolBallData[ poolid ][ E_MOVING ][ j ] = true; + + SetTimerEx("deleteBall", 500, false, "dd", poolid, j); + + PlayerPlaySound(pool_player, 31803, 0.0, 0.0, 0.0); + + if (( GetPoolBallsCount( poolid ) - 1) <= 1) + { + g_poolTableData[ poolid ][ E_STARTED ] = false; + g_poolTableData[ poolid ][ E_AIMER ] = -1; + + new + win_score = GetMaxPoolScore( poolid ); + + RestoreCamera(i, poolid); + g_poolTableData[ poolid ][ E_LAST_SHOOTER ] = -1; + + if ( IsPlayerPlayingPool( i ) && p_PoolScore[ i ] == win_score) + { + SendClientMessageToAllFormatted( -1, ""COL_POOL"[SERVER]"COL_WHITE" The winner is %s(%d) with %d points.", ReturnPlayerName(i), i, win_score); + + p_isPlayingPool{ i } = false; + p_PoolScore[ i ] = -1; + p_PoolID[ i ] = -1; + } + + gameEnd(poolid); + } + else if (AreAllBallsStopped(poolid)) + { + SetTimerEx("RestoreCamera", 800, 0, "dd", g_poolTableData[ poolid][ E_LAST_SHOOTER ], poolid); + g_poolTableData[ i][ E_LAST_SHOOTER ] = -1; + } + } + } + } + } + + return 1; +} + +/* ** Commands ** */ + +CMD:pool(playerid, params[]) +{ + new selection[32]; + + if ( sscanf( params, "s[32] ", selection) ) + return SendUsage(playerid, "/pool [INVITE/ACCEPT/DECLINE]" ); + + if ( strmatch( selection, "accept") ) + { + if ( !IsPlayerConnected(p_PoolSender[ playerid ]) ) + return SendError(playerid, "You do not have any pool game invitations to accept." ); + + if ( IsPlayerPlayingPool( playerid )) + return SendError(playerid, "You are already playing pool." ); + + new targetid = p_PoolSender[ playerid ]; + + if (GetDistanceBetweenPlayers(playerid, targetid) > 10.0) + return SendError(playerid, "You must be within 10.0 meters of your opponent!"); + + new poolid = p_PoolID[ playerid ]; + + g_poolTableData[ poolid ][ E_PLAYER ] [ 0 ] = playerid; + g_poolTableData[ poolid ][ E_PLAYER ] [ 1 ] = targetid; + + SendClientMessageFormatted(targetid, -1, ""COL_POOL"[SERVER]"COL_WHITE" %s(%d) has accepted your pool game invitation.", ReturnPlayerName(playerid), playerid); + SendClientMessageFormatted(playerid, -1, ""COL_POOL"[SERVER]"COL_WHITE" You have accepted %s(%d)'s pool game invitation.", ReturnPlayerName(targetid), targetid); + + SendClientMessageFormatted(playerid, -1, ""COL_POOL"[SERVER]"COL_WHITE" %s(%d) will be breaking!", ReturnPlayerName(playerid), playerid); + //UpdateDynamicLabel(poolid, 10000, "{C0C0C0}Pool Table\n{FFFFFF}%s(%d) will be breaking!", ReturnPlayerName(g_poolTableData[ poolid][poolPlayer][startid]), g_poolTableData[ poolid][poolPlayer][startid]); + + format(szNormalString, sizeof(szNormalString), "{FFDC2E}%s [0] - [0] %s", ReturnPlayerName(playerid), ReturnPlayerName(targetid)); + UpdateDynamic3DTextLabelText(g_poolTableData[ poolid][ E_LABEL ], -1, szNormalString); + + p_isPlayingPool{ playerid } = true; + p_PoolID[ playerid ] = poolid; + p_PoolScore[ playerid ] = 0; + + p_isPlayingPool{ targetid } = true; + p_PoolID[ targetid ] = poolid; + p_PoolScore[ targetid ] = 0; + + PlayerPlaySound(playerid, 1085, 0.0, 0.0, 0.0); + PlayerPlaySound(targetid, 1085, 0.0, 0.0, 0.0); + + GivePlayerWeapon(targetid, 7, 1); + GivePlayerWeapon(playerid, 7, 1); + + if (!g_poolTableData[ poolid][ E_STARTED ]) + { + g_poolTableData[ poolid][ E_STARTED ] = true; + RespawnPoolBalls(poolid, 1); + } + return 1; + } + else if ( strmatch( selection, "decline") ) + { + if ( !IsPlayerConnected( p_PoolSender[ playerid ]) ) + return SendError( playerid, "You do not have any pool game invitations to decline." ); + + new targetid = p_PoolSender[ playerid ]; + + SendClientMessageFormatted( targetid, -1, ""COL_POOL"[SERVER]{FFFFFF} %s(%d) has declined your pool game invitation.", ReturnPlayerName(playerid), playerid ); + SendClientMessageFormatted( playerid, -1, ""COL_POOL"[SERVER]{FFFFFF} You have declined %s(%d)'s pool game invitation.", ReturnPlayerName(targetid), targetid ); + + return 1; + } + else if (strmatch(selection, "invite")) + { + new id = -1, targetid; + + id = getNearestPoolTable(playerid); + + if (id == -1) + return SendError(playerid, "You are not close enough to a pool table."); + + if (g_poolTableData[ id ][ E_STARTED ]) + return SendError(playerid, "You cannot invite anyone to this table, since there is already a game in progress."); + + if (sscanf(params, "s[32] u", selection, targetid)) + return SendUsage(playerid, "/pool invite [PLAYER_ID]"); + + if (targetid == playerid) + return SendError(playerid, "You cannot play pool with yourself!"); + + if (targetid == INVALID_PLAYER_ID || !IsPlayerConnected(targetid)) + return SendError(playerid, "Invalid Player ID."); + + if ( IsPlayerPlayingPool( targetid )) + return SendError(playerid, "This player is already playing pool!"); + + //if (GetDistanceBetweenPlayers(playerid, targetid) > 10.0) + //return SendError(playerid, "The player you wish to play pool with is not near you."); + + if (GetPlayerWantedLevel(playerid)) + return SendError(playerid, "You can't play pool with this person right now, they are wanted"); + + // if (IsPlayerJailed(targetid)) + // return SendError(playerid, "You can't play pool with this person right now, they are currently in jail."); + + p_PoolSender[ targetid ] = playerid; + p_PoolReciever[ playerid ] = targetid; + p_PoolID[ targetid ] = id; + + SendClientMessageFormatted(playerid, -1, ""COL_POOL"[SERVER]{FFFFFF} You have sent a pool game invitation to %s(%d)!", ReturnPlayerName(targetid), targetid); + + SendClientMessageFormatted(targetid, -1, ""COL_POOL"[SERVER]{FFFFFF} You have recieved a pool game invitation by %s(%d)!", ReturnPlayerName(playerid), playerid); + SendClientMessageFormatted(targetid, -1, ""COL_POOL"[SERVER]{FFFFFF} To accept or decline the invite, use /pool [ACCEPT/DECLINE]"); + } + else + { + SendUsage(playerid, "/pool [INVITE/ACCEPT/DECLINE]"); + } + + return 1; +} + +CMD:endgame(playerid) +{ + if ( ! IsPlayerAdmin( playerid ) ) + return 0; + + new iPool = getNearestPoolTable( playerid ); + + if ( iPool == -1 ) + return SendError( playerid, "You must be near a pool table to use this command." ); + + gameEnd( iPool ); + + SendClientMessage(playerid, -1, ""COL_PINK"[ADMIN]"COL_WHITE" You have force ended the pool game!"); + return 1; +} + +CMD:play(playerid) +{ + new + iPool = getNearestPoolTable( playerid ); + + if ( iPool == -1 ) + return SendError( playerid, "You are not near a pool table." ); + + if ( ! IsPlayerPlayingPool( playerid )) + { + p_isPlayingPool { playerid } = true; + p_PoolID[ playerid ] = iPool; + + PlayerPlaySound( playerid, 1085, 0.0, 0.0, 0.0 ); + GivePlayerWeapon( playerid, 7, 1 ); + + p_PoolScore[ playerid ] = 0; + + if (!g_poolTableData[ iPool ][ E_STARTED ]) + { + g_poolTableData[ iPool ][ E_STARTED ] = true; + + UpdateDynamic3DTextLabelText(g_poolTableData[ iPool ][ E_LABEL ], -1, sprintf( "{FFDC2E}%s is currently playing a test game.", ReturnPlayerName( playerid )) ); + + RespawnPoolBalls(iPool, 1); + } + } + else + { + gameEnd(iPool); + } + + return 1; +} + +/* ** Commands ** */ + +CMD:addpool(playerid) +{ + if ( p_AdminLevel[ playerid ] < 6 ) + return SendError( playerid, ADMIN_COMMAND_REJECT ); + + new Float: x, Float: y, Float: z; + + GetPlayerFrontPos(playerid, x, y, z, 2.0); + + CreatePoolTable(x, y, z, 0.0, GetPlayerInterior(playerid), GetPlayerVirtualWorld(playerid)); + + SendClientMessage(playerid, -1, ""COL_PINK"[ADMIN]{FFFFFF} You have created a pool table."); + return 1; +} \ No newline at end of file