Jump to content

Recommended Posts

Hi all,
Want to play with a "One man tank"? Here is a little script for "World of tank" aficionados.
Works on all tanks in game, as far as you can jump into the driver's seat.

Usage:
you're driver until you move the mouse, pointing cannon at cursor direction. Driver is always in 3rd person.
Then, you're gunner but you can use your keys to continue driving the tank.
- in external view, you'll be back at driver's seat if no waypoint (see further) and no turret movement for 10 seconds.
- in gunner view, you stay as gunner role and continue to drive.
- if in gunner (or external) view and right click (Temporary zoom) on landscape, you create a temporary waypoint where the tank goes as far as you don't touch any of the driver's keys. Driver's keys will delete this waypoint when strike.

Hints to know:
- when driving from gunner's seat, avoid maintaining the forward key when you need to turn. release all, strike left(/right), maintain if you want; As soon as the direction is good, release left(/right) key, strike forward key. The tank will start to sway a little around the desired direction but will go where you want. Remember release all keys to make change.
- there is no rear clutch while in gunner, just because Arma's engine prefers a 180° turn instead of a 10 meter rear drive...
So, I disabled the backward key in gunner.

Other stuffs:
There are 2 parameters O/1 for displaying:
- tank icon, in order to have a clear view of the direction of the tank when you are in gunner view. Gun is always up, of course.
- little radar displaying other vehicles in game, along with knowledge of these units.

Now, the function. Just add it into init.sqf or initPlayer.sqf, or any script which run for player:

MGI_1ManTank = {
params [["_icon",1,[0]],["_radar",1,[0]]];
if (!hasInterface) exitWith {};
MGI_iTk = _icon;
MGI_rdrTk = _radar;

MGI_timerTurreting = 0;
MGI_timerStopping = 0;
MGI_icon_tk = "";
coef_ratioTK = (getResolution select 4)/ 1.77778;
coef_uiSpaceTK = 0.55/(getResolution select 5);
MGI_keysMovingTk = ["carForward","Turbo","carSlowForward","carBack","carLeft","carRight"] apply {actionkeys _x select 0};
MGI_destTk = [0,0,0];

inGameUISetEventHandler ["Action", "
      if (_this select 0 isKindOf 'tank') then {
        MGI_icon_tk = getText (configFile >> 'cfgVehicles' >> typeof (_this select 0) >> 'icon');
        if ((_this select 3) == 'GetInDriver' and count crew (_this select 0) > 0) then {
          _units = crew (_this select 0);
          {unassignVehicle _x} forEach _units; _units allowGetIn false
        }; 
        if ((_this select 3) in ['GetInGunner','GetInCommander','GetInTurret']) exitWith { hint parseText ('<t>Jump in driver'+""'""+'s seat<t/>'); true};
        if ((_this select 3) in ['MoveToGunner','MoveToCommander','MoveToTurret'] && !(player getVariable ['gunning',false])) exitWith { hint parseText ('<t>Only driver'+""'""+'s seat available<t/>'); true};
    }
"];

_MGI_EHTank =  ["MGI_TK","onEachFrame",
  {
    coef_zoomTK = ([0.5,0.5] distance worldToScreen positionCameraToWorld [0,10,10])* (getResolution select 5);
    _veh = vehicle player;
    if (inputAction "zoomTemp" == 1 && {!isnil "MGI_agent"}) then {
      MGI_destTk = screenToWorld [0.5,0.5];
     if (isnil "MGI_signTkDest") then {
        MGI_agent setDestination [MGI_destTk, 'VEHICLE PLANNED', true];
        MGI_destTk set [2,2];
        MGI_signTkDest = "Sign_Arrow_Large_F" createvehicle MGI_destTk
      };
    };
    if (!isnil "MGI_signTkDest" && {MGI_destTk isEqualTo [0,0,0] or (player distanceSqr MGI_destTk < 100) or driver _veh == player}) then {
      deleteVehicle MGI_signTkDest; MGI_signTkDest = nil};
    if (!(_veh isKindOf "tank") && !isNil "MGI_agent") exitWith {
      deleteVehicle MGI_agent; MGI_agent = nil;
      if (!isnil "MGI_keysDriving") then {(findDisplay 46) displayRemoveEventHandler ["keyDown",MGI_keysDriving]; MGI_keysDriving = nil};
      if (!isnil "MGI_keysDrivingUp") then {(findDisplay 46) displayRemoveEventHandler ["keyUp",MGI_keysDrivingUp]; MGI_keysDrivingUp = nil};
    };
    if (player == driver _veh) then {
      {_veh lockTurret [_x,true]} forEach allTurrets _veh;
      if (cameraView != "external" && _veh isKindOf "tank") then {player switchcamera "external"}
    } else {
      if (player == gunner _veh  && diag_tickTime > MGI_timerTurreting + 10 && (cameraView == "external" && isnil "MGI_signTkDest")) then {
        player action ["MoveToDriver", _veh];
        player setVariable ["gunning",false];
        if !(isnil "MGI_agent") then {deleteVehicle MGI_agent; MGI_agent = nil;{_veh lockTurret [_x,true]} forEach allTurrets _veh};
      };
    };
    if (isnil "MGI_keysDriving") then {
      MGI_keysDriving = (findDisplay 46) displayAddEventHandler ["KeyDown",
        "
          private _handled = false;
          if (!isnil 'MGI_agent') then {
            MGI_timerStopping = diag_tickTime;
            _veh = vehicle player;
            call {
              if ((_this select 1) == MGI_keysMovingTk select 4) exitWith {
                 MGI_agent setDestination [_veh modelToWorldVisual [-30,10,0], 'VEHICLE PLANNED', true]; MGI_destTk = [0,0,0];
                _handled = true
              };
              if ((_this select 1) == MGI_keysMovingTk select 5) exitWith {
                MGI_agent setDestination [_veh modelToWorldVisual [30,10,0], 'VEHICLE PLANNED', true]; MGI_destTk = [0,0,0];
                _handled = true
              };
              if ((_this select 1) == MGI_keysMovingTk select 1) exitWith {
                MGI_agent setDestination [_veh modelToWorldVisual [0,100,0], 'VEHICLE PLANNED', true]; MGI_agent setSpeedMode 'FULL'; MGI_destTk = [0,0,0];
                _handled = true
              };
              if ((_this select 1) == MGI_keysMovingTk select 2) exitWith {
                MGI_agent setDestination [_veh modelToWorldVisual [0,30,0], 'VEHICLE PLANNED', true]; MGI_agent setSpeedMode 'LIMITED'; MGI_destTk = [0,0,0];
                _handled = true
              };
              if ((_this select 1) == MGI_keysMovingTk select 0) exitWith {
                MGI_agent setDestination [_veh modelToWorldVisual [0,100,0], 'VEHICLE PLANNED', true]; MGI_agent setSpeedMode 'NORMAL'; MGI_destTk = [0,0,0];
                _handled = true
              };
              if ((_this select 1) == MGI_keysMovingTk select 3) exitWith {
                MGI_agent setDestination [_veh modelToWorldVisual [0,0,0], 'DoNotPlan', true]; MGI_destTk = [0,0,0];
                _handled = true
              };
            };
          };
          _handled
      "];
      MGI_keysDrivingUp = (findDisplay 46) displayAddEventHandler ["KeyUp",
        "
          if (!isnil 'MGI_agent' && diag_tickTime > MGI_timerStopping + 3 && (MGI_destTk isEqualTo [0,0,0])) then {
            MGI_agent setDestination [vehicle player modelToWorldVisual [0,0,0], 'DoNotPlan', true]
          };
      "];
    };
}] call BIS_fnc_addStackedEventHandler;

_MGI_DrawRadar = addMissionEventHandler ["draw3D",{
  if (cameraView == "gunner" && vehicle player isKindOf "tank") then {
    _veh = vehicle player;
    _aTurret = Deg (_veh AnimationPhase "mainturret");
    if (MGI_iTk == 1) then {
      _tkIconPos  =  positionCameraToWorld [0,-370/coef_zoomTK,1000];
      _damageTK = [2*(damage _veh),2 - 2 * (damage _veh),0.3,0.5];
      drawIcon3D [MGI_icon_tk, _damageTK,_tkIconPos, 2, 2, - _aTurret, "", 1, 0.05, "TahomaB"];
    };
    if (MGI_rdrTk == 1) then {
      for "_i" from 0 to 350 step 10 do {
        _posdiam = positionCameraToWorld [(sin _i) * 110 * coef_ratioTK / coef_zoomTK,(-370+ ((cos _i) * 110)) / coef_zoomTK,1000];
        drawIcon3D ["A3\ui_f\data\IGUI\Cfg\squadRadar\SquadRadarOtherGroupUnit_ca.paa", [0.7,1,0.3,0.8], _posdiam, 0.4, 0.4, 0, "", 1, 0.05, "PuristaMedium"];
      };
      if (!isnil "MGI_signTkDest") then {
        _dirS = (((_veh) getRelDir MGI_destTK) + _aTurret) mod 360;
        _d2S = ((player distanceSqr MGI_destTK) min 10^6) max 10^4;
        _xx = 100 - ((10^6-_d2S)/19800);
        _posWpt = positionCameraToWorld [(sin _dirS) * _xx * coef_ratioTK / coef_zoomTK,(-370+ ((cos _dirS) * _xx)) / coef_zoomTK,1000];
        drawIcon3D ["A3\ui_f\data\GUI\Cfg\Cursors\hc_move_gs.paa", [1,1,0.5,1], _posWpt, 0.5, 0.5, 0, "", 1, 0.05, "PuristaMedium"];
      };
      _allvehicles = vehicles select {alive _x &&  !(_x isKindOf "WeaponHolderSimulated") && side _x != civilian};
      _enyVehs = _allvehicles select {side _x getFriend side player < 0.6};
      _frdVehs = _allvehicles - _enyVehs;
      if ( count (_enyVehs + _frdVehs) > 0) then {
        private ["_icon","_color"];
        {
          if (_x isKindOf "air") then {
            _icon = "A3\ui_f\data\IGUI\Cfg\tacticalDisplay\targetAirTexture_gs.paa"
          } else {
            _icon = "A3\ui_f\data\IGUI\Cfg\tacticalDisplay\targetTexture_gs.paa"
          };
          _dir = ((_veh) getRelDir _x) + _aTurret;
          _d2 = ((player distanceSqr _x) min 10^6) max 10^4;
          _dd = 100 - ((10^6 - _d2)/19800);
          _posVeh = positionCameraToWorld [(sin _dir) * _dd * coef_ratioTK / coef_zoomTK,(-370+ ((cos _dir) * _dd)) / coef_zoomTK,1000];
          call {
            if (_x in _frdVehs) exitWith {
              _kwn = player knowsAbout _x;
              _color = if (_kwn < 1.5) then [{[0.3,0.3,0.3,0.3]},{[0.3,0.8,0.9,0.8]}];
              };
            _kwn = playerSide knowsAbout _x;
            _color = [0.3 max (_kwn/2),((0.3 max (_kwn/2)) min (2 - (0.3 max (_kwn/2)))) max 0.3,0.3,0.3 + (0.5*_kwn/4)];
          };
          drawIcon3D [_icon, _color, _posVeh, 0.5, 0.5, 0, "", 1, 0.05, "PuristaMedium"];
        } forEach (_allvehicles - [_veh]);
      };
    };
  };
}];

_MGI_mousingGunner = (findDisplay 46) displayAddEventHandler ["mouseMoving",
  {
    _veh = vehicle player;
    if (_veh isKindOf "tank") then {
      player setVariable ["gunning",true];
      if (gunner _veh != player) then {player action ["MoveToTurret",_veh,[0]]};
      MGI_timerTurreting = diag_tickTime;
      if (isnil "MGI_agent") then {
        MGI_agent = createAgent ["B_Soldier_VR_F", getpos _veh, [], 0, "CAN_COLLIDE"];
        MGI_agent moveInDriver _veh;
        MGI_agent setBehaviour "COMBAT";
        MGI_agent setSpeedMode "FULL";
      };
   };
}];
};

 

Then call this function with desired parameters:

[1,1] call MGI_1ManTank; // 1 = enable tank icon, 1 = enable radar

 

EDITED : You'll find below, a lighter version (with no radar and no destination on marker). This light version is also updated & improved in MGI Advanced Modules.


Hope you'll have fun!
Pierre MGI

  • Like 7

Share this post


Link to post
Share on other sites

Thanks a lot for sharing!

 

Couple of questions on your design approach:

1. Mouse movement to become gunner - I guess to make it easier than say action menu or key combo?

2. Why driver 3rd only? To make it more accessible or why not keep the choice the the player?

3. No turret movement for 10 seconds - isnt this limiting the ability to hide/be sneaky? You have to get into gunner view to do so, right?

4. Did you try to improve the vehicle turning via scripting (setDir+setVelocity)?

 

Will test ingame soon - sounds really well thought out and tweaked. :)

Share this post


Link to post
Share on other sites

1 All is question of choice. Mouse movement is fluid, and yes, easier than any  key.

 

2 Driver 1st view is disabled because I think this view is not fine, too "tunneled". For this script, the realism is of course less important than the playability, then fast gaming action. But yes, this could easily become a player's choice.

 

3 No turret movement for 10 sec, means you have to wait for this time before to drive as driver. But you can move the tank from the gunner seat of course. Perhaps a key could also do that. My problem was to avoid any "hard" key binding. Players keep their own settings. In this script, all actions (even marking a waypoint have to be as easy and natural as possible).  And no, it's the contrary, you have to be in external view to be back in the driver seat (after 10 sec of mouse inactivity). If you're in gunner view, you're supposed to be on a priority action, regardless of the mouse activity.

 

4 any attempt with setVelocity failed on uneven terrain. Any little rock can lead to a flight into the air or weird vectoring. I'm not so skilled to reproduce the movements induced by the driver's keys. If I could, Agent were not mandatory anymore!

 

Thanks for you comment. As shared, this script can evolve as you like, by your own, or asking here for modifications.

  • Like 2

Share this post


Link to post
Share on other sites

Saw this in Operation Flashpoint as a mod back in the day.  Good to see this back in the sandbox !

 

Scott out 

Share this post


Link to post
Share on other sites

A couple friends and I are trying to get this script to work on our Exile server and we are running into some problems.

Where do we put the script itself?
And secondly, how do we call the script to work on spawned vehicles.

Lastly, is it possible to make this script work with helicopters or APC's?


Thank you for your help

Share this post


Link to post
Share on other sites

As mission editor, you can add an sqf file inside the mission folder (then execVM it from initPlayerLocal.sqf) or just add this whole code in the initPlayerLocal.sqf file.

I remember I have already given a lighter but wider version of this code.

Personally, I just place the whole code inside a trigger (non repeatable, set to TRUE as condition, for everyone so not on server only)
 

Spoiler

 


 


inGameUISetEventHandler ["Action", "  
  _tk = _this select 0;  
  if (_tk in MGI_tanks) then {  
    if ((_this select 3) == 'GetInDriver' and count crew (_this select 0) > 0) then {  
      _units = crew (_this select 0);  
      if (!isnil MGI_agent) then {_units = _units - [mgi_agent]};  
      {unassignVehicle _x} forEach _units;  
      _units allowGetIn false;  
    };  
    if ((_this select 3) in ['GetInGunner','GetInCommander','GetInTurret']) exitWith {  
      hint parseText ('<t>Jump in driver'+""'""+'s seat<t/>');  
      true  
    };  
    if ((_this select 3) in ['MoveToGunner','MoveToCommander','MoveToTurret'] && !(player getVariable ['gunning',false])) exitWith {  
      hint parseText ('<t>Only driver'+""'""+'s seat available<t/>');  
      true  
    };  
  };  
"];  
   
MGI_EHTank =  ["MGI_TK","onEachFrame", {  
    _veh = vehicle player;  
    if (!isNil "MGI_agent" && {!(_veh in MGI_tanks) or !(MGI_agent in _veh)}) exitWith { 
      deleteVehicle MGI_agent; MGI_agent = nil; 
      if (!isnil "MGI_keysDriving") then {(findDisplay 46) displayRemoveEventHandler ["keyDown",MGI_keysDriving]; MGI_keysDriving = nil}; 
    };  
    if (player == driver _veh and _veh in MGI_tanks) then {  
      {_veh lockTurret [_x,true]} forEach allTurrets _veh;  
      if (cameraView != "external") then {player switchcamera "external"}  
    } else {  
      if (player == gunner _veh  && _veh in MGI_tanks && diag_tickTime > MGI_timerTurreting + 10 && (cameraView == "external" && isnil "MGI_signTkDest")) then {  
        player action ["MoveToDriver", _veh];  
        player setVariable ["gunning",false];  
        if !(isnil "MGI_agent") then {  
          deleteVehicle MGI_agent;  
          MGI_agent = nil;  
          deleteGroup MGI_agent_Grp;  
          {_veh lockTurret [_x,true]} forEach allTurrets _veh};  
      };  
    };  
    if (isnil "MGI_keysDriving") then {  
      MGI_keysDriving = (findDisplay 46) displayAddEventHandler ["KeyDown",  
        "  
          private _handled = false;  
          if (!isnil 'MGI_agent'&& {if (inputAction _x >0) exitWith {1} } count ['turnLeft','turnRight','moveBack','moveForward','moveFastForward'] >0) then {  
            enableSentences false;  
            [] spawn {uisleep 1; enableSentences true};  
          };  
          _handled  
      "];  
    };  
}] call BIS_fnc_addStackedEventHandler;  
   
   
MGI_1ManTank = {  
  if (!hasInterface) exitWith {};  
  MGI_timerTurreting = 0;  
  MGI_tanks = [];  
  waituntil {!isNull findDisplay 46};  
  _MGI_mousingGunner = (findDisplay 46) displayAddEventHandler ["mouseMoving",{  
    _veh = vehicle player;  
    if (_veh in MGI_tanks) then {  
      _veh allowCrewInImmobile true;  
      _veh setUnloadInCombat [true,false];     
      player setVariable ["gunning",true];  
      if (gunner _veh != player) then {player action ["MoveToTurret",_veh,[0]]};  
      MGI_timerTurreting = diag_tickTime;  
      if (isnil "MGI_agent") then {  
        MGI_agent_Grp = createGroup playerSide;  
        MGI_agent = MGI_agent_Grp createunit ["B_Soldier_VR_F", getpos _veh, [], 0, "CAN_COLLIDE"];  
        MGI_agent moveInDriver _veh;  
        MGI_agent setBehaviour "COMBAT";  
        MGI_agent setSpeedMode "FULL";  
      };  
    };  
  }];  
  while {true} do {  
    uisleep 2;  
    {  
      MGI_tanks pushBackUnique _x;  
      _x setVariable ["onetk",true];  
    } forEach (vehicles select {  (_x isKindOf "tank" or _x isKindOf "Wheeled_APC_F" )  && isnil {_x getVariable "onetk"}});  
  };  
}; 

0 = [] spawn MGI_1ManTank;

 

 

 

The code works on all tanks, even spawned, as far as the action menu is concerned, without filtering vehicles except for their kind (tanks so far).

APC's have been added.

For helos, I never tested but it seems to me difficult to make something like that, overriding the manual fire of BI. I don't have any time to tune the code with all "gunner" "copilot", "turret" possibilities, right now.

  • Like 3
  • Thanks 1

Share this post


Link to post
Share on other sites

Script working until sometime later in scenario(deathmatch) 

 

Quote

findDisplay 46) displayRemoveEventHandler ["keyDown",MGI>
22:34:04   Error position: <displayRemoveEventHandler ["keyDown",MGI>
22:34:04   Error Type Any, expected Number
22:34:04 Error in expression <gent;
MGI_agent = nil;
(findDisplay 46) displayRemoveEventHandler ["keyDown",MGI>
22:34:04   Error position: <displayRemoveEventHandler ["keyDown",MGI>
22:34:04   Error Type Any, expected Number
22:34:04 Error in expression <gent;
MGI_agent = nil;
(findDisplay 46) displayRemoveEventHandler ["keyDown",MGI>
22:34:04   Error position: <displayRemoveEventHandler ["keyDown",MGI>
22:34:04   Error Type Any, expected Number
22:34:04 Error in expression <gent;
MGI_agent = nil;

...

 

 

 

Possible bug here is that 

 

MGI_agent_Grp = createGroup playerSide;

 

might be 

 

MGI_agent_Grp = createGroup [playerSide, true];

 

will check

 

Share this post


Link to post
Share on other sites

This code is rather old.

 

I slightly modified the both scripts (front page and light one).

 

For better performance, always use the MGI advanced module One Man Tank. (or any other module. The codes are frequently updated)

  • Like 1

Share this post


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

I have question does it work only with original tanks? 

No. Any tank or APC as far as they are of these types: "tank" (this  script) or  "Wheeled_APC_F" (added in module).

Share this post


Link to post
Share on other sites
On 3/27/2020 at 2:17 PM, pierremgi said:

Personally, I just place the whole code inside a trigger (non repeatable, set to TRUE as condition, for everyone so not on server only)

Where exacly to put the code? Because when I did this the script wasn't working

Share this post


Link to post
Share on other sites
On 1/22/2023 at 1:31 PM, Majkal said:

Where exacly to put the code? Because when I did this the script wasn't working

As said, just run it in init.sqf or in activation field of a trigger ser to TRUE as condition (of course).
If the script doesn't work, check what mod(s) you are using. There is sometimes mods or even custom scripts forbidding use of event handlers or perhaps you are trying a "tank" or an "APC" not identified as is... I can't say without your arma configuration.

You can use the module instead (MGI advanced Modules) if you are not familiar with scripting.

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

×