Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- Triple 6ix Chat App
- Simple CSP Lua App for Assetto Corsa
- Features:
- - Modern chat interface with drag & resize
- - Player colors and typing indicators
- - H hotkey to show/hide
- - Auto-hide when inactive
- - Arabic language support
- Installation:
- 1. Save as chat_app.lua
- 2. Place in content/gui/ or apps/lua/
- 3. Add to CSPExtraOptions in extra_cfg.yml
- 4. Players activate from CSP apps menu
- ]]
- -- إعدادات التطبيق
- local config = {
- windowTitle = "💬 Triple 6ix Chat",
- defaultWidth = 450,
- defaultHeight = 350,
- minWidth = 300,
- minHeight = 200,
- maxWidth = 700,
- maxHeight = 600,
- backgroundColor = rgbm(0.08, 0.08, 0.12, 0.95),
- headerColor = rgbm(0.15, 0.15, 0.25, 1.0),
- textColor = rgbm(1, 1, 1, 1),
- systemColor = rgbm(0.7, 0.9, 1.0, 1),
- maxMessages = 100,
- autoHideDelay = 15, -- ثواني
- fadeSpeed = 3.0,
- fontSize = 14,
- headerHeight = 35
- }
- -- متغيرات الحالة
- local chatState = {
- visible = true,
- position = vec2(100, 150),
- size = vec2(config.defaultWidth, config.defaultHeight),
- isDragging = false,
- isResizing = false,
- dragOffset = vec2(0, 0),
- lastActivity = 0,
- alpha = 1.0,
- inputText = "",
- messages = {},
- playerColors = {},
- typingPlayers = {},
- scrollOffset = 0,
- maxScroll = 0,
- isInputFocused = false
- }
- -- ألوان اللاعبين المحسنة
- local playerColorPalette = {
- rgbm(1.0, 0.5, 0.5, 1), -- أحمر فاتح
- rgbm(0.5, 1.0, 0.5, 1), -- أخضر فاتح
- rgbm(0.5, 0.7, 1.0, 1), -- أزرق فاتح
- rgbm(1.0, 1.0, 0.6, 1), -- أصفر فاتح
- rgbm(1.0, 0.6, 1.0, 1), -- وردي فاتح
- rgbm(0.6, 1.0, 1.0, 1), -- سماوي فاتح
- rgbm(1.0, 0.8, 0.5, 1), -- برتقالي فاتح
- rgbm(0.8, 0.6, 1.0, 1), -- بنفسجي فاتح
- rgbm(0.9, 0.9, 0.5, 1), -- ذهبي
- rgbm(0.6, 0.9, 0.7, 1) -- أخضر نعناعي
- }
- -- دالة للحصول على لون اللاعب
- local function getPlayerColor(playerName)
- if not chatState.playerColors[playerName] then
- local hash = 0
- for i = 1, #playerName do
- hash = hash + string.byte(playerName, i)
- end
- local colorIndex = (hash % #playerColorPalette) + 1
- chatState.playerColors[playerName] = playerColorPalette[colorIndex]
- end
- return chatState.playerColors[playerName]
- end
- -- دالة لإضافة رسالة
- local function addMessage(playerName, message, isSystem)
- if #chatState.messages >= config.maxMessages then
- table.remove(chatState.messages, 1)
- end
- table.insert(chatState.messages, {
- player = playerName,
- message = message,
- color = isSystem and config.systemColor or getPlayerColor(playerName),
- timestamp = os.time(),
- isSystem = isSystem or false
- })
- chatState.lastActivity = os.clock()
- chatState.scrollOffset = 0 -- التمرير للأسفل عند رسالة جديدة
- -- حساب الحد الأقصى للتمرير
- local messageHeight = 22
- local visibleArea = chatState.size.y - config.headerHeight - 60
- local totalHeight = #chatState.messages * messageHeight
- chatState.maxScroll = math.max(0, totalHeight - visibleArea)
- end
- -- دالة للتحقق من النقر داخل منطقة
- local function isPointInRect(point, rectPos, rectSize)
- return point.x >= rectPos.x and point.x <= rectPos.x + rectSize.x and
- point.y >= rectPos.y and point.y <= rectPos.y + rectSize.y
- end
- -- دالة رسم الشات المحسنة
- local function drawChat()
- if not chatState.visible then return end
- local currentTime = os.clock()
- -- تلاشي تلقائي
- if currentTime - chatState.lastActivity > config.autoHideDelay then
- chatState.alpha = math.max(0.3, chatState.alpha - config.fadeSpeed * ac.getDeltaT())
- else
- chatState.alpha = math.min(1, chatState.alpha + config.fadeSpeed * ac.getDeltaT())
- end
- -- رسم الخلفية الرئيسية مع حواف مدورة
- local bgColor = rgbm(config.backgroundColor.r, config.backgroundColor.g, config.backgroundColor.b, config.backgroundColor.a * chatState.alpha)
- ui.drawRectFilled(chatState.position, chatState.position + chatState.size, bgColor, 12)
- -- رسم حدود النافذة
- ui.drawRect(chatState.position, chatState.position + chatState.size, rgbm(0.3, 0.3, 0.4, chatState.alpha), 12, 2)
- -- رسم شريط العنوان المحسن
- local headerColor = rgbm(config.headerColor.r, config.headerColor.g, config.headerColor.b, config.headerColor.a * chatState.alpha)
- ui.drawRectFilled(chatState.position, chatState.position + vec2(chatState.size.x, config.headerHeight), headerColor, 12)
- -- رسم عنوان النافذة مع أيقونة
- local titleColor = rgbm(config.textColor.r, config.textColor.g, config.textColor.b, config.textColor.a * chatState.alpha)
- ui.drawText(config.windowTitle, chatState.position + vec2(12, 10), 16, titleColor)
- -- رسم أزرار التحكم
- local buttonSize = 20
- local buttonY = chatState.position.y + 7
- -- زر الإغلاق
- local closeButtonPos = vec2(chatState.position.x + chatState.size.x - 30, buttonY)
- ui.drawRectFilled(closeButtonPos, closeButtonPos + vec2(buttonSize, buttonSize), rgbm(0.9, 0.3, 0.3, chatState.alpha), 4)
- ui.drawText("×", closeButtonPos + vec2(6, 2), 14, titleColor)
- -- زر تصغير
- local minimizeButtonPos = vec2(chatState.position.x + chatState.size.x - 55, buttonY)
- ui.drawRectFilled(minimizeButtonPos, minimizeButtonPos + vec2(buttonSize, buttonSize), rgbm(0.5, 0.5, 0.5, chatState.alpha), 4)
- ui.drawText("−", minimizeButtonPos + vec2(6, 2), 14, titleColor)
- -- منطقة الرسائل
- local messagesArea = {
- pos = chatState.position + vec2(8, config.headerHeight + 8),
- size = vec2(chatState.size.x - 16, chatState.size.y - config.headerHeight - 50)
- }
- -- رسم خلفية منطقة الرسائل
- ui.drawRectFilled(messagesArea.pos, messagesArea.pos + messagesArea.size, rgbm(0.05, 0.05, 0.08, chatState.alpha), 6)
- -- رسم الرسائل مع تحسينات
- local messageHeight = 22
- local startY = messagesArea.pos.y + messagesArea.size.y - messageHeight + chatState.scrollOffset
- for i = #chatState.messages, 1, -1 do
- local msg = chatState.messages[i]
- local messageY = startY - (i - 1) * messageHeight
- if messageY >= messagesArea.pos.y - messageHeight and messageY <= messagesArea.pos.y + messagesArea.size.y then
- local msgColor = rgbm(msg.color.r, msg.color.g, msg.color.b, msg.color.a * chatState.alpha)
- -- رسم خلفية الرسالة (متناوبة)
- if i % 2 == 0 then
- ui.drawRectFilled(vec2(messagesArea.pos.x, messageY), vec2(messagesArea.pos.x + messagesArea.size.x, messageY + messageHeight), rgbm(0.1, 0.1, 0.15, chatState.alpha * 0.3), 3)
- end
- -- رسم اسم اللاعب مع تنسيق محسن
- local playerText = msg.isSystem and "🔹 " .. msg.player or msg.player .. ":"
- ui.drawText(playerText, vec2(messagesArea.pos.x + 8, messageY + 2), config.fontSize, msgColor)
- -- رسم الرسالة
- local textColor = rgbm(config.textColor.r, config.textColor.g, config.textColor.b, config.textColor.a * chatState.alpha)
- local messageX = msg.isSystem and messagesArea.pos.x + 8 or messagesArea.pos.x + 100
- ui.drawText(msg.message, vec2(messageX, messageY + 2), config.fontSize, textColor)
- -- رسم الوقت (صغير)
- local timeStr = os.date("%H:%M", msg.timestamp)
- local timeColor = rgbm(0.6, 0.6, 0.6, chatState.alpha * 0.7)
- ui.drawText(timeStr, vec2(messagesArea.pos.x + messagesArea.size.x - 40, messageY + 2), 10, timeColor)
- end
- end
- -- رسم مؤشر الكتابة المحسن
- if next(chatState.typingPlayers) then
- local typingText = "💭 يكتب..."
- local typingColor = rgbm(0.4, 0.9, 0.6, chatState.alpha)
- ui.drawText(typingText, messagesArea.pos + vec2(8, messagesArea.size.y - 20), 12, typingColor)
- end
- -- رسم شريط التمرير
- if chatState.maxScroll > 0 then
- local scrollBarX = messagesArea.pos.x + messagesArea.size.x - 8
- local scrollBarHeight = messagesArea.size.y
- local scrollThumbHeight = math.max(20, scrollBarHeight * (messagesArea.size.y / (chatState.maxScroll + messagesArea.size.y)))
- local scrollThumbY = messagesArea.pos.y + (scrollBarHeight - scrollThumbHeight) * (chatState.scrollOffset / chatState.maxScroll)
- ui.drawRectFilled(vec2(scrollBarX, scrollThumbY), vec2(scrollBarX + 4, scrollThumbY + scrollThumbHeight), rgbm(0.5, 0.5, 0.5, chatState.alpha), 2)
- end
- -- رسم مقبض تغيير الحجم المحسن
- local resizeHandlePos = chatState.position + chatState.size - vec2(20, 20)
- local resizeHandleSize = vec2(20, 20)
- ui.drawText("⋱", resizeHandlePos + vec2(4, 2), 14, rgbm(0.6, 0.6, 0.6, chatState.alpha))
- -- رسم معلومات الحالة
- local statusText = string.format("الرسائل: %d | اللاعبين: %d", #chatState.messages, ac.getConnectedCarsCount())
- local statusColor = rgbm(0.5, 0.5, 0.5, chatState.alpha * 0.8)
- ui.drawText(statusText, chatState.position + vec2(8, chatState.size.y - 15), 10, statusColor)
- end
- -- دالة معالجة الإدخال المحسنة
- local function handleInput()
- local mousePos = ui.mousePos()
- local mouseDown = ui.mouseDown()
- local mouseClicked = ui.mouseClicked()
- if not chatState.visible or chatState.alpha <= 0.1 then return end
- -- تحديث النشاط عند التفاعل
- if mouseClicked and isPointInRect(mousePos, chatState.position, chatState.size) then
- chatState.lastActivity = os.clock()
- end
- -- التحقق من النقر على زر الإغلاق
- local closeButtonPos = vec2(chatState.position.x + chatState.size.x - 30, chatState.position.y + 7)
- local closeButtonSize = vec2(20, 20)
- if mouseClicked and isPointInRect(mousePos, closeButtonPos, closeButtonSize) then
- chatState.visible = false
- return
- end
- -- التحقق من النقر على زر التصغير
- local minimizeButtonPos = vec2(chatState.position.x + chatState.size.x - 55, chatState.position.y + 7)
- if mouseClicked and isPointInRect(mousePos, minimizeButtonPos, closeButtonSize) then
- chatState.alpha = chatState.alpha > 0.5 and 0.3 or 1.0
- chatState.lastActivity = os.clock()
- return
- end
- -- التحقق من السحب
- local headerArea = {pos = chatState.position, size = vec2(chatState.size.x - 60, config.headerHeight)}
- if mouseClicked and isPointInRect(mousePos, headerArea.pos, headerArea.size) then
- chatState.isDragging = true
- chatState.dragOffset = mousePos - chatState.position
- elseif not mouseDown then
- chatState.isDragging = false
- end
- if chatState.isDragging and mouseDown then
- chatState.position = mousePos - chatState.dragOffset
- chatState.lastActivity = os.clock()
- end
- -- التحقق من تغيير الحجم
- local resizeHandlePos = chatState.position + chatState.size - vec2(20, 20)
- local resizeHandleSize = vec2(20, 20)
- if mouseClicked and isPointInRect(mousePos, resizeHandlePos, resizeHandleSize) then
- chatState.isResizing = true
- elseif not mouseDown then
- chatState.isResizing = false
- end
- if chatState.isResizing and mouseDown then
- local newSize = mousePos - chatState.position
- chatState.size.x = math.max(config.minWidth, math.min(config.maxWidth, newSize.x))
- chatState.size.y = math.max(config.minHeight, math.min(config.maxHeight, newSize.y))
- chatState.lastActivity = os.clock()
- end
- -- التمرير بالعجلة المحسن
- if isPointInRect(mousePos, chatState.position, chatState.size) then
- local scroll = ui.mouseWheel()
- if scroll ~= 0 then
- chatState.scrollOffset = chatState.scrollOffset + scroll * 30
- chatState.scrollOffset = math.max(-chatState.maxScroll, math.min(0, chatState.scrollOffset))
- chatState.lastActivity = os.clock()
- end
- end
- end
- -- دوال الأحداث
- function script.update(dt)
- -- تحديث حالة الكتابة
- for player, timer in pairs(chatState.typingPlayers) do
- chatState.typingPlayers[player] = timer - dt
- if chatState.typingPlayers[player] <= 0 then
- chatState.typingPlayers[player] = nil
- end
- end
- end
- function script.drawUI()
- drawChat()
- handleInput()
- end
- -- استقبال الرسائل من السيرفر
- function script.onChatMessage(message, authorId, authorName)
- addMessage(authorName, message, false)
- end
- -- استقبال إشعارات الكتابة
- function script.onChatInput(text)
- if text and text ~= "" then
- chatState.typingPlayers["أنت"] = 3.0 -- مؤقت الكتابة
- end
- end
- -- دوال الأحداث للاعبين
- function script.onPlayerConnected(playerId, playerName)
- addMessage("النظام", playerName .. " انضم إلى السيرفر 🎉", true)
- end
- function script.onPlayerDisconnected(playerId, playerName)
- addMessage("النظام", playerName .. " غادر السيرفر 👋", true)
- chatState.playerColors[playerName] = nil
- end
- -- تفعيل الشات بمفتاح H
- function script.onKeyPressed(key)
- if key == ui.Key.H then
- chatState.visible = not chatState.visible
- chatState.lastActivity = os.clock()
- chatState.alpha = 1.0
- end
- end
- -- تهيئة التطبيق
- function script.onInit()
- addMessage("النظام", "🚀 مرحباً بك في شات Triple 6ix Chat المتطور!", true)
- addMessage("النظام", "💡 اضغط H لإظهار/إخفاء الشات", true)
- addMessage("النظام", "🎮 يمكنك سحب النافذة وتغيير حجمها", true)
- chatState.lastActivity = os.clock()
- end
Advertisement
Add Comment
Please, Sign In to add comment