From Bohemia Interactive Community
Revision as of 17:48, 8 November 2023 by Lou Montana (talk | contribs) (Text replacement - " +\[ +" to " [")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

a Cooperation by Wolfrug and Presents: Dynamic Sound AI (By Wolfrug and Sickboy)


  • Ready made scripts for Dynamic Sound AI that is easily modifiable by the end-user.
  • Your AI will shout curses at the enemy, tell you when they're reloading, throwing a grenade, engaging, when they're hurt, fleeing or when they've scored a big kill! And much more.
  • Works in both SP, client-side MP and server-side MP
  • Features English, Arab, Russian and Spanish voices by default
  • Can assign voices to all sides (BLUFOR, OPFOR, Independent, Civilian, SideEnemy)
  • Easily activated/deactived by mission makers, addon makers or server admins as required, using global variables and config entries (see below for more information)
  • Auto-initialization using XEH (dead link) (fully XEH compatible)
  • Now also converted to Arma 2! (everything below still applies, except XEH = CBA)
  • For the Arma 2 version only: requires CBA (Arma 2 version of XEH).


  • Place the .pbos that come with the package (RUG_DSAI.pbo, RUG_DSAIArab.pbo, RUG_DSAIENG.pbo, RUG_DSAIGen.pbo, RUG_DSAIRUS.pbo, RUG_DSAISPA.pbo) into a mod folder (for instance @RUG_DSAI/Addons) or into your main addons folder (not recommended!). This is enough to make the addon work by default.
  • Advanced: By default, BLUFOR will have English voices, Independent will have Arab voices, and OPFOR will have Spanish or Russian voices. If you want OPFOR to have Russian voices, simply remove RUG_DSAISPA.pbo from your addon folder (create a secondary folder for instance and put them there in the meantime). If you don't want the Independent Arab voices, remove the appropriate file (RUG_DSAIArab.pbo) and the scripts will assign another language to them (if available). Note that aside from scripting, two sides will not have the same language.
  • Default sides for the packs:
    RUG_DSAIENG (English) : BLUFOR/Independent
    RUG_DSAIArab (Arab) : Independent/OPFOR
    RUG_DSAISPA (Spanish) : OPFOR/Independent
  • NB: Only RUG_DSAI.pbo and RUG_DSAIGen.pbo are strictly necessary for the proper functioning of the mod, but if you have none of the language modules installed you won't get any sounds! When switching languages, always keep these two loaded. RUG_DSAIGen contains the "generic" non-language specific sounds, such as coughing and sneezing.
  1. It runs in SP Mode, if:
  2. Playing SP
  3. Playing MP as a Client
  4. Playing MP as a ServerClient

It runs in MP Synchronized mode, if:

  1. Dedicated Server and Clients are both running DSAI

This way, server owners that wish to require DSAI when playing on their servers, and have it in a synchronised way, they can install it on their server and voila.



There are various settings you (as a mission maker/server admin) can use to modify RUG DSAI without messing with the .pbo files themselves, or creating your own packs. These are all handled by global variables, which should be set during mission init (in the init.sqs or sqf). If none of these are sets, default values are used. The global variables are:

RUG_DSAI_TerminalDistance (default : 300)

- a number which tells the script at which range in meters from the player the voices should start functioning. Setting it to 0 will effectively pause all voices, and setting it to -1 will terminate all scripts (note that you can't restart the scripts easily after termination, although newly spawned units etc. will get the voices again).

RUG_DSAI_CycleTime (default : 10)

- a relative number in seconds which decides how quickly certain scripts cycle (such as the behavioural voices). A lower number will make the units speak more often with less time between utterings, a larger number will make them speak less often. Set as you see fit, but a number lower than 1 is not recommended (and will probably cause a tower-of-babel effect anyway).

RUG_DSAI_SIDES (array with 5 strings)

- This array can pre-determine what sides should have what language assigned to them. The order is as follows: [EAST, WEST, GUER, CIV, sideEnemy]. The string should correspond to the name of the language (which currently corresponds exactly to the name of the .pbo, minus the extension). An example setup could be : RUG_DSAI_SIDES = ["RUG_DSAIArab", "RUG_DSAIENG", "RUG_DSAISpa", "RUG_DSAISpa", "RUG_DSAIRus" ];

Note that you can also leave one of the strings as "UNDEFINED", which will make the script automatically define a language for that side, or put it as "NONE" which will make that side mute.

Finally, you can also define languages or disable languages for specific units.

Disable DSAI for given unit (should be leader of group):

_unit setVariable ["RUG_DSAI_OVERRIDE", 1];

Set specific language for unit (should be leader of group):

_unit setVariable ["RUG_DSAI_LANG", "RUG_DSAIENG"];


If you are an addon-maker, you can also define the language used by your units in their configs. Note that your units MUST BE XEH compatible notwithstanding, or the script-inits simply won't run! The lines you need to add in the unit's config are as follows:


Wolfrug 12.3.2008

Creating Custom Voices Pack

Creating a custom voices pack with RUG DSAI is fairly simple as long as you have a basic understanding of configs, pbo-packing and, of course, sound editing. The easiest way to learn is simply to open up one of the existing language packs and poke around : excepting the core RUG_DSAI.pbo file, they all follow the same pattern. Basically all the files in the .pbo need to be changed for an entirely new language pack, but the easiest way to do it is by editing an existing pack. Here's a step-by-step manual which describes the function and the needed changes within each file of the pack:


The addon.h is just a file that is included in the main config.cpp. You need to change the defines for RUG_ADDON and RUG_ADDON_STR to comply with yours : for instance RUG_DSAI_TAG_LANGUAGE. Make the string and the addon-name identical. The GENERAL_SPEECH_SOUND_LEVEL defines decide how far your sounds are heard - more about this later. By default, the first (no number) is for "normal" speech, the second is for shouted (i.e. combat taunts) sounds, and the third for very low sounds (coughs, hums, stealth etc.). RUG_WANTEDSIDE is an array which needs to contain two strings: "WEST", "EAST", "GUER" or "CIV" are the possible entries. The first entry ("WEST") is the first choice, the second ("GUER") the alternative if the first is already taken. Note that you can't force the scripts to pick your sound pack out of all installed - the only way to make your take precedence is by instructing the users not to have the other packs loaded.

#include "addon.h" class CfgPatches { class RUG_ADDON { units[] = {}; weapons[] = {}; requiredVersion = 1.08; requiredAddons[] = {"CAData", "CASounds", "Extended_Init_Eventhandlers", "RUG_DSAI"}; }; }; class RUG_DSAI { class Languages { class RUG_ADDON { wantedSide[] = RUG_WANTEDSIDE }; }; }; class CfgSounds { // RUG_DSAI sounds #include "RUG_DSAI\DSAI_BehaviourSounds.h" #include "RUG_DSAI\DSAI_FleeingSounds.h" #include "RUG_DSAI\DSAI_WoundedSounds.h" #include "RUG_DSAI\DSAI_OwnKilledSounds.h" #include "RUG_DSAI\DSAI_EnemyKilledSounds.h" #include "RUG_DSAI\DSAI_MiscSounds.h" #include "RUG_DSAI\DSAI_ContactSounds.h" #include "RUG_DSAI\DSAI_UnderFireSounds.h" //CAM DSAI Extension #include "RUG_DSAI\CAMSoundsUSBehaviour.h" #include "RUG_DSAI\CAMSoundsUSContact.h" #include "RUG_DSAI\CAMSoundsUSFleeing.h" };

This is the proper config.cpp, which is vital to the proper functioning of your pack. Notice the inclusion of the addon.h at the top. The only part you need to edit here is the cfgSounds section. Depending on how complete your soundpack is, you might want to edit out certain of the sound files used. For instance, you've only got sounds for behavioural modes and wounded - then you remove all the other sound types. The includes point towards .h files that reside in the appropriate folder in your addon - make sure these match up. If your pack is very small, you could also just put the sound definitions straight into the config here, but that is not advised since it makes for very ugly text.

// Define the addon, name must comply with cfgPatches and pbo name #include "addon.h" RUG_ADDON = [ call compile loadfile ("\"+RUG_ADDON_STR+"\RUG_DSAI\DSAI_Behaviour.sqf"), // RUG_DSAI_Behaviour - 0 call compile loadfile ("\"+RUG_ADDON_STR+"\RUG_DSAI\DSAI_Fleeing.sqf"), // RUG_DSAI_Fleeing - 1 call compile loadfile ("\"+RUG_ADDON_STR+"\RUG_DSAI\DSAI_Wounded.sqf"), // RUG_DSAI_Wounded - 2 call compile loadfile ("\"+RUG_ADDON_STR+"\RUG_DSAI\DSAI_OwnKilled.sqf"), // RUG_DSAI_OwnKilled - 3 call compile loadfile ("\"+RUG_ADDON_STR+"\RUG_DSAI\DSAI_EnemyKilled.sqf"), // RUG_DSAI_EnemyKilled - 4 call compile loadfile ("\"+RUG_ADDON_STR+"\RUG_DSAI\DSAI_Misc.sqf"), // RUG_DSAI_Misc - 5 call compile loadfile "\RUG_DSAIGen\RUG_DSAI\DSAI_Generic.sqf", // RUG_DSAI_Generic - 6 call compile loadfile ("\"+RUG_ADDON_STR+"\RUG_DSAI\DSAI_Contact.sqf"), // RUG_DSAI_Contact - 7 call compile loadfile ("\"+RUG_ADDON_STR+"\RUG_DSAI\DSAI_UnderFire.sqf") // RUG_DSAI_UnderFire - 8 ];

This is the file named RUG_DSAILANGUAGE_Init.sqf found in the main folder. Please name the script accordingly, substituting ENG/LANUAGE with your own pack's name. This script simply loads the various scripts used, and compiles the lists of sounds used. If you do not have sounds for for instance OwnKilled, simply give it an empty array instead of the call compile loadfile : []. Note that you should always call Generic (notice the different path of the call) since that loads the coughing and burping and other non-language specific sounds. If you want to create your own generic sounds for your language, simply edit the path accordingly. Example from russian config:

// Define the addon, name must comply with cfgPatches and pbo name #include "addon.h" RUG_ADDON = [ call compile loadfile ("\"+RUG_ADDON_STR+"\RUG_DSAI\DSAI_Behaviour.sqf"), // RUG_DSAI_Behaviour - 0 [], // RUG_DSAI_Fleeing - 1 [], // RUG_DSAI_Wounded - 2 [], // RUG_DSAI_OwnKilled - 3 [], // RUG_DSAI_EnemyKilled - 4 [], // RUG_DSAI_Misc - 5 call compile loadfile "\RUG_DSAIGen\RUG_DSAI\DSAI_Generic.sqf", // RUG_DSAI_Generic - 6 [], // RUG_DSAI_Contact - 7 [] // RUG_DSAI_UnderFire - 8 ];

Now that we've passed the initial configs, we come to the real meat and bones of the creation. As mentioned above, the various sound definitions for the config.cpp already exist in separate .h files. These can be found within the RUG_DSAI folder inside your addon. Each .h file simply defines the sounds - as mentioned, you can add them directly to the config.cpp as well, although it will look ugly. By dividing them like this, it is easier for you or someone else to edit them, as well as see what goes where. Example of the contents of one of the files :

// Idle Russian class rus_idle001 { name = ""; sound[] = {\RUG_DSAIRUS\Sounds\rus_idle\rus_idle001.wss, GENERAL_SPEECH_SOUND_LEVEL, 1.0}; titles[] = {}; }; class rus_idle002 { name = ""; sound[] = {\RUG_DSAIRUS\Sounds\rus_idle\rus_idle002.wss, GENERAL_SPEECH_SOUND_LEVEL, 1.0}; titles[] = {}; }; class rus_idle003 { name = ""; sound[] = {\RUG_DSAIRUS\Sounds\rus_idle\rus_idle003.wss, GENERAL_SPEECH_SOUND_LEVEL, 1.0}; titles[] = {}; };

As you can see, it is here that the GENERAL_SPEECH_SOUND_LEVEL definition comes into play - decide yourself what "loudness" you want each sound to have - or each set of sounds. Also note that when defining sounds, you need to include your addon name (in this case RUG_DSAIRUS) as the first "folder", otherwise it will fail to find them.

Each .h file also has a corresponding .sqf file (named the same, without the 'sounds' at the end) : these contain the class names of each sound used (i.e., what you'd use in game when doing something like Loon1 say "rus_idle003"), divided into named arrays. These arrays are then interpreted by the main scripts in RUG_DSAI, so it is important you place the sounds correctly. Example of contents of DSAI_Misc.sqf for RUG_DSAIENG:

comment "Miscellaneous sounds, such as reloading, grenade-throwing etc."; private ["_OutputArray", "_reloading", "_throwgrenade", "_fireweapon", "_formationLeader"]; _Outputarray = []; comment "Array select 0"; _reloading= [[ "RP_Misc_Univ_v43", "HO_Misc_Univ_v43", "BR_Misc_Univ_v43", "DA_Misc_Univ_v43", "DU_Misc_Univ_v43", "JE_Misc_Univ_v43", "MA_Misc_Univ_v43", "RU_Misc_Univ_v43", "RY_Misc_Univ_v43" ]]; _OutputArray = _OutputArray + _reloading; comment "Array select 1"; _throwgrenade= [[ "RP_Misc_Univ_v39", "RP_Misc_Univ_v02", "RP_Misc_Univ_v03", "HO_Misc_Univ_v39", "HO_Misc_Univ_v02", "HO_Misc_Univ_v03", "BR_Misc_Univ_v39", "BR_Misc_Univ_v02", "BR_Misc_Univ_v03", "DA_Misc_Univ_v39", "DA_Misc_Univ_v02", "DA_Misc_Univ_v03", "DU_Misc_Univ_v39", "DU_Misc_Univ_v02", "DU_Misc_Univ_v03", "JE_Misc_Univ_v39", "JE_Misc_Univ_v02", "JE_Misc_Univ_v03", "MA_Misc_Univ_v39", "MA_Misc_Univ_v02", "MA_Misc_Univ_v03", "RU_Misc_Univ_v39", "RU_Misc_Univ_v02", "RU_Misc_Univ_v03", "RY_Misc_Univ_v39", "RY_Misc_Univ_v02", "RY_Misc_Univ_v03" ]]; _OutputArray = _OutputArray + _throwgrenade; comment "Array select 2"; _fireweapon= [[ "RP_Misc_Univ_v13", "RP_Misc_Univ_v42", "RP_Misc_Univ_v48", "HO_Misc_Univ_v13", "HO_Misc_Univ_v42", "HO_Misc_Univ_v48", "BR_Misc_Univ_v13", "BR_Misc_Univ_v42", "BR_Misc_Univ_v48", "DA_Misc_Univ_v13", "DA_Misc_Univ_v42", "DA_Misc_Univ_v48", "DU_Misc_Univ_v13", "DU_Misc_Univ_v42", "DU_Misc_Univ_v48", "JE_Misc_Univ_v13", "JE_Misc_Univ_v42", "JE_Misc_Univ_v48", "MA_Misc_Univ_v13", "MA_Misc_Univ_v42", "MA_Misc_Univ_v48", "RU_Misc_Univ_v13", "RU_Misc_Univ_v42", "RU_Misc_Univ_v48", "RY_Misc_Univ_v13", "RY_Misc_Univ_v42", "RY_Misc_Univ_v48" ]]; _OutputArray = _OutputArray + _fireweapon; comment "Array select 3"; _formationLeader= [[ "RP_Misc_Univ_v30", "RP_Misc_Univ_v40", "HO_Misc_Univ_v30", "HO_Misc_Univ_v40", "BR_Misc_Univ_v30", "BR_Misc_Univ_v40", "DA_Misc_Univ_v30", "DA_Misc_Univ_v40", "DU_Misc_Univ_v30", "DU_Misc_Univ_v40", "JE_Misc_Univ_v30", "JE_Misc_Univ_v40", "MA_Misc_Univ_v30", "MA_Misc_Univ_v40", "RU_Misc_Univ_v30", "RU_Misc_Univ_v40", "RY_Misc_Univ_v30", "RY_Misc_Univ_v40" ]]; _OutputArray = _OutputArray + _formationLeader; _OutputArray

Simply place the appropriate names of the sounds (note that they have to be strings) inside the brackets - if you have no sounds for that particular type, simply leave it empty. Each .sqf file -should- have a comment on top which explains what the sounds inside it are meant for (NB: the DSAI_Wounded.sqf file by default has a _notwounded section, however that functionality is not implemented as of the current version, so leave empty). You do not and should not change neither the folder name nor the script/.h file names unless you know what you're doing!

Finally, the folder with the sounds themselves. You may use whatever or no folder-structure to keep track of them - I prefer to put them inside their own subclasses (i.e. Behaviour, OwnKilled, EnemyKilled, Wounded etc.) - as long as they correspond to the paths given in the RUG_DSAI\.h files! Remember the rules about adding sounds in ArmA and OFP : particularly you should make sure they're in mono, or the "says" will sound from everywhere. ;)

As mentioned, the best way to get cleanly away with creating a new soundpack is by copying the already existing ones. The most time-consuming job is creating the configs for the sounds, and copy-pasting all their names into the appropriate folders. But the end result might just be worth it!

Wolfrug, 11.3.2008


  • v.1.0 for Arma 2
    • First public release of Arma 2-compatible version
  • v 1.0 RC
    • First public release of new version
  • v0.2
    • Full optimization overhaul by Sickboy
  • v0.1 - Initial Version