Jump to content
Sign in to follow this  
Norco321

How to turn SQF into a standalone PBO?

Recommended Posts

Hi guys, I'm new to this forum and SQF.

As it stands I have been testing my scripts using the init.sqf in the Editor; however, I want to be able to distribute them as PBOs.

Now I understand how to make a PBO using BinPBO but after creating my PBO, I tried to add it into game via the mod folders/launch options but it does not appear to function/run.

I have seen there's a config.cpp/bin that is present in all addons and I am unsure how I am supposed to configure this for a purely script-based addon (no assets).

I've searched everywhere but I can't seem to find anything. I don't know whether it's because I'm searching for the wrong terms or what but any help would be greatly appreciated.

Cheers.

Just for extra info, I am a programmer by day so you can assume I understand general programming constructs.

Share this post


Link to post
Share on other sites

There are probably several ways to do it, but the way I was originally shown (by Das Attorney), uses CBA.

Here's how I did it for an addon of mine called TPW LOS

1 - I created a directory called TPW_LOS

2- I dropped tpw_los.sqf (the actual script that does the work) into this directory

// THIS SCRIPT WON'T RUN ON DEDICATED SERVERS
if (isDedicated) exitWith {};

/*
TPW LOS A3
Version: 1.03
Author: tpw
Date: 20130818
Original Line of sight stuff: SaOk 
Azimuth stuff: CarlGustaffa
Additional code: Ollem
Features:
- Works for all editor placed and spawned infantry.
- Infantry units will stop and rapidly turn (stance dependent) and fire upon any visible enemies they have line of sight to.
- Enemy visibility is influenced by time of day, stance, speed, camouflage and NV at night.
- Enemies closer than a specified minimum distance (default 25m) are considered visible regardless.
- Enemies beyond a maximum distance (default 100m) are not subject to line of sight calculations.
- Debugging will enable blue balls over any units that have line of sight to an enemy. 

Disclaimer: Feel free to use and modify this code, on the proviso that you post back changes and improvements so that everyone can benefit from them, and acknowledge the original author (tpw) in any derivative works. 	
*/

///////////
//VARIABLES
///////////

if ((count _this) < 5) exitWith {hint "TPW LOS incorrect/no config, exiting."};

tpwlos_hint = _this select 0; // Startup hint. 0 = no hint, 1 = hint
tpwlos_debug = _this select 1; // Debugging. Units with los to a visible enemy will have a blue ball over their heads. 0 = no debugging, 1 = debugging.
tpwlos_maxdist = _this select 2; // Maximum distance (m). LOS stuff only works for units closer than this.
tpwlos_mindist = _this select 3; // Minimum distance (m). Enemies are considered "visible" no matter what, if less than this distance.
tpwlos_sleep = _this select 4; // Delay before LOS functions start. 



/////////
//SET UP
/////////

//WAIT
sleep tpwlos_sleep;  

//START HINT
if (tpwlos_hint == 1) then 
{
[] spawn 
	{
	hintsilent "TPW LOS 1.03 active"; 
	sleep 3; 
	hintsilent ""
	};
};

//////////////////////////////////////////	
//ANGLE OF SUN - ADAPTED FROM CARLGUSTAFFA
//////////////////////////////////////////
tpwlos_fnc_sunangle =
{
private ["_lat","_day","_hour"];
while {true} do 
	{
	_lat = -1 * getnumber(configfile >> "cfgworlds" >> worldname >> "latitude");
	_day = 360 * (datetonumber date);
	_hour = (daytime / 24) * 360;
	tpwlos_sunangle = round (((12 * cos(_day) - 78) * cos(_lat) * cos(_hour)) - (24 * sin(_lat) * cos(_day)));  
	sleep 300; 
	};
};


//////////////////////////////
// RAPIDLY TURN TO ENEMY
/////////////////////////////	
tpwlos_fnc_turn =
{
private ["_unit","_near","_i","_stance","_delta","_inc","_div"];
_unit = _this select 0;
_near = _this select 1;
_delta = _this select 2;
_stance = stance _unit;

switch _stance do
	{
	case "prone": 
		{
		_div = 6;
		};
	case "crouch": 
		{
		_div = 4;
		};
	case "stand": 
		{
		_div = 2;
		};
	default 
		{
		_div = 2;
		};	
	};

// Turn increment (smaller for lower stances ie slower)
_inc = (_delta / _div) * 0.1; 
_unit setvariable ["tpwlos_turning", 1]; 

for "_i" from 1 to 10 do 
	{
	sleep 0.01;
	_unit setdir ((direction _unit) + _inc);
	};

	_unit setvariable ["tpwlos_turning", 0]; 	
};



////////////////
//MAIN FUNCTION
////////////////
tpwlos_fnc_mainloop =  
{
private ["_x","_nexttime","_unit","_near","_nearunits","_a","_b","_dirto","_eyed","_eyepb","_eyepa","_eyedv","_ang","_tint","_lint","_vm","_dist","_esp","_usp","_camo","_formula","_ball","_upos","_stance","_delta","_unitdir","_mod","_fsmtime"]; 	
    {
	// ONLY RUN FOR UNINJURED COMBATANT AI
	if ((side _x != civilian) && {(canstand _x) && (_x != player)}) then 
		{	 
		_unit = _x; 
		_nexttime = _unit getvariable ["tpwlos_nexttime", -1]; 
		_fsmtime = _unit getvariable ["tpwlos_fsmtime", -1]; 
		_turning = _unit getvariable ["tpwlos_turning", 0]; 

		//SET UP INITIAL UNIT PARAMETERS
		if(_nexttime == -1) then 
			{
			//ENEMY SIDE
			switch (side _unit) do 
			{
			case east: 
				{
				_unit setvariable ["tpwlos_enemyside",west];
				};
			case west: 
				{
				_unit setvariable ["tpwlos_enemyside",east];
				};
			case resistance: 
				{
				_unit setvariable ["tpwlos_enemyside",east];
				};
			};

			//DEBUG BLUE BALLS
			if (tpwlos_debug == 1) then 
				{
				_ball = "sign_sphere25cm_F" createvehicle getposatl _unit;
				_ball attachto [_unit,[0,0,2.3]]; 
				_unit setvariable ["tpwlos_losball",_ball];
				_ball setObjectTexture [0,"#(argb,8,8,3)color(0.2,0.2,0.9,0.5,ca)"];  
				_unit addeventhandler ["killed","_this call tpwlos_fnc_deadclean"];
				};
			_unit setvariable ["tpwlos_nexttime", diag_ticktime + random 1];
			};

		//ALLOW INDEPENDENT MOVEMENT AND TARGETTING 
		if (diag_ticktime >= _fsmtime) then  
			{	 
			//DISABLE FSM
			_unit enableai "AUTOTARGET";
			_unit enableai "MOVE";
			};

		//IF ENOUGH TIME HAS PASSED SINCE LAST LOS CHECK	
		if(diag_ticktime >= _nexttime) then  
			{	 
			//HIDE DEBUG BALLS
			if (tpwlos_debug == 1) then 
				{
				_ball = _unit getvariable "tpwlos_losball"; 
				_ball hideobject true;
				};		
			_unit setvariable ["tpwlos_nexttime", diag_ticktime + random 1]; 

			//FIND NEAR MEN AND CARS
			_nearunits = (getposatl _unit) nearentities [["man","car"],tpwlos_maxdist]; 
				{ 
				_near = _x; 
				tpwlos_cansee = 0; 

				//IF ENEMY
				if (side _near == _unit getvariable "tpwlos_enemyside") then  
					//DOES UNIT HAVE LINE OF SIGHT
					{ 
					_a = _unit;  
					_b = _near;  
					_eyedv = eyedirection _a;  
					_eyed = ((_eyedv select 0) atan2 (_eyedv select 1));   
					_dirto = ([_b, _a] call bis_fnc_dirto);  
					_ang = abs (_dirto - _eyed); 
					_eyepa = eyepos _a; 
					_eyepb = eyepos _b; 
					_tint = terrainintersectasl [_eyepa, _eyepb]; 
					_lint = lineintersects [_eyepa, _eyepb]; 
					if (((_ang > 120) && (_ang < 240)) && {!(_lint) && !(_tint)}) then
						{
						//OTHER FACTORS AFFECTING VISIBILITY OF ENEMY
						_vm = (currentvisionmode _unit); 
						if (_vm == 1) then 
							{
							_vm = -1
							} 
							else 
							{
							_vm = 1
							}; 

						_dist = (_unit distance _near); 
						_esp = abs (speed _near);
						_usp = abs (speed _unit);
						_camo = getnumber (configfile >> "cfgvehicles" >> (typeof _near) >> "camouflage");

						//GET ENEMY'S CURRENT STANCE
						_stance= stance _b;
						switch _stance do
							{
							case "STAND": 
								{
								_upos = 1.00;
								};
							case "CROUCH":
								{
								_upos = 0.75;
								};
							case "PRONE":
								{
								_upos = 0.25;
								};	
							default 
								{
								_upos = 1.00;
								};
							};

						//MAGIC VISIBILITY FORMULA
						_formula = (_vm * (tpwlos_sunangle) * _upos) + (_esp * 6) - (_usp * 2) - _dist + random 40;

						//ANYONE LESS THAN 25m IS FAIR GAME
						if (_dist < tpwlos_mindist) then 
							{
							_formula = 200
							};

						//IGNORE CAMO ENEMY	
						if (_camo > 0.5) then 
							{
							tpwlos_cansee = _formula
							};
						};
					}; 
				if (tpwlos_cansee > 0) exitwith  
					//IF VISIBLE ENEMY
					{ 
					//DISALLOW INDEPENDENT MOVEMENT AND TARGETTING FOR NEXT 5 SEC
					_unit disableai "AUTOTARGET";
					_unit disableai "MOVE";
					_unit setvariable ["tpwlos_fsmtime", diag_ticktime + 5]; 

					//HOW MANY DEGREES MUST UNIT TURN TO FACE ENEMY
					_dirto = ([_a, _b] call bis_fnc_dirto);  
					_unitdir = direction _unit;
					_delta = (_dirto - _unitdir);
					if (_delta <= -180) then 
						{
						_delta = 360 + _delta;
						};

					// ONLY RAPID TURN AND FIRE IF NOT ALREADY TURNING, AND IF MORE THAN 15 DEGREES FROM ENEMY
					_unit lookat _near; 
					if ((_turning == 0) && ((abs _delta) > 15)) then 
						{
						[_unit,_near,(floor _delta)] spawn tpwlos_fnc_turn;
						};	
					if ((combatMode _x) != "BLUE") then
						{			
						_unit lookat _near;
						_unit dotarget _near;
						_unit dofire _near;	
						};

					//SHOW DEBUG BALLS
					if (tpwlos_debug == 1) then 
						{
						_ball = _unit getvariable "tpwlos_losball";
						_ball hideobject false;
						}; 
					};
				} foreach _nearunits; 
			};
		}; 
	} foreach allunits;
};

//////////////////////////////////////
//CLEAN UP DEBUG BALLS FROM DEAD UNITS
//////////////////////////////////////
tpwlos_fnc_deadclean = 
{
_unit = _this select 0;
_ball = _unit getvariable "tpwlos_losball";
detach _ball; 
deleteVehicle _ball;  
};

//RUN IT
[] spawn tpwlos_fnc_sunangle;	
[tpwlos_fnc_mainloop,0.5] call cba_fnc_addperframehandler;

3 - Next I created a config.cpp file in the TPW_LOS directory

// TPW_LOS Version 1.03

class CfgPatches
{
class TPW_LOS
	{
		units[] = { };
		weapons[] = { };
		requiredAddons[] = {"CBA_Extended_EventHandlers"};
		version = "1.03";
		versionStr = "1.03";
		versionDesc="TPW LOS";
		versionAr[] = {1,0,3};
		author[] = {"tpw"};
	};
};

class Extended_PostInit_EventHandlers {
   class TPW_LOS {
       clientInit = "call compile preprocessFileLineNumbers '\TPW_LOS\init.sqf'";
   };
}; 

class TPW_LOS_Key_Setting
{
#include "\userconfig\TPW_LOS\TPW_LOS.hpp"
}; 

This is where CBA comes in. It allows you to start the whole shebang off from an init.sqf file, and allows you to specify to read in settings from userconfig.

4 - I created an init.sqf file in TPW_LOS

_hint = getnumber(configfile>> "tpw_los_key_setting" >> "tpw_los_hint");
_debug = getnumber(configfile>> "tpw_los_key_setting" >> "tpw_los_debug");
_max = getnumber(configfile>> "tpw_los_key_setting" >> "tpw_los_maxdist");
_min = getnumber(configfile>> "tpw_los_key_setting" >> "tpw_los_mindist");
_delay = getnumber(configfile>> "tpw_los_key_setting" >> "tpw_los_sleep");

nul = [_hint,_debug,_max,_min,_delay] execvm "\tpw_los\tpw_los.sqf";

This allowed me to read in the various variables from the TPW_LOS.hpp, and pass them to tpw_los.sqf at launch time

Once I had all these files in place it was just a matter of firing up binpbo, pointing it at TPW_LOS, and hitting "pack" to create the pbo.

I hope this helps you. Please PM if you need anything else.

  • Like 1

Share this post


Link to post
Share on other sites

Great post! The next question is, how to do it without requiring CBA. :) I'd tried this once before and only way I could get anything to work was by using CBA.

Share this post


Link to post
Share on other sites

Thanks a lot mate, that worked an absolute treat.

I appreciate the well structured response.

Share this post


Link to post
Share on other sites

Non-CBA way: http://community.bistudio.com/wiki/Functions_Library_(Arma_3)

Eg.

This will execute the script "\FOO_MyScriptAddon\scripts\fn_init.sqf" when the mission is started.

class CfgPatches
{
   class FOO_MyScriptAddon
   {
         units[] = {};
         weapons[] = {};
         requiredAddons[] = {};
   };
};

class CfgFunctions
{
class FOO
{
	class MyCategory
	{
		class MyInit
		{
			postInit=1;
               file = "\FOO_MyScriptAddon\scripts\fn_init.sqf";
               description = "script run after mission started and object initialization is complete";
		};
	};
};
};

Share this post


Link to post
Share on other sites

^^ nice call mrflay, nothing wrong with CBA, but i don't like dependencies even if this one would generaly be installed.

Share this post


Link to post
Share on other sites

Perfect mrflay, even better :).

Edited by Norco321

Share this post


Link to post
Share on other sites
Non-CBA way: http://community.bistudio.com/wiki/Functions_Library_(Arma_3)

Eg.

This will execute the script "\FOO_MyScriptAddon\scripts\fn_init.sqf" when the mission is started.

class CfgPatches
{
   class FOO_MyScriptAddon
   {
         units[] = {};
         weapons[] = {};
         requiredAddons[] = {};
   };
};

class CfgFunctions
{
class FOO
{
	class MyCategory
	{
		class MyInit
		{
			postInit=1;
               file = "\FOO_MyScriptAddon\scripts\fn_init.sqf";
               description = "script run after mission started and object initialization is complete";
		};
	};
};
};

Thanks very much for that. What's the simplest non CBA to read in variables from a config hpp?

Share this post


Link to post
Share on other sites
Thanks very much for that. What's the simplest non CBA to read in variables from a config hpp?

I'm pretty sure the way you do it in your example above also works without CBA.

Share this post


Link to post
Share on other sites

The only thing with using CfgFunctions does mean that other people will be able to use the function you've defined.

Is there a way to make it non-accessible?

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
Sign in to follow this  

×