العودة إلى المدونة
Guide9 دقيقة قراءة

نظام المحكمة والقانون في FiveM: برمجة محاكمات واقعية

إضافة نظام محكمة يعمل إلى خادم FiveM الخاص بك. أدوات القاضي، أدوار المحامين، واجهات الأدلة وأفضل سكربتات النظام القانوني للعب أدوار عميق.

Agency Scripts

المؤسس والمطور الرئيسي في Agency Scripts

هيكل نظام قانوني

نظام المحكمة والقانون يرفع خادم دور FiveM من لعبة شرطة ولصوص أساسية إلى مجتمع منظم حيث للقوانين وزن وتتبع العواقب الإجراءات القانونية. يشمل النظام أوامر القبض التي تستخدمها الشرطة لتفويض التفتيش والاعتقالات، سير عمل جلسات المحكمة حيث تُعرض القضايا أمام القاضي، أدوار الدفاع والادعاء للمحامين، نظام إدارة الأدلة الذي يتتبع الأدلة المادية والرقمية، وإطار الأحكام للغرامات، السجن، والعقوبات البديلة. تتركز البنية على قاعدة بيانات إدارة القضايا التي تتتبع كل إجراء قانوني من التهمة الأولية مرورًا بالاستدعاء، المحاكمة، والحكم. ترتبط كل قضية بالأطراف المعنية، أدوارهم، الأدلة المقدمة، والنتيجة النهائية. تبقى هذه البيانات دائمة، مما يبني تاريخًا قانونيًا للخادم يمكن للاعبين والمسؤولين الرجوع إليه في الإجراءات المستقبلية.

مخطط قاعدة البيانات للسجلات القانونية

قاعدة بياناتك تحتاج إلى التعامل مع مذكرات التوقيف، القضايا القضائية، الأدلة، والسجلات القانونية. المخطط يربط تحقيقات الشرطة بالإجراءات القضائية من خلال نظام أدلة مشترك حيث تصبح العناصر التي تم جمعها أثناء التحقيق معروضات في المحاكمة. صمم الجداول للحفاظ على سجل تدقيق كامل لكل إجراء يتم اتخاذه في الإجراءات القانونية:

CREATE TABLE IF NOT EXISTS warrants (
    id INT AUTO_INCREMENT PRIMARY KEY,
    type ENUM('arrest', 'search', 'bench') NOT NULL,
    target_citizenid VARCHAR(50) NOT NULL,
    target_name VARCHAR(100) NOT NULL,
    reason TEXT NOT NULL,
    issued_by VARCHAR(50) NOT NULL,
    approved_by VARCHAR(50) DEFAULT NULL,
    status ENUM('pending', 'active', 'executed', 'expired', 'revoked') DEFAULT 'pending',
    issued_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    expires_at TIMESTAMP NULL,
    executed_at TIMESTAMP NULL,
    INDEX idx_target (target_citizenid),
    INDEX idx_status (status)
);

CREATE TABLE IF NOT EXISTS court_cases (
    id INT AUTO_INCREMENT PRIMARY KEY,
    case_number VARCHAR(20) UNIQUE NOT NULL,
    defendant_citizenid VARCHAR(50) NOT NULL,
    defendant_name VARCHAR(100) NOT NULL,
    prosecutor_citizenid VARCHAR(50) DEFAULT NULL,
    defense_citizenid VARCHAR(50) DEFAULT NULL,
    judge_citizenid VARCHAR(50) DEFAULT NULL,
    charges TEXT NOT NULL,
    status ENUM('filed', 'arraignment', 'pretrial', 'trial', 'verdict', 'closed', 'dismissed') DEFAULT 'filed',
    plea ENUM('not_guilty', 'guilty', 'no_contest') DEFAULT NULL,
    verdict ENUM('guilty', 'not_guilty', 'mistrial', 'dismissed') DEFAULT NULL,
    sentence TEXT DEFAULT NULL,
    fine_amount INT DEFAULT 0,
    jail_minutes INT DEFAULT 0,
    filed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    hearing_scheduled TIMESTAMP NULL,
    closed_at TIMESTAMP NULL,
    INDEX idx_defendant (defendant_citizenid),
    INDEX idx_status (status)
);

CREATE TABLE IF NOT EXISTS evidence (
    id INT AUTO_INCREMENT PRIMARY KEY,
    case_id INT DEFAULT NULL,
    type ENUM('physical', 'digital', 'testimony', 'document', 'photo') NOT NULL,
    label VARCHAR(200) NOT NULL,
    description TEXT DEFAULT NULL,
    collected_by VARCHAR(50) NOT NULL,
    collected_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    chain_of_custody TEXT DEFAULT NULL,
    is_admitted BOOLEAN DEFAULT FALSE,
    FOREIGN KEY (case_id) REFERENCES court_cases(id)
);

CREATE TABLE IF NOT EXISTS legal_records (
    id INT AUTO_INCREMENT PRIMARY KEY,
    citizenid VARCHAR(50) NOT NULL,
    record_type ENUM('conviction', 'acquittal', 'fine', 'warning', 'restraining_order') NOT NULL,
    description TEXT NOT NULL,
    case_id INT DEFAULT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    expunged BOOLEAN DEFAULT FALSE,
    INDEX idx_citizen (citizenid),
    FOREIGN KEY (case_id) REFERENCES court_cases(id)
);

نظام المذكرات القضائية

المذكرات القضائية هي البوابة القانونية بين تحقيق الشرطة والإجراءات. مذكرة الاعتقال تخول الضباط لاحتجاز شخص معين، مذكرة التفتيش تسمح بتفتيش عقار أو مركبة، ومذكرة المحكمة تصدرها القاضي عندما يفشل شخص في الحضور إلى المحكمة. ينشئ ضباط الشرطة طلبات المذكرات عبر MDT التي تدخل في قائمة انتظار للمراجعة القضائية. يقوم قاضٍ أو مسؤول مخول بمراجعة الطلب، فحص وصف السبب المحتمل، إما بالموافقة أو الرفض. المذكرات الموافق عليها تصبح نشطة وتظهر على MDT الشرطة عندما يتفاعل الضباط مع الشخص المستهدف، مما ينبههم بوجود مذكرة. نفذ انتهاء صلاحية المذكرات حتى لا تبقى للأبد، حيث تدوم مذكرات الاعتقال 7 أيام حقيقية ومذكرات التفتيش 48 ساعة بعد الموافقة:

-- Warrant request by police
RegisterNetEvent('legal:server:requestWarrant', function(data)
    local src = source
    local Officer = QBCore.Functions.GetPlayer(src)
    if not Officer or Officer.PlayerData.job.name ~= 'police' then return end

    local warrant = {
        type = data.type,
        target_citizenid = data.targetCitizenid,
        target_name = data.targetName,
        reason = data.reason,
        issued_by = Officer.PlayerData.citizenid,
    }

    local id = MySQL.insert.await(
        'INSERT INTO warrants (type, target_citizenid, target_name, reason, issued_by) VALUES (?, ?, ?, ?, ?)',
        { warrant.type, warrant.target_citizenid, warrant.target_name, warrant.reason, warrant.issued_by }
    )

    -- Notify judges
    local players = QBCore.Functions.GetQBPlayers()
    for _, player in pairs(players) do
        if player.PlayerData.job.name == 'judge' then
            TriggerClientEvent('legal:client:warrantPending', player.PlayerData.source, {
                id = id,
                type = warrant.type,
                targetName = warrant.target_name,
                reason = warrant.reason,
                officerName = Officer.PlayerData.charinfo.firstname .. ' ' .. Officer.PlayerData.charinfo.lastname,
            })
        end
    end

    TriggerClientEvent('QBCore:Notify', src, 'Warrant request submitted for judicial review', 'success')
end)

-- Judge approval
RegisterNetEvent('legal:server:approveWarrant', function(warrantId)
    local src = source
    local Judge = QBCore.Functions.GetPlayer(src)
    if not Judge or Judge.PlayerData.job.name ~= 'judge' then return end

    local warrant = MySQL.single.await('SELECT * FROM warrants WHERE id = ? AND status = "pending"', { warrantId })
    if not warrant then return end

    local expiryHours = warrant.type == 'search' and 48 or 168
    local expiresAt = os.date('!%Y-%m-%d %H:%M:%S', os.time() + (expiryHours * 3600))

    MySQL.update('UPDATE warrants SET status = "active", approved_by = ?, expires_at = ? WHERE id = ?',
        { Judge.PlayerData.citizenid, expiresAt, warrantId })

    -- Notify requesting officer if online
    TriggerClientEvent('QBCore:Notify', src, 'Warrant #' .. warrantId .. ' approved', 'success')
end)

تدفق جلسات المحكمة

تتبع جلسات المحكمة تدفقًا منظمًا ينقل القضايا عبر التوجيه، والحركات قبل المحاكمة، والمحاكمة، والحكم. عند تقديم القضية، ينشئ النظام رقم قضية فريد ويعين لها حالة "مقدمة". يراجع القاضي القضية ويحدد موعد جلسة توجيه حيث يدلي المتهم بالرد. إذا أدلى المتهم ببراءة، تنتقل القضية إلى مرحلة ما قبل المحاكمة حيث يمكن للمحامين تقديم الحركات والأدلة، ثم إلى المحاكمة حيث يعرض الطرفان حججهما. يتحكم القاضي في سير الجلسة من خلال أوامر تقدم حالة القضية وتطلق تحديثات واجهة المستخدم لجميع المشاركين. نفذ واجهة NUI لقسم المحكمة تعرض معلومات القضية والمرحلة الحالية وتوفر عناصر تحكم خاصة بالأدوار للقاضي والمدعي والمحامي الدفاعي. يحصل القاضي على أزرار الحكم ومدخلات الحكم، بينما يحصل المحامون على أزرار الاعتراض وعناصر تحكم عرض الأدلة.

دور المحامي ونظام الدفاع

وظيفة المحامي تخلق مسارًا مهنيًا كاملاً على الخادم مع آليات لعب مميزة. يمكن توظيف محامي الدفاع من قبل المتهمين عبر دليل المحامين المتاح من السجن أو تطبيق الهاتف. عند قبول المحامي للعميل، يحصل على الوصول إلى ملف القضية في النظام القانوني، بما في ذلك كل الأدلة المقدمة من النيابة. يمكن للمحامين تقديم طلبات لقمع الأدلة، طلب تأجيلات لتأخير الجلسات، التفاوض على صفقات إقرار بالذنب مع المدعي، وتقديم أدلتهم وشهادات الشهود أثناء المحاكمة. نفذ نظام امتحان نقابة حيث يجب على الشخصيات الجديدة اجتياز اختبار معرفة قبل منح وظيفة المحامي، لضمان مستوى أدنى من جودة لعب الأدوار القانونية. تتبع إحصائيات المحامي مثل القضايا التي فاز بها، القضايا التي خسرها، ومتوسط تخفيض العقوبة لعملائهم، مما يخلق سوقًا تنافسية حيث يمكن للمحامين المعروفين فرض رسوم أعلى:

Config.LawyerSystem = {
    barExamQuestions = 15,
    passingScore = 11,       -- 73% to pass
    examCooldown = 86400,    -- 24 hours between attempts
    maxActiveClients = 5,
    consultationFee = 500,   -- base fee for initial consultation
    trialFeeRange = { min = 2000, max = 25000 },

    motionTypes = {
        { id = 'suppress_evidence', label = 'Motion to Suppress Evidence', description = 'Request exclusion of illegally obtained evidence' },
        { id = 'dismiss_charges', label = 'Motion to Dismiss', description = 'Request dismissal due to insufficient evidence' },
        { id = 'continuance', label = 'Motion for Continuance', description = 'Request to postpone the hearing' },
        { id = 'change_venue', label = 'Motion for Change of Venue', description = 'Request trial at different location' },
        { id = 'bail_reduction', label = 'Motion for Bail Reduction', description = 'Request lower bail amount' },
        { id = 'expungement', label = 'Motion for Expungement', description = 'Request to clear prior conviction' },
    },
}

-- Hire a lawyer from jail
RegisterNetEvent('legal:server:hireLawyer', function(lawyerCitizenid)
    local src = source
    local Player = QBCore.Functions.GetPlayer(src)
    if not Player then return end

    local citizenid = Player.PlayerData.citizenid

    -- Find active case for this player
    local activeCase = MySQL.single.await(
        'SELECT * FROM court_cases WHERE defendant_citizenid = ? AND status NOT IN ("closed", "dismissed") ORDER BY filed_at DESC LIMIT 1',
        { citizenid }
    )
    if not activeCase then
        TriggerClientEvent('QBCore:Notify', src, 'No active case found', 'error')
        return
    end

    -- Assign lawyer to case
    MySQL.update('UPDATE court_cases SET defense_citizenid = ? WHERE id = ?',
        { lawyerCitizenid, activeCase.id })

    -- Notify lawyer
    local lawyerPlayer = QBCore.Functions.GetPlayerByCitizenId(lawyerCitizenid)
    if lawyerPlayer then
        TriggerClientEvent('QBCore:Notify', lawyerPlayer.PlayerData.source,
            'New client: ' .. Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname ..
            ' | Case #' .. activeCase.case_number, 'success')
    end

    TriggerClientEvent('QBCore:Notify', src, 'Attorney assigned to your case', 'success')
end)

نظام إدارة الأدلة

يوفر نظام الأدلة سلسلة حفظ تربط التحقيق في مسرح الجريمة بعرض المحكمة. عندما تجمع الشرطة أدلة في موقع باستخدام أمر جمع الأدلة، ينشئ النظام سجل أدلة بهوية الضابط الجامع، الطابع الزمني، والموقع. يحصل كل دليل على معرف فريد يستمر طوال العملية القانونية. تشمل أنواع الأدلة العناصر المادية مثل الأسلحة، المخدرات، والملابس، الأدلة الرقمية مثل سجلات الهاتف وتسجيلات CCTV، شهادة الشهود المسجلة كنصوص، والوثائق مثل السجلات المالية أو بطاقات الهوية المزورة. يمكن للمحامين الطعن في قبول الأدلة من خلال طلبات تشكك في طريقة الجمع أو سلسلة الحفظ. يراجع القاضي هذه الطلبات ويمكنه تعليم الأدلة على أنها غير مقبولة، مما يزيلها من ملف القضية. نفذ خزنة أدلة في مركز الشرطة حيث تُخزن الأدلة المادية، باستخدام تكامل نظام الجرد لتتبع العناصر الفعلية التي جُمعت أثناء التحقيقات.

آليات الغرامات والكفالة

تخلق الغرامات والكفالة عواقب اقتصادية ضمن النظام القانوني. عندما يُحاكم المتهم، يحدد القاضي مبلغ الكفالة بناءً على شدة التهم والسجل الجنائي للمتهم. يمكن للمتهم دفع الكفالة من خلال النظام القضائي ليتم إطلاق سراحه من الحجز أثناء انتظار المحاكمة، أو البقاء في السجن حتى الجلسة. يتم خصم دفع الكفالة من حساب اللاعب البنكي ويتم استرداده بعد انتهاء القضية إذا حضر المتهم جميع الجلسات. إذا فشل المتهم في الحضور، تُصادر الكفالة ويصدر أمر اعتقال. تُفرض الغرامات كجزء من الحكم ويجب دفعها خلال فترة زمنية محددة. تتراكم الفوائد على الغرامات غير المدفوعة ويمكن أن تؤدي إلى عواقب قانونية إضافية مثل تعليق رخصة القيادة أو الحجز على الممتلكات. نفذ نظام خطة دفع الغرامات للغرامات الكبيرة حيث يمكن للمتهم دفع أقساط أسبوعية بدلاً من دفع المبلغ الكامل دفعة واحدة، مما يضيف التزامًا ماليًا مستمرًا يحافظ على صلة النظام القانوني بتجربة اللاعب اليومية على الخادم.

أوامر القضاة والأحكام

يحتاج القضاة إلى مجموعة أوامر شاملة لإدارة إجراءات المحكمة وتنفيذ النظام القانوني. تشمل الأوامر الأساسية /case لعرض وإدارة الحالات، /warrant للموافقة أو رفض طلبات المذكرة، /sentence لإصدار وقت السجن والغرامات، /bail لتعيين مبالغ الكفالة، /gag لكتم اللاعبين المزعجين أثناء الجلسات، و /contempt لسجن اللاعبين الذين لا يحترمون المحكمة. يجب أن تشير أمر الحكم إلى تكوين قانون العقوبات الذي يحدد الحد الأدنى والأقصى للأحكام لكل تهمة، لضمان الاتساق بين القضاة المختلفين. نفذ نظام إرشادات الحكم الذي يقترح العقوبات المناسبة بناءً على التهم والسجل الجنائي للمدعى عليه، مع السماح للقضاة بالمرونة في الانحراف مع التبرير. خزّن جميع القرارات القضائية في جدول السجلات القانونية حتى يبني الخادم سابقة يمكن للاعبين ذوي الخبرة الرجوع إليها في الإجراءات المستقبلية. أضف عملية مراجعة قضائية حيث يمكن استئناف الأحكام إلى قاضٍ أعلى رتبة أو لجنة، مما يخلق طبقات إضافية من التمثيل القانوني للاعبين المكرسين.

الدمج مع الشرطة والسجن وMDT

يجب أن يندمج النظام القانوني بسلاسة مع موارد الشرطة والسجن وMDT الحالية لتشكيل خط أنابيب عدالة متماسك. عندما تقدم الشرطة تهمًا عبر MDT، يجب أن ينشئ النظام تلقائيًا قضية محكمة برقم القضية المناسب ويربط أي أدلة تم جمعها أثناء التحقيق. عندما يصدر القاضي حكمًا بالسجن، يجب أن يستدعي النظام وظيفة التوقيف في مورد السجن مباشرةً بحيث يتدفق الحكم تلقائيًا دون الحاجة لضابط شرطة لتنفيذ أمر السجن يدويًا. يجب أن تظهر المذكرات النشطة على MDT الشرطة عند بحث الضباط عن مواطن، مع مؤشرات واضحة تظهر نوع المذكرة، السلطة المصدرة، وتاريخ الانتهاء. يجب أن تكون السجلات الجنائية الناتجة عن أحكام المحكمة متاحة في MDT تحت ملف المواطن، تعرض تاريخهم القانوني الكامل بما في ذلك الإدانات، البراءات، القضايا النشطة، والغرامات المستحقة. صدر كل وظائف النظام القانوني بحيث يمكن للموارد الأخرى التحقق من حالة المذكرة، التحقق من مؤهلات المحامي، البحث في السجلات الجنائية، والتفاعل مع نظام المحكمة برمجيًا.

جاهز للبدء؟

احصل على السكربتات من متجرنا، أو انضم إلى Discord للدعم والتحديثات ونظرة على ما هو قادم.