Jump to content

Recommended Posts

Hello

I'm using the "CAR_F" from Arma 3 Samples to try to configure the FFV (Fire From Vehicle). More or less it works but it does not finish going as I want.

I want you to not be able to shoot inside and have the same animation as the others who are sitting (Proxy.Cargo01.XX).

Once you go out with the "turn in" I want it to stand up and be able to shoot as if you were out of the vehicle.

Some references:
MyTestAddonPbo: https://drive.google.com/drive/folders/1qv4Nbt2gfjcp5g31MHKcmNPY1pNiWM0m?usp=sharing
Reference 1: https://community.bistudio.com/wiki/Arma_3_Cars_Config_Guidelines#Firing_from_vehicles
Reference 2:

Quote

#include "basicdefines_A3.hpp"
class DefaultEventhandlers;

#include "CfgPatches.hpp"

class WeaponFireGun;
class WeaponCloudsGun;
class WeaponFireMGun;
class WeaponCloudsMGun;

class CfgVehicles
{
	class Car;
	class Car_F: Car
	{
		class HitPoints /// we want to use hitpoints predefined for all cars
		{
			class HitLFWheel;
			class HitLF2Wheel;
			class HitRFWheel;
			class HitRF2Wheel;
			class HitBody;
			class HitGlass1;
			class HitGlass2;
			class HitGlass3;
			class HitGlass4;
		};
		class EventHandlers;
	};

	class Car_F2: Car_F
	{
		class CargoTurret;
		class ViewCargo;
		class NewTurret;
		class Turrets
		{
			class MainTurret: NewTurret
			{
				class ViewOptics;
				class ViewGunner;
				class Turrets
				{
					class CommanderOptics;
				};
			};
		};

	};

	class Test_Car_01_base_F: Car_F2
	{
		model 	= "\Samples_f\Test_Car_01\Test_Car_01";  /// simple path to model
		picture	= "\A3\Weapons_F\Data\placeholder_co.paa"; /// just some icon in command bar
		Icon	= "\A3\Weapons_F\Data\placeholder_co.paa"; /// icon in map

		displayName = "Test Car"; /// displayed in Editor

		hiddenSelections[] = {"camo1"}; ///we want to allow changing the color of this selection

		terrainCoef 	= 6.5; 	/// different surface affects this car more, stick to tarmac
		turnCoef 		= 2.5; 	/// should match the wheel turn radius
		precision 		= 10; 	/// how much freedom has the AI for its internal waypoints - lower number means more precise but slower approach to way
		brakeDistance 	= 3.0; 	/// how many internal waypoints should the AI plan braking in advance
		acceleration 	= 15; 	/// how fast acceleration does the AI think the car has

		fireResistance 	= 5; 	/// lesser protection against fire than tanks
		armor 			= 32; 	/// just some protection against missiles, collisions and explosions
		cost			= 50000; /// how likely is the enemy going to target this vehicle

		transportMaxBackpacks 	= 3; /// just some backpacks fit the trunk by default
		transportSoldier 		= 3; /// number of cargo except driver

		/// some values from parent class to show how to set them up
		wheelDamageRadiusCoef 	= 0.9; 			/// for precision tweaking of damaged wheel size
		wheelDestroyRadiusCoef 	= 0.4;			/// for tweaking of rims size to fit ground
		maxFordingDepth 		= 0.5;			/// how high water would damage the engine of the car
		waterResistance 		= 1;			/// if the depth of water is bigger than maxFordingDepth it starts to damage the engine after this time
		crewCrashProtection		= 0.25;			/// multiplier of damage to crew of the vehicle => low number means better protection
		driverLeftHandAnimName 	= "drivewheel"; /// according to what bone in model of car does hand move
		driverRightHandAnimName = "drivewheel";	/// beware, non-existent bones may cause game crashes (even if the bones are hidden during play)

		class TransportItems /// some first aid kits in trunk according to safety regulations
		{
			item_xx(FirstAidKit,4);
		};

		class HitPoints: HitPoints
		{
			class HitLFWheel: HitLFWheel	{armor=0.125; passThrough=0;}; /// it is easier to destroy wheels than hull of the vehicle
			class HitLF2Wheel: HitLF2Wheel	{armor=0.125; passThrough=0;};

			class HitRFWheel: HitRFWheel	{armor=0.125; passThrough=0;};
			class HitRF2Wheel: HitRF2Wheel 	{armor=0.125; passThrough=0;};

			class HitFuel 			{armor=0.50; material=-1; name="fueltank"; visual=""; passThrough=0.2;}; /// correct points for fuel tank, some of the damage is aFRLied to the whole
			class HitEngine 		{armor=0.50; material=-1; name="engine"; visual=""; passThrough=0.2;};
			class HitBody: HitBody 	{name = "body"; visual="camo1"; passThrough=1;}; /// all damage to the hull is aFRLied to total damage

			class HitGlass1: HitGlass1 {armor=0.25;}; /// it is pretty easy to puncture the glass but not so easy to remove it
			class HitGlass2: HitGlass2 {armor=0.25;};
			class HitGlass3: HitGlass3 {armor=0.25;};
			class HitGlass4: HitGlass4 {armor=0.25;};
		};

		driverAction 		= driver_offroad01; /// what action is going the driver take inside the vehicle. Non-existent action makes the vehicle inaccessible
		cargoAction[] 		= {passenger_low01, passenger_generic01_leanleft, passenger_generic01_foldhands}; /// the same of all the crew
		getInAction 		= GetInLow; 		/// how does driver look while getting in
		getOutAction 		= GetOutLow; 		/// and out
		cargoGetInAction[] 	= {"GetInLow"}; 	/// and the same for the rest, if the array has fewer members than the count of crew, the last one is used for the rest
		cargoGetOutAction[] = {"GetOutLow"}; 	/// that means all use the same in this case

		#include "sounds.hpp"	/// sounds are in a separate file to make this one simple
		#include "pip.hpp"		/// PiPs are in a separate file to make this one simple
		#include "physx.hpp"	/// PhysX settings are in a separate file to make this one simple

		class PlayerSteeringCoefficients /// steering sensitivity configuration
		{
			 turnIncreaseConst 	= 0.3; // basic sensitivity value, higher value = faster steering
			 turnIncreaseLinear = 1.0; // higher value means less sensitive steering in higher speed, more sensitive in lower speeds
			 turnIncreaseTime 	= 1.0; // higher value means smoother steering around the center and more sensitive when the actual steering angle gets closer to the max. steering angle

			 turnDecreaseConst 	= 5.0; // basic caster effect value, higher value = the faster the wheels align in the direction of travel
			 turnDecreaseLinear = 3.0; // higher value means faster wheel re-centering in higher speed, slower in lower speeds
			 turnDecreaseTime 	= 0.0; // higher value means stronger caster effect at the max. steering angle and weaker once the wheels are closer to centered position

			 maxTurnHundred 	= 0.7; // coefficient of the maximum turning angle @ 100km/h; limit goes linearly to the default max. turn. angle @ 0km/h
		};

		/// memory points where do tracks of the wheel appear
		// front left track, left offset
		memoryPointTrackFLL = "TrackFLL";
		// front left track, right offset
		memoryPointTrackFLR = "TrackFLR";
		// back left track, left offset
		memoryPointTrackBLL = "TrackBLL";
		// back left track, right offset
		memoryPointTrackBLR = "TrackBLR";
		// front right track, left offset
		memoryPointTrackFRL = "TrackFRL";
		// front right track, right offset
		memoryPointTrackFRR = "TrackFRR";
		// back right track, left offset
		memoryPointTrackBRL = "TrackBRL";
		// back right track, right offset
		memoryPointTrackBRR = "TrackBRR";

		class Damage /// damage changes material in specific places (visual in hitPoint)
		{
			tex[]={};
			mat[]=
			{
				"A3\data_f\glass_veh_int.rvmat", 		/// material mapped in model
				"A3\data_f\Glass_veh_damage.rvmat", 	/// changes to this one once damage of the part reaches 0.5
				"A3\data_f\Glass_veh_damage.rvmat",		/// changes to this one once damage of the part reaches 1

				"A3\data_f\glass_veh.rvmat",			/// another material
				"A3\data_f\Glass_veh_damage.rvmat",		/// changes into different ones
				"A3\data_f\Glass_veh_damage.rvmat"
			};
		};

		class Exhausts /// specific exhaust effects for the car
		{
			class Exhaust1 /// the car has two exhausts - each on one side
			{
				position 	= "exhaust";  		/// name of initial memory point
				direction 	= "exhaust_dir";	/// name of memory point for exhaust direction
				effect 		= "ExhaustsEffect";	/// what particle effect is it going to use
			};

			class Exhaust2
			{
				position 	= "exhaust2_pos";
				direction 	= "exhaust2_dir";
				effect 		= "ExhaustsEffect";
			};
		};

		class Reflectors	/// only front lights are considered to be reflectors to save CPU
		{
			class LightCarHeadL01 	/// lights on each side consist of two bulbs with different flares
			{
				color[] 		= {1900, 1800, 1700};		/// approximate colour of standard lights
				ambient[]		= {5, 5, 5};				/// nearly a white one
				position 		= "LightCarHeadL01";		/// memory point for start of the light and flare
				direction 		= "LightCarHeadL01_end";	/// memory point for the light direction
				hitpoint 		= "Light_L";				/// point(s) in hitpoint lod for the light (hitPoints are created by engine)
				selection 		= "Light_L";				/// selection for artificial glow around the bulb, not much used any more
				size 			= 1;						/// size of the light point seen from distance
				innerAngle 		= 100;						/// angle of full light
				outerAngle 		= 179;						/// angle of some light
				coneFadeCoef 	= 10;						/// attenuation of light between the above angles
				intensity 		= 1;						/// strength of the light
				useFlare 		= true;						/// does the light use flare?
				dayLight 		= false;					/// switching light off during day saves CPU a lot
				flareSize 		= 1.0;						/// how big is the flare

				class Attenuation
				{
					start 			= 1.0;
					constant 		= 0;
					linear 			= 0;
					quadratic 		= 0.25;
					hardLimitStart 	= 30;		/// it is good to have some limit otherwise the light would shine to infinite distance
					hardLimitEnd 	= 60;		/// this allows adding more lights into scene
				};
			};

			class LightCarHeadL02: LightCarHeadL01
			{
				position 	= "LightCarHeadL02";
				direction 	= "LightCarHeadL02_end";
				FlareSize 	= 0.5;						/// side bulbs aren't that strong
			};

			class LightCarHeadR01: LightCarHeadL01
			{
				position 	= "LightCarHeadR01";
				direction 	= "LightCarHeadR01_end";
				hitpoint 	= "Light_R";
				selection 	= "Light_R";
			};

			class LightCarHeadR02: LightCarHeadR01
			{
				position 	= "LightCarHeadR02";
				direction 	= "LightCarHeadR02_end";
				FlareSize 	= 0.5;
			};
		};

		aggregateReflectors[] = {{"LightCarHeadL01", "LightCarHeadL02"}, {"LightCarHeadR01", "LightCarHeadR02"}}; /// aggregating reflectors helps the engine a lot
		/// it might be even good to aggregate all lights into one source as it is done for most of the cars

		class EventHandlers: EventHandlers
		{
			// (_this select 0): the vehicle
			// """" Random texture source (pick one from the property textureList[])
			// []: randomize the animation sources (accordingly to the property animationList[])
			// false: Don't change the mass even if an animation source has a defined mass
			init="if (local (_this select 0)) then {[(_this select 0), """", [], false] call bis_fnc_initVehicle;};";
		};

		// Must be kept as fail-safe in case of issue with the function
		hiddenSelectionsTextures[]={"\A3\Weapons_F\Data\placeholder_co.paa"};	 /// we could use any texture to cover the car

		// Definition of texture sources (skins), used for the VhC (Vehicle customization)
		// Also, because the Garage uses the VhC, it will make them available from the garage
		class textureSources
		{
			class red // Source class
			{
				displayName="Red"; // name displayed, among other, from the garage
				author=$STR_A3_Bohemia_Interactive; // Author of the skin
				textures[]=// List of textures, in the same order as the hiddenSelections definition
				{
					"#(rgb,8,8,3)color(1,0,0,1)" // This is procedural texture, can be useful to set placeholder
				};
				factions[]=// This source should be available only for these factions
				{
					"OPF_F", "OPF_G_F" // Side Opfor
				};
			};
			class blue
			{
				displayName="BBBBLue";
				author=$STR_A3_Bohemia_Interactive;
				textures[]=
				{
					"#(rgb,8,8,3)color(0,0,1,1)"
				};
				factions[]=
				{
					"BLU_F", "BLU_G_F" // Side Blufor
				};
			};
			class green
			{
				displayName="Green";
				author=$STR_A3_Bohemia_Interactive;
				textures[]=
				{
					"#(rgb,8,8,3)color(0,1,0,1)"
				};
				factions[]=
				{
					"IND_F", "IND_G_F" // Side independent
				};
			};
			class yellow
			{
				displayName="Yellow power";
				author=$STR_A3_Bohemia_Interactive;
				textures[]=
				{
					"#(rgb,8,8,3)color(0,1,0,1)"
				};
				factions[]=
				{
					// Guerilla only
					"BLU_G_F",
					"OPF_G_F",
					"IND_G_F"
				};
			};
			class white
			{
				displayName="White is white";
				author="Another name";
				textures[]=
				{
					"#(rgb,8,8,3)color(1,1,1,1)"
				};
				factions[]=
				{
					"CIV_F" // side civilian
				};
			};
			class black
			{
				displayName="Dark side";
				author="Tom_48_97";
				textures[]=
				{
					"#(rgb,8,8,3)color(0,0,0,1)"
				};
				factions[]= {}; // Should be available for every factions
			};
		};
		// [_textureSourceClass1, _probability1, _textureSourceClass2, _probability2, ...]
		// Default behavior of the VhC is to select one of these sources, with a weighted random
		textureList[]=
		{
			"red", 1,
			"green", __EVAL(1/3), // You can also use EVAL to evaluate an expression
			"blue", 1,
			"black", 1
			// You can noticed that the white source is missing, therefore, it won't be part of the random
		};

		class MFD /// Clocks on the car board
		{
			class ClockHUD
			{
				#include "cfgHUD.hpp"
			};
		};


		class Turrets: Turrets
		{
			class CargoTurret_01 : CargoTurret	//(FFV) Firing From Vehicles
			{
				class ViewGunner : ViewCargo {};  //should fix the arseview, hopefully
				gunnerAction = "vehicle_turnout_2";
				memoryPointsGetInGunner = "pos cargo L";
				memoryPointsGetInGunnerDir = "pos cargo L dir";
				gunnerName = $STR_A3_TURRETS_CARGOTURRET_R2;
				gunnerCompartments = Compartment1;
				proxyIndex = 4;
				isPersonTurret = 1; // this turret is able to fire both when turned in and out				
				gunnerGetInAction = "GetInHigh";
				gunnerGetOutAction = "GetOutHigh";
				canHideGunner = 1;
				gunnerInAction = "passenger_apc_generic02";
				enabledByAnimationSource = "left_gunner_move";
				inGunnerMayFire = 0;
				outGunnerMayFire = 1;
				LODTurnedIn = VIEW_DEFAULT_LOD;
				LODTurnedOut = VIEW_DEFAULT_LOD;

				// Old view limits inbounce
				maxElev = 45;	// vertical limit for field of view
				minElev = -5;	// vertical limit for field of view
				maxTurn = 95;	// horizontal limit for field of view
				minTurn = -95;	// horizontal limit for field of view
				
				class dynamicViewLimits	// additional limits according to filled positions
				{
					CargoTurret_02[] = { -65, 95 };	// if CargoTurret_02 is filled, this turret cannot turn that much to negative way (limits from -95 to -65 degrees)
				};

				/// New view limits inbounce
				class TurnIn /// limits for gunner turned in
				{
					limitsArrayTop[] = { {33.8208, -93.9616}, {40.8906, 66.5705} };	// points for the upper curve
					limitsArrayBottom[] = { {-9.4643, -94.5753}, {-8.3683, -67.6867}, {-9.7173, 43.6372}, {-10.1082, 78.9166} }; /// points for the lower curve
				};
				class TurnOut : TurnIn {}; /// turn out uses the same limits as turn in this time				
			};
		};
	};

	// Derivate from the base class
	class C_Test_Car_01_F: Test_Car_01_base_F /// some class that is going to be visible in editor
	{
		scope	= 2; 			/// makes the car visible in editor
		scopeCurator=2;			// scope 2 means it's available in Zeus mode (0 means hidden)
		crew 	= "C_man_1"; 	/// we need someone to fit into the car
		side	= 3; 			/// civilian car should be on civilian side
		faction	= CIV_F;		/// and with civilian faction
	};

};

 

 

Thx for your help,
Spyke

Share this post


Link to post
Share on other sites

Well finally with some help from the arma 3 discord (reyhard thx) this is what I have:

This is the code for a FFV from a BMR600 (4 cargoTurrets with 2 hatches).
 

Quote

class CargoTurret_01 : CargoTurret	//(FFV) Firing From Vehicles
{
  gunnerAction 				= "passenger_inside_6_Idle";	// When you are OUT
  gunnerInAction				= "passenger_apc_narrow_generic01";	// When you are IN		
  gunnerCompartments 			= "Compartment1";			/// gunner is able to switch gunner seats
  cargoCompartments			= "Compartment1";			/// gunner is able to switch cargo seats
  memoryPointsGetInGunner 	= "pos cargoTurret";		/// specific memory points to allow choice of position
  memoryPointsGetInGunnerDir	= "pos cargoTurret dir";	/// direction of get in action
  gunnerName 					= "Cargo Turret 1 (BL)";	/// name of the position in the Action menu
  proxyIndex 					= 5;					/// what cargo proxy is used according to index in the model
  maxElev 					= 50;					/// what is the highest possible elevation of the turret
  minElev 					= -15;					/// what is the lowest possible elevation of the turret
  maxTurn 					= 120;					/// what is the left-most possible turn of the turret
  minTurn 					= -120;					/// what is the right-most possible turn of the turret
  isPersonTurret 				= 1;					/// enables firing from vehicle functionality
  ejectDeadGunner 			= 0;					/// seatbelts included
  //enabledByAnimationSource 	= "hatchGunnerOffset_1";			/// doesn't work unless the said animation source is 1 (This doesn't work if the vehicle is inherits from CAR_F)
  animationSourceHatch 		= "hatchGunnerOffset_1";
  showAsCargo 				= true;		
  minOutElev=-15; maxOutElev=+80; initOutElev=0;
  minOutTurn=-90; maxOutTurn=+90; initOutTurn=0;
  maxHorizontalRotSpeed = 1.0; maxVerticalRotSpeed = 1.0;			
};
class CargoTurret_02 : CargoTurret_01
{
  gunnerName = "Cargo Turret 2 (BR)";
  animationSourceHatch = "hatchGunnerOffset_2";
  proxyIndex = 6;
};
class CargoTurret_03 : CargoTurret_01
{
  gunnerName = "Cargo Turret 3 (FL)";
  animationSourceHatch = "hatchGunnerOffset_3";
  proxyIndex = 7;
};
class CargoTurret_04 : CargoTurret_01
{
  gunnerName = "Cargo Turret 4 (FR)";
  animationSourceHatch = "hatchGunnerOffset_4";
  proxyIndex = 8;
};

 

This requieres to create an animationSource
 

Quote

class AnimationSources
{
	// Turn 180º the player proxy
  class hatchGunnerOffset_1
  {
    source="user";
    animPeriod=0.5;
    initPhase=0;
  };
  class hatchGunnerOffset_2
  {
    source="user";
    animPeriod=0.5;
    initPhase=0;
  };
  class hatchGunnerOffset_3
  {
    source="user";
    animPeriod=0.5;
    initPhase=0;
  };
  class hatchGunnerOffset_4
  {
    source="user";
    animPeriod=0.5;
    initPhase=0;
  };
	// Hatch Animations	
  class hatchtop1
  {
    source = "user";
    animPeriod = 0;
    initPhase = 0;
  };
  class hatchtop2
  {
    source = "user";
    animPeriod = 0;
    initPhase = 0;
  };	
};

 

An EventHandler to detect when the player is turnedOut and move the hatch and rotate the player to the correct direction
 

Quote

class EventHandlers: DefaultEventhandlers
{
  class Ripper_BMR600_AnimationsFFV	// Este script controlará las animaciones de las escotillas (abrir/cerrar compuerta y Girar 180º el proxy)
  {
    init="_scr = _this execVM 'ripper_bmr600\scripts\fn_BMR_TurnOutFFV.sqf'";
  };
};

 

And this is the code (fn_BMR_TurnOutFFV.sqf):
 

Quote

params[["_veh",objNull]];

if(isNull _veh)exitWith{};
if !(isServer) exitWith {};

while {alive _veh} do
{   
    // Open/Close hatches
    if (isTurnedOut (_veh turretUnit [1]) || isTurnedOut (_veh turretUnit [2])) then {
        if (_veh animationPhase "hatchtop1" < 1) then {
            _veh animateSource ["hatchtop1",1];
        };
    } else {
        if ((_veh animationPhase "hatchtop1") > 0) then {
            _veh animateSource ["hatchtop1", 0];
        };
    };
    if (isTurnedOut (_veh turretUnit [3]) || isTurnedOut (_veh turretUnit [4])) then {
        if (_veh animationPhase "hatchtop2" < 1) then {
            _veh animateSource ["hatchtop2",1];
        };
    } else {
        if ((_veh animationPhase "hatchtop2") > 0) then {
            _veh animateSource ["hatchtop2", 0];
        };
    };
    
    // Rotate player
    if(isTurnedOut (_veh turretUnit [1]))then{_veh animateSource ["hatchGunnerOffset_1",1];}else{_veh animateSource ["hatchGunnerOffset_1",0];};
    if(isTurnedOut (_veh turretUnit [2]))then{_veh animateSource ["hatchGunnerOffset_2",1];}else{_veh animateSource ["hatchGunnerOffset_2",0];};
    if(isTurnedOut (_veh turretUnit [3]))then{_veh animateSource ["hatchGunnerOffset_3",1];}else{_veh animateSource ["hatchGunnerOffset_3",0];};
    if(isTurnedOut (_veh turretUnit [4]))then{_veh animateSource ["hatchGunnerOffset_4",1];}else{_veh animateSource ["hatchGunnerOffset_4",0];};
       
    sleep 0.5;
};

 

And this the model.cfg
 

Quote

class Animations
{  
  class hatchGunnerOffset_1
  {
  type="rotationY";
  source="user";						// The controller that provides input above
  selection="cargoTurret_01";			// The name of the skeleton bone used.
  axis="cargoTurret_01_Axis";			// name of the axis in the model.
  memory = true;
  minValue = 0;
  maxValue = 1;
  angle0 = "(rad 0)";
  angle1 = "(rad 180)";	
  };
  class hatchGunnerOffset_2 : hatchGunnerOffset_1
  {
  selection="cargoTurret_02";
  axis="cargoTurret_02_Axis";
  };
  class hatchGunnerOffset_3 : hatchGunnerOffset_1
  {
  selection="cargoTurret_03";
  axis="cargoTurret_03_Axis";
  };		
  class hatchGunnerOffset_4 : hatchGunnerOffset_1
  {
  selection="cargoTurret_04";
  axis="cargoTurret_04_Axis";
  };  
  class hatchTop1
  {
  type="rotation";
  source="user";
  selection="hatchtop1";
  axis="hatchtop1_axis";
  animPeriod=0;
  minValue="0";
  maxValue="1";
  angle0="rad 0";
  angle1="rad -170";
  memory=1;
  };
  class hatchTop2: hatchTop1
  {
  selection="hatchtop2";
  axis="hatchtop2_axis";
  };
};

 


Hope this helps.

  • Like 2

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now

×