Jump to content

Announcement box


Recommended Posts

Hi everyone.

I've been working on an Announcement box script, but I have a big problem, if the messages are too long, it'll start on another line, but now the problem comes when you send another message, it'll mess with the previous one.

Part of script:

        if ( messages [ #messages ] ) then 
            y = messages [ #messages ] [ "y" ] 
        else 
            y = originalY 
        end 
        local numLines = math.floor ( ( dxGetTextWidth ( text, 1, "default-bold" ) / 370 ) + 1 ) 
        local height = ( dxGetFontHeight ( 1, "default-bold" ) + 3 ) 
        local y = ( y + height + numLines ) 

Screenshot of the problem:

DZFjL.png

If someone could find a way to fix this, I'll be very thankful.

Thanks in advance.

Link to comment

I know this sounds a little weird, but are you able to add some kind of data on the message to mark it as a longer message, and if it's a longer message, the next message will be sent one line lower? I know, it sounds pretty lame and unofficial fix but yeah.

Link to comment
I know this sounds a little weird, but are you able to add some kind of data on the message to mark it as a longer message, and if it's a longer message, the next message will be sent one line lower? I know, it sounds pretty lame and unofficial fix but yeah.

I was going to say the same. Like using a "string.len" function.

PD : Castillo asking something on the scripting forum :o:o

Link to comment
function string.transfer( s, nMax ) 
    if type( s ) == 'string' and type( nMax ) == 'number' then 
        local nMaxOld = nMax 
        local nLength = #s -- change to utfLen( s ) if you working with unicode. 
        if nLength >= nMax then 
            local sNew = '' 
            local nStart = 0 
            for nCount = 1, math.ceil( nLength / nMax ) do 
                sNew = sNew .. '\n'.. s:sub( nStart + 1, nMax ) 
                nStart = nMax 
                nMax = nMax + nMaxOld 
            end 
            return sNew:sub( 2, #sNew ) -- -- change #sNew to utfLen( sNew ) if you working with unicode. 
        end 
        return s 
    end 
    return false 
end 
  
print( string.transfer( '123456', 2 ) ) 
--[[ 
12 
34 
56 
]] 
  

?

Edited by Guest
Link to comment

@myonlake: You mean split the whole string and send it as many messages? if so, then I already had that idea and didn't work either.

@CapY: Why would I use timers?

@Kenix: I didn't post the whole code because it was not required, that part of script is the part which fails.

Link to comment
@Kenix: I didn't post the whole code because it was not required, that part of script is the part which fails.

If you not want fix. Okay ..

Better council. Check variables height, numLines, ..

Edited by Guest
Link to comment

I'm not one of these who ask for the script done, if you tell me how you think I can fix it.

Edit: I've edited the function you've posted Kenix, and made it to use a table instead:

function string.transfer ( s, nMax ) 
    if ( type ( s ) == 'string' ) and ( type ( nMax ) == 'number' ) then 
        local stringsTable = { } 
        local nMaxOld = nMax 
        local nLength = #s -- change to utfLen( s ) if you working with unicode. 
        if ( nLength >= nMax ) then 
            local nStart = 0 
            for nCount = 1, math.ceil ( nLength / nMax ) do 
                table.insert ( stringsTable, s:sub ( nStart + 1, nMax ) ) 
                nStart = nMax 
                nMax = ( nMax + nMaxOld ) 
            end 
  
            return stringsTable 
        end 
  
        return s 
    end 
  
    return false 
end 

        local stringT = string.transfer ( text, 45 ) 
        if ( type ( stringT ) ~= "table" ) then 
            local y = ( originalY + 18 * #messages ) 
            table.insert ( 
                messages, 
                { 
                    [ "text" ] = text, 
                    [ "y" ] = y, 
                    [ "r" ] = r, 
                    [ "g" ] = g, 
                    [ "b" ] = b, 
                    [ "addTime" ] = getTickCount ( ), 
                    [ "table" ] = formatTable 
                } 
            ) 
        else 
            for index, msg in ipairs ( stringT ) do 
                local y = ( originalY + 18 * #messages ) 
                table.insert ( 
                    messages, 
                    { 
                        [ "text" ] = msg, 
                        [ "y" ] = y, 
                        [ "r" ] = r, 
                        [ "g" ] = g, 
                        [ "b" ] = b, 
                        [ "addTime" ] = getTickCount ( ), 
                        [ "table" ] = formatTable 
                    } 
                ) 
            end 
        end 

That kinda fixed the problem, but now I got this new issue:

68Ch5.png

As you can see, there is one extra text, it should only support 6.

Link to comment

I already have a way to get the total lines the string will use, I just need a way to make it work without bug.

Edit: Kenix, the function: string.transfer only works with character len, but that doesn't work for this I noticed, I would need a function that divides text by width.

Link to comment
  
            function fixBug() 
                if ( #messages >= 6 ) then 
                    table.remove( messages, 1 ) 
                    fixBug ( ) 
                end 
            end 
  
  
  
            local stringT = string.transfer ( text, 45 ) 
            if ( type ( stringT ) ~= "table" ) then 
                local y = ( originalY + 18 * #messages ) 
                table.insert ( 
                    messages, 
                    { 
                        [ "text" ] = text, 
                        [ "y" ] = y, 
                        [ "r" ] = r, 
                        [ "g" ] = g, 
                        [ "b" ] = b, 
                        [ "addTime" ] = getTickCount ( ), 
                        [ "table" ] = formatTable 
                    } 
                ) 
                fixBug ( ) 
            else 
                for index, msg in ipairs ( stringT ) do 
                    local y = ( originalY + 18 * #messages ) 
                    table.insert ( 
                        messages, 
                        { 
                            [ "text" ] = msg, 
                            [ "y" ] = y, 
                            [ "r" ] = r, 
                            [ "g" ] = g, 
                            [ "b" ] = b, 
                            [ "addTime" ] = getTickCount ( ), 
                            [ "table" ] = formatTable 
                        } 
                    ) 
                    fixBug ( ) 
                end 
            end 
  

Try use, I didnt tested yet.

Edited by Guest
Link to comment

Sorry, but I already done something similar.

At start of function:

local numLines = math.floor ( ( dxGetTextWidth ( text, 1, "default-bold" ) / 370 ) + 1 ) 
if ( #messages >= 6 ) then 
    local extraLines = ( 6 - #messages + numLines ) 
    for line = 1, extraLines do 
        table.remove ( messages, line ) 
    end 
end 
  

At end of function:

for index, msg in ipairs ( messages ) do 
    local index = ( index - 1 ) 
    msg [ "y" ] = ( originalY + 18 * index ) 
end 

Link to comment

I've built my own function to split the string by width, but it fails at second line for some reason:

Source:

function string.split ( text, maxWidth ) 
    local oldlen = 1 
    local len = 1 
    local width = 0 
    local strings = { } 
    for i = 1, text:len ( ) do 
        width = ( width + dxGetTextWidth ( string.char ( text:byte ( i ) ), 1, "default-bold" ) ) 
        if ( width > maxWidth ) then 
            table.insert ( strings, text:sub ( oldlen, len ) ) 
            oldlen = len 
            width = 0 
        end 
  
        len = i 
    end 
  
    if ( #strings == 0 ) then 
        return text 
    else 
        return strings 
    end 
end 

Screenshot of the problem:

3udn9.png

As you can see, there are some letters outside the rectangle.

Link to comment
  
function outputBox( s, nMax ) 
    if type( s ) == 'string' and type( nMax ) == 'number' then 
        local nMaxOld = nMax 
        local nLength = #s 
        if nLength >= nMax then 
            local sNew = '' 
            local nStart = 0 
            for nCount = 1, math.ceil( nLength / nMax ) do 
                local y = ( originalY + 18 * #messages ) 
                table.insert ( 
                    messages, 
                    { 
                        [ "text" ] = s:sub( nStart + 1, nMax ), 
                        [ "y" ] = y, 
                        [ "r" ] = r, 
                        [ "g" ] = g, 
                        [ "b" ] = b, 
                        [ "addTime" ] = getTickCount ( ), 
                        [ "table" ] = formatTable 
                    } 
                ) 
                nStart = nMax 
                nMax = nMax + nMaxOld 
            end 
            local y = ( originalY + 18 * #messages ) 
            table.insert ( 
                messages, 
                { 
                    [ "text" ] = sNew:sub( 2, #sNew ), 
                    [ "y" ] = y, 
                    [ "r" ] = r, 
                    [ "g" ] = g, 
                    [ "b" ] = b, 
                    [ "addTime" ] = getTickCount ( ), 
                    [ "table" ] = formatTable 
                } 
            ) 
        end 
        local y = ( originalY + 18 * #messages ) 
        table.insert ( 
            messages, 
            { 
                [ "text" ] = s, 
                [ "y" ] = y, 
                [ "r" ] = r, 
                [ "g" ] = g, 
                [ "b" ] = b, 
                [ "addTime" ] = getTickCount ( ), 
                [ "table" ] = formatTable 
            } 
        ) 
    end 
end 
  

I edited that function, try use function. I can't test for now.

outputBox("ASDASDASDASDASDASDDDDDDDDDDDDDAAAAAAASDASDASDASDASDASDASDASDASDASDASASDASDASDASDAS", 45)

Link to comment

Split the string by words. The method you us to split string is OK but it will cut words half way if it's too long or 2 letter words will split and you will end up with 1 letter on 1 line and another on the next line. You can use MTA native split function.

Link to comment

Sad to see that most of the people that try to help on this forum are all idiots. How unfortunate.

Anyway - this uses dxDrawText's wordBreak parameter to wrap the text, and the clip parameter to stop it from drawing outside the box. It might need some tweaking to suit your needs, but the basics are there.

  
-- Basic constants 
local SCREEN_WIDTH, SCREEN_HEIGHT = guiGetScreenSize() 
local BOX_LEFT, BOX_TOP = (SCREEN_WIDTH/2) - 150, (SCREEN_HEIGHT/2) - 150 
local BOX_WIDTH, BOX_HEIGHT = 300, 300 
local BOX_COLOR = tocolor(0, 0, 0, 200) 
local FONT_HEIGHT, EXPIRE_TIME = dxGetFontHeight(1, "default-bold"), 15000 
  
-- Table of all notifications 
local g_notifications = {} 
  
-- Adds a notification to the notification list 
function addNotification(message, r, g, b) 
    if type(message) ~= "string" then 
        error("Invalid argument(s) to addNotification() [expected string at argument 1]!", 2); 
    end 
     
    if type(r) ~= "number" then 
        r = 255 
        g = 255 
        b = 255 
    end 
     
     
    -- If 5 notifications already exist, remove the oldest one 
    -- If this is the first notification, call addEventHandler 
     
    if #g_notifications >= 5 then 
        table.remove(g_notifications) 
    elseif #g_notifications <= 0 then 
        addEventHandler("onClientRender", root, drawNotifications) 
    end 
     
    -- Determine the height of this notification 
    local notificationWidth = dxGetTextWidth(message, 1, "default-bold") 
    local numLines = math.ceil(notificationWidth / BOX_WIDTH) 
    local notificationHeight = (FONT_HEIGHT + 1) * numLines 
             
    -- Insert the new notification at beginning of table (it will be drawn at the top of the box) 
    table.insert(g_notifications, 1, {message, tocolor(r, g, b), getTickCount(), notificationHeight}) 
end 
  
-- Draws the notifications 
function drawNotifications() 
    -- Draw the base rectangle 
    dxDrawRectangle(BOX_LEFT, BOX_TOP, BOX_WIDTH, BOX_HEIGHT, BOX_COLOR) 
     
    -- Track the top of the notification and the current tick count 
    local notificationTop = BOX_TOP + 2 
    local thisTick = getTickCount() 
     
    for i, notification in ipairs(g_notifications) do 
        -- Remove this notification if it is expired 
        -- If there are no more notifications, call removeEventHandler 
        if thisTick - notification[3] >= EXPIRE_TIME then 
            table.remove(g_notifications, i) 
            if #g_notifications <= 0 then 
                removeEventHandler("onClientRender", root, drawNotifications) 
                return 
            end 
        else 
         
            -- Draw this notification, and increment notificationTop so we can draw the next one under it 
            dxDrawText(notification[1], BOX_LEFT, notificationTop, BOX_LEFT + BOX_WIDTH, BOX_TOP + BOX_HEIGHT,  
                        notification[2], 1, "default-bold", "left", "top", true, true) 
                     
            notificationTop = notificationTop + notification[4] + 2 
        end 
    end 
end 
  

mta-screen_2012-05-27_22-30-40.png

GET ON MY LEVEL.

Edited by Guest
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...