Jump to content

Recommended Posts

I have a script that displays score based on how the player kills an enemy using a Killed EH.

I would like the score that is displayed to add up for 5 seconds after a kill, resetting the timer back to 5 seconds if another kill is made (continuing to add up score), then have the score reset to 0 if the timer runs out.

 

I have something that kind of works but I'm struggling to do the timer bit.

 

Score earned is defined by 'ratingScore'.

Message is displayed by 'scoreMsg'.

scoreArr = [];
total = 0;

Obviously how I have it here without any formula around the sleep value, the score adds up for 5 seconds after the first kill, then resets & starts again when a kill is made after the 5 seconds.

if (ratingScore > 0)
then
{
	[] spawn
	{
		scoreArr pushBack ratingScore;
		{total = (_x + total)} forEach scoreArr;
		scoreArr call scoreMsg;
		scoreArr = [];
		sleep 5;
		total = 0;
	};
};

If anyone can help with this or knows a better way of adding up values in an array, I have a slightly out of date bottle of Tobasco sauce I would be more than willing to part with.

Many Thanks.

Share this post


Link to post
Share on other sites

Create a new variable and add 5 sec sleep to it for every additional kill after the first one. 

 

After 3 kills:

Sleep 5;

sleep TimeForAdditionalKills;

//Reset counter

 

I am at my phone so it's kinda tedious to write it down more detailed.

Share this post


Link to post
Share on other sites

I have tried something like this but I can't get it to work.  I'm obviously doing it wrong.

 

New variable,

sleepDelay = 0;

Then on each kill,

sleepDelay = sleepDelay + 5;

Then in code,

sleep sleepDelay;

This just has the exact same effect as with sleep 5.

 

The thing is though I don't want to keep adding time, I just want it so if the sleep timer hasn't reached zero yet & another kill is made then the sleep timer resets to 5.

So on each kill,

sleepDelay = 5;

Then maybe something like this:

if (ratingScore > 0)
then
{
	[] spawn
	{
		if (sleepDelay <= 0)
		exitWith {total = 0};
		scoreArr pushBack ratingScore;
		{total = (_x + total)} forEach scoreArr;
		scoreArr call scoreMsg;
		scoreArr = [];
		sleep sleepDelay;
	};
};

The only thing is sleepDelay doesn't count down within it's variable, it's always 5 so is there a way to maybe count this down or return the sleep value?

 

 

Share this post


Link to post
Share on other sites

Think I may have found a way using countdown function.

timeLeft = [0] call BIS_fnc_countdown;

Now I have a variable that counts down to 0 then resets to 5 when I get a kill.

if (ratingScore > 0)
then
{
	[5, false] call BIS_fnc_countdown;
	[] spawn
	{
		if (timeLeft <= 0)
		exitWith {total = 0};
		scoreArr pushBack ratingScore;
		{total = (_x + total)} forEach scoreArr;
		scoreArr call scoreMsg;
		scoreArr = [];
	};
};

Only problem now is the score does not display at all 😞

Share this post


Link to post
Share on other sites

Got it, doesn't seem to read timeLeft variable.

Doing it like this works:

if (ratingScore > 0)
then
{
	if (([0] call BIS_fnc_countdown) <= 0) then {total = 0;};
	[5, false] call BIS_fnc_countdown;
	[] spawn
	{
		scoreArr pushBack ratingScore;
		{total = (_x + total)} forEach scoreArr;
		scoreArr call scoreMsg;
		scoreArr = [];
	};
};

If there is a better / more optimized way of doing this your help will be much appreciated.

Share this post


Link to post
Share on other sites

Not sure this helps or not because I am not sure I have completely understood the purpose of your code. Nevertheless, one way to reset the counter on every kill is to use the Bohemia's function BIS_fnc_countDown like you found out yourself in conjunction with the "EntityKilled" mission event handler. This could possibly look like the following

// Declare some global parameters
score = 0;

// Add event handler to reset timer and increment the score
addMissionEventHandler ["EntityKilled", {
	params ["_unit"];

	// Check if killed unit is the player
	if(!(_unit isEqualTo player)) then {
		score = score + 1; // Increment score
		[5 false] call BIS_fnc_countDown; // Reset counter
	} else { // If player was killed
		score = 0; // Reset score
	};
}];

// "Spawn" code to run
[] spawn {
	// Run "forever"
	while{true} do {
		// Check if timer has reached 0
		if (!([true] call BIS_fnc_countDown)) then {
			score = 0; // Reset score
		};

		// Sleep to spare some CPU cycles
		uiSleep 1;
	};
};

You could place the presented code in init.sqf or use as you see fit. Please note that this is good for single player. If you try to use it on multiplayer (place the script in initPlayerLocal.sqf) the event handler will be called even if another player kills a unit which I am not sure whether it constitutes intended behavior or not...

 

Just to make sure everything is understood I will try to briefly explain all parts of the code...

 

1) Create a variable to hold the score (you already have that)...

2) Add an event handler that will be automatically called by the engine when an entity is killed. In the event handler you check that the unit killed is not the player and if this is the case you increase the score and reset the counter. Otherwise you reset the score (player died).

3) Then you spawn some code that runs continuously and in there you check if the timer has reached 0. In this case you reset the score. Finally, you can change the sleep duration if you see that the code is very slow to respond.

 

Hope this provides some insight in a different solution to your problem. Not sure if this is optimal in any sense as it constantly (every roughly one second) checks the timer. Additionally, please keep in mind that this snippet is not tested so it should be treated with caution.

 

Oh, and you should also add all the "print" calls in the mission event handler.

Share this post


Link to post
Share on other sites

Might be best to show you what I have, I'm sure it could use some serious refactoring.  I'll play the noob card here as I've only been doing this sort of thing in what little free time I've had for about the last 8 months.  Still learning.

 

I initially had a 'scoreMsg' to display the score but I thought it best to try to include it in the 'killMsg' for the ability to change the position on the screen easily if needed.  Reason being this is actually part of a mod I have on the workshop 'Kill Confirmed', which uses CBA setting so users can customize it to their liking.

 

The problem I'm having now is the first kill when the countdown starts presents 0 score.  Maybe you might be able to see where I've gone wrong?

Seems the score shown on the second kill is the score for the first kill if that makes sense.

 

initPlayerLocal.sqf

[] execVM "Kill_Confirmed.sqf";

Kill_Confirmed.sqf

sleep 0.5;

ratingScore = [];
assists = 0;
scoreArr = [];
total = 0;

#include "killMsg.sqf"

#include "EntityKilled.sqf"

#include "HitPart.sqf"

#include "HandleDamage.sqf"

killMsg.sqf

killMsg =
{
	private _messages = _this;
	private _messageContent = "<t align='right'>";
	{
		_messageContent = _messageContent + format ["<t font='PuristaSemibold' size='1.25'>%1</t><br/>", killType];
	} 
	forEach _messages;
	_messageContent = _messageContent + "</t>";
	if (ratingScore > 0)
	then
	{
		if (([0] call BIS_fnc_countdown) <= 0) then {total = 0;};
		[4, false] call BIS_fnc_countdown;
		[] spawn
		{
			scoreArr pushBack ratingScore;
			{total = (_x + total)} forEach scoreArr;
			scoreArr = [];
		};
		_messageContent = _messageContent + (format ["<t align='right' color='#ffff00' font='PuristaBold' size='1.4'>+%1</t>", total]);
	};
	[parseText _messageContent, [safezoneX, safezoneY + safeZoneH * 0.51, safezoneW * 0.62, safeZoneH * 0.57], nil, 3, 0.7, 0] spawn BIS_fnc_textTiles;
};

EntityKilled.sqf

addMissionEventHandler ["EntityKilled",
{
	params ["_killed", "_killer", "_instigator"];
	
	if(!local player) exitWith {};
	
	isFriendly = [(side group _killer),(side group _killed)] call BIS_fnc_sideIsFriendly;
	private _distance = _killer distance _killed;
	private _minDistance = 100;
	private _cqbDistance = 2;
	private _assisters = (_killed getVariable ["shooterIndex",[]]) - [_instigator, objNull];
	_assisters = if (_assisters isEqualTo []) then [{""},{format ["assisters: %1", _assisters apply {name _x}] }];
	
	kill = {[[killType]] call killMsg;};
	
	if (isNull _instigator)
	then
	{
		_instigator = _killer;
	};
	if (((driver (vehicle player)) isEqualTo player) && (player isEqualTo _killer))
	then
	{
		if (((vehicle player isKindOf "LandVehicle") || (vehicle player isKindOf "Air") || (vehicle player isKindOf "Ship")) && (_killed isKindOf "CAManBase"))
		then
		{
			if !(isFriendly)
			then
			{
				killType = "ROAD KILL";
				ratingScore = 50;
				player spawn kill;
			};
		}
		else
		{
			if ((!(vehicle player isKindOf "LandVehicle") && !(vehicle player isKindOf "Air") && !(vehicle player isKindOf "Ship")) && (_killed isKindOf "CAManBase"))
			then
			{
				if !(isFriendly)
				then
				{
					if (head)
					then
					{
						if (_distance >= _minDistance)
						then
						{
							killType = "HEADSHOT";
							ratingScore = 200;
							player spawn kill;
						}
						else
						{
							if (_distance <= _cqbDistance)
							then
							{
								killType = "HEADSHOT";
								ratingScore = 175;
								player spawn kill;
							}
							else
							{
								if ((_distance > _cqbDistance && {_distance < _minDistance}))
								then
								{
									killType = "HEADSHOT";
									ratingScore = 150;
									player spawn kill;
								};
							};
						};
					}
					else
					{
						if !(head)
						then
						{
							if !(frag)
							then
							{
								if (_distance >= _minDistance)
								then
								{
									killType = "LONG RANGE KILL";
									ratingScore = 150;
									player spawn kill;
								}
								else
								{
									if (_distance <= _cqbDistance)
									then
									{
										killType = "POINT BLANK KILL";
										ratingScore = 125;
										player spawn kill;
									}
									else
									{
										if ((_distance > _cqbDistance && {_distance < _minDistance}))
										then
										{
											killType = "ENEMY KILLED";
											ratingScore = 100;
											player spawn kill;
										};
									};
								};
							}
							else
							{
								if (frag)
								then
								{
									if (_distance >= _minDistance)
									then
									{
										killType = "EXPLOSIVE KILL";
										ratingScore = 150;
										player spawn kill;
									}
									else
									{
										if (_distance <= _cqbDistance)
										then
										{
											killType = "EXPLOSIVE KILL";
											ratingScore = 125;
											player spawn kill;
										}
										else
										{
											if ((_distance > _cqbDistance && {_distance < _minDistance}))
											then
											{
												killType = "EXPLOSIVE KILL";
												ratingScore = 100;
												player spawn kill;
											};
										};
									};
								};
							};
						};
					};
				};
			};
		};
	};
	if (vehicle player isEqualTo _killer)
	then
	{
		if (((vehicle player isKindOf "LandVehicle") || (vehicle player isKindOf "Air") || (vehicle player isKindOf "Ship")) && (_killed isKindOf "CAManBase"))
		then
		{
			if !(isFriendly)
			then
			{
				killType = "VEHICLE KILL";
				ratingScore = 50;
				player spawn kill;
			};
		};
	};
	if ((player in (UAVControl vehicle _killer)) && (_killed isKindOf "CAManBase"))
	then
	{
		if !(isFriendly)
		then
		{
			killType = "DRONE KILL";
			ratingScore = 50;
			player spawn kill;
		};
	};
	if (!((driver (vehicle player)) isEqualTo _killer) && {!(player isEqualTo _killed)})
	then
	{
		if (name player in _assisters)
		then
		{
			if !(isFriendly)
			then
			{
				killType = "ASSIST";
				ratingScore = 20;
				assists = assists + 1;
				player spawn kill;
			};
		};
	};
}];

HitPart.sqf

0 = [] spawn
{
	while {true} do
	{
		{
			_x addEventHandler ["HitPart",
			{
				(_this select 0) params ["_target", "_shooter", "_projectile", "_position", "_velocity", "_selection", "_ammo", "_vector", "_radius", "_surfaceType", "_isDirect"];
				head = ("head" in (_this select 0 select 5));
				frag = (_isDirect isEqualTo false);
			}];
		_x setVariable ["passedThatHitPart",TRUE];
		} forEach (allUnits select {isNil {_x getVariable "passedThatHitPart"}});
	sleep 2;
	};
};

HandleDamage.sqf

0 = [] spawn
{
	while {true} do
	{
		{
			_x  setVariable ["shooterIndex",[]];
			_x  addEventHandler ["HandleDamage",
			{
				params ["_unit", "_selection", "_damage", "_source", "_projectile", "_hitIndex", "_instigator", "_hitPoint"];
				(_unit getVariable "shooterIndex") pushBackUnique _instigator;
				_damage
			}];
		_x setVariable ["passedThatHandleDamage",TRUE];
		} forEach (allUnits select {isNil {_x getVariable "passedThatHandleDamage"}});
	sleep 2;
	};
};

 

Share this post


Link to post
Share on other sites

Hhhhmmmm, it seems that, since the variable killType is set inside the EntityKilled event handler, but is done so after its first call, which is somewhere in the first lines of the code in the event handler. This means that the first time it is called is nil while the second time you call it has the information of the first call.

 

I haven't tested it but I believe that this is the issue here...

 

One additional comment is that you could set the

killType = "HEADSHOT";

right after the "head check". This could look like (copying your code)

if (head) then {
	killType = "HEADSHOT";
	// Here go all the other checks you do
};

The same goes for the "EXPLOSIVE KILL" which could go right after the "frag check". Neither the result nor the efficiency of the code will change but it is good coding practice to avoid redundancy whenever possible. Most often than not this makes code more readable and easier to debug/maintain. This way, if you decide to change the "title" of the kill you will have to do it only in one place thus avoiding "bugs" (well, this may not qualify as a bug since it won't affect the behavior of the code but I believe you get the idea).

 

Please let us know if this solves your issue or you may need further assistance.

Share this post


Link to post
Share on other sites

Doesn't seem to change anything, the 'killType' shows on the first kill, which wasn't the problem, it's the score returning 0.  I think it has something to do with the score array 'scoreArr' , perhaps the placement of it or the formula for summing up the values.

It works when I separate it from the 'killType' notification, but then the notification doesn't show.  I'm guessing because you can't have 2 BIS_fnc_textTiles running because if I disable the score the notification shows & vice versa.

 

Score works when I have this in the Entity Killed EH:

if (ratingScore > 0)
then
{
	if (([0] call BIS_fnc_countdown) <= 0) then {total = 0;};
	[4, false] call BIS_fnc_countdown;
	[] spawn
	{
		scoreArr pushBack ratingScore;
		{total = (_x + total)} forEach scoreArr;
		scoreArr call scoreMsg;
		scoreArr = [];
	};
};

Then scoreMsg is:

scoreMsg = {[parseText format ["<t align='right' color='#ffff00' font='PuristaBold' size='1.4'>+%1</t>", total], [safezoneX, safezoneY + safeZoneH * 0.62, safezoneW * 0.475, safeZoneH * 1], nil, 3, 0.7, 0] spawn BIS_fnc_textTiles;};

Another option could be to use a different code for the notifications.  It's not mine though, found it on a thread for a kill feed a while back.  It's nice but it opens up another out of date bottle of Tobasco sauce.

I adapted it to work for my killTypes, but for some reason if you get 2 or more kills at the exact same time (explosive kills mainly), the notifications don't animate & refuse to be deleted, then any notifications after just intersect.  Using a ctrlSetFade makes them disappear but technically they're still there & cause performance issues if they build up.

 

Here's the code anyway should you know why it happens:

killMsg =
{
	private _text = format ["%1", killType];
	disableSerialization;
	{
		_ctrl = (findDisplay 46) displayCtrl _x;
		_pos = ctrlPosition _ctrl;
		_pos set [1, (_pos select 1) + 0.04];
		_ctrl ctrlSetPosition _pos;
		_ctrl ctrlCommit 0.25;
	} forEach actKillCtrls;

	sleep 0.25;
	
	_ctrl = (findDisplay 46) ctrlCreate ["RscText", _this select 0];
	_ctrl ctrlSetPosition [0.48 * safezoneW + safezoneX, 0.138 * safezoneH + safezoneY, 1 * safezoneW, 1 * safezoneH];
	_ctrl ctrlSetFont "PuristaSemibold";
	_ctrl ctrlSetFontHeight 0.05;
	_ctrl ctrlSetTextColor [1, 1, 1, 1];
	_ctrl ctrlSetText _text;
	_ctrl ctrlCommit 0;

	0 = (_this select 0) spawn
	{
		disableSerialization;
		_ctrl = (findDisplay 46) displayCtrl _this;
		sleep 4;
		ctrlDelete _ctrl;
		actKillCtrls = actKillCtrls - [_this];	
	};
	actKillCtrls = [_this select 0] + actKillCtrls;
	killCtrl = killCtrl + 1;
};

Outside of this code is defined:

killCtrl = 2000;
actScoreCtrls = [];

Then the code to call:

[killCtrl, _this select 0] spawn killMsg;

I appreciate you taking time to try & help.  Thank you!

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

×