Help with making a morale system

So I got an idea for my upcoming project is to create a “Morale system”. Basically how this work is when your close to your teammate (maximum 3 players in order for it to take affect) or have specific actions (such as getting a kill, near the base, etc), the morale will go up and will boost your stats. If your morale goes down, the stats will be decrease. Those stats would be the weapon’s accuracy, range, etc. I know I will have to use the magnitude and get the character, but I don’t know how to get a specific amount of players. Any help is appreciated!

3 Likes

Wouldn’t you just have a function getSurroundingPlayers(player, distance) then loop through all the players (game:GetService("Players"):GetChildren()) and do magnitude checks for each then return the sum and then use that function when the player gets a kill or something.

In this post, what are you exactly asking, are you asking how to make your scripts detect the amount of people around the given person? If not please correct me.

Yes I am planning to do that, but I don’t know how to get specific players (like I only want to get 3, 4 etc players)

Is that possible? If yes, where do I need to put it?

Where ever you need to get the number of players. That might be when the player gets a kill or, if you need the player count constantly, constantly (probably delay that, maybe RunService.Heartbeat or task.wait(n)).

I don’t understand much about what you said, yes I will need to get the amount of players around me using framerate but I don’t understand about the magnidute part you said above. Could you give me an example of that if you don’t mind?

So first, you need to loop through the players. You can get a table of the players by getting the children of Players:
game:GetService("Players"):GetChildren()
Now we can loop through that with ipairs, because the table is an array (it uses numbers as keys, ex: {[1]=player2, [2]=player1}):

for index, player in ipairs(game:GetService("Players"):GetChildren()) do
    --code to run on each player here
end

Then we need to make a sum variable to keep track of the number of players:

local sum = 0
for index, player in ipairs(game:GetService("Players"):GetChildren()) do
    --code to run on each player here
end

Now we need to find if the player is close enough. How we do that is we subtract the main player’s position from the other player’s position.

First we learn how to get the player’s character:

local player --Equals the player

local character = player.Character
if not character then
    --handle there not being a character
end

The distance between two points is:

--Difference between the two points then the length of the difference
(positionOne - positionTwo).Magnitude

Then we use that stuff and add the function stuff and get this:

--The function stuff
local function getClosePlayers(mainPlayer, distance)
    local sum = 0

    --Get the main player's character and it's position
    local mainCharacter = mainPlayer.Character
    if not mainCharacter then
        return 0 -- if the main player has no character there are zero surrounding players. You can also return nil and handle it somewhere else.
    end
    local mainPlayerPosition = mainCharacter.HumanoidRootPart.Position

    for index, otherPlayer in ipairs(game:GetService("Players"):GetChildren()) do
        --Get the other player's character and it's position
        local otherCharacter = otherPlayer.Character
        if not otherCharacter then
            break --Goes to the next player b|c there is no character for this player
        end
        local otherPlayerPosition = otherCharacter.HumanoidRootPart.Position

        -- We find the difference between the positions, then we find the length of the difference
        -- then we check if the distance between the players is within the distance if it is we add
        -- to the sum
        if (mainPlayerPosition - otherPlayerPosition).Magnitude < distance then
            sum = sum + 1
        end 
    end
    return sum --Output the sum so you can use it ;)
end
2 Likes

It actually works! Thank you very much. But is there a way to update the player’s position without using RunService.RenderStepped or RunService.Heartbeat? Or should I make a while loop inside a thread and run it?
Example of what I mean:

local sum
spawn(function()
    while wait(.5) do
        sum = getClosePlayers()
    end
end)
-- Functions above here will deploy and use the sum variable

And also do you know how to make so when they are in a formation (such as they’re all in a straight line, or they’re in a group (not in a line but it kinda like when your spreading out)), the stats will behave differently (Sorry for asking you too much).

If you’re worried about performance, unless you have 100+ players in a server, it shouldn’t drop performance. I would recommend using Heartbeat.

Aye, I never know the difference between Heartbeat and RenderStepped (probably Heartbeat is for real-time game framerate) but I’ll look into it!

The difference is that Heartbeat runs after physics and rendering, while RenderStepped runs before rendering and will actually block rendering until it is finished. For this reason, don’t use RenderStepped unless it impacts rendering, like updating viewmodels or the camera.