Jump to content

unequivocal

Member
  • Content Count

    1
  • Joined

  • Last visited

  • Medals

Posts posted by unequivocal


  1. I've written a dynamic convoy ambush mission generator as part of a larger dynamic mission system (to be released soon).

    When activated the script does the following:

    • Creates a well-armed convoy
    • Creates task for player to intercept/destroy
    • Shows start/end markers for convoy
    • Detects mission success/failure

    I use the SecOp module a lot, but the ambush missions are usually disappointments. Often they are buggy and fail on start. Also the ambush task shows you the entire path of the convoy which seems too unrealistic - my system makes you figure out where to set up your ambush, and it's possible the convoy will go a different route.

    This mission add-on is simply a single stand-alone script file. You can add it to any mission, and activate simply by including the file in your init.sqf and calling a single method to start the mission. Only one convoy ambush mission is permitted at a time.

    Add to Init.sqf:

    #include "convoyMission.sqf";

    Call from code or trigger to activate mission:

    call fSpawnEnemyConvoy;

    I've also created a demo mission, so you can try it out without creating your own mission.

    As this is my first post, I can't post the links, but here they are in plaintext:

    PBO Mission here: misuse.org/downloads/ConvoyMission.Chernarus.pbo

    Script file here: misuse.org/downloads/convoyMission.sqf

    Instructions for adding this into your own missions are in the script file itself. Please post here with questions/feedback.

    I plan to add some additional features, like different kind of ambush missions (assassination, destroy specific guarded vehicle, etc). Feedback welcome on ideas for ambush missions.

    Also, the entire script is here inside this spoiler if you want to access that way:

    // Most basic way to use this script:
    
    // Start with a blank map in editor
    // Save map with a name (e.g. ConvoyMission)
    // Go to that folder with a text editor (e.g., C:\Users\[Your user name]\Documents\ArmA 2\Missions\[mission name].[map])
    // Create empty "init.sqf" file there
    // Add single line in init.sqf: #include "convoyMission.sqf"
    // Save this file to that folder
    // Place "Ambient Combat Module" on map & sync to player
    // Place Trigger on map:
    //   Activation: Radio Alpha
    //   Activation: Repeatedly
    //   Type: None
    //   On Act: call fSpawnEnemyConvoy;
    //   Axis a: 0
    //   Axis b: 0
    // Save map. You can try it out with preview function in editor.
    // To activate a convoy mission, press 0-0-1 within game
    
    HQ = [West,"HQ"];
    
    fHQMsg = {
     [_this select 0] spawn {  
       msg = _this select 0;
       sleep 4;
       HQ sideChat msg;
     };
    };
    
    // returns the direction (tangent) of a road segement based on connected road segment
    // will return the direction closest to parameter "preferred angle"
    // param1: road to get angle of
    // param2: preferred angle -- return reciprocal angle closest to this angle
    // returns integer heading of road
    fGetRoadHeading = {
     _road = _this select 0;
     _preferredAngle = _this select 1;
     _roadConnectedTo = roadsConnectedTo _road;
     _connectedRoad = _roadConnectedTo select 0;
     _angle = [_road, _connectedRoad] call BIS_fnc_DirTo;
     _preferredMin = ((_preferredAngle-90)+360) mod 360;
     _preferredMax = ((_preferredAngle+90)+360) mod 360;
     // if the angle is "facing the wrong way" to our preferred angle
     // return the reciprocal angle
     if ((_angle > _preferredMin) && (_angle < _preferredMax)) then {
       _angle = _angle;
     }
     else {
       _angle = (_angle + 180) mod 360;
     };
     _angle;
    };
    
    // returns a data structure
    //   a array of position points based on starting position/angle
    // returns the point on closest road to each point on the line 
    // each point is distance/angle further along line from previous point
    // param1: startPoint
    // param2: angle
    // param3: distance
    // param4: number of points
    fGetArrayOfPointsOnRoadFromAngle = {
     _startPos = _this select 0;
     _angle = _this select 1;
     _distance = _this select 2;
     _num = _this select 3;
     _startRoad = [_startPos, 0, 1000] call fGetNearestRoad;
     _startPos = getPos _startRoad;
     _retVal = [];
     _lVal = _startPos;
     // create _num entries of road positions
     for "_x" from 1 to _num do {
       _lVal = [_lVal, _angle, _distance] call fGetPointFromAngle;
       // find empty position nearest this location, if any
       _altVal = _lVal findEmptyPosition [0,10];
       if (count _altVal > 0) then {
         _lVal = _altVal;
       };
       _retVal = _retVal + [_lVal];
       _nextRoad = [_lVal, 0, 1000] call fGetNearestRoad;
       _lVal = getPos _nextRoad;
     };
     _retVal;
    };
    
    
    // returns a array of points based on starting position/angle
    // each point is distance/angle further along line from previous point
    // param1: startPoint
    // param2: angle
    // param3: distance
    // param4: number of points
    fGetArrayOfPointsFromAngle = {
     _startPos = _this select 0;
     _angle = _this select 1;
     _distance = _this select 2;
     _num = _this select 3;
     _retVal = [];
     _lVal = _startPos;
     for "_x" from 1 to _num do {
       _lVal = [_lVal, _angle, _distance] call fGetPointFromAngle;
       _retVal = _retVal + [_lVal];
     };
     _retVal;
    };
    
    // returns a point that is specified distance/angle from point
    // param1: startPos
    // param2: angle
    // param3: distance
    fGetPointFromAngle = {
     _startPos = _this select 0;
     _startX = _startPos select 0;
     _startY = _startPos select 1;
     _startZ = _startPos select 2;
     _angle = _this select 1;
     _distance = _this select 2;
     _endX = _startX + (_distance * sin _angle);
     _endY = _startY + (_distance * cos _angle);
     [_endX, _endY, _startZ];
    };
    
    // pass two positions, returns angle from pos1 to pos2
    fGetAngleOfTwoPoints ={
     _pos1 = _this select 0;
     _pos2 = _this select 1;
    
     _pos1_x = _pos1 select 0;
     _pos1_y = _pos1 select 1;
     _pos2_x = _pos2 select 0;
     _pos2_y = _pos2 select 1;
    
     _dx = _pos2_x - _pos1_x;
     _dy = _pos2_y - _pos1_y;
    
     _ang = _dx atan2 _dy;
     _ang = _ang mod 360;
     _ang;
    };
    
    //position to center search on
    fGetNearestRoad={
     _nearestRoad=objNull;
     _closestDistanceToRoad=0;
     _searchPos = _this select 0;
     _minDistance = _this select 1;
     _maxDistance = _this select 2;
     _closestDistanceToRoad = _maxDistance;
     {
       if ((_searchPos distance _x < _maxDistance) && (_searchPos distance _x > _minDistance)) then {
         _distanceToRoad = _searchPos distance _x;
         if (_distanceToRoad < _closestDistanceToRoad) then {
           _nearestRoad = _x;
           _closestDistanceToRoad = _distanceToRoad;
         };
       };
     } forEach (_searchPos nearRoads _maxDistance);
     _nearestRoad;
    };
    
    
    // Function creates a random convoy intercept mission
    //   Randomizes starting and ending locations
    // Uses semaphore to prevent multiple missions at the same time
    // Creates task for player to intercept convoy
    // Create triggers that monitors convoy death or convoy completed
    //   reset multi-mission semaphore 
    //   clean up all waypoints
    //     fail task on convoy complete
    //     succeed task on convoy death
    // Creates convoy units in a group
    // Creates convoy waypoint at destination
    // Creates start/end markers
    // Cleans up markers, group and task on mission success/failure
    
    fSpawnEnemyConvoy = {
     if (convoyMissionAssigned) exitWith {
       hint "Convoy mission is already assigned. Complete the assigned mission.";
     };
     _randomStartDistanceX = random 1000 - (1000/2);
     _randomStartDistanceY = random 1000 - (1000/2);
     _startPositionMin = 1500;
     _startPositionMax = 3000;
     _endPositionMin = 2000;
     _endPositionMax = 4000;
     convoyMissionAssigned = true;
     convoyMarkers = [];
     _playerUnit = player;
     _searchPos = getPos _playerUnit;
     // randomize the starting location +/- 100m
     _searchPos = [(_searchPos select 0) + (_randomStartDistanceX), (_searchPos select 1) + (_randomStartDistanceY), _searchPos select 2];
     _startRoad = [_searchPos, _startPositionMin, _startPositionMax] call fGetNearestRoad;
     mkrConvoyStart = createMarker ["convoyMarkerStart", getPos _startRoad];
     mkrConvoyStart setMarkerText "Convoy start";
     mkrConvoyStart setMarkerType "Start";
     mkrConvoyStart setMarkerColor "ColorRed";
     mkrConvoyStart setMarkerAlpha 0.5;
     //"Flag", "Flag1", "Dot", "Destroy", "Start", "End", "Warning", "Join", "Pickup", "Unknown", "Marker", "Arrow" or "Empty".
     //markerName setMarkerPos pos
    
     _searchPos = getMarkerPos mkrConvoyStart;
     _endRoad = [_searchPos, _endPositionMin, _endPositionMax] call fGetNearestRoad;
     mkrConvoyEnd = createMarker ["convoyMarkerEnd", getPos _endRoad];
     mkrConvoyEnd setMarkerText "Convoy End";
     mkrConvoyEnd setMarkerType "End";
     mkrConvoyEnd setMarkerColor "ColorRed";
     mkrConvoyEnd setMarkerAlpha 0.5;
    
     // get the convoy pointing towards the ending marker
     //_startAngle = [getMarkerPos mkrConvoyStart, getMarkerPos mkrConvoyEnd] call fGetAngleOfTwoPoints;
     _startPos = getMarkerPos mkrConvoyStart;
     _endPos = getMarkerPos mkrConvoyEnd;
     _preferredAngle = [_startPos, _endPos] call BIS_fnc_DirTo;
     _startAngle = [_startRoad, _preferredAngle] call fGetRoadHeading;
     _startingPositions = [_startPos, _startAngle, -10, 10] call fGetArrayOfPointsOnRoadFromAngle;
     _spawn = [_startingPositions select 0, _startAngle, "Offroad_DSHKM_INS", EAST] call BIS_fnc_spawnVehicle;
     unit1 = _spawn select 0;
     convoyGroup = _spawn select 2;
     _wp = convoyGroup addWaypoint [_endPos, 0];
     _wp setWaypointType "SAD"; 
     _wp setWaypointBehaviour "SAFE";
     convoyGroup setFormation "COLUMN";
    
     // BUG: change behavior of entire group to alert on any awareness change/gunfire
    
     //create the rest of the group with delays - to let the lead element get rolling
     [_startingPositions, _startAngle] spawn {
       _startingPositions = _this select 0;
       _startAngle = _this select 1;
       sleep 6;
       _retVal = [_startingPositions select 1, _startAngle, "Ural_INS", convoyGroup] call BIS_fnc_spawnVehicle;
       _transport = _retVal select 0;
       groupConvoyEscort = [_startingPositions select 3, EAST, (configFile >> "CfgGroups" >> "East" >> "INS" >> "Infantry" >> "INS_InfSquad_Weapons"),[],[],[0.8,1],[],[12,1],_startAngle] call BIS_fnc_spawnGroup;
       {_x moveInCargo _transport; sleep 0.05;} forEach units groupConvoyEscort;
       sleep 10;
       [_startingPositions select 2, _startAngle, "UralRefuel_INS", convoyGroup] call BIS_fnc_spawnVehicle;
       sleep 6;
       [_startingPositions select 3, _startAngle, "Pickup_PK_Ins", convoyGroup] call BIS_fnc_spawnVehicle;
       sleep 6;
       [_startingPositions select 4, _startAngle, "UAZ_AGS30_INS", convoyGroup] call BIS_fnc_spawnVehicle;
       sleep 6;
       [_startingPositions select 5, _startAngle, "TT650_Ins", convoyGroup] call BIS_fnc_spawnVehicle;
       // we do this to improve their driving ability (hopefully)
       {_x setSkill 1} forEach units convoyGroup;
       hint "Convoy is enroute..";
     };
     // create task for player
     convoyTask = _playerUnit createSimpleTask ["InterceptConvoy"];
     convoyTask setSimpleTaskDescription ["We have intel of an armed Opfor convoy. Intercept and destroy it before it reaches the destination.", "Destroy Convoy", "Destroy Convoy"];
     convoyTask setTaskState "Assigned";
     ["HQ here. We have intel of an armed Opfor convoy. Intercept and destroy it before it reaches the destination."] call fHQMsg;
     // create trigger to detect convoy arrival to destination
     trgDetectConvoyArrived = createTrigger ["EmptyDetector", _endPos];
     trgDetectConvoyArrived setTriggerArea [100,100,0,false];
     trgDetectConvoyArrived setTriggerActivation ["EAST", "PRESENT", true];
     trgDetectConvoyArrived setTriggerStatements ["{vehicle _x in thislist} forEach units convoyGroup;", "[false] call fCleanUpConvoyMission;", ""];
     // create trigger to detect convoy destruction
     trgDetectConvoyDestroyed = createTrigger ["EmptyDetector", _endPos];
     trgDetectConvoyDestroyed setTriggerArea [0,0,0,false];
     trgDetectConvoyDestroyed setTriggerActivation ["NONE", "PRESENT", true];
     trgDetectConvoyDestroyed setTriggerStatements ["({alive _x} count units convoyGroup) < 1;", "[true] call fCleanUpConvoyMission;", ""];
    };
    
    // removes all the markers and triggers for the mission
    // param1: "Succeeded"/"Failed" -- sets task to success or failure
    fCleanUpConvoyMission = {
     _taskState = _this select 0;
     if !(convoyMissionAssigned) exitWith {};
     convoyMissionAssigned = false;
     if (_taskState) then {
       player sideChat "HQ, Alpha here. All convoy elements have been destroyed."; 
       ["HQ here. Roger that, nice work."] call fHQMsg; 
       convoyTask setTaskState "Succeeded";
     } else {
       ["HQ here. Intel reports that convoy has arrived at destination. Mission failed."] call fHQMsg; 
       convoyTask setTaskState "Failed";
       {deleteVehicle vehicle _x;  deleteVehicle _x;} forEach units convoyGroup;
     };
     trgDetectConvoyArrived = objNull;
     trgDetectConvoyDestroyed = objNull;
     deleteMarker mkrConvoyEnd;
     deleteMarker mkrConvoyStart;
    
    };
    

×