Another Array Question #2

How would I set an Array at the index of the slot of a player?

So im trying to keep track of players with in a specified AOE (players w/in Radius of a point) And populate this Variable (array) to those players, but at the index value OF the array, corresponding to the Slot OF each player.

Example:
Set Var A: Players within Radius (Vector XYZ).
Let’s say there are 6 players on a team. & lets say Players in Slot 0, 2 & 4 are within radius of Vector xyz.
So, i want Variable A to look like:
Index 0: Player Charlie
Index 1: 0
Index 2: Player Alpha
Index 3: 0
Index 4: Player Bravo
Index 5: 0

IF i were to simply set Var A to Players within Radius. It would set Var A at Index 0, 1 & 2 to those players.

Normally this wouldn’t be a problem, However, when I add an Effect and a Damage Over Time to these players, It becomes complicated. I don’t know how to Remove Effect/Stop DOT from a specific player as other players are added to the list or are removed from the list (as the get closer or further away from Vector XYZ)
And to complicate things even further, Vector XYZ may Not be the only point at a given time on the map & some points could Overlap. So a player could be part of 2 or more arrays. Each w/ an effect attached TOO that player & a DOT.

Without locking a player to a given Index value, the array will shuffle its self around as players are Added to/Removed from the list. I don’t think Sorting the array will help either.

Any suggestions?
If needed, i have a Scrip that works right now, however, it only works w/ the assumption that there Can’t be more then 1 Vector XYZ at a time.

rule("Rule 24")
{
	event
	{
		Ongoing - Each Player;
		Team 1;
		All;
	}

	conditions
	{
		Is Button Held(Event Player, Button(Interact)) == True;
	}

	actions
	{
		Global.A = Mapped Array(All Players(Team 2), Array Contains(Players Within Radius(Event Player, 5, Team 2, Off),
			Current Array Element));
	}
}

rule("Rule 25")
{
	event
	{
		Ongoing - Each Player;
		Team 2;
		All;
	}

	conditions
	{
		Global.A[Index Of Array Value(All Players(Team 2), Event Player)] == True;
	}

	actions
	{
		Small Message(All Players(All Teams), Custom String("Hi :>"));
	}
}

Turning this into something working with multiple positions would be ugh
You’d need to set Global.A at the Index of the Position then run the Set Global A for every Index and Duplicate the Second Rule for every position, (If they’re static or there’s a reasonable maximum number of possibilities; I HOPE) if not have fun with that mess.


It would also be possible to get the maximum number of players into 1 array and just multiply their slot number by 2 if they’re on team 2


For something like this the Values Condition Is True; and Condition Is False would be godly as you’d simply be able to tell the rule to wait until the condition is no longer met and then execute the code to remove said effects from the player.

1 Like

Ya, i kinda tried what u posted, but couldn’t use it for the way I needed it to work.

Tell ya what; Here’s my code. This works fine as long as there’s only 1 hero per team using this. What i need to convert it to thou is for it to function correctly if i turn off Hero Limits, and all 6 ppl on a team went this hero.

variables
{
	player:
		11: IDs
		15: SharedVar
		22: Cooldown
}

rule("Winston Unique 2: Tesla Orb (Main)")
{
	event
	{
		Ongoing - Each Player;
		All;
		Winston;
	}

	conditions
	{
		Is Button Held(Event Player, Button(Secondary Fire)) == True;
		Is Button Held(Event Player, Button(Interact)) == True;
		Is Using Ultimate(Event Player) == False;
		Is Alive(Event Player) == True;
		disabled Is Using Ultimate(Event Player) == False;
		disabled Event Player.Cooldown[0] == 0;
	}

	actions
	{
		Create HUD Text(Event Player, Custom String("Charge Level: {0}%", Round To Integer(Event Player.A * 200, To Nearest)), Null, Null,
			Top, 1, Event Player.A != 0.500 ? Color(White) : Color(Red), Color(White), Color(White), String and Color, Default Visibility);
		Event Player.IDs[0] = Last Text ID;
		Wait(0.016, Ignore Condition);
		"What Player Sees"
		Create Effect(Event Player, Good Aura, Color(Purple), Eye Position(Event Player) + World Vector Of(Vector(-0.050, -0.200, 0),
			Event Player, Rotation) + Facing Direction Of(Event Player) * 0.600, Event Player.A / 5, Position and Radius);
		Event Player.IDs[1] = Last Created Entity;
		"What Everyone Else sees"
		Create Effect(Remove From Array(All Players(All Teams), Event Player), Sphere, Color(Purple), Update Every Frame(Eye Position(
			Event Player) + World Vector Of(Vector(-0.550, -1, 0), Event Player, Rotation) + Facing Direction Of(Event Player) * 2),
			Event Player.A / 2, Position and Radius);
		Event Player.IDs[2] = Last Created Entity;
		Wait(0.016, Ignore Condition);
		Chase Player Variable Over Time(Event Player, A, 0.500 * 1, 3, None);
		Wait Until(!Is Button Held(Event Player, Button(Secondary Fire)) || Is Button Held(Event Player, Button(Primary Fire)), 10);
		Stop Chasing Player Variable(Event Player, A);
		Destroy HUD Text(Event Player.IDs[0]);
		Destroy Effect(Event Player.IDs[1]);
		Destroy Effect(Event Player.IDs[2]);
		Wait(0.016, Ignore Condition);
		"Create Tesla Orb"
		If(!Is Button Held(Event Player, Button(Primary Fire)));
			Event Player.B = Eye Position(Event Player);
			Event Player.C = Ray Cast Hit Position(Eye Position(Event Player), Eye Position(Event Player) + Facing Direction Of(Event Player)
				* 50, Null, All Players(All Teams), False);
			"Distance Check"
			If(Distance Between(Event Player, Event Player.C) > 8);
				Create Effect(All Players(All Teams), Sphere, Color(Purple), Event Player.B, Event Player.A / 2, Position and Radius);
				Event Player.IDs[3] = Last Created Entity;
				Wait(0.016, Ignore Condition);
				Chase Player Variable At Rate(Event Player, B, Event Player.C, 7.500, None);
				"Victim Array Set Loop"
				While(Event Player.B != Event Player.C);
					Players Within Radius(Event Player.B, 7.500, Opposite Team Of(Team Of(Event Player)), Surfaces And Enemy Barriers)
						.SharedVar[0] = Event Player;
					Wait(0.240, Ignore Condition);
				End;
				Stop Chasing Player Variable(Event Player, B);
				Event Player.B = Null;
				disabled Event Player.Cooldown[0] = 30;
				Destroy Effect(Event Player.IDs[3]);
				Wait(0.016, Ignore Condition);
				Play Effect(All Players(All Teams), Ring Explosion, Color(Purple), Event Player.C, Event Player.A * 10);
				Damage(Players Within Radius(Event Player.C, Event Player.A * 10, Opposite Team Of(Team Of(Event Player)), Surfaces), Event Player,
					Event Player.A * 200);
			Else;
				Small Message(Event Player, Custom String("Distance too Close. Tesla Orb Aborted"));
			End;
		Else;
			Small Message(Event Player, Custom String("Tesla Orb Terminated"));
		End;
		Wait(0.064, Ignore Condition);
		Event Player.A = Null;
		End;
	}
}

rule("Winston Unique 2: Tesla Orb (Effect)")
{
	event
	{
		Ongoing - Each Player;
		All;
		All;
	}

	conditions
	{
		Event Player.SharedVar[0] == True;
	}

	actions
	{
		Create Beam Effect(All Players(All Teams), Bad Beam, Event Player, Event Player.SharedVar[0].B, Color(Blue), Position and Radius);
		Event Player.SharedVar[1] = Last Created Entity;
		Wait(0.016, Ignore Condition);
		Start Damage Over Time(Event Player, Event Player.SharedVar[0], 15, 50 * Event Player.SharedVar[0].A);
		Event Player.SharedVar[2] = Last Damage Over Time ID;
		Wait Until(Distance Between(Event Player, Event Player.SharedVar[0].B) > 8 || Event Player.SharedVar[0].B != True, 20);
		Destroy Effect(Event Player.SharedVar[1]);
		Stop Damage Over Time(Event Player.SharedVar[2]);
		Event Player.SharedVar[0] = False;
	}
}

I Did come up with a way that IS specific to each player. So there could be several hero’s (in this case, Monkey) who could use this at the say time. However, it’s…ugly. It has to loop over Creating & Destroying the Effects & DOT every time the list changes (Variable X Array) which can happen several times a sec as it passes by a group of players…

If I understood correctly what you want to achieve, you can do it rather easily.

First you need an array in wich you will store the “tesla orbs”. They are arrays themself consisting of:

  • their position
  • their radius (if you want to make it dynamic)
  • the player who owns it (to only affect the other team / other players depending on the gamemode)
  • the effect id (to destroy it)
  • the creation time (total time elapsed - to remove the tesla orb after some time has passed)

Create a rule that checks if its true for any of the tesla orb array that the event player is in the range of its radius.
If this is the case filter the tesla orb array for all the orbs the event player is in its radius.
Destroy all the DOTs on the event player and create a new one for each of the orbs the event player is close to.
If it is not true for all of the tesla orb, that the event player is outside of their radius, loop the rule at a reasonable rate.

1 Like

Hey thx for the input. When you say, “loop at a reasonable rate”, what’s looping? Any chance you could write my something like what your talking about? I honestly can’t put together what your explaining.

A loop is a basic control structure in programming. It repeats a block of code lines over and over again.

I made a simplified version of what I was describing earlier:

variables
{
	global:
		0: teslaOrbs
		1: teslaOrbsLastId

	player:
		0: orbPos
		1: tempArray
		2: orbsInRange
		3: loopCounter
}

rule("initialisation")
{
	event
	{
		Ongoing - Global;
	}

	actions
	{
		Global.teslaOrbs = Empty Array;
		Global.teslaOrbsLastId = 0;
	}
}

rule("tesla orbs")
{
	event
	{
		Ongoing - Each Player;
		All;
		Winston;
	}

	conditions
	{
		Is Dummy Bot(Event Player) == False;
		Is Alive(Event Player) == True;
		Is Button Held(Event Player, Button(Interact)) == True;
	}

	actions
	{
		Event Player.orbPos = Vector(1, 2, 3);
		Create Effect(All Players(All Teams), Orb, Color(Purple), Event Player.orbPos, 1, Visible To Position and Radius);
		Event Player.tempArray = Array(Event Player.orbPos, Event Player, Last Created Entity, Total Time Elapsed);
		Global.teslaOrbs[Global.teslaOrbsLastId] = Event Player.tempArray;
		Global.teslaOrbsLastId += 1;
	}
}

rule("player is in range of tesla orbs")
{
	event
	{
		Ongoing - Each Player;
		All;
		All;
	}

	conditions
	{
		Is Dummy Bot(Event Player) == False;
		Is Alive(Event Player) == True;
		Is True For Any(Global.teslaOrbs, Current Array Element[1] != Event Player && Distance Between(Event Player,
			Current Array Element[0]) <= 1) == True;
	}

	actions
	{
		Event Player.orbsInRange = Filtered Array(Global.teslaOrbs, Current Array Element[1] != Event Player && Distance Between(
			Event Player, Current Array Element[0]) <= 1);
		Stop All Damage Over Time(Event Player);
		For Player Variable(Event Player, loopCounter, 0, Count Of(Event Player.orbsInRange), 1);
			Start Damage Over Time(Event Player, Event Player.orbsInRange[Event Player.loopCounter][1], 9999, 20);
		End;
		Wait(0.500, Ignore Condition);
		Loop If Condition Is True;
		Stop All Damage Over Time(Event Player);
	}
}

In the last rule you can see 2 loops. The first one being a for loop, wich repeats the actions between the for and the end a set number of times. The second one being a do…while loop (in workshop it is just called “loop”) wich repeats all actions above of it until its conditions is false.
Also, the wait action before the loop is important, so workshop doesn’t try to loop an infinite amount of times in a single frame.

1 Like

Hey, appreciate the input. However, your code, doesn’t seem to do anything. Am i supposed to integrate it into something? I was hoping, after looking it over, to see how it worked in the inspector…But the “player is in range of tesla orbs” part, doesn’t do anything. For one, what’s with the vector 1,2,3?
I changed ‘that’ to Position Of Eventplayer, and still nothing happened…even with me or a Bot (a normal AI bot, not a dummy bot) standing on top of the purple orb the 1st part creates, nothing happens. (Changed the Distance Between value to 5 too)
So, i removed the Is Dummy Bot Conditions, Create a dummy Winston bot that, once spawned, presses Interact to initiate the script. And, well the 2nd part does show up in the inspector, but just loops endlessly. Nothing happens. OrbsinRange variable never populates.

TLDR;
I don’t mean to pry, im not asking anyone to write my game for me. But this issue has me stumped.
Keep in mind, while I won’t call myself an expert by any means, i DO consider myself fairly capable in working w/ this Workshop. I’ve build several game modes in this Workshop, One I’ve worked on ever since workshop came out. All built from scratch, by myself. 223 Rules. Over 30k Total Element Count.

Yes, I meant you to adjust the code you have in a way that it works similar to my example, wich is why you should use your actions to create a tesla orb.

Its just an example, cause i wanted to keep it simple. Of course, in your mode it is not just 1,2,3, but the position the winstons are aiming towards.

That one is on me, I forgot to change the ‘==’ to ‘!=’ in the first action of the rule. So the actions should look like that instead (i fixed it in the original post aswell):
Event Player.orbsInRange = Filtered Array(Global.teslaOrbs, Current Array Element[1] != Event Player && Distance Between(Event Player, Current Array Element[0]) <= 1);

I’m sorry, I didn’t test my code, since I couldn’t invest to much time and recreate everything like your code, so I went with a simplified example to demonstrate you the idea I had.

So the idea is to populate an array with all the information needed about a single tesla orb, so it works like a tesla orb object, then put all the tesla orb objects (= arrays) into a global array.
Each player then filters the array for himself and checks wether close to any orbs he doesn’t own himself.

I hope this will help you.

1 Like

Ah ok, i see it working now… If you mind, few more questions.

  1. OrbsinRange & teslaOrbs populates with ‘Array of 4’. Now whenever i saw this before, i assumed it was a screw up on my part, but you did this intentionally right? An Array within an array? I thought those weren’t allowed in workshop? Does this mean any part of the Player Var tempArray can be referenced From this? By stating Index OF this ‘array of 4’? Cuz i see you calling out the Index OF this, in the Damager Credit part OF the DOT action.
    .
  2. So i like how you use the For Loop to start a DOT per orb that is in range. However, after the loop, it’s a standard wait action. If i were to have a Wait Until action, how would word it so it waits until;
  • Distance between Eventplayer and any of the orbs is > value
    or
  • the Orb(s) no longer exist
    or
  • Event Player died

& then, (assuming the player Is still alive) stop the DOT only from the orb(s) that are too far away/no longer exist. You use a Stop ALL DOTs action. I can’t use this because the ‘Winston Unique 2: Tesla Orb’ isn’t the only scripted ability in the game that has DOT. Thus may Not be the only DOT the eventplayer has actively damage them atm.

  1. Im my case, my “ability” is a projectile, so it’s moving. With a moving point, how does orbPos update? Do have to loop it insanely fast? You reference the orb’s position for orbsInRange by the Index 1 OF Global.teslaOrbs. Obviously after the initial setting OF Global.teslaOrbs, its position is changing.
    .
  2. Similar to Issue 2; a Beam effect is created from Eventplayer to the Orb. And this effect is destroyed same time as the DOT. Same issue, I have to stop each effect individually. I can’t destroy all effects across the map.

Yes it is intentional and it works totally fine. I actually used an array of 3 dimensions in one of my gamemodes, so I just needed to change the indices in some in world texts.
Yes you can reference any part of the “Array of 4”.
To create an array as the value of an array index, you can’t use the action modify global variable(A, append to array, array) since this just merges both arrays together.
Instead you need to use the actions set global variable at index(A, index, array). So if you want to dynamically append arrays as values, you need to keep track of the last index of work with count of(array) as the index.

is dead(event player) || count of(global.teslaOrbs) == 0 || is true for any(event player.orbsInRange, distance between(event player, current array element[0]) > 1)

Though it wont be that easy. What happens, if a player is within 2 orbs and then gets within another one?
The rule “player is in range of tesla orbs” could potentially be reworked by comparing the event player.orbsInRange array to the teslaOrbs array fitlered by distance between event player and tesla orbs, but I would have to use is true for any(sorted array(filtered array(Global.teslaOrbs))) in the conditions and I’m not sure if it works to nest sorted array(), filtered array() etc, since I would use “current array element” multiple times. Also, the rule wouldn’t necessarily be better.

My usage of Stop All Damage Over Time(Event Player); was a very simple approach here. But it can easily improved like this:

rule("player is in range of tesla orbs")
{
	event
	{
		Ongoing - Each Player;
		All;
		All;
	}

	conditions
	{
		Is Dummy Bot(Event Player) == False;
		Is Alive(Event Player) == True;
		Is True For Any(Global.teslaOrbs, Current Array Element[1] != Event Player && Distance Between(Event Player,
			Current Array Element[0]) <= 1) == True;
	}

	actions
	{
		Event Player.orbsInRange = Filtered Array(Global.teslaOrbs, Current Array Element[1] != Event Player && Distance Between(
			Event Player, Current Array Element[0]) <= 1);
		For Player Variable(Event Player.loopCounter, 0, Count Of(Event Player.dotIds), 1);
                        Stop Damage Over Time(Event Player.dotIds[Event Player.loopCounter]);
                End;
                Event Player.dotIds = Empty Array;
		For Player Variable(Event Player, loopCounter, 0, Count Of(Event Player.orbsInRange), 1);
			Start Damage Over Time(Event Player, Event Player.orbsInRange[Event Player.loopCounter][1], 9999, 20);
                        Modify Player Variable(Event Player.dotIds, Append To Array, Last Damage Over Time Id);
		End;
		Wait(0.500, Ignore Condition);
		Loop If Condition Is True;
		For Player Variable(Event Player.loopCounter, 0, Count Of(Event Player.dotIds), 1);
                        Stop Damage Over Time(Event Player.dotIds[Event Player.loopCounter]);
                End;
                Event Player.dotIds = Empty Array;
	}
}

You can add another value to the Event Player.tempArray (lets say on index 4) before adding the tempArray to Global.teslaOrbs. This value woud be the direction vector of your orb.
Then you create a rule that updates the positions of the orbs:

rule

condition:
 - count of(global.teslaOrbs) > 0

action:
 - for(global.loopCounter, 0, count of(global.teslaOrbs), 1)
 - global.teslaOrbs[loopCounter][0] += global.teslaOrbs[loopCounter][4]
 - *if you want collision you can check it here and potentially set global.teslaOrbs[loopCounter][4] to vector(0, 0, 0)*
 - end
 - wait(0.25, ignore condition)
 - loop if condition is true

You can do it the same way as with the Event Player.dotIds array.

I know, repeatedly destroying and creating DOTs and beam effects might be rather server load heavy. I have some ideas for improving the DOTs and beam effect handling, but I need to test something for that when I have the time.

1 Like

Hey thx for the input. I’ll dive into this next time i play. Test it all out to see how it all works. Definitely look into those nested arrays. Thanks.

1 Like