[SNIPPET] Simple skin galery.

Started by ., Mar 30, 2015, 12:19 PM

Previous topic - Next topic

.

I implemented this a while ago for someone who needed a customizable class system. But since he didn't needed it after all, I decided to make it public. So that others could use it if they want to. This is exactly what the title says. But first the code:
// --------------------------------------------------------------------------------------
_SkinSet <- [];
_SkinNav <- null;

// --------------------------------------------------------------------------------------
enum _STATE {
    Playing = 0,
    SkinSel = 1
}

// --------------------------------------------------------------------------------------
_Key_Left <- null;
_Key_Right <- null;
_Key_Up <- null;
_Key_Down <- null;
_Key_Enter <- null;

// --------------------------------------------------------------------------------------
class _Client
{
    // ----------------------------------------------------------------------------------
    function constructor(i_player)
    {
        // See the the specified argument is actually a player instance
        if (typeof i_player != "instance") {
            // Print some debugging information
            print("Cannot create a Client instance from an invalid player instance");
            // No point in going forward now
            return null;
        } else {
            // Store the player instance
            Instance = i_player
        }
    }
    // ----------------------------------------------------------------------------------
    function Connect()
    {
        // Initialization...
    }
    // ----------------------------------------------------------------------------------
    function Disconnect(reason)
    {
        // Deinitialization...
    }
    // ----------------------------------------------------------------------------------
    function SkinSelect()
    {
        // Do not allow the player to move during this time
        Instance.Frozen = true;
        // Make the player invisible during the skin selection
        Instance.SetAlpha(0, 0);
        // Save the current player position
        Position = Instance.Pos;
        // Move the player to an isolated area for the skin sellection
        Instance.Pos = Vector(-922.0, 797.5, 20.0);
        // Position the player camera to view the available skins
        Instance.SetCameraPos(Vector(-920.0, 797.5, 26.0), Vector(-900.0, 797.5, 20.0));
        // Set the player in the skin selection state
        _CLIENTS[Instance.ID].State = _STATE.SkinSel;
        // Display the first set of skins
        _SkinSet[SkinSel.SET][SkinSel.IDX].Spr.ShowForPlayer(Instance);
        _SkinSet[SkinSel.SET][SkinSel.IDX].Tex.ShowForPlayer(Instance);
        // Display information about the skin navigation keys
        _SkinNav.ShowForPlayer(Instance);
    }
    // ----------------------------------------------------------------------------------
    function Spawn()
    {
        // Hide the information about the skin navigation keys
        _SkinNav.HideFromPlayer(Instance);
        // Hide the skin selection
        _SkinSet[SkinSel.SET][SkinSel.IDX].Spr.HideFromPlayer(Instance);
        _SkinNav.HideFromPlayer(Instance);
        // Apply the selected player skin
        Instance.Skin = _SkinSet[SkinSel.SET][SkinSel.IDX].ID;
        // Restore the player position
        Instance.Pos = Position;
        // Restore the player camera
        Instance.RestoreCamera();
        // Unfrease the player
        Instance.Frozen = false;
        // Make the player visible again
        Instance.SetAlpha(255, 0);
    }
    // ----------------------------------------------------------------------------------
    function KeyPress(bind_id)
    {
        // See if the player is in the skin selection state
        if (State == _STATE.SkinSel) {
            // Hide the current sprite so we can show the next one
            _SkinSet[SkinSel.SET][SkinSel.IDX].Spr.HideFromPlayer(Instance);
            _SkinSet[SkinSel.SET][SkinSel.IDX].Tex.HideFromPlayer(Instance);
            // See which key was pressed
            switch (bind_id)
            {
                case _Key_Left:
                    // Go to the previous skin in the set
                    SkinSel.IDX -= 1;
                    // Cycle back so we don't get out of bounds
                    if (SkinSel.IDX < 0) {
                        SkinSel.IDX = _SkinSet[SkinSel.SET].len()-1;
                    }
                break;
                case _Key_Right:
                    // Go to the next skin in the set
                    SkinSel.IDX += 1;
                    // Cycle back so we don't get out of bounds
                    if (SkinSel.IDX >= _SkinSet[SkinSel.SET].len()) {
                        SkinSel.IDX = 0;
                    }
                break;
                case _Key_Up:
                    // Go to the next set
                    SkinSel.SET += 1;
                    // Cycle back so we don't get out of bounds
                    if (SkinSel.SET >= _SkinSet.len()) {
                        SkinSel.SET = 0;
                    }
                break;
                case _Key_Down:
                    // Go to the previous set
                    SkinSel.SET -= 1;
                    // Cycle back so we don't get out of bounds
                    if (SkinSel.SET < 0) {
                        SkinSel.SET = _SkinSet.len()-1;
                    }
                break;
                case _Key_Enter:
                    // See if we have to skip th enter key once
                    if (SkinSel.ENT == true) {
                        // Don't skip the enter key next time
                        SkinSel.ENT = false;
                        // No point in going forward now
                        break;
                    }
                    // Allow the player to spawn with the selected skin
                    Spawn();
                    // Set the player in the playing state
                    _CLIENTS[Instance.ID].State = _STATE.Playing;
                break;
            }
            // See if the player is still in the skin selection
            if (State == _STATE.SkinSel) {
                // Display the currently selected sprite in the set
                _SkinSet[SkinSel.SET][SkinSel.IDX].Spr.ShowForPlayer(Instance);
                _SkinSet[SkinSel.SET][SkinSel.IDX].Tex.ShowForPlayer(Instance);
            }
        }
    }
    // ----------------------------------------------------------------------------------
    function KeyRelease(bind_id)
    {
   
    }
    // ----------------------------------------------------------------------------------
    Instance = null
    // ----------------------------------------------------------------------------------
    Position = null
    // ----------------------------------------------------------------------------------
    State = _STATE.Playing
    // ----------------------------------------------------------------------------------
    SkinSel = {SET = 0, IDX = 0, ENT = false}
}

// --------------------------------------------------------------------------------------
_CLIENTS <- [];

// --------------------------------------------------------------------------------------
function onServerStart()
{
    // Reserve enough space to hold the maximum number of Clients that the server can hold
    _CLIENTS = array(GetMaxPlayers());
    // Attempt to find any previously connected Clients in case of a script reload
    foreach (idx, inst in _CLIENTS) {
        // Attempt to find the player by it's unique identifier
        local i_player = FindPlayer(idx);
        // See if a valid player instance was found at this ID
        if (i_player != null) {
            // Create a Client instance for this player instance
            inst = _Client(i_player);
            // Allow the Client instance to initialize
            inst.Connect();
        }
    }

    // Bind to some generic keyboard buttons
    _Key_Left <- ::BindKey(true, 0x25, 0, 0); // Arrow Left
    _Key_Right <- ::BindKey(true, 0x27, 0, 0); // Arrow Right
    _Key_Up <- ::BindKey(true, 0x26, 0, 0); // Arrow Up
    _Key_Down <- ::BindKey(true, 0x28, 0, 0); // Arrow Down
    _Key_Enter <- ::BindKey(true, 0x0D, 0, 0); // Enter, Return

    // Create the skin navigation info textdraw
    _SkinNav <- ::CreateTextdraw("Left|Right: change skin, Up|Down: change set, Enter: select",
                                    200, 124, 0xFF00CED1);

    // Create the first set of skins
    _SkinSet.append([
        {
            Spr = ::CreateSprite("Skin_0.png", 24, 112, 0, 0, 0.0, 255),
            Tex = ::CreateTextdraw(::format("Set: Basic Skin: %s",
                                    ::GetSkinName(0)), 200, 148, 0xFF1E90FF),
            ID = 0,
            CLS = -1 // Create a custom class here
        },
        {
            Spr = ::CreateSprite("Skin_9.png", 24, 112, 0, 0, 0.0, 255),
            Tex = ::CreateTextdraw(::format("Set: Basic Skin: %s",
                                    ::GetSkinName(9)), 200, 148, 0xFF1E90FF),
            ID = 9,
            CLS = -1 // Create a custom class here
        },
        {
            Spr = ::CreateSprite("Skin_10.png", 24, 112, 0, 0, 0.0, 255),
            Tex = ::CreateTextdraw(::format("Set: Basic Skin: %s",
                                    ::GetSkinName(10)), 200, 148, 0xFF1E90FF),
            ID = 10,
            CLS = -1 // Create a custom class here
        }
    ]);

    // Create the second set of skins
    _SkinSet.append([
        {
            Spr = ::CreateSprite("Skin_11.png", 24, 112, 0, 0, 0.0, 255),
            Tex = ::CreateTextdraw(::format("Set: Clan Skin: %s",
                                    ::GetSkinName(11)), 200, 148, 0xFF1E90FF),
            ID = 11,
            CLS = -1 // Create a custom class here
        },
        {
            Spr = ::CreateSprite("Skin_12.png", 24, 112, 0, 0, 0.0, 255),
            Tex = ::CreateTextdraw(::format("Set: Clan Skin: %s",
                                    ::GetSkinName(12)), 200, 148, 0xFF1E90FF),
            ID = 12,
            CLS = -1 // Create a custom class here
        },
        {
            Spr = ::CreateSprite("Skin_13.png", 24, 112, 0, 0, 0.0, 255),
            Tex = ::CreateTextdraw(::format("Set: Clan Skin: %s",
                                    ::GetSkinName(13)), 200, 148, 0xFF1E90FF),
            ID = 13,
            CLS = -1 // Create a custom class here
        }
    ]);

    // Create the third set of skins
    _SkinSet.append([
        {
            Spr = ::CreateSprite("Skin_16.png", 24, 112, 0, 0, 0.0, 255),
            Tex = ::CreateTextdraw(::format("Set: Premium Skin: %s",
                                    ::GetSkinName(16)), 200, 148, 0xFF1E90FF),
            ID = 16,
            CLS = -1 // Create a custom class here
        },
        {
            Spr = ::CreateSprite("Skin_28.png", 24, 112, 0, 0, 0.0, 255),
            Tex = ::CreateTextdraw(::format("Set: Premium Skin: %s",
                                    ::GetSkinName(28)), 200, 148, 0xFF1E90FF),
            ID = 28,
            CLS = -1 // Create a custom class here
        },
        {
            Spr = ::CreateSprite("Skin_89.png", 24, 112, 0, 0, 0.0, 255),
            Tex = ::CreateTextdraw(::format("Set: Premium Skin: %s",
                                    ::GetSkinName(89)), 200, 148, 0xFF1E90FF),
            ID = 89,
            CLS = -1 // Create a custom class here
        }
    ]);
}

// --------------------------------------------------------------------------------------
function onServerStop()
{
    // Attempt to deinitialize all connected players from the server
    foreach (idx, client in _CLIENTS) {
        // See if there was any Client instance in this slot
        if (client != null) {
            // Allow the Client instance to deinitialize
            client.Disconnect();
            // Clear the slot
            _CLIENTS[i_player.ID] = null;
        }
    }
    // Clear the skin sets
    foreach (set in _SkinSet) {
        foreach (skin in set) {
            skin.Spr.Delete();
            skin.Tex.Delete();
        }
    }
}

// --------------------------------------------------------------------------------------
function onPlayerJoin(i_player)
{
    // Create a Client instance for this player instance
    _CLIENTS[i_player.ID] = _Client(i_player);
    // Allow the newlly created Client instance to initialize
    _CLIENTS[i_player.ID].Connect();
    // Force the player to spawn and enter the skin selection
    i_player.Spawn();
}

// --------------------------------------------------------------------------------------
function onPlayerPart(i_player, reason)
{
    // Allow the Client instance to deinitialize
    _CLIENTS[i_player.ID].Disconnect(reason);
    // Clear the slot for other Clients
    _CLIENTS[i_player.ID] = null;
}

// --------------------------------------------------------------------------------------
function onPlayerSpawn(i_player)
{
    _CLIENTS[i_player.ID].SkinSelect();
}

// --------------------------------------------------------------------------------------
function onKeyDown(i_player, bind_id)
{
    // Allow the Client to process the event
    _CLIENTS[i_player.ID].KeyPress(bind_id);
}

// --------------------------------------------------------------------------------------
function OnKeyBindUp(i_player, bind_id)
{
    // Allow the Client to process the event
    _CLIENTS[i_player.ID].KeyRelease(bind_id);
}

// --------------------------------------------------------------------------------------
function onPlayerCommand(i_player, cmd, args)
{
    switch (cmd)
    {
        // ------------------------------------------------------------------------------
        case "skinsel":
            // When using the command we must skip the enter key once
            _CLIENTS[i_player.ID].SkinSel.ENT = true;
            // Enter the skin selection mode
            _CLIENTS[i_player.ID].SkinSelect();
        break;
    }
}

Save the code above in a simple script file and set that as your game mode. Then Download these sample images used by the script and extract them in your server path as well. The images should end up in the storage folder.

As soon as you wish to spawn, you'll be teleported to a remote location and asked to select a skin. More explained bellow.

Skins are grouped into sets. So that you can have sets of skins like:
  • Basic: For example, these could be free for all
  • Clan: These could be only for specific clans
  • Premium: These can be only for premium/vip members.
  • etc.

To cycle through the sets of skins, use the up and down arrows. To cycle through the skins of a set, use the left and right arrows. Once you've decided on your skin, use enter key to select. To go to the skin selection menu, use the follwing command: /skinsel

You can customize this in many ways. Have certain weapons, health, armour etc. per skin. Your imagination is the limit.

Just to be clear. This is just an example of how something like this could implemented and to give an idea to anyone who wants to have a set of images that could identify certain things in a script. Which is why the word "gallery" is in the title.


.

Sebastian

I suggest you to specify the number of textdraws used, because it may go over the textdraws' limit in some servers.

Quote from: VC:MP WikiMAX_TEXTDRAWS 256

Anyway, the idea sounds good. I hope I will test it soon, and come with an edit. 8)



OFF: No offence, but there is no need to write [SNIPPET] in title, since you posted this script in the Snippet Showroom. :D

.

#2
Quote from: sseebbyy on Mar 30, 2015, 01:20 PMOFF: No offence, but there is no need to write [SNIPPET] in title, since you posted this script in the Snippet Showroom. :D

You're probably right. I have this nasty habit label most of my stuff :D

Quote from: sseebbyy on Mar 30, 2015, 01:20 PM
Quote from: VC:MP WikiMAX_TEXTDRAWS 256

That's one of the issues I've encountered. But there's no fixed number of text-draws. These are added by user and he's in charge of accounting them :D
.

Sebastian

Quote from: S.L.C on Mar 30, 2015, 01:22 PMThat's one of the issues I've encountered. But there's no fixed number of text-draws. These are added by user and he's in charge of accounting them :D

I was talking only about your example. :P
I believe that it's users will use it as it is left, for a while.
( maybe they will just change the pictures, but leaving the same name, for it to fit with the script, haha )

DizzasTeR

I have the exact same thing but its for vehicles. :D