Releases: ScriptedEvents/ScriptedEvents
Version 3.5.0 for EXILED 9.10.0
Changes
- Updated to EXILED 9.10.0, fixing console errors
Version 3.4.0 for EXILED 9.8.0+
Bug fixes:
- Fixed the
!-- EVENTflag, courtesy of exiled devtools
Breaking changes:
- None
Additions:
- {STR-FLOORIFY} variable
Version 3.2.3
Version 3.2.2
Added
- EFFECTIMMUNITYRULE action
- {MAPSEED} variable
(these features were supposed to be added much earlier, but this did not happen due to our VCS issues)
Fixed
- {CUFFER} variable not being usable as intended
Version 3.2.1
Version 6.6.6 (v3.2.0)
Happy Halloween! A very spooky version 6.6.6 has been released!
Changes
- Updated to Exiled 8.13.1
- Fixed spooky null reference exceptions
- Updated all sample scripts to work with the current version
- SE will scream at you if scripts with the same names exist
- Fixed the
scr exacommand - Documentation generator will now require you to have matching plugin and documentation versions
- Improved vague documentation generator messages
Join our Discord server!
Version 3.1.8
Version 3.1.7
Version 3.1.6
Another release with another batch of amazing features and the obligatory bug fixes. Thank you all for the constant support in the development of SE!
Better EXILED event integration
A long awaited feature has finally been added; every EXILED event variable will now be available as a Scripted Events variable! But what does it change?
- You will now be able to access a lot more information from your event
Lists, dictionaries and arrays are currently not supported; this will be added in the next update. If you try to access a list variable you will be greeted with something similar to System.Collections.Generic.List'1[ItemType].
- All documentation in EXILED events should line up with Scripted Events
- Old scripts should be unaffected
Note
Scripts triggered by events start running only after the event has happened. This is important to keep in mind as EXILED event variables are usually referencing the state before the event has happened.
Tip
Try to limit the amount of unnecessary EXILED event scripts, as they may to take up to 6ms to process all of the event variables.
But that's not all!
Using the EVENT action, you can now block any deniable EXILED event! This works similar to DISABLEPLAYER action, but with much more flexibility + the event doesn't have to be a player event.
There is also a tutorial attached to the action for how to check if an event is deniable.
API finally gets some love
The API has been reworked to add new features and fix some legacy bugs.
We now also have an extensive up-to-date example of our API in action available here.
Note
Other plugins using the SE API might take some time before updating to the newer version. You can contact the respective plugin developers in order to inform them about the change, if it causes any issues.
Smart arguments
There is a new way of handling action inputs: Smart arguments! These allow you to effortlessly pass arguments to actions in ways not possible before, as well as making scripts more readable.
Here are 2 examples of smart args in action:
# look how we have to make a new variable >:(
LOCAL {CAMP_TIME} {GET:PLR:CampingTime} + 1
PLAYERDATA SET {PLR} CampingTime {CAMP_TIME}
# less syntax & doesnt create useless variables!
PLAYERDATA SET {PLR} CampingTime #1
// {GET:PLR:CampingTime} + 1
# this line is one of the reasons smart arguments were added lmao
CALL FuncIsInRange {GET:PLR:LastPosX} {GET:PLR:LastPosY} {GET:PLR:LastPosZ} {GET:EVPLAYER:POSX} {GET:EVPLAYER:POSY} {GET:EVPLAYER:POSZ} 12
# and thats how it looks with smart args
CALL FuncIsInRange #1 #2 #3 #4 #5 #6 #7
// {GET:PLR:LastPosX}
// {GET:PLR:LastPosY}
// {GET:PLR:LastPosZ}
// {GET:EVPLAYER:POSX}
// {GET:EVPLAYER:POSY}
// {GET:EVPLAYER:POSZ}
// 12
Warning
Smart arguments will try to perform math and condition checks before passing the value. Because of that, player variables do not work with smart arguments. This issue will be addressed in a later release.
Note
Some actions (especially third-party ones) might not fully support this feature. Please keep that in mind when using.
Value extraction from actions
Value extraction is a tool for a better way returning values using actions!
Variables can be named in any way, the only thing that matters is the order in which they are named. The 1st variable on the left will receive the 1st value returned by the action, the 2nd variable will get the 2nd value and so on.
Important
If there isn't any value for variables to take (like when there are too little values returned), they will not be created at all.
It's good to check if the variable was created using the {VEXISTS} variable.
As of now, this system is used only by custom actions made with the API, but going forward this will be the default system for creating variables in Scripted Events.
Full changelog
Additions
Actions
- EVENT
disable any event for specified players
- SPAWNRAGDOLL
spawn ragdolls at the specified XYZ coordinates
- TPPLAYER action
teleport one or more players to another player
- DROPITEM action
drop specified items from player inventories
Variables
- AHP mode to {GET} variable
check how much AHP a player has
- VARIABLES option to {THIS} variable
check what local variables are available
- {STR-UPPER} variable
make all letters in the variable uppercase
- {STR-LOWER} variable
make all letters in the variable lowercase
- {STR-REMOVE} variable
remove specified letters in the variable
- Smart arguments
- Variable extraction
Refactors
Note
Please ensure that all of your scripts are updated using the information below.
- LOBBYLOCK TRUE -> LOBBY LOCK
- LOBBYLOCK FALSE -> LOBBY UNLOCK
- ROUNDLOCK TRUE -> ROUND LOCK
- ROUNDLOCK FALSE -> ROUND UNLOCK
- ROUNDSTART -> ROUND START
- ROUNDEND -> ROUND END
- ADDTO -> APPEND
- {GET} variable will now return UNDEFINED instead of NONE when provided with an invalid key
Fixed
- {GET} variable ITEMCOUNT and ITEMS keys
- Scripts stopping when variable syntax is not used properly
- HTTPPOST not processing variables
- Event scripts not running after a round restart
- API not working when used by a plugin with a priority higher than SE
- \n not working for PRINTPLAYER action
- Some errors not appearing when running a script from Remote Admin console
v3.0.0
Version 3.0
It's real guys. This is a HUGE release, which means likely (definitely) all of your scripts will not function after updating. Don't worry, we will be available to help on our Discord server.
Main changes
They aren't ordered in any way, just so you know ![]()
shelp documentation generator
Tired of constantly using shelp for every single action/variable? Fear not, for now you can generate updated documentation on your PC, with descriptions and examples directly from the plugin's source code. Run shelp GENERATE in your server console to begin.
Disclaimer: This generated documentation will not update when SE updates, you'll need to re-run the generate command.
New safety system
We are glad to introduce to you our new safety system for ScriptedEvents! Thanks to it, you don't have to worry about your script crashing the server or the script randomly stopping. It's actually really simple; a tiny delay is added after every completed action. This delay is dependent on the tick speed on your server, where one action will be executed every tick. This shouldn't affect most scripts, but if you require the most performance, you can use the !-- NOSAFETY flag to remove the delay.
Multi-line comments
It's a very simple addition, but it's surprisingly helpful for creating script documentation. To enter or exit a multi-line comment, you have to use a double hashtag (##). If you leave a single double hashtag at the beginning of the script, it will be treated as the entire script being a comment. This is easier to spot if you use our VS Code extension.
##
look at
this beautiful
multi line comment!
##
PRINT hello!
Local variables
You can now use LOCAL and LOCALPLAYERVAR actions to manage variables accessible in that script only! We recommend you always use local variables unless you want the variable to be accessible in other scripts on purpose.
Custom events
Using the new TRIGGER action, you can register your own events and subscribe to other events using the !-- CUSTOMEVENT flag.
# example script 1
!-- CUSTOMEVENT test
LOG Tested!
# example script 2
LOG Testing!
TRIGGER test
output:
> Testing!
> Tested!
Folders
Instead of having one giant folder for everything, Scripted Events will now separate everything into custom subfolders. This includes Scripts, Documentation and VariableStorage folders (and Commands folder in the future).
Action and variable reworks
Close to all actions and variables were modified in some way or another. Do not assume that if a certain action still exists, it works in the exact same way. We recommend you have a good look at the new documentation before updating your scripts.
New error system
Errors should now provide you with a lot more information and be a lot more consistent. You can also get more information about them using shelp. Here is an example of the shelp SE-108 command:
=== ERROR CODE ===
ID: SE-108
The specified event '{0}' in the 'On' config was not found!
This error occurs when an invalid event name is provided in the on Exiled config. This error can be resolved by checking for typos in the name of events and referencing Exiled's list of provided events.
Argument processing
Our new ArgumentProcessor will verify if all of the action arguments provided are of the correct type before the action is executed. Together with the new error system, this will help with finding all argument related bugs in your scripts.
Functions
Functions are reusable snippets of code, allowing you to stop copy pasting the same code over and over again in different places. These are very powerful and we aim to upgrade ScriptedEvents from being a procedural programming language to a functional programming language in the future!
Function labels
Function labels work similarly to labels, but they have a defined end. When you reach the end of a function label, the script will continue execution from the last place the function was called from. Function labels use -> and <- syntax.
# example script
LOG i'm gonna call a function
GOTO Function
LOG i left a function
STOP
-> Function
LOG i'm inside of a function
<-
output:
> i'm gonna call the function
> i'm inside of the function
> i left the function
Function scripts
Function scripts are normal scripts, but they're not to be called by a player, but rather another script. You can also provide and return values to and from a function script. When values are provided to a called script, they will be encapsulated in variables like {ARG1}, {ARG2} etc.. When variables are returned from a script, they inherit their name from the function script.
# example script
CALL GetRandomPlayer {PLAYERS}
LOG Our random player is: {GET:RANDOM_PLAYER:NAME}
# example function script GetRandomPlayer.txt
IF {!VEXISTS:ARG1}
ERROR {THIS} - players were not provided
STOP
ENDIF
LOCALPLAYERVAR SET {RANDOM_PLAYER} {LIMIT:ARG1:1}
RETURN {RANDOM_PLAYER}
output:
> Our random player is: Josh
Action decorators
Action decorators are things you put after an action, which modify the behavior of said action. There are currently 2 action decorators: $IF and $FOR.
$IF action decorator
$IF allows an action to execute only if the condition provided results in TRUE.
# example script
LOG Players: {PLAYERS}
LOG players on server $IF {PLAYERS} > 0
LOG no players on server $IF {PLAYERS} = 0
output:
> Players: 0
> no players on server
$FOR action decorator
$FOR is a decorator that will repeat an action per every player in a variable, and assigning said player to its own variable. It follows the following syntax - $FOR [singlePlayerVar] IN [loopingPlayerVar], where [singlePlayerVar] is the variable which will be assigned the player currently looping through, and [loopingPlayerVar] is the variable from which the players will be looped over.
# example script
LOG Hello, {GET:PLR:NAME}! $FOR {PLR} IN {PLAYERS}
output:
> Hello, John!
> Hello, Jack!
> Hello, Josh!
Using $IF and $FOR together
These decorators are very powerful, but what if we were to combine them? Using this syntax - $IF [condition] $FOR [singlePlayerVar] IN [loopingPlayerVar] we can run a certain action per each player, but only if the condition is met for that player.
# example script
LOG All players: {DISPLAY:PLAYERS}
LOG {GET:PLR:NAME} has low hp ({GET:PLR:HP}) $IF {GET:PLR:HP} < 40 $FOR {PLR} IN {PLAYERS}
output:
> All players: Josh, Jack, John
> Jack has low hp (37)
> John has low hp (14)
This is where the functions come in
As good as that is, there is one drawback to it; readability. Fortunately, we have a solution to that! Using function labels, we can create a function that will be called for every player, and the rest of the logic can stay inside of that function. This is how it would look like when using functions:
# example script
LOG All players: {DISPLAY:PLAYERS}
GOTO LowHealthInfo $FOR {PLR} IN {PLAYERS}
STOP
-> LowHealthInfo
<- $IF {GET:PLR:HP} < 40
LOG {GET:PLR:NAME} has low hp ({GET:PLR:HP})
<-
output:
> All players: Josh, Jack, John
> Jack has low hp (37)
> John has low hp (14)
Case insensitivity
Do you hate writing all actions and variables in UPPERCASE? Constantly juggling with shift is kind of a pain, and we know it. Fortunately, version 3.0 introduces case insensitivity for actions and variables. Of course, the "recommended" way will still be writing actions and variables in uppercase, but who cares?
log we have {players} players on the server: {display:players}
output:
> we have 3 players on the server: Josh, Jack, John
New IF "statements"
Version 3.0 introduces a new way of handling IF statements! IF action now works completely differently. Instead of stopping the script if the condition evaluates to FALSE, the script will continue executing, but actions will be blocked from running. The block will be lifted after encountering an ENDIF action. There also exists a FLIPIF action, which will flip the state of the IF block, so if action execution was blocked before, it won't be after it.
Because these are not actual statements, it means that you stack them. This is tragic since it forces people to write something known as "clean code".
# example script
!-- EVENT ChangingItem
# ev item will not be provided when player changes to an empty hand
IF {VEXISTS:EVITEM}
LOG EVITEM exists, were good to go
FLIPIF
LOG EVITEM does not exist, stopping the script
STOP
ENDIF
LOG simulating work here…
output (when changing to an empty hand):
> EVITEM does not exist, stopping the script
output (when changing to a valid item):
> EVITEM exists, were good to go
> simulating work here…
Indentation
If you weren't using one of the bajillion pre-release versions of 3.0, you are probably surprised to see indentation being used in SE. How does this affect the way you have to write scripts? Well, fear not, as indentation is only just pure formatting sugar! When scripts are read and cached, all indentation is removed. It exists just so quiche eaters could have some false sense of safety.
Full Changelog
We have probably missed some stuff along these like 5 months of development, so we attached the full changelog for those brave enough to try and read it.
v2.8.0...v3.0.0

