sfcnr/gamemodes/irresistible/cnr/features/battleroyale/battleroyale.pwn

442 lines
15 KiB
Plaintext

/*
* Irresistible Gaming (c) 2018
* Developed by Lorenc
* Module: cnr\features\battleroyale\battleroyale.pwn
* Purpose: Battle Royale minigame implementation for SA-MP
*/
/*
https://github.com/RIDE-2DAY/GZ_Shapes/blob/master/GZ_ShapesALS.inc
1. Player creates lobby
- Lobby can be CAC only
- Player can select area
- Player can select speed in which the circle shrinks
- Player can select between running weapons, walking weapons or both (as drops)
- Player can make an entry fee, this entry fee gets added to a prize pool
2. Players join the lobby, you teleport to an island
- After the maximum slots are achieved, the game will start
- Host can start the match forcefully
3. Plane in the middle, you have a parachute, jump out
4. Stay within red zone, if you leave it you get killed
5. Last man standing wins ...
*/
/* ** Includes ** */
#include < YSI\y_hooks >
#include < YSI\y_iterate >
/* ** Definitions ** */
#define BR_MAX_LOBBIES ( 10 )
#define BR_MAX_PLAYERS ( 32 )
#define BR_INVALID_LOBBY ( -1 )
/* ** Dialogs ** */
#define DIALOG_BR_LOBBY ( 6373 )
#define DIALOG_BR_LOBBY_EDIT ( 6374 )
#define DIALOG_BR_LOBBY_EDIT_ENTRY ( 6375 )
/* ** Constants ** */
static const
Float: BR_CHECKPOINT_POS[ 3 ] = {
0.0, 0.0, 0.0
},
BR_RUNNING_WEAPONS[ ] = {
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34
},
BR_WALKING_WEAPONS[ ] = {
4, 8, 9, 23, 24, 25, 27, 29, 30, 31, 33, 34
}
;
/* ** Variables ** */
enum E_BR_LOBBY_STATUS
{
E_STATUS_SETUP,
E_STATUS_WAITING_FOR_PLAYERS,
E_STATUS_STARTED
};
enum E_BR_LOBBY_DATA
{
E_NAME[ 24 ], E_HOST, E_PASSWORD[ 5 ],
E_LIMIT, E_AREA_ID, E_BR_LOBBY_STATUS: E_STATUS,
E_ENTRY_FEE,
Float: E_ARMOUR, Float: E_HEALTH,
bool: E_WALK_WEP, bool: E_CAC_ONLY
};
enum E_BR_AREA_DATA
{
E_NAME[ 24 ], Float: E_MIN_X, Float: E_MAX_X,
Float: E_MIN_Y, Float: E_MAX_Y
};
static stock
// where all the area data is stored
br_areaData [ 1 ] [ E_BR_AREA_DATA ] =
{
{ "San Fierro", 0.0, 0.0, 0.0, 0.0 }
},
// lobby data & info
br_lobbyData [ BR_MAX_LOBBIES ] [ E_BR_LOBBY_DATA ],
Iterator: battleroyale < BR_MAX_LOBBIES >,
Iterator: battleroyaleplayers [ BR_MAX_LOBBIES ] < BR_MAX_PLAYERS >,
// player related
p_battleRoyaleLobby [ MAX_PLAYERS ] = { BR_INVALID_LOBBY, ... },
// global related
g_battleRoyaleStadiumCP = -1
;
/* ** Hooks ** */
hook OnScriptInit( )
{
g_battleRoyaleStadiumCP = CreateDynamicCP( BR_CHECKPOINT_POS[ 0 ], BR_CHECKPOINT_POS[ 1 ], BR_CHECKPOINT_POS[ 2 ], 1.0, 0 );
CreateDynamic3DTextLabel( "[BATTLE ROYALE]", COLOR_GOLD, BR_CHECKPOINT_POS[ 0 ], BR_CHECKPOINT_POS[ 1 ], BR_CHECKPOINT_POS[ 2 ], 20.0 );
return 1;
}
hook OnPlayerEnterDynamicCP( playerid, checkpointid )
{
if ( checkpointid == g_battleRoyaleStadiumCP )
{
return BattleRoyale_ShowLobbies( playerid );
}
return 1;
}
hook OnDialogResponse( playerid, dialogid, response, listitem, inputtext[ ] )
{
if ( dialogid == DIALOG_BR_LOBBY && response )
{
new
x = 0;
// check if the player selected an existing lobby
foreach ( new l : battleroyale )
{
if ( x == listitem )
{
// status must be in a waiting state
if ( br_lobbyData[ l ] [ E_STATUS ] != E_STATUS_WAITING_FOR_PLAYERS )
{
return BattleRoyale_ShowLobbies( playerid ), SendError( playerid, "You cannot join this lobby at the moment." );
}
// check if the count is under the limit
if ( Iter_Count( battleroyaleplayers[ l ] ) >= br_lobbyData[ l ] [ E_LIMIT ] )
{
return BattleRoyale_ShowLobbies( playerid ), SendError( playerid, "This lobby has reached its maximum player count." );
}
// check if player has money for the lobby
if ( GetPlayerCash( playerid ) < br_lobbyData[ l ] [ E_ENTRY_FEE ] )
{
return BattleRoyale_ShowLobbies( playerid ), SendError( playerid, "You need %s to join this lobby.", cash_format( br_lobbyData[ l ] [ E_ENTRY_FEE ] ) );
}
GivePlayerCash( playerid, -br_lobbyData[ l ] [ E_ENTRY_FEE ] );
return BattleRoyale_JoinLobby( playerid, l ), 1;
}
}
// check if player has money
if ( GetPlayerCash( playerid ) < 10000 ) {
return SendError( playerid, "You need $10,000 to create a battle royale lobby." );
}
new
lobbyid = BattleRoyale_CreateLobby( playerid );
// otherwise assume they are creating a new lobby
if ( lobbyid != ITER_NONE ) {
return SendError( playerid, "You cannot create a battle royale lobby at the moment" );
}
GivePlayerCash( playerid, -10000 );
p_battleRoyaleLobby[ playerid ] = lobbyid;
return BattleRoyale_EditLobby( playerid, lobbyid );
}
else if ( dialogid == DIALOG_BR_LOBBY_EDIT )
{
new lobbyid = p_battleRoyaleLobby[ playerid ];
if ( listitem == 3 ) // select an area
{
// TODO: select an area
}
else if ( listitem == 7 ) // select walking weapon mode
{
br_lobbyData[ lobbyid ] [ E_WALK_WEP ] = ! br_lobbyData[ lobbyid ] [ E_WALK_WEP ];
SendServerMessage( playerid, "You have set only walking weapons to %s.", bool_to_string( br_lobbyData[ lobbyid ] [ E_WALK_WEP ] ) );
return BattleRoyale_EditLobby( playerid, lobbyid );
}
else if ( listitem == 8 ) // select cac mode
{
if ( IsPlayerUsingSampAC( playerid ) ) {
br_lobbyData[ lobbyid ] [ E_CAC_ONLY ] = ! br_lobbyData[ lobbyid ] [ E_CAC_ONLY ];
SendServerMessage( playerid, "You have set CAC mode to %s.", bool_to_string( br_lobbyData[ lobbyid ] [ E_CAC_ONLY ] ) );
} else {
SendError( playerid, "You must have SA-MP CAC activated in order to enable this option." );
}
return BattleRoyale_EditLobby( playerid, lobbyid );
}
else
{
SetPVarInt( playerid, "editing_field", listitem );
return ShowPlayerDialog( playerid, DIALOG_BR_LOBBY_EDIT_ENTRY, DIALOG_STYLE_INPUT, ""COL_WHITE"Battle Royale", "Please enter a value for this field:", "Submit", "Back" );
}
}
else if ( dialogid == DIALOG_BR_LOBBY_EDIT_ENTRY )
{
if ( ! response ) {
return BattleRoyale_EditLobby( playerid, p_battleRoyaleLobby[ playerid ] );
}
new lobbyid = p_battleRoyaleLobby[ playerid ];
new editing_field = GetPVarInt( playerid, "editing_field" );
switch ( editing_field )
{
// lobby name
case 0:
{
new
name[ 24 ];
if ( sscanf( inputtext, "s[24]", name ) ) SendError( playerid, "You must enter a valid name." );
else if ( 3 <= strlen( name ) < 24 ) SendError( playerid, "You must enter a name between 3 and 24 characters." );
else
{
strcpy( br_lobbyData[ lobbyid ] [ E_NAME ], name );
return BattleRoyale_EditLobby( playerid, lobbyid );
}
}
// lobby pw
case 1:
{
new
password[ 5 ];
if ( sscanf( inputtext, "s[24]", password ) )
{
erase( br_lobbyData[ lobbyid ] [ E_PASSWORD ] );
SendServerMessage( playerid, "Password for this lobby has been reset." );
return BattleRoyale_EditLobby( playerid, lobbyid );
}
else if ( strlen( password ) >= 5 ) SendError( playerid, "You must enter a password between 1 and 5 characters." );
else
{
strcpy( br_lobbyData[ lobbyid ] [ E_PASSWORD ], password );
return BattleRoyale_EditLobby( playerid, lobbyid );
}
}
// limit
case 2:
{
new
limit;
if ( sscanf( inputtext, "d", limit ) ) SendError( playerid, "You must enter a valid limit." );
else if ( ! ( 1 <= limit < BR_MAX_PLAYERS ) ) SendError( playerid, "You must enter a limit between 1 and %d", BR_MAX_PLAYERS );
else
{
br_lobbyData[ lobbyid ] [ E_LIMIT ] = limit;
return BattleRoyale_EditLobby( playerid, lobbyid );
}
}
// entry_fee
case 4:
{
new
entry_fee;
if ( sscanf( inputtext, "d", entry_fee ) ) SendError( playerid, "You must enter a valid entry fee." );
else if ( entry_fee <= 0 )
{
br_lobbyData[ lobbyid ] [ E_ENTRY_FEE ] = entry_fee;
SendServerMessage( playerid, "Password for this lobby has been reset." );
return BattleRoyale_EditLobby( playerid, lobbyid );
}
else if ( ! ( 0 < entry_fee <= 10000000 ) ) SendError( playerid, "You must enter a entry fee between $1 and $10,000,000." );
else
{
br_lobbyData[ lobbyid ] [ E_ENTRY_FEE ] = entry_fee;
return BattleRoyale_EditLobby( playerid, lobbyid );
}
}
// health
case 5:
{
new
Float: health;
if ( sscanf( inputtext, "f", health ) ) SendError( playerid, "You must enter a valid health value." );
else if ( ! ( 1.0 <= health <= 100.0 ) ) SendError( playerid, "You must enter a health value between 1 and 100." );
else
{
br_lobbyData[ lobbyid ] [ E_HEALTH ] = health;
return BattleRoyale_EditLobby( playerid, lobbyid );
}
}
// armour
case 6:
{
new
Float: armour;
if ( sscanf( inputtext, "f", armour ) ) SendError( playerid, "You must enter a valid armour value." );
else if ( ! ( 1.0 <= armour <= 100.0 ) ) SendError( playerid, "You must enter a armour value between 1 and 100." );
else
{
br_lobbyData[ lobbyid ] [ E_ARMOUR ] = armour;
return BattleRoyale_EditLobby( playerid, lobbyid );
}
}
}
return ShowPlayerDialog( playerid, DIALOG_BR_LOBBY_EDIT_ENTRY, DIALOG_STYLE_INPUT, ""COL_WHITE"Battle Royale", "Please enter a value for this field:", "Submit", "Back" );
}
return 1;
}
/* ** Functions ** */
static stock BattleRoyale_CreateLobby( playerid )
{
new
lobbyid = Iter_Free( battleroyale );
if ( lobbyid != ITER_NONE )
{
strcpy( br_lobbyData[ lobbyid ] [ E_NAME ], "Battle Royale Lobby" );
erase( br_lobbyData[ lobbyid ] [ E_PASSWORD ] );
br_lobbyData[ lobbyid ] [ E_LIMIT ] = 6;
br_lobbyData[ lobbyid ] [ E_AREA_ID ] = 0;
br_lobbyData[ lobbyid ] [ E_ENTRY_FEE ] = 0;
br_lobbyData[ lobbyid ] [ E_HOST ] = playerid;
br_lobbyData[ lobbyid ] [ E_STATUS ] = E_STATUS_SETUP;
br_lobbyData[ lobbyid ] [ E_ARMOUR ] = 100.0;
br_lobbyData[ lobbyid ] [ E_HEALTH ] = 0.0;
br_lobbyData[ lobbyid ] [ E_WALK_WEP ] = false;
br_lobbyData[ lobbyid ] [ E_CAC_ONLY ] = false;
}
return lobbyid; // create lobby dialog
}
static stock BattleRoyale_EditLobby( playerid, lobbyid )
{
if ( ! BR_IsValidLobby( lobbyid ) ) {
return 0;
}
// header
szLargeString = ""COL_WHITE"Lobby Setting\t"COL_WHITE"Value\n";
for ( new i = 0; i < sizeof( br_lobbyData ); i ++ )
{
format(
szLargeString, sizeof( szLargeString ),
"%sLobby Name\n"COL_GREY"%s\n" \
"Password\n"COL_GREY"%s\n" \
"Player Limit\n"COL_GREY"%d\n" \
"Area\n"COL_GREY"%s\n" \
"Entry Fee\n"COL_GREEN"%s\n" \
"Health\t"COL_GREY"%0.2f%%\n" \
"Armour\t"COL_GREY"%0.2f%%\n" \
"Running Weapons Only\t%s\n",
"CAC Only\t%s\n",
szLargeString,
br_lobbyData[ lobbyid ] [ E_NAME ],
br_lobbyData[ lobbyid ] [ E_PASSWORD ],
br_lobbyData[ lobbyid ] [ E_LIMIT ],
br_areaData[ br_lobbyData[ lobbyid ] [ E_AREA_ID ] ] [ E_NAME ],
cash_format( br_lobbyData[ lobbyid ] [ E_ENTRY_FEE ] ),
br_lobbyData[ lobbyid ] [ E_HEALTH ],
br_lobbyData[ lobbyid ] [ E_ARMOUR ],
br_lobbyData[ lobbyid ] [ E_WALK_WEP ] ? ( COL_GREEN # "YES" ) : ( COL_RED # "NO" ),
br_lobbyData[ lobbyid ] [ E_CAC_ONLY ] ? ( COL_GREEN # "YES" ) : ( COL_RED # "NO" )
);
}
return ShowPlayerDialog( playerid, DIALOG_BR_LOBBY_EDIT, DIALOG_STYLE_TABLIST_HEADERS, ""COL_WHITE"Battle Royale", szLargeString, "Select", "Close" );
}
static stock BattleRoyale_JoinLobby( playerid, lobbyid )
{
// TODO:
return 1;
}
static stock BattleRoyale_ShowLobbies( playerid )
{
// set the headers
szLargeString = ""COL_WHITE"Lobby Name\tHost\tPlayers\tEntry Fee\n";
// format dialog
foreach ( new l : battleroyale )
{
format(
szLargeString, sizeof( szLargeString ),
"%s%s\t%s\t%d / %d\t%s\n",
szLargeString,
br_lobbyData[ l ] [ E_NAME ],
IsPlayerConnected( br_lobbyData[ l ] [ E_HOST ] ) ? ( ReturnPlayerName( br_lobbyData[ l ] [ E_HOST ] ) ) : ( "N/A" ),
Iter_Count( battleroyaleplayers[ l ] ),
br_lobbyData[ l ] [ E_LIMIT ],
cash_format( br_lobbyData[ l ] [ E_ENTRY_FEE ] )
);
}
// make final option to create lobby
format( szLargeString, sizeof( szLargeString ), COL_PURPLE # "Create Lobby\t \t"COL_PURPLE"$10,000\t"COL_PURPLE">>>" );
return ShowPlayerDialog( playerid, DIALOG_BR_LOBBY, DIALOG_STYLE_TABLIST_HEADERS, ""COL_WHITE"Battle Royale", szLargeString, "Select", "Close" );
}
stock BattleRoyale_RemovePlayer( playerid )
{
new
lobbyid = p_battleRoyaleLobby[ playerid ];
if ( lobbyid != BR_INVALID_LOBBY )
{
// unset player variables from the match
p_battleRoyaleLobby[ playerid ] = BR_INVALID_LOBBY;
// perform neccessary operations/checks on the lobby
Iter_Remove( battleroyaleplayers[ lobbyid ], playerid );
BattleRoyale_CheckPlayers( lobbyid );
}
return 1;
}
static stock BattleRoyale_CheckPlayers( lobbyid )
{
if ( BR_IsValidLobby( lobbyid ) && Iter_Count( battleroyaleplayers[ lobbyid ] ) <= 0 )
{
return BattleRoyale_DestroyLobby( lobbyid );
}
return 0;
}
static stock BattleRoyale_DestroyLobby( lobbyid )
{
// TODO:
return 1;
}
static stock BR_IsValidLobby( lobbyid ) {
return 0 <= lobbyid < BR_MAX_LOBBIES && Iter_Contains( battleroyale, lobbyid );
}