wvorster 10 Posted April 23, 2015 Hi Guys, This is working great , however we are having a small issue - the toxic gas grenade doesn't affect anyone that's elevated. e.g. get into a bunker or a house that's not flat on the ground , throw grenade and it does nothing .. Step out onto the ground and throw the toxic grenade and it works perfect. What can I change or try to make sure this works at the correct elevation ? // @file Name: toxic_gas.sqf // @file Author: Mokey // @file Description: Toxic Gas addon for A3W // @web: http://www.fractured-gaming.com // @Special Thanks to Pitoucc _gasMask = ["H_CrewHelmetHeli_B","H_CrewHelmetHeli_O","H_CrewHelmetHeli_I"]; // define the gasmasks here setNoGasStatus={ "dynamicBlur" ppEffectEnable true; // enables ppeffect "dynamicBlur" ppEffectAdjust [0]; // enables normal vision "dynamicBlur" ppEffectCommit 10; // time it takes to go back to normal vision resetCamShake; // resets the shake 20 fadeSound 1; // fades the sound back to normal }; setGasStatus = { "dynamicBlur" ppEffectEnable true; // enables ppeffect "dynamicBlur" ppEffectAdjust [15]; // intensity of blur "dynamicBlur" ppEffectCommit 5; // time till vision is fully blurred enableCamShake true; // enables camera shake addCamShake [10, 45, 10]; // sets shakevalues // player setFatigue 0; // sets the fatigue to 100% 5 fadeSound 0.1; // fades the sound to 10% in 5 seconds }; gasDamage = { player setDamage (damage player + 0.12); //damage per tick sleep 2.5; // Timer damage is assigned "seconds" }; While{true} do{ call setNoGasStatus; waituntil{ ((nearestObject [getPosATL player, "SmokeShell"]) distance player < 10) // detects if player is within grenade radius && (getPosATL (nearestObject [getPosATL player, "SmokeShell"]) select 2 < 0.5) }; if !(headgear player in _gasMask) then { call setGasStatus; call gasDamage; } else {}; }; Share this post Link to post Share on other sites
EagleByte 40 Posted April 23, 2015 I believe this line of code is the culprit. It is getting the height of the player and sees if they are less than 0.5 m above the ground. So depending on how high the smoke effect is, you can edit that number to say 1 or 1.5? (getPosATL (nearestObject [getPosATL player, "SmokeShell"]) select 2 < 0.5) Share this post Link to post Share on other sites
Larrow 2827 Posted April 23, 2015 This line (getPosATL (nearestObject [getPosATL player, "SmokeShell"]) select 2 < 0.5) is detecting whether the smoke shells height above the terrain is smaller than 0.5 meters. If you are throwing the shell in a building then it may well come to rest above 0.5 meters from the terrain. A better solution maybe to check that the grenade is at rest rather than its height. waituntil{ _smokeShell = nearestObject [getPosATL player, "SmokeShell"]; _smokeShell distance player < 10 && velocity _smokeShell isEqualTo [ 0, 0, 0 ] }; if the smoke shells velocity is at [0,0,0] then you know the shell is at rest and spewing toxic gas from its position. Also due to the way you have it set up once a smoke is near and the player has no mask you call your distortion and damage effects but then loop straight back around to then cancel the effects, which if the smoke is still near starts all over again. Its not a very efficient loop. Share this post Link to post Share on other sites
austin_medic 109 Posted April 23, 2015 This line (getPosATL (nearestObject [getPosATL player, "SmokeShell"]) select 2 < 0.5) is detecting whether the smoke shells height above the terrain is smaller than 0.5 meters. If you are throwing the shell in a building then it may well come to rest above 0.5 meters from the terrain. A better solution maybe to check that the grenade is at rest rather than its height. waituntil{ _smokeShell = nearestObject [getPosATL player, "SmokeShell"]; _smokeShell distance player < 10 && velocity _smokeShell isEqualTo [ 0, 0, 0 ] }; if the smoke shells velocity is at [0,0,0] then you know the shell is at rest and spewing toxic gas from its position. Also due to the way you have it set up once a smoke is near and the player has no mask you call your distortion and damage effects but then loop straight back around to then cancel the effects, which if the smoke is still near starts all over again. Its not a very efficient loop. On occasion the velocity calcuations go nuts with PhysX bugging out (object typically starts 'warping' into the floor then pops back up) thus its velocity might not ever equal zero... Share this post Link to post Share on other sites
Larrow 2827 Posted April 23, 2015 (edited) On occasion the velocity calcuations go nuts with PhysX bugging out (object typically starts 'warping' into the floor then pops back up) thus its velocity might not ever equal zero... true.How about checking the magnitude of the velocity instead? Just need to find a decent threshold for it to be below! Something like.... //Gas masks gasMasks = ["H_CrewHelmetHeli_B","H_CrewHelmetHeli_O","H_CrewHelmetHeli_I"]; //Are we near a smoke shell fnc_smokeNear = { //Are we not wearing a gas mask if ( !( headgear player in gasMasks ) ) then { //Get nearest smoke shell _smokeShell = nearestObject [ getPosATL player, "SmokeShell" ]; //If there is a smoke shell if !( isNull _smokeShell ) then { //Is it at rest AND within 10 meters of the player ( will need to experiment with magnitude threshold ) vectorMagnitudeSqr velocity _smokeShell <= 0.5 && { _smokeShell distance player < 10 } //There is no smoke shell }else{ //Return false false }; //If we are wearing a gas mask }else{ //Return false as it does not matter if a smoke shell is near false }; }; //We are in smoke fnc_inSmoke = { //Set a variable on the player so we know we are in smoke player setVariable [ "inSmoke", true ]; //Do effect "dynamicBlur" ppEffectEnable true; "dynamicBlur" ppEffectAdjust [15]; "dynamicBlur" ppEffectCommit 5; enableCamShake true; addCamShake [10, 45, 10]; 5 fadeSound 0.1; //While were in smoke while { [] call fnc_smokeNear } do { //Damage the player player setDamage (damage player + 0.12); sleep 2.5; }; //We are no longer in smoke [] call fnc_smokeClear; }; //We are not in smoke fnc_smokeClear = { //Reset the player variable player setVariable [ "inSmoke", false ]; //Clear effects "dynamicBlur" ppEffectEnable true; "dynamicBlur" ppEffectAdjust [0]; "dynamicBlur" ppEffectCommit 10; resetCamShake; 20 fadeSound 1; }; //Check each frame if we are near smoke //If we are not already flagged as in smoke AND near a smoke shell //Start gas effects smokeNearSEHID = [ "smokeNear", "onEachFrame", { if ( !( player getVariable [ "inSmoke", false ] ) && { [] call fnc_smokeNear } ) then { _inSmokeThread = [] spawn fnc_inSmoke; }; }] call BIS_fnc_addStackedEventHandler; Edited April 23, 2015 by Larrow added extra clause for null smokeShell Share this post Link to post Share on other sites
wvorster 10 Posted April 24, 2015 Superb help guys !! the check for velocity is a good start ! I will look at the magnitude as well !! Thank you so much !! Just a question - this will not affect loot that has spawned into buildings and dropped on the floor I assume - I'd need to test this. Share this post Link to post Share on other sites
Jigsor 176 Posted September 7, 2015 (edited) Sorry to dig up old thread, but this is relevant to this post.As usual Larrow's code is solid.I've Taken Larrow's modified code and enhanced upon it adding 3d choking sounds and functionality for server to apply damage to AI from player's gas grenade.Also added list of qualified gas grenades in addition to lists of gas masks.Tested working with Vanilla. Untested, but should also work with Hidden Identity Pack mod gas masks.In my implementation and test on dedi. these script block parts are divided up into multiple scripts ex; for sake of performance I've call compiled global variables and functions in other scripts and divided per locality.For simplicity all together as one script would look like this. // Global Variables // Choke_Sounds = [ "A3\Sounds_f\characters\human-sfx\Person0\P0_choke_02.wss", "A3\Sounds_f\characters\human-sfx\Person0\P0_choke_03.wss", "A3\Sounds_f\characters\human-sfx\Person0\P0_choke_04.wss", "A3\Sounds_f\characters\human-sfx\Person1\P1_choke_04.wss", "A3\Sounds_f\characters\human-sfx\Person2\P2_choke_04.wss", "A3\Sounds_f\characters\human-sfx\Person2\P2_choke_05.wss", "A3\Sounds_f\characters\human-sfx\Person3\P3_choke_02.wss", "A3\Sounds_f\characters\human-sfx\P06\Soundbreathinjured_Max_2.wss", "A3\Sounds_f\characters\human-sfx\P05\Soundbreathinjured_Max_5.wss" ]; // All Headgear to use as Gasmask INS_gasMaskH = ["H_CrewHelmetHeli_B","H_CrewHelmetHeli_O","H_CrewHelmetHeli_I","H_PilotHelmetFighter_B","H_PilotHelmetFighter_O","H_PilotHelmetFighter_I"]; // All Goggles to use as Gasmask INS_gasMaskG = ["Mask_M50","Mask_M40","Mask_M40_OD"];//Hidden Identity Pack V.3 // All Grenades to use as Poisonous Gas Grenades INS_Gas_Grenades = ["SmokeShellYellow","G_40mm_SmokeYellow"];//fired ammo // Server // if (isServer) then { // Server functions // editorAI_GasMask = { private "_ai"; _ai = allUnits; {if (isPlayer _x) then {_ai =_ai - [_x];};} count _ai; { removeHeadgear _x; if (side _x isEqualTo resistance) then {_x addHeadgear "H_CrewHelmetHeli_I";}; if (side _x isEqualTo east) then {_x addHeadgear "H_CrewHelmetHeli_O";}; If (side _x isEqualTo west) then {_x addHeadgear "H_CrewHelmetHeli_B";}; } count _ai; }; GAS_smoke_AIdamage = { //Apply damage to AIs not wearing gas mask and play choking sounds in 3d private ["_currPos","_aiArray","_maxtype","_sound","_odd"]; _currPos = _this; _maxtype = (count Choke_Sounds); _odd = 1; // loop time based on approximate life time of smoke grenade (22 seconds) for '_i' from 1 to 10 do { _aiArray = _currPos nearEntities [["CAManBase"],15]; {if ((isPlayer _x) || (headgear _x in INS_gasMaskH) || (goggles _x in INS_gasMaskG)) then {_aiArray = _aiArray - [_x];};} count _aiArray; { if (_aiArray isEqualTo []) exitWith {}; if (_odd isEqualTo 1) then { _sound = Choke_Sounds select (floor random _maxtype); playsound3d [_sound, _x, false, getPosasl _x, 14,1,40]; _odd = 2; }else{ _odd = 1; }; uiSleep (random 0.21); _x setDamage (damage _x + 0.13); } count _aiArray; uiSleep 2.1; }; ToxicGasLoc = []; }; // Give Gas masks to all existing AI [] spawn editorAI_GasMask; // Server eventHandler fires when player's fired gas grenade comes to rest. Variable "ToxicGasLoc" is position of rested grenade. ToxicGasLoc = [];publicVariable "ToxicGasLoc"; "ToxicGasLoc" addPublicVariableEventHandler {(_this select 1) spawn GAS_smoke_AIdamage}; // Client // if (!isDedicated && hasInterface) then { // Client functions // GAS_smokeNear = { //Are we near a smoke shell //Are we not wearing a gas mask if ((headgear player in INS_gasMaskH) || {(goggles player in INS_gasMaskG)}) then { //We are wearing a gas mask. Return false as it does not matter if a smoke shell is near false } else { _smokeShell = player nearObjects ["GrenadeHand", 30]; { if !(typeOf _x in INS_Gas_Grenades) then {_smokeShell = _smokeShell - [_x];}; } count _smokeShell; //If there is a smoke shell if !(isNull (_smokeShell select 0)) then { //Is it at rest AND within 10 meters of the player ( will need to experiment with magnitude threshold ) vectorMagnitudeSqr velocity (_smokeShell select 0) <= 0.5 && { (_smokeShell select 0) distance player < 10 } } else { //There is no smoke shell so Return false false }; }; }; GAS_inSmoke = { // We are in smoke player setVariable ["inSmoke",true]; private ["_maxtype","_sound"]; _maxtype = (count Choke_Sounds); //Do effects "dynamicBlur" ppEffectEnable true; "dynamicBlur" ppEffectAdjust [12]; "dynamicBlur" ppEffectCommit 5; enableCamShake true; addCamShake [10, 45, 10]; 5 fadeSound 0.1; //While were in smoke while { alive player && not captive player && [] call GAS_smokeNear } do { _sound = Choke_Sounds select (floor random _maxtype); playsound3d [_sound, player, false, getPosasl player, 10,1,30]; player setDamage (damage player + 0.12); //if(round(random(1)) isEqualTo 0) then {hint "You Should Wear a Gas Mask";}; uiSleep 2.8123; }; //We are no longer in smoke [] call GAS_smokeClear; }; GAS_smokeClear = { player setVariable ["inSmoke",false]; //Clear effects "dynamicBlur" ppEffectEnable true; "dynamicBlur" ppEffectAdjust [0]; "dynamicBlur" ppEffectCommit 10; resetCamShake; 20 fadeSound 1; }; waitUntil {!isNull player && player == player}; // player eventhandlers // // debug //player addEventHandler ["Fired", {hint format ["Fired ammo object: %1", (_this select 4)]; diag_log text format ["Fired ammo object: %1", (_this select 4)];}];}; // broadcast to server position of newly fired gas grenade once resting player addEventHandler ["Fired", { if ((_this select 4) in INS_Gas_Grenades) then { (_this select 6) spawn { private "_grenadePos"; waitUntil { vectorMagnitudeSqr velocity _this <= 0.5}; _grenadePos = getPosATL _this; sleep 0.2; ToxicGasLoc = _grenadePos; publicVariableServer "ToxicGasLoc"; }; }; }]; //Check each frame if we are near smoke //If we are not already flagged as in smoke AND near a smoke shell //Start gas effects smokeNearSEHID = [ "smokeNear", "onEachFrame", { if (!(player getVariable ["inSmoke",false]) && { [] call GAS_smokeNear }) then { _inSmokeThread = [] spawn GAS_inSmoke; }; }] call BIS_fnc_addStackedEventHandler; }; Edited September 13, 2015 by jigsor Share this post Link to post Share on other sites
Jigsor 176 Posted September 8, 2015 Nevermind, solution found. All working as intended now. Corrections made to code above. Share this post Link to post Share on other sites
Jigsor 176 Posted September 11, 2015 (edited) Hmm, code is working fine and does not give errors while playing, but when playing on dedi, after playing some and then going back to lobby, while in lobby I get this error: false }else{ _smokeShell = player nearObjects ["GrenadeHand", 30]; { if !(> 20:56:23 Error position: <nearObjects ["GrenadeHand", 30]; { if !(> 20:56:23 Error 0 elements provided, 3 expected 20:56:23 Bad conversion: array I suspect the oneachframe is still running and trying to reference player object/player position even though it does not exist at that point.Really just nit picking here I guess because all is working, but I just don't like to see script errors ever. I don't have much scripting experience with oneachframe stacked eventhandler.Is this behaviour typical or is there a way to fix without adding much more overhead? Script above reuploaded. I forgot to add some changes. Just tested again Issue from this post still remains. Edited September 11, 2015 by jigsor Share this post Link to post Share on other sites
Jigsor 176 Posted September 22, 2015 Looks like it is an acknowledged problem of stacked event handlers that need to run for duration of mission will not be removed by engine if player goes back to lobby and rejoins. This is a major design flaw. We need your help folks. Please up vote fix here. Share this post Link to post Share on other sites