Jump to content

ZaellixA

Member
  • Content Count

    277
  • Joined

  • Last visited

  • Medals

Community Reputation

288 Excellent

6 Followers

About ZaellixA

  • Rank
    Staff Sergeant

Contact Methods

  • Skype
    zaellixa
  • Biography
    Born in Ioannina, Greece. Grew up all around Greece and now still trying to settle somewhere. Sound engineering pays for most of my expenses.
  • Steam url id
    zaellixa
  • Linkedin
    achilleskappis
  • Reddit
    ZaellixA

Profile Information

  • Gender
    Male
  • Location
    Greece
  • Interests
    Acoustics, Digital Signal Processing, ArmA 3, Programming, Research, Computational Acoustics, Wave-Fields, 3D Audio, Electroacoustics

Recent Profile Visitors

1104 profile views
  1. Well, if you intend to count how many times a function is called you could do that inside the function. For example you could do something like that in your function /* * You function sqf */ // Get parameters params[...]; // Do your thing do stuff do stuff do stuff // Increase the count private _funcCallNum = missionNamespace getVariable[JKB_funcCallNum, 0]; // Get current value missionNamespace setVariable["JKB_funcCallNum", _funcCallNum + 1]; // Set value to current + 1 // Return value _retVal; In this way you will increment the count every time the function is called. You could also add a variable and a test to check whether counting is to be used. This could possibly look like /* * You function sqf */ // Get parameters params[..., ["_countCalls", false, [false]]]; // Do your thing do stuff do stuff do stuff // Increase the count if(_countCalls) then { private _funcCallNum = missionNamespace getVariable[JKB_funcCallNum, 0]; // Get current value missionNamespace setVariable["JKB_funcCallNum", _funcCallNum + 1]; // Set value to current + 1 }; // Return value _retVal; The only caveat here is that you should keep in mind that you have to explicitly declare you would like to count the call. This means that possibly some calls could be count while some others not. Additionally, you could set the default value of the parameter to true to make sure you will get a count if you forget to set it (if you don't need it you could just ignore the variable JKB_funcCallNum). This could be done like params[..., ["_countCalls", true, [true]]]; where the ellipses declares all other parameters you may get inside the function. As an extra let me say that you could one-line the parameter set command like missionNamespace setVariable["JKB_funcCallNum", (missionNamespace getVariable[JKB_funcCallNum, 0]) + 1]; // Set value to current + 1 So, if you follow this approach all you have to do in order to wait for the function count to reach the value you want is waitUntil { // It's good practice to use sleep to save some CPU cycles uiSleep 5; (missionNamespace getVariable["JKB_funcCallNum", 0]) == 5; }; Of course I used 5 here as the desirable count but you could either hardcode the one you want or even get it from a variable/parameter/mission parameter etc. One thing you could possibly do differently is to use a global variable instead of storing and retrieving a variable from the mission namespace (or another namespace... I used mission namespace for the sake of demonstration). This wouldn't really change the code much. You would just discard the getVariable commands and just increase by one the global variable. Please note that this is not tested code and should be treated with caution. Let us know if this works out for you or if you have any questions.
  2. ZaellixA

    My wits have ended

    I may be completely wrong and way far away from the right track, but are you sure that all the clients have access to the .sqfs that are called?
  3. ZaellixA

    \m/

    Also, it will be beneficial in many ways if you use more descriptive post titles.
  4. I believe this is a nice (most hopefully working) solution. I believe you could also use pushBackUnique in order to avoid some checks as to whether this vehicle is in the array or not. The adapted solution could look like the following (adapting das attorney's solution) // Declare and initialise empty vehicles array _vehs = []; // Go through the units in the group of the player { // Add the vehicle to the array if not already in there _vehs pushBackUnique (vehicle _x); } forEach units group player; // Present some results hint format ["%1", _vehs]; {player sideChat format ["%1", typeOf _x]} forEach _vehs; Please note that this code snippet is not tested and should be treated with caution. Nevertheless I hope it does help somehow one way or another.
  5. On top of what stanhope said (which is correct as far as I am aware) I believe that the forEach loop you have at the beginning of the script will leave in the _player variable only the name of the last playable or switchable unit. I am not sure this is what you want to achieve. If this is the case please just skip this post, otherwise you may want to consider placing the switch statement inside the forEach loop.
  6. ZaellixA

    Help with While loop

    Hehehe, I was just typing when beno_83au posted. So, yes, in the way you have coded the while loop will run forever (or at least until the mission is over) and the deleteGroups will never be reached. One alternative to that would be to place these two commands inside the while loop. You will most probably want to add some check to see whether they have been deleted before trying to delete them. This could possibly look like (replicating your code and adapting) while {true} do { waitUntil {({alive _x} count units A == 0) or ({alive _x} count units B == 0)}; hint "boom yah"; A forgetTarget player1; // A & B are group names B forgetTarget player1; sleep 3; // Check if group A is empty if (!(isNull A)) then { if (({alive _x} count units A) == 0) then {deleteGroup A}; }; // Check if group A is empty if (!(isNull B)) then { if (({alive _x} count units B) == 0) then {deleteGroup B}; }; }; This is a quite naive implementation though (and I think that you have mistyped the condition for the second deleteGroup command). In this way, the condition to checked in order to delete or not a group is doubly checked. Once in the waitUntil and once at the last two checks before deleting the groups. Additionally, the hint you have inside the while loop will run every 3 seconds, which I believe is not what you really want to achieve. I am not sure exactly what you are trying to achieve so I am not sure I can provide a good solution to your problem. What you have coded will run forever even if the two groups are emptied. I don't think that this is a good way to go about it. beno_83au has provided a valid and rather nice solution to your problem.
  7. Hey there, I know this is a quite old post but a solution must have already been found (like the last post from HartOfARMA mentions). Just wanted to present a quick alternative to simply count how many units died from each side. You could just create a variable or add one to the mission namespace. I will present the mission namespace case which may be a wee bit more generic. So you can count the units that are alive on each at the beginning of the game and then again at the end of the game and get the difference as the dead units. This could possibly look something like /* * This part goes in a file like the init.sqf or initServer.sqf */ // Set the variables with the units of each side missionNamespace setVariable ["bluUnits", west countSide allUnits]; missionNamespace setVariable ["opUnits", east countSide allUnits]; missionNamespace setVariable ["indUnits", independent countSide allUnits]; missionNamespace setVariable ["civUnits", civilian countSide allUnits]; /* * This part must be executed at the end of the mission */ // Calculate the BluFor dead units private _bluDead = missionNamespace getVariable "bluUnits"; _bluDead = _bluDead - (west countSide allUnits); // Calculate the OpFor dead units private _opDead = missionNamespace getVariable "opUnits"; _opDead = _opDead - (east countSide allUnits); // Calculate the IndFor dead units private _indDead = missionNamespace getVariable "indUnits"; _indDead = _indDead - (independent countSide allUnits); // Calculate the civilian dead units private _civDead = missionNamespace getVariable "civUnits"; _civDead = _civDead - (civilian countSide allUnits); // Post the results systemChat ("BluFor casaulties: " + (str _bluDead)); systemChat ("OpFor casaulties: " + (str _opDead)); systemChat ("IndFor casaulties: " + (str _indDead)); systemChat ("Civilian casaulties: " + (str _civDead)); Of course, you could choose another way to log or show the results, this is just a short example. Additionally, you may choose to one-line the dead calculation like private _bluDead = (missionNamespace getVariable "bluUnits") - (west countSide allUnits); And, of course you could also use the event handler approach in conjunction with the setVariable command (most probably set a variable in the mission namespace like in the example above). This could possibly look something like (I also present a way to add the event handler to all the units) /* * This should be executed in a script like init.sqf or initServer.sqf */ // Set the namespace variables missionNamespace setVariable ["bluDead", 0]; missionNamespace setVariable ["opDead", 0]; missionNamespace setVariable ["indDead", 0]; missionNamespace setVariable ["civDead", 0]; // Add the event handler to all the units on the map allUnits apply { // Add the event handler _x addEventHandler ["Killed", { params["_unit"]; // Get the unit that was killed // Check the side of the dead unit switch (side _unit) do { // Increase the dead counter of the appropriate side case west: {missionNamespace setVariable ["bluDead", (missionNamespace getVariable "bluDead") + 1]}; case east: {missionNamespace setVariable ["opDead", (missionNamespace getVariable "opDead") + 1]}; case independent: {missionNamespace setVariable ["indDead", (missionNamespace getVariable "indDead") + 1]}; case civilian: {missionNamespace setVariable ["civDead", (missionNamespace getVariable "civDead") + 1]}; }; }]; }; /* * This part should be executed at the mission end */ // Post the results systemChat ("BluFor casaulties: " + (str (missionNamespace getVariable "bluDead"))); systemChat ("OpFor casaulties: " + (str (missionNamespace getVariable "opDead"))); systemChat ("IndFor casaulties: " + (str (missionNamespace getVariable "indDead"))); systemChat ("Civilian casaulties: " + (str (missionNamespace getVariable "civDead"))); Finally, you could have used a local or global variable instead of setting one in the mission namespace. This could save you some long one-lined commands and make the code look a wee bit cleaner. The result should be the same though. Please note that the presented code is not tested and should be treated with caution. I do hope that wit will, at least, provide some help to people who will have a look at this post in the future.
  8. ZaellixA

    Making AI forget you

    Well, if you have a look at the event handler you'll see that they area passed to the code that will be run when the event handler is called automatically. So, all you have to do is get them as input parameters (this is what the params["_unit", "_killer"] line does). Just to clarify a bit, the event handler is first "added" to the unit (in the example above this refers to the unit as it is given in the init field) and is called when the unit is killed (there are other event handlers which are called on different "events" - this is what the first variable "Killed" defines). The code provided as the second argument will be executed when the handler is called/triggered (please don't confuse the event handler "triggering" with the triggers used in the game, they are not the same thing). For each event handler some variables are passed as input parameters to the code. In the "Killed" event handler the first two are the unit that got killed (_unit) and the unit that did the killing (_killer). So, this is how you get the units. So, the first line in the code (to be executed when the event handler is called) is to get the two units. In the next (and last) line I get the units in the group of the unit that was killed (in an array) and apply a command (forgetTarget) to each one of them. So, when the unit is killed, all the units in its group will "forget" the unit that did the killing (of course if the unit is visible, they will immediately go back to "know" about it). As I said, this is a wee bit naive and rather unrealistic. Nevertheless, I believe that this a quite good way to tackle the issue. In order to add the event handler to all units you could possibly do something like (the example is for all units that are not in the player's side) // Get all units that are not in the player's side private _enemies = allUnits select {!((side _x) isEqualTo playerSide)}; // Add the event handler to all the units _enemies apply { _x addEventHandler["Killed", { // Get the unit and the killer params["_unit", "_killer"]; // Run the forgetTarget command for all units of the group (units (group _unit)) apply {_x forgetTarget _killer}; }]; }; Now, of course you could code a more complex behavior than that. One example could be to make all units on the side of the killed unit to forget about the killer. In this way you could make all units on the side of the killed unit to forget about the unit that did the killing. In this way, all units (or someone in their group) that do not have line of sight to the killer will lose track of him, with the units (and their groups) that can see the killer keep up the fight (they will forget and immediately go back to "know" again). This could be done like (presenting only the code for the event handler) _x addEventHandler["Killed", { // Get the unit and the killer params["_unit", "_killer"]; // Get the units on the side of the dead unit private _enemies = allUnits select {(side _x) isEqualTo (side _unit)}; // Run the forgetTarget command for all units of the group _enemies apply {_x forgetTarget _killer}; }]; So, in this way, you apply the forgetTarget command to all the units on the side of the dead unit. One more thing you could possibly do is to apply the forgetTarget command to all the units on the side of the dead unit for all units in the group of the killer (I believe that if a unit knows about another unit it automatically knows about all the units in the spotted unit's group. I am not 100% sure about it though so you will have to check that). This could look like (again I only present the code for the event handler) _x addEventHandler["Killed", { // Get the unit and the killer params["_unit", "_killer"]; // Get the units on the side of the dead unit private _enemies = allUnits select {(side _x) isEqualTo (side _unit)}; // Run the forgetTarget command for all units of the group _enemies apply { // Get the current enemy in a variable to be used in the forEach below private _curEnemy = _x; // Get the units in the killer's group private _killGroup = units (group _killer); // Apply the forget target for each unit in killer's group { // Forget the unit of killer's group _curEnemy forgetTarget _x; } forEach _killGroup; }; }]; Please note that all code presented here is not tested and should be treated with caution. I hope that this provides some help and clarification somehow. Do not hesitate to ask again if this does not solve your problem, help or you may need further assistance.
  9. ZaellixA

    Making AI forget you

    Well, you can use an event handler for this purpose and try to make the whole group forget about the target. If they can still see the target, they will revert back to the previous (most probably aggressive) behavior. This could possibly look like (inside each unit's init field) // Add the event handler to the unit this addEventHandler["Killed", { // Get the unit and the killer params["_unit", "_killer"]; // Run the forgetTarget command for all units of the group (units (group _unit)) apply {_x forgetTarget _killer}; }]; Now, this is very naive and there's a lot of room for improvement. One major issue here is that the units will "forget" about the killer but not the rest of the units they "know about". So, this may serve as a base for further development, depending on your needs. If this is intended for solo ("lone wolf") SP missions it will most probably work quite OK for isolated groups. Otherwise, further refinement is needed. Furthermore, if you intend to use it with all AI units you should most probably find a better way (than the init field) to add the event handler to the units. Please note that the provided code snippet is not tested and it should be treated with caution. Feel free to ask for more help and/or clarifications if the need arises.
  10. I believe that if you know that the intel is spawned one metre high from the floor (where the unit is standing) you could set the appropriate value in the command that translates the coordinates from the model to the world. This should look something like (copying and adapting R3vo's code) // R3vo's code // intel setPos (officer modelToWorld [1,-1,0]); // Adapted code intel setPos (officer modelToWorld [1,-1,-1]); // Get the coordinates 1 metre below the centre of the unit (last entry which should correspond to z-coordinate) Please make sure to test that and adapt the values accordingly... One more alternative, which may or may not be an overburden to your needs could look like (trying to be very explanatory in the snippet below, feel free to adapt) // Get the position relative to the terrain private _unitPos = getPosATL officer; // Set the position relative to the terrain with z-coordinate equal to zero (this means on the terrain) intel setPosATL [(_unitPos select 0) + 1, (_unitPos select 1) - 1, 0]; This should help a wee bit with clipping if not very close to boundaries and most probably (if I haven't made any mistakes........, which doesn't happen very often 😂) will save you from habving to "measure" (or approximate) the height at which the intel is spawned (to counter it). Please note that both of the above snippets are untested and should be treated with caution. I hope this helped somehow, or at least provided some more insight into a possibly better solution.
  11. Hey S3LMON. I am not sure I understand what exactly scope means in the context of your question, but I will assume that you mean "area". You could possibly try to run a script like the following /* I will use the position of the player here and a distance of * 500 metres from the player to delete everything but the buildings */ // Get all objects in a sphere with radius 500 and centre the player private _allObjs = (getPos player) nearObjects 500; // Get the buildings in the same sphere private _allBlds = (getPos player) nearObjects ["House", 500]; // Subtract the buildings from all the objects _allObjs = _allObjs - _allBlds; // Delete the objects _allObjs apply {deleteVehicle _x;}; Please keep in mind that the above code snippet is not tested and should be treated with caution. One more thing to note is that with the command deleteVehicle you can only delete objects inserted in the mission editor and during the game's progress. I hope this helps somehow, but please don't hesitate to ask for more help if this is not a solution to your problem or a new issue arises.
  12. I guess you are right... I, myself have typed forEach (and many more) like foreach many times... Not sure why I had this feeling that .sqf is case sensitive... I strongly apologize for that... Thanks a lot.
  13. Hhhmmm, not sure I understand... isn't a string like "_zombArr = [zomb0, zomb1, zomb2, ...];" supposed to be callable code? I can see the difference in your code (_arr apply {call compile _x};) compared to mine but I am wondering why mine wouldn't compile into something "meaningful". Could you please shed some light on it, as I seem to lack intuition on here... 😟
  14. Hey there SOVIET_IDIOT. A couple of simple solutions would be to do something like (copying code provided by UnDeaD.) // Get all the objects whose name starts with "zomb" private _objArr = (allMissionObjects "All") select {(vehicleVarName _x) find "zomb" == 0}; // Disable simulation to all of them _objArr apply {_x enableSimulation false}; Alternatively, you could create the array and then go through it like // Initialise array private _objArr = "_zombArr = ["; // Create an array as a string (go from 0 to 99) for[{private _i = 0}, {_i < 100}, {_i = _i + 1}] do { // Append the "zombX" string, // where X is equal to the current value of _i _zombArr = _zombArr + ("zomb" + (str _i)); // Add a comma if(_i < 99) then { _zombArr = _zombArr + ", "; }; }; // Add the closing bracket and the assignment to a variable _zombArr = _zombArr + "];"; // Now you can compile and call that to be an array call (compile _zombArr); // Next step, disable simulation to all those objects _zombArr apply {_x enableSimulation false;}; This may seem a wee bit of an overburden compared to the first method, but this may be a wee bit more flexible if you would like to do something to only a "subset" of all the "zombie range". You could also change the "zomb" part and the initial or the range to get the objects for resulting in an array starting at "zomb2" and going up to "zomb5" for example. This morning I happened to create such a function which you could use as-is, adapt, or keep parts of it without having to credit or reference anyone (it is licenced under The Unlicenced). I will copy it here for your convenience (see below). Additionally, you could have a look at this (recent) post in these ArmA 3 forums. Please note that I haven't personally tested any of those solutions (not even the function I provide in the end) so you should treat them with caution and of course test before use. Hope this helps somehow and if you need further assistance please don't hesitate to ask.
  15. Not sure this was the problem but you used a capital "x" instead of a small one. Since .sqf is case sensitive _X is different than _x, where the latter is the magic variable that corresponds to each object and (most probably) _X is undefined. Nevertheless, gc8 have you a nice solution to your problem. Alternatively, you could create the array in the way I showed you above and compile once in the end (instead of compiling the variable in each iteration) and use either a forEach to go through it, or apply to disable the simulation to all elements. Not sure which approach is faster since in gc8's solution you have to compile each time but in the one I suggest here you will have to go through the array twice (one time to create it and one to disable simulation).
×