Difference between revisions of "User:Nexii Malthus/Object-based health"

From Second Life Wiki
Jump to navigation Jump to search
 
(4 intermediate revisions by the same user not shown)
Line 1: Line 1:
[[Category:LSL Combat2|Combat2]]
[[Category:LSL Combat2|Combat2]]


This is pretty much as simple as it gets. No damage adjustment, just processing final damage. We initialise with a set amount of health which other scripts can read via [[llGetHealth]]. The presence of the [[final_damage]] event marks this as a DAMAGEABLE object for sensors and collisions.
This is pretty much as simple as it gets. No damage adjustment, just processing final damage. We initialise with a set amount of health which other scripts can read via [[llGetHealth]]. The presence of the [[final_damage]] event marks this as a [[DAMAGEABLE]] object for sensors and collisions.


For object-based health the script needs to manually manage it's own health, applying the final damage to the health amount and setting the objects health.
For object-based health the script needs to manually manage it's own health, applying the final damage to the health amount and setting the objects health. If the health reaches 0 or below during the damage processing, it should be considered dead and stop further processing.
 
Because objects don't generate death events, whether the on_death or the system generated combat log messages, we have to handle that aspect ourselves. A community proposals is to send a synthetic OBJECT_DEATH event into the combat channel.


<syntaxhighlight lang="lsl2">
<syntaxhighlight lang="lsl2">
Line 10: Line 12:
     state_entry()
     state_entry()
     {
     {
         llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_HEALTH, 300.0]);
         llSetLinkPrimitiveParamsFast(LINK_THIS, [
            PRIM_HEALTH, 300.0,
            PRIM_TEXT, "300/300", <0,1,0>, 1
        ]);
     }
     }
      
      
Line 16: Line 21:
     {
     {
         float health = llGetHealth(llGetKey());
         float health = llGetHealth(llGetKey());
         while(count --> 0)
         integer deadlyDamage = -1;
        integer index;
        for(index = 0; index < count; ++index)
         {
         {
             list damage = llDetectedDamage(count);
             list damage = llDetectedDamage(index);
             float amount = llList2Float(damage, 0);
             float amount = llList2Float(damage, 0);
             health -= amount;
             health -= amount;
           
            // Check which damage dealt a deadly blow and break the loop
            if(health <= 0)
            {
                health = 0;
                deadlyDamage = index;
                index = count;
            }
           
            // Prevent overhealing
            else if(health > 300.0) health = 300.0;
         }
         }
          
          
         if(health < 0) health = 0;
         // Update the scripted health and set a useful hovertext
         else if(health > 300.0) health = 300.0;
         llSetLinkPrimitiveParamsFast(LINK_THIS, [
            PRIM_HEALTH, health,
            PRIM_TEXT, (string)llRound(health) + "/300", <0,1,0>, 1
        ]);
          
          
        llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_HEALTH, health]);
          
          
         if(health == 0) state dead;
         if(health == 0)
        {
            // Generate synthetic object death event as per https://wiki.secondlife.com/wiki/Talk:Combat_Log#Damageable_Object_Deaths
            vector sourcePos = llDetectedPos(deadlyDamage);
            vector targetPos = llGetPos();
            llRegionSay(COMBAT_CHANNEL, llList2Json(JSON_ARRAY, [
                llList2Json(JSON_OBJECT, [
                    "event", "OBJECT_DEATH",
                    "owner", llDetectedOwner(deadlyDamage),
                    "rezzer", llDetectedRezzer(deadlyDamage),
                    "source", llDetectedKey(deadlyDamage),
                    "source_pos", llList2Json(JSON_ARRAY, [sourcePos.x, sourcePos.y, sourcePos.z]),
                    "target", llGetKey(),
                    "target_pos", llList2Json(JSON_ARRAY, [targetPos.x, targetPos.y, targetPos.z]),
                    "type", llList2Integer(llDetectedDamage(deadlyDamage), 1)
                ])
            ]));
           
            state dead;
        }
     }
     }
}
}
Line 37: Line 76:
     {
     {
         // We are dead, jim
         // We are dead, jim
        llSetText("dead", <1,0,0>, 1);
     }
     }
}
}
</syntaxhighlight>
</syntaxhighlight>

Latest revision as of 01:09, 11 August 2024


This is pretty much as simple as it gets. No damage adjustment, just processing final damage. We initialise with a set amount of health which other scripts can read via llGetHealth. The presence of the final_damage event marks this as a DAMAGEABLE object for sensors and collisions.

For object-based health the script needs to manually manage it's own health, applying the final damage to the health amount and setting the objects health. If the health reaches 0 or below during the damage processing, it should be considered dead and stop further processing.

Because objects don't generate death events, whether the on_death or the system generated combat log messages, we have to handle that aspect ourselves. A community proposals is to send a synthetic OBJECT_DEATH event into the combat channel.

default
{
    state_entry()
    {
        llSetLinkPrimitiveParamsFast(LINK_THIS, [
            PRIM_HEALTH, 300.0,
            PRIM_TEXT, "300/300", <0,1,0>, 1
        ]);
    }
    
    final_damage(integer count)
    {
        float health = llGetHealth(llGetKey());
        integer deadlyDamage = -1;
        integer index;
        for(index = 0; index < count; ++index)
        {
            list damage = llDetectedDamage(index);
            float amount = llList2Float(damage, 0);
            health -= amount;
            
            // Check which damage dealt a deadly blow and break the loop
            if(health <= 0)
            {
                health = 0;
                deadlyDamage = index;
                index = count;
            }
            
            // Prevent overhealing
            else if(health > 300.0) health = 300.0;
        }
        
        // Update the scripted health and set a useful hovertext
        llSetLinkPrimitiveParamsFast(LINK_THIS, [
            PRIM_HEALTH, health,
            PRIM_TEXT, (string)llRound(health) + "/300", <0,1,0>, 1
        ]);
        
        
        if(health == 0)
        {
            // Generate synthetic object death event as per https://wiki.secondlife.com/wiki/Talk:Combat_Log#Damageable_Object_Deaths
            vector sourcePos = llDetectedPos(deadlyDamage);
            vector targetPos = llGetPos();
            llRegionSay(COMBAT_CHANNEL, llList2Json(JSON_ARRAY, [
                llList2Json(JSON_OBJECT, [
                    "event", "OBJECT_DEATH",
                    "owner", llDetectedOwner(deadlyDamage),
                    "rezzer", llDetectedRezzer(deadlyDamage),
                    "source", llDetectedKey(deadlyDamage),
                    "source_pos", llList2Json(JSON_ARRAY, [sourcePos.x, sourcePos.y, sourcePos.z]),
                    "target", llGetKey(),
                    "target_pos", llList2Json(JSON_ARRAY, [targetPos.x, targetPos.y, targetPos.z]),
                    "type", llList2Integer(llDetectedDamage(deadlyDamage), 1)
                ])
            ]));
            
            state dead;
        }
    }
}

state dead
{
    state_entry()
    {
        // We are dead, jim
        llSetText("dead", <1,0,0>, 1);
    }
}