Page cover image

๐Ÿ’ญmad-thoughts

Turn ๐Ÿ’ฌ notifications into ๐Ÿ“– narratives.

Tebex Package

Introduction

A thought bubble notification system designed for immersive roleplay.

In traditional FiveM servers, notifications often break immersion with meta-gaming information: "Not enough police online" or "You don't have the required skill level." These messages force players to acknowledge game mechanics rather than staying in character.

mad-thoughts transforms this experience by displaying notifications as the character's inner thoughts. When a player encounters a locked door they can't pick, instead of seeing "Lockpicking skill too low," they'll think: "This lock looks too complex for me..."


Preview

Watch the preview video to see mad-thoughts in action, or view the screenshots below.

mad-thoughts Preview Video
Screenshots


Features & Benefits

  • ๐Ÿ’ญ Immersive Thought Bubbles: Displays character thoughts above the player's head

  • ๐ŸŽจ Rich Customization: Icons, colors, and timing options

  • ๐Ÿ‘‰ Scenario System: Automatic thoughts based on gameplay situations

  • ๐Ÿ’ฌ Message Variety: Random selection prevents repetition

  • ๐Ÿ“ Location Awareness: Thoughts trigger in specific areas

  • ๐Ÿ” Sequential Thoughts: Create story-driven thought chains

  • ๐ŸŒ Server-Wide Thoughts: Send thoughts to all connected players

  • ๐Ÿ’ป Developer-Friendly: Simple exports for easy implementation

โญ Perfect For:

  • Skill check feedback that doesn't break immersion

  • Subtle environmental storytelling

  • Replacing meta-gaming notifications with in-character thoughts

  • Adding personality and depth to player characters

  • Creating a more cinematic and immersive experience

Transform your server's notification system from immersion-breaking text to character-driven thoughts. Your players will feel more connected to their characters, and your world will feel more authentic and alive.


Scenarios & Locations

The real power of mad-thoughts comes from automatic triggers that create thoughts based on specific conditions. These features transform passive notifications into immersive character experiences. While the resource includes several pre-built examples, you're encouraged to create ones tailored to your server.


Scenario-Based Thoughts

Scenarios are condition-driven thoughts that monitor your player's state and environment. When specific conditions are met, they automatically trigger appropriate thoughts. Common scenario types include:

  • Health & Status: Low health, stress levels, character needs

  • Environmental: Weather conditions, time of day, underwater

  • Action-Based: Swimming, running, combat situations

  • Character Needs: Hunger, thirst, fatigue

Scenarios use custom check functions to determine when to trigger, making them highly flexible for any roleplay situation.


Location-Based Thoughts

Location triggers create area-specific thoughts that enhance environmental storytelling. Players automatically think contextually appropriate thoughts when entering designated areas.

Location triggers support both pre-configured areas (set in config.lua) and dynamic registration and destruction, giving you complete control over when and where thoughts appear.

Circular Areas

Perfect for simple zones around points of interest:

  • Hospitals and police stations

  • Beaches, mountains, and landmarks

  • Buildings and neighborhoods

  • General area triggers

Polygon Zones

Ideal for complex, custom-shaped areas:

  • Detailed building interiors

  • Irregularly shaped districts

  • Precise zone boundaries

  • Custom map areas and routes


How to Use

Basic Thoughts

-- Basic notification
exports['mad-thoughts']:thought("I can't do this right now...")

-- With duration (10 seconds)
exports['mad-thoughts']:thought("I wonder what that means...", 10)

-- With icon
exports['mad-thoughts']:thought("Something doesn't feel right about this...", 5, "fas fa-question-circle")

-- With icon and color
exports['mad-thoughts']:thought("I need to get out of here!", 8, "fas fa-exclamation", "#e74c3c")

Parameters

  • message: The text content of the thought (string)

  • duration: How long the thought displays in seconds (number, default: 5)

  • icon: Font Awesome icon class (string, default: "fas fa-comment-dots")

  • color: Hex color code for the icon and border (string, default: "#F2F2F2")


Using predefined types

exports['mad-thoughts']:info("I just remembered where I left my keys...", 5)
exports['mad-thoughts']:success("I finally figured it out!", 5)
exports['mad-thoughts']:warning("This doesn't look safe...", 5)
exports['mad-thoughts']:error("I've made a terrible mistake...", 5)

Predefined types use the following icons and colors:

  • info: "fas fa-info-circle" with blue color (#2B78FC)

  • success: "fas fa-check-circle" with green color (#06CE6B)

  • warning: "fas fa-exclamation-triangle" with orange color (#FB8607)

  • error: "fas fa-times-circle" with red color (#fe2436)


Sequential Thoughts

Display multiple thoughts in sequence:

exports['mad-thoughts']:thoughtChain({
    {message = "That's strange...", duration = 3},
    {message = "I wonder if anyone is here...", duration = 4, icon = "fas fa-question"},
    {message = "Better be careful.", duration = 3, color = "#e74c3c"}
}, 4000)

Parameters

  • thoughts: Array of thought objects, each with message, duration, icon, and color

  • delay: Time between thoughts in milliseconds (default: 3s)

  • initialDelay: Optional delay before starting the sequence (default: 0s)


Dynamic Scenario and Location Triggers

The system allows you to dynamically create and remove thought triggers. This is especially useful for:

  • Scenario and location triggers that appear only during certain jobs, heists, or events

  • Temporary areas that should trigger thoughts for a limited time

  • Dynamic story elements that change based on server state

Creating Custom Scenarios

Scenarios automatically trigger thoughts based on conditions you define. Each scenario includes a check function that determines when to trigger the thought.

Scenario Registration

exports['mad-thoughts']:registerScenario('myResourceScenario', {
    check = function(ped)
        return IsPedAimingFromCover(ped)
    end,
    message = "Ready, aim, fire...",
    duration = 6,
    icon = "fas fa-crosshairs",
    color = "#FF0000",
    cooldown = 30
})

Parameters

  • check: Function that returns true when the scenario should trigger

  • message: The thought text (string or array for random selection)

  • duration: How long the thought displays (seconds)

  • icon: Font Awesome icon class

  • color: Hex color code for styling

  • cooldown: Minimum seconds between triggers

Creating Custom Locations

Location triggers create thoughts when players enter specific areas. The system supports both circular areas and complex polygon zones.

Circular Zones Registration

Define a radius around a point to create your zone where the thought will trigger:

exports['mad-thoughts']:registerLocation('myResourceLocation', {
    coords = vector3(176.52, -954.48, 30.09),
    distance = 20.0,
    message = "This place looks familiar...",
    duration = 5,
    icon = "fas fa-building",
    color = "#3498db",
    cooldown = 300
})

Parameters

  • coords: Center point coordinates (vector3)

  • distance: Trigger radius in game units

  • message: The thought text (string or array)

  • duration: Display duration in seconds

  • icon: Font Awesome icon class

  • color: Hex color code

  • cooldown: Seconds between triggers

Polygon Zone Registration

For complex, custom-shaped areas, use polygon zones:

exports['mad-thoughts']:registerPolygonZone('myResourceZone', {
    points = {
        vector3(447.9, -998.8, 25.8),
        vector3(450.3, -998.2, 25.8),
        vector3(449.9, -995.5, 25.8),
        vector3(447.2, -995.6, 25.8),
        vector3(446.3, -997.9, 25.8),
    },
    thickness = 4.0,
    message = "This custom zone feels different...",
    duration = 5,
    icon = "fas fa-draw-polygon",
    color = "#9b59b6",
    cooldown = 300
})

Parameters

  • points: Array of vector3 coordinates defining the polygon shape

  • thickness: Vertical height of the zone (optional, default: 4.0)

  • message: The thought text (string or array)

  • duration: Display duration in seconds

  • icon: Font Awesome icon class

  • color: Hex color code

  • cooldown: Seconds between triggers

Note: Polygon zones require all Z coordinates to be on the same plane. The system automatically handles this requirement:

  • When mixed Z coordinates are detected (e.g., some points at 25.0, others at 30.0), the system automatically calculates the average Z value

Setting up Polygon Zones

You can use /zone poly to easily setup new zones. Read the documentation for the zone-creator here.

Removing Custom Triggers

Clean up your custom scenarios and locations when they're no longer needed:

-- Remove a scenario you previously registered
exports['mad-thoughts']:removeScenario('myResourceScenario')

-- Remove a circular location you previously registered
exports['mad-thoughts']:removeLocation('myResourceLocation')

-- Remove a polygon zone you previously registered
exports['mad-thoughts']:removePolygonZone('myResourceZone')

Server-Wide Thoughts

You can send thoughts to all connected players:

From a Client Script

-- Send a thought to all players on the server
exports['mad-thoughts']:sendThoughtToAll(
  "Everyone should see this message!", -- message
  5, -- duration in seconds
  "fas fa-bullhorn", -- icon
  "#E67E22" -- color (orange)
)

From a Server Script

-- Send a thought directly from a server script
exports['mad-thoughts']:sendThoughtToAll(
  "Server announcement as a thought", -- message
  5, -- duration in seconds
  "fas fa-server", -- icon
  "#3498db" -- color (blue)
)

Via Command

-- Basic usage
/globalthought "This is a global announcement"

-- With custom duration (in seconds)
/globalthought "This is a global announcement" "10"

-- With custom icon
/globalthought "This is a global announcement" "10" "fa-solid fa-bell"

-- With custom color
/globalthought "This is a global announcement" "10" "fa-solid fa-bell" "#FF5733"

This command requires the group.admin permission.


Player-Specific Thoughts

You can send thoughts to specific players:

From a Client Script

-- Send a thought to a specific player
exports['mad-thoughts']:sendThoughtToPlayer(
  1, -- target player's server ID
  "This message is only for you", -- message
  5, -- duration in seconds
  "fas fa-user-secret", -- icon
  "#9B59B6" -- color (purple)
)

From a Server Script

-- Send a thought directly from a server script
exports['mad-thoughts']:sendThoughtToPlayer(
  1, -- target player's server ID
  "This message is only for you", -- message
  5, -- duration in seconds
  "fas fa-envelope", -- icon
  "#3498db" -- color (blue)
)

Via Command

-- Basic usage
/playerthought 1 "This is a private thought"

-- With custom duration (in seconds)
/playerthought 1 "This is a private thought" "10"

-- With custom icon
/playerthought 1 "This is a private thought" "10" "fa-solid fa-crown"

-- With custom color
/playerthought 1 "This is a private thought" "10" "fa-solid fa-crown" "#9B59B6"

This command requires the group.admin permission.


Examples

Making NPCs More Immersive

-- Example: When player approaches a mission NPC
exports['mad-thoughts']:thought("I wonder if I should talk to this stranger...", 5)

Skill Check Feedback

-- Example: Instead of "Lockpicking failed"
exports['mad-thoughts']:error("I can't seem to get these tumblers right...", 4)

Environmental Storytelling

-- Example: When entering an abandoned building
exports['mad-thoughts']:thoughtChain({
    {message = "This place gives me the creeps...", duration = 4},
    {message = "Feels like someone's watching me...", duration = 3, icon = "fas fa-eye"}
}, 3000)

Proximity

-- Example: Send a thought to nearby players
local function notifyNearbyPlayers(message, duration, icon, color)
    local myCoords = GetEntityCoords(cache.ped)
    local players = GetActivePlayers()
    
    for _, playerId in ipairs(players) do
        if playerId ~= PlayerId() then
            local targetPed = GetPlayerPed(playerId)
            local targetCoords = GetEntityCoords(targetPed)
            local distance = #(myCoords - targetCoords)
            
            if distance <= 10.0 then
                exports['mad-thoughts']:sendThoughtToPlayer(
                    GetPlayerServerId(playerId),
                    message or "This guy looks suspicious",
                    duration or 5,
                    icon or "fas fa-exclamation",
                    color or "#e74c3c"
                )
            end
        end
    end
end

-- Example: When a player discovers something important
RegisterNetEvent('discovered')
AddEventHandler('discovered', function()
    -- Thought for the player who made the discovery
    exports['mad-thoughts']:thought("What's this strange artifact?", 5)
    
    -- Send a different thought to nearby players
    notifyNearbyPlayers(
        "Did someone just find something?",
        5,
        "fas fa-question-circle",
        "#9B59B6"
    )
end)

Group Coordination

-- Example: Coordinating with specific team members
RegisterNetEvent('heist:beginOperation')
AddEventHandler('heist:beginOperation', function(teamMembers)
    for role, playerId in pairs(teamMembers) do
        if role == "hacker" then
            exports['mad-thoughts']:sendThoughtToPlayer(
                playerId,
                "I need to focus on bypassing the security system...",
                5,
                "fas fa-laptop-code",
                "#3498db"
            )
        elseif role == "lookout" then
            exports['mad-thoughts']:sendThoughtToPlayer(
                playerId,
                "I should keep an eye out for guards...",
                5,
                "fas fa-eye",
                "#f39c12"
            )
        elseif role == "driver" then
            exports['mad-thoughts']:sendThoughtToPlayer(
                playerId,
                "Engine's running. Ready for a quick getaway...",
                5,
                "fas fa-car",
                "#2ecc71"
            )
        end
    end
end)

Dependencies


Installation

  1. Ensure you have the required dependency

  2. Place the folder in your server's resources directory

  3. Add start mad-thoughts to your server.cfg

  4. Configure scenarios & locations in the config.lua file to match your server's needs


Configuration

The resource comes with a comprehensive config.lua file that includes:

  1. Ready-to-use templates for scenarios and locations

  2. Example circular and polygon locations for popular map areas

  3. Example scenarios for common situations (underwater, low health, weather conditions)

  4. Detailed comments explaining every configuration option

mad-thoughts config file

Debug

The resource includes debug visualizations to help you set up and test your location triggers:

Enable debug mode in your config.lua:

Debug = true, -- boolean (true/false | default: false)

When debug mode is enabled, you'll see:

  • Visual indicators showing location trigger zones as red spheres

  • Location IDs displayed above each zone

This is particularly useful when:

  • Setting up new location triggers to ensure they're in the right place

  • Testing the detection radius of your locations

Debug mode displaying locations

Support

Join our Discord community for support, regular updates and to request new features.

Escrow Protection

This resource is protected by FiveM's escrow system to safeguard against unauthorised distribution. The core functionality is secured while maintaining full customisability through the extensive configuration system.

Despite the security measures:

  • All configuration options remain fully editable.

  • The UI remains fully editable (html, css, js)

  • Server owners retain complete control over all settings.

  • No functionality is limited by the protection system.

This approach ensures you receive a premium, leak-protected resource while maintaining the freedom to customise it for your server's unique needs.

Last updated