Combat Systems | Updated 2025

How to Make Weapons & Combat Systems in LSL

Build complete combat systems from scratch! Learn to create guns, swords, health tracking, damage calculation, team systems, and respawn mechanics for RPG and combat roleplay.

6 Complete Systems
Combat Ready
2 Hour Tutorial

Combat System Basics

Important LSL Combat Concepts:

1. Damage in LSL:

  • llSetDamage(float) - Sets collision damage
  • llRezObject() - Creates bullets/projectiles
  • Damage only works on land with damage enabled

2. Health Tracking:

  • llGetHealth() - Current avatar health (0-100)
  • CHANGED_REGION - Detect region changes
  • Attachments can monitor and display health
Combat System Components
Weapons

Objects that deal damage through collision or rezzing projectiles

Health Systems

HUDs or attachments that monitor and display avatar health

Respawn Logic

Teleport players to spawn points when health reaches zero

System 1: Basic Raycast Gun

A simple gun that shoots invisible bullets dealing damage on hit.

// Basic Raycast Gun - Click to shoot damage-dealing bullets float DAMAGE = 15.0; // Damage per hit (out of 100 health) float BULLET_SPEED = 50.0; // How fast bullet travels float RANGE = 96.0; // Maximum bullet range (meters) float FIRE_RATE = 0.5; // Delay between shots (seconds) integer canFire = TRUE; default { state_entry() { llRequestPermissions(llGetOwner(), PERMISSION_TRIGGER_ANIMATION); llSay(0, "๐Ÿ”ซ Gun ready. Click to fire!"); } touch_start(integer num) { if (!canFire) return; // Prevent rapid fire canFire = FALSE; // Get shooter's position and rotation vector startPos = llGetPos(); rotation gunRot = llGetRot(); // Calculate bullet trajectory (forward direction) vector direction = llRot2Fwd(gunRot); // Cast a ray to detect what we hit list raycast = llCastRay( startPos, startPos + (direction * RANGE), [RC_REJECT_TYPES, RC_REJECT_PHYSICAL | RC_REJECT_LAND] ); // Check if we hit something integer hitCount = llList2Integer(raycast, -1); if (hitCount > 0) { key hitTarget = llList2Key(raycast, 0); // Create damage-dealing projectile at hit location vector hitPos = llList2Vector(raycast, 1); // Visual/audio feedback llPlaySound("gunshot_sound_uuid", 1.0); llParticleSystem([]); // Add muzzle flash particles here llSay(0, "๐Ÿ’ฅ HIT! " + llKey2Name(hitTarget)); } else { llSay(0, "โŒ MISS"); } // Fire rate delay llSleep(FIRE_RATE); canFire = TRUE; } }
Setting Up Your Gun:
  1. Create a gun-shaped prim (or link multiple prims)
  2. Make it an attachment (Edit โ†’ More โ†’ Attach To โ†’ Right Hand)
  3. Insert this script into the gun
  4. Important: Make sure you're in a damage-enabled region to test!

System 2: Melee Weapon (Sword)

A sword that deals damage through collision when swung.

// Melee Sword - Collision-based damage weapon float MELEE_DAMAGE = 25.0; // Damage per hit float SWING_COOLDOWN = 1.0; // Seconds between swings integer isSwinging = FALSE; default { state_entry() { // Enable damage on collision llSetStatus(STATUS_PHANTOM, FALSE); // Make solid for collision llCollisionSound("", 0.0); // Disable default collision sound llSay(0, "โš”๏ธ Sword ready. Click to swing!"); } touch_start(integer num) { if (isSwinging) return; // Can't swing again yet isSwinging = TRUE; // Visual swing animation (rotate sword) rotation originalRot = llGetLocalRot(); rotation swingRot = llEuler2Rot(<0, 90*DEG_TO_RAD, 0>); llSetLocalRot(originalRot * swingRot); // Enable damage during swing llSetDamage(MELEE_DAMAGE); // Swing sound effect llPlaySound("sword_swing_uuid", 1.0); // Wait for swing to complete llSleep(0.3); // Return to original position llSetLocalRot(originalRot); // Disable damage llSetDamage(0.0); // Cooldown period llSleep(SWING_COOLDOWN); isSwinging = FALSE; } collision_start(integer num) { // Only register hits during active swing if (!isSwinging) return; integer i; for (i = 0; i < num; i++) { key hitKey = llDetectedKey(i); string hitName = llDetectedName(i); // Don't damage the owner if (hitKey != llGetOwner()) { llPlaySound("metal_hit_uuid", 1.0); llSay(0, "โš”๏ธ HIT: " + hitName + " for " + (string)MELEE_DAMAGE + " damage!"); } } } }
Collision Damage Tips:
  • llSetDamage() only works on regions with damage enabled
  • Damage is dealt per collision - fast movement = more hits = more damage
  • Use phantom mode when NOT swinging to avoid accidental damage
  • Physical objects deal more consistent collision damage

System 3: Health Monitoring HUD

A HUD attachment that displays your current health and alerts when low.

// Health HUD - Displays avatar health with visual bar float health = 100.0; float LOW_HEALTH_THRESHOLD = 25.0; // Alert below 25% float UPDATE_RATE = 1.0; // Check health every second // Display health as colored text updateHealthDisplay() { health = llGetHealth(); // Choose color based on health level vector color; if (health > 75.0) color = <0, 1, 0>; // Green - healthy else if (health > 50.0) color = <1, 1, 0>; // Yellow - wounded else if (health > 25.0) color = <1, 0.5, 0>; // Orange - critical else color = <1, 0, 0>; // Red - dying // Display health percentage string healthText = "HP: " + (string)(integer)health + "%"; llSetText(healthText, color, 1.0); // Low health alert if (health < LOW_HEALTH_THRESHOLD && health > 0) { llOwnerSay("โš ๏ธ WARNING: Low health! " + (string)(integer)health + "%"); } // Death detection if (health <= 0) { llOwnerSay("๐Ÿ’€ You have died!"); llSetText("DEAD", <0.5, 0, 0>, 1.0); } } default { state_entry() { llRequestPermissions(llGetOwner(), PERMISSION_ATTACH); updateHealthDisplay(); llSetTimerEvent(UPDATE_RATE); } timer() { updateHealthDisplay(); } attach(key id) { if (id != NULL_KEY) { // Attached - start monitoring updateHealthDisplay(); llSetTimerEvent(UPDATE_RATE); } else { // Detached - stop monitoring llSetTimerEvent(0.0); } } touch_start(integer num) { // Manual health check on click updateHealthDisplay(); llOwnerSay("Current health: " + (string)(integer)health + "%"); } }
Creating a Visual Health Bar

Instead of text, use texture UV mapping to show a graphical health bar:

llScaleTexture(health/100.0, 1.0, ALL_SIDES);

Scales texture horizontally based on health percentage.

Audio Alerts

Add heartbeat sound when health is critical:

if (health < 30) llLoopSound("heartbeat", 1.0);

Creates tension and urgency during combat.

System 4: Advanced Damage Receiver

A script that detects damage, tracks who hit you, and logs combat statistics.

// Damage Receiver - Tracks damage sources and combat stats integer totalDamageTaken = 0; list attackers = []; // List of [attacker_key, damage_dealt] default { state_entry() { llOwnerSay("๐Ÿ›ก๏ธ Damage tracking active. Combat stats enabled."); } changed(integer change) { if (change & CHANGED_HEALTH) { float currentHealth = llGetHealth(); float damageTaken = 100.0 - currentHealth; if (damageTaken > totalDamageTaken) { float recentDamage = damageTaken - totalDamageTaken; totalDamageTaken = (integer)damageTaken; // Detect who damaged us (requires collision or sensor data) llOwnerSay("๐Ÿ’” Took " + (string)(integer)recentDamage + " damage! Health: " + (string)(integer)currentHealth + "%"); // Visual damage indicator (red flash) llSetColor(<1, 0, 0>, ALL_SIDES); llSleep(0.2); llSetColor(<1, 1, 1>, ALL_SIDES); } // Death detection if (currentHealth <= 0) { llOwnerSay("๐Ÿ’€ You died! Total damage taken: " + (string)totalDamageTaken); // Reset stats totalDamageTaken = 0; attackers = []; // Trigger respawn (see System 5) } } } collision_start(integer num) { // Track who's hitting us with melee/collision damage integer i; for (i = 0; i < num; i++) { key attacker = llDetectedKey(i); if (attacker != llGetOwner()) // Don't log self-damage { llOwnerSay("โš”๏ธ Hit by: " + llDetectedName(i)); // Add to attackers list (track for kill credit) integer index = llListFindList(attackers, [attacker]); if (index == -1) { attackers += [attacker, 1]; // New attacker } else { // Increment hit count integer hits = llList2Integer(attackers, index + 1) + 1; attackers = llListReplaceList(attackers, [hits], index + 1, index + 1); } } } } touch_start(integer num) { // Display combat stats llOwnerSay("๐Ÿ“Š COMBAT STATS:"); llOwnerSay("Health: " + (string)(integer)llGetHealth() + "%"); llOwnerSay("Damage Taken: " + (string)totalDamageTaken); llOwnerSay("Attackers: " + (string)(llGetListLength(attackers)/2)); } }

System 5: Respawn System

Automatically teleport players to spawn points when they die and restore health.

// Respawn System - Teleports to spawn and restores health on death vector SPAWN_POINT = <128, 128, 25>; // Respawn coordinates float RESPAWN_DELAY = 3.0; // Seconds before respawn default { state_entry() { llRequestPermissions(llGetOwner(), PERMISSION_TELEPORT); llSetTimerEvent(1.0); // Check health every second } run_time_permissions(integer perm) { if (perm & PERMISSION_TELEPORT) { llOwnerSay("โœ… Respawn system ready. You will respawn if killed."); } } timer() { float health = llGetHealth(); if (health <= 0) { // Player is dead - initiate respawn llSetTimerEvent(0.0); // Stop health checks llOwnerSay("๐Ÿ’€ You died! Respawning in " + (string)(integer)RESPAWN_DELAY + " seconds..."); // Death effects (optional) llPlaySound("death_sound_uuid", 1.0); // Wait before respawn llSleep(RESPAWN_DELAY); // Teleport to spawn point llOwnerSay("๐Ÿ”„ Respawning..."); llTeleportAgent(llGetOwner(), "", SPAWN_POINT, ZERO_VECTOR); // Note: Health auto-restores to 100 after teleport in most grids // If not, use region restart or experience tools llSleep(2.0); llOwnerSay("โœจ Respawned! Health restored to 100%"); // Resume health monitoring llSetTimerEvent(1.0); } } changed(integer change) { if (change & CHANGED_TELEPORT) { llOwnerSay("๐Ÿ“ Teleported to: " + (string)llGetPos()); } } }
Important Respawn Notes:
  • PERMISSION_TELEPORT must be granted for respawn to work
  • Teleporting within the same region auto-restores health to 100 in most grids
  • For cross-region respawns, you may need Experience permissions to set health
  • Alternative: Use llTeleportAgent() to a health-restore zone/object

System 6: Team-Based Combat

Prevent friendly fire using group/team detection - only damage enemies!

// Team Combat System - Group-based friendly fire prevention float DAMAGE = 20.0; key TEAM_GROUP; // UUID of team group (set in state_entry) default { state_entry() { // Get the group this object is set to list details = llGetObjectDetails(llGetKey(), [OBJECT_GROUP]); TEAM_GROUP = llList2Key(details, 0); if (TEAM_GROUP == NULL_KEY) { llOwnerSay("โš ๏ธ WARNING: No group set! Set object to team group to enable friendly fire protection."); } else { llOwnerSay("๐Ÿ›ก๏ธ Team weapon ready. Friendly fire protection enabled."); } } touch_start(integer num) { // Detect targets in front of weapon vector startPos = llGetPos(); rotation gunRot = llGetRot(); vector direction = llRot2Fwd(gunRot); // Raycast to find target list raycast = llCastRay( startPos, startPos + (direction * 50.0), [RC_REJECT_TYPES, RC_REJECT_PHYSICAL | RC_REJECT_LAND] ); integer hitCount = llList2Integer(raycast, -1); if (hitCount > 0) { key hitKey = llList2Key(raycast, 0); // Check if target is an avatar if (llGetAgentSize(hitKey) != ZERO_VECTOR) { // It's an avatar - check team membership list agentGroups = llGetObjectDetails(hitKey, [OBJECT_GROUP]); key targetGroup = llList2Key(agentGroups, 0); if (targetGroup == TEAM_GROUP && TEAM_GROUP != NULL_KEY) { // FRIENDLY - Don't shoot! llOwnerSay("๐Ÿ›ก๏ธ FRIENDLY: " + llKey2Name(hitKey) + " is on your team!"); llPlaySound("error_beep_uuid", 0.5); } else { // ENEMY - Deal damage! llOwnerSay("๐Ÿ’ฅ HIT ENEMY: " + llKey2Name(hitKey)); llPlaySound("gunshot_uuid", 1.0); // Deal damage (requires bullet rezzing or collision in damage-enabled region) // Example: llRezObject("bullet", hitPos, ZERO_VECTOR, ZERO_ROTATION, 0); } } } } }
Setting Up Teams
  1. Create groups for each team (Blue Team, Red Team, etc.)
  2. Set weapons to the team's group (Edit โ†’ General โ†’ Set Group)
  3. Players wear/activate team tag when in combat
  4. Weapons automatically detect group membership!
Advanced: Kill/Death Tracking

Use HTTP requests to external database:

llHTTPRequest(api_url, [HTTP_METHOD, "POST"], "kill=" + killer + "&victim=" + victim);

Track leaderboards, K/D ratios, team scores!

โš”๏ธ Build Your Combat System Today!

Join Alife Virtual and create epic combat experiences with these scripts.