Jump to content

Recommended Posts

CRATERS

Hi all,

This topic gave me an idea for scripting craters after an explosion.

I share this code you can add in an sqf or a trigger set to TRUE, server only should work.

 

I'll add a similar code in my "terrain & map interactive" MGI module.

 

Parameters:  none
 

MGI_hashAmmo = createHashMapFromarray (("true" configClasses (configFile / "cfgAmmo")) apply {[configName _x, getNumber (_x/"hit")]});

["MGI_craters", "onEachFrame", {
  _flyingProj = (8 allObjects 2);
  {
   if (isNil {_x getVariable "EH"} ) then {
    _x setVariable ["EH",
     _x addEventHandler ["explode", {
      params ["_proj","_pos","_vel"];
      _pos deleteAt 2;
      private _hit = MGI_hashAmmo get typeOf _proj;
      private _calc = log ((sqrt vectorMagnitude _vel*sqrt _hit) max 1.1);
      [_proj,_calc,_pos] spawn {
       params ["_proj","_calc","_pos"];
       sleep 0.1;
       private _crater = _pos nearestObject "#crater";
       if (!isNull _crater) then {
        _pos = getPosASL _crater;
        private _surface = (configFile /"cfgSurfaces"/ (surfaceType _pos splitString "#")#0);
        private _depress = getTerrainHeightASL _pos - ((_calc/(getNumber (_surface  / "surfaceFriction") max 1)*(getNumber (_surface /"dust") max 0.01 min 1)) min 3);
        _pos set [2,_depress];
        (setTerrainHeight [[_pos],TRUE]) remoteExec ["call",2];
       };
      };
 
     }]
    ];
   };
  } forEach _flyingProj;
}] call BIS_fnc_addStackedEventHandler;

 

This code creates craters after explosion on ground (where Arma craters are). So, not on vehicles, not on buildings.

Note1: Firing AP shell (armor piercing one) doesn't lead to explosion (Arma engine), so you need to fire HE shell for craters.

Note2: at this time, craters after crash (planes) don't fire the code. this code is for EXPLODING PROJECTILES only.

 

Feedback are welcome!

Have fun.

 

 

 

  • Like 7

Share this post


Link to post
Share on other sites

I keep telling people I saw this a long time ago in a video put out by someone before the game came out. It had "actual" craters but then they took it out before the game came out. It was part of the reason I bought the game. I keep wondering if that is not still inside the game but disabled and now modders have to code craters back in themselves.

 

Still thanks Pierre.

 

@H4wek, also, good work. Not gonna lie some people like scripts better cause the devs are constantly breaking mods with updates. They break scripts as well but not as often it seems. People can make adjustments to scripts more easily, not me but others LOL. Also many modders disappear after being around for a couple of years/months (not Pierre) and the mod is broke and no one can fix it. Must be hundreds of them over at the steam workshop that no longer work and will not be fixed.

Share this post


Link to post
Share on other sites

image.png

 

Nice but I also get this

image.png

 

I used the debug console to set off a GBU. Don't know if that could cause the error. Doesn't matter, it works. I put it in a trigger, the one I always use to make something work map wide.

 

Edit, okay I put a navel mine of the ground and shot it till it blew up, nice crater but it still does the error. I don't care but I know you do.

Share this post


Link to post
Share on other sites
1 hour ago, Alleged Accomplice said:

image.png

 

Nice but I also get this

image.png

 

I used the debug console to set off a GBU. Don't know if that could cause the error. Doesn't matter, it works. I put it in a trigger, the one I always use to make something work map wide.

 

Edit, okay I put a navel mine of the ground and shot it till it blew up, nice crater but it still does the error. I don't care but I know you do.

 

Yep, sorry for that. The first line creating the hashmap was not embedded as code! Corrected.

Share this post


Link to post
Share on other sites

You are right - this can be somewhere in  code prepared - and probably it will work much faster than this scripting method - anyway is strange that some of eventhandlers used for that was relased/added not log time ago like (explode or subammocreate) - when I observe some limitation in oposite to VBS  it seems to be made intentionally to A3 - game can't be so advanced like army sumulation - even in so simple things like waves or craters but it is my own observation only beacouse second explanation is worse - they are just  leazy - so many things better then carts could be done e and relase as DLC's but nobody care and want to do it tin BI - better is to ban modders who done it without blessing https://steamcommunity.com/sharedfiles/filedetails/?id=2879760031 .

If You want it as script I can put code here in mod it works together on few separate scripts (first on eventhandlers - and this part is most problematic when you want to add it in missions - during create vehicles) and second is for forming craters based on power of explosion (parameters like hit and indirecthit in arma are crazy so this calculation base on hit only) in some cases craters are too big due to those valuse used by mod makers for example in RHS one of russians bombs act like mini atomic charge and left by my calculator hole like 10kt head).

 

https://steamcommunity.com/sharedfiles/filedetails/?id=2962610738

 

here is script for ammo and fired weapons (eventhandlers) I name it '"Fn_AMS_mark.sqf" for example so for init of vehicle just put second part of script is for mark missiles or mortar shells so you can remove it for craters only, of course you should check if execvm is eunogh for MP use (i made it as mod due to MP problems and after many trys and checks it start to work on mp correctly so this version is for SP sure but I don't know how it act on MP use by this execvm method, if you change it to function calls it should work the same as in my mod).

 

this addEventHandler ["Fired", {[_this#0,_this#6,[['BombCore'],['RocketBase'],['MissileBase']]] execvm 'Fn_AMS_mark.sqf'}];

or 

this addEventHandler ["Fired", {[_this#0,_this#6,[['Sh_155mm_AMOS'],['Sh_155mm_AMOS_LG'],['Sh_155mm_AMOS_guided'],['Cluster_155mm_AMOS']]] execvm 'Fn_AMS_mark.sqf'}];

 

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

params ["_luncher","_firedammo",["_types",[]]];

//systemchat format ["ammo %1",typeof _firedammo];

if (_firedammo iskindof "BulletCore") exitWith {};
//if (count (attachedObjects _firedammo) > 0) exitWith {};
if (count _types == 0) exitWith {};
//missile = _firedammo;
    {
        if (_firedammo iskindof (_x#0)) exitwith {
            //systemchat format ["count %1, - %2" ,_x,count _x];
            //_firedammo call HWK_Fnc_AMS_shell_crater;
            _firedammo execvm "Fn_AMS_shell_crater.sqf";

            if (count _x > 1) then {
                            //systemchat "added drone";
                            private _crew = "E_UAV_AI";
                            switch (side _luncher) do
                            {
                                case WEST: {_crew = "B_UAV_AI";};
                                case EAST: {_crew = "O_UAV_AI";};
                                case independent: {_crew = "I_UAV_AI";};
                            };
                            _targetdrone = createVehicle [(_x#1), (getpos _firedammo), [], 0, "CAN_COLLIDE"];
                            _targetdrone attachto [_firedammo,[0,0,0]];
                            _unit = createAgent [_crew, (getPos _firedammo), [], 0, "CAN_COLLIDE"];_unit moveInAny _targetdrone;
                            _targetdrone setVehicleLock "LOCKED";

                            _firedammo addEventHandler ["Deleted", {params ["_projectile"];
                            {deletevehicle _x}foreach (attachedObjects _projectile);
                            }];
            };
        };
    }foreach _types;

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

script in "Fn_AMS_shell_crater.sqf" is like that:

-----------------------------------------------------------------------------------------------------------------------------------------

params ["_projectile"];

_projectile addEventHandler ["Explode", {params ["_projectile", "_pos", "_velocity"];_pos = ASLToAGL _pos;
    _hit = getnumber (configfile >> "CfgAmmo" >> (typeof _projectile) >> "Hit");
    _range = getnumber (configfile >> "CfgAmmo" >> (typeof _projectile) >> "indirectHitRange");
    //systemchat format["direct explosion pos %1/range %2 hit %3",_pos#2,_range,_hit];
    if  ((_hit != 0) && (_range != 0)) then {
        _diameter = 0.008*_hit;_deep = (((_diameter)^0.8)*0.5) - (_pos#2);
        //systemchat format["speed h = %1, hit = %2, range = %3, deep = %4, diameter = %5",(_velocity#2),_hit,_range,_deep,_diameter];
        if ((_deep > 0) && (_pos#2 < _range) && (_hit<10000)) then {[_pos,_deep,_diameter,(_diameter>=10),objnull] execvm "Fn_AMS_CRATER_GEN.sqf"};
        //if ((_hit>=10000) && (_pos#2 < _range)) then {[_pos,_hit] call HWK_Fnc_AMS_nuke_detonation};
        //[_pos,_deep,_diameter,(_range>=50),objnull] EXECVM "Fn_AMS_crater_gen.sqf";
    };
}];

_projectile addEventHandler ["SubmunitionCreated", {(_this#1) addEventHandler ["Explode", {params ["_projectile", "_pos", "_velocity"];_pos = ASLToAGL _pos;
    _hit = getnumber (configfile >> "CfgAmmo" >> (typeof _projectile) >> "Hit");
    _range = getnumber (configfile >> "CfgAmmo" >> (typeof _projectile) >> "indirectHitRange");
    //systemchat format["sub explosion pos %1/range %2 hit %3",_pos#2,_range,_hit];
    if  ((_hit != 0) && (_range != 0)) then {
        _diameter = 0.008*_hit;_deep = (((_diameter)^0.8)*0.5) - (_pos#2);
        //systemchat format["speed h = %1, hit = %2, range = %3, deep = %4, diameter = %5",(_velocity#2),_hit,_range,_deep,_diameter];
        if ((_deep > 0) && (_pos#2 < _range) && (_hit<10000)) then {[_pos,_deep,_diameter,(_diameter>=10),objnull] execvm "Fn_AMS_CRATER_GEN.sqf"};
       // if ((_hit>=10000) && (_pos#2 < _range)) then {[_pos,_hit] call HWK_Fnc_AMS_nuke_detonation};
        //[_pos,_deep,_diameter,(_range>=50),objnull] EXECVM "Fn_AMS_crater_gen.sqf";
    };
}]}];

---------------------------------------------------------------------------------------------------------------------------------------------

there is also call to script for nuclear charges but for that is not need so i remove it.

----------------------------------------------------------------------------------------------------------------------------------------------------

last script is for make craters "Fn_AMS_CRATER_GEN.sqf" -> I use method not just only for make hole with specified deep but in bigger sizes (where it is possibile to observe difference by grid resolution)  it make real shaped crater with surrounding up area and shape inside is rounded not straight, also is used texture object for color crater hole but resize command cause on bigger size of it some laggs (it depend on terrain grid and size of final crater - texture is apllying to sufrace and higher grid take more data to calc). in last version I make even depend deep of crater to kind of terrin, softer/harder but not all sufraces are possibile to discover, also script destroy trees  in surround area)  - so you can reduce this part to simplyfy.

-------------------------------------------------------------------------------------------------------------------------------------------------------

// [getpos player, 2, 5,false,objnull] execVM "Fn_AMS_crater_gen.sqf";

    params ["_vector","_velocity","_veh"];

private _position = getpos _veh;
private _crater = objnull;
private _cutter = objnull;
private _cellsize = (getTerrainInfo#2);
private _vehsize = ((boundingBoxReal _veh)#2);

    _terrainRES = 75; //(Mpascalas/m2)

/*    _other = ["#Default","#floor","#floor_exp","#floor_inside","#floor_in_exp","#GdtCliff","#GdtDead","#GdtField","#GdtKLCobblestone","#GdtKlField","#GdtKlSoil","#GdtKlStubble","#GdtMarsh","#GdtRubble","#GdtSeabed","#GdtSeabedExp","#GdtSoil","#GdtStony","#GdtStonyThistle","#GdtStratisSeabed","#GdtStratisSeabedCluttered","#GdtThorn","#GdtVolcano","#GdtVRsurface01","#GdtWeed","#GdtWildField","#grid","#grid_exp","#lino","#lino_exp","#lino_in_exp","#mat_in_exp","#parquet","#planks","#planks_exp","#planks_inside","#planks_in_exp","#roof_tiles_exp","#rubble","#rubble_exp",,"#softwood_in_exp","#steel","#steel_exp","#stones","#stones_exp","#straw_exp","#SurfIntWood","#surfint_wood","#SurfRoofTin","#SurfWater","#SurfWood","#surf_rooftiles","#surf_rooftin","#surf_wood","#TEST_SurfNormal","#tiling","#trash","#trash_exp","#Water","#woodenFloor"];
    if ((surfaceType _position) in _other) then {_terrainRES = selectrandom[1,5,10,25,40,50,100]};*/

    _grass = ["#GdtGrassDry","#GdtGrassGreen","#GdtGrassLong","#GdtGrassShort","#GdtGrassTall","#GdtGrassWild","#GdtKLGrass1","#GdtKLGrass2","#GdtStratisDryGrass","#GdtStratisGreenGrass","#SAGrass"];
    if ((surfaceType _position) in _grass) then {_terrainRES = 50};
    _road = ["#dirtrunway","#GdtKLDirt","#GdtRedDirt","#GdtDirt","#GdtStratisDirt","#SurfRoadDirt","#SurfRoadDirt_Enoch","#SurfRoadDirt_exp","#SurfTrailDirt_Enoch","#SurfTrailDirt_exp","#surf_roaddirt"];
    if ((surfaceType _position) in _road) then {_terrainRES = 100};
    _asphalt = ["#GdtAsphalt","#road","#road_exp","#SurfRoadTarmac","#SurfRoadTarmac1_Enoch","#SurfRoadTarmac2_Enoch","#SurfRoadTarmac3_Enoch","#SurfRoadTarmac_exp","#GdtKlTarmac","#GdtKlWeatheredTarmac","#surf_roadtarmac","#SAAsfalt"];
    if ((surfaceType _position) in _asphalt) then {_terrainRES = 100};
    _rocks = ["#GdtRock","#GdtStratisRocky","#GdtStratisThistles","#SurfIntTiles","#surfint_tiles","#SurfRoofTiles","#SAMountain"];
    if ((surfaceType _position) in _rocks) then {_terrainRES = 300};
    _concrete = ["#concrete","#concrete_exp","#concrete_hall","#concrete_hall_exp","#concrete_inside","#concrete_in_exp","#concrete_out","#GdtConcrete","#GdtStratisConcrete","#SurfIntConcrete","#surfint_concrete","#SurfRoadConcrete","#SurfRoadConcrete_exp","#surf_roadconcrete"];
    if ((surfaceType _position) in _concrete) then {_terrainRES = 200};
    _metal = ["#metalPlate","#metalPlatePressed_exp","#metalPlate_exp","#metalPlate_in_exp","#SurfIntMetal","#surfint_metal","#SurfMetal","#surf_metal","#wavyMetal","#wavyMetal_exp"];
    if ((surfaceType _position) in _metal) then {_terrainRES = 1000};
    _sand = ["#sand","#sand_exp","#GdtBeach","#GdtStratisBeach","#GdtVolcanoBeach","#GdtMud","#mud","#mud_exp","#GdtDesert","#SASand","#SAWater"];
    if ((surfaceType _position) in _sand) then {_terrainRES = 10};
    _forest = ["#GdtForest","#GdtForestMalden","#GdtForestPine","#GdtStratisForestPine","#GdtKLForestCon","#GdtKLForestDec"];
    if ((surfaceType _position) in _forest) then {_terrainRES = 30};

    _planar = (2.5*(_vehsize));
    _sizeFRONT = 0.04 * _planar; //m2
    _vectorIMP = abs(((_vector#0)#1)*((_vector#1)#2)*_planar);
    _deep = (((getmass _veh) * (abs _velocity))/ (_vectorIMP * (_terrainRES*1000)));
    if (_deep > (_vehsize/2)) then {_deep = _vehsize/2};

    _diameter = _vehsize*0.75;
    _area = _diameter *1.5;

    //d = (C * m^(2/3) * v^(1/3)) / (ρ * A)   Murray'a
    //d = (2 * E) / (ρ * A * v^2)             Halfa
    //d = (m * v^2) / (m * 9.81)

    //hint format ["deep1 %1\n, vector %2\n, sufrace %3\n",_deep,_velocity,_terrainRES];

if ((count _position >= 2) && (_cellsize < (2*_diameter))) then {

    {deletevehicle _x}foreach (((_position nearEntities _area) - allplayers) + (_position nearobjects _area) - [_veh]);
    {_x hideObjectGlobal true}foreach (nearestTerrainObjects [_position, [], _area]);
    {_x setdamage 1}foreach ((nearestTerrainObjects [_position, [], _area*1.25]) - (nearestTerrainObjects [_position, [], _area]));

    _cutter = createvehicle ["Land_ClutterCutter_large_F", _position, [], 0, "CAN_COLLIDE"];_cutter setvectorup [0,0,1];//_cutter setdir (getdir _veh);

    if ((_deep > 0) && (isnil "ams_craters_off")) then {

    _points = [];
    _baseH = (getTerrainHeight _position);
    _points pushback [_position#0,_position#1,_baseH - _deep];

        private _edge = 0.3;
        private _edgemax = _diameter * 1.5;
        private _H = (_baseH - _deep);
        private _Csize = (getTerrainInfo#2)/1.5;
        private _Rstep = (getTerrainInfo#2)/1.5;

        private _diameterX = _Rstep;
        private _HSTEP = ((_diameterX/_diameter) bezierInterpolation [[0,0,-_deep],[0,_diameter*(1-_edge),-_deep*0.7],[0,_diameter,0]])#2;
        private _agle = 0;
        private _step = 360/((2 * 3.14 * _diameterX) / _Csize);

        while {_diameterX < _edgemax} do
            {
                while {_agle < 360} do
                {
                    private _point = [];

                    if (_diameterX <= _diameter) then {
                        /*_p1 = _position getPos [_diameter*(1-_edge), _agle];
                        _p2 = _position getPos [_diameter, _agle];
                        _point = ((_diameterX/_diameter) bezierInterpolation [_points#0,[_p1#0,_p1#1,_H],[_p2#0,_p2#1,_baseH]]);*/
                        _pos = _position getPos [_diameterX, _agle];
                        _point = [_pos#0,_pos#1, (_baseH + _HSTEP)];
                    };

                    if (_diameterX > _diameter) then {
                        _p0 = _position getPos [_diameter, _agle];
                        _p1 = _position getPos [_diameter*(1+_edge), _agle];
                        _p2 = _position getPos [_edgemax, _agle];
                        _point = (((_diameterX - _diameter)/(_edgemax - _diameter)) bezierInterpolation [[_p0#0,_p0#1,_baseH],[_p1#0,_p1#1,(getTerrainHeight _p1) + (_deep/2)],[_p2#0,_p2#1,(getTerrainHeight _p2)]]);
                        //systemchat format ["%1/%2-%3-%4",_point,_p0,_p1,_p2];sleep 0.1;
                    };

                    _points pushback _point;
                    _agle = _agle + _step;
                };

                    _agle = 0;
                    _diameterX = (_diameterX + _Rstep);
                    _step = 360/((2 * 3.14 * _diameterX) / _Csize);

                if (_diameterX <= _diameter) then {_HSTEP = ((_diameterX/_diameter) bezierInterpolation [[0,0,-_deep],[0,_diameter*(1-_edge),-_deep*0.7],[0,_diameter,0]])#2};
            };
        [[_points,true]] remoteExecCall ["setTerrainHeight",2];
    };

    if (isnil "ams_textures_off") then {
        _model = "\hwk_ams\data\hwk_krater.p3d";_scale = (_diameter/2);
        _crater = createSimpleObject [_model, AGLtoASL _position,false];
        if ((_scale > 1) && (_scale < 20))  then {_crater setObjectScale _scale};
    };
};

    _veh attachto [_cutter,[0,0,0]];_veh setVectorDirAndUp _vector;
    if (surfaceIsWater _position) then {_veh attachto [_cutter,[0,0,-((GETPOSATL _veh)#2)]]}else {_veh attachto [_cutter,[0,0,-((getpos _veh)#2)]]};sleep 0.1;deletevehicle _cutter;

        //systemchat "clearing";
        _mutiply = 4;_area = _diameter*_mutiply;
        {
            _x setdamage (((_area/((_x distance _position)+0.01))/2)-0.33);
        }foreach (nearestTerrainObjects [_position, ["TREE", "SMALL TREE", "BUSH", "FOREST","FOREST BORDER", "FOREST TRIANGLE", "FOREST SQUARE"], _area]);

    [[_crater,_cutter],_diameter] spawn {sleep (3600*(_this#1)*0.1); {deletevehicle _x} foreach (_this#0)};

------------------------------------------------------------------------------------------------------------------------------------------------

Share this post


Link to post
Share on other sites
4 hours ago, pierremgi said:

 

Yep, sorry for that. The first line creating the hashmap was not embedded as code! Corrected.

I may try to add some debris to it, likely will fail, but some rocks in the hole and outside it would be nice

Share this post


Link to post
Share on other sites

Tried it, no error but craters are way smaller especially on hardened surface.

 

Edit: Okay it seems to take projectile into account now. I can make a fairly deep crater by firing an HE tank shell into the ground but the GBU blown up the debug doesn't do much anymore.

Share this post


Link to post
Share on other sites
18 hours ago, Alleged Accomplice said:

Tried it, no error but craters are way smaller especially on hardened surface.

 

Edit: Okay it seems to take projectile into account now. I can make a fairly deep crater by firing an HE tank shell into the ground but the GBU blown up the debug doesn't do much anymore.

Yes, there are some parameters to be tweaked:
I took "Hit" coef for ammo, and velocity,

and "surfaceFriction" and "dust" for the terrain below crater.

Not ideal but there is not so much parameter for impact or penetration.

 

Note: All craters (I mean even caused by AIs fire) are treated. I tested with mortars, bombs, missiles... 

On the other hand, the crater holes are just depression on one point, not shaped ones like @h4wek did.

 

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

×