[{"data":1,"prerenderedAt":2151},["ShallowReactive",2],{"/docs/jobs/ambulancejob/custom-medications":3,"/docs/jobs/ambulancejob/custom-medications-surround":2140},{"id":4,"title":5,"body":6,"description":2131,"extension":2132,"head":2133,"meta":2134,"navigation":1345,"path":2135,"schemaOrg":2133,"seo":2136,"sitemap":2137,"stem":2138,"__hash__":2139},"docs/1.docs/0.jobs/0.ambulancejob/3.custom-medications.md","Custom Medications",{"type":7,"value":8,"toc":2108},"minimark",[9,14,49,84,87,95,176,178,182,567,570,592,595,634,640,642,650,664,671,674,706,709,728,731,780,787,815,821,824,840,853,863,899,902,923,925,929,933,1120,1127,1131,1616,1623,1630,1856,1863,1865,1872,1882,1911,1922,1924,1928,2026,2033,2035,2039,2104],[10,11,13],"h2",{"id":12},"what-it-is","What it is",[15,16,17,21,22,25,26,29,30,33,34,37,38,41,42,41,45,48],"p",{},[18,19,20],"code",{},"Config.CustomMedications"," is a third sibling table to ",[18,23,24],{},"Config.Medications"," and ",[18,27,28],{},"Config.HealingItems",". Each entry registers a usable inventory item that, when used, plays an animation on the patient, applies declarative vitals effects, and (optionally) runs paired ",[18,31,32],{},"onUseClient"," / ",[18,35,36],{},"onUseServer"," callbacks (and ",[18,39,40],{},"onTick","/",[18,43,44],{},"onFinish",[18,46,47],{},"onCancel"," variants) for full control.",[15,50,51,52,55,56,55,59,55,62,55,65,55,68,55,71,55,74,55,77,80,81,83],{},"Declarative fields (",[18,53,54],{},"pain",", ",[18,57,58],{},"bleeding",[18,60,61],{},"heal",[18,63,64],{},"effect",[18,66,67],{},"requiresOpenWound",[18,69,70],{},"stopBleeding",[18,72,73],{},"pauseBleedingSeconds",[18,75,76],{},"duration",[18,78,79],{},"effectDurationSeconds",") are forwarded to the same engine that powers ",[18,82,24],{},", so vitals stay synchronised without duplicated logic.",[85,86],"hr",{},[10,88,90,91,94],{"id":89},"the-three-type-values","The three ",[18,92,93],{},"type"," values",[96,97,98,111],"table",{},[99,100,101],"thead",{},[102,103,104,108],"tr",{},[105,106,107],"th",{},"Type",[105,109,110],{},"Behaviour",[112,113,114,134,166],"tbody",{},[102,115,116,122],{},[117,118,119],"td",{},[18,120,121],{},"\"medication\"",[117,123,124,125,128,129,33,131,133],{},"One-shot consumable. Plays anim for ",[18,126,127],{},"time"," ms, runs ",[18,130,32],{},[18,132,36],{}," once, applies declarative effects on finish.",[102,135,136,141],{},[117,137,138],{},[18,139,140],{},"\"infusion\"",[117,142,143,144,146,147,150,151,33,154,157,158,161,162,165],{},"Setup phase (",[18,145,127],{}," ms) then a tick loop running for ",[18,148,149],{},"injectingTime"," ms. ",[18,152,153],{},"onTickClient",[18,155,156],{},"onTickServer"," fire every ",[18,159,160],{},"tickIntervalMs"," (default ",[18,163,164],{},"1000","). Declarative effects apply once on finish.",[102,167,168,173],{},[117,169,170],{},[18,171,172],{},"\"custom\"",[117,174,175],{},"No built-in effects. Pure callback hook. Use this for anything that doesn't fit the declarative model — defibrillators, vehicle interactions, custom revives.",[85,177],{},[10,179,181],{"id":180},"field-reference","Field reference",[96,183,184,199],{},[99,185,186],{},[102,187,188,191,193,196],{},[105,189,190],{},"Field",[105,192,107],{},[105,194,195],{},"Required",[105,197,198],{},"Notes",[112,200,201,223,237,251,267,290,307,321,335,354,367,384,397,410,423,439,452,465,478,502,518,533,550],{},[102,202,203,207,210,213],{},[117,204,205],{},[18,206,93],{},[117,208,209],{},"string",[117,211,212],{},"yes",[117,214,215,55,217,219,220,222],{},[18,216,121],{},[18,218,140],{},", or ",[18,221,172],{},".",[102,224,225,229,232,234],{},[117,226,227],{},[18,228,127],{},[117,230,231],{},"number (ms)",[117,233,212],{},[117,235,236],{},"Duration of the progress phase. For infusions this is the setup phase before the tick loop starts.",[102,238,239,243,245,248],{},[117,240,241],{},[18,242,149],{},[117,244,231],{},[117,246,247],{},"infusion",[117,249,250],{},"How long the tick loop runs.",[102,252,253,257,259,262],{},[117,254,255],{},[18,256,160],{},[117,258,231],{},[117,260,261],{},"no",[117,263,264,265,222],{},"Tick cadence. Default ",[18,266,164],{},[102,268,269,274,277,279],{},[117,270,271],{},[18,272,273],{},"removeItem",[117,275,276],{},"boolean",[117,278,261],{},[117,280,281,282,285,286,289],{},"Remove the item on finish. Default ",[18,283,284],{},"true",". Set ",[18,287,288],{},"false"," for reusable items like a defibrillator.",[102,291,292,297,302,304],{},[117,293,294],{},[18,295,296],{},"anim",[117,298,299],{},[18,300,301],{},"{ dict, name }",[117,303,261],{},[117,305,306],{},"Played on the user's ped while the run is active.",[102,308,309,314,316,318],{},[117,310,311],{},[18,312,313],{},"lang",[117,315,209],{},[117,317,261],{},[117,319,320],{},"Progress label shown while the run is active.",[102,322,323,328,330,332],{},[117,324,325],{},[18,326,327],{},"langUsed",[117,329,209],{},[117,331,261],{},[117,333,334],{},"Success notification text shown on finish.",[102,336,337,342,345,347],{},[117,338,339],{},[18,340,341],{},"volume",[117,343,344],{},"number",[117,346,261],{},[117,348,349,350,353],{},"Informational. Surfaced on ",[18,351,352],{},"self.volume"," for callback use.",[102,355,356,360,362,364],{},[117,357,358],{},[18,359,54],{},[117,361,344],{},[117,363,261],{},[117,365,366],{},"Negative reduces pain, positive raises it. Routed through the existing pain-modifier system.",[102,368,369,373,375,377],{},[117,370,371],{},[18,372,58],{},[117,374,344],{},[117,376,261],{},[117,378,379,380,383],{},"Class delta (",[18,381,382],{},"-2"," reduces bleeding by 2 classes on the matched wound).",[102,385,386,390,392,394],{},[117,387,388],{},[18,389,61],{},[117,391,344],{},[117,393,261],{},[117,395,396],{},"HP to restore on finish.",[102,398,399,403,405,407],{},[117,400,401],{},[18,402,64],{},[117,404,209],{},[117,406,261],{},[117,408,409],{},"Screen effect name.",[102,411,412,416,418,420],{},[117,413,414],{},[18,415,79],{},[117,417,344],{},[117,419,261],{},[117,421,422],{},"Effect duration in seconds.",[102,424,425,429,431,433],{},[117,426,427],{},[18,428,67],{},[117,430,276],{},[117,432,261],{},[117,434,435,436,438],{},"If ",[18,437,284],{},", run only starts when the target has an active open wound.",[102,440,441,445,447,449],{},[117,442,443],{},[18,444,70],{},[117,446,276],{},[117,448,261],{},[117,450,451],{},"Permanently stops bleeding on every open wound.",[102,453,454,458,460,462],{},[117,455,456],{},[18,457,73],{},[117,459,344],{},[117,461,261],{},[117,463,464],{},"Pauses bleeding on every open wound for N seconds.",[102,466,467,471,473,475],{},[117,468,469],{},[18,470,76],{},[117,472,344],{},[117,474,261],{},[117,476,477],{},"Optional pain-modifier expiry in seconds.",[102,479,480,485,487,489],{},[117,481,482],{},[18,483,484],{},"access.lockAccess",[117,486,276],{},[117,488,261],{},[117,490,491,493,494,497,498,501],{},[18,492,284],{}," -> only on-duty medics can use the item, and ",[18,495,496],{},"self.target"," is auto-resolved to the closest player within ",[18,499,500],{},"_maxTargetDistance"," (refused if none).",[102,503,504,510,513,515],{},[117,505,506,55,508],{},[18,507,32],{},[18,509,36],{},[117,511,512],{},"function",[117,514,261],{},[117,516,517],{},"Run once at start, on each side.",[102,519,520,526,528,530],{},[117,521,522,55,524],{},[18,523,153],{},[18,525,156],{},[117,527,512],{},[117,529,261],{},[117,531,532],{},"Infusions only. Run on each tick on each side.",[102,534,535,543,545,547],{},[117,536,537,55,540],{},[18,538,539],{},"onFinishClient",[18,541,542],{},"onFinishServer",[117,544,512],{},[117,546,261],{},[117,548,549],{},"Run once on completion on each side.",[102,551,552,560,562,564],{},[117,553,554,55,557],{},[18,555,556],{},"onCancelClient",[18,558,559],{},"onCancelServer",[117,561,512],{},[117,563,261],{},[117,565,566],{},"Run once on interruption on each side.",[15,568,569],{},"Legacy aliases (normalised at load):",[571,572,573,583],"ul",{},[574,575,576,579,580],"li",{},[18,577,578],{},"painReduce = N"," -> ",[18,581,582],{},"pain = -N",[574,584,585,588,589],{},[18,586,587],{},"lockAccess = true/false"," (top-level) -> ",[18,590,591],{},"access.lockAccess = ...",[15,593,594],{},"A single top-level knob applies to every entry:",[596,597,603],"pre",{"className":598,"code":599,"filename":600,"language":601,"meta":602,"style":602},"language-lua shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","Config.CustomMedications._maxTargetDistance = 3.0  -- metres\n","config.lua","lua","",[18,604,605],{"__ignoreMap":602},[606,607,610,614,618,620,622,626,630],"span",{"class":608,"line":609},"line",1,[606,611,613],{"class":612},"sTEyZ","Config.",[606,615,617],{"class":616},"sBMFI","CustomMedications",[606,619,222],{"class":612},[606,621,500],{"class":616},[606,623,625],{"class":624},"sMK4o"," =",[606,627,629],{"class":628},"sbssI"," 3.0",[606,631,633],{"class":632},"sHwdD","  -- metres\n",[15,635,636,637,639],{},"This bounds the auto-resolved ",[18,638,496],{}," for medic-only items and is also the range threshold that auto-cancels an in-progress cross-player infusion if the medic walks away.",[85,641],{},[10,643,645,646,649],{"id":644},"the-self-helper","The ",[18,647,648],{},"self"," helper",[15,651,652,653,655,656,663],{},"Each callback receives a ",[18,654,648],{}," table sized to its environment. ",[657,658,659,660,662],"strong",{},"Client-side ",[18,661,648],{}," cannot mutate vitals"," — only the server-side helper can. This makes the security model trivial: the client can't ask the server to mutate state through the helper.",[665,666,668,669],"h3",{"id":667},"client-self","Client ",[18,670,648],{},[15,672,673],{},"Static state (read-only):",[571,675,676,695,701],{},[574,677,678,55,681,55,684,55,686,55,689,55,692],{},[18,679,680],{},"self.itemName",[18,682,683],{},"self.type",[18,685,352],{},[18,687,688],{},"self.time",[18,690,691],{},"self.injectingTime",[18,693,694],{},"self.elapsed",[574,696,697,700],{},[18,698,699],{},"self.source"," — serverId of the user",[574,702,703,705],{},[18,704,496],{}," — serverId resolved at start (closest player for medic-only, otherwise self)",[15,707,708],{},"Vital mirrors (refreshed every tick from a piggybacked snapshot — no extra round-trip):",[571,710,711],{},[574,712,713,55,716,55,719,55,722,55,725],{},[18,714,715],{},"self.blood",[18,717,718],{},"self.pain",[18,720,721],{},"self.heartRate",[18,723,724],{},"self.bloodPressure",[18,726,727],{},"self.oxygenLevel",[15,729,730],{},"Local helpers (run on the user's machine):",[571,732,733,741,746,751,761,770],{},[574,734,735,33,738],{},[18,736,737],{},"self:fadeOut(ms)",[18,739,740],{},"self:fadeIn(ms)",[574,742,743],{},[18,744,745],{},"self:ragdoll(ms)",[574,747,748],{},[18,749,750],{},"self:playSound(soundSet, soundName)",[574,752,753,756,757,760],{},[18,754,755],{},"self:playSoundAt(url, volume)"," — wraps ",[18,758,759],{},"exports.xsound:PlayUrlPos"," at the user's coords",[574,762,763,766,767],{},[18,764,765],{},"self:coords()"," — returns the user's ",[18,768,769],{},"vector3",[574,771,772,775,776,779],{},[18,773,774],{},"self:cancel(reason)"," — abort cleanly (no ",[18,777,778],{},"onFinish*",", no item consumption)",[15,781,782,783,786],{},"Targeting helpers (return a serverId or ",[18,784,785],{},"nil","):",[571,788,789,809],{},[574,790,791,794,795,161,798,801,802,805,806,222],{},[18,792,793],{},"self:nearbyPlayer(opts)"," — closest player ped within ",[18,796,797],{},"opts.maxDistance",[18,799,800],{},"3.0","); ",[18,803,804],{},"opts.requireFacing = true"," for forward-cone filter; ",[18,807,808],{},"opts.includeSelf = false",[574,810,811,814],{},[18,812,813],{},"self:aimingAt()"," — the ped the user is currently free-aiming at.",[665,816,818,819],{"id":817},"server-self","Server ",[18,820,648],{},[15,822,823],{},"Same static state, plus:",[571,825,826,834],{},[574,827,828,831,832],{},[18,829,830],{},"self.patient"," — the patient record for ",[18,833,699],{},[574,835,836,839],{},[18,837,838],{},"self:patientFor(serverId)"," — patient record for any other player",[15,841,842,843,55,846,55,849,852],{},"Direct read of the patient record is fine: ",[18,844,845],{},"self.patient.conditions.bloodVolume",[18,847,848],{},"self.patient.conditions.pain",[18,850,851],{},"self.patient.vitals.heart_rate",", etc.",[15,854,855,856,859,860,862],{},"State mutators (no event hop, direct call into the medication engine — ",[18,857,858],{},"target"," defaults to ",[18,861,496],{}," when omitted):",[571,864,865,873,882,887,893],{},[574,866,867,33,870],{},[18,868,869],{},"self:reducePain(amount, target?)",[18,871,872],{},"self:addPain(amount, target?)",[574,874,875,878,879],{},[18,876,877],{},"self:addBlood(amount, target?)"," — clamped to ",[18,880,881],{},"Config.BloodSystem.maxVolume",[574,883,884],{},[18,885,886],{},"self:setBleeding(zone, classDelta, target?)",[574,888,889,892],{},[18,890,891],{},"self:heal(amount, target?)"," — fires the existing heal event on the target",[574,894,895,898],{},[18,896,897],{},"self:revive(target?)"," — runs the standard revive flow",[15,900,901],{},"Helpers:",[571,903,904,913,918],{},[574,905,906,909,910],{},[18,907,908],{},"self:isMedic(serverId?)"," — uses ",[18,911,912],{},"Sky_Jobs.PlayerCache",[574,914,915],{},[18,916,917],{},"self:distance(target?)",[574,919,920,922],{},[18,921,774],{}," — server-driven cancel (e.g. when the target walks out of range mid-infusion)",[85,924],{},[10,926,928],{"id":927},"worked-examples","Worked examples",[665,930,932],{"id":931},"one-shot-medication","One-shot medication",[596,934,936],{"className":598,"code":935,"filename":600,"language":601,"meta":602,"style":602},"vomex = {\n    type        = \"medication\",\n    time        = 2000,\n    removeItem  = true,\n    anim        = {\n        dict = \"anim@heists@narcotics@funding@gang_idle\",\n        name = \"gang_chatting_idle01\"\n    },\n    lang        = \"Nehme Vomex...\",\n    langUsed    = \"Vomex eingenommen\",\n    pain        = -2,\n    access      = { lockAccess = false }\n},\n",[18,937,938,949,970,983,996,1006,1023,1039,1045,1062,1079,1095,1114],{"__ignoreMap":602},[606,939,940,943,946],{"class":608,"line":609},[606,941,942],{"class":612},"vomex ",[606,944,945],{"class":624},"=",[606,947,948],{"class":612}," {\n",[606,950,952,955,957,960,964,967],{"class":608,"line":951},2,[606,953,954],{"class":612},"    type        ",[606,956,945],{"class":624},[606,958,959],{"class":624}," \"",[606,961,963],{"class":962},"sfazB","medication",[606,965,966],{"class":624},"\"",[606,968,969],{"class":612},",\n",[606,971,973,976,978,981],{"class":608,"line":972},3,[606,974,975],{"class":612},"    time        ",[606,977,945],{"class":624},[606,979,980],{"class":628}," 2000",[606,982,969],{"class":612},[606,984,986,989,991,994],{"class":608,"line":985},4,[606,987,988],{"class":612},"    removeItem  ",[606,990,945],{"class":624},[606,992,993],{"class":624}," true",[606,995,969],{"class":612},[606,997,999,1002,1004],{"class":608,"line":998},5,[606,1000,1001],{"class":612},"    anim        ",[606,1003,945],{"class":624},[606,1005,948],{"class":612},[606,1007,1009,1012,1014,1016,1019,1021],{"class":608,"line":1008},6,[606,1010,1011],{"class":612},"        dict ",[606,1013,945],{"class":624},[606,1015,959],{"class":624},[606,1017,1018],{"class":962},"anim@heists@narcotics@funding@gang_idle",[606,1020,966],{"class":624},[606,1022,969],{"class":612},[606,1024,1026,1029,1031,1033,1036],{"class":608,"line":1025},7,[606,1027,1028],{"class":612},"        name ",[606,1030,945],{"class":624},[606,1032,959],{"class":624},[606,1034,1035],{"class":962},"gang_chatting_idle01",[606,1037,1038],{"class":624},"\"\n",[606,1040,1042],{"class":608,"line":1041},8,[606,1043,1044],{"class":612},"    },\n",[606,1046,1048,1051,1053,1055,1058,1060],{"class":608,"line":1047},9,[606,1049,1050],{"class":612},"    lang        ",[606,1052,945],{"class":624},[606,1054,959],{"class":624},[606,1056,1057],{"class":962},"Nehme Vomex...",[606,1059,966],{"class":624},[606,1061,969],{"class":612},[606,1063,1065,1068,1070,1072,1075,1077],{"class":608,"line":1064},10,[606,1066,1067],{"class":612},"    langUsed    ",[606,1069,945],{"class":624},[606,1071,959],{"class":624},[606,1073,1074],{"class":962},"Vomex eingenommen",[606,1076,966],{"class":624},[606,1078,969],{"class":612},[606,1080,1082,1085,1087,1090,1093],{"class":608,"line":1081},11,[606,1083,1084],{"class":612},"    pain        ",[606,1086,945],{"class":624},[606,1088,1089],{"class":624}," -",[606,1091,1092],{"class":628},"2",[606,1094,969],{"class":612},[606,1096,1098,1101,1103,1106,1108,1111],{"class":608,"line":1097},12,[606,1099,1100],{"class":612},"    access      ",[606,1102,945],{"class":624},[606,1104,1105],{"class":612}," { lockAccess ",[606,1107,945],{"class":624},[606,1109,1110],{"class":624}," false",[606,1112,1113],{"class":612}," }\n",[606,1115,1117],{"class":608,"line":1116},13,[606,1118,1119],{"class":612},"},\n",[15,1121,1122,1123,1126],{},"Player uses ",[18,1124,1125],{},"vomex"," from inventory -> 2-second progress -> item removed -> pain drops by 2. No callbacks needed.",[665,1128,1130],{"id":1129},"sustained-infusion","Sustained infusion",[596,1132,1134],{"className":598,"code":1133,"filename":600,"language":601,"meta":602,"style":602},"fentanyl = {\n    type           = \"infusion\",\n    time           = 3000,\n    injectingTime  = 5 * 60 * 1000,\n    tickIntervalMs = 1000,\n    removeItem     = true,\n    volume         = 20,\n    anim           = { dict = \"anim@heists@narcotics@funding@gang_idle\",\n                       name = \"gang_chatting_idle01\" },\n    lang           = \"Verabreiche Fentanyl...\",\n    langUsed       = \"Fentanyl verabreicht\",\n    pain           = -8,\n    duration       = 300,\n    access         = { lockAccess = true },\n\n    -- Visual: ragdoll + fade. Runs on the patient's machine.\n    onUseClient    = function(self) self:fadeOut(15000) end,\n    onTickClient   = function(self) self:ragdoll(5000) end,\n    onFinishClient = function(self) self:fadeIn(15000) end,\n\n    -- Authoritative: blood + pain mutations. Runs on the server.\n    onTickServer   = function(self)\n        if self.patient.conditions.bloodVolume \u003C 60 then\n            self:addBlood(0.1)\n        end\n        local pain = self.patient.conditions.pain or 0\n        if pain > 0 then\n            self:reducePain(pain / 5)\n        end\n    end\n},\n",[18,1135,1136,1145,1160,1172,1195,1206,1217,1229,1249,1265,1281,1297,1311,1323,1340,1347,1353,1395,1428,1459,1464,1470,1487,1517,1533,1539,1568,1583,1600,1605,1611],{"__ignoreMap":602},[606,1137,1138,1141,1143],{"class":608,"line":609},[606,1139,1140],{"class":612},"fentanyl ",[606,1142,945],{"class":624},[606,1144,948],{"class":612},[606,1146,1147,1150,1152,1154,1156,1158],{"class":608,"line":951},[606,1148,1149],{"class":612},"    type           ",[606,1151,945],{"class":624},[606,1153,959],{"class":624},[606,1155,247],{"class":962},[606,1157,966],{"class":624},[606,1159,969],{"class":612},[606,1161,1162,1165,1167,1170],{"class":608,"line":972},[606,1163,1164],{"class":612},"    time           ",[606,1166,945],{"class":624},[606,1168,1169],{"class":628}," 3000",[606,1171,969],{"class":612},[606,1173,1174,1177,1179,1182,1185,1188,1190,1193],{"class":608,"line":985},[606,1175,1176],{"class":612},"    injectingTime  ",[606,1178,945],{"class":624},[606,1180,1181],{"class":628}," 5",[606,1183,1184],{"class":624}," *",[606,1186,1187],{"class":628}," 60",[606,1189,1184],{"class":624},[606,1191,1192],{"class":628}," 1000",[606,1194,969],{"class":612},[606,1196,1197,1200,1202,1204],{"class":608,"line":998},[606,1198,1199],{"class":612},"    tickIntervalMs ",[606,1201,945],{"class":624},[606,1203,1192],{"class":628},[606,1205,969],{"class":612},[606,1207,1208,1211,1213,1215],{"class":608,"line":1008},[606,1209,1210],{"class":612},"    removeItem     ",[606,1212,945],{"class":624},[606,1214,993],{"class":624},[606,1216,969],{"class":612},[606,1218,1219,1222,1224,1227],{"class":608,"line":1025},[606,1220,1221],{"class":612},"    volume         ",[606,1223,945],{"class":624},[606,1225,1226],{"class":628}," 20",[606,1228,969],{"class":612},[606,1230,1231,1234,1236,1239,1241,1243,1245,1247],{"class":608,"line":1041},[606,1232,1233],{"class":612},"    anim           ",[606,1235,945],{"class":624},[606,1237,1238],{"class":612}," { dict ",[606,1240,945],{"class":624},[606,1242,959],{"class":624},[606,1244,1018],{"class":962},[606,1246,966],{"class":624},[606,1248,969],{"class":612},[606,1250,1251,1254,1256,1258,1260,1263],{"class":608,"line":1047},[606,1252,1253],{"class":612},"                       name ",[606,1255,945],{"class":624},[606,1257,959],{"class":624},[606,1259,1035],{"class":962},[606,1261,1262],{"class":624},"\" ",[606,1264,1119],{"class":612},[606,1266,1267,1270,1272,1274,1277,1279],{"class":608,"line":1064},[606,1268,1269],{"class":612},"    lang           ",[606,1271,945],{"class":624},[606,1273,959],{"class":624},[606,1275,1276],{"class":962},"Verabreiche Fentanyl...",[606,1278,966],{"class":624},[606,1280,969],{"class":612},[606,1282,1283,1286,1288,1290,1293,1295],{"class":608,"line":1081},[606,1284,1285],{"class":612},"    langUsed       ",[606,1287,945],{"class":624},[606,1289,959],{"class":624},[606,1291,1292],{"class":962},"Fentanyl verabreicht",[606,1294,966],{"class":624},[606,1296,969],{"class":612},[606,1298,1299,1302,1304,1306,1309],{"class":608,"line":1097},[606,1300,1301],{"class":612},"    pain           ",[606,1303,945],{"class":624},[606,1305,1089],{"class":624},[606,1307,1308],{"class":628},"8",[606,1310,969],{"class":612},[606,1312,1313,1316,1318,1321],{"class":608,"line":1116},[606,1314,1315],{"class":612},"    duration       ",[606,1317,945],{"class":624},[606,1319,1320],{"class":628}," 300",[606,1322,969],{"class":612},[606,1324,1326,1329,1331,1333,1335,1337],{"class":608,"line":1325},14,[606,1327,1328],{"class":612},"    access         ",[606,1330,945],{"class":624},[606,1332,1105],{"class":612},[606,1334,945],{"class":624},[606,1336,993],{"class":624},[606,1338,1339],{"class":612}," },\n",[606,1341,1343],{"class":608,"line":1342},15,[606,1344,1346],{"emptyLinePlaceholder":1345},true,"\n",[606,1348,1350],{"class":608,"line":1349},16,[606,1351,1352],{"class":632},"    -- Visual: ragdoll + fade. Runs on the patient's machine.\n",[606,1354,1356,1360,1363,1367,1370,1373,1376,1379,1382,1384,1387,1390,1393],{"class":608,"line":1355},17,[606,1357,1359],{"class":1358},"s2Zo4","    onUseClient",[606,1361,1362],{"class":624},"    =",[606,1364,1366],{"class":1365},"s7zQu"," function",[606,1368,1369],{"class":624},"(",[606,1371,648],{"class":1372},"sHdIc",[606,1374,1375],{"class":624},")",[606,1377,1378],{"class":612}," self:",[606,1380,1381],{"class":1358},"fadeOut",[606,1383,1369],{"class":612},[606,1385,1386],{"class":628},"15000",[606,1388,1389],{"class":612},") ",[606,1391,1392],{"class":1365},"end",[606,1394,969],{"class":612},[606,1396,1398,1401,1404,1406,1408,1410,1412,1414,1417,1419,1422,1424,1426],{"class":608,"line":1397},18,[606,1399,1400],{"class":1358},"    onTickClient",[606,1402,1403],{"class":624},"   =",[606,1405,1366],{"class":1365},[606,1407,1369],{"class":624},[606,1409,648],{"class":1372},[606,1411,1375],{"class":624},[606,1413,1378],{"class":612},[606,1415,1416],{"class":1358},"ragdoll",[606,1418,1369],{"class":612},[606,1420,1421],{"class":628},"5000",[606,1423,1389],{"class":612},[606,1425,1392],{"class":1365},[606,1427,969],{"class":612},[606,1429,1431,1434,1436,1438,1440,1442,1444,1446,1449,1451,1453,1455,1457],{"class":608,"line":1430},19,[606,1432,1433],{"class":1358},"    onFinishClient",[606,1435,625],{"class":624},[606,1437,1366],{"class":1365},[606,1439,1369],{"class":624},[606,1441,648],{"class":1372},[606,1443,1375],{"class":624},[606,1445,1378],{"class":612},[606,1447,1448],{"class":1358},"fadeIn",[606,1450,1369],{"class":612},[606,1452,1386],{"class":628},[606,1454,1389],{"class":612},[606,1456,1392],{"class":1365},[606,1458,969],{"class":612},[606,1460,1462],{"class":608,"line":1461},20,[606,1463,1346],{"emptyLinePlaceholder":1345},[606,1465,1467],{"class":608,"line":1466},21,[606,1468,1469],{"class":632},"    -- Authoritative: blood + pain mutations. Runs on the server.\n",[606,1471,1473,1476,1478,1480,1482,1484],{"class":608,"line":1472},22,[606,1474,1475],{"class":1358},"    onTickServer",[606,1477,1403],{"class":624},[606,1479,1366],{"class":1365},[606,1481,1369],{"class":624},[606,1483,648],{"class":1372},[606,1485,1486],{"class":624},")\n",[606,1488,1490,1493,1496,1499,1501,1504,1506,1509,1512,1514],{"class":608,"line":1489},23,[606,1491,1492],{"class":1365},"        if",[606,1494,1495],{"class":612}," self.",[606,1497,1498],{"class":616},"patient",[606,1500,222],{"class":612},[606,1502,1503],{"class":616},"conditions",[606,1505,222],{"class":612},[606,1507,1508],{"class":616},"bloodVolume",[606,1510,1511],{"class":624}," \u003C",[606,1513,1187],{"class":628},[606,1515,1516],{"class":1365}," then\n",[606,1518,1520,1523,1526,1528,1531],{"class":608,"line":1519},24,[606,1521,1522],{"class":612},"            self:",[606,1524,1525],{"class":1358},"addBlood",[606,1527,1369],{"class":612},[606,1529,1530],{"class":628},"0.1",[606,1532,1486],{"class":612},[606,1534,1536],{"class":608,"line":1535},25,[606,1537,1538],{"class":1365},"        end\n",[606,1540,1542,1545,1548,1550,1552,1554,1556,1558,1560,1562,1565],{"class":608,"line":1541},26,[606,1543,1544],{"class":624},"        local",[606,1546,1547],{"class":612}," pain ",[606,1549,945],{"class":624},[606,1551,1495],{"class":612},[606,1553,1498],{"class":616},[606,1555,222],{"class":612},[606,1557,1503],{"class":616},[606,1559,222],{"class":612},[606,1561,54],{"class":616},[606,1563,1564],{"class":624}," or",[606,1566,1567],{"class":628}," 0\n",[606,1569,1571,1573,1575,1578,1581],{"class":608,"line":1570},27,[606,1572,1492],{"class":1365},[606,1574,1547],{"class":612},[606,1576,1577],{"class":624},">",[606,1579,1580],{"class":628}," 0",[606,1582,1516],{"class":1365},[606,1584,1586,1588,1591,1594,1596,1598],{"class":608,"line":1585},28,[606,1587,1522],{"class":612},[606,1589,1590],{"class":1358},"reducePain",[606,1592,1593],{"class":612},"(pain ",[606,1595,41],{"class":624},[606,1597,1181],{"class":628},[606,1599,1486],{"class":612},[606,1601,1603],{"class":608,"line":1602},29,[606,1604,1538],{"class":1365},[606,1606,1608],{"class":608,"line":1607},30,[606,1609,1610],{"class":1365},"    end\n",[606,1612,1614],{"class":608,"line":1613},31,[606,1615,1119],{"class":612},[15,1617,1618,1619,1622],{},"Medic uses ",[18,1620,1621],{},"fentanyl"," near a downed patient -> closest player is auto-targeted -> 3 s setup -> tick loop fires every second for 5 minutes, ragdolling the patient and topping up blood until conscious.",[665,1624,1626,1627,1375],{"id":1625},"pure-callback-type-custom","Pure callback (",[18,1628,1629],{},"type = \"custom\"",[596,1631,1633],{"className":598,"code":1632,"filename":600,"language":601,"meta":602,"style":602},"defibrillator = {\n    type        = \"custom\",\n    time        = 8000,\n    removeItem  = false,\n    anim        = { dict = \"anim@heists@narcotics@funding@gang_idle\",\n                    name = \"gang_chatting_idle01\" },\n    lang        = \"Benutze Defibrillator...\",\n    langUsed    = \"Defibrillator benutzt\",\n    access      = { lockAccess = true },\n\n    onUseClient = function(self)\n        self:playSoundAt(\"https://example.com/defib.mp3\", 1.0)\n    end,\n    onUseServer = function(self)\n        Wait(6000)\n        self:revive(self.target)\n    end\n}\n",[18,1634,1635,1644,1659,1670,1680,1698,1713,1728,1743,1757,1761,1775,1799,1806,1821,1833,1847,1851],{"__ignoreMap":602},[606,1636,1637,1640,1642],{"class":608,"line":609},[606,1638,1639],{"class":612},"defibrillator ",[606,1641,945],{"class":624},[606,1643,948],{"class":612},[606,1645,1646,1648,1650,1652,1655,1657],{"class":608,"line":951},[606,1647,954],{"class":612},[606,1649,945],{"class":624},[606,1651,959],{"class":624},[606,1653,1654],{"class":962},"custom",[606,1656,966],{"class":624},[606,1658,969],{"class":612},[606,1660,1661,1663,1665,1668],{"class":608,"line":972},[606,1662,975],{"class":612},[606,1664,945],{"class":624},[606,1666,1667],{"class":628}," 8000",[606,1669,969],{"class":612},[606,1671,1672,1674,1676,1678],{"class":608,"line":985},[606,1673,988],{"class":612},[606,1675,945],{"class":624},[606,1677,1110],{"class":624},[606,1679,969],{"class":612},[606,1681,1682,1684,1686,1688,1690,1692,1694,1696],{"class":608,"line":998},[606,1683,1001],{"class":612},[606,1685,945],{"class":624},[606,1687,1238],{"class":612},[606,1689,945],{"class":624},[606,1691,959],{"class":624},[606,1693,1018],{"class":962},[606,1695,966],{"class":624},[606,1697,969],{"class":612},[606,1699,1700,1703,1705,1707,1709,1711],{"class":608,"line":1008},[606,1701,1702],{"class":612},"                    name ",[606,1704,945],{"class":624},[606,1706,959],{"class":624},[606,1708,1035],{"class":962},[606,1710,1262],{"class":624},[606,1712,1119],{"class":612},[606,1714,1715,1717,1719,1721,1724,1726],{"class":608,"line":1025},[606,1716,1050],{"class":612},[606,1718,945],{"class":624},[606,1720,959],{"class":624},[606,1722,1723],{"class":962},"Benutze Defibrillator...",[606,1725,966],{"class":624},[606,1727,969],{"class":612},[606,1729,1730,1732,1734,1736,1739,1741],{"class":608,"line":1041},[606,1731,1067],{"class":612},[606,1733,945],{"class":624},[606,1735,959],{"class":624},[606,1737,1738],{"class":962},"Defibrillator benutzt",[606,1740,966],{"class":624},[606,1742,969],{"class":612},[606,1744,1745,1747,1749,1751,1753,1755],{"class":608,"line":1047},[606,1746,1100],{"class":612},[606,1748,945],{"class":624},[606,1750,1105],{"class":612},[606,1752,945],{"class":624},[606,1754,993],{"class":624},[606,1756,1339],{"class":612},[606,1758,1759],{"class":608,"line":1064},[606,1760,1346],{"emptyLinePlaceholder":1345},[606,1762,1763,1765,1767,1769,1771,1773],{"class":608,"line":1081},[606,1764,1359],{"class":1358},[606,1766,625],{"class":624},[606,1768,1366],{"class":1365},[606,1770,1369],{"class":624},[606,1772,648],{"class":1372},[606,1774,1486],{"class":624},[606,1776,1777,1780,1783,1785,1787,1790,1792,1794,1797],{"class":608,"line":1097},[606,1778,1779],{"class":612},"        self:",[606,1781,1782],{"class":1358},"playSoundAt",[606,1784,1369],{"class":612},[606,1786,966],{"class":624},[606,1788,1789],{"class":962},"https://example.com/defib.mp3",[606,1791,966],{"class":624},[606,1793,55],{"class":612},[606,1795,1796],{"class":628},"1.0",[606,1798,1486],{"class":612},[606,1800,1801,1804],{"class":608,"line":1116},[606,1802,1803],{"class":1365},"    end",[606,1805,969],{"class":612},[606,1807,1808,1811,1813,1815,1817,1819],{"class":608,"line":1325},[606,1809,1810],{"class":1358},"    onUseServer",[606,1812,625],{"class":624},[606,1814,1366],{"class":1365},[606,1816,1369],{"class":624},[606,1818,648],{"class":1372},[606,1820,1486],{"class":624},[606,1822,1823,1826,1828,1831],{"class":608,"line":1342},[606,1824,1825],{"class":1358},"        Wait",[606,1827,1369],{"class":612},[606,1829,1830],{"class":628},"6000",[606,1832,1486],{"class":612},[606,1834,1835,1837,1840,1843,1845],{"class":608,"line":1349},[606,1836,1779],{"class":612},[606,1838,1839],{"class":1358},"revive",[606,1841,1842],{"class":612},"(self.",[606,1844,858],{"class":616},[606,1846,1486],{"class":612},[606,1848,1849],{"class":608,"line":1355},[606,1850,1610],{"class":1365},[606,1852,1853],{"class":608,"line":1397},[606,1854,1855],{"class":612},"}\n",[15,1857,1858,1859,1862],{},"Medic uses the defibrillator -> sound plays at the user's coords -> after a 6 second charge, the targeted player is revived -> item is ",[657,1860,1861],{},"not"," removed.",[85,1864],{},[10,1866,1868,1871],{"id":1867},"lockaccess-semantics",[18,1869,1870],{},"lockAccess"," semantics",[15,1873,1874,1877,1878,1881],{},[18,1875,1876],{},"access.lockAccess = true"," means the use is gated server-side as ",[657,1879,1880],{},"medic job + on duty",":",[1883,1884,1885,1899,1905],"ol",{},[574,1886,1887,1888,1891,1892,1895,1896,222],{},"The source's job (via ",[18,1889,1890],{},"Sky_Jobs.PlayerCache.GetJob",") must appear in ",[18,1893,1894],{},"Config.Jobs"," with ",[18,1897,1898],{},"countsAsMedic = true",[574,1900,1901,1904],{},[18,1902,1903],{},"Sky_Jobs.PlayerCache.GetDuty"," must return truthy.",[574,1906,1907,1908,1910],{},"A target player must exist within ",[18,1909,500],{}," of the medic. If none, the use is refused with a notification.",[15,1912,1913,1914,1917,1918,1921],{},"For self-use items (",[18,1915,1916],{},"access.lockAccess = false",", the default), ",[18,1919,1920],{},"self.target = self.source"," and the range check is skipped.",[85,1923],{},[10,1925,1927],{"id":1926},"cancellation-stacking-collisions","Cancellation, stacking, collisions",[96,1929,1930,1940],{},[99,1931,1932],{},[102,1933,1934,1937],{},[105,1935,1936],{},"Situation",[105,1938,1939],{},"Outcome",[112,1941,1942,1957,1965,1976,1991,1999,2007],{},[102,1943,1944,1947],{},[117,1945,1946],{},"User enters a vehicle",[117,1948,1949,1950,1953,1954,1956],{},"Auto-cancel. ",[18,1951,1952],{},"onCancel*"," fires. No declarative effects. Item is ",[657,1955,1861],{}," consumed.",[102,1958,1959,1962],{},[117,1960,1961],{},"User dies",[117,1963,1964],{},"Auto-cancel. Same as above.",[102,1966,1967,1970],{},[117,1968,1969],{},"Source disconnects",[117,1971,1972,1973,222],{},"Server clears the run on ",[18,1974,1975],{},"playerDropped",[102,1977,1978,1985],{},[117,1979,1980,1981,1984],{},"Cross-player infusion: medic walks > ",[18,1982,1983],{},"_maxTargetDistance + 0.5"," from the target",[117,1986,1987,1988,222],{},"Server cancels with ",[18,1989,1990],{},"reason = \"out_of_range\"",[102,1992,1993,1996],{},[117,1994,1995],{},"User tries to start a second custom medication while one is active",[117,1997,1998],{},"Refused.",[102,2000,2001,2004],{},[117,2002,2003],{},"User has a self-bandage in progress",[117,2005,2006],{},"Custom medication start is refused.",[102,2008,2009,2020],{},[117,2010,2011,2014,2015,2017,2018],{},[18,2012,2013],{},"itemName"," collides with ",[18,2016,24],{}," or ",[18,2019,28],{},[117,2021,2022,2023,2025],{},"Console prints a collision warning at start. The custom medication is ",[657,2024,1861],{}," registered. The original medication still works.",[15,2027,2028,2029,2032],{},"Callback runtime errors are caught by ",[18,2030,2031],{},"pcall"," on both sides — a typo in your config will log the offending item and side, and clean-cancel the run rather than crashing the player thread.",[85,2034],{},[10,2036,2038],{"id":2037},"common-pitfalls","Common pitfalls",[571,2040,2041,2054,2069,2080,2093],{},[574,2042,2043,2050,2051,2053],{},[657,2044,2045,2046,33,2048,222],{},"Don't mutate vitals from ",[18,2047,32],{},[18,2049,153],{}," The client ",[18,2052,648],{}," deliberately has no mutators. Put state changes in the server-side callback.",[574,2055,2056,2068],{},[657,2057,2058,2059,2062,2063,2065,2066],{},"Don't call ",[18,2060,2061],{},"Wait(...)"," longer than ",[18,2064,127],{}," in ",[18,2067,32],{}," for non-infusion types — the run finishes when the server timer expires regardless of the client callback's progress.",[574,2070,2071,2076,2077,2079],{},[657,2072,2073],{},[18,2074,2075],{},"requiresOpenWound = true"," validates against the ",[657,2078,858],{},", not the source. For self-use items this is the user; for medic-only items it's the auto-resolved nearby player.",[574,2081,2082,2088,2089,2092],{},[657,2083,2084,2085,1375],{},"Reusable items (",[18,2086,2087],{},"removeItem = false"," still go through the cooldown of ",[18,2090,2091],{},"activeRuns[src]"," — a player can't trigger the same item twice in parallel.",[574,2094,2095,2100,2101,222],{},[657,2096,2097,2099],{},[18,2098,496],{}," is fixed at start."," If you want a callback to retarget mid-run, pass an explicit target into the mutator: ",[18,2102,2103],{},"self:heal(20, self:nearbyPlayer())",[2105,2106,2107],"style",{},"html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}",{"title":602,"searchDepth":609,"depth":951,"links":2109},[2110,2111,2113,2114,2121,2127,2129,2130],{"id":12,"depth":951,"text":13},{"id":89,"depth":951,"text":2112},"The three type values",{"id":180,"depth":951,"text":181},{"id":644,"depth":951,"text":2115,"children":2116},"The self helper",[2117,2119],{"id":667,"depth":972,"text":2118},"Client self",{"id":817,"depth":972,"text":2120},"Server self",{"id":927,"depth":951,"text":928,"children":2122},[2123,2124,2125],{"id":931,"depth":972,"text":932},{"id":1129,"depth":972,"text":1130},{"id":1625,"depth":972,"text":2126},"Pure callback (type = \"custom\")",{"id":1867,"depth":951,"text":2128},"lockAccess semantics",{"id":1926,"depth":951,"text":1927},{"id":2037,"depth":951,"text":2038},"Declare inventory items that mix declarative effects (pain, blood, heal) with optional per-tick callbacks running on the client and server.","md",null,{},"/docs/jobs/ambulancejob/custom-medications",{"title":5,"description":2131},{"loc":2135},"1.docs/0.jobs/0.ambulancejob/3.custom-medications","Y63L4CoFdrC8L7w7kri-j3YHcUWEzZIpzCcFrOFyjbw",[2141,2146],{"title":2142,"path":2143,"stem":2144,"description":2145,"children":-1},"Permissions","/docs/jobs/ambulancejob/permissions","1.docs/0.jobs/0.ambulancejob/2.permissions","Grant admin access so commands like /setboss and /revive work in your framework.",{"title":2147,"path":2148,"stem":2149,"description":2150,"children":-1},"Vitals & Treatment","/docs/jobs/ambulancejob/vitals","1.docs/0.jobs/0.ambulancejob/4.vitals","Understand how Sky Ambulancejob tracks death causes, assigns injuries, and guides medics through the correct treatment flow.",1778233299548]