It helps if you used named constants for your timer numbers, instead of magic numbers. For example;
void dp88_RemoteControlConsole::Timer_Expired ( GameObject *obj, int number )
{
	if ( number == TIMER_REMOTECONTROL_TIMEOUT && vehicleID == 0 )
	{
		<code>
	}
	else if ( number == TIMER_REMOTECONTROL_DRIVERENTER )
	{
		<code>
	}
	// This can be called for the vehicle being destroyed OR the console becoming disabled
	else if ( number == TIMER_REMOTECONTROL_DRIVEREXIT )
	{
		<code>
	}
	// Count down tick for charge time
	else if ( number == TIMER_REMOTECONTROL_CHARGETICK )
	{
		<code>
	}
}
The above is actually very read-able and you could call seperate functions to handle each if/elseif case. You could alternatively use a timed custom and pass the address of a function to be called when the custom is fired if you really wanted to.
This also works for custom messages, in cases where you don't need them to be user-controllable (because the script should't be attached to the same object twice anyway). For instance;
void dp88_buildingScripts_baseClass::Custom ( GameObject *obj, int type, int param, GameObject *sender )
{
  if ( (m_parentId == -1 && obj == sender)
    || (m_parentId != -1 && Commands->Get_ID(sender) == m_parentId ) )
  {
    if ( type == CUSTOM_BUILDINGSCRIPTS_BUILDINGOFFLINE )
      return OnBuildingOffline(obj);
    if ( type == CUSTOM_BUILDINGSCRIPTS_BUILDINGONLINE )
      return OnBuildingOnline(obj);
    if ( type == CUSTOM_BUILDINGSCRIPTS_BUILDINGCAPTURED )
      return OnBuildingCaptured(obj, param);
    if ( type == CUSTOM_BUILDINGSCRIPTS_BUILDINGDESTROYED )
    {
      OnBuildingDestroyed(obj);
      m_parentId = -1;
      return;
    }
  }
  OnCustom(obj,type,param,sender);
}