Duel System

Started by Maximiliano, Oct 12, 2019, 06:15 PM

Previous topic - Next topic

Maximiliano

Commands: /newduel , /duel

Any questions, suggestions or constructive criticisms can be left in the comments, in advance, thank you very much.

Review: https://www.youtube.com/watch?v=DcVRFbofSsE&feature=youtu.be
Server Side:
[spoiler]
Put in OnScriptLoad:
[noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae]dofile("scripts/_DuelSystem.nut");
[/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae]
Put in OnPlayerPart:
[noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae] if( Duels[player.World] && ( Duels[player.World].Player1.Name == player.Name || Duels[player.World].Player2.Name == player.Name ) )
{
DuelSystem.EndDuel(player.World);
}

if( Invitations[player.ID] && Invitations[player.ID].Accepted == false ) DuelSystem.DenyInvitation(player, "Quit");
[/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae]

Put in OnPlayerCommand:
[noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae]if ( cmd.tolower() == "newduel" || cmd.tolower() == "duel" ) DuelSystem.onPlayerCommand( player, cmd.tolower(), text )[/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae]
Put in OnPlayerKill:
[noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae] if( Duels[player.World] && ( Duels[player.World].Player1.Name == player.Name || Duels[player.World].Player2.Name == player.Name ) )
{
DuelSystem.AddKill(player.Team, player.World);
}
[/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae]

Put in onClientScriptData:
[noae][noae][noae][noae][noae]local string = Stream.ReadString();
switch ( string )
{
case "DuelDeny":
{
onPlayerCommand( player , "duel", "deny");
}
break;

case "DuelAccept":
{
onPlayerCommand( player , "duel", "accept");
}
break;
}
[/noae][/noae][/noae][/noae][/noae]

Put in onPlayerRequestClass:
[noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae] if( Duels[player.World] && ( Duels[player.World].Player1.Name == player.Name || Duels[player.World].Player2.Name == player.Name ) )
{
player.Spawn();
DuelSystem.Respawn(player);
}
[/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae]

Put in OnPlayerSpawn:
[noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae] if( Duels[player.World] && ( Duels[player.World].Player1.Name == player.Name || Duels[player.World].Player2.Name == player.Name ) )
{
player.Spawn();
DuelSystem.Respawn(player);
}
[/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae]
Put at the end of the main.nut:

[noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae]function GetTok(string, separator, n, ...)
{
 local m = vargv.len() > 0 ? vargv[0] : n,
    tokenized = split(string, separator),
    text = "";
 if (n > tokenized.len() || n < 1) return null;
 for (; n <= m; n++)
 {
  text += text == "" ? tokenized[n-1] : separator + tokenized[n-1];
 }
 return text;
}

function SendDataToClient( player, ... )
{
    if( vargv[0] )
    {
        local     byte = vargv[0],
                len = vargv.len();
               
        if( 1 > len ) devprint( "ToClent <" + byte + "> No params specified." );
        else
        {
            Stream.StartWrite();
            Stream.WriteByte( byte );

            for( local i = 1; i < len; i++ )
            {
                switch( typeof( vargv[i] ) )
                {
                    case "integer": Stream.WriteInt( vargv[i] ); break;
                    case "string": Stream.WriteString( vargv[i] ); break;
                    case "float": Stream.WriteFloat( vargv[i] ); break;
                }
            }
           
            if( player == null ) Stream.SendStream( null );
            else if( typeof( player ) == "instance" ) Stream.SendStream( player );
            else devprint( "ToClient <" + byte + "> Player is not online." );
        }
    }
    else devprint( "ToClient: Even the byte wasn't specified..." );
}
[/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae]

Create a file .nut called _DuelSystem with the following code:
PasteBin: https://pastebin.com/RaBqihk2

[spoiler]
[noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae][noae]Duels <- array( 3000, null ); //This Array will store the duels data
Invitations <- array( GetMaxPlayers(), null );//This Array will store the invitatios data
 
class DuelClass //This data will be saved in the duels array.
{
Player1 = null;
Player2 = null;
Player1Kills = 0;
Player2Kills = 0;
MaxKills = 0;
}
 
DuelSystem <- {
 
    //Function responsible for sending requests for duels
    function SendInvitation(player, player2, KillsToWin)
    {
        MessagePlayer("[#81F79F]You have received a duel invitation from the player [#FF5733]"+ player.Name +"[#81F79F]. You must kill him [#FF5733]"+KillsToWin+ " [#81F79F]times to win", player2);
        MessagePlayer("[#81F79F]You have sent the invitation to a duel to the player [#FF5733]"+ player2.Name +"[#81F79F]. Kills to Win: [#FF5733]"+ KillsToWin +"[#81F79F].", player);
       
        Invitations[player.ID] =
        {
            Sent = player2
            Kills = KillsToWin
            InvitedBy = player
            Accepted = false
        };
 
        Invitations[player2.ID] =
        {
            Sent = player
            Kills = KillsToWin
            InvitedBy = player
            Accepted = false
        };
 
        SendDataToClient( player2, 0x02, player.Name );
    }
 
    //Function responsible for denying requests for duels
    function DenyInvitation(player, reason)
    {
        local plr = Invitations[player.ID].Sent;
       
        MessagePlayer(player+ " [#81F79F]canceled the duel invitation. Reason: [#FF5733]"+reason+".", plr);
        if (reason != "Quit") MessagePlayer("[#81F79F]You have successfully canceled the duel", player); //


        SendDataToClient( plr, 0x02, "cancel");
        Invitations[plr.ID] = null;
        Invitations[player.ID] = null;
    }
 
    //This function is executed when accepting duels
    function StartDuel(player1, player2, kills)
    {
        local World = (rand() % 3000).tointeger();
       
        Duels[ World ] = DuelClass();
        Duels[World].Player1 = player1;
        Duels[World].Player2 = player2;
        Duels[World].MaxKills = kills;
       
        player1.World = World;
        player1.Pos = Vector(-1759.98, -193.022, 14.8683);
        player1.Team = 1;
 
        player2.World = World;
        player2.Team = 2;
        player2.Pos = Vector(-1763.34, -127.249, 14.8683);
 
        Invitations[player2.ID].Accepted = true;
        Invitations[player1.ID].Accepted = true;
        SayKills(World);
        Message("[#FF5733]" + player1.Name + "[#81F79F] has started a duel against [#FF5733]"+ player2.Name +"[#81F79F]. Kills to win: [#FF5733]"+ kills +"[#81F79F].");
    }
 
    function EndDuel(World)
    {
        local winner, loser, result;
       
        if( Duels[World].Player1Kills < Duels[World].Player2Kills )
        {
            winner = Duels[World].Player2.Name;
            loser = Duels[World].Player1.Name;
            result = Duels[World].Player2Kills +" - "+ Duels[World].Player1Kills;
        }
        else
        {
            winner = Duels[World].Player1.Name;
            loser = Duels[World].Player2.Name;
            result = Duels[World].Player1Kills +" - "+ Duels[World].Player2Kills;
        }
 
        local player1 = Duels[World].Player1;
        local player2 = Duels[World].Player2;
       
        SendDataToClient( player1, 0x03, "DuelEnd|DuelEnd|DuelEnd");
        SendDataToClient( player2, 0x03, "DuelEnd|DuelEnd|DuelEnd");
 
        player1.World = 0;
        player1.Select();
 
        player2.World = 0;
        player2.Select();
 
        Invitations[player1.ID] = null;
        Invitations[player2.ID] = null;
        Duels[World] = null;
 
       
        Message("[#FF5733]" + winner + " [#81F79F]won a duel to [#FF5733]"+ loser +"[#81F79F]. Result: [#FF5733]"+ result +".");
    }
 
    function AddKill(team, World)
    {
       if (team == 1)
       {
           Duels[World].Player1Kills++;
           DuelSystem.SayKills(World);
           if ( Duels[World].MaxKills <= Duels[World].Player1Kills ) DuelSystem.EndDuel(World);
       }
       else
       {
           Duels[World].Player2Kills++;
           DuelSystem.SayKills(World);
           if ( Duels[World].MaxKills <= Duels[World].Player2Kills ) DuelSystem.EndDuel(World);
       }
 
    }
 
   
    function SayKills(World)
    {
        local msg = Duels[World].Player1.Name+" "+ Duels[World].Player1Kills +"|"+ Duels[World].Player2Kills+" "+ Duels[World].Player2.Name;
        SendDataToClient( Duels[World].Player1, 0x03, msg + "|Kills to Win: " + Duels[World].MaxKills);
        SendDataToClient( Duels[World].Player2, 0x03, msg + "|Kills to Win: " + Duels[World].MaxKills);
    }
 
    function Respawn(player)
    {
       
        if ( Duels[player.World].Player1.Name == player.Name )
        {
            player.Pos = Vector(-1759.98, -193.022, 14.8683);
            player.Team = 1;
        }
        else
        {
            player.Pos = Vector(-1763.34, -127.249, 14.8683);
            player.Team = 2;
        }
    }
 
 
    // =========================== Commands ========================== //
 
    function onPlayerCommand(player, cmd, text)
    {
        if (cmd == "newduel")
        {
            if(!text) MessagePlayer("[#81F79F]/newduel Nick KillsToWin", player);
            else if ( !GetPlayer(GetTok(text, " ", 1)) ) MessagePlayer("[#81F79F]/newduel Nick KillsToWin", player);
            else if ( GetPlayer(GetTok(text, " ", 1)).Name == player.Name ) MessagePlayer("[#81F79F]You can't invite yourself.", player);
            else if ( !IsNum(GetTok(text, " ", 2)) ) MessagePlayer("[#81F79F]/newduel Nick KillsToWin", player);
            else if ( Invitations[ player.ID ] && Invitations[ player.ID ].Accepted == true) MessagePlayer("[#81F79F]You cannot create an invitation while in a duel.", player);
            else if ( Invitations[ player.ID ] ) MessagePlayer("[#81F79F]You have already created a grieving invitation.", player);
            else if ( Invitations[ GetPlayer(GetTok(text, " ", 1)).ID ] && Invitations[ GetPlayer(GetTok(text, " ", 1)).ID ].Accepted == true ) MessagePlayer("[#81F79F]He is participating in a duel.", player);
            else if ( Invitations[ GetPlayer(GetTok(text, " ", 1)).ID ] ) MessagePlayer("[#81F79F]He has already been invited to a duel", player);
            else
            {
               
                local kills = GetTok(text, " ", 2);
                local plr = GetPlayer(GetTok(text, " ", 1));
                DuelSystem.SendInvitation(player, plr, kills);
            }
        }
 
        else if (cmd == "duel")
        {
            if( !text ) MessagePlayer("[#81F79F]/duel accept/deny", player);
            else
            {
            local subcommand = GetTok(text, " ", 1);
            switch (subcommand.tolower())
                {
                    case "accept":
                    if ( !Invitations[ player.ID ] ) MessagePlayer("[#81F79F]Nobody has invited you to a duel.", player);
                        else if ( Invitations[ player.ID ] && Invitations[ player.ID ].InvitedBy.Name == player.Name ) MessagePlayer("[#81F79F]You cannot accept your own duel", player);
                    else if ( Invitations[ player.ID ] && Invitations[ player.ID ].Accepted == true) MessagePlayer("[#81F79F]You can't accept while you're in a duel.", player);
                    else DuelSystem.StartDuel(player, Invitations[ player.ID ].Sent, Invitations[ player.ID ].Kills.tointeger() );
                    break;
 
                    case "deny":
                    case "cancel":         
                    if ( !Invitations[ player.ID ] ) MessagePlayer("[#81F79F]Nobody has invited you to a duel.", player);
                    else if ( Invitations[ player.ID ] && Invitations[ player.ID ].Accepted == true) MessagePlayer("[#81F79F]You can't accept while you're in a duel.", player);
                    else if ( Invitations[ player.ID ] && Invitations[ player.ID ].InvitedBy.Name == player.Name ) DuelSystem.DenyInvitation(player, "Canceled");
                    else DuelSystem.DenyInvitation(player, "Denied.");
                    break;
                    default:
                    MessagePlayer("[#81F79F]/duel accept/deny", player);
                }
            }
 
        }
 
    }
 
};
[/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae][/noae]
[/spoiler]
[/spoiler]

Client-Side:
[spoiler]
Put in Server::ServerData:
[noae][noae][noae][noae][noae][noae]    local type = stream.ReadByte();
    local string = stream.ReadString();
    switch( type )
    {
        case 0x02:
        {
            if(string == "cancel")
            {
                InvitationDuel.Menu = null;
                InvitationDuel.ButtonCancel = null;
                InvitationDuel.ButtonAccept = null;
            }
            else
            {
                GUI.SetMouseEnabled(true);
                InvitationDuel.Menu <- GUIWindow(VectorScreen(sX * 0.66, sY * 0.64), VectorScreen(sX * 0.28, sY * 0.160), Colour(0, 0, 0, 900), string + " has challenged you to a 10-kills duel");
                InvitationDuel.Menu.RemoveFlags( GUI_FLAG_WINDOW_RESIZABLE | GUI_FLAG_WINDOW_CLOSEBTN );
                InvitationDuel.Menu.FontFlags = ( GUI_FFLAG_BOLD );
 
                InvitationDuel.ButtonAccept = GUIButton( );
                InvitationDuel.ButtonAccept.Size = VectorScreen( 140, 50 );
                InvitationDuel.ButtonAccept.Colour = Colour( 89, 193, 43 );
                InvitationDuel.ButtonAccept.TextColour  = Colour( 0, 0, 0 );
                InvitationDuel.ButtonAccept.Pos = VectorScreen( sX * 0.0205, sY * 0.030);
                InvitationDuel.ButtonAccept.Text = "Accept";
                InvitationDuel.ButtonAccept.FontFlags = ( GUI_FFLAG_BOLD );

                InvitationDuel.ButtonCancel = GUIButton( );
                InvitationDuel.ButtonCancel.Size = VectorScreen( 140, 50 );
                InvitationDuel.ButtonCancel.Colour = Colour( 219, 0, 0 );
                InvitationDuel.ButtonCancel.TextColour  = Colour( 0, 0,0 );
                InvitationDuel.ButtonCancel.Pos = VectorScreen( sX * 0.1419, sY * 0.030 );
                InvitationDuel.ButtonCancel.Text = "Decline";
                InvitationDuel.ButtonCancel.FontFlags = ( GUI_FFLAG_BOLD );
 
                InvitationDuel.Menu.AddChild(InvitationDuel.ButtonAccept);
                InvitationDuel.Menu.AddChild(InvitationDuel.ButtonCancel);
            }
        }
        break;

        case 0x03:
        {
            local scores = split(string, "|");
            local Player1 = scores[0];
            local Player2 = scores[1];
            local KillsToWin = scores[2];
            if(Player1 != "DuelEnd")
            {
                DuelScore.Player1 = GUILabel(VectorScreen(sX * 0.76, sY * 0.25),Colour(255,170,0), Player1 + " - " + Player2);
                DuelScore.KillsToWin = GUILabel(VectorScreen(sX * 0.76, sY * 0.29),Colour(255,170,0), KillsToWin);

                DuelScore.Player1.FontSize = 20;
                DuelScore.KillsToWin.FontSize = 20;

                DuelScore.Player1.FontFlags = ( GUI_FFLAG_BOLD );
                DuelScore.KillsToWin.FontFlags = ( GUI_FFLAG_BOLD );

                DuelScore.Player1.TextAlignment = ( GUI_ALIGN_LEFT );
                DuelScore.KillsToWin.TextAlignment = ( GUI_ALIGN_LEFT );
            }
            else
            {
                DuelScore.Player1 = null;
                DuelScore.KillsToWin = null;
            }
        }
        break;


        default:
        break;
    }
[/noae][/noae][/noae][/noae][/noae][/noae]

Put in GUI::ElementRelease:
[noae][noae][noae][noae][noae][noae]switch (element)
    {
        case InvitationDuel.ButtonAccept:
        {
            local Data = Stream();
            Data.WriteString(" DuelAccept");
            Server.SendData(Data);
            GUI.SetMouseEnabled(false);
            InvitationDuel.Menu = null;
            InvitationDuel.ButtonCancel = null;
            InvitationDuel.ButtonAccept = null;
        }
        break;

        case InvitationDuel.ButtonCancel:
        {

            local Data = Stream();
            Data.WriteString(" DuelDeny");
            Server.SendData(Data);
            GUI.SetMouseEnabled(false);
            InvitationDuel.Menu = null;
            InvitationDuel.ButtonCancel = null;
            InvitationDuel.ButtonAccept = null;
        }
        break;
    }
[/noae][/noae][/noae][/noae][/noae][/noae]
Put at the end of the main.nut (CLIENT SIDE):
[noae][noae][noae][noae][noae][noae]InvitationDuel <-
{
    UserName = null
    Menu = null
    ButtonAccept = null
    ButtonCancel = null
}

DuelScore <-
{
    Menu = null
    Player1 = null
    Player2 = null
    KillsToWin = null
}

sX <- GUI.GetScreenSize().X;
sY <- GUI.GetScreenSize().Y;
[/noae][/noae][/noae][/noae][/noae][/noae]
[/spoiler]

Sebastian

#1
Nice and easy.
Would look better with GUI contribution when about invitation with accept/decline and score

Maximiliano

Quote from: Sebastian on Oct 13, 2019, 08:02 AMNice and easy.
Would look better with GUI contribution when about invitation with accept/decline and score

The system now has a GUI, Thanks for your suggestion ;D.

https://www.youtube.com/embed/DcVRFbofSsE?

Sebastian

#3
That's just awesome! That's how a duel system should look like, in vcmp 0.4

Gulk2

I'll use it but mod it, to give the gui vice city style. Nice job

Maximiliano

#5
Quote from: Sebastian on Oct 13, 2019, 02:38 PMThat's just awesome! That's how a duel system should look like, in vcmp 0.4
Woow, irony? xd, Thanks anyway ;D

Quote from: Gulk2 on Oct 13, 2019, 08:03 PMI'll use it but mod it, to give the gui vice city style. Nice job
What style would that be?
I will gladly change it, but I need an example of the gui what you want.

Gulk2

This font is the official one used in VC for subtitles,
https://fonts2u.com/sf-arborcrest-heavy.font
VC contains other fonts too.

Saiyan Attack

what if sender decide to cancel their request? i think you forgot about it?!

Maximiliano

Quote from: Saiyan Attack on Oct 18, 2019, 08:44 PMwhat if sender decide to cancel their request? i think you forgot about it?!


I think you haven't seen the video, the system has to accept and deny duels. '-'

Saiyan Attack

i have seen it and i have also seen your command /duel cancel - that can use only for those user who sent request of duel ... and i want to tell you about when sender cancel their duel request and then the popup window should remove automatically ....

Maximiliano

Quote from: Saiyan Attack on Oct 19, 2019, 01:37 AMi have seen it and i have also seen your command /duel cancel - that can use only for those user who sent request of duel ... and i want to tell you about when sender cancel their duel request and then the popup window should remove automatically ....

Code updated. Thanks for notifying xD

=RK=MarineForce

Thanks bro i really needed it <3

 i m making Battle royale server if you help me its cool :X

Maximiliano

Quote from: =RK=MarineForce on Nov 09, 2019, 07:49 AMThanks bro i really needed it <3
You're welcome ;D

Quote from: =RK=MarineForce on Nov 09, 2019, 07:49 AMi m making Battle royale server if you help me its cool :X

Sure, no problem, talk to me in discord ;).
My discord is: (ARG)Maximiliano#3058