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.
1. Damage in LSL:
llSetDamage(float) - Sets collision damagellRezObject() - Creates bullets/projectiles2. Health Tracking:
llGetHealth() - Current avatar health (0-100)CHANGED_REGION - Detect region changesObjects that deal damage through collision or rezzing projectiles
HUDs or attachments that monitor and display avatar health
Teleport players to spawn points when health reaches zero
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;
}
}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!");
}
}
}
}llSetDamage() only works on regions with damage enabledA 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 + "%");
}
}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.
Add heartbeat sound when health is critical:
if (health < 30) llLoopSound("heartbeat", 1.0);
Creates tension and urgency during combat.
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));
}
}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());
}
}
}PERMISSION_TELEPORT must be granted for respawn to workllTeleportAgent() to a health-restore zone/objectPrevent 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);
}
}
}
}
}Use HTTP requests to external database:
llHTTPRequest(api_url, [HTTP_METHOD, "POST"], "kill=" + killer + "&victim=" + victim);
Track leaderboards, K/D ratios, team scores!
Join Alife Virtual and create epic combat experiences with these scripts.