From 1b8cf346f88db34335e345a16ba677fab888fef4 Mon Sep 17 00:00:00 2001 From: SmokeyDevGR <70451077+smokeytempo@users.noreply.github.com> Date: Mon, 12 May 2025 17:29:23 +0300 Subject: [PATCH] Update to 2.2.0 Updated to 2.2.0. Added Greek locale ( locales/el.lua ) Adjusted the project scripts to make some enhancements --- config.lua | 12 +- enhancements.lua | 352 +++++++++++++++++++++++++++++++++++++++++++++++ fxmanifest.lua | 6 +- locales/el.lua | 82 +++++++++++ 4 files changed, 449 insertions(+), 3 deletions(-) create mode 100644 enhancements.lua create mode 100644 locales/el.lua diff --git a/config.lua b/config.lua index 6391159..35de8f8 100644 --- a/config.lua +++ b/config.lua @@ -7,9 +7,19 @@ Config.PaymentInterval = 24 -- time in hours between p Config.MinimumDown = 10 -- minimum percentage allowed down Config.MaximumPayments = 24 -- maximum payments allowed Config.PreventFinanceSelling = false -- allow/prevent players from using /transfervehicle if financed -Config.FilterByMake = false -- adds a make list before selecting category in shops +Config.FilterByMake = true -- adds a make list before selecting category in shops Config.SortAlphabetically = true -- will sort make, category, and vehicle selection menus alphabetically Config.HideCategorySelectForOne = true -- will hide the category selection menu if a shop only sells one category of vehicle or a make has only one category + +-- Enhanced features +Config.AllowTestDriveDiscount = true -- enable discounts for test driving a vehicle before purchasing +Config.TestDriveDiscount = 0.05 -- 5% discount if player test drives first +Config.EnableShowroomRotation = true -- enable rotation of showroom vehicles +Config.ShowroomRotationSpeed = 0.015 -- rotation speed of showroom vehicles (higher = faster) +Config.ShowVehicleStats = true -- show vehicle stats in the purchase menu (top speed, acceleration, braking) +Config.EnableCustomColors = true -- allow customers to choose custom colors when purchasing +Config.EnableVehicleTax = true -- enable tax on vehicle purchases +Config.VehicleTaxPercentage = 0.08 -- 8% tax on vehicle purchases Config.Shops = { ['pdm'] = { ['Type'] = 'free-use', -- no player interaction is required to purchase a car diff --git a/enhancements.lua b/enhancements.lua new file mode 100644 index 0000000..7710c17 --- /dev/null +++ b/enhancements.lua @@ -0,0 +1,352 @@ +-- qb-vehicleshop enhancements.lua +-- This file contains enhanced features for the qb-vehicleshop script + +local QBCore = exports['qb-core']:GetCoreObject() + +-- Vehicle Stats Cache +local VehicleStatCache = {} + +-- Get vehicle performance stats +local function GetVehicleStats(model) + if VehicleStatCache[model] then return VehicleStatCache[model] end + + -- Default values + local stats = { + topSpeed = 0, + acceleration = 0, + braking = 0, + handling = 0 + } + + -- Calculate vehicle stats + local vehicleHash = GetHashKey(model) + if not IsModelInCdimage(vehicleHash) then return stats end + + stats.topSpeed = GetVehicleModelMaxSpeed(vehicleHash) * 3.6 -- Convert to km/h + stats.acceleration = GetVehicleModelAcceleration(vehicleHash) * 10 + stats.braking = GetVehicleModelMaxBraking(vehicleHash) * 10 + stats.handling = GetVehicleModelMaxTraction(vehicleHash) + + -- Normalize values to be between 0-100 + stats.topSpeed = math.floor(stats.topSpeed / 2.5) + if stats.topSpeed > 100 then stats.topSpeed = 100 end + + stats.acceleration = math.floor(stats.acceleration * 10) + if stats.acceleration > 100 then stats.acceleration = 100 end + + stats.braking = math.floor(stats.braking * 10) + if stats.braking > 100 then stats.braking = 100 end + + stats.handling = math.floor(stats.handling * 10) + if stats.handling > 100 then stats.handling = 100 end + + -- Cache the stats + VehicleStatCache[model] = stats + + return stats +end + +-- Format vehicle stats for display +function FormatVehicleStats(model) + local stats = GetVehicleStats(model) + local display = "" + + display = display .. "━━━━━━━━ VEHICLE STATS ━━━━━━━━\\n" + display = display .. "Top Speed: " .. GenerateStatBar(stats.topSpeed) .. " " .. stats.topSpeed .. "\\n" + display = display .. "Acceleration: " .. GenerateStatBar(stats.acceleration) .. " " .. stats.acceleration .. "\\n" + display = display .. "Braking: " .. GenerateStatBar(stats.braking) .. " " .. stats.braking .. "\\n" + display = display .. "Handling: " .. GenerateStatBar(stats.handling) .. " " .. stats.handling .. "\\n" + display = display .. "━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + + return display +end + +-- Generate a visual bar for stat display +function GenerateStatBar(value) + local barLength = 10 + local filledBars = math.floor(value / (100 / barLength)) + + local bar = "" + for i = 1, barLength do + if i <= filledBars then + bar = bar .. "█" + else + bar = bar .. "▒" + end + end + + return bar +end + +-- Apply test drive discount +function ApplyTestDriveDiscount(vehiclePrice) + if not Config.AllowTestDriveDiscount then return vehiclePrice end + + local discount = math.floor(vehiclePrice * Config.TestDriveDiscount) + local finalPrice = vehiclePrice - discount + + return finalPrice, discount +end + +-- Apply vehicle tax +function ApplyVehicleTax(vehiclePrice) + if not Config.EnableVehicleTax then return vehiclePrice, 0 end + + local taxAmount = math.floor(vehiclePrice * Config.VehicleTaxPercentage) + local finalPrice = vehiclePrice + taxAmount + + return finalPrice, taxAmount +end + +-- Custom color picker for vehicle purchase +function OpenColorPickerMenu(vehicle, callback) + if not Config.EnableCustomColors then + callback(0, 0) -- Default colors + return + end + + local colorOptions = { + { + header = "Choose Primary Color", + isMenuHeader = true + } + } + + local colors = { + {name = "Black", colorIndex = 0}, + {name = "Carbon Black", colorIndex = 147}, + {name = "Graphite", colorIndex = 1}, + {name = "Anthracite Black", colorIndex = 11}, + {name = "Black Steel", colorIndex = 2}, + {name = "Dark Steel", colorIndex = 3}, + {name = "Silver", colorIndex = 4}, + {name = "Bluish Silver", colorIndex = 5}, + {name = "Rolled Steel", colorIndex = 6}, + {name = "Shadow Silver", colorIndex = 7}, + {name = "Stone Silver", colorIndex = 8}, + {name = "Midnight Silver", colorIndex = 9}, + {name = "Cast Iron Silver", colorIndex = 10}, + {name = "Red", colorIndex = 27}, + {name = "Torino Red", colorIndex = 28}, + {name = "Formula Red", colorIndex = 29}, + {name = "Lava Red", colorIndex = 150}, + {name = "Blaze Red", colorIndex = 30}, + {name = "Grace Red", colorIndex = 31}, + {name = "Garnet Red", colorIndex = 32}, + {name = "Sunset Red", colorIndex = 33}, + {name = "Cabernet Red", colorIndex = 34}, + {name = "Wine Red", colorIndex = 143}, + {name = "Candy Red", colorIndex = 35}, + {name = "Hot Pink", colorIndex = 135}, + {name = "Pfsiter Pink", colorIndex = 137}, + {name = "Salmon Pink", colorIndex = 136}, + {name = "Sunrise Orange", colorIndex = 36}, + {name = "Orange", colorIndex = 38}, + {name = "Bright Orange", colorIndex = 138}, + {name = "Gold", colorIndex = 99}, + {name = "Bronze", colorIndex = 90}, + {name = "Yellow", colorIndex = 88}, + {name = "Race Yellow", colorIndex = 89}, + {name = "Dew Yellow", colorIndex = 91}, + {name = "Green", colorIndex = 139}, + {name = "Dark Green", colorIndex = 49}, + {name = "Racing Green", colorIndex = 50}, + {name = "Sea Green", colorIndex = 51}, + {name = "Olive Green", colorIndex = 52}, + {name = "Bright Green", colorIndex = 53}, + {name = "Gasoline Green", colorIndex = 54}, + {name = "Blue", colorIndex = 64}, + {name = "Midnight Blue", colorIndex = 141}, + {name = "Dark Blue", colorIndex = 62}, + {name = "Saxon Blue", colorIndex = 63}, + {name = "Navy Blue", colorIndex = 65}, + {name = "Harbor Blue", colorIndex = 66}, + {name = "Diamond Blue", colorIndex = 67}, + {name = "Surf Blue", colorIndex = 68}, + {name = "Nautical Blue", colorIndex = 69}, + {name = "Racing Blue", colorIndex = 73}, + {name = "Ultra Blue", colorIndex = 70}, + {name = "Light Blue", colorIndex = 74}, + {name = "Chocolate Brown", colorIndex = 96}, + {name = "Bison Brown", colorIndex = 101}, + {name = "Creek Brown", colorIndex = 95}, + {name = "Feltzer Brown", colorIndex = 94}, + {name = "Maple Brown", colorIndex = 97}, + {name = "Beechwood Brown", colorIndex = 103}, + {name = "Sienna Brown", colorIndex = 104}, + {name = "Saddle Brown", colorIndex = 98}, + {name = "Moss Brown", colorIndex = 100}, + {name = "Woodbeech Brown", colorIndex = 102}, + {name = "Straw Brown", colorIndex = 99}, + {name = "Sandy Brown", colorIndex = 105}, + {name = "Bleached Brown", colorIndex = 106}, + {name = "Schafter Purple", colorIndex = 71}, + {name = "Spinnaker Purple", colorIndex = 72}, + {name = "Midnight Purple", colorIndex = 142}, + {name = "Bright Purple", colorIndex = 145}, + {name = "Cream", colorIndex = 107}, + {name = "Ice White", colorIndex = 111}, + {name = "Frost White", colorIndex = 112} + } + + for _, color in ipairs(colors) do + table.insert(colorOptions, { + header = color.name, + params = { + event = "qb-vehicleshop:client:setSecondaryColor", + args = { + vehicle = vehicle, + colorIndex = color.colorIndex, + colorName = color.name, + callback = callback + } + } + }) + end + + exports['qb-menu']:openMenu(colorOptions) +end + +RegisterNetEvent('qb-vehicleshop:client:setSecondaryColor', function(data) + local colorOptions = { + { + header = "Choose Secondary Color", + isMenuHeader = true + }, + { + header = "Same as Primary", + params = { + event = "qb-vehicleshop:client:confirmColors", + args = { + primaryColor = data.colorIndex, + secondaryColor = data.colorIndex, + primaryName = data.colorName, + secondaryName = data.colorName, + vehicle = data.vehicle, + callback = data.callback + } + } + } + } + + local colors = { + {name = "Black", colorIndex = 0}, + {name = "Carbon Black", colorIndex = 147}, + {name = "Graphite", colorIndex = 1}, + {name = "Anthracite Black", colorIndex = 11}, + {name = "Black Steel", colorIndex = 2}, + {name = "Dark Steel", colorIndex = 3}, + {name = "Silver", colorIndex = 4}, + {name = "Bluish Silver", colorIndex = 5}, + {name = "Rolled Steel", colorIndex = 6}, + {name = "Shadow Silver", colorIndex = 7}, + {name = "Stone Silver", colorIndex = 8}, + {name = "Midnight Silver", colorIndex = 9}, + {name = "Cast Iron Silver", colorIndex = 10}, + {name = "Red", colorIndex = 27}, + {name = "Torino Red", colorIndex = 28}, + {name = "Formula Red", colorIndex = 29}, + {name = "Lava Red", colorIndex = 150}, + {name = "Blaze Red", colorIndex = 30}, + {name = "Grace Red", colorIndex = 31}, + {name = "Garnet Red", colorIndex = 32}, + {name = "Sunset Red", colorIndex = 33}, + {name = "Cabernet Red", colorIndex = 34}, + {name = "Wine Red", colorIndex = 143}, + {name = "Candy Red", colorIndex = 35}, + {name = "Hot Pink", colorIndex = 135}, + {name = "Pfsiter Pink", colorIndex = 137}, + {name = "Salmon Pink", colorIndex = 136}, + {name = "Sunrise Orange", colorIndex = 36}, + {name = "Orange", colorIndex = 38}, + {name = "Bright Orange", colorIndex = 138}, + {name = "Gold", colorIndex = 99}, + {name = "Bronze", colorIndex = 90}, + {name = "Yellow", colorIndex = 88}, + {name = "Race Yellow", colorIndex = 89}, + {name = "Dew Yellow", colorIndex = 91}, + {name = "Green", colorIndex = 139}, + {name = "Dark Green", colorIndex = 49}, + {name = "Racing Green", colorIndex = 50}, + {name = "Sea Green", colorIndex = 51}, + {name = "Olive Green", colorIndex = 52}, + {name = "Bright Green", colorIndex = 53}, + {name = "Gasoline Green", colorIndex = 54}, + {name = "Blue", colorIndex = 64}, + {name = "Midnight Blue", colorIndex = 141}, + {name = "Dark Blue", colorIndex = 62}, + {name = "Saxon Blue", colorIndex = 63}, + {name = "Navy Blue", colorIndex = 65}, + {name = "Harbor Blue", colorIndex = 66}, + {name = "Diamond Blue", colorIndex = 67}, + {name = "Surf Blue", colorIndex = 68}, + {name = "Nautical Blue", colorIndex = 69}, + {name = "Racing Blue", colorIndex = 73}, + {name = "Ultra Blue", colorIndex = 70}, + {name = "Light Blue", colorIndex = 74}, + {name = "Chocolate Brown", colorIndex = 96}, + {name = "Bison Brown", colorIndex = 101}, + {name = "Creek Brown", colorIndex = 95}, + {name = "Feltzer Brown", colorIndex = 94}, + {name = "Maple Brown", colorIndex = 97}, + {name = "Beechwood Brown", colorIndex = 103}, + {name = "Sienna Brown", colorIndex = 104}, + {name = "Saddle Brown", colorIndex = 98}, + {name = "Moss Brown", colorIndex = 100}, + {name = "Woodbeech Brown", colorIndex = 102}, + {name = "Straw Brown", colorIndex = 99}, + {name = "Sandy Brown", colorIndex = 105}, + {name = "Bleached Brown", colorIndex = 106}, + {name = "Schafter Purple", colorIndex = 71}, + {name = "Spinnaker Purple", colorIndex = 72}, + {name = "Midnight Purple", colorIndex = 142}, + {name = "Bright Purple", colorIndex = 145}, + {name = "Cream", colorIndex = 107}, + {name = "Ice White", colorIndex = 111}, + {name = "Frost White", colorIndex = 112} + } + + for _, color in ipairs(colors) do + table.insert(colorOptions, { + header = color.name, + params = { + event = "qb-vehicleshop:client:confirmColors", + args = { + primaryColor = data.colorIndex, + secondaryColor = color.colorIndex, + primaryName = data.colorName, + secondaryName = color.name, + vehicle = data.vehicle, + callback = data.callback + } + } + }) + end + + exports['qb-menu']:openMenu(colorOptions) +end) + +RegisterNetEvent('qb-vehicleshop:client:confirmColors', function(data) + QBCore.Functions.Notify('Selected Colors: ' .. data.primaryName .. ' (Primary) / ' .. data.secondaryName .. ' (Secondary)', 'success') + data.callback(data.primaryColor, data.secondaryColor) +end) + +-- Check if player has test driven a vehicle +-- Used to apply test drive discount +local TestDrivenVehicles = {} + +function HasTestDriven(vehicle) + return TestDrivenVehicles[vehicle] ~= nil +end + +function AddTestDrivenVehicle(vehicle) + TestDrivenVehicles[vehicle] = true +end + +-- Export functions for use in other scripts +exports('FormatVehicleStats', FormatVehicleStats) +exports('ApplyTestDriveDiscount', ApplyTestDriveDiscount) +exports('ApplyVehicleTax', ApplyVehicleTax) +exports('OpenColorPickerMenu', OpenColorPickerMenu) +exports('HasTestDriven', HasTestDriven) +exports('AddTestDrivenVehicle', AddTestDrivenVehicle) diff --git a/fxmanifest.lua b/fxmanifest.lua index e86f449..5845d88 100644 --- a/fxmanifest.lua +++ b/fxmanifest.lua @@ -3,12 +3,13 @@ game 'gta5' lua54 'yes' author 'Kakarot' description 'Allows players to purchase vehicles and manage shops through a job' -version '2.1.0' +version '2.2.0' shared_script { 'config.lua', '@qb-core/shared/locale.lua', - 'locales/en.lua', + 'locales/en.lua', + 'locales/el.lua', 'locales/*.lua' } @@ -18,6 +19,7 @@ client_scripts { '@PolyZone/EntityZone.lua', '@PolyZone/CircleZone.lua', '@PolyZone/ComboZone.lua', + 'enhancements.lua', 'client.lua' } diff --git a/locales/el.lua b/locales/el.lua new file mode 100644 index 0000000..1d91e7c --- /dev/null +++ b/locales/el.lua @@ -0,0 +1,82 @@ +local Translations = { + error = { + testdrive_alreadyin = "Είστε ήδη σε δοκιμαστική οδήγηση", + testdrive_return = "Αυτό δεν είναι το δοκιμαστικό σας όχημα", + Invalid_ID = "Μη έγκυρο αναγνωριστικό παίκτη", + playertoofar = "Αυτός ο παίκτης δεν είναι αρκετά κοντά", + notenoughmoney = "Δεν έχετε αρκετά χρήματα", + minimumallowed = "Η ελάχιστη επιτρεπόμενη πληρωμή είναι $", + overpaid = "Πληρώσατε παραπάνω", + alreadypaid = "Το όχημα έχει ήδη εξοφληθεί", + notworth = "Το όχημα δεν αξίζει τόσο πολύ", + downtoosmall = "Η προκαταβολή είναι πολύ μικρή", + exceededmax = "Υπέρβαση του μέγιστου ποσού πληρωμής", + repossessed = "Το όχημά σας με πινακίδα %{plate} κατασχέθηκε", + buyerinfo = "Δεν ήταν δυνατή η λήψη πληροφοριών αγοραστή", + notinveh = "Πρέπει να είστε στο όχημα που θέλετε να μεταβιβάσετε", + vehinfo = "Δεν ήταν δυνατή η λήψη πληροφοριών οχήματος", + notown = "Δεν σας ανήκει αυτό το όχημα", + buyertoopoor = "Ο αγοραστής δεν έχει αρκετά χρήματα", + nofinanced = "Δεν έχετε χρηματοδοτούμενα οχήματα σε αυτήν την τοποθεσία", + financed = "Αυτό το όχημα είναι χρηματοδοτούμενο", + }, + success = { + purchased = "Συγχαρητήρια για την αγορά σας!", + earned_commission = "Κερδίσατε $ %{amount} σε προμήθεια", + gifted = "Χαρίσατε το όχημά σας", + received_gift = "Σας χάρισαν ένα όχημα", + soldfor = "Πουλήσατε το όχημά σας για $", + boughtfor = "Αγοράσατε ένα όχημα για $", + }, + menus = { + vehHeader_header = "Επιλογές Οχήματος", + vehHeader_txt = "Αλληλεπιδράστε με το τρέχον όχημα", + financed_header = "Χρηματοδοτούμενα Οχήματα", + finance_txt = "Περιηγηθείτε στα οχήματα που σας ανήκουν", + returnTestDrive_header = "Ολοκλήρωση Δοκιμαστικής Οδήγησης", + goback_header = "Επιστροφή", + veh_price = "Τιμή: $", + veh_platetxt = "Πινακίδα: ", + veh_finance = "Πληρωμή Οχήματος", + veh_finance_balance = "Υπόλοιπο Συνολικού Ποσού", + veh_finance_currency = "€", + veh_finance_total = "Υπόλοιπο Συνολικών Πληρωμών", + veh_finance_reccuring = "Ποσό Επαναλαμβανόμενης Πληρωμής", + veh_finance_pay = "Κάντε μια πληρωμή", + veh_finance_payoff = "Εξόφληση οχήματος", + veh_finance_payment = "Ποσό Πληρωμής (€)", + submit_text = "Υποβολή", + test_header = "Δοκιμαστική Οδήγηση", + finance_header = "Χρηματοδότηση Οχήματος", + swap_header = "Αλλαγή Οχήματος", + swap_txt = "Αλλαγή τρέχοντος επιλεγμένου οχήματος", + financesubmit_downpayment = "Ποσό Προκαταβολής - Ελάχιστο ", + financesubmit_totalpayment = "Συνολικές Πληρωμές - Μέγιστο ", + --Free Use + freeuse_test_txt = "Δοκιμάστε το τρέχον επιλεγμένο όχημα", + freeuse_buy_header = "Αγορά Οχήματος", + freeuse_buy_txt = "Αγοράστε το τρέχον επιλεγμένο όχημα", + freeuse_finance_txt = "Χρηματοδοτήστε το τρέχον επιλεγμένο όχημα", + --Managed + managed_test_txt = "Επιτρέψτε στον παίκτη δοκιμαστική οδήγηση", + managed_sell_header = "Πώληση Οχήματος", + managed_sell_txt = "Πουλήστε όχημα σε Παίκτη", + managed_finance_txt = "Χρηματοδοτήστε όχημα σε Παίκτη", + submit_ID = "Αναγνωριστικό Διακομιστή (#)", + }, + general = { + testdrive_timer = "Υπολειπόμενος Χρόνος Δοκιμαστικής Οδήγησης:", + vehinteraction = "Αλληλεπίδραση με Όχημα", + testdrive_timenoti = "Έχετε %{testdrivetime} λεπτά ακόμα", + testdrive_complete = "Η δοκιμαστική οδήγηση του οχήματος ολοκληρώθηκε", + paymentduein = "Η πληρωμή του οχήματός σας πρέπει να γίνει εντός %{time} λεπτών", + command_transfervehicle = "Χαρίστε ή πουλήστε το όχημά σας", + command_transfervehicle_help = "Αναγνωριστικό αγοραστή", + command_transfervehicle_amount = "Ποσό πώλησης (προαιρετικό)", + } +} + +Lang = Lang or Locale:new({ + phrases = Translations, + warnOnMissing = true +})