Jump to content
Sign in to follow this  
Monsada

UPSMON - Urban Patrol Script Mon

Recommended Posts

They seem to still take vehicles even when the vehicles are locked and even with extremely high searchVehicleDist.

Share this post


Link to post
Share on other sites

That's right. It's a very annoying problem if you use upsmon civilians patrols. Sometimes the civilians run 100-150m out of the patrol area just to steal your humvee.

the feature "AI try to get in combat vehicles" should be swithed off for civilians

edit and

how to stop CIV to use static weapons. NoAI does not work.

Edited by Rafalski

Share this post


Link to post
Share on other sites

Hmm, I was wondering how to get a sniper to successfully spot targets for troops in the area, and have come up with this that works extremely well.

nul=[this,"Sniper_Zone_1","nomove","nowp3"] execVM "Scripts\upsmon.sqf";this setUnitPos "DOWN";this doWatch sniper_watch_2;this SelectWeapon "Binocular";

Sniper_Zone_1 = Marker where your sniper is located

Sniper_Watch_2 = Gamelogic named "Sniper_Watch_2"

Make sure some squads are patrolling within his zone (I created 2 small squads patrolling behind him), and they will move and flank when he spots.

You can choose to let him fire or just spot, that is up to you. Nice and simple script segment of code for people hopefully.

Share this post


Link to post
Share on other sites

I don't think "nomove" does anything when you already use "nowp3"? As "nomove" tells the script how to control the unit but "nowp3" already tells the script to not even try controlling the unit...

Share this post


Link to post
Share on other sites

Just did it to ensure he NEVER moves at all. Had issues with him moving about beforehand.

Share this post


Link to post
Share on other sites

"nomove" only means he doesn't move until enemy is detected and even after enemy is detected it will act defensively, while "nowp3" means the script doesn't tell it what to do at all so you can use your own waypoints/scripting to control it while still having it report units it detects back to other patrolling groups.

Share this post


Link to post
Share on other sites

With "fortify" it seems they sometimes return to formation or something after reaching their "fortify" position, which kinda messes the whole idea up :(

Also it would be nice if when they say "sorry, I can't" when they try reach a certain position to have UPSMON try give them a different one.

Edited by galzohar

Share this post


Link to post
Share on other sites

quick question, how would i make cloned units spawn running a script called IED.sqf

example:

nul=[this,"bombs","min:",3,"max:",6,"init:"," nul=[this]execvm"scritps\ied.sqf";"]execvm"scripts\upsmon.sqf"

btw UPSMON is an amazing script!!

Share this post


Link to post
Share on other sites

Do difficulty settings affect UPSMON at all?

I was playing a mission with some friends online (a mission I had made) with UPSMON.

My friends wanted to play it in expert (although I am of the opinion that higher difficulties are a nuisance because all they do is disable useful things in your gui)

Anyway, when going into the mission and making contact with the enemy, the enemy were just standing around and not patrolling in their marker area.

Is it possible that higher difficulty settings could delete markers that are used in UPSMON and are crucial for it to work?

Thanks,

-AD

Share this post


Link to post
Share on other sites

Difficulty doesn't affect the patrol routes that are picked by the units. Make sure you are running the script properly.

Share this post


Link to post
Share on other sites

Hey, anyone know how to remove the zone markers from the briefing screen? My old way of doing it doesn't seem to be working, if the commands have changed since 1.03/4 then please inform me :)

Share this post


Link to post
Share on other sites

Either use setMarkerAlpha in a game logic's init line, or in that game logic's init line write hNil = call compile preprocessFile "markeralpha.sqf" and make a script called markeralpha.sqf and in it type all the setMarkerAlpha commands.

Since these commands will run during mission initialization before briefing is even loaded, the markers will never be visible.

Share this post


Link to post
Share on other sites

put in init.sqf

"area0" setMarkerAlpha 0;

"area1" setMarkerAlpha 0;

Share this post


Link to post
Share on other sites

init.sqf starts after briefing is loaded, so it might still briefly show the markers, unlike my solution.

Share this post


Link to post
Share on other sites

Cheers guys, worked like a charm. Usually did it via briefing but this game logic method is much better (stops people knowing positions during briefing stage).

Share this post


Link to post
Share on other sites

-how do we spanw units randomly in marker carea forma an template unit or must we define an spwan position ?

-and for the spawned units and an squad with patrol,random and min and max values,

if i define this as reinforcement 1, all the created other squads (with min and max values) will be einforcement 1 and move for help with KRON_UPSMON_reinforcement1=TRUE or just the first group will move ?

Share this post


Link to post
Share on other sites

It seems like the problem with fortify is actually again AI trying to get into buildings that they cannot find a path to get into. This happens way too much, I wish UPSMON would handle this somehow (by realizing they didn't reach their destination and try give them a different position, and repeat until a proper one is found).

Share this post


Link to post
Share on other sites

I tried updating the script so that if I give it an array of all bugged buildings it will not use those buildings. However even after editing what seems to be the functions for finding nearest buildings and removing those buildings from the returned building array, they still seem to try go into those buildings, so I'm most likely missing something.

Anyone has any idea where exactly I need to make changes in order to modify the way UPSMON searches for buildings?

I think I found it - in MON_GetNearestBuildings (which appears in both scripts\common\MON_functions.sqf as well as scripts\UPSMON\common\MON_functions.sqf, not sure why), add the following line:

// _posinfo: [0,0]=no house near, [obj,0]=house near, but no roof positions, [obj,pos]=house near, with roof pos
//_posinfo= _object call MON_PosInfo;										
_OCercanos = nearestObjects [_object, ["house","building"] , _distance];

[b]	if (!isNil "buggedBuildings") then {_OCercanos = _OCercanos - buggedBuildings;}[/b]

{
	_bldpos = _x call MON_BldPos; 
	if ( _bldpos >= _minfloors && damage _x <= 0 ) then { _blds = _blds + [[_x,_bldpos]];};
	//player sidechat format["%1 cerca de edificio con %2 plantas %5",typeof _object,_bldpos];	
}foreach _OCercanos;

Then if your mission defines an array called buggedBuildings that holds all the bugged buildings that you don't want AI to get into, those buildings will not be considered by UPSMON.

To test whether a building is bugged or not, place an AI unit in the editor next to it and in its init line type:

this doMove ((nearestBuilding this) buildingPos 0);

If the unit gets in the building, it's working, and if the unit stands next to the building then the building is bugged and whoever made the island will hopefully fix it someday...

Edited by galzohar

Share this post


Link to post
Share on other sites

Ive ran in to a strange problem. I was wanting to put a trigger in so that when a person enters a certain aera a patrol will spawn .

after working on it for a while I got the debug message to tell me the untis where spawning etc and could see markers moving around on the maps but the spawned patrol was not visable in the game .

I am able to put static patrols in the mission via the editor but any that I spawn via trigger or script do not show up .

thanks

Share this post


Link to post
Share on other sites

It seems like with the "NOFOLLOW" parameter only the leader will stay in the zone, but the rest of the units will feel free to go well away from the zone to engage enemies. Any way to reduce that so that I get the enemies to act more defensively?

Share this post


Link to post
Share on other sites

Using setCombatMode "YELLOW" doesn't seem to help here, AI will still go and engage well outside their zone. It seems though that if I place them far enough away (but still within the sharedist so that they do become aware), they won't engage, so it might be the group leader giving commands on his own that aren't directly related to UPSMON. Though shouldn't a "YELLOW" combat mode prevent independent engaging?

Share this post


Link to post
Share on other sites

Monsada, are you still around here and/or intending to keep working on UPSMON? Because I had another nice idea:

Option to change parameters of an already patrolling group:

1. [unit, "PARAMETER" (, "PARAMETER2", ...)] execVM "scripts\add_param.sqf"; would make the patrolling unit behave as if the included parameters were used when UPSMON was first spawned.

2. [unit, "marker", ... ] execVM "scripts\restart_UPSMON.sqf" will make the group stop whatever they are doing and re-run UPSMON with newly given parameters.

That way a script will easily be able to change a group's patrol zone dynamically, change a "NOMOVE" squad to a "NOFOLLOW" one or change them to "FORTIFY". Hopefully it's not something that would be extremely hard to implement (I think UPS already had built-in ability to abort the script?).

Share this post


Link to post
Share on other sites

Hello together,

hope you can help me with a little problem with ups.

I want to set units on the map with the parameter "nomove" so that they stay as long no enmey is there. That works good.

But i want them that the stay in behaviour "safe" and not in behaviour "Fight".

Sometimes they stay but sometimes they are lying on the ground, what can i do? I want them staying in safe pos as long as the enemy is not there

Thanks for help!

Share this post


Link to post
Share on other sites

Try editing the script so that while there is no enemy contact put them back into "SAFE" mode. You would have to continually check it because once the AI spots an enemy they switch to "AWARE" or "COMBAT" modes, and won't necessarily (or at least not imediately) switch back to "SAFE" on their own after seeing the enemy.

Alternatively, you could just do all of this in a seperate script, but I can't guaruntee the other script won't interfere with it.

Share this post


Link to post
Share on other sites

Thats the whole script, where i can change this?

Iam no script kiddy so i have just noobish Scripting expirience

thx for help!

// =========================================================================================================
//  Urban Patrol Script  
//  Version: 2.1.0
//  Author: Kronzky (www.kronzky.info / kronzky@gmail.com)
// ---------------------------------------------------------------------------------------------------------
//  Required parameters:
//    unit          = Unit to patrol area (1st argument)
//    markername    = Name of marker that covers the active area. (2nd argument)
//    (e.g. nul=[this,"town"] execVM "ups.sqf")
//
//  Optional parameters: 
//    random        = Place unit at random start position.
//    randomdn      = Only use random positions on ground level.
//    randomup      = Only use random positions at top building positions. 
//    min:n/max:n   = Create a random number (between min and max) of 'clones'.
//    init:string   = Cloned units' init string.
//    prefix:string = Cloned units' names will start with this prefix.
//    nomove        = Unit will stay at start position until enemy is spotted.
//    nofollow      = Unit will only follow an enemy within the marker area.
//    delete:n      = Delete dead units after 'n' seconds.
//    nowait        = Do not wait at patrol end points.
//    noslow        = Keep default behaviour of unit (don't change to "safe" and "limited").
//    noai          = Don't use enhanced AI for evasive and flanking maneuvers.
//    showmarker    = Display the area marker.
//    trigger       = Display a message when no more units are left in sector.
//    empty:n       = Consider area empty, even if 'n' units are left.
//    track         = Display a position and destination marker for each unit.
//
// =========================================================================================================

if (!isServer) exitWith {};

// how far opfors should move away if they're under attack
// set this to 200-300, when using the script in open areas (rural surroundings)
#define SAFEDIST 75

// how close unit has to be to target to generate a new one 
#define CLOSEENOUGH 10

// how close units have to be to each other to share information
#define SHAREDIST 100

// how long AI units should be in alert mode after initially spotting an enemy
#define ALERTTIME 180

// ---------------------------------------------------------------------------------------------------------
//echo format["[K] %1",_this];

// convert argument list to uppercase
_UCthis = [];
for [{_i=0},{_i<count _this},{_i=_i+1}] do {_e=_this select _i; if (typeName _e=="STRING") then {_e=toUpper(_e)};_UCthis set [_i,_e]};

// ***************************************** SERVER INITIALIZATION *****************************************

// global functions
if (isNil("KRON_UPS_INIT")) then {
KRON_UPS_INIT=0;

// find a random position within a radius
KRON_randomPos = {private["_cx","_cy","_rx","_ry","_cd","_sd","_ad","_tx","_ty","_xout","_yout"];_cx=_this select 0; _cy=_this select 1; _rx=_this select 2; _ry=_this select 3; _cd=_this select 4; _sd=_this select 5; _ad=_this select 6; _tx=random (_rx*2)-_rx; _ty=random (_ry*2)-_ry; _xout=if (_ad!=0) then {_cx+ (_cd*_tx - _sd*_ty)} else {_cx+_tx}; _yout=if (_ad!=0) then {_cy+ (_sd*_tx + _cd*_ty)} else {_cy+_ty}; [_xout,_yout]};
// find any building (and its possible building positions) near a position
KRON_PosInfo = {private["_pos","_lst","_bld","_bldpos"];_pos=_this select 0; _lst= nearestObjects [_pos,["House","vbs2_house"],20]; if (count _lst==0) then {_bld=0;_bldpos=0} else {_bld=_lst select 0; _bldpos=[_bld] call KRON_BldPos}; [_bld,_bldpos]};
/// find the highest building position	
KRON_BldPos = {private ["_bld","_bi","_bldpos","_maxZ","_bp","_bz","_higher"];_bld=_this select 0;_maxZ=0;_bi=0;_bldpos=0;while {_bi>=0} do {_bp = _bld BuildingPos _bi;if ((_bp select 0)==0) then {_bi=-99} else {_bz=_bp select 2; _higher = ((_bz>_maxZ) || ((abs(_bz-_maxZ)<.5) && (random 1>.5))); if ((_bz>4) && _higher) then {_maxZ=_bz; _bldpos=_bi}};_bi=_bi+1};_bldpos};
KRON_OnRoad = {private["_pos","_car","_tries","_lst"];_pos=_this select 0; _car=_this select 1; _tries=_this select 2; _lst=_pos nearRoads 4; if ((count _lst!=0) && (_car || !(surfaceIsWater _pos))) then {_tries=99}; (_tries+1)};
KRON_getDirPos = {private["_a","_b","_from","_to","_return"]; _from = _this select 0; _to = _this select 1; _return = 0; _a = ((_to select 0) - (_from select 0)); _b = ((_to select 1) - (_from select 1)); if (_a != 0 || _b != 0) then {_return = _a atan2 _b}; if ( _return < 0 ) then { _return = _return + 360 }; _return};
KRON_distancePosSqr = {(((_this select 0) select 0)-((_this select 1) select 0))^2 + (((_this select 0) select 1)-((_this select 1) select 1))^2};
KRON_relPos = {private["_p","_d","_a","_x","_y","_xout","_yout"];_p=_this select 0; _x=_p select 0; _y=_p select 1; _d=_this select 1; _a=_this select 2; _xout=_x + sin(_a)*_d; _yout=_y + cos(_a)*_d;[_xout,_yout,0]};
KRON_rotpoint = {private["_cp","_a","_tx","_ty","_cd","_sd","_cx","_cy","_xout","_yout"];_cp=_this select 0; _cx=_cp select 0; _cy=_cp select 1; _a=_this select 1; _cd=cos(_a*-1); _sd=sin(_a*-1); _tx=_this select 2; _ty=_this select 3; _xout=if (_a!=0) then {_cx+ (_cd*_tx - _sd*_ty)} else {_cx+_tx}; _yout=if (_a!=0) then {_cy+ (_sd*_tx + _cd*_ty)} else {_cy+_ty}; [_xout,_yout,0]};
KRON_stayInside = {
	private["_np","_nx","_ny","_cp","_cx","_cy","_rx","_ry","_d","_tp","_tx","_ty","_fx","_fy"];
	_np=_this select 0;	_nx=_np select 0;	_ny=_np select 1;
	_cp=_this select 1;	_cx=_cp select 0;	_cy=_cp select 1;
	_rx=_this select 2;	_ry=_this select 3;	_d=_this select 4;
	_tp = [_cp,_d,(_nx-_cx),(_ny-_cy)] call KRON_rotpoint;
	_tx = _tp select 0; _fx=_tx;
	_ty = _tp select 1; _fy=_ty;
	if (_tx<(_cx-_rx)) then {_fx=_cx-_rx};
	if (_tx>(_cx+_rx)) then {_fx=_cx+_rx};
	if (_ty<(_cy-_ry)) then {_fy=_cy-_ry};
	if (_ty>(_cy+_ry)) then {_fy=_cy+_ry};
	if ((_fx!=_tx) || (_fy!=_ty)) then {_np = [_cp,_d*-1,(_fx-_cx),(_fy-_cy)] call KRON_rotpoint};
	_np;
};
// Misc
KRON_getArg = {private["_cmd","_arg","_list","_a","_v"]; _cmd=_this select 0; _arg=_this select 1; _list=_this select 2; _a=-1; {_a=_a+1; _v=format["%1",_list select _a]; if (_v==_cmd) then {_arg=(_list select _a+1)}} foreach _list; _arg};
KRON_deleteDead = {private["_u","_s"];_u=_this select 0; _s= _this select 1; _u removeAllEventHandlers "killed"; sleep _s; deletevehicle _u};

KRON_AllWest=[];
KRON_AllEast=[];
KRON_AllRes=[];
KRON_KnownEnemy=[objNull,objNull];

// find all units in mission
{
	_s = side _x;
	switch (_s) do {
		case west: 
			{ KRON_AllWest=KRON_AllWest+[_x]; };
		case east: 
			{ KRON_AllEast=KRON_AllEast+[_x]; };
		case resistance: 
			{ KRON_AllRes=KRON_AllRes+[_x]; };
	};
}forEach allUnits;

if (isNil("KRON_UPS_Debug")) then {KRON_UPS_Debug=0};
KRON_HQ="Logic" createVehicle [0,0];
KRON_UPS_Instances=0;
KRON_UPS_Total=0;
KRON_UPS_Exited=0;
KRON_UPS_INIT=1;
};
if ((count _this)<2) exitWith {
if (format["%1",_this]!="INIT") then {hint "UPS: Unit and marker name have to be defined!"};
};
_exit = false;
_onroof = false;

// ---------------------------------------------------------------------------------------------------------
waitUntil {KRON_UPS_INIT==1};
sleep (random 1);

KRON_UPS_Instances =	KRON_UPS_Instances + 1;

// get name of area marker 
_areamarker = _this select 1;
if (isNil ("_areamarker")) exitWith {
hint "UPS: Area marker not defined.\n(Typo, or name not enclosed in quotation marks?)";
};	

_centerpos = [];
_centerX = [];
_centerY = [];
_rangeX = 0;
_rangeY = 0;
_areadir = 0;
_areaname = "";
_areatrigger = objNull;
_showmarker = "HIDEMARKER";
_getAreaInfo = {
if (typeName _areamarker=="String") then {
	// remember center position of area marker
	_centerpos = getMarkerPos _areamarker;
	_centerX = abs(_centerpos select 0);
	_centerY = abs(_centerpos select 1);

	// X/Y range of target area
	_areasize = getMarkerSize _areamarker;
	_rangeX = _areasize select 0;
	_rangeY = _areasize select 1;
	// marker orientation (needed as negative value!)
	_areadir = (markerDir _areamarker) * -1;

	_areaname = _areamarker;

	// show area marker 
	_showmarker = if ("SHOWMARKER" in _UCthis) then {"SHOWMARKER"} else {"HIDEMARKER"};
	if (_showmarker=="HIDEMARKER") then {
		_areamarker setMarkerPos [-abs(_centerX),-abs(_centerY)];
	};
} else {
	_centerpos = getPos _areamarker;
	_centerX = abs(_centerpos select 0);
	_centerY = abs(_centerpos select 1);

	// X/Y range of target area
	_rangeX = triggerArea _areamarker select 0;
	_rangeY = triggerArea _areamarker select 1;
	// marker orientation (needed as negative value!)
	_areadir = (getDir _areamarker) * -1;

	_areaname = vehicleVarName _areamarker;
};
// update trigger position
if !(isNull _areatrigger) then {
	_areatrigger setPos [_centerX,_centerY];
};
};
[] call _getAreaInfo;
sleep .01;

// unit that's moving
_obj = _this select 0;		
_npc = _obj;
// is anybody alive in the group?
_exit = true;		
if (typename _obj=="OBJECT") then {
if (alive _npc) then {_exit = false;}		
} else {
if (count _obj>0) then {
	{if (alive _x) then {_npc = _x; _exit = false;}} forEach _obj;
};
};

// give this group a unique index
_grpidx = format["%1",KRON_UPS_Instances];
_grpname = format["%1_%2",(side _npc),_grpidx];

// remember the original group members, so we can later find a new leader, in case he dies
_members = units _npc;
KRON_UPS_Total = KRON_UPS_Total + (count _members);

// what type of "vehicle" is unit ?
_isman = _npc isKindOf "Man";
_iscar = _npc isKindOf "vbs2_LandVehicles";
_isboat = _npc isKindOf "Ship";
_isplane = _npc isKindOf "Air";

// check to see whether group is an enemy of the player (for attack and avoidance maneuvers)
// since countenemy doesn't count vehicles, and also only counts enemies if they're known, 
// we just have to brute-force it for now, and declare *everyone* an enemy who isn't a civilian
_issoldier = side _npc != civilian;

_friends=[];
_enemies=[];	
_sharedenemy=0;
//TODO: FIND A WAY TO DETERMINE ASSOCIATION OF RESISTANCE UNITS
if (_issoldier) then {
switch (side _npc) do {
	case west:
		{ _friends=_friends+KRON_AllWest; _enemies=_enemies+KRON_AllEast+KRON_AllRes; _sharedenemy=0; };
	case east:
		{ _friends=_friends+KRON_AllEast; _enemies=_enemies+KRON_AllWest+KRON_AllRes; _sharedenemy=1; };
	case resistance:
		{ _enemies=_enemies+KRON_AllEast+KRON_AllWest; _sharedenemy=2; };
};
{
	_friends=_friends-[_x];
	_x disableAI "autotarget";
} forEach _members;
};
sleep .01;

// global unit variable to externally influence script 
_named = false;
_npcname = str(side _npc);
if ("NAMED" in _UCthis) then {
_named = true;
_npcname = format["%1",_npc];
_grpidx = _npcname;
};
// create global variable for this group
call compile format ["KRON_UPS_%1=1",_npcname];

// store some trig calculations
_cosdir=cos(_areadir);
_sindir=sin(_areadir);

// minimum distance of new target position
if (_rangeX==0) exitWith {
hint format["UPS: Cannot patrol Sector: %1\nArea Marker doesn't exist",_areaname]; 
};
_mindist=(_rangeX^2+_rangeY^2)/4;

// remember the original mode & speed
_orgMode = behaviour _npc;
_orgSpeed = speedmode _npc;
_speedmode = _orgSpeed;

// set first target to current position (so we'll generate a new one right away)
_currPos = getpos _npc;
_orgPos = _currPos;
_orgWatch=[_currPos,50,getDir _npc] call KRON_relPos; 
_orgDir = getDir _npc;
_avoidPos = [0,0];
_flankPos = [0,0];
_attackPos = [0,0];

_dist = 0;
_lastdist = 0;
_lastmove1 = 0;
_lastmove2 = 0;
_maxmove=0;
_moved=0;

_damm=0;
_dammchg=0;
_lastdamm = 0;
_timeontarget = 0;

_fightmode = "walk";
_fm=0;
_gothit = false;
_hitPos=[0,0,0];
_react = 99;
_lastdamage = 0;
_lastknown = 0;
_opfknowval = 0;

_sin90=1; _cos90=0;
_sin270=-1; _cos270=0;

// set target tolerance high for choppers & planes
_closeenough=CLOSEENOUGH*CLOSEENOUGH;
if (_isplane) then {_closeenough=5000};

sleep .01;
// ***************************************** optional arguments *****************************************

// wait at patrol end points
_pause = if ("NOWAIT" in _UCthis) then {"NOWAIT"} else {"WAIT"};
// don't move until an enemy is spotted
_nomove  = if ("NOMOVE" in _UCthis) then {"NOMOVE"} else {"MOVE"};
// don't follow outside of marker area
_nofollow = if ("NOFOLLOW" in _UCthis) then {"NOFOLLOW"} else {"FOLLOW"};
// share enemy info 
_shareinfo = if ("NOSHARE" in _UCthis) then {"NOSHARE"} else {"SHARE"};
// "area cleared" trigger activator
_usetrigger = if ("TRIGGER" in _UCthis) then {"TRIGGER"} else {if ("NOTRIGGER" in _UCthis) then {"NOTRIGGER"} else {"SILENTTRIGGER"}};
// suppress fight behaviour
if ("NOAI" in _UCthis) then {_issoldier=false};
// adjust cycle delay 
_cycle = ["CYCLE:",5,_UCthis] call KRON_getArg;
// drop units at random positions
_initpos = "ORIGINAL";
if ("RANDOM" in _UCthis) then {_initpos = "RANDOM"};
if ("RANDOMUP" in _UCthis) then {_initpos = "RANDOMUP"}; 
if ("RANDOMDN" in _UCthis) then {_initpos = "RANDOMDN"}; 
// don't position groups or vehicles on rooftops
if ((_initpos!="ORIGINAL") && ((!_isman) || (count _members)>1)) then {_initpos="RANDOMDN"};
// set behaviour modes (or not)
_noslow = if ("NOSLOW" in _UCthis) then {"NOSLOW"} else {"SLOW"};
if (_noslow!="NOSLOW") then {
_npc setbehaviour "safe"; 
_npc setSpeedMode "limited";
_speedmode = "limited";
}; 

// make start position random 
if (_initpos!="ORIGINAL") then {
// find a random position (try a max of 20 positions)
_try=0;
_bld=0;
_bldpos=0;
while {_try<20} do {
	_currPos=[_centerX,_centerY,_rangeX,_rangeY,_cosdir,_sindir,_areadir] call KRON_randomPos;
	if ((_initpos=="RANDOMUP") || ((_initpos=="RANDOM") && (random 1>.75))) then {
		_posinfo=[_currPos] call KRON_PosInfo;
		// _posinfo: [0,0]=no house near, [obj,-1]=house near, but no roof positions, [obj,pos]=house near, with roof pos
		_bld=_posinfo select 0;
		_bldpos=_posinfo select 1;
	};
	if (_isplane || _isboat || !(surfaceiswater _currPos)) then {
		if (((_initpos=="RANDOM") || (_initpos=="RANDOMUP")) && (_bldpos>0)) then {_try=99};
		if (((_initpos=="RANDOM") || (_initpos=="RANDOMDN")) && (_bldpos==0)) then {_try=99};
	};
	_try=_try+1;
};
if (_bldpos==0) then {
	if (_isman) then {
		{_x setPos _currPos} foreach units _npc; 
	} else {
		_npc setPos _currPos;
	};
} else {
// put the unit on top of a building
	_npc setPos (_bld buildingPos _bldpos); 
	_npc setUnitPos "up";
	_currPos = getPos _npc;
	_onroof = true;
	_exit=true; // don't patrol if on roof
};
};
sleep .01;

// track unit
_track = 	if (("TRACK" in _UCthis) || (KRON_UPS_Debug>0)) then {"TRACK"} else {"NOTRACK"};
_trackername = "";
_destname = "";
if (_track=="TRACK") then {
_track = "TRACK";
_trackername=format["trk_%1",_grpidx];
_markerobj = createMarker[_trackername,[0,0]];
_markerobj setMarkerShape "ICON";
_markertype = if (isClass(configFile >> "cfgMarkers" >> "WTF_Dot")) then {"WTF_DOT"} else {"DOT"};
_trackername setMarkerType _markertype;
_markercolor = switch (side _npc) do {
	case west: {"ColorGreen"};
	case east: {"ColorRed"};
	case resistance: {"ColorBlue"};
	default {"ColorBlack"};
};
_trackername setMarkerColor _markercolor;
_trackername setMarkerText format["%1",_grpidx];
_trackername setmarkerpos _currPos; 
_trackername setMarkerSize [.5,.5];

_destname=format["dest_%1",_grpidx];
_markerobj = createMarker[_destname,[0,0]];
_markerobj setMarkerShape "ICON";
_markertype = if (isClass(configFile >> "cfgMarkers" >> "WTF_Flag")) then {"WTF_FLAG"} else {"FLAG"};
_destname setMarkerType _markertype;
_destname setMarkerColor _markercolor;
_destname setMarkerText format["%1",_grpidx];
_destname setMarkerSize [.5,.5];
};	
sleep .01;

// delete dead units
_deletedead = ["DELETE:",0,_UCthis] call KRON_getArg;
if (_deletedead>0) then {
{_x addEventHandler['killed',format["[_this select 0,%1] spawn KRON_deleteDead",_deletedead]]}forEach _members;
};

// how many group clones?
// TBD: add to global side arrays?
_mincopies = ["MIN:",0,_UCthis] call KRON_getArg;
_maxcopies = ["MAX:",0,_UCthis] call KRON_getArg;
if (_mincopies>_maxcopies) then {_maxcopies=_mincopies};
if (_maxcopies>140) exitWith {hint "Cannot create more than 140 groups!"};
if (_maxcopies>0) then {
if !(_isMan) exitWith {hint "Vehicles cannot be cloned."};
_copies=_mincopies+round(random (_maxcopies-_mincopies));
// any init strings?
_initstr = ["INIT:","",_UCthis] call KRON_getArg;

// name of clones
_nameprefix = ["PREFIX:","UPSCLONE",_UCthis] call KRON_getArg;

// create the clones
for "_grpcnt" from 1 to _copies do {
	// group leader
	_unittype=typeof _npc;
	// copy groups
	if (isNil ("KRON_cloneindex")) then {
		KRON_cloneindex = 0;
	}; 
	// make the clones civilians
	// use random Civilian models for single unit groups
	if ((_unittype=="Civilian") && (count _members==1)) then {_rnd=1+round(random 20); if (_rnd>1) then {_unittype=format["Civilian%1",_rnd]}};

	_grp=createGroup side _npc;
	_lead = _grp createUnit [_unittype, getpos _npc, [], 0, "form"];
	KRON_cloneindex = KRON_cloneindex+1;
	_lead setVehicleVarName format["%1%2",_nameprefix,KRON_cloneindex];
	call compile format["%1%2=_lead",_nameprefix,KRON_cloneindex];
	_lead setBehaviour _orgMode;
	_lead setSpeedMode _orgSpeed;
	_lead setSkill skill _npc;
	_lead setVehicleInit _initstr;
	[_lead] join _grp;
	_grp selectLeader _lead;
	// copy team members (skip the leader)
	_c=0;
	{
		_c=_c+1;
		if (_c>1) then {
			_newunit = _grp createUnit [typeof _x, getpos _x, [],0,"form"];
			KRON_cloneindex = KRON_cloneindex+1;
			_newunit setVehicleVarName format["%1%2",_nameprefix,KRON_cloneindex];
			call compile format["%1%2=_newunit",_nameprefix,KRON_cloneindex];
			_newunit setBehaviour _orgMode;
			_newunit setSpeedMode _orgSpeed;
			_newunit setSkill skill _x;
			_newunit setVehicleInit _initstr;
			[_newunit] join _grp;
		};
	} foreach _members;
	_nul=[_lead,_areamarker,_pause,_noslow,_nomove,_nofollow,_initpos,_track,_showmarker,_shareinfo,"DELETE:",_deletedead] execVM "ups.sqf";
	sleep .05;
};	
processInitCommands;
};
sleep .01;


// units that can be left for area to be "cleared"
_zoneempty = ["EMPTY:",0,_UCthis] call KRON_getArg;

// create area trigger
if (_usetrigger!="NOTRIGGER") then {
_trgside = switch (side _npc) do { case west: {"WEST"}; case east: {"EAST"}; case resistance: {"GUER"}; case civilian: {"CIV"};};
_trgname="KRON_Trig_"+_trgside+"_"+_areaname;
_flgname="KRON_Cleared_"+_areaname;
// has the trigger been created already?
KRON_TRGFlag=-1;
call compile format["%1=false",_flgname];
call compile format["KRON_TRGFlag=%1",_trgname];
if (isNil ("KRON_TRGFlag")) then {
	// trigger doesn't exist yet, so create one (make it a bit bigger than the marker, to catch path finding 'excursions' and flanking moves)
	call compile format["%1=createTrigger['EmptyDetector',[_centerX,_centerY]];",_trgname];
	call compile format["_areatrigger = %1",_trgname];
	call compile format["%1 setTriggerArea[_rangeX*1.5,_rangeY*1.5,markerDir _areaname,true]",_trgname];
	call compile format["%1 setTriggerActivation[_trgside,'PRESENT',true]",_trgname];
	call compile format["%1 setEffectCondition 'true'",_trgname];
	call compile format["%1 setTriggerTimeout [5,7,10,true]",_trgname];
	if (_usetrigger!="SILENTTRIGGER") then {
		_markerhide = [-_centerX,-_centerY];
		_markershow = [_centerX,_centerY];
		if (_showmarker=="HIDEMARKER") then {
			_markershow = [-_centerX,-_centerY];
		};
		call compile format["%1 setTriggerStatements['count thislist<=%6', 'titletext [''SECTOR <%2> CLEARED'',''PLAIN''];''%2'' setmarkerpos %4;%3=true;', 'titletext [''SECTOR <%2> HAS BEEN RE-OCCUPIED'',''PLAIN''];''%2'' setmarkerpos %5;%3=false;']", _trgname,_areaname,_flgname,_markerhide,_markershow,_zoneempty];
	} else {
		call compile format["%1 setTriggerStatements['count thislist<=%3', '%2=true;', '%2=false;']", _trgname,_flgname,_zoneempty];
	};
};
sleep .01;
};

// init done
_makenewtarget=true;
_newpos=false;
_targetPos = _currPos;
_swimming = false;
_waiting = if (_nomove=="NOMOVE") then {9999} else {0};

// exit if something went wrong during initialization (or if unit is on roof)
if (_exit) exitWith {
if ((KRON_UPS_DEBUG>0) && !_onroof) then {hint "Initialization aborted"};
};

// ***********************************************************************************************************
// ************************************************ MAIN LOOP ************************************************
_loop=true;
_currcycle=_cycle;
while {_loop} do {
sleep .01;
// keep track of how long we've been moving towards a destination
_timeontarget=_timeontarget+_currcycle;
_react=_react+_currcycle;

// did anybody in the group got hit?
_newdamage=0; 
{
	if((damage _x)>0.2) then {
		_newdamage=_newdamage+(damage _x); 
		// damage has increased since last round
		if (_newdamage>_lastdamage) then {
			_lastdamage=_newdamage; 
			_gothit=true;
		};
		_hitPos=getpos _x; 
		if (!alive _x) then {
			_members=_members-[_x]; 
			_friends=_friends-[_x]; 
		};
	};
} foreach _members;
sleep .01;

// nobody left alive, exit routine
if (count _members==0) then {
	_exit=true;
} else {
	// did the leader die?
	if (!alive _npc) then {
		_npc = _members select 0; 
		group _npc selectLeader _npc;
		if (isPlayer _npc) then {_exit=true};
	};
};

// current position
_currPos = getpos _npc; _currX = _currPos select 0; _currY = _currPos select 1;
if (_track=="TRACK") then { _trackername setmarkerpos _currPos; };

// if the AI is a civilian we don't have to bother checking for enemy encounters
if ((_issoldier) && ((count _enemies)>0) && !(_exit)) then {

	// if the leader comes across another unit that's either injured or dead, go into combat mode as well. 
	// If the other person is still alive, share enemy information.
	if ((_shareinfo=="SHARE") && (behaviour _npc=="SAFE")) then {
		_others=_friends-_members;
		{
			if ((!(isNull _x) && (_npc distance _x<SHAREDIST)) && ((damage _x>.5) || (behaviour _x in ["AWARE","COMBAT"]))) exitWith {
				_npc setBehaviour "aware"; 
				_gothit=true; 
				if ((_hitPos select 0)==0) then {_hitPos = getPos _x};
				if (_npc knowsabout _x>3) then {
					if (alive _x) then {_npc reveal (KRON_KnownEnemy select _sharedenemy)}; 
				};
			};
		}forEach _others;
	};
	sleep .01;

	// did the group spot an enemy?
	_lastknown=_opfknowval;
	_opfknowval=0; 
	_maxknowledge=0;
	{
		_knows=_npc knowsabout _x; 
		if ((alive _x) && (_knows>0.2) && (_knows>_maxknowledge)) then {
			KRON_KnownEnemy set [_sharedenemy,_x]; 
			_opfknowval=_opfknowval+_knows; 
			_maxknowledge=_knows;
		};
		if (!alive _x) then {_enemies=_enemies-[_x]};
		if (_maxknowledge==4) exitWith {};
	}forEach _enemies;
	sleep .01;

	_pursue=false;
	_accuracy=100;
	// opfor spotted an enemy or got shot, so start pursuit
	if (_opfknowval>_lastknown || _gothit) then {
		_npc setbehaviour "combat";
		_pursue=true;
		// make the exactness of the target dependent on the knowledge about the shooter
		_accuracy=21-(_maxknowledge*5);
	};

	if (isNull (KRON_KnownEnemy select _sharedenemy)) then {
		_pursue=false;
	};

	// don't react to new fatalities if less than 60 seconds have passed since the last one
	if ((_react<60) && (_fightmode!="walk")) then {_pursue=false};

	if (_pursue) then	{
		// get position of spotted unit in player group, and watch that spot
		_offsx=_accuracy/2-random _accuracy; _offsY=_accuracy/2-random _accuracy;
		_targetPos = getpos (KRON_KnownEnemy select _sharedenemy);
		_targetPos = [(_targetPos select 0) + _offsX, (_targetPos select 1) + _offsY];
		_targetX = _targetPos select 0; _targetY = _targetPos select 1;
		{_x dowatch _targetPos} foreach units _npc;
		sleep .01;			

		// also go into "combat mode"
		_npc setSpeedMode "full"; 
		_speedmode = "full";
		_npc setbehaviour "combat";
		_pause="NOWAIT";
		_waiting=0;

		// angle from unit to target
		_dir1 = [_currPos,_targetPos] call KRON_getDirPos;
		// angle from target to unit (reverse direction)
		_dir2 = (_dir1+180) mod 360;
		// angle from fatality to target
		_dir3 = if (_hitPos select 0!=0) then {[_hitPos,_targetPos] call KRON_getDirPos} else {_dir1};
		_dd=(_dir1-_dir3);

		// unit position offset straight towards target
		_relUX = sin(_dir1)*SAFEDIST; _relUY = cos(_dir1)*SAFEDIST;
		// target position offset straight towards unit
		_relTX = sin(_dir2)*SAFEDIST; _relTY = cos(_dir2)*SAFEDIST;
		// go either left or right (depending on location of fatality - or randomly if no fatality)
		_sinU=_sin90; _cosU=_cos90; _sinT=_sin270; _cosT=_cos270;
		if ((_dd<0) || (_dd==0 && (random 1)>.5)) then {_sinU=_sin270; _cosU=_cos270; _sinT=_sin90; _cosT=_cos90};

		// avoidance position (right or left of unit)
		_avoidX = _currX + _cosU*_relUX - _sinU*_relUY;
		_avoidY = _currY + _sinU*_relUX + _cosU*_relUY;
		_avoidPos = [_avoidX,_avoidY];
		// flanking position (right or left of target)
		_flankX = _targetX + _cosT*_relTX - _sinT*_relTY;
		_flankY = _targetY + _sinT*_relTX + _cosT*_relTY;
		_flankPos = [_flankX,_flankY];
		// final target position
		_attackPos = _targetPos;
		// for now we're stepping a bit to the side
		_targetPos = _avoidPos;

		if (_nofollow=="NOFOLLOW") then {
			_avoidPos = [_avoidPos,_centerpos,_rangeX,_rangeY,_areadir] call KRON_stayInside;
			_flankPos = [_flankPos,_centerpos,_rangeX,_rangeY,_areadir] call KRON_stayInside;
			_attackPos = [_attackPos,_centerpos,_rangeX,_rangeY,_areadir] call KRON_stayInside;
			_targetPos = [_targetPos,_centerpos,_rangeX,_rangeY,_areadir] call KRON_stayInside;
		};

		_react=0;
		_fightmode="fight";
		_timeontarget=0; 
		_fm=1;
		 if (KRON_UPS_Debug!=0) then {
			"dead" setmarkerpos _hitPos; "avoid" setmarkerpos _avoidPos; "flank" setmarkerpos _flankPos; "target" setmarkerpos _attackPos;
		};
		_newpos=true;
		// speed up the cycle duration after an incident
		if (_currcycle>=_cycle) then {_currcycle=1};
	};
}; 
sleep .01;

if !(_newpos) then {
	// calculate new distance
	// if we're waiting at a waypoint, no calculating necessary
	if (_waiting<=0) then {
		// distance to target
		_dist = [_currPos,_targetPos] call KRON_distancePosSqr;
		if (_lastdist==0) then {_lastdist=_dist};
		_moved = abs(_dist-_lastdist);
		// adjust the target tolerance for fast moving vehicles
		if (_moved>_maxmove) then {_maxmove=_moved; if ((_maxmove/40) > _closeenough) then {_closeenough=_maxmove/40}};
		// how much did we move in the last three cycles?
		_totmove=_moved+_lastmove1+_lastmove2;
		_damm = damage _npc;
		// is our damage changing (increasing)?
		_dammchg = abs(_damm - _lastdamm);

		// we're either close enough, seem to be stuck, or are getting damaged, so find a new target 
		if ((!_swimming) && ((_dist<=_closeenough) || (_totmove<.2) || (_dammchg>0.01) || (_timeontarget>ALERTTIME))) then {_makenewtarget=true;};

		// in 'attack (approach) mode', so follow the flanking path (don't make it too predictable though)
		if ((_fightmode!="walk") && (_dist<=_closeenough)) then {
			if ((random 1)<.95) then {
				if (_flankPos select 0!=0) then {
					_targetPos=_flankPos; _flankPos=[0,0]; _makenewtarget=false; _newpos=true;
					_fm=1;
				} else {
					if (_attackPos select 0!=0) then {
						_targetPos=_attackPos; _attackPos=[0,0]; _makenewtarget=false; _newpos=true;
						_fm=2;
					};
				};
			};
		};
		sleep .01;

		// make new target
		if (_makenewtarget) then {
			if ((_nomove=="NOMOVE") && (_timeontarget>ALERTTIME)) then {
				if (([_currPos,_orgPos] call KRON_distancePosSqr)<_closeenough) then {
					_newpos = false;
				} else {
					_targetPos=_orgPos;
				};
			} else {
				// re-read marker position/size
				[] call _getAreaInfo;
				// find a new target that's not too close to the current position
				_targetPos=_currPos;
				_tries=0;
				while {((([_currPos,_targetPos] call KRON_distancePosSqr) < _mindist)) && (_tries<20)} do {
					_tries=_tries+1;
					// generate new target position (on the road)
					_tries=0;
					while {_tries<20} do {
						_targetPos=[_centerX,_centerY,_rangeX,_rangeY,_cosdir,_sindir,_areadir] call KRON_randomPos; 
						if (_iscar) then {
							_roadlist = _targetPos nearRoads 100;
							if (count _roadlist>0) then {
								_targetPos = getPos (_roadlist select 0);
								_tries=99;
							};
						} else {
							_tries=99;
						};
						//_road=[_targetPos,(_isplane||_isboat),_road] call KRON_OnRoad;
						sleep .01;			
					};
				};
			};
			_avoidPos = [0,0]; _flankPos = [0,0]; _attackPos = [0,0];
			_gothit=false;
			_hitPos=[0,0,0];
			_fm=0;
			_npc setSpeedMode _orgSpeed;
			_newpos=true;

			// if we're waiting at patrol end points then don't create a new target right away. Keep cycling though to check for enemy encounters
			if ((_pause!="NOWAIT") && (_waiting<0)) then {_waiting = (15 + random 20)};
		};
	};
};
sleep .01;

// if in water, get right back out of it again
if (surfaceIsWater _currPos) then {
	if (_isman && !_swimming) then {
		_drydist=999;
		// look around, to find a dry spot
		for [{_a=0}, {_a<=270}, {_a=_a+90}] do {
			_dp=[_currPos,30,_a] call KRON_relPos; 
			if !(surfaceIsWater _dp) then {_targetPos=_dp};
		};
		_newpos=true; 
		_swimming=true;
	};
} else {
	_swimming=false;
};

_waiting = _waiting - _currcycle;
if ((_waiting<=0) && _newpos) then {
	// tell unit about new target position
	if (_fightmode!="walk") then {
		// reset patrol speed after following enemy for a while
		if (_timeontarget>ALERTTIME) then {
			_fightmode="walk";
			_speedmode = _orgSpeed;
			{
				_x setSpeedMode _speedmode;
				_x setBehaviour _orgMode;
			}forEach _members;
		};
		// use individual doMoves if pursuing enemy, 
		// as otherwise the group breaks up too much
		{_x doMove _targetPos}forEach _members;
	} else {
		(group _npc) move _targetPos;
		(group _npc) setSpeedMode _speedmode;
	};
	if (_track=="TRACK") then { 
		switch (_fm) do {
			case 1: 
				{_destname setmarkerSize [.4,.4]};
			case 2: 
				{_destname setmarkerSize [.6,.6]};
			default
				{_destname setmarkerSize [.5,.5]};
		};
		_destname setMarkerPos _targetPos;
	};
	_dist=0; 
	_moved=0; 
	_lastmove1=10; 
	_waiting=-1; 
	_newpos=false;
	_swimming=false;
	_timeontarget = 0; 
};

// move on
_lastdist = _dist; _lastmove2 = _lastmove1; _lastmove1 = _moved; _lastdamm = _damm;

// check external loop switch
_cont = (call compile format ["KRON_UPS_%1",_npcname]);
if (_cont==0) then {_exit=true};

_makenewtarget=false;
if ((_exit) || (isNil("_npc"))) then {
	_loop=false;
} else {
	// slowly increase the cycle duration after an incident
	if (_currcycle<_cycle) then {_currcycle=_currcycle+.5};
	sleep _currcycle;
};
};

if !(isNil("_npc")) then {
{doStop _x; _x domove getPos _x; _x move getPos _x} forEach _members;
};

KRON_UPS_Exited=KRON_UPS_Exited+1;
if (_track=="TRACK") then {
_trackername setMarkerType "Dot";
_destname setMarkerType "Empty";
};
_friends=nil;
_enemies=nil;

By the way, i tried to set the ki behaviour to safe manual by marker but the ups script set the behaviour back all 2~3 secounds so a secound script would do nothing :(

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
Sign in to follow this  

×