Jump to content

Zenophon

Member
  • Content Count

    530
  • Joined

  • Last visited

  • Medals

Everything posted by Zenophon

  1. The setVariable command is just declaring the variable; you need to post the function that uses that data. You can use a simple getVariable check to make sure the value exists (which it should, as your setVariable statement looks fine). You also need to clarify how 'dbNumber' is determined and what type it is. The setVariable command is broadcasting the value. Is this because something is being done on the server and something else on the clients? Are other clients relying on this data? Also, check your database for missing values or inconsistencies. I am not sure what you mean by 'title' or where that would be displayed. Do you you mean subtitles in a cutscene? Finally, are you testing this in the editor or in multiplayer?
  2. Variables are abstracted such that they exist in 'namespaces'. They do not just point to a memory location that you can access. What we commonly call 'global variables' are variables existing in the mission namespace. There is a namespace for every object that exists in game and for your profile (that is how VAS saves data persistently). When you create a variable without setVariable, the engine defaults to the mission namespace or a local namespace. For example: Test = 3; // this is now global for the mission _test = 2; // this is local for the function executing Then, when you retrieve the value of a variable, the engine makes the same assumptions. For example: hint str Test; // prints 3 from anywhere hint str _test; // prints 2 only from the function By using setVariable, you can tell the engine which namespace exactly you want. You must then use getVariable to specify the correct namespace to retrieve from. For setVariable, making the value public (true as the last argument) does not change the namespace where it is stored, but updates the local namespace for all other machines on the network. Thus, another machine can request the same variable from the same namespace and get the same value. If you had put false there, the other machine would read an old value or no value at all. http://community.bistudio.com/wiki/setVariable http://community.bistudio.com/wiki/getVariable http://community.bistudio.com/wiki/missionNamespace So, in your example, the object called house1 now has a variable with value 1 stored at variable referenced by 'bought', and this change its namespace has been broadcast to all other machines. To get this value, you would use: house1 getVariable "bought"; // returns 1 The strength of this system is that you can now keep track of arbitrary values for all objects in an almost object-oriented way. Otherwise, you would have to create some sort of name-value pair data structure to store the 'bought' value for dozens of houses. The weakness of this system is that it obfuscates your data structure into invisible namespace pools. It is critical to have good documentation and standards to use set/get variable on large scale and have maintainable code.
  3. First, you need to continuously update the ticket count variables and check for the conditions. A trigger would work, but it will check very often (every frame if I remember correctly). I suggest a loop like this: private ["_eastTickets", "_westTickets"]; while {true} do { sleep 10; _eastTickets = [east] call BIS_fnc_respawnTickets; _westTickets = [west] call BIS_fnc_respawnTickets; if (_eastTickets == 0) exitWith { if (side player == east) then { "OpforLose" call BIS_fnc_endMission; } else { "BluforWin" call BIS_fnc_endMission; } }; if (_westTickets == 0) exitWith { if (side player == east) then { "OpforWin" call BIS_fnc_endMission; } else { "BluforLose" call BIS_fnc_endMission; } }; }; I changed the variables to local ones, as I would run this from the init.sqf as a separate thread. You could run it like this: 0 = [] spawn {<code here>}; I have also used BIS_fnc_endMission, so that you can set up better ending screens for the four possible outcomes. This code should run on all client machines and the server, as BIS_fnc_endMission has local effect. Depending on your init.sqf and mission, the clients should be running this code in synch, so the mission ends at the same time for everyone. http://community.bistudio.com/wiki/BIS_fnc_endMission http://community.bistudio.com/wiki/Debriefing Based upon the side of the client, a different ending will display. I do not know if there is any way to do this all in the editor, as I greatly prefer to use external functions. Also, I have not tested this in any way, so this is just a rough example for doing this. Alternatively, you could run everything on the server and force an ending on the clients using BIS_fnc_MP. This is more efficient, clearer, and easier to maintain, but requires more up-front work and understanding of client and server communication.
  4. Some of these should have radio dialog with them, especially those starting with 'command': http://community.bistudio.com/wiki/Category:Command_Group:_Unit_Control
  5. I've had this lying around for a while. You would need to set up a support menu action to call it if you want players to use it at will. Also, it does not work for groups with an AI leader because it does not order any units to exit or enter the helicopter. However, it is simple and effective, and it can use the same helicopter repeatedly without spawning and despawning aircraft. It also gets the helicopter to land exactly at the given spot and not several hundred meters away. Zen_HelicopterTransport = { /* Orders the helicopter to land at the first point and wait the given amount of time before flying to and landing at the second point, after which the function exits 1. Object, the helicopter 2. Position, the first place it will land 3. Position, the second place it will land 4. Scalar, the height the helicopter will fly in, in meters 5. Scalar, the time that the helicopter will wait for units to get in/out */ private ["_heli", "_landingPosition", "_endingPosition", "_heliHeight", "_waitTime", "_heliPilot", "_heliGroup"]; _heli = _this select 0; _landingPosition = _this select 1; _endingPosition = _this select 2; _heliHeight = _this select 3; _waitTime = _this select 4; _heliPilot = driver _heli; _heliGroup = group _heliPilot; (createVehicle ["Land_helipadempty_f", _landingPosition, [], 0, "NONE"]) setPosATL _landingPosition; (createVehicle ["Land_helipadempty_f", _endingPosition, [], 0, "NONE"]) setPosATL _endingPosition; _heliPilot move _landingPosition; _heliGroup setBehaviour "careless"; _heliGroup setCombatMode "yellow"; _heliGroup setSpeedMode "normal"; _heli flyInHeight _heliHeight; waitUntil { sleep 1; unitReady _heli; }; _heli land "land"; waitUntil { sleep 1; isTouchingGround _heli; }; _heli flyInHeight 0; sleep _waitTime; _heliPilot move _endingPosition; _heliGroup setBehaviour "careless"; _heliGroup setCombatMode "yellow"; _heliGroup setSpeedMode "normal"; _heli flyInHeight _heliHeight; waitUntil { sleep 1; unitReady _heli; }; _heli land "land"; }; For example, you could call it like this: 0 = [Heli, (getMarkerPos "mkInsertion"), (getMarkerPos "mkBase"), 40, 10] spawn Zen_HelicopterTransport; And the helicopter move from where ever it was flying at a height of 40m, land at the insertion point, wait 10 seconds, then return to base and land.
  6. Zenophon

    Placing Objects

    For the height of the table, you could use this to eliminate guesswork: http://community.bistudio.com/wiki/boundingBoxReal
  7. I think there is a misunderstanding regarding what was meant by container. I though it meant an ammo box, in which case the explosives would destroy it. If it means a large cargo container, then cobra4v320 is right.
  8. Zenophon

    Trouble with Scripts: Need Help

    If you have the names of the refugees, then why not assign the action to each of them? The action would only show up when it could do something instead of all the time, and you would not need to use nearestObjects. There are only 4 of them, so the action does not have to be generalized to anything the officer encounters (in that case adding it to the officer is correct). Regarding the script you posted, 'exit' at the bottom is unnecessary, and, if anything, it should be 'if (true) exitWith {};'. Also, you select an element from an array before testing how many elements there are. Have you printed out the array itself to see if it contains what you assume it does? To order an AI into a vehicle: {_x assignAsCargo _vehicle;} forEach _units; _units orderGetIn true; Where '_units' is any array of AI, and '_vehicle' is any vehicle. Alternatively, you could have the refugee join the officer's group and (I assume the officer is the player) have the player order the refugee into the vehicle. In the code cobra4v320 posted, it should be 'nearestObject' instead of 'nearestObjects', and the ', 2' should be removed.
  9. Creating an explosive charge as a vehicle used to detonate the charge instantly in ArmA 2, but it does not in ArmA 3. Try spawning some mortar or artillery shells, using 'createVehicle', such as these: r_60mm_he r_80mm_he Bo_Mk82_MI08 For a larger effect, spawn multiple shells in a for loop.
  10. You could try this: http://community.bistudio.com/wiki/land
  11. Zenophon

    Where is the Game?

    ArmA is primarily a sandbox, and user content is about 90% of the game. There are hundreds if not thousands of missions on the steam workshop, and you can create your own. How could you run out of content?
  12. Zenophon

    global AI setting

    You do not need a trigger, just put this in the init field of a unit: 0 = [0.2] spawn { while {true} do { sleep 10; { _x setSkill ["aimingAccuracy", (_this select 0)]; } forEach allUnits; }; } Change '0.2' to any number between 0 and 1. You only need to run this once; it will take care of all units you spawn later.
  13. First some general advice: use as few global variables as possible. They are difficult to keep track of, are not a clear and organized way of passing data to other functions, and cause bugs that are very hard to find. Your mission would be much better organized if functions used local variables and took arguments rather than accessing global variables. Obviously, global variables from the editor or debug variables are fine because generally no function will change them; they are just constants. Global variables become even more of an issue in multiplayer when determining which clients have what value in what variable. To deal with multiplayer issues, I have found that the most organized and effect design is have the server handle everything and only make the clients execute certain functions. This way a multiplayer mission is designed just like a singleplayer mission, but with some uses of BIS_fnc_MP. The mission should then behave exactly the same in the editor as in multiplayer. I have not spent hours studying your mission and testing. I have looked at the functions you posted and made some changes that follow my above advice. Do not expect my changes to work perfectly; they are just an example of how you could do things differently (and in my opinion better). The init: if (!isServer) then {waitUntil {!(isNull player)}}; waituntil {!isnil "bis_fnc_init"}; finishMissionInit; enableSaving [false, false]; fwd_debug = compileFinal preprocessFileLineNumbers "Scripts\fwd_debug.sqf"; fwd_randomstart_init = compileFinal preprocessFileLineNumbers "Scripts\fwd_randomstart_init.sqf"; fwd_randomtime_init = compileFinal preprocessFileLineNumbers "Scripts\fwd_randomtime_init.sqf"; fwd_randomstart = compileFinal preprocessFileLineNumbers "Scripts\fwd_randomstart.sqf"; fwd_randomtime = compileFinal preprocessFileLineNumbers "Scripts\fwd_randomtime.sqf"; fwd_wait = compileFinal preprocessFileLineNumbers "Scripts\fwd_wait.sqf"; fwd_OPFOR = compileFinal preprocessFileLineNumbers "Scripts\OPFOR\fwd_OPFOR.sqf"; fwd_objectives = compileFinal preprocessFileLineNumbers "Scripts\fwd_objectives.sqf"; call compileFinal preprocessFileLineNumbers "Scripts\fwd_revive.sqf"; call compileFinal preprocessFileLineNumbers "Scripts\shk_pos_init.sqf"; call compileFinal preprocessFileLineNumbers "Scripts\shk_taskmaster.sqf"; if !(isServer) exitWith {}; _missionSectorArray = ["Z1","Z2","Z3","Z4","Z5","Z6","Z7","Z8","Z9","Z10","Z11","Z12","Z13"]; _missionsector = _missionSectorArray select (floor (random count _missionSectorArray)); 0 = [1,1,0] call fwd_debug; 0 = [_missionsector] call fwd_randomstart_init; _weatherArray = [] call fwd_randomtime_init; 0 = [[_missionsector], "fwd_randomstart", true] spawn BIS_fnc_MP; 0 = [(_weatherArray select 0), "fwd_randomtime", true] spawn BIS_fnc_MP; 0 = [(_weatherArray select 1), "fwd_wait", true] spawn BIS_fnc_MP; 0 = [[_missionsector], "fwd_objectives", true] spawn BIS_fnc_MP; 0 = [] call fwd_OPFOR; The init that you posted is somewhat strange. There is no reason to wait for functions to be done if they do not have sleep commands in them. It would be easier to compile the functions and then use 'call'. Call also returns a value from the function, which I then use as the arguments of the next function. Call also waits for the function to finish executing. Few changes were made to 'fwd_debug', 'fwd_randomstart_init', 'fwd_OPFOR', and 'fwd_objectives'. I just made 'fwd_randomstart_init' and 'fwd_objectives' accept an argument and use local variables. I also moved the random selection of a marker from 'fwd_randomstart_init' to the init. fwd_randomtime_init: private ["_weather", "_rain", "_fog", "_windStr", "_windDir", "_time", "_randomWeather", "_randomWindStr", "_randomWindDir", "_randomFog", "_randomRain"]; switch (paramsArray select 0) do { case 1: {_weather = 0;_rain = 0;_fog = 0;_windStr = 1;_windDir = 1;}; case 2: {_weather = .40;_rain = .40;_fog= 0;_windStr = 2;_windDir = 2;}; case 3: {_weather = .70;_rain = .70;_fog = .05;_windStr= 3;_windDir = 3;}; case 4: {_weather = 1;_rain = 1;_fog = .05;_windStr = 4;_windDir = 4;}; case 5: {_weather = .75;_rain = .10;_fog = .30;_windStr = 1;_windDir = 1;}; case 6: {_weather = .85;_rain = .20;_fog = .50;_windStr= 0;_windDir = 0;}; case 7: { _randomWeather = 0.2 + ((round (random 5))/10); _randomWindStr = (round(random 60)) - 30; _randomWindDir = (round(random 60)) - 30; if ( _randomWeather > 0.7) then { _randomFog = 0.2 - ((round(random 2))/(10)); } else { _randomFog= 0.01; }; if ( _randomWeather > 0.5) then { _randomRain = _randomWeather +((round(random 2))/(10)); } else { _randomRain= 0; }; _weather = _randomWeather; _rain = _randomRain; _fog = _randomFog; _windStr = _randomWindStr; _windDir= _randomWindDir; }; }; switch (paramsArray select 1) do { case 1: {_time = 13;}; case 2: {_time = 17;}; case 3: {_time = 23;}; case 4: {_time = 30;}; case 5: {_time = 33;}; case 6: {_time = round(random 24);}; }; [[_time, _weather, _fog],[_rain, _windStr, _windDir]] In the weather function, there was simply no reason to declare so many global variables, some of which were never used again, when you could make the function return the values that it used to publicVariable. These next functions are meant to be executed on the client machines (or at least it looks like that to me). I have changed them to be executed by BIS_fnc_MP and accept arguments. fwd_randomstart: private ["_startPos"]; _startPos = getMarkerPos (_this select 0); player setPosATL getMarkerPos "S3"; player setDir ([player, _startPos] call BIS_fnc_dirTo)}; fwd_randomtime: private ["_time", "_weather", "_fog"]; _time = _this select 0; _weather = _this select 1; _fog = _this select 2; skipTime _time; 1 setOvercast _weather; 1 setFog _fog; fwd_wait: private ["_rain", "_windStr", "_windDir"]; _rain = _this select 0; _windStr = _this select 1; _windDir = _this select 2; skipTime 1; 1 setRain _rain; setWind [_windStr,_windDir,true]; Using BIS_fnc_MP ensures that all clients will execute these functions with arguments determined only by the server. The key is that only the server decided what numbers to use for the time and weather. The clients then just react to that information. There is no chance of them doing anything unexpected.
  14. For each unit, there is an optional called 'special'. I assume that that is set to 'in formation'. Set it to 'none', then arrange the units in the editor in a line. That will make them spawn exactly where they are placed, instead of automatically changing the points to form the correct formation. You must arrange them correctly in the editor, or they will rearrange themselves to form a line in the correct order.
  15. First, does the mission work without any changes? If yes, what changes did you make? If no, contact the author of the mission. Next, what symptoms of these errors are observable in game other than lag? What features of the mission fail to work, or are there only lag and desynch issues? The errors basically mean what they say, e.g. if a variable is undefined, have you defined it or given it as an argument properly? If an object cannot be found, does the object exist? When and how was it created? Is there any feature of the mission that depends directly on the number of players? Do those features fail? After downloading the linked mission, I see five .pbo's in the file, and none of them match the name of the mission that the .rpt file says it loaded. Exactly what mission are your running? In general, a lot of missions are poorly optimized and simply fail when forced to handle a large number of players. I do not really expect you to post an answer to all these questions, but these are standard questions to go through during debug. Without the code of the mission, it is impossible to solve these problems. You need to look through the mission and figure out how it is designed before you can fix anything.
  16. Each subclass that you define in params places a value in paramsArray. If only one param is defined, then paramsArray has only one element. '(paramsArray select 1)' is trying to access the second element. Array indexes start at 0. Also, the description.ext snippet that you posted has an extra } in it. I removed that and tested your code. It works fine using this: 10 setOvercast (paramsArray select 0); Regarding the unit condition, I cannot get that to work. It could be an issue with the order of initialization of the mission (paramsArray must be undefined when the game checks that condition).
  17. You could try the helicopter transport support modules. I do not know if they would work well in multiplayer, but they provide a simple system to tell the AI pilot where to go. Otherwise, you could try these: http://community.bistudio.com/wiki/remoteControl http://community.bistudio.com/wiki/switchCamera If that does not work, it would be possible to spawn an empty helicopter, let a player fly it, then spawn an AI in it to fly it back once all the players get out. This last option seems like the best one.
  18. It works fine for me using 'Sides of synch'd objects', but it does not work for 'All playable units'. Test this and see if it works: Place a player unit and a playable unit. It does not matter if they are grouped or not. Place a create task module. Set owner to synch'd objects only. In the description and title field enter some text, to confirm the task is working properly. Synch the task to both units. Preview the mission and switch between the units. They should both have the task. The tasks cannot be transferred to the new unit. Each unit receives a unique task, even if they appear to be the same and complete at the same time. The modules (rather the scripts behind them) organize the actual task names so that the tasks given to many units looks like the same task, but they are not. You must create the individual tasks for each object. This gets even more complex in multiplayer, where tasks are local data to the client where they were created. Luckily, modules and task systems deal with all this internally.
  19. You have a ; instead of && in the middle of the condition. A ; ends a statement and is not used in boolean conditions. This should work: (((p1 distance s1) <= 40) && (p1 in car1 && p2 in car1 && p3 in car1 && p4 in car1 && p5 in car1)) They must all be in the car, so you only need to check the distance to one of the objects.
  20. First, you need to determine if the player is dead, then execute the spawning function. You could use these: http://community.bistudio.com/wiki/addEventHandler http://community.bistudio.com/wiki/Arma_3:_Event_Handlers#Killed http://community.bistudio.com/wiki/createUnit This is an example: player addEventHandler ["killed", { 0 = _this spawn { _spawnPos = getPosATL (_this select 0); sleep (5 * 60); "o_soldier_f" createUnit [_spawnPos, (createGroup east)]; }; }]; The eventHandler will execute locally and 'createUnit' has global effect, so only one AI will spawn and all clients will see it. You would also need some function to save the player's loadout to give the AI. I recommend a forum/google search for that.
  21. A 'zero divisor' error is probably an out of bounds error in this case; you are trying to access an element of any array that does not exist. That means that the paramArray does not contain what you expect it to. Try printing out the value of the paramsArray to see what is really there. Also make sure you save the mission to reload any changes made to the description.ext. It is working for me in a very simple test mission with an extremely simple params class. Create a new mission in the editor, save it, and put this in the description.ext: class Params { class Test { title = "Test"; values[] = {0,1,2}; texts[] = {"0","1","2"}; default = 0; } } Then save and preview the mission. In the debug console, type this and click local exec: hint str paramsArray The game should print out: [0]
  22. When I said infinite loop I meant infinite loop. if (!isServer) exitwith {}; private ["_side", "_groupSquad1", "_leader"]; _side = createCenter EAST; _groupSquad1 = [getMarkerPos "Group", _side, ["o_soldier_TL_F", "O_soldier_AA_F", "o_soldier_AA_F", "o_soldier_AA_F"], [], [], [0.3, 0.6]] call BIS_fnc_spawnGroup; _leader = leader _groupSquad1; _leader move (getPosATL player); _groupSquad1 setCombatMode "RED"; _groupSquad1 setBehaviour "Aware"; 0 = _groupSquad1 spawn { while {true} do { sleep 5; if ((player distance (leader _this)) > 500) exitWith { { deleteVehicle _x; } forEach (units _this); }; }; }; while {true} do { sleep 5; if (({ alive _x} count (units _groupSquad1)) == 0) exitWith { { deleteVehicle _x; } forEach (units _groupsquad1); deleteGroup _groupSquad1; }; _leader = leader _groupSquad1; if ((unitReady _leader) && {(alive _leader)}) then { sleep 200; if (({ alive _x} count (units _groupSquad1)) != 0) then { _leader = leader _groupSquad1; _leader move (getPosATL player); _groupSquad1 setCombatMode "RED"; _groupSquad1 setBehaviour "Aware"; }; }; }; This is not tested and may require some changes, but it gives you a good idea on how to do this.
  23. I would recommend 'move'. It technically adds a waypoint but without any extra code. http://community.bistudio.com/wiki/move You also do not have to worry about what waypoint is current or what order they are in. You can give the command to a group or a group leader and his squad will follow. You can then set things like speed and combat mode with a few more commands, but you need to set them again every time move is used. This allows for infinite loops of move orders and only that last one given will be seem by the AI. Also, you can make each move position random very easily without editing a fixed number of waypoints that are being cycled through.
  24. Zenophon

    Array, set, do for...

    The 'exec' command is used with sqs syntax, which is deprecated. All functions should be written in sqf syntax, and 'exec' should not be used to call sqf scripts, only 'execVM'. The 'execVM' command compiles and executes the script as a new thread and passes in arguments. You can also use 'spawn' to execute a function as a new thread. A global variable is defined for all functions for the entire mission, unless it is removed with 'nil'. Any function can access and modify a global variable; it does not have to be passed as a argument. In multiplayer, a global variable is defined on all machines that was declared on, but the value does not sync between them nor is it transferred to other machines. You must use 'publicVariable' to do that.
  25. Zenophon

    Array, set, do for...

    If there are 5 elements in the array then 'Arr select 5' is out of bounds (oddly called 'error zero divisor' in ArmA). Array indexes start at 0 for the first element; count command starts at 1 for the first element, because the count of an empty array is 0. I would recommend this: http://community.bistudio.com/wiki/forEach There are only a few cases in which it is preferable to use a for loop to iterate on arrays. I get the vague sense that you are trying to order each object in the array based upon its distance from the player. Under that assumption, I would do it like this: /* Reorders the elements of the given array into a new array based upon their distance from a single center object Params: 1. Object, the center 2. Array of objects Return: Array of objects */ private ["_unit", "_givenArray", "_sortedArray", "_nextObj"]; _unit = _this select 0; _givenArray = _this select 1; _sortedArray = []; { _nextObj = _givenArray select 0; { if (((_x distance _unit) < (_nextObj distance _unit)) && {(!(_x in _sortedArray) && (alive _x))}) then {_nextObj = _x;}; } forEach _givenArray; if !(_nextObj in _sortedArray) then { _sortedArray set [(count _sortedArray), _nextObj]; }; } forEach _givenArray; _sortedArray I accounted for the objects being alive, as you seem to want that; that code should remove all dead objects from the array. This is tested and working with objects around the player in the editor, some of them dead. Just define it as a function with any name you want and call it like so: Arr = [player, Arr] call <FunctionName>;
×