1. On August 16th at 9pm CST, the site will be put in to read only mode for maintenance. Maintenance should not take longer than an hour.

Slime - The lost material type

Discussion in 'Mapping Questions & Discussion' started by henke37, Jun 23, 2016.

  1. henke37

    aa henke37

    Messages:
    1,909
    Positive Ratings:
    446
    I am sure that most of us have at least noticed the existence of a dev/dev_slime material when skimming the dev folder in the texture browser. But what does it do?

    Let's start by looking at the material itself:

    Code:
    // dev/dev_slime.vmt
    "LightmappedGeneric"
    {
        // Original shader: BaseTimesLightmap
        "%compileSlime" 1
        "$basetexture" "Dev/dev_slime"
        "$surfaceprop" "slime"
    }
    
    Ok, so it passes the %compileSlime flag to vbsp. What does that mean?

    Code:
    // from int FindMiptex (const char *name) in textures.cpp
    // https://github.com/Noiwex/hl2sb-src/blob/master/src/utils/vbsp/textures.cpp#L261
        if ( ( propVal = GetMaterialVar( matID, "%compileSlime" ) ) &&
           StringIsTrue( propVal ) )
         {
           textureref[i].contents &= ~(CONTENTS_SOLID|CONTENTS_DETAIL);
           textureref[i].contents |= CONTENTS_SLIME;
           textureref[i].flags |= SURF_NODECALS;
           // Set this so that we can check at the end of the process the presence of a a WaterLODControl entity.
           g_bHasWater = true;
         }
    
    Now it's passed along as CONTENTS_SLIME. Lets see where the game code checks for that!

    First up we have some old quake code. I can only assume that Valve didn't keep this one when they redesigned their physics system.
    Code:
    //void JumpButton (void)
    //http://osxr.org:8080/android/source/external/quake/quake/src/QW/client/pmove.c#0667
      if (waterlevel >= 2)
      {  // swimming, not jumping
      onground = -1;
      if (watertype == CONTENTS_WATER)
      pmove.velocity[2] = 100;
      else if (watertype == CONTENTS_SLIME)
      pmove.velocity[2] = 80;
      else
      pmove.velocity[2] = 50;
      return;
      }
    
    
    Next up we have some mentions in the HL2 source code:
    Code:
    // https://github.com/ValveSoftware/source-sdk-2013/blob/master/sp/src/game/server/basebludgeonweapon.cpp#L236
    bool CBaseHLBludgeonWeapon::ImpactWater( const Vector &start, const Vector &end )
    {
       //FIXME: This doesn't handle the case of trying to splash while being underwater, but that's not going to look good
       //      right now anyway...
       
       // We must start outside the water
       if ( UTIL_PointContents( start ) & (CONTENTS_WATER|CONTENTS_SLIME))
         return false;
    
       // We must end inside of water
       if ( !(UTIL_PointContents( end ) & (CONTENTS_WATER|CONTENTS_SLIME)))
         return false;
    
       trace_t   waterTrace;
    
       UTIL_TraceLine( start, end, (CONTENTS_WATER|CONTENTS_SLIME), GetOwner(), COLLISION_GROUP_NONE, &waterTrace );
    
       if ( waterTrace.fraction < 1.0f )
       {
         CEffectData   data;
    
         data.m_fFlags  = 0;
         data.m_vOrigin = waterTrace.endpos;
         data.m_vNormal = waterTrace.plane.normal;
         data.m_flScale = 8.0f;
    
         // See if we hit slime
         if ( waterTrace.contents & CONTENTS_SLIME )
         {
           data.m_fFlags |= FX_WATER_IN_SLIME;
         }
    
         DispatchEffect( "watersplash", data );       
       }
    
       return true;
    }
    There is also a mention in physics_fx.cpp, again for making splashes.

    Both of these use the FX_WATER_IN_SLIME constant. Lets see where that is used:
    Code:
    // http://hlssmod.net/he_code/game/client/fx_water.cpp
    void SplashCallback( const CEffectData &data )
    {
        Vector    normal;
    
        AngleVectors( data.m_vAngles, &normal );
    
        if ( data.m_fFlags & FX_WATER_IN_SLIME )
        {
            FX_GunshotSlimeSplash( data.m_vOrigin, Vector(0,0,1), data.m_flScale );
        }
        else
        {
            FX_GunshotSplash( data.m_vOrigin, Vector(0,0,1), data.m_flScale );
        }
    }
    
    DECLARE_CLIENT_EFFECT( "watersplash", SplashCallback );
    
    
    void GunshotSplashCallback( const CEffectData &data )
    {
        if ( data.m_fFlags & FX_WATER_IN_SLIME )
        {
            FX_GunshotSlimeSplash( data.m_vOrigin, Vector(0,0,1), data.m_flScale );
        }
        else
        {
            FX_GunshotSplash( data.m_vOrigin, Vector(0,0,1), data.m_flScale );
        }
    }
    
    DECLARE_CLIENT_EFFECT( "gunshotsplash", GunshotSplashCallback );
    
    Looks like we are getting close to a meaningful difference in behaviour!

    Code:
    void FX_GunshotSlimeSplash( const Vector &origin, const Vector &normal, float scale )
    {
       if ( cl_show_splashes.GetBool() == false )
         return;
    
       VPROF_BUDGET( "FX_GunshotSlimeSplash", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
       
    #if 0
    // cut for brevity since it's not used
    // it's more or less identical to the code of FX_GunshotSplash, but with a different effect material
    #else
       
       QAngle vecAngles;
       VectorAngles( normal, vecAngles );
       if ( scale < 2.0f )
       {
         DispatchParticleEffect( "slime_splash_01", origin, vecAngles );
       }
       else if ( scale < 4.0f )
       {
         DispatchParticleEffect( "slime_splash_02", origin, vecAngles );
       }
       else
       {
         DispatchParticleEffect( "slime_splash_03", origin, vecAngles );
       }
    
    #endif
    
       //Play a sound
       CLocalPlayerFilter filter;
    
       EmitSound_t ep;
       ep.m_nChannel = CHAN_VOICE;
       ep.m_pSoundName =  "Physics.WaterSplash";
       ep.m_flVolume = 1.0f;
       ep.m_SoundLevel = SNDLVL_NORM;
       ep.m_pOrigin = &origin;
    
       C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, ep );
    }
    So, this ultimately ends up as water that has a different particle effect when shot at. Clearly an important difference from water.

    If anyone know of any more differences, please just post them in this topic.
     
    • Useful Useful x 1
  2. Pocket

    aa Pocket func_croc

    Messages:
    4,489
    Positive Ratings:
    2,219
    I don't know about any of this code, but I'm pretty sure the slime surfaceprop is for slippery surfaces. Like in Half-Life 2 when you encounter the buttload of barnacles you're supposed to blow up with the explosive barrels, and near the end of Portal when you're in the trenches in the huge room where all the turrets pop out. I never did find out if it's meant to be something you stand in or something you stand on since you can't see your own feet in either of those games, but if it's based on water, I guess it's the former.
     
    • Agree Agree x 1