Jump to content
valefor

AI goes stupid after respawning

Recommended Posts

Hi.

I am trying to get into scripting in Arma 3 and thought a fun little exercise would be to create a simple queue system for some helicopters in a mission.
The basic idea is as follows: A number of playable units (AI and players) start at a location, some choppers are spawned (with crew). Each playable unit is entered into a queue, and all choppers are entered into a different queue. Once there are enough people to fill a chopper (or justify one traveling), a number of passengers are popped off the queue. These passengers are made into a group, told to enter a helicopter (also just popped off its queue), before the helicopter takes off, transports them to their destination, where they get out. Afterward, the helicopter returns back to its base and queues up again. If a playable unit dies, they respawn at a respawn point and are queued up back for another transport.

 

All playable units are in individual groups initially and are only grouped up once they are transported. This also means that upon respawn, I remove units from their previous group.

 

For simplicity's sake, if the helicopter or the pilot dies, I simply delete the entire vehicle and spawn it again instantly.
This is also very in progress, so a lot of functionality is not implemented yet (like AI re-queueing if their spot in a chopper is taken by a player. It probably doesn't work online either, as I haven't gotten into the topic of local or global execution yet).

 

The reason I am writing this post is that I have run into an issue that I don't really know how to deal with. (think it is just one issue, but it manifests in multiple ways)
1: Most of the time after respawn, AI controlled playables never leave their position. They join groups and order their group members to enter vehicles, but they never actually move to execute the order. (They can physically move in place, going prone, shooting back in case of friendly fire, etc, but I haven't been able to get them to move around). 

2: Other times they respawn, form into groups and try to walk to the location (more than 2 km away).

3: A few times (very uncommon) a small group might actually respawn fully functionally and get into the chopper. (If they haven't already been reserved by a nonfunctioning group).

 

If I kill them before they enter a chopper they usually respawn fully functional.

I am kinda at my witts end, having spent a lot of time trying to debug this yesterday and today, and was hoping that someone here perhaps has some tips. 
I have added my code (with explanatory comments below).
Any help or pointers as to why this might be happening would be truly appreciated.

// All playable units are given this as their initialization script
PM_fnc_InitPlayable =
{
    Respawn =
    {
        private _unit = param[0, objNull, [objNull]];

        // Put them in their own group upon respawn, to avoid being spammed with orders etc etc.
        [_unit] joinSilent createGroup [side _playable, true];

        // Just experimentation to see if any of these things affected why the AI's wouldn't move.
        (group _unit) setBehaviour "CARELESS";

        // They don't manage to move to this waypoint either.
        private _base_helipad_0 = (missionNamespace getVariable "HelipadBase_0");
        private _load_wp = (group _unit) addWaypoint [position _base_helipad_0, 10];
        _load_wp setWaypointType "MOVE";
        _load_wp setWaypointSpeed "FULL";
        _load_wp setWaypointCombatMode "YELLOW";
        _load_wp setWaypointStatements ["true", "deleteWaypoint [group this, currentWaypoint (group this)];"];

        // Tried to see if it was a problem that they were still "ordered" to get in their former vehicle (which is why I unnassign it)
        [_unit] orderGetIn false;
        unassignVehicle _unit;
        [format ["Assigned to vehicle: %1", assignedVehicle _unit]] call PM_fnc_Log;
    };

    QueueLater =
    {
        private _playable = param[0, objNull, [objNull]];
        sleep 1.0; // Need to sleep a bit, otherwise the choppers aren't ready to be queued into.
        [_playable] call PM_fnc_EnqueuePassenger;
    };

    private _playable = param[0, objNull, [objNull]];

    _playable addEventHandler["Respawn", {
        [(_this select 0), (_this select 1)] call Respawn; // Send in dead corpse to get weapons information etc from.
        [(_this select 0)] call PM_fnc_EnqueuePassenger;

    }];

    [_playable] spawn QueueLater;

};


// These are supplied as function library functions, to have access to them in the editor and other scripts.
// Written with function names here so it is easier to read:
PM_fnc_EnqueuePassenger =
{
    private _passenger = param[0, objNull, [objNull]];
    gQueuedPassengers pushBack _passenger;
};

// Just simple function for creating a BLUFOR helicopter to be used by independents,
// and to give different combat mode to gunners and pilots.
CreateHelicopter =
{
    private _in_pos = param [0, [], [[]],3];
    private _vehicle = "B_Heli_Transport_01_F" createVehicle _in_pos;
    private _pilots = createGroup [independent, true];

    [_vehicle, _pilots, false, "", "I_Helipilot_F"] call BIS_fnc_spawnCrew;

    deleteVehicle (_vehicle turretUnit[0]);
    deleteVehicle (_vehicle turretUnit[1]);
    deleteVehicle (_vehicle turretUnit[2]);

    private _gunners = createGroup [independent, true];
    _gunners createUnit["I_Helipilot_F", position _vehicle, [], 0, "FORM"];
    _gunners createUnit["I_Helipilot_F", position _vehicle, [], 0, "FORM"];

    { _x moveInTurret[_vehicle, [_forEachIndex + 1]]; } forEach (units _gunners);
    (units _gunners) orderGetIn true;

    _vehicle lockTurret [[0], true];
    _vehicle lockTurret [[1], true];
    _vehicle lockTurret [[2], true];
    _vehicle lockDriver true;

    _gunners setBehaviour "COMBAT";
    _gunners setCombatMode "YELLOW";

    _vehicle;
};

// Sets up the helicopter for its transport route.
HelicopterTransport =
{
    private _vehicle = param[0, objNull, [objNull]];
    private _base = param [1, objNull, [objNull]];
    private _destination =  param [2, objNull, [objNull]];
    private _pilots = group _vehicle;

    // Just here to ensure it doesn't take off until people are actually in.
    waitUntil
    {
        count (crew _vehicle) > 3;
    };

    [format ["%1 Moving to target", _vehicle]] call PM_fnc_Log;
    private _landing_wp = _pilots addWaypoint [position _destination, 10];
    _landing_wp setWaypointType "TR UNLOAD";
    _landing_wp setWaypointSpeed "FULL";
    _landing_wp setWaypointCombatMode "YELLOW";
    _landing_wp setWaypointBehaviour "CARELESS";
    _landing_wp setWaypointStatements ["true", "deleteWaypoint [group this, currentWaypoint (group this)]"];

    // Waiting until we have actually moved to the place where we are unloading people.
    // < 2 because from what I have seen so far it seems stuff always have at least one waypoint by default (?)
    waitUntil
    {
        count (waypoints _pilots) < 2;
    };

    [format ["%1 Returning home, alive status: %2", _vehicle, (alive _vehicle) and (alive driver _vehicle)]] call PM_fnc_Log;

    private _load_wp = _pilots addWaypoint [position _base, 10];
    _load_wp setWaypointType "MOVE";
    _load_wp setWaypointSpeed "FULL";
    _load_wp setWaypointCombatMode "YELLOW";
    _load_wp setWaypointStatements ["true", "deleteWaypoint [group this, currentWaypoint (group this)];"];

    // Waiting until we get back home with queueing up.
    waitUntil
    {
        count (waypoints _pilots) < 2;
    };

    // Double check incase we died before getting back home.
    if ((alive _vehicle) and (alive driver _vehicle)) then
    {
        [format ["%1 arrived home", _vehicle]] call PM_fnc_Log;
        _vehicle land "GET IN";
        [[_vehicle, _base, _destination]] call EnqueueHelicopter;
    };

};

// Function for respawning helicopter.
// Essentially just waits for the helicopter to die.
// then removes it completely, and spawns a new one, queues it up, etc.
RespawnHelicopter =
{
    private _params = param[0, []];
    private _vehicle = _params # 0;
    private _base = _params # 1;
    private _destination =  _params # 2;

    waitUntil
    {
        (!alive _vehicle) or (!alive driver _vehicle);
    };

    // Want to ensure stuff is actually dead, so it can be removed (?)
    // Also, don't allow other people to fly the chopper, so might as well just kill the poeple in it.
    _vehicle setDamage 1;
    (driver _vehicle) setDamage 1;
    (_vehicle turretUnit[0]) setDamage 1;
    (_vehicle turretUnit[1]) setDamage 1;

    // I don't really want this in here, because if the chopper crashes and people survive, then they should be allowed to get out
    // However, for some reason, the AI did work one time when this was in. But it's kinda voodoo code, and I don't really like that.
    {
      forceRespawn _x;
    } forEach (crew _vehicle);

    ["Respawning Helicopter"] call PM_fnc_Log;
    _vehicle = [position _base] call CreateHelicopter;

    [[_vehicle, _base, _destination]] call EnqueueHelicopter;
    [[_vehicle, _base, _destination]] spawn RespawnHelicopter;
};

// Just the two global queues.
// Don't have the impression that I can easily create classes or something here, so I just made them global like this.
// Format in gQueuedHelicopters is: [[<helicopter>, <base helipad>, <target helipad>], ...]
gQueuedHelicopters = [];
gQueuedPassengers = [];

EnqueueHelicopter =
{
    ["Queueing Helicopter"] call PM_fnc_Log;
    private _chopper = param[0, []];
    gQueuedHelicopters pushBack _chopper;
    [format["Current helicopters queued: %1", count gQueuedHelicopters]] call PM_fnc_Log;
};

// Essentially main logic for the queueing system.
// As explained in the post. Just wait for enough people and enough choppers to be in the queues
// Then pop off enough people for a group, group them together and send em to a chopper.
QueueingSystemMain =
{
    // Hack, this should be parameter or, it should perhaps just not be done in here.
    private _beach_helipad = (missionNamespace getVariable "HelipadBeach_0");

    while {true} do
    {
        // Wait until enough people to satisfy a chopper going off.
        waitUntil
        {
            (count gQueuedPassengers >= 2) and (count gQueuedHelicopters >= 1);
        };

        // Create groups of for the passengers
        while {count gQueuedPassengers >= 2 and count gQueuedHelicopters >= 1} do
        {
            private _new = createGroup [independent, true];
            private _new_group = gQueuedPassengers select[0, 8];
            gQueuedPassengers deleteRange[0, 8];

            private _heli_info = gQueuedHelicopters deleteAt 0;
            private _helicopter = _heli_info select 0;

            [format["Dequeued helicopter, Current chopper queue: %1, Current passenger queue: %2", count gQueuedHelicopters, count gQueuedPassengers]] call PM_fnc_Log;

            _new_group joinSilent _new;

            {
              _x assignAsCargo _helicopter;
            } forEach (units _new);

            units _new orderGetIn true;
            [format["New Group: %1", (units _new)]] call PM_fnc_Log;

            // Hacky waypoint just to get people into combat when they arrive at their location.
            private _startup_wp = _new addWaypoint [position _beach_helipad, 400];
            _startup_wp setWaypointType "SAD";
            _startup_wp setWaypointSpeed "FULL";
            _startup_wp setWaypointCombatMode "YELLOW";
            _startup_wp setWaypointBehaviour "COMBAT";

            // Call on helicopter.
            [_helicopter, _heli_info # 1, _heli_info # 2] spawn HelicopterTransport;
        };
    };
};

Main =
{
    [] spawn QueueingSystemMain;

    private _beach_helipad_0 = (missionNamespace getVariable "HelipadBeach_0");
    private _beach_helipad_1 = (missionNamespace getVariable "HelipadBeach_1");
    private _beach_helipad_2 = (missionNamespace getVariable "HelipadBeach_2");
    private _beach_helipad_3 = (missionNamespace getVariable "HelipadBeach_3");

    private _base_helipad_0 = (missionNamespace getVariable "HelipadBase_0");
    private _base_helipad_1 = (missionNamespace getVariable "HelipadBase_1");
    private _base_helipad_2 = (missionNamespace getVariable "HelipadBase_2");
    private _base_helipad_3 = (missionNamespace getVariable "HelipadBase_3");

    [[objNull, _base_helipad_0, _beach_helipad_0]] spawn RespawnHelicopter;
    [[objNull, _base_helipad_1, _beach_helipad_1]] spawn RespawnHelicopter;
    [[objNull, _base_helipad_2, _beach_helipad_2]] spawn RespawnHelicopter;
    [[objNull, _base_helipad_3, _beach_helipad_3]] spawn RespawnHelicopter;


};

// Just personal preference to avoid if possible to have stuff directly in file, I find it harder to see what is executed and what isn't.
[] call Main;

 

Edited by valefor
Fixed topic, as it's not only that they don't move

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

×