Multipassenger Vehicle Abstract
This article needs to be cleaned up to conform to a higher standard of quality.
This page will describe in high-level how to successfully implement a multi-passenger vehicle system on top of the existing Valve vehicles. There won't be much of any code shown however I will try to explain in detail what needs to occur. I will also offer some insight into a few other features that you can use in improving vehicles.
Introduction to Source Engine Vehicles
First and foremost it is important to understand the structure of the Source Engine Vehicles.
On the Client you have:
- Client-side vehicle entity derived from the Client Vehicle Interface and the Base Animating class
On the Server you have:
- The Server Vehicle Class which handles the physical aspects of the vehicle which derives of the Base Server Vehicle class
- The Server Vehicle Entity which derives off a Prop Vehicle class and a Drivable Vehicle interface and handles the input from the player
In implementing a multi-passenger system for my vehicles I chose to start out by pretending that the Drivable Vehicle class and the Drivable Vehicle interface never existed. Though you will likely reuse a lot of code from it, but to keep things clean I chose to do it this way. I basically created a new IPassengerVehicle interface and reused all the functions from the Drivable Vehicle interface but included role anywhere it wasn't already included and added other useful things I might need that weren't there before.
Another important item to understand is the chain of events that gets a player into a vehicle. The chain is as follows:
Implementing the System
The first item we will need to take care of is the storage of our passengers. Normally you have a single Entity Handle (EHANDLE) to the driver of the vehicle. We will need to create a networked array for our passengers. Something such as:
CNetworkArray( EHANDLE, m_hPassenger, LAST_SHARED_VEHICLE_ROLE );
LAST_SHARED_VEHICLE_ROLE would correlate to an enumeration for how many maximum passengers for any vehicles you wish to allow. I decided to allow a maximum of 8 players to be using a vehicle at one time and just created an enumeration over each passenger such as VEHICLE_ROLE_PASSENGER0, etc. It is of note that you should define the VEHICLE_ROLE_DRIVER to point to VEHICLE_ROLE_PASSENGER0 and to always craft your vehicles with the driver as the 1st passenger to make things easier.
The next step is once we reach the HandlePassengerEntry function we must begin to determine what role the player is trying to assume. For my purposes I ignored supporting entry and exit animations which basically cut down the original function to a simple check for the role and a check if the vehicle can be used by the player. I created a function that takes in the player's eye position and returns the role he will use. In this function I assume all of our vehicles will use a special hitbox set called the "entryboxes" which will contain the hitboxes to use for determining what role a player is trying to access. Essentially we want to determine two things. First, we want to iterate over the hitboxes in the "entryboxes" set and determine which hitbox the player's eyes are in. If they are not in any we can return -1 and have that role value end the chain for using the vehicle. However if we do find a valid role we need to first check if that role is occupied or not. This is simply adding a function that checks if there is a valid EHANDLE in the passenger array for that particular role.
If you have followed everything prior you should now have the empty role that the player is trying to access. Conveniently you will find that the player class GetInVehicle function already requires a role to be passed in which in the past was always 0 for the VEHICLE_ROLE_DRIVER. Now we will be passing in more than just a 0 role. A few things are occurring in this GetInVehicle function. First the player checks if his weapons are available to use at the role. Next it checks if the player is visible, and finally it checks where it needs to place the player on the vehicle. This function is called GetPassengerStartPoint and you can override it to work with your roles. What I did was to have the attachments for feet and eyes referred to as vehicle_passenger%d_eyes and vehicle_passenger%d_feet where the %d is the role number. This maintains consistency across authoring any vehicles you use in this system.