Back to home

TRON Light Cycles/Multiplayer snake

HHTS9
click to copy
This game is archived.
If you with to unarchive it, click the "restore" button in the options menu.
This code can also be found at workshop.codes/HHTS9

Category:
Custom game mode

Author:
CuddlyFlower

Rating:
5

Version:
1.0.1

Posted:
9 months ago

Last updated:
6 months ago

Tags:
while you wait snake deathmatch tron wall arena light cycle

Project Links

Share this workshop!

Options

TRON Light Cycles

Create walls behind you as you move and get other players to smash into them - but look out, as the same thing can happen to you! After spawning, players start with a temporary shield that prevents them from smashing into walls. If you don't know anything about TRON, think of it like multiplayer snake.

For further customization options (e.g. arena size, speed), check the first rule ("Options") in the workshop code.

Check the Discord for updates and discussion.

settings
{
	main
	{
		Description: "TRON Light Cycles - Updates at discord.gg/YP544CH"
	}

	lobby
	{
		Allow Players Who Are In Queue: Yes
		Map Rotation: Paused
		Match Voice Chat: Enabled
		Return To Lobby: Never
	}

	modes
	{
		Deathmatch
		{
			enabled maps
			{
				Workshop Expanse Night
			}
		}

		General
		{
			Allow Hero Switching: Off
			Enemy Health Bars: Off
			Game Mode Start: Immediately
			Hero Limit: 1 Per Game
			Respawn Time Scalar: 25%
			Score To Win: 30
			Self Initiated Respawn: Off
			Spawn Health Packs: Disabled
		}
	}

	heroes
	{
		General
		{
			Movement Speed: 300%
			Primary Fire: Off
			Quick Melee: Off
			Ultimate Ability: Off

			Ana
			{
				Biotic Grenade: Off
				No Scope: On
				Quick Melee: Off
				Sleep Dart: Off
				Ultimate Ability Nano Boost: Off
			}

			Ashe
			{
				Coach Gun: Off
				Dynamite: Off
				No Scope: On
				Primary Fire: Off
				Quick Melee: Off
				Ultimate Ability B.O.B.: Off
			}

			Baptiste
			{
				Immortality Field: Off
				Primary Fire: Off
				Quick Melee: Off
				Secondary Fire: Off
				Ultimate Ability Amplification Matrix: Off
			}

			Bastion
			{
				Primary Fire: Off
				Quick Melee: Off
				Reconfigure: Off
				Self-Repair: Off
				Ultimate Ability Configuration: Tank: Off
			}

			Brigitte
			{
				Barrier Shield: Off
				Primary Fire: Off
				Quick Melee: Off
				Repair Pack: Off
				Shield Bash: Off
				Ultimate Ability Rally: Off
				Whip Shot: Off
			}

			D.Va
			{
				Boosters: Off
				Defense Matrix: Off
				Micro Missiles: Off
				Primary Fire: Off
				Quick Melee: Off
				Spawn Without Mech: On
				Ultimate Ability Self-Destruct: Off
			}

			Doomfist
			{
				Primary Fire: Off
				Quick Melee: Off
				Rising Uppercut: Off
				Rocket Punch: Off
				Seismic Slam: Off
				Ultimate Ability Meteor Strike: Off
			}

			Hanzo
			{
				Lunge: Off
				Primary Fire: Off
				Quick Melee: Off
				Sonic Arrow: Off
				Storm Arrows: Off
				Ultimate Ability Dragonstrike: Off
			}

			Junkrat
			{
				Concussion Mine: Off
				Primary Fire: Off
				Quick Melee: Off
				Steel Trap: Off
				Ultimate Ability RIP-Tire: Off
			}

			McCree
			{
				Combat Roll: Off
				Flashbang: Off
				Primary Fire: Off
				Quick Melee: Off
				Secondary Fire: Off
				Ultimate Ability Deadeye: Off
			}

			Mei
			{
				Cryo-Freeze: Off
				Ice Wall: Off
				Primary Fire: Off
				Quick Melee: Off
				Secondary Fire: Off
				Ultimate Ability Blizzard: Off
			}

			Mercy
			{
				Guardian Angel: Off
				Primary Fire: Off
				Quick Melee: Off
				Regeneration: Off
				Resurrect: Off
				Secondary Fire: Off
				Ultimate Ability Valkyrie: Off
			}

			Moira
			{
				Biotic Orb: Off
				Fade: Off
				Primary Fire: Off
				Quick Melee: Off
				Secondary Fire: Off
				Ultimate Ability Coalescence: Off
			}

			Orisa
			{
				Fortify: Off
				Halt!: Off
				Primary Fire: Off
				Protective Barrier: Off
				Quick Melee: Off
				Ultimate Ability Supercharger: Off
			}

			Pharah
			{
				Concussive Blast: Off
				Hover Jets: Off
				Jump Jet: Off
				Primary Fire: Off
				Quick Melee: Off
				Ultimate Ability Barrage: Off
			}

			Reaper
			{
				Primary Fire: Off
				Quick Melee: Off
				Shadow Step: Off
				Ultimate Ability Death Blossom: Off
				Wraith Form: Off
			}

			Reinhardt
			{
				Barrier Field: Off
				Charge: Off
				Fire Strike: Off
				Primary Fire: Off
				Quick Melee: Off
				Ultimate Ability Earthshatter: Off
			}

			Roadhog
			{
				Chain Hook: Off
				Primary Fire: Off
				Quick Melee: Off
				Secondary Fire: Off
				Spawn With Ultimate Ready: On
				Take a Breather: Off
				Ultimate Ability Whole Hog: Off
			}

			Sigma
			{
				Accretion: Off
				Experimental Barrier: Off
				Kinetic Grasp: Off
				Primary Fire: Off
				Quick Melee: Off
				Ultimate Ability Gravitic Flux: Off
			}

			Soldier: 76
			{
				Biotic Field: Off
				Helix Rockets: Off
				Primary Fire: Off
				Quick Melee: Off
				Sprint: Off
				Ultimate Ability Tactical Visor: Off
			}

			Symmetra
			{
				Primary Fire: Off
				Quick Melee: Off
				Secondary Fire: Off
				Sentry Turret: Off
				Teleporter: Off
				Ultimate Ability Photon Barrier: Off
			}

			Torbjörn
			{
				Deploy Turret: Off
				Overload: Off
				Primary Fire: Off
				Quick Melee: Off
				Secondary Fire: Off
				Ultimate Ability Molten Core: Off
			}

			Widowmaker
			{
				Grappling Hook: Off
				No Scope: On
				Primary Fire: Off
				Quick Melee: Off
				Ultimate Ability Infra-Sight: Off
				Venom Mine: Off
			}

			Winston
			{
				Barrier Projector: Off
				Jump Pack: Off
				Primary Fire: Off
				Quick Melee: Off
				Ultimate Ability Primal Rage: Off
			}

			Wrecking Ball
			{
				Adaptive Shield: Off
				Grappling Claw: Off
				Piledriver: Off
				Primary Fire: Off
				Quick Melee: Off
				Roll: Off
				Ultimate Ability Minefield: Off
			}

			Zarya
			{
				Particle Barrier: Off
				Primary Fire: Off
				Projected Barrier: Off
				Quick Melee: Off
				Secondary Fire: Off
				Ultimate Ability Graviton Surge: Off
			}

			Zenyatta
			{
				Orb of Discord: Off
				Orb of Harmony: Off
				Primary Fire: Off
				Quick Melee: Off
				Secondary Fire: Off
				Ultimate Ability Transcendence: Off
			}

			disabled heroes
			{
				Echo
				Genji
				Junkrat
				Lúcio
				Sombra
				Tracer
				Wrecking Ball
			}
		}
	}
}

variables
{
	global:
		0: Nodes_position_x
		1: Initial_spawn_done
		2: Nodes_count
		3: Nodes_position_x_start
		4: Nodes_position_x_end
		5: Nodes_position_z
		6: Initial_spawn_positions
		7: Nodes_position_z_count
		8: Nodes_position_z_start
		9: Nodes_position_z_end
		10: Nodes_stamp
		11: Nodes_created_entities
		12: Nodes_links
		13: Nodes_associated_player_id
		14: Movements_player_direction
		15: Movements_player_x_z
		16: Movements_player_id
		17: Border_entities
		18: Border_variable
		19: Temp_notified_by
		20: Temp_notified_players
		21: Temp_Value
		22: Temp_Value2
		23: Temp_parent_index
		24: Temp_child_index
		25: Iterator_index
		26: Temp_index
		27: Temp_array
		28: Temp_break
		29: Option_base_speed_multiplier
		30: Option_center
		31: Option_arena_size
		32: Option_max_wall_segments
		33: Option_min_throttle
		34: Option_dir_choosing_time
		35: Spawn_position_index
		36: Option_turn_delay
		37: Temp_leave_index
		38: Node_index_to_be_removed
		39: Option_power_up_point_max
		40: Power_up_entities
		41: Power_up_positions
		42: Temp_power_up_position
		43: Power_up_points_count
		44: Power_up_type
		45: Temp_leave_count
		46: Player_count
		47: Option_enable_dynamic_max_walls
		48: Option_max_entities

	player:
		0: player_direction
		2: next_wall_indices
		3: requires_next_wall_update
		4: next_wall_stamps
		5: last_checked_value
		6: next_wall_value
		7: spawn_position
		8: corresponding_player_index
		9: is_spawning
		10: initial_rotation
		11: shield_active
		12: previous_node_position
		13: next_node_position
		14: current_node_count
		15: created_node_entities
		16: associated_node_position_indices
		18: dynamic_wall
		20: requires_initial_spawn
		21: temp_index
		22: temp_value_1
		23: temp_value_2
		24: temp_value_3
		25: throttle_before_direction_change
		26: shield_entities
		27: requires_respawn
		28: camera_mode
		29: is_choosing_spawn_direction
		30: chase_variable
}

subroutines
{
	0: add_node
	1: add_node_entity
	2: remove_node
	3: remove_node_x_z
	4: set_next_wall_x
	5: set_next_wall_z
	6: notify_players_next_wall_update
	8: update_next_node_position
	9: player_starts_moving
	10: replace_dynamic_wall
	11: kill_on_collision
	12: update_player_direction
	13: enable_shield_break
	14: disable_shield_break
	15: choose_direction
	16: initialize_player
	17: set_initial_rotation
	18: reset_player
	19: setup_player_movements
	20: remove_node_links
	21: cleanup
}

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

	actions
	{
		"Center of arena (default: 0, 0, 0)"
		Global.Option_center = Vector(0, 0, 0);
		"Size of arena (default: 200, i.e. 200 x 200 units)"
		Global.Option_arena_size = 150;
		"Number of wall segments - keep low (less than 9 for 12 players) to avoid reaching the entitiy limit (default: 8)"
		Global.Option_max_wall_segments = 8;
		"Minimum throttle (forced forward movement) of the player (value between 0 and 1, default: 0.5)"
		Global.Option_min_throttle = 0.500;
		"Base speed multiplier (default: 250)"
		Global.Option_base_speed_multiplier = 300;
		"Time in seconds for choosing direction after spawn (default: 3)"
		Global.Option_dir_choosing_time = 3;
		"Delay after each turn (default: 0.250)"
		Global.Option_turn_delay = 0.250;
		"Number of power ups that give extra points (default: 4)"
		Global.Option_power_up_point_max = 4;
		"Set wall segment limit according to number of players - overrides max wall set (default: FALSE)"
		Global.Option_enable_dynamic_max_walls = True;
		"Used in combination with the dynamic wall limit to determine walls per player (default: 100)"
		Global.Option_max_entities = 100;
	}
}

rule("Disable reporting")
{
	event
	{
		Ongoing - Global;
	}

	actions
	{
		Disable Inspector Recording;
	}
}

rule("Create environment")
{
	event
	{
		Ongoing - Global;
	}

	actions
	{
		Create Effect(All Players(All Teams), Sphere, Sky Blue, Global.Option_center, Global.Option_arena_size   0, Visible To);
		Create Effect(All Players(All Teams), Light Shaft, Yellow, Vector(Global.Option_arena_size * 1   0, 0, 0), 5, Visible To);
		Create Effect(All Players(All Teams), Light Shaft, Green, Vector(Global.Option_arena_size * -1   0, 0, 0), 5, Visible To);
		Create Effect(All Players(All Teams), Light Shaft, Purple, Vector(0, 0, Global.Option_arena_size * 1   0), 5, Visible To);
		Create Effect(All Players(All Teams), Light Shaft, Aqua, Vector(0, 0, Global.Option_arena_size * -1   0), 5, Visible To);
	}
}

rule("Create borders")
{
	event
	{
		Ongoing - Global;
	}

	actions
	{
		Global.Border_entities = Empty Array;
		Global.Border_variable = 0.500 * Global.Option_arena_size;
		Create Beam Effect(All Players(All Teams), Bad Beam, Vector(X Component Of(Global.Option_center)   Global.Border_variable, 0.100,
			Z Component Of(Global.Option_center)   Global.Border_variable), Vector(X Component Of(Global.Option_center)
			  -1 * Global.Border_variable, 0.100, Z Component Of(Global.Option_center)   Global.Border_variable), Sky Blue,
			Visible To Position and Radius);
		Modify Global Variable(Border_entities, Append To Array, Last Created Entity);
		Create Beam Effect(All Players(All Teams), Bad Beam, Vector(-1 * (X Component Of(Global.Option_center)   Global.Border_variable),
			0.100, -1 * (Z Component Of(Global.Option_center)   Global.Border_variable)), Vector(X Component Of(Global.Option_center)
			  -1 * Global.Border_variable, 0.100, Z Component Of(Global.Option_center)   Global.Border_variable), Sky Blue,
			Visible To Position and Radius);
		Modify Global Variable(Border_entities, Append To Array, Last Created Entity);
		Create Beam Effect(All Players(All Teams), Bad Beam, Vector(X Component Of(Global.Option_center)   Global.Border_variable, 0.100,
			Z Component Of(Global.Option_center)   Global.Border_variable), Vector(X Component Of(Global.Option_center)
			  1 * Global.Border_variable, 0.100, Z Component Of(Global.Option_center)   -1 * Global.Border_variable), Sky Blue,
			Visible To Position and Radius);
		Modify Global Variable(Border_entities, Append To Array, Last Created Entity);
		Create Beam Effect(All Players(All Teams), Bad Beam, Vector(X Component Of(Global.Option_center)   -1 * Global.Border_variable,
			0.100, Z Component Of(Global.Option_center)   -1 * Global.Border_variable), Vector(X Component Of(Global.Option_center)
			  1 * Global.Border_variable, 0.100, Z Component Of(Global.Option_center)   -1 * Global.Border_variable), Sky Blue,
			Visible To Position and Radius);
		Modify Global Variable(Border_entities, Append To Array, Last Created Entity);
		Create Effect(All Players(All Teams), Orb, Sky Blue, Vector(1 * Global.Border_variable, 0.100, 1 * Global.Border_variable), 0.200,
			Visible To);
		Create Effect(All Players(All Teams), Orb, Sky Blue, Vector(-1 * Global.Border_variable, 0.100, 1 * Global.Border_variable), 0.200,
			Visible To);
		Create Effect(All Players(All Teams), Orb, Sky Blue, Vector(1 * Global.Border_variable, 0.100, -1 * Global.Border_variable), 0.200,
			Visible To);
		Create Effect(All Players(All Teams), Orb, Sky Blue, Vector(-1 * Global.Border_variable, 0.100, -1 * Global.Border_variable),
			0.200, Visible To);
	}
}

rule("Setup global variables")
{
	event
	{
		Ongoing - Global;
	}

	actions
	{
		Global.Nodes_position_x = Empty Array;
		Global.Nodes_position_x_start = -1;
		Global.Nodes_position_x_end = -1;
		Global.Nodes_count = 0;
		Global.Nodes_position_z = Empty Array;
		Global.Nodes_position_z_start = -1;
		Global.Nodes_position_z_end = -1;
		Global.Nodes_position_z_count = 0;
		Global.Nodes_created_entities = Empty Array;
		Global.Nodes_links = Empty Array;
		Global.Nodes_associated_player_id = Empty Array;
		Global.Movements_player_direction = Empty Array;
		Global.Movements_player_x_z = Empty Array;
		Global.Movements_player_id = Empty Array;
		Global.Temp_array = Empty Array;
		Global.Temp_break = False;
		Global.Nodes_stamp = Empty Array;
		Global.Initial_spawn_done = False;
		Global.Power_up_entities = Empty Array;
		Global.Power_up_positions = Empty Array;
		Global.Power_up_type = Empty Array;
	}
}

rule("Create power up - points (type: 1)")
{
	event
	{
		Ongoing - Global;
	}

	conditions
	{
		Is Game In Progress == True;
		Global.Power_up_points_count < Global.Option_power_up_point_max;
	}

	actions
	{
		Global.Temp_power_up_position = Vector(Random Integer(-1 * (Global.Border_variable - 5), Global.Border_variable - 5), 0,
			Random Integer(-1 * (Global.Border_variable - 5), Global.Border_variable - 5));
		Global.Temp_index = 0;
		While(Global.Power_up_positions[Global.Temp_index] != 0);
			Global.Temp_index  = 1;
		End;
		Global.Power_up_positions[Global.Temp_index] = Global.Temp_power_up_position;
		Create Effect(All Players(All Teams), Sphere, Green, Global.Temp_power_up_position, 3, Visible To);
		Global.Power_up_entities[Global.Temp_index] = Last Created Entity;
		Global.Power_up_type[Global.Temp_index] = 1;
		Global.Power_up_points_count  = 1;
		Wait(1, Ignore Condition);
		Loop If Condition Is True;
	}
}

rule("Collect power ups")
{
	event
	{
		Ongoing - Each Player;
		All;
		All;
	}

	conditions
	{
		Is Alive(Event Player) == True;
		Has Spawned(Event Player) == True;
		Global.Power_up_points_count > 0;
		Count Of(Filtered Array(Global.Power_up_positions, Current Array Element != 0 && Distance Between(Position Of(Event Player),
			Current Array Element) <= 3)) > 0;
		Is In Setup == False;
		Is In Spawn Room(Event Player) == False;
	}

	actions
	{
		For Player Variable(Event Player, temp_index, 0, Count Of(Global.Power_up_positions), 1);
			If(Global.Power_up_positions[Event Player.temp_index] != 0 && Distance Between(Position Of(Event Player),
				Global.Power_up_positions[Event Player.temp_index]) <= 3);
				Destroy Effect(Global.Power_up_entities[Event Player.temp_index]);
				Global.Power_up_entities[Event Player.temp_index] = 0;
				Play Effect(All Players(All Teams), Ring Explosion, Green, Global.Power_up_positions[Event Player.temp_index], 4);
				Global.Power_up_positions[Event Player.temp_index] = 0;
				Set Player Score(Event Player, Score Of(Event Player)   1);
				Global.Power_up_points_count -= 1;
			End;
		End;
	}
}

rule("Setup mode")
{
	event
	{
		Ongoing - Global;
	}

	actions
	{
		"Reduce hero selection time"
		Set Match Time(10);
		Disallow Button(All Players(All Teams), Crouch);
		Disallow Button(All Players(All Teams), Jump);
	}
}

rule("Setup player variables")
{
	event
	{
		Player Joined Match;
		All;
		All;
	}

	conditions
	{
		Array Contains(Global.Movements_player_id, Event Player) == False;
	}

	actions
	{
		Event Player.created_node_entities = Empty Array;
		Event Player.associated_node_position_indices = Empty Array;
		Event Player.next_wall_indices = Empty Array;
		Call Subroutine(setup_player_movements);
		Event Player.requires_next_wall_update = False;
		Event Player.is_spawning = True;
		Event Player.shield_active = False;
		Event Player.shield_entities = Empty Array;
		Event Player.requires_initial_spawn = !Is Game In Progress;
		Event Player.requires_respawn = True;
		Event Player.camera_mode = 0;
		Disallow Button(Event Player, Crouch);
		Event Player.is_choosing_spawn_direction = False;
		Disallow Button(Event Player, Crouch);
		Disallow Button(Event Player, Jump);
	}
}

rule("Setup player movement variables")
{
	event
	{
		Subroutine;
		setup_player_movements;
	}

	actions
	{
		Global.Temp_index = 0;
		While(Global.Movements_player_id[Global.Temp_index] != 0);
			Global.Temp_index  = 1;
		End;
		Global.Movements_player_id[Global.Temp_index] = Event Player;
		Global.Movements_player_x_z[Global.Temp_index] = Vector(-1, 0, -1);
		Global.Movements_player_direction[Global.Temp_index] = Vector(-1, 0, 0);
		Event Player.corresponding_player_index = Global.Temp_index;
	}
}

rule("Setup player effects")
{
	event
	{
		Player Joined Match;
		All;
		All;
	}

	conditions
	{
		Is Game In Progress == True;
	}

	actions
	{
		Create Effect(All Players(All Teams), Good Aura Sound, White, Position Of(Event Player), 10000, Visible To Position and Radius);
	}
}

rule("Set player Camera")
{
	event
	{
		Player Joined Match;
		All;
		All;
	}

	actions
	{
		Start Camera(Event Player, Position Of(Event Player)   World Vector Of(Vector(0, 20, -20 - Min(0.400 * (Absolute Value(
			X Component Of(Velocity Of(Event Player)))   Absolute Value(Z Component Of(Velocity Of(Event Player)))), 45)), Event Player,
			Rotation), Event Player, 5);
	}
}

rule("Change camera to dynamic")
{
	event
	{
		Ongoing - Each Player;
		All;
		All;
	}

	conditions
	{
		Event Player.camera_mode == 1;
		Is Button Held(Event Player, Reload) == True;
	}

	actions
	{
		Stop Camera(Event Player);
		Start Camera(Event Player, Position Of(Event Player)   World Vector Of(Vector(0, 20, -20 - Min(0.400 * (Absolute Value(
			X Component Of(Velocity Of(Event Player)))   Absolute Value(Z Component Of(Velocity Of(Event Player)))), 45)), Event Player,
			Rotation), Event Player, 5);
		Wait(0.500, Ignore Condition);
		Event Player.camera_mode = 0;
	}
}

rule("Change camera to static")
{
	event
	{
		Ongoing - Each Player;
		All;
		All;
	}

	conditions
	{
		Event Player.camera_mode == 0;
		Is Button Held(Event Player, Reload) == True;
	}

	actions
	{
		Stop Camera(Event Player);
		Start Camera(Event Player, Position Of(Event Player)   Vector(0, 75, -2), Event Player, 10);
		Wait(0.500, Ignore Condition);
		Event Player.camera_mode = 1;
	}
}

rule("Setup initial spawn positions")
{
	event
	{
		Ongoing - Global;
	}

	conditions
	{
		Is Assembling Heroes == False;
	}

	actions
	{
		Global.Player_count = Count Of(All Players(All Teams));
		Global.Temp_Value = Max(2, Global.Player_count);
		Global.Temp_Value = 360 / Global.Temp_Value;
		"Radius"
		Global.Temp_Value2 = Global.Border_variable - 5;
		Global.Temp_index = 0;
		Global.Initial_spawn_positions = Empty Array;
		While(Global.Temp_index < 360);
			Modify Global Variable(Initial_spawn_positions, Append To Array, Vector(0   Global.Temp_Value2 * Cosine From Degrees(
				Global.Temp_index), 0, 0   Global.Temp_Value2 * Sine From Degrees(Global.Temp_index)));
			Global.Temp_index = Global.Temp_index   Global.Temp_Value;
		End;
	}
}

rule("Initialize player")
{
	event
	{
		Subroutine;
		initialize_player;
	}

	actions
	{
		Call Subroutine(enable_shield_break);
		Set Status(Event Player, Null, Phased Out, 9999);
		Set Move Speed(Event Player, 0);
		Start Forcing Throttle(Event Player, 0, 0, 0, 0, 0, 1);
		Event Player.is_spawning = True;
		Event Player.initial_rotation = Vector(-1, 0, 0);
		Event Player.player_direction = Event Player.initial_rotation;
	}
}

rule("Set initial rotation")
{
	event
	{
		Subroutine;
		set_initial_rotation;
	}

	actions
	{
		Event Player.temp_value_1 = Normalize(Event Player.spawn_position);
		Event Player.temp_value_1 = Vector(Round To Integer(X Component Of(Event Player.temp_value_1), To Nearest), 0, Round To Integer(
			Z Component Of(Event Player.temp_value_1), To Nearest));
		Event Player.temp_value_1 = -1 * Event Player.temp_value_1;
		Event Player.initial_rotation = Event Player.temp_value_1;
		If(Event Player.initial_rotation == Vector(0, 0, 0));
			Event Player.initial_rotation = Normalize(Vector(Random Real(-1, 1), 0, 0));
		Else If(X Component Of(Event Player.initial_rotation) != 0 && Z Component Of(Event Player.initial_rotation) != 0);
			Event Player.initial_rotation = Vector(X Component Of(Event Player.initial_rotation), 0, 0);
		End;
		Event Player.player_direction = Event Player.initial_rotation;
		Global.Movements_player_direction[Event Player.corresponding_player_index] = Event Player.player_direction;
	}
}

rule("Set fixed spawn position at match start")
{
	event
	{
		Ongoing - Each Player;
		All;
		All;
	}

	conditions
	{
		Event Player.spawn_position == 0;
		Has Spawned(Event Player) == True;
		Event Player.requires_initial_spawn == True;
	}

	actions
	{
		Call Subroutine(initialize_player);
		Event Player.spawn_position = Global.Initial_spawn_positions[Global.Spawn_position_index];
		Call Subroutine(set_initial_rotation);
		Teleport(Event Player, Event Player.spawn_position);
		Global.Spawn_position_index  = 1;
		Wait(1, Ignore Condition);
		Stop Facing(Event Player);
		Set Facing(Event Player, Event Player.initial_rotation, To World);
		Start Facing(Event Player, Event Player.initial_rotation, 9999, To World, None);
		Wait(4, Ignore Condition);
		Call Subroutine(choose_direction);
		Event Player.requires_initial_spawn = False;
	}
}

rule("Set random player spawn during match")
{
	event
	{
		Ongoing - Each Player;
		All;
		All;
	}

	conditions
	{
		Is Alive(Event Player) == True;
		Event Player.requires_initial_spawn == False;
		Event Player.requires_respawn == True;
		Is Game In Progress == True;
		Has Spawned(Event Player) == True;
	}

	actions
	{
		Call Subroutine(initialize_player);
		Event Player.spawn_position = Vector(X Component Of(Global.Option_center)   Random Integer(-1 * (Global.Border_variable - 5),
			Global.Border_variable - 5), 0, Z Component Of(Global.Option_center)   Random Integer(-1 * (Global.Border_variable - 5),
			Global.Border_variable - 5));
		Call Subroutine(set_initial_rotation);
		Teleport(Event Player, Event Player.spawn_position);
		Stop Facing(Event Player);
		Set Facing(Event Player, Event Player.initial_rotation, To World);
		Start Facing(Event Player, Event Player.initial_rotation, 9999, To World, None);
		Call Subroutine(choose_direction);
	}
}

rule("Start direction choosing phase")
{
	event
	{
		Subroutine;
		choose_direction;
	}

	actions
	{
		Big Message(Event Player, Custom String("{0} Choose direction! {1}", Icon String(Arrow: Left), Icon String(Arrow: Right)));
		Event Player.is_choosing_spawn_direction = True;
		Event Player.chase_variable = Global.Option_dir_choosing_time;
		Create Effect(All Players(All Teams), Light Shaft, Sky Blue, Event Player, Event Player.chase_variable,
			Visible To Position and Radius);
		Chase Player Variable At Rate(Event Player, chase_variable, 0, 1, None);
		Wait(Global.Option_dir_choosing_time, Ignore Condition);
		Stop Chasing Player Variable(Event Player, chase_variable);
		Destroy Effect(Last Created Entity);
		Big Message(Event Player, Custom String("Go!"));
		Event Player.is_choosing_spawn_direction = False;
		Event Player.is_spawning = False;
		Event Player.requires_respawn = False;
		Wait(0.200, Ignore Condition);
		Call Subroutine(player_starts_moving);
		Wait(3, Ignore Condition);
		Call Subroutine(disable_shield_break);
	}
}

rule("Change spawn direction")
{
	event
	{
		Ongoing - Each Player;
		All;
		All;
	}

	conditions
	{
		Event Player.is_choosing_spawn_direction == True;
		Event Player.is_spawning == True;
		Is Alive(Event Player) == True;
		X Component Of(Throttle Of(Event Player)) != 0;
		Event Player.throttle_before_direction_change == 0;
	}

	actions
	{
		Event Player.throttle_before_direction_change = Vector(Round To Integer(X Component Of(Throttle Of(Event Player)), To Nearest), 0,
			Round To Integer(Z Component Of(Throttle Of(Event Player)), To Nearest));
		Start Forcing Throttle(Event Player, 0, 0, 0, 0, 0, 0);
		Stop Facing(Event Player);
		Start Facing(Event Player, World Vector Of(Vector(X Component Of(Event Player.throttle_before_direction_change), 0, 0),
			Event Player, Rotation), 10000, To World, None);
		Wait(Global.Option_turn_delay, Ignore Condition);
		"Update direction"
		Call Subroutine(update_player_direction);
		Start Forcing Throttle(Event Player, 0, 0, 0, 0, 0, 1);
		Event Player.throttle_before_direction_change = 0;
	}
}

rule("Player starts moving")
{
	event
	{
		Subroutine;
		player_starts_moving;
	}

	actions
	{
		Set Move Speed(Event Player, Global.Option_base_speed_multiplier);
		Start Forcing Throttle(Event Player, Global.Option_min_throttle, 1, 0, 0, 0, 1);
		Start Accelerating(Event Player, Vector(0, 0, 1), 10000, Z Component Of(Throttle Of(Event Player)) * 2000, To Player,
			Direction Rate and Max Speed);
		Event Player.next_node_position = Vector(X Component Of(Position Of(Event Player)), Y Component Of(Position Of(Event Player)),
			Z Component Of(Position Of(Event Player)));
		Event Player.previous_node_position = Event Player.next_node_position;
		Call Subroutine(add_node);
		Call Subroutine(replace_dynamic_wall);
		Call Subroutine(notify_players_next_wall_update);
	}
}

rule("Change move direction")
{
	event
	{
		Ongoing - Each Player;
		All;
		All;
	}

	conditions
	{
		Is Alive(Event Player) == True;
		Event Player.is_spawning == False;
		Is Moving(Event Player) == True;
		X Component Of(Throttle Of(Event Player)) != 0;
		Event Player.throttle_before_direction_change == 0;
	}

	actions
	{
		Event Player.throttle_before_direction_change = Vector(Round To Integer(X Component Of(Throttle Of(Event Player)), To Nearest), 0,
			Round To Integer(Z Component Of(Throttle Of(Event Player)), To Nearest));
		Start Forcing Throttle(Event Player, Global.Option_min_throttle, 1, 0, 0, 0, 0);
		If(Global.Option_enable_dynamic_max_walls == True);
			Global.Option_max_wall_segments = Round To Integer(Global.Option_max_entities / Global.Player_count, To Nearest);
		End;
		If(Event Player.current_node_count > Global.Option_max_wall_segments);
			Call Subroutine(remove_node);
		End;
		Stop Facing(Event Player);
		Start Facing(Event Player, World Vector Of(Vector(X Component Of(Event Player.throttle_before_direction_change), 0, 0),
			Event Player, Rotation), 10000, To World, None);
		Wait(Global.Option_turn_delay, Ignore Condition);
		Call Subroutine(update_next_node_position);
		"Update direction"
		Call Subroutine(update_player_direction);
		If(X Component Of(Event Player.player_direction) != 0);
			Event Player.last_checked_value = X Component Of(Event Player.next_node_position);
			Call Subroutine(set_next_wall_x);
		Else If(Z Component Of(Event Player.player_direction) != 0);
			Event Player.last_checked_value = Z Component Of(Event Player.next_node_position);
			Call Subroutine(set_next_wall_z);
		End;
		Global.Movements_player_x_z[Event Player.corresponding_player_index] = Position Of(Event Player);
		Call Subroutine(add_node);
		Call Subroutine(replace_dynamic_wall);
		Call Subroutine(notify_players_next_wall_update);
		Start Forcing Throttle(Event Player, Global.Option_min_throttle, 1, 0, 0, 0, 1);
		Event Player.throttle_before_direction_change = 0;
	}
}

rule("Update next node position")
{
	event
	{
		Subroutine;
		update_next_node_position;
	}

	actions
	{
		Event Player.previous_node_position = Event Player.next_node_position;
		If(Z Component Of(Event Player.player_direction) != 0);
			Event Player.next_node_position = Vector(X Component Of(Event Player.previous_node_position), 0.500, Z Component Of(Position Of(
				Event Player)));
		Else;
			Event Player.next_node_position = Vector(X Component Of(Position Of(Event Player)), 0.500, Z Component Of(
				Event Player.previous_node_position));
		End;
	}
}

rule("Update player direction")
{
	event
	{
		Subroutine;
		update_player_direction;
	}

	actions
	{
		If(X Component Of(Event Player.player_direction) != 0);
			Event Player.player_direction = Vector(0, 0, -1 * X Component Of(Event Player.player_direction) * X Component Of(
				Event Player.throttle_before_direction_change));
		Else;
			Event Player.player_direction = Vector(Z Component Of(Event Player.player_direction) * X Component Of(
				Event Player.throttle_before_direction_change), 0, 0);
		End;
		Global.Movements_player_direction[Event Player.corresponding_player_index] = Event Player.player_direction;
	}
}

rule("Add Node")
{
	event
	{
		Subroutine;
		add_node;
	}

	actions
	{
		Global.Temp_index = 0;
		Global.Temp_parent_index = -1;
		Global.Temp_child_index = Global.Nodes_position_x_start - 0;
		Global.Iterator_index = Global.Nodes_position_x_start;
		While(Y Component Of(Global.Nodes_position_x[Global.Iterator_index]) < X Component Of(Event Player.next_node_position)
			&& Global.Iterator_index != -1);
			Global.Temp_parent_index = Global.Iterator_index;
			Global.Iterator_index = Z Component Of(Global.Nodes_position_x[Global.Iterator_index]);
			Global.Temp_child_index = Global.Iterator_index;
		End;
		While(Global.Nodes_position_x[Global.Temp_index] != 0);
			Global.Temp_index  = 1;
		End;
		"Set x position"
		Global.Nodes_position_x[Global.Temp_index] = Vector(Global.Temp_parent_index, X Component Of(Event Player.next_node_position),
			Global.Temp_child_index);
		"Reset start x"
		If(Global.Nodes_position_x_start == -1 || Y Component Of(Global.Nodes_position_x[Global.Temp_index]) <= Y Component Of(
			Global.Nodes_position_x[Global.Nodes_position_x_start]));
			Global.Nodes_position_x_start = Global.Temp_index;
		End;
		"Reset end x"
		If(Global.Nodes_position_x_end == -1 || Y Component Of(Global.Nodes_position_x[Global.Temp_index]) > Y Component Of(
			Global.Nodes_position_x[Global.Nodes_position_x_end]));
			Global.Nodes_position_x_end = Global.Temp_index;
		End;
		"Link parent x"
		Skip If(Global.Temp_parent_index == -1, 1);
		Global.Nodes_position_x[Global.Temp_parent_index] = Vector(X Component Of(Global.Nodes_position_x[Global.Temp_parent_index]),
			Y Component Of(Global.Nodes_position_x[Global.Temp_parent_index]), Global.Temp_index);
		"Link child x"
		Skip If(Global.Temp_child_index == -1, 1);
		Global.Nodes_position_x[Global.Temp_child_index] = Vector(Global.Temp_index, Y Component Of(
			Global.Nodes_position_x[Global.Temp_child_index]), Z Component Of(Global.Nodes_position_x[Global.Temp_child_index]));
		Global.Temp_parent_index = -1;
		Global.Temp_child_index = Global.Nodes_position_z_start - 0;
		Global.Iterator_index = Global.Nodes_position_z_start;
		While(Y Component Of(Global.Nodes_position_z[Global.Iterator_index]) < Z Component Of(Event Player.next_node_position)
			&& Global.Iterator_index != -1);
			Global.Temp_parent_index = Global.Iterator_index;
			Global.Iterator_index = Z Component Of(Global.Nodes_position_z[Global.Iterator_index]);
			Global.Temp_child_index = Global.Iterator_index;
		End;
		"Set z position"
		Global.Nodes_position_z[Global.Temp_index] = Vector(Global.Temp_parent_index, Z Component Of(Event Player.next_node_position),
			Global.Temp_child_index);
		"Reset start z"
		If(Global.Nodes_position_z_start == -1 || Y Component Of(Global.Nodes_position_z[Global.Temp_index]) <= Y Component Of(
			Global.Nodes_position_z[Global.Nodes_position_z_start]));
			Global.Nodes_position_z_start = Global.Temp_index;
		End;
		"Reset end z"
		If(Global.Nodes_position_z_end == -1 || Y Component Of(Global.Nodes_position_z[Global.Temp_index]) > Y Component Of(
			Global.Nodes_position_z[Global.Nodes_position_z_end]));
			Global.Nodes_position_z_end = Global.Temp_index;
		End;
		"Link parent z"
		Skip If(Global.Temp_parent_index == -1, 1);
		Global.Nodes_position_z[Global.Temp_parent_index] = Vector(X Component Of(Global.Nodes_position_z[Global.Temp_parent_index]),
			Y Component Of(Global.Nodes_position_z[Global.Temp_parent_index]), Global.Temp_index);
		"Link child z"
		Skip If(Global.Temp_child_index == -1, 1);
		Global.Nodes_position_z[Global.Temp_child_index] = Vector(Global.Temp_index, Y Component Of(
			Global.Nodes_position_z[Global.Temp_child_index]), Z Component Of(Global.Nodes_position_z[Global.Temp_child_index]));
		Call Subroutine(add_node_entity);
		If(Count Of(Event Player.associated_node_position_indices) != 0);
			"Set Y component to 1 if wall to next added node happens to be vertical, 0 if horizontal"
			If(Y Component Of(Global.Nodes_position_x[Global.Temp_index]) == Y Component Of(Global.Nodes_position_x[Last Of(
				Event Player.associated_node_position_indices)]));
				Global.Nodes_links[Last Of(Event Player.associated_node_position_indices)] = Vector(X Component Of(Global.Nodes_links[Last Of(
					Event Player.associated_node_position_indices)]), 1, Global.Temp_index);
			Else;
				Global.Nodes_links[Last Of(Event Player.associated_node_position_indices)] = Vector(X Component Of(Global.Nodes_links[Last Of(
					Event Player.associated_node_position_indices)]), 0, Global.Temp_index);
			End;
			"Set latest node - Y component is the opposite of previous value in link"
			Global.Nodes_links[Global.Temp_index] = Vector(Last Of(Event Player.associated_node_position_indices), (Y Component Of(
				Global.Nodes_links[Last Of(Event Player.associated_node_position_indices)])   1) % 2, -1);
		Else;
			Global.Nodes_links[Global.Temp_index] = Vector(-1, Absolute Value(Z Component Of(Event Player.player_direction)), -1);
		End;
		Modify Player Variable(Event Player, associated_node_position_indices, Append To Array, Global.Temp_index);
		Global.Nodes_count  = 1;
		Event Player.current_node_count  = 1;
		Global.Nodes_stamp[Global.Temp_index]  = 1;
		Global.Nodes_associated_player_id[Global.Temp_index] = Event Player;
	}
}

rule("Add Node Entity")
{
	event
	{
		Subroutine;
		add_node_entity;
	}

	actions
	{
		If(Event Player.previous_node_position != Event Player.next_node_position);
			"Create beam"
			Create Beam Effect(All Players(All Teams), Bad Beam, Event Player.previous_node_position, Event Player.next_node_position, Yellow,
				Visible To);
			Global.Nodes_created_entities[Last Of(Event Player.associated_node_position_indices)] = Last Created Entity;
			Play Effect(All Players(All Teams), Good Pickup Effect, Yellow, Event Player.next_node_position, 50);
			Play Effect(All Players(All Teams), Buff Impact Sound, White, Event Player.next_node_position, 50);
		End;
	}
}

rule("Replace dynamic wall")
{
	event
	{
		Subroutine;
		replace_dynamic_wall;
	}

	actions
	{
		Skip If(Event Player.dynamic_wall == 0, 1);
		Destroy Effect(Event Player.dynamic_wall);
		If(X Component Of(Event Player.player_direction) != 0);
			Create Beam Effect(All Players(All Teams), Bad Beam, Event Player.next_node_position, Vector(X Component Of(Position Of(
				Event Player)), 0.500, Z Component Of(Event Player.next_node_position)), Yellow, Visible To Position and Radius);
		Else;
			Create Beam Effect(All Players(All Teams), Bad Beam, Event Player.next_node_position, Vector(X Component Of(
				Event Player.next_node_position), 0.500, Z Component Of(Position Of(Event Player))), Yellow, Visible To Position and Radius);
		End;
		Event Player.dynamic_wall = Last Created Entity;
	}
}

rule("Remove Node")
{
	event
	{
		Subroutine;
		remove_node;
	}

	actions
	{
		Global.Node_index_to_be_removed = Event Player.associated_node_position_indices[0];
		Destroy Effect(Global.Nodes_created_entities[Global.Node_index_to_be_removed]);
		Global.Nodes_created_entities[Global.Node_index_to_be_removed] = 0;
		Event Player.associated_node_position_indices[0] = -1;
		Event Player.associated_node_position_indices = Filtered Array(Event Player.associated_node_position_indices,
			Current Array Element != -1);
		Event Player.current_node_count -= 1;
		Call Subroutine(remove_node_links);
		Call Subroutine(remove_node_x_z);
		Global.Nodes_associated_player_id[Global.Node_index_to_be_removed] = 0;
	}
}

rule("Remove Node Links")
{
	event
	{
		Subroutine;
		remove_node_links;
	}

	actions
	{
		If(Global.Nodes_links[Global.Node_index_to_be_removed] != 0);
			If(X Component Of(Global.Nodes_links[Global.Node_index_to_be_removed]) != -1);
				Global.Nodes_links[X Component Of(Global.Nodes_links[Global.Node_index_to_be_removed])] = Vector(X Component Of(
					Global.Nodes_links[X Component Of(Global.Nodes_links[Global.Node_index_to_be_removed])]), Y Component Of(
					Global.Nodes_links[X Component Of(Global.Nodes_links[Global.Node_index_to_be_removed])]), Z Component Of(
					Global.Nodes_links[Global.Node_index_to_be_removed]));
			End;
			If(Z Component Of(Global.Nodes_links[Global.Node_index_to_be_removed]) != -1);
				Global.Nodes_links[Z Component Of(Global.Nodes_links[Global.Node_index_to_be_removed])] = Vector(X Component Of(
					Global.Nodes_links[Global.Node_index_to_be_removed]), Y Component Of(Global.Nodes_links[Z Component Of(
					Global.Nodes_links[Global.Node_index_to_be_removed])]), Z Component Of(Global.Nodes_links[Z Component Of(
					Global.Nodes_links[Global.Node_index_to_be_removed])]));
			End;
		End;
	}
}

rule("Remove Node Coords")
{
	event
	{
		Subroutine;
		remove_node_x_z;
	}

	actions
	{
		Global.Iterator_index = Global.Node_index_to_be_removed;
		If(Global.Nodes_position_x[Global.Iterator_index] != 0);
			Global.Nodes_stamp[Global.Iterator_index]  = 1;
			If(X Component Of(Global.Nodes_position_x[Global.Iterator_index]) != -1);
				"Parent"
				Global.Nodes_position_x[X Component Of(Global.Nodes_position_x[Global.Iterator_index])] = Vector(X Component Of(
					Global.Nodes_position_x[X Component Of(Global.Nodes_position_x[Global.Iterator_index])]), Y Component Of(
					Global.Nodes_position_x[X Component Of(Global.Nodes_position_x[Global.Iterator_index])]), Z Component Of(
					Global.Nodes_position_x[Global.Iterator_index]));
			Else;
				"Reset start of the list"
				Global.Nodes_position_x_start = Z Component Of(Global.Nodes_position_x[Global.Iterator_index]);
			End;
			If(Z Component Of(Global.Nodes_position_x[Global.Iterator_index]) != -1);
				"Child"
				Global.Nodes_position_x[Z Component Of(Global.Nodes_position_x[Global.Iterator_index])] = Vector(X Component Of(
					Global.Nodes_position_x[Global.Iterator_index]), Y Component Of(Global.Nodes_position_x[Z Component Of(
					Global.Nodes_position_x[Global.Iterator_index])]), Z Component Of(Global.Nodes_position_x[Z Component Of(
					Global.Nodes_position_x[Global.Iterator_index])]));
			Else;
				"Reset end of the list"
				Global.Nodes_position_x_end = X Component Of(Global.Nodes_position_x[Global.Iterator_index]);
			End;
			Global.Nodes_position_x[Global.Iterator_index] = 0;
			Global.Nodes_count -= 1;
			If(X Component Of(Global.Nodes_position_z[Global.Iterator_index]) != -1);
				"Parent"
				Global.Nodes_position_z[X Component Of(Global.Nodes_position_z[Global.Iterator_index])] = Vector(X Component Of(
					Global.Nodes_position_z[X Component Of(Global.Nodes_position_z[Global.Iterator_index])]), Y Component Of(
					Global.Nodes_position_z[X Component Of(Global.Nodes_position_z[Global.Iterator_index])]), Z Component Of(
					Global.Nodes_position_z[Global.Iterator_index]));
			Else;
				"Reset start of the list"
				Global.Nodes_position_z_start = Z Component Of(Global.Nodes_position_z[Global.Iterator_index]);
			End;
			If(Z Component Of(Global.Nodes_position_z[Global.Iterator_index]) != -1);
				"Child"
				Global.Nodes_position_z[Z Component Of(Global.Nodes_position_z[Global.Iterator_index])] = Vector(X Component Of(
					Global.Nodes_position_z[Global.Iterator_index]), Y Component Of(Global.Nodes_position_z[Z Component Of(
					Global.Nodes_position_z[Global.Iterator_index])]), Z Component Of(Global.Nodes_position_z[Z Component Of(
					Global.Nodes_position_z[Global.Iterator_index])]));
			Else;
				"Reset end of the list"
				Global.Nodes_position_z_end = X Component Of(Global.Nodes_position_z[Global.Iterator_index]);
			End;
			Global.Nodes_position_z[Global.Iterator_index] = 0;
			Global.Nodes_links[Global.Iterator_index] = 0;
		End;
	}
}

rule("Notify players of possible collision")
{
	event
	{
		Subroutine;
		notify_players_next_wall_update;
	}

	actions
	{
		Global.Temp_notified_players = Empty Array;
		If(X Component Of(Event Player.player_direction) != 0);
			Global.Temp_notified_players = Filtered Array(Global.Movements_player_id, Current Array Element != Event Player && Z Component Of(
				Current Array Element.player_direction) != 0);
		Else;
			Global.Temp_notified_players = Filtered Array(Global.Movements_player_id, Current Array Element != Event Player && X Component Of(
				Current Array Element.player_direction) != 0);
		End;
		Global.Temp_notified_players.requires_next_wall_update = True;
		Global.Temp_notified_by = Event Player;
	}
}

rule("Notified players set next wall X by other player")
{
	event
	{
		Ongoing - Each Player;
		All;
		All;
	}

	conditions
	{
		Is Alive(Event Player) == True;
		Event Player.requires_next_wall_update == True;
		X Component Of(Event Player.player_direction) != 0;
	}

	actions
	{
		If(X Component Of(Event Player.player_direction) > 0);
			If(X Component Of(Position Of(Global.Temp_notified_by)) > X Component Of(Position Of(Event Player)) && (Count Of(
				Event Player.next_wall_indices) <= 0 || X Component Of(Position Of(Global.Temp_notified_by)) < X Component Of(
				Event Player.next_wall_value)));
				Event Player.next_wall_indices = Empty Array;
				Event Player.next_wall_stamps = Empty Array;
				Modify Player Variable(Event Player, next_wall_indices, Append To Array, Last Of(
					Global.Temp_notified_by.associated_node_position_indices));
				Modify Player Variable(Event Player, next_wall_stamps, Append To Array, Global.Nodes_stamp[Last Of(
					Global.Temp_notified_by.associated_node_position_indices)]);
				Event Player.next_wall_value = Vector(X Component Of(Position Of(Global.Temp_notified_by)), 0, 0);
			End;
		Else If(X Component Of(Event Player.player_direction) < 0);
			If(X Component Of(Position Of(Global.Temp_notified_by)) < X Component Of(Position Of(Event Player)) && (Count Of(
				Event Player.next_wall_indices) <= 0 || X Component Of(Position Of(Global.Temp_notified_by)) > X Component Of(
				Event Player.next_wall_value)));
				Event Player.next_wall_indices = Empty Array;
				Event Player.next_wall_stamps = Empty Array;
				Modify Player Variable(Event Player, next_wall_indices, Append To Array, Last Of(
					Global.Temp_notified_by.associated_node_position_indices));
				Modify Player Variable(Event Player, next_wall_stamps, Append To Array, Global.Nodes_stamp[Last Of(
					Global.Temp_notified_by.associated_node_position_indices)]);
				Event Player.next_wall_value = Vector(X Component Of(Position Of(Global.Temp_notified_by)), 0, 0);
			End;
		End;
		Event Player.requires_next_wall_update = False;
	}
}

rule("Notified players set next wall Z by other player")
{
	event
	{
		Ongoing - Each Player;
		All;
		All;
	}

	conditions
	{
		Is Alive(Event Player) == True;
		Event Player.requires_next_wall_update == True;
		Z Component Of(Event Player.player_direction) != 0;
	}

	actions
	{
		If(Z Component Of(Event Player.player_direction) > 0);
			If(Z Component Of(Position Of(Global.Temp_notified_by)) > Z Component Of(Position Of(Event Player)) && (Count Of(
				Event Player.next_wall_indices) <= 0 || Z Component Of(Position Of(Global.Temp_notified_by)) < Z Component Of(
				Event Player.next_wall_value)));
				Event Player.next_wall_indices = Empty Array;
				Event Player.next_wall_stamps = Empty Array;
				Modify Player Variable(Event Player, next_wall_indices, Append To Array, Last Of(
					Global.Temp_notified_by.associated_node_position_indices));
				Modify Player Variable(Event Player, next_wall_stamps, Append To Array, Global.Nodes_stamp[Last Of(
					Global.Temp_notified_by.associated_node_position_indices)]);
				Event Player.next_wall_value = Vector(0, 0, Z Component Of(Position Of(Global.Temp_notified_by)));
			End;
		Else If(Z Component Of(Event Player.player_direction) < 0);
			If(Z Component Of(Position Of(Global.Temp_notified_by)) < Z Component Of(Position Of(Event Player)) && (Count Of(
				Event Player.next_wall_indices) <= 0 || Z Component Of(Position Of(Global.Temp_notified_by)) > Z Component Of(
				Event Player.next_wall_value)));
				Event Player.next_wall_indices = Empty Array;
				Event Player.next_wall_stamps = Empty Array;
				Modify Player Variable(Event Player, next_wall_indices, Append To Array, Last Of(
					Global.Temp_notified_by.associated_node_position_indices));
				Modify Player Variable(Event Player, next_wall_stamps, Append To Array, Global.Nodes_stamp[Last Of(
					Global.Temp_notified_by.associated_node_position_indices)]);
				Event Player.next_wall_value = Vector(0, 0, Z Component Of(Position Of(Global.Temp_notified_by)));
			End;
		End;
		Event Player.requires_next_wall_update = False;
	}
}

rule("Set next wall X")
{
	event
	{
		Subroutine;
		set_next_wall_x;
	}

	actions
	{
		Event Player.T = Position Of(Event Player);
		Event Player.next_wall_indices = Empty Array;
		Event Player.next_wall_stamps = Empty Array;
		If(X Component Of(Event Player.player_direction) > 0 && Y Component Of(Global.Nodes_position_x[Global.Nodes_position_x_end])
			>= Event Player.last_checked_value);
			Event Player.temp_index = Global.Nodes_position_x_end;
			While(Event Player.temp_index != -1 && Y Component Of(Global.Nodes_position_x[Event Player.temp_index])
				>= Event Player.last_checked_value);
				If(Event Player.temp_index != Last Of(Event Player.associated_node_position_indices) && Y Component Of(
					Global.Nodes_links[Event Player.temp_index]) == 1);
					If(Y Component Of(Global.Nodes_position_x[Event Player.temp_index]) != Y Component Of(Global.Nodes_position_x[First Of(
						Event Player.next_wall_indices)]));
						Event Player.next_wall_stamps = Empty Array;
						Event Player.next_wall_indices = Empty Array;
					End;
					Modify Player Variable(Event Player, next_wall_indices, Append To Array, Event Player.temp_index);
					Modify Player Variable(Event Player, next_wall_stamps, Append To Array, Global.Nodes_stamp[Event Player.temp_index]);
					Event Player.next_wall_value = Vector(Y Component Of(Global.Nodes_position_x[Event Player.temp_index]), 0, 0);
				End;
				Event Player.temp_index = X Component Of(Global.Nodes_position_x[Event Player.temp_index]);
			End;
		Else If(X Component Of(Event Player.player_direction) < 0 && Y Component Of(Global.Nodes_position_x[Global.Nodes_position_x_start])
				<= Event Player.last_checked_value);
			Event Player.temp_index = Global.Nodes_position_x_start;
			While(Event Player.temp_index != -1 && Y Component Of(Global.Nodes_position_x[Event Player.temp_index])
				<= Event Player.last_checked_value);
				If(Event Player.temp_index != Last Of(Event Player.associated_node_position_indices) && Y Component Of(
					Global.Nodes_links[Event Player.temp_index]) == 1);
					If(Y Component Of(Global.Nodes_position_x[Event Player.temp_index]) != Y Component Of(Global.Nodes_position_x[First Of(
						Event Player.next_wall_indices)]));
						Event Player.next_wall_indices = Empty Array;
						Event Player.next_wall_stamps = Empty Array;
					End;
					Modify Player Variable(Event Player, next_wall_indices, Append To Array, Event Player.temp_index);
					Modify Player Variable(Event Player, next_wall_stamps, Append To Array, Global.Nodes_stamp[Event Player.temp_index]);
					Event Player.next_wall_value = Vector(Y Component Of(Global.Nodes_position_x[Event Player.temp_index]), 0, 0);
				End;
				Event Player.temp_index = Z Component Of(Global.Nodes_position_x[Event Player.temp_index]);
			End;
		End;
		Event Player.requires_next_wall_update = False;
	}
}

rule("Set next wall Z")
{
	event
	{
		Subroutine;
		set_next_wall_z;
	}

	actions
	{
		Event Player.T = Position Of(Event Player);
		Event Player.next_wall_indices = Empty Array;
		Event Player.next_wall_stamps = Empty Array;
		If(Z Component Of(Event Player.player_direction) > 0 && Y Component Of(Global.Nodes_position_z[Global.Nodes_position_z_end])
			>= Event Player.last_checked_value);
			Event Player.temp_index = Global.Nodes_position_z_end;
			While(Event Player.temp_index != -1 && Y Component Of(Global.Nodes_position_z[Event Player.temp_index])
				>= Event Player.last_checked_value);
				If(Event Player.temp_index != Last Of(Event Player.associated_node_position_indices) && Y Component Of(
					Global.Nodes_links[Event Player.temp_index]) == 0);
					If(Y Component Of(Global.Nodes_position_z[Event Player.temp_index]) != Y Component Of(Global.Nodes_position_z[First Of(
						Event Player.next_wall_indices)]));
						Event Player.next_wall_stamps = Empty Array;
						Event Player.next_wall_indices = Empty Array;
					End;
					Modify Player Variable(Event Player, next_wall_indices, Append To Array, Event Player.temp_index);
					Modify Player Variable(Event Player, next_wall_stamps, Append To Array, Global.Nodes_stamp[Event Player.temp_index]);
					Event Player.next_wall_value = Vector(0, 0, Y Component Of(Global.Nodes_position_z[Event Player.temp_index]));
				End;
				Event Player.temp_index = X Component Of(Global.Nodes_position_z[Event Player.temp_index]);
			End;
		Else If(Z Component Of(Event Player.player_direction) < 0 && Y Component Of(Global.Nodes_position_z[Global.Nodes_position_z_start])
				<= Event Player.last_checked_value);
			Event Player.temp_index = Global.Nodes_position_z_start;
			While(Event Player.temp_index != -1 && Y Component Of(Global.Nodes_position_z[Event Player.temp_index])
				<= Event Player.last_checked_value);
				If(Event Player.temp_index != Last Of(Event Player.associated_node_position_indices) && Y Component Of(
					Global.Nodes_links[Event Player.temp_index]) == 0);
					If(Y Component Of(Global.Nodes_position_z[Event Player.temp_index]) != Y Component Of(Global.Nodes_position_z[First Of(
						Event Player.next_wall_indices)]));
						Event Player.next_wall_indices = Empty Array;
						Event Player.next_wall_stamps = Empty Array;
					End;
					Modify Player Variable(Event Player, next_wall_indices, Append To Array, Event Player.temp_index);
					Modify Player Variable(Event Player, next_wall_stamps, Append To Array, Global.Nodes_stamp[Event Player.temp_index]);
					Event Player.next_wall_value = Vector(0, 0, Y Component Of(Global.Nodes_position_z[Event Player.temp_index]));
				End;
				Event Player.temp_index = Z Component Of(Global.Nodes_position_z[Event Player.temp_index]);
			End;
		End;
		Event Player.requires_next_wall_update = False;
	}
}

rule("Check for collision")
{
	event
	{
		Ongoing - Each Player;
		All;
		All;
	}

	conditions
	{
		Is Game In Progress == True;
		Is Alive(Event Player) == True;
		Count Of(Event Player.next_wall_indices) > 0;
		(Dot Product(Event Player.player_direction, Position Of(Event Player)) >= Dot Product(Event Player.player_direction,
			Event Player.next_wall_value)) == True;
	}

	actions
	{
		Event Player.T = Position Of(Event Player);
		"Check for collision with vertical wall"
		If(X Component Of(Event Player.player_direction) != 0);
			For Player Variable(Event Player, temp_index, 0, Count Of(Event Player.next_wall_indices), 1);
				If(
					Event Player.next_wall_stamps[Event Player.temp_index] == Global.Nodes_stamp[Event Player.next_wall_indices[Event Player.temp_index]]);
					Event Player.temp_value_1 = Y Component Of(Global.Nodes_position_z[Event Player.next_wall_indices[Event Player.temp_index]]);
					If(Z Component Of(Global.Nodes_links[Event Player.next_wall_indices[Event Player.temp_index]]) == -1);
						Event Player.temp_value_2 = Z Component Of(Position Of(
							Global.Nodes_associated_player_id[Event Player.next_wall_indices[Event Player.temp_index]]));
					Else;
						Event Player.temp_value_2 = Y Component Of(Global.Nodes_position_z[Z Component Of(
							Global.Nodes_links[Event Player.next_wall_indices[Event Player.temp_index]])]);
					End;
					Event Player.temp_value_3 = Z Component Of(Position Of(Event Player));
					Call Subroutine(kill_on_collision);
				End;
			End;
			If(Event Player.temp_index < 9999);
				Event Player.last_checked_value = X Component Of(Event Player.player_direction) * 0.001   X Component Of(
					Event Player.next_wall_value);
				Call Subroutine(set_next_wall_x);
			End;
		"Check for collision with horizontal wall"
		Else If(Z Component Of(Event Player.player_direction) != 0);
			For Player Variable(Event Player, temp_index, 0, Count Of(Event Player.next_wall_indices), 1);
				If(
					Event Player.next_wall_stamps[Event Player.temp_index] == Global.Nodes_stamp[Event Player.next_wall_indices[Event Player.temp_index]]);
					Event Player.temp_value_1 = Y Component Of(Global.Nodes_position_x[Event Player.next_wall_indices[Event Player.temp_index]]);
					If(Z Component Of(Global.Nodes_links[Event Player.next_wall_indices[Event Player.temp_index]]) == -1);
						Event Player.temp_value_2 = X Component Of(Position Of(
							Global.Nodes_associated_player_id[Event Player.next_wall_indices[Event Player.temp_index]]));
					Else;
						Event Player.temp_value_2 = Y Component Of(Global.Nodes_position_x[Z Component Of(
							Global.Nodes_links[Event Player.next_wall_indices[Event Player.temp_index]])]);
					End;
					Event Player.temp_value_3 = X Component Of(Position Of(Event Player));
					Call Subroutine(kill_on_collision);
				End;
			End;
			If(Event Player.temp_index < 9999);
				Event Player.last_checked_value = Z Component Of(Event Player.player_direction) * 0.001   Z Component Of(
					Event Player.next_wall_value);
				Call Subroutine(set_next_wall_z);
			End;
		End;
		Wait(0.016, Ignore Condition);
		Loop If Condition Is True;
	}
}

rule("Kill on collision")
{
	event
	{
		Subroutine;
		kill_on_collision;
	}

	actions
	{
		If(Event Player.shield_active == True || Is Alive(Event Player) == False);
			Abort;
		End;
		"Check if player position is between two nodes"
		If(Max(Event Player.temp_value_1, Event Player.temp_value_3) == Event Player.temp_value_1 && Max(Event Player.temp_value_2,
			Event Player.temp_value_3) == Event Player.temp_value_3);
			Play Effect(All Players(All Teams), Bad Explosion, Red, Event Player, 5);
			Kill(Event Player, Global.Nodes_associated_player_id[Event Player.next_wall_indices[Event Player.temp_index]]);
			Event Player.temp_index = 9999;
		Else If(Max(Event Player.temp_value_1, Event Player.temp_value_3) == Event Player.temp_value_3 && Max(Event Player.temp_value_2,
				Event Player.temp_value_3) == Event Player.temp_value_2);
			Play Effect(All Players(All Teams), Bad Explosion, Red, Event Player, 5);
			Kill(Event Player, Global.Nodes_associated_player_id[Event Player.next_wall_indices[Event Player.temp_index]]);
			Event Player.temp_index = 9999;
		End;
	}
}

rule("Kill out of border players")
{
	event
	{
		Ongoing - Each Player;
		All;
		All;
	}

	conditions
	{
		Is Game In Progress == True;
		Is Alive(Event Player) == True;
		Has Spawned(Event Player) == True;
		(Absolute Value(X Component Of(Position Of(Event Player))) > Global.Border_variable || Absolute Value(Z Component Of(Position Of(
			Event Player))) > Global.Border_variable) == True;
	}

	actions
	{
		Play Effect(All Players(All Teams), Bad Explosion, Purple, Event Player, 5);
		Kill(Event Player, Event Player);
	}
}

rule("Reset player on death")
{
	event
	{
		Player Died;
		All;
		All;
	}

	actions
	{
		Call Subroutine(reset_player);
		Event Player.requires_respawn = True;
	}
}

rule("Player joins")
{
	event
	{
		Ongoing - Global;
	}

	conditions
	{
		Global.Player_count < Count Of(All Players(All Teams));
	}

	actions
	{
		Global.Player_count = Count Of(All Players(All Teams));
		disabled Wait(1, Ignore Condition);
		disabled Loop If Condition Is True;
	}
}

rule("Player leaves")
{
	event
	{
		Ongoing - Global;
	}

	conditions
	{
		Global.Player_count > Count Of(All Players(All Teams));
	}

	actions
	{
		Call Subroutine(cleanup);
		Global.Player_count = Count Of(All Players(All Teams));
		disabled Wait(1, Ignore Condition);
		disabled Loop If Condition Is True;
	}
}

rule("Cleanup")
{
	event
	{
		Subroutine;
		cleanup;
	}

	actions
	{
		Abort If(Global.Temp_leave_index != 0);
		Global.Temp_leave_count = Count Of(Global.Nodes_associated_player_id);
		For Global Variable(Temp_leave_index, 0, Global.Temp_leave_count, 1);
			If(Global.Nodes_associated_player_id[Global.Temp_leave_index] != 0 && Array Contains(All Players(All Teams),
				Global.Nodes_associated_player_id[Global.Temp_leave_index]) == False);
				If(Global.Nodes_created_entities[Global.Temp_leave_index] != 0);
					Destroy Effect(Global.Nodes_created_entities[Global.Temp_leave_index]);
					Global.Nodes_created_entities[Global.Temp_leave_index] = 0;
				End;
				Global.Node_index_to_be_removed = Global.Temp_leave_index;
				Call Subroutine(remove_node_links);
				Call Subroutine(remove_node_x_z);
				Global.Nodes_associated_player_id[Global.Temp_leave_index] = 0;
			End;
			Wait(0.016, Ignore Condition);
		End;
		Global.Temp_leave_count = Count Of(Global.Movements_player_id);
		For Global Variable(Temp_leave_index, 0, Global.Temp_leave_count, 1);
			If(Global.Movements_player_id[Global.Temp_leave_index] != 0 && Array Contains(All Players(All Teams),
				Global.Movements_player_id[Global.Temp_leave_index]) == False);
				Global.Movements_player_direction[Global.Temp_leave_index] = 0;
				Global.Movements_player_x_z[Global.Temp_leave_index] = 0;
				Global.Movements_player_id[Global.Temp_leave_index] = 0;
			End;
			Wait(0.016, Ignore Condition);
		End;
		Global.Temp_leave_index = 0;
	}
}

rule("Reset player")
{
	event
	{
		Subroutine;
		reset_player;
	}

	actions
	{
		Call Subroutine(disable_shield_break);
		Event Player.requires_initial_spawn = 0;
		Start Forcing Throttle(Event Player, 0, 0, 0, 0, 0, 0);
		Stop Accelerating(Event Player);
		Wait(0.250, Ignore Condition);
		Destroy Effect(Event Player.dynamic_wall);
		Event Player.dynamic_wall = 0;
		While(Count Of(Event Player.associated_node_position_indices) > 0);
			Call Subroutine(remove_node);
			Wait(0.016, Ignore Condition);
		End;
		Event Player.associated_node_position_indices = Empty Array;
		Event Player.next_wall_indices = Empty Array;
		Event Player.requires_next_wall_update = False;
		Event Player.next_node_position = 0;
		Event Player.previous_node_position = 0;
		Event Player.next_wall_stamps = Empty Array;
		Event Player.next_wall_value = 0;
	}
}

rule("Enable shield")
{
	event
	{
		Subroutine;
		enable_shield_break;
	}

	actions
	{
		Event Player.shield_active = True;
		Create Effect(All Players(All Teams), Sphere, Aqua, Event Player, 1, Visible To Position and Radius);
		Modify Player Variable(Event Player, shield_entities, Append To Array, Last Created Entity);
		Create HUD Text(Event Player, Custom String("{0}", Icon String(Ring Thick)), Custom String("Shield"), Custom String(
			"Move through walls unharmed"), Left, 0, Aqua, Aqua, White, Visible To and String, Default Visibility);
		Modify Player Variable(Event Player, shield_entities, Append To Array, Last Text ID);
		Small Message(Event Player, Custom String("Shield enabled"));
	}
}

rule("Disable shield")
{
	event
	{
		Subroutine;
		disable_shield_break;
	}

	actions
	{
		Event Player.shield_active = False;
		If(Count Of(Event Player.shield_entities) <= 0);
			Abort;
		End;
		Destroy Effect(First Of(Event Player.shield_entities));
		Destroy HUD Text(Last Of(Event Player.shield_entities));
		Event Player.shield_entities = Empty Array;
		Play Effect(All Players(All Teams), Ring Explosion, Aqua, Event Player, 4);
		Small Message(Event Player, Custom String("Shield disabled"));
	}
}

disabled rule("Test - Static wall")
{
	event
	{
		Ongoing - Global;
	}

	actions
	{
		Global.Nodes_position_x[0] = Vector(3, -10, 1);
		Global.Nodes_position_z[0] = Vector(2, 10, 1);
		Create Beam Effect(All Players(All Teams), Good Beam, Vector(-10, 0.500, 10), Vector(10, 0.500, 10), White,
			Visible To Position and Radius);
		Global.Nodes_position_x[1] = Vector(0, 10, 2);
		Global.Nodes_position_z[1] = Vector(0, 10, -1);
		Create Beam Effect(All Players(All Teams), Good Beam, Vector(10, 0.500, 10), Vector(10, 0.500, -10), White,
			Visible To Position and Radius);
		Global.Nodes_position_x[2] = Vector(1, 10, -1);
		Global.Nodes_position_z[2] = Vector(3, -10, 0);
		Create Beam Effect(All Players(All Teams), Good Beam, Vector(10, 0.500, -10), Vector(-10, 0.500, -10), White,
			Visible To Position and Radius);
		Global.Nodes_position_x[3] = Vector(-1, -10, 0);
		Global.Nodes_position_z[3] = Vector(-1, -10, 2);
		Global.Nodes_position_x_start = 3;
		Global.Nodes_position_x_end = 2;
		Global.Nodes_count = 4;
		Global.Nodes_position_z_start = 3;
		Global.Nodes_position_z_end = 1;
		Global.Nodes_links[0] = Vector(-1, 0, 1);
		Global.Nodes_links[1] = Vector(0, 1, 2);
		Global.Nodes_links[2] = Vector(1, 0, 3);
		Global.Nodes_links[3] = Vector(2, 0, -1);
	}
}

disabled rule("Test - Bot")
{
	event
	{
		Ongoing - Global;
	}

	conditions
	{
		Is Game In Progress == True;
	}

	actions
	{
		Big Message(All Players(All Teams), Custom String("Bot created"));
		Create Dummy Bot(Hero(Wrecking Ball), All Teams, -1, Vector(10, 0.500, 0), Vector(0, 0, 0));
	}
}

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

	actions
	{
		"For updates, check the Discord"
		Create HUD Text(All Players(All Teams), Null, Null, Custom String("discord.gg/YP544CH"), Right, 0, White, White, Sky Blue,
			Visible To and String, Default Visibility);
		Create HUD Text(All Players(All Teams), Null, Null, Custom String("V1.01 (20-06-14)"), Right, 1, White, White, White,
			Visible To and String, Default Visibility);
		Create HUD Text(All Players(All Teams), Custom String("{0}", Icon String(Exclamation Mark)), Custom String("Change Camera"),
			Custom String("Press Reload"), Left, -1, White, White, White, Visible To and String, Default Visibility);
		Create HUD Text(All Players(All Teams), Custom String("{0}", Icon String(Exclamation Mark)), Custom String("Avoid hitting walls"),
			Custom String("(Unless you have a shield)"), Left, -2, Yellow, White, White, Visible To and String, Default Visibility);
	}
}

disabled rule("Debug - UI")
{
	event
	{
		Ongoing - Global;
	}

	actions
	{
		Create HUD Text(Host Player, Null, Null, Custom String("{0} (Current load)n{1} (Average load) n{2} (Peak load)", Server Load,
			Server Load Average, Server Load Peak), Left, 99, White, White, White, Visible To and String, Default Visibility);
	}
}

disabled rule("Debug - World")
{
	event
	{
		Ongoing - Global;
	}

	conditions
	{
		Total Time Elapsed > 3;
	}

	actions
	{
		Create Effect(Host Player, Light Shaft, White, Vector(0, 0, 0), 1, None);
		Create Beam Effect(Host Player, Bad Beam, Vector(0, 1, 0), Vector(5, 1, 0), Green, Visible To Position and Radius);
		Create Beam Effect(Host Player, Good Beam, Vector(0, 1, 0), Vector(0, 1, 5), Blue, Visible To Position and Radius);
		For Global Variable(Temp_index, 0, Count Of(Global.Initial_spawn_positions), 1);
			Create Effect(All Players(All Teams), Sphere, White, Global.Initial_spawn_positions[Global.Temp_index], 2, Visible To);
		End;
	}
}

disabled rule("Debug - Player")
{
	event
	{
		Ongoing - Each Player;
		All;
		All;
	}

	actions
	{
		disabled Event Player.B = Velocity Of(Event Player);
		disabled Wait(0.050, Ignore Condition);
		disabled Loop;
	}
}

rule("Have Fun! -CuddlyFlower")
{
	event
	{
		Ongoing - Global;
	}
}

Changelog

6 months ago 1.0.1

  • Fixed afk score gain
  • Changed map to night version for better visibility

HHTS9
click to copy
6 months ago 1.0.0

  • Disabled debug rules for first 1.0 release

HHTS9
click to copy
9 months ago 0.9.2

  • Fixed crash after player leaving, should be more stable now in general

9HYEX
click to copy
9 months ago 0.9.1

  • Fixed a variety of bugs
  • Added first power up, which gives additional points when collected (green spheres)

VT7SY
click to copy
9 months ago 0.9.0

This revision contains no notes

Z0J3M
click to copy