Power Plays are the traps of a level: the fuel trucks, the parked cars and coaches, the helicopters, and the big ones that change the route. ss.powerplays lists every Power Play the loaded level has, whether a player could reach it right now or not, and a script can set one off, reset it or switch it off. A Power Play is a live object: reading a field reads the game at that moment. Power Plays only exist within a race.

Static members#

These elements are static to the class itself and can be accessed like so:

local ahead = ss.powerplays.near(ss.vehicle.position, 150)

Static functions#

FunctionReturn ValuesDescription
ss.powerplays[integer index] powerplay powerplay Returns the Power Play at the given index: 0-based, in the level's own order. Returns nil if there is no such Power Play.
ss.powerplays.count integer count The number of Power Plays in the loaded level. 0 outside a race.
ss.powerplays.all() table of powerplay powerplays Returns a table of references to all Power Plays in the loaded level.
ss.powerplays.each() function iterator Returns an iterator over all Power Plays in the loaded level, for use in a for loop.
ss.powerplays.find(string pattern) table of powerplay powerplays Returns a table of references to all Power Plays whose name matches the given Lua pattern, case-insensitively. find("fueltruck") returns every fuel truck; find("^Cars_5$") returns the one with exactly that name.
ss.powerplays.near( vector-like point, number radius ) table of powerplay powerplays Returns a table of references to all Power Plays within the given radius, in metres, of the given point, nearest first. The radius defaults to 100. Power Plays without a position are never in the result.

Instance members#

Instance members must be accessed through a reference to a specific Power Play object.

local truck = ss.powerplays.find("fueltruck")[1]
if truck.ready then truck:fire(ss.player) end
WARNING: Attempting to call instance members statically will result in an error!

Instance Methods#

What is a method?

FunctionReturn ValuesDescription
fire() boolean fired, string reason Sets the Power Play off as nobody's. Returns true if the game accepted the fire. Otherwise returns false and the reason; see Firing a Power Play.
fire( player who ) boolean fired, string reason Sets the Power Play off as the given player's. who can be a player, a vehicle or a player index. Results in an error if that player is not in the race.
fire( player who, integer trigger ) boolean fired, string reason Sets the Power Play off by one of its triggers, 0-based, for Power Plays that have more than one. Pass nil for who to fire it as nobody's.
reset() boolean reset Puts the Power Play back as the level loaded it, so that it can be fired again. The game does this on its next frame, and the Power Play is idle about a second later. Also works while the Power Play is playing.
mem( integer offset, string type ) any value Returns a value of the Power Play's object at a specific memory address-offset. See ss.mem for the types.
mem( integer offset, string type, any value ) nil Sets a value of the Power Play's object at a specific memory address-offset.
memdump( integer lowerBound, integer upperBound ) nil Logs the current state of the object's memory addresses in the given range, for debugging.

Instance Fields#

TypeFieldRead-only?Description
boolean valid Yes Validates that the Power Play exists in the loaded level. A Power Play kept across the end of a race becomes invalid: its fields read nil and its methods result in an error.
string name Yes The Power Play's name in the level, such as FuelTruck, Cars_5 or PA11_PetrolStation_P.
integer index Yes The Power Play's index, as taken by ss.powerplays[index] and passed by the powerplay event.
integer id Yes The game's own id for the Power Play. The powerplay event passes the same number as id.
vec3 position Yes Where the Power Play stands, in metres. nil for Power Plays that keep no position of their own: the route changes and the ones that belong to Nemesis actors.
integer level Yes The number of power bar segments the Power Play costs a player: 1, or 3 for the route changes and the other big ones. A fire from a script costs nothing.
integer triggers Yes The number of triggers the Power Play has. Most have 1. A Power Play with 0 triggers cannot be fired.
string state Yes idle (nothing of it has gone off), playing (going off right now) or played (over). Most Power Plays stay played until they are reset; a few return to idle by themselves.
boolean ready Yes Whether the game would accept a fire of the Power Play right now. False while it is going off, after it has gone off, and while it is switched off. See Firing a Power Play.
boolean enabled No Whether the Power Play is part of the race. Setting this field to false switches it off for everybody: no player and no AI can fire it, and neither can a script.
integer address Yes The address of the Power Play's object, for ss.mem.

Instance Memory Offsets#

These offsets can be manipulated by the instance's mem method. They are relative to address.

WARNING: Be careful when manipulating memory offsets directly! Doing so may yield unexpected results.
FieldFieldtypeDescription
0x50 int The number of triggers. Use field triggers
0x58 float The timer, in seconds. It runs while the Power Play is playing.
0x60 int 1 while the timer runs. Use field state
0x94 3 floats The position. Use field position
0x120 int The id. Use field id
0x1bc byte The reset request. The game clears it once the reset is done. Use method reset
0x1c6 u16 The level. Use field level
0x1ec byte Enabled. Use field enabled

Firing a Power Play#

fire hands the Power Play to the game the same way a player's button does, so everything that follows is the game's own: the explosion, the wrecks, the debris. The Power Play goes off two frames later, and that is when the powerplay event runs, with scripted set to true.

A fire from a script is free. It does not look at anybody's power bar and does not spend it, and the Power Play's level does not matter. Nobody has to be near it either.

Some of the big Power Plays can be fired a second time a while after the first, as they can by a player. ready reads true again when that second fire is possible, even though state still reads playing.

When the game cannot accept the fire, fire returns false and one of these reasons:

TypeFieldDescription
string it is playing The Power Play is going off right now and has no further stage ready.
string it has played and was not reset Most Power Plays go off once. Call reset first, then fire it again about a second later.
string it is queued already The same Power Play was fired twice in one frame.
string it is switched off Its enabled field is false.
string no such trigger The trigger index is past the Power Play's triggers, or the Power Play has none.
string that trigger plays nothing The trigger exists but is empty. Use another trigger of the Power Play.
string the fire queue is full The game takes at most 32 fires per frame.
-- Fires every Power Play near the leader as the local player's, once every five seconds.
ss.on("race_start", function()
	ss.every(5, function()
		local leader
		for car in ss.vehicles.each() do
			if not leader or car.race.position < leader.race.position then leader = car end
		end
		if not leader or leader.is_local then return end
		for _, pp in ipairs(ss.powerplays.near(leader.position + leader.forward * 40, 120)) do
			if pp.ready then pp:fire(ss.player) end
		end
	end)
end)

Using a Power Play again#

Most Power Plays go off once and then stay played. reset rebuilds one through the game's own reset. Wait until ready reads true before firing it again.

-- Blows up the same row of parked cars every eight seconds.
local cars = ss.powerplays.find("^Cars_5$")[1]
ss.every(8, function()
	if not cars.valid then return end
	if cars.ready then
		cars:fire()
	elseif cars.state == "played" then
		cars:reset()
	end
end)

Switching a Power Play off#

Setting enabled to false takes a Power Play out of the race for everybody. It is in nobody's reach, the AI's included, and fire returns false. Setting it back to true brings it back.

-- The airport without its two route changes.
ss.on("race_start", function()
	for _, pp in ipairs(ss.powerplays.find("^RCA")) do pp.enabled = false end
end)
NOTE: The names and the number of Power Plays are different on every track. Log them once with for pp in ss.powerplays.each() do ss.log(tostring(pp)) end to see what a track has.