Cleanup is going to take awhile, so the site is back up but editing has been disabled.

Making Rain toggleable

From HalfLife 2 Knowledge Base

Jump to: navigation, search

Contents

Foreword

In this tutorial we will make the func_precipitation entity toggleable by the I/O system. I originally coded this feature for my mod before I decided to make it a tutorial. This tutorial is mainly for beginners and explains the basics of entity networking and the I/O system.

Files we will modify

  • src/dlls/effects.cpp
  • src/cl_dll/c_effects.cpp

src/dlls/effects.cpp

First, find the class declaration of CPrecipitation. Below the line

   void Spawn( void );

add

   void InputTurnOn( inputdata_t &inputdata ) { m_bOn = true; }
   void InputTurnOff( inputdata_t &inputdata ) { m_bOn = false; }
   void InputToggle( inputdata_t &inputdata ) { m_bOn = !m_bOn; }

and below the line

   CNetworkVar( PrecipitationType_t, m_nPrecipType );

add

   CNetworkVar( bool, m_bOn );

Now I will explain what that does. As you can see the functions we added control the boolean variable m_bOn which will be used to determine wether our entity should create precipitation or not. But wait, the variable isn't of type bool, it's of type CNetworkVar. Yet the code treats it as if it was a boolean. That's because it basically is a boolean, enclosed in the CNetworVar type. We need to make it a CNetworkVar so we can send it to the client later, which creates the actual "rain". A CNetworkVar can carry all the base types like

  • int
  • float
  • bool

but also some more advanced things like vectors and coordinates. Now let's take a closer look at the functions. You have no return value and the parameter "inputdata_t &inputdata". Every Input function has to look like that. You should also begin the name with "Input" because that's what Valve does and it makes the code more readable. Now we learn how to actually send the value of our "m_bOn". Find this code:

   IMPLEMENT_SERVERCLASS_ST( CPrecipitation, DT_Precipitation)
       SendPropInt( SENDINFO( m_nPrecipType ), 1, SPROP_UNSIGNED )
   END_SEND_TABLE()

and change it to this:

   IMPLEMENT_SERVERCLASS_ST( CPrecipitation, DT_Precipitation)
       SendPropInt( SENDINFO( m_nPrecipType ), 1, SPROP_UNSIGNED ),
       SendPropBool( SENDINFO( m_bOn ) ),
   END_SEND_TABLE()

Note the commas added at the end of each line. The IMPLEMENT_SERVERCLASS_ST links the server entity to the client version and makes sure everything arrives where it should. But now for the stuff we added. Notice how the already existing line says SendPropInt. This is used because an integer should be sent to the client. This makes it obvious that we have to use SendPropBool here, since we are sending a boolean. Also available for use are:

  • SendPropFloat
  • SendPropString
  • SendPropVector

and others. I don't really know what the "SENDINFO" thing is for, fact is: you must have it. Now we need to link our input functions to the Inputs from hammer. Find the code

BEGIN_DATADESC( CPrecipitation )
        DEFINE_KEYFIELD( m_nPrecipType, FIELD_INTEGER, "preciptype" )
END_DATADESC()

and change it to

BEGIN_DATADESC( CPrecipitation )
       DEFINE_KEYFIELD( m_nPrecipType, FIELD_INTEGER, "preciptype" ),
       DEFINE_INPUTFUNC( FIELD_VOID, "TurnOn", InputTurnOn ),
       DEFINE_INPUTFUNC( FIELD_VOID, "TurnOff", InputTurnOff ),
       DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
END_DATADESC()

Again, don't forget the commas. The DEFINE_INPUTFUNC macro links our function to our input from hammer. The first parameter determines what kind of parameters the input gets. There's different stuff like:

  • FIELD_VOID
  • FIELD_FLOAT
  • FIELD_STRING

but we use "FIELD_VOID" because our input doesn't need any parameters. Note that this does NOT change the parameters our actual input function gets. An input function has to have the parameter "inputdata_t &inputdata". The second parameter of the macro is what you want the name of the input to be and the third parameter is our input function we added earlier. Now we are done with the server file. Lets move on to the client.

src/cl_dll/c_effects.cpp

What we need to do here is catch the value that the server sends and toggle rain creation based on that. Find the line

virtual ~CClient_Precipitation();

in the class definition of CClient_Precipitation and add

bool m_bOn;

below. Note that it is a normal "bool" and not a "CNetworVar". Now find the code

IMPLEMENT_CLIENTCLASS_DT(CClient_Precipitation, DT_Precipitation, CPrecipitation)
       RecvPropInt( RECVINFO( m_nPrecipType ) ),
END_RECV_TABLE()

and change it to

IMPLEMENT_CLIENTCLASS_DT(CClient_Precipitation, DT_Precipitation, CPrecipitation)
       RecvPropInt( RECVINFO( m_nPrecipType ) ),
       RecvPropBool( RECVINFO( m_bOn ) ),
END_RECV_TABLE()

Again, don't forget the commas. Note that it is similar to the macro used in the server code. The "RecvPropSomething" functions are in the client what the "SendPropSomething" functions are in the server and the "RECVINFO" macro matches the serverside SENDINFO macro. Now we are about to make the hardest of all changes in this tutorial. Find the line

EmitParticles( dt );

and add if(m_bOn) above it.

Testing

Congratulations you're done, that's it. Compile and run it to see if it works. To be able to use the input from hammer you will need to edit the fgd file(not covered in this tutorial). You can test it by making a map with a func_precipitation in it and using "ent_fire" commands to fire the "TurnOn"/"TurnOff" inputs. If it doesn't work, or you have other questions about the tutorial, feel free to email me: [d4ryl5@gmail.com]

Personal tools