diff --git a/INSTALL FIRST/schema.sql b/INSTALL FIRST/schema.sql index 1c75d69..d86f00b 100644 --- a/INSTALL FIRST/schema.sql +++ b/INSTALL FIRST/schema.sql @@ -124,7 +124,7 @@ CREATE TABLE IF NOT EXISTS `player_fractures` ( CREATE TABLE IF NOT EXISTS `medical_history` ( `id` int(11) NOT NULL AUTO_INCREMENT, `citizenid` varchar(50) NOT NULL, - `event_type` enum('wound_created', 'wound_change', 'treatment_applied', 'treatment_change', 'treatment_removed', 'infection_started', 'infection_cured', 'wound_healed', 'wound_scarred', 'fracture_created', 'fracture_healed', 'admin_clear_wounds', 'medical_inspection') NOT NULL, + `event_type` enum('wound_created', 'wound_change', 'treatment_applied', 'treatment_change', 'treatment_removed', 'infection_started', 'infection_cured', 'wound_healed', 'wound_scarred', 'fracture_created', 'fracture_healed', 'admin_clear_wounds', 'medical_inspection','medical_treatment') NOT NULL, `body_part` varchar(20) DEFAULT NULL, `details` json NOT NULL, `performed_by` varchar(50) DEFAULT NULL, diff --git a/client/client.lua b/client/client.lua index 2f4fff1..986e8cd 100644 --- a/client/client.lua +++ b/client/client.lua @@ -451,13 +451,16 @@ end) -- player update health loop --------------------------------------------------------------------- CreateThread(function() + local lasthealth = 0 repeat Wait(1000) until LocalPlayer.state['isLoggedIn'] while true do local health = GetEntityHealth(cache.ped) -- PERFORMANCE FIX: Don't send server events when dead (saves network traffic) - if not deathactive then + if not deathactive and health ~= lasthealth then TriggerServerEvent('QC-AdvancedMedic:server:SetHealth', health) + lasthealth = health + print('^2[QC-AdvancedMedic] Sent health update to server: ' .. tostring(health) .. '^7') end Wait(deathactive and 5000 or 1000) -- Check every 5 seconds when dead, every 1 second when alive @@ -1492,9 +1495,11 @@ end) -- Handle medical treatment messages from NUI (via window.postMessage) RegisterNUICallback('medical-treatment', function(data, cb) + print(json.encode(data)) local action = data.action local treatmentData = data.data - + local targetPlayerId = treatmentData.playerId + if not action or not treatmentData then cb({status = 'error', message = 'Invalid treatment data'}) return @@ -1508,7 +1513,6 @@ RegisterNUICallback('medical-treatment', function(data, cb) if action == 'administer-medicine' then -- Use the existing administer-medicine callback logic local medicineType = treatmentData.itemType - local targetPlayerId = treatmentData.playerId if not medicineType then cb({status = 'error', message = 'Missing medicine type'}) @@ -1550,6 +1554,7 @@ RegisterNUICallback('medical-treatment', function(data, cb) end else -- Handle real player medicine application + print(string.format("^3[MEDICAL-TREATMENT] Administering %s to player %s^7", medicineType, tostring(targetPlayerId))) TriggerServerEvent('QC-AdvancedMedic:server:MedicApplyMedicine', targetPlayerId, medicineType) cb({status = 'success', message = 'Medicine administered successfully'}) @@ -1573,6 +1578,7 @@ RegisterNUICallback('medical-treatment', function(data, cb) cb({status = 'success', message = 'Bandage applied to mission patient'}) else + print(string.format("^3[MEDICAL-TREATMENT] Applying %s bandage to player %s on body part %s^7", bandageType, tostring(targetPlayerId), bodyPart)) -- Handle real player bandage application TriggerServerEvent('QC-AdvancedMedic:server:MedicApplyBandage', targetPlayerId, bodyPart, bandageType) cb({status = 'success', message = 'Bandage applied successfully'}) diff --git a/client/treatment_system.lua b/client/treatment_system.lua index 8b462d8..c5f34dc 100644 --- a/client/treatment_system.lua +++ b/client/treatment_system.lua @@ -30,13 +30,15 @@ local InjectionEffects = {} -- NEW BANDAGE SYSTEM - One-time Application with Decay --========================================================= function ApplyBandage(bodyPart, bandageType, appliedBy) + print("Applying bandage:", bodyPart, bandageType, appliedBy) + local bandageConfig = Config.BandageTypes[bandageType] if not bandageConfig then print("[ERROR] Unknown bandage type: " .. tostring(bandageType)) return false end - local bodyPartConfig = Config.BodyParts[bodyPart] + local bodyPartConfig = Config.BodyParts[string.upper(bodyPart)] or Config.BodyParts[bodyPart] if not bodyPartConfig then print("[ERROR] Unknown body part: " .. tostring(bodyPart)) return false @@ -45,7 +47,10 @@ function ApplyBandage(bodyPart, bandageType, appliedBy) -- Get current wounds for this body part local wounds = PlayerWounds or {} local wound = wounds[bodyPart] + local bleadingLevel = wound and tonumber(wound.bleedingLevel) or 0 + local painLevel = wound and tonumber(wound.painLevel) or 0 + -- Check if wound exists if not wound then lib.notify({ title = locale('cl_menu_treatment'), @@ -57,7 +62,8 @@ function ApplyBandage(bodyPart, bandageType, appliedBy) end -- Check if wound is bleeding (bandages only work on bleeding wounds) - if not wound.bleedingLevel or wound.bleedingLevel <= 0 then + print(bleadingLevel) + if not bleadingLevel or bleadingLevel <= 0 then lib.notify({ title = locale('cl_menu_treatment'), description = string.format(locale('cl_desc_fmt_no_bleeding_detected'), bodyPartConfig.label), @@ -93,24 +99,24 @@ function ApplyBandage(bodyPart, bandageType, appliedBy) -- SIMPLIFIED TIME-BASED BANDAGE SYSTEM -- Store original wound levels for 50% return when bandage expires - local originalPain = wound.painLevel - local originalBleeding = wound.bleedingLevel + local originalPain = painLevel + local originalBleeding = bleadingLevel -- BLEEDING REDUCTION (immediate effect) local bleedingReduction = 0 - if wound.bleedingLevel > 0 and bandageConfig.bleedingReduction then + if bleadingLevel > 0 and bandageConfig.bleedingReduction then bleedingReduction = bandageConfig.bleedingReduction -- Apply reduction but maintain minimum level 1 (wounds don't vanish) - wound.bleedingLevel = math.max(wound.bleedingLevel - bleedingReduction, 1) + bleadingLevel = math.max(bleadingLevel - bleedingReduction, 1) end -- PAIN REDUCTION (proportional to bleeding reduction since pain = bleeding + tissue damage) local painReduction = 0 - if bleedingReduction > 0 and wound.painLevel > 0 then + if bleedingReduction > 0 and painLevel > 0 then -- Pain reduces proportionally to bleeding (since pain is related to bleeding) -- But maintain minimum level 2 (tissue damage persists) painReduction = bleedingReduction - wound.painLevel = math.max(wound.painLevel - painReduction, 2) + painLevel = math.max(painLevel - painReduction, 2) end -- Update wound data on server @@ -118,7 +124,7 @@ function ApplyBandage(bodyPart, bandageType, appliedBy) if Config.WoundSystem.debugging.enabled then print(string.format("^3[BANDAGE] Pain:%.1f→%.1f Bleed:%.1f→%.1f^7", - originalPain or 0, wound.painLevel or 0, originalBleeding or 0, wound.bleedingLevel or 0)) + originalPain or 0, painLevel or 0, originalBleeding or 0, bleadingLevel or 0)) end -- SIMPLIFIED TIME-BASED BANDAGE TRACKING @@ -236,6 +242,7 @@ end --========================================================= local function ApplyTourniquet(bodyPart, tourniquetType, appliedBy) local tourniquetConfig = Config.TourniquetTypes[tourniquetType] + local bodyPart = string.upper(bodyPart) if not tourniquetConfig then print("[ERROR] Unknown tourniquet type: " .. tostring(tourniquetType)) return false @@ -282,11 +289,12 @@ local function ApplyTourniquet(bodyPart, tourniquetType, appliedBy) -- Get current wounds for bleeding check local wounds = PlayerWounds or {} local wound = wounds[bodyPart] - + local bleadingLevel = wound and tonumber(wound.bleedingLevel) or 0 + local painLevel = wound and tonumber(wound.painLevel) or 0 -- Apply immediate bleeding control - if wound and wound.bleedingLevel > 0 then + if wound and bleadingLevel > 0 then if math.random() <= tourniquetConfig.bleedingStopChance then - wound.bleedingLevel = 0 + bleadingLevel = 0 TriggerServerEvent('QC-AdvancedMedic:server:UpdateWoundData', wounds) lib.notify({ @@ -315,7 +323,7 @@ local function ApplyTourniquet(bodyPart, tourniquetType, appliedBy) -- Increase pain due to tourniquet pressure if wound and tourniquetConfig.painIncrease then - wound.painLevel = math.min(wound.painLevel + (tourniquetConfig.painIncrease / 10), 10) + painLevel = math.min(painLevel + (tourniquetConfig.painIncrease / 10), 10) TriggerServerEvent('QC-AdvancedMedic:server:UpdateWoundData', wounds) end @@ -449,7 +457,8 @@ local function AdministreMedicine(medicineType, appliedBy) -- Medicine affects pain conditions across all wounded body parts if PlayerWounds then for bodyPart, woundData in pairs(PlayerWounds) do - if woundData and woundData.painLevel and woundData.painLevel > 0 then + local painLevel = tonumber(woundData.painLevel) or 0 + if woundData and painLevel and painLevel > 0 then -- Add medicine treatment to the wound's treatments if not woundData.treatments then woundData.treatments = {} @@ -694,6 +703,7 @@ end) RegisterNetEvent('QC-AdvancedMedic:client:ApplyBandage') AddEventHandler('QC-AdvancedMedic:client:ApplyBandage', function(bodyPart, bandageType, appliedBy) ApplyBandage(bodyPart, bandageType, appliedBy) + end) RegisterNetEvent('QC-AdvancedMedic:client:ApplyTourniquet') diff --git a/config.lua b/config.lua index 7edabfa..52b860e 100644 --- a/config.lua +++ b/config.lua @@ -164,7 +164,7 @@ Config.MedicJobLocations = { prompt = 'valmedic', coords = vector3(-289.46, 806.82, 119.39 - 0.08), showblip = true, - job = 'valmedic' + job = 'doctor' }, { name = 'Saint Denis', @@ -318,7 +318,7 @@ Config.BodyParts = { HEAD = { label = 'Head', maxHealth = 100 , limp = false }, NECK = { label = 'Neck', maxHealth = 80 , limp = false }, SPINE = { label = 'Spine', maxHealth = 120 , limp = true }, - UPPER_BODY = { label = 'Upper Body', maxHealth = 150 , limp = false }, + UPBODY = { label = 'Upper Body', maxHealth = 150 , limp = false }, LOWER_BODY = { label = 'Lower Body', maxHealth = 150 , limp = true }, LARM = { label = 'Left Arm', maxHealth = 90 , limp = false }, LHAND = { label = 'Left Hand', maxHealth = 60 , limp = false }, diff --git a/server/database.lua b/server/database.lua index fa7157c..b290304 100644 --- a/server/database.lua +++ b/server/database.lua @@ -207,7 +207,6 @@ local function SaveTreatmentData(citizenid, treatmentData) if not citizenid or not treatmentData then return false end -- Mark all existing treatments as inactive - MySQL.Async.execute('UPDATE medical_treatments SET is_active = 0 WHERE citizenid = ? AND is_active = 1', {citizenid}) -- Insert current active treatments (supports all treatment types) for bodyPart, treatment in pairs(treatmentData) do @@ -229,9 +228,9 @@ local function SaveTreatmentData(citizenid, treatmentData) MySQL.Async.execute([[ INSERT INTO medical_treatments - (citizenid, body_part, treatment_type, item_type, applied_by, expiration_time, duration, + (citizenid, body_part, treatment_type, item_type, applied_by, expiration_time, duration, is_active, original_pain_level, original_bleeding_level, pain_reduction, bleeding_reduction, metadata) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ]], { citizenid, bodyPart, @@ -240,6 +239,7 @@ local function SaveTreatmentData(citizenid, treatmentData) treatment.appliedBy or citizenid, -- Default to self if not specified mysqlExpirationTime, -- Properly formatted MySQL datetime treatment.duration, -- NULL for bandages, seconds for medicines + 1, treatment.originalPainLevel, -- Original pain before treatment treatment.originalBleedingLevel, -- Original bleeding before treatment treatment.painReduction, -- How much pain was reduced @@ -261,11 +261,12 @@ end -- Load treatment data for a player local function LoadTreatmentData(citizenid) + print('Loading treatment data for ' .. citizenid) if not citizenid then return {} end local result = MySQL.Sync.fetchAll('SELECT * FROM medical_treatments WHERE citizenid = ? AND is_active = 1', {citizenid}) local treatmentData = {} - + print('Found ' .. #result .. ' treatment records') for _, row in ipairs(result) do local metadata = {} if row.metadata then diff --git a/server/medical_server.lua b/server/medical_server.lua index 1df9432..10c7ec0 100644 --- a/server/medical_server.lua +++ b/server/medical_server.lua @@ -200,8 +200,8 @@ RegisterNetEvent('QC-AdvancedMedic:server:MedicApplyBandage') AddEventHandler('QC-AdvancedMedic:server:MedicApplyBandage', function(targetId, bodyPart, bandageType) local src = source local Medic = RSGCore.Functions.GetPlayer(src) - local Patient = RSGCore.Functions.GetPlayer(targetId) - + local Patient = RSGCore.Functions.GetPlayerByCitizenId(targetId) + print(targetId) if not Medic or not Patient then return end -- Check if source is a medic @@ -216,7 +216,7 @@ AddEventHandler('QC-AdvancedMedic:server:MedicApplyBandage', function(targetId, end -- Check if medic has the required item - if not Medic.Functions.GetItemByName(bandageType) then + if not Medic.Functions.GetItemByName(Config.BandageTypes[bandageType].itemName or bandageType) then TriggerClientEvent('ox_lib:notify', src, { title = locale('sv_missing_supplies'), description = string.format(locale('sv_you_dont_have_item'), bandageType), @@ -227,7 +227,7 @@ AddEventHandler('QC-AdvancedMedic:server:MedicApplyBandage', function(targetId, end -- Remove item from medic - if Medic.Functions.RemoveItem(bandageType, 1) then + if Medic.Functions.RemoveItem(Config.BandageTypes[bandageType].itemName or bandageType, 1) then TriggerClientEvent('rsg-inventory:client:ItemBox', src, RSGCore.Shared.Items[bandageType], 'remove', 1) -- Apply treatment to patient @@ -236,7 +236,7 @@ AddEventHandler('QC-AdvancedMedic:server:MedicApplyBandage', function(targetId, -- Log medical action exports['QC-AdvancedMedic']:LogMedicalEvent( Patient.PlayerData.citizenid, - 'medic_treatment', + 'medical_treatment', string.format("Medic applied %s to %s", bandageType, bodyPart), bodyPart, Medic.PlayerData.citizenid @@ -263,7 +263,8 @@ RegisterNetEvent('QC-AdvancedMedic:server:MedicApplyTourniquet') AddEventHandler('QC-AdvancedMedic:server:MedicApplyTourniquet', function(targetId, bodyPart, tourniquetType) local src = source local Medic = RSGCore.Functions.GetPlayer(src) - local Patient = RSGCore.Functions.GetPlayer(targetId) + local Patient = RSGCore.Functions.GetPlayerByCitizenId(targetId) + if not Medic or not Patient then return end @@ -279,7 +280,7 @@ AddEventHandler('QC-AdvancedMedic:server:MedicApplyTourniquet', function(targetI end -- Check if medic has the required item - if not Medic.Functions.GetItemByName(tourniquetType) then + if not Medic.Functions.GetItemByName(Config.TourniquetTypes[tourniquetType].itemName or tourniquetType) then TriggerClientEvent('ox_lib:notify', src, { title = locale('sv_missing_supplies'), description = string.format(locale('sv_you_dont_have_item'), tourniquetType), @@ -290,7 +291,7 @@ AddEventHandler('QC-AdvancedMedic:server:MedicApplyTourniquet', function(targetI end -- Remove item from medic - if Medic.Functions.RemoveItem(tourniquetType, 1) then + if Medic.Functions.RemoveItem(Config.TourniquetTypes[tourniquetType].itemName or tourniquetType, 1) then TriggerClientEvent('rsg-inventory:client:ItemBox', src, RSGCore.Shared.Items[tourniquetType], 'remove', 1) -- Apply emergency treatment to patient @@ -299,7 +300,7 @@ AddEventHandler('QC-AdvancedMedic:server:MedicApplyTourniquet', function(targetI -- Log medical action exports['QC-AdvancedMedic']:LogMedicalEvent( Patient.PlayerData.citizenid, - 'emergency_treatment', + 'medical_treatment', string.format("Medic applied emergency %s to %s", tourniquetType, bodyPart), bodyPart, Medic.PlayerData.citizenid @@ -324,9 +325,11 @@ end) RegisterNetEvent('QC-AdvancedMedic:server:MedicApplyMedicine') AddEventHandler('QC-AdvancedMedic:server:MedicApplyMedicine', function(targetId, medicineType) + print("MedicApplyMedicine triggered",targetId) local src = source local Medic = RSGCore.Functions.GetPlayer(src) - local Patient = RSGCore.Functions.GetPlayer(targetId) + local Patient = RSGCore.Functions.GetPlayerByCitizenId(targetId) + if not Medic or not Patient then return end @@ -384,7 +387,7 @@ AddEventHandler('QC-AdvancedMedic:server:MedicApplyMedicine', function(targetId, -- Log medical action exports['QC-AdvancedMedic']:LogMedicalEvent( Patient.PlayerData.citizenid, - 'medicine_treatment', + 'medical_treatment', string.format("Medic administered %s for pain management", medicineConfig.label or medicineType), 'patient', -- Medicine affects the whole patient, not specific body part Medic.PlayerData.citizenid @@ -556,7 +559,7 @@ end) --========================================================= -- MEDIC INSPECT COMMAND --========================================================= -RSGCore.Commands.Add('inspect', 'Inspect another player\'s medical condition (Medic Only)', {{name = 'id', help = 'Player ID to inspect'}}, true, function(source, args) +RSGCore.Commands.Add('inspectmedic', 'Inspect another player\'s medical condition (Medic Only)', {{name = 'id', help = 'Player ID to inspect'}}, true, function(source, args) local src = source print('^3[QC-AdvancedMedic] DEBUG: /inspect command triggered by player ' .. src .. '^7') local Medic = RSGCore.Functions.GetPlayer(src)