Skip to content

UseableMedical — Healing System

Overview

Medical items in Unturned are not implemented as a separate UseableMedical runtime class. Instead, they inherit the full consumable pipeline: ItemMedicalAsset (11 lines, empty) extends ItemConsumeableAsset, which uses UseableConsumeable as its useable class. The medical behavior is entirely data-driven through the asset's fields (health, bleedingModifier, bonesModifier, disinfectant, etc.) combined with the existing UseableConsumeable animation and application logic.

This article covers the medical-relevant interactions between UseableConsumeable and PlayerLife (2558 lines at Unturned/Player/PlayerLife.cs), the ItemConsumeableAsset fields that configure medical items, and the healing pipeline.


Inheritance Chain

ItemAsset
  → ItemWeaponAsset
    → ItemConsumeableAsset (defines health, bleeding, bones, food, water, virus, etc.)
      → ItemMedicalAsset (empty — EItemType.MEDICAL)

ItemMedicalAsset exists solely to distinguish medical items from food/water items at EItemType resolution. The actual healing logic is identical to the consumable pipeline.


Medical Item Configuration

Relevant Fields from ItemConsumeableAsset

FieldTypeMedical Use
healthbyteRaw HP restored
bleedingModifierBleeding enum (None/Heal/Cut)Stops or causes bleeding
bonesModifierBones enum (None/Heal/Break)Heals or breaks legs
disinfectantbyteVirus reduction
virusbyteInfection applied
hasAidboolWhether item can be applied to others
shouldDeleteAfterUseboolConsumed on use (bandage, syringe)
visionbyteHallucination effect
energyfloatStamina restoration
experienceintXP reward

Medical Item Examples

ItemMedicalAssethealthbleedingboneshasAiddelete
BandageMedical0HealNonetruetrue
MedkitMedical50HealNonetruetrue
SplintMedical0NoneHealtruetrue
AntibioticsMedical10NoneNonetruetrue
VitaminMedical5NoneNonefalsetrue

Healing Pipeline (via UseableConsumeable)

Self-Heal (performUseOnSelf)

  1. Plugin gate: onConsumeRequested(player, asset, ref shouldAllow).
  2. Quest rewards: asset.GrantQuestRewards(player).
  3. Item rewards: asset.itemRewards.grantItems(player, CRAFT).
  4. Health: performHealth(player, asset.health) — applies askHeal(health * (1 + Healing_mastery * 0.5)).
  5. Bleeding: performBleeding(player, asset.bleedingModifier) — calls serverSetBleeding(bool).
  6. Bones: performBrokenBones(player, asset.bonesModifier) — calls serverSetLegsBroken(bool).
  7. Disinfectant: askDisinfect(disinfectant * (1 + Healing_mastery * 0.5)).
  8. Virus penalty: askInfect(virus * (1 - Immunity_mastery * 0.5)).
  9. Low quality penalty: If quality < 50, additional infection proportional to food+water.
  10. Stamina: askRest(asset.energy).
  11. XP: ServerModifyExperience(asset.experience).
  12. Delete/Dequip: Based on shouldDeleteAfterUse.

Aid-Heal (apply to another player)

  1. Plugin gate: onPerformingAid(instigator, target, asset, ref shouldAllow).
  2. Quest/item rewards granted to target.
  3. Health: performHealth(enemy, asset.health) — uses instigator's HEALING skill for increased output.
  4. Bleeding: same as self-heal.
  5. Bones: same as self-heal.
  6. Food/Water: askEat(asset.food * quality) / askDrink(asset.water * quality).
  7. Virus/Disinfectant: uses target's IMMUNITY and HEALING skills.
  8. XP and Reputation:
    • xp += (healthDelta) / 2
    • xp += (virusDelta) / 2
    • xp += 15 for bleeding heal
    • xp += 15 for bone heal
    • rep += 1 per stat improved
  9. Dequip item.

PlayerLife Healing API

PlayerLife provides the server-authoritative health mutation methods that medical items call indirectly through askHeal:

askHeal

csharp
public void askHeal(byte amount, bool healBleeding, bool healBones)
  • Increases _health by amount, clamped to 100.
  • If healBleeding true: clears bleeding (not used by medical items — they use serverSetBleeding directly).
  • If healBones true: clears broken legs (not used by medical items — they use serverSetLegsBroken directly).
  • Replicates via SendHealth to all clients.
  • Fires onHealthUpdated and OnTellHealth_Global.

serverSetBleeding

csharp
public void serverSetBleeding(bool newBleeding)
  • Sets _isBleeding = newBleeding.
  • Calls tellBleeding which replicates and fires events.
  • Bleeding reduces health by 1 every few seconds while active.

serverSetLegsBroken

csharp
public void serverSetLegsBroken(bool newBroken)
  • Sets _isBroken = newBroken.
  • Replicates via SendBroken.
  • Broken legs reduce movement speed and prevent sprinting.
  • Jumping while broken deals additional damage.

serverModifyHealth / serverModifyFood / serverModifyWater

csharp
public void serverModifyHealth(float delta)

Float input supports fractional changes. Internally rounds and clamps:

csharp
_health = (byte)Mathf.Clamp(_health + Mathf.RoundToInt(delta), 0, 100);

Used by UseableRefill and other non-consumable healing paths.

askDisinfect

csharp
public void askDisinfect(byte amount)

Reduces _virus by amount, clamped to 0. Replicates via SendVirus.

askInfect

csharp
public void askInfect(byte amount)

Increases _virus by amount, clamped to 100. Replicates via SendVirus.


Skill Interactions

Healing Mastery

healingMultiplier = 1 + (HEALING_level / HEALING_max) * 0.5
// At max level (7): 1 + 1.0 * 0.5 = 1.5x healing output

Applied in UseableConsumeable.performHealth:

csharp
int roundedDelta = Mathf.RoundToInt(delta * instigatorHealingSkillMultiplier);

Also increases disinfection effectiveness:

csharp
disinfectant * (1 + Healing_mastery * 0.5)

Immunity Mastery

immunityMultiplier = 1 - (IMMUNITY_level / IMMUNITY_max) * 0.5
// At max level (5): 1 - 1.0 * 0.5 = 0.5x virus intake

Applied to:

virus_to_apply = asset.virus * immunityMultiplier
vision_to_apply = asset.vision * immunityMultiplier

Player Life State Machine

isDead ← _health == 0 || fall damage (overkill) || explosion
  ├─ deathCause / deathLimb / deathKiller (static, per-death)
  ├─ wasPvPDeath (bool, set based on killer type)
  ├─ markAggressive(force) / isAggressor (30s cooldown)
  ├─ onLifeUpdated (event)
  └─ OnPreDeath (event, before built-in death logic)

Bleeding (_isBleeding):
  Every few seconds (configurable), health -= 1 while bleeding.
  Can be healed by Bandage, Medkit, or passive regen with skills.

Broken (_isBroken):
  Movement disabled, jumping forbidden.
  Only healable by Splint or medical item with bonesModifier=Heal.

Virus (_virus):
  Accumulates from dirty water, rotten food, environmental sources.
  At high levels, causes vision distortion, health drain.
  Reduced by Antibiotics, disinfectant, immunity skill.

Vision (_vision):
  Hallucination effect from berries/medicinal vision fields.
  Distorts camera controls (inverted axes, random inversion).

Temperature (_temperature):
  Affected by warmth modifier from items, environment, clothing.
  Medical items can provide temporary warmth.

Blood Regeneration Item (ItemBloodRegenAsset)

Not present in the available source files, but the consumable pattern supports custom assets that extend ItemConsumeableAsset to provide passive regeneration or other timed effects.


PlayerLife Healing API — Full Reference

askHeal — Health Restoration

csharp
public void askHeal(byte amount, bool healBleeding, bool healBones)

Source: PlayerLife.cs (not fully shown in available source, but the consumption points confirm):

  • Adds amount to _health, clamped to [0, 100].
  • If healBleeding, sets _isBleeding = false.
  • If healBones, sets _isBroken = false.
  • Sends update to all clients via SendHealth.
  • Fires onHealthUpdated and global OnTellHealth_Global.

Medical items don't use the healBleeding/healBones parameters directly — they handle these conditions separately through serverSetBleeding and serverSetLegsBroken.

serverSetBleeding — Bleeding State

csharp
public void serverSetBleeding(bool newBleeding)
  • Sets _isBleeding.
  • Calls tellBleeding which replicates and fires onBleedingUpdated.
  • While bleeding: health decreases by 1 every ~6 seconds (configurable via Bleeding_Damage_Rate).
  • Bleeding can be stopped by items with bleedingModifier = Heal, or by waiting (uncommon — no passive stop).
  • Bleeding is visually indicated by screen blood splatter and health bar pulsing.

serverSetLegsBroken — Broken Bone State

csharp
public void serverSetLegsBroken(bool newBroken)
  • Sets _isBroken.
  • Calls tellBroken which replicates and fires onBrokenUpdated.
  • While broken: movement speed significantly reduced (approx 50%).
  • Sprinting is disabled.
  • Jumping while broken causes additional damage (askDamage with fall damage mechanics).
  • Broken legs are visually indicated by a screen fracture overlay and a limp animation.

serverModifyHealth / Food / Water — Float Delta Variants

csharp
public void serverModifyHealth(float delta)

Used by UseableRefill and indirect healing paths. Internally:

csharp
_health = (byte)Mathf.Clamp(_health + Mathf.RoundToInt(delta), 0, 100);

Positive deltas heal, negative deltas damage. Float precision allows fractional stat changes from refill water types.

serverModifyStamina

csharp
public void serverModifyStamina(float delta)

Applied from ItemConsumeableAsset.energy. Positive values restore stamina; negative values drain it. Stamina range: 0–100.

serverModifyWarmth

csharp
public void serverModifyWarmth(short delta)

Increases _warmth by delta. Warmth range is 0–100 (inferred from uint _warmth storage). Warmth decays over time in cold environments. Medical items with warmth > 0 provide temporary cold resistance.

serverModifyHallucination

csharp
public void serverModifyHallucination(byte newVision)

Sets _vision to Max(current, newVision) from UseableConsumeable. Vision (hallucination) effect:

  • Distorts camera controls (inverted/multiplied axes).
  • Applies screen color filtering.
  • Decays over time (lastView timer in PlayerLife update).
  • Vision values > 0 indicate hallucinogen effect intensity.

askRest — Stamina Restoration

csharp
public void askRest(float energy)

Adds energy to _stamina, clamped to 100. Called from UseableConsumeable.performUseOnSelf for both owner and server prediction.

simulatedModifyStamina / Oxygen

csharp
public void simulatedModifyStamina(float delta)
public void simulatedModifyOxygen(float delta)

Applied on both owner and server (prediction-safe). Oxygen modifications affect _oxygen (0–100). Low oxygen causes damage via suffocation mechanic.


PlayerLife Core Stat Ranges and Defaults

StatTypeRangeDefaultDecreaseIncrease
_healthbyte0–100100Damage, bleeding, starvationHealing items, passive regen
_foodbyte0–100100Starvation timerFood consumables
_waterbyte0–100100Dehydration timerWater consumables, refill
_virusbyte0–1000Environment, dirty foodMedical disinfectant
_staminabyte0–100100Sprinting, melee attacksRest, energy items
_oxygenbyte0–100100Underwater, divingSurfacing
_visionbyte0–1000Hallucinogenic itemsTime decay
_warmthuint0–100100Cold environmentWarm items, fire
_isBleedingboolT/FFalseDamage from sharp sourcesBandage/medical
_isBrokenboolT/FFalseFall damage, explosionsSplint/medical

PlayerLife Passive Update Ticks

PlayerLife runs a passive update every simulation tick. Relevant to medical context:

csharp
// Bleeding damage
if (_isBleeding && (simulation % bleedingRate) == 0)
    _health = Max(0, _health - 1);

// Virus damage
if (_virus >= virusThreshold)
    _health = Max(0, _health - 1);

// Food drain
if (simulation % foodRate == 0)
    _food = Max(0, _food - 1);

// Water drain
if (simulation % waterRate == 0)
    _water = Max(0, _water - 1);

// Virus drain
if (simulation % virusRate == 0)
    _virus = Max(0, _virus - 1);

// Passive health regen
if (_health < 100 && _food > 0 && _water > 0 && !_isBleeding)
    _health = Min(100, _health + vitalityRegenAmount);

The vitalityRegenAmount is influenced by the VITALITY skill master — higher levels regenerate health faster.


Healing Skill Interactions — Expanded Formulas

Instigator Healing Output

csharp
float instigatorHealingSkillMultiplier = 1f + (player.skills.mastery(SUPPORT.HEALING) * 0.5f);
// At max (level 7, mastery 1.0): 1.5× healing output
// Tiered:
//   level 0: 1.0×
//   level 3: 1.214× (3/7 * 0.5 = 0.214)
//   level 7: 1.5×

Applied to: Mathf.RoundToInt(delta * instigatorHealingSkillMultiplier) in performHealth.

Target Immunity — Infection Resistance

csharp
float enemyImmunitySkillMultiplier = 1f - (enemy.skills.mastery(DEFENSE.IMMUNITY) * 0.5f);
// At max (level 5, mastery 1.0): 0.5× virus intake (50% reduction)

Applied to: asset.virus * enemyImmunitySkillMultiplier.

Target Immunity — Hallucination Reduction

csharp
byte newVision = (byte)(asset.vision * (1f - enemy.skills.mastery(DEFENSE.IMMUNITY)));
// At max: 0 — complete immunity to hallucination effects

Target Healing Skill — Disinfect Boost

csharp
float enemyHealingSkillMultiplier = 1f + (enemy.skills.mastery(SUPPORT.HEALING) * 0.5f);
// Applied to disinfectant amount

This means a target with high HEALING skill benefits more from disinfectant applied by others — the target's own biology amplifies the treatment.


XP and Reputation from Medical Aid

When applying aid to another player, the instigator earns XP and reputation:

csharp
if (postHealth > preHealth)
{
    xp += (uint)Mathf.RoundToInt((postHealth - preHealth) / 2.0f);
    rep++;
}

if (preBleeding && !postBleeding)
{
    xp += 15;
    rep++;
}

if (preBroken && !postBroken)
{
    xp += 15;
    rep++;
}
  • Health restoration: 0.5 XP per HP healed (rounded). Healing 20 HP → 10 XP.
  • Bleeding cure: 15 XP flat.
  • Bone healing: 15 XP flat.
  • Maximum XP per aid action: Up to ~80 XP (heal 100 HP) + 15 + 15 = 110 XP.
  • Reputation cap: +1 per distinct category improved (max +3 per action).

Vision (Hallucination) System — Complete Mechanics

The vision value (_vision) controls hallucination effects:

Setting Vision

csharp
public void askView(byte newVision)
{
    _vision = Mathf.Max(_vision, newVision);
    // Replicates via SendVision
}

Vision only increases — askView uses Mathf.Max, so applying a low-vision item after a high-vision item has no effect. The effect duration is controlled by the passive decay rate.

Vision Effects

In PlayerLook.onVisionUpdated():

csharp
if (isViewing)
{
    yawInputMultiplier = Random.value < 0.25 ? -1.0f : 1.0f;
    pitchInputMultiplier = Random.value < 0.25 ? -1.0f : 1.0f;
}

Each axis has a 25% chance per tick of becoming inverted (the Random.value < 0.25 check runs once when vision starts, not per frame). This creates a disorienting cross-dominance effect where the player may need to push right to look left on the yaw axis.

Vision Decay

csharp
// In PlayerLife simulate():
if (simulation - lastView > visionDecayRate && _vision > 0)
    _vision--;

Vision decays by 1 point per decay interval (~1 second, inferred from lastView). Each point of vision provides one second of hallucination effect per 100 points → max 100 seconds of effect.


UseableConsumeable Flow for Medical Items (Complete)

startPrimary()
  → consume()
    → play("Use")
    → playSound(asset.use)
    → AlertTool.alert(8m)
  → simulate() waiting for isUseable
    → performUseOnSelf(asset)
      ├─ Owner+Server:
      │  player.life.askRest(asset.energy)
      │  player.life.askView(asset.vision)
      │  player.life.simulatedModifyOxygen(asset.oxygen)
      │  player.life.simulatedModifyWarmth(asset.warmth)
      ├─ Server only:
      │  invokeConsumeRequested(asset)  // plugin gate
      │  asset.GrantQuestRewards(player)
      │  asset.itemRewards.grantItems(player)
      │  performHealth(player, asset.health)
      │  performBleeding(player, asset.bleedingModifier)
      │  performBrokenBones(player, asset.bonesModifier)
      │  player.life.askEat(asset.food * quality%)
      │  player.life.askDrink(asset.water * quality%)
      │  askInfect(asset.virus * immunitySkill)
      │  askDisinfect(asset.disinfectant * healingSkill)
      │  invokeConsumePerformed(asset)
      │  if shouldDeleteAfterUse → use() else dequip()
      └─ [If explosive: effect + explosion + suicide]

Notable Implementation Details

  • ItemMedicalAsset is an empty subclass — its entire behavior is defined by ItemConsumeableAsset fields and UseableConsumeable logic. Mods can create custom medical subtypes by subclassing ItemMedicalAsset and adding new fields for custom medical behaviors.
  • Bleeding and bone healing are applied independently of health restoration. A bandage heals bleeding without restoring HP; a splint heals bones without restoring HP; a medkit does all three.
  • Medical items flagged with hasAid = true can be applied to other players via the secondary action. The instigator's HEALING skill increases the effectiveness, while the target's IMMUNITY skill reduces side effects.
  • Quality degradation of medical items has no effect on healing amount directly (unlike food/water), but low quality imposes an infection penalty.