├── .github └── FUNDING.yml ├── .gitignore ├── CHANGES.md ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake └── toolchain-mingw.cmake ├── docs ├── CNAME ├── download.md ├── engine │ ├── actor.md │ ├── androidplatform.md │ ├── animation.md │ ├── behavior.md │ ├── brick.md │ ├── camera.md │ ├── circular_movement.md │ ├── collider.md │ ├── collisionball.md │ ├── collisionbox.md │ ├── delayedevent.md │ ├── directional_movement.md │ ├── enemy.md │ ├── entity.md │ ├── entityevent.md │ ├── event.md │ ├── eventchain.md │ ├── eventlist.md │ ├── functionevent.md │ ├── game.md │ ├── input.md │ ├── lang.md │ ├── level.md │ ├── mobile_gamepad.md │ ├── mouse.md │ ├── music.md │ ├── platform.md │ ├── platformer.md │ ├── player.md │ ├── prefs.md │ ├── screen.md │ ├── sensor.md │ ├── sound.md │ ├── surgeengine.md │ ├── text.md │ ├── transform.md │ ├── vector2.md │ ├── video.md │ └── web.md ├── img │ ├── favicon.ico │ ├── state-machine.png │ ├── surge.png │ └── tree.png ├── index.md ├── js │ ├── analytics.js │ └── donate.js ├── reference │ ├── application.md │ ├── arguments.md │ ├── array.md │ ├── boolean.md │ ├── console.md │ ├── date.md │ ├── dictionary.md │ ├── gc.md │ ├── iterator.md │ ├── math.md │ ├── number.md │ ├── object.md │ ├── plugin.md │ ├── string.md │ ├── surgescript.md │ ├── system.md │ ├── tags.md │ └── time.md └── tutorials │ ├── advanced_features.md │ ├── best_practices.md │ ├── comments.md │ ├── components.md │ ├── conditionals.md │ ├── expressions.md │ ├── functions.md │ ├── hello.md │ ├── loops.md │ ├── object_tree.md │ ├── objects.md │ ├── packages.md │ ├── properties.md │ ├── selections.md │ ├── tags.md │ ├── testing.md │ └── variables.md ├── examples ├── alfred_the_npc.ss ├── arguments.ss ├── array.ss ├── component.ss ├── count_to_10.ss ├── date.ss ├── dictionary.ss ├── factory.ss ├── garbage_collector.ss ├── getters_setters.ss ├── hello.ss ├── package.ss ├── performance.ss ├── sort_array.ss ├── switch.ss ├── tags.ss ├── timeout.ss ├── type_a_number.ss └── unit_testing.ss ├── mkdocs.yml └── src ├── main.c ├── surgescript.h └── surgescript ├── compiler ├── asm.c ├── asm.h ├── lexer.c ├── lexer.h ├── nodecontext.h ├── parser.c ├── parser.h ├── symtable.c ├── symtable.h ├── token.c └── token.h ├── misc ├── icon.png ├── iconwin.rc ├── info.c.in ├── pack-windows.sh ├── surgescript.appdata.xml.in ├── surgescript.ico ├── surgescript.pc.in └── surgescript.png ├── runtime ├── heap.c ├── heap.h ├── managed_string.c ├── managed_string.h ├── object.c ├── object.h ├── object_manager.c ├── object_manager.h ├── program.c ├── program.h ├── program_operators.h ├── program_pool.c ├── program_pool.h ├── renv.c ├── renv.h ├── sslib │ ├── application.c │ ├── arguments.c │ ├── array.c │ ├── boolean.c │ ├── console.c │ ├── date.c │ ├── dictionary.c │ ├── gc.c │ ├── math.c │ ├── number.c │ ├── object.c │ ├── plugin.c │ ├── sslib.h │ ├── string.c │ ├── surgescript.c │ ├── system.c │ ├── tags.c │ ├── temp.c │ └── time.c ├── stack.c ├── stack.h ├── tag_system.c ├── tag_system.h ├── variable.c ├── variable.h ├── vm.c ├── vm.h ├── vm_time.c └── vm_time.h ├── third_party ├── gettimeofday.h ├── utf8.c ├── utf8.h ├── uthash.h ├── xoroshiro128plus.c ├── xxhash.c └── xxhash.h └── util ├── fasthash.c ├── fasthash.h ├── perfect_hash.c ├── perfect_hash.h ├── ssarray.h ├── transform.c ├── transform.h ├── util.c ├── util.h └── version.h.in /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: alemart # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Specifies intentionally untracked files to ignore when using Git 2 | # http://git-scm.com/docs/gitignore 3 | 4 | # vscode 5 | .vscode 6 | .vscode/* 7 | !.vscode/settings.json 8 | !.vscode/tasks.json 9 | !.vscode/launch.json 10 | !.vscode/extensions.json 11 | 12 | # msvc 13 | .vs/ 14 | out/ 15 | CMakeSettings.json 16 | 17 | # vim 18 | # swap 19 | [._]*.s[a-v][a-z] 20 | [._]*.sw[a-p] 21 | [._]s[a-v][a-z] 22 | [._]sw[a-p] 23 | # session 24 | Session.vim 25 | # temporary 26 | .netrwhist 27 | *~ 28 | 29 | # mine 30 | docs_html/ 31 | build/ 32 | private/ 33 | CMakeFiles/ 34 | !src/** 35 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | # Release Notes 2 | 3 | ## 0.6.1 - August 23rd, 2024 4 | 5 | * Introduced switch statements 6 | * Made optional the expressions in for loops 7 | * Added an optional message to assertions 8 | * Bugfix in continue statements 9 | * Updated docs 10 | * General improvements 11 | 12 | ## 0.6.0 - May 17th, 2024 13 | 14 | * Optimized function calls with self-modifying SurgeScript bytecode that recognizes opportunities for optimization 15 | * Optimized tag tests with faster hashes and bitsets 16 | * Optimized the allocation and the deallocation of strings with a pool of managed strings 17 | * Introduced do-while loops 18 | * Changed `Math.mod()` so that it returns the modulo instead of the remainder 19 | * Made various updates and additions to the standard library 20 | * Updated the documentation 21 | * Updated the CLI 22 | * Added support for reading scripts in virtual files 23 | * Removed support for emoticons 24 | * General improvements to the code. Bugfixes 25 | 26 | ## 0.5.6.1 - September 22nd, 2022 27 | 28 | * Tweaks to the build system 29 | 30 | ## 0.5.6 - September 1st, 2022 31 | 32 | * Improved the SurgeScript CLI with a time limit option, the ability to run scripts from stdin and optional multithreading support 33 | * Added Visual Studio support (Cody Licorish) 34 | * Added Emscripten support 35 | * Updated docs 36 | * General improvements 37 | 38 | ## 0.5.5 - January 22nd, 2021 39 | 40 | * Added the ability to pause the SurgeScript VM 41 | * Added utility macros for checking the SurgeScript version at compile time 42 | * Introduced a dedicated module for keeping track of time 43 | * Renamed Object.childCount to Object.__childCount 44 | * Updated docs 45 | 46 | ## 0.5.4.4 - April 16th, 2020 47 | 48 | * Added LIB_SUFFIX compilation option 49 | * Updated docs 50 | 51 | ## 0.5.4.3 - February 16th, 2020 52 | 53 | * SurgeScript is now available as a shared library 54 | * Added pkg-config files to make it easy to link a program to libsurgescript 55 | * Improved interoperability with C++ 56 | * Included AppStream metadata for Linux and for the free software ecosystem 57 | * Built-in iterables and iterators are now tagged "iterable" and "iterator", respectively 58 | 59 | ## 0.5.4.2 - January 5th, 2020 60 | 61 | * Added support for UTF-8 filenames on Windows 62 | 63 | ## 0.5.4.1 - December 31st, 2019 64 | 65 | * Included Transform utilities 66 | * Updated the documentation 67 | * Added Math.lerpAngle(), Math.deltaAngle() 68 | * General improvements 69 | 70 | ## 0.5.4 - September 23rd, 2019 71 | 72 | * Performance optimizations 73 | * Improved the built-in pseudo-random number generator 74 | * Introduced the @Package annotation 75 | * Trailing commas are now accepted when declaring Arrays & Dictionaries 76 | * Added tree traversal routines: Object.findObjects() and similar others 77 | * Added Object.__arity(), Math.signum(), Time.now 78 | * New option flags for the parser 79 | * Updated the documentation 80 | * Bugfixes and general improvements 81 | 82 | ## 0.5.3 - March 20th, 2019 83 | 84 | * Introduced the remainder operator (%) 85 | * Introduced the 'caller' keyword 86 | * Introduced the 'readonly' keyword 87 | * Improved the 'timeout' feature 88 | * Added the 'assert' feature 89 | * Added Object.__file, Math.NaN 90 | * Added utility functions for Arrays and Strings 91 | * Removed Transform2D from the core lib 92 | * The parser now accepts option flags 93 | * Bugfixes and performance optimizations 94 | * Updated documentation 95 | * General improvements 96 | 97 | ## 0.5.2 - May 31st, 2018 98 | 99 | * Introduced the Plugin system 100 | * Introduced the Date object for date and time routines 101 | * Now representing numbers as 64-bit floating point values 102 | * Performance optimizations 103 | * Added Object.__invoke() 104 | * Updated the naming convention of getters/setters 105 | * Bugfixes and general improvements 106 | 107 | ## 0.5.1 - May 5th, 2018 108 | 109 | * SurgeScript now compiles as a static library 110 | * Introduced the header for ease of use 111 | * Improved compiling-related data 112 | * Improved documentation 113 | * Small improvements to the language 114 | 115 | ## 0.5.0 - April 15th, 2018 116 | 117 | * Initial release 118 | -------------------------------------------------------------------------------- /cmake/toolchain-mingw.cmake: -------------------------------------------------------------------------------- 1 | # -------------------------- 2 | # Cross-compiling with MinGW 3 | # -------------------------- 4 | # Use the commands below to build the Windows version of SurgeScript with MinGW: 5 | # 6 | # mkdir build && cd build 7 | # cmake .. \ 8 | # -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchain-mingw.cmake 9 | # make && sudo make install 10 | # 11 | # This is for cross-compiling only. 12 | 13 | # Set the system name 14 | set(CMAKE_SYSTEM_NAME Windows) 15 | 16 | # Set the location of the C compiler and of the target environment (MINGDIR) 17 | # The paths below are taken from the Allegro 5 build system; if MinGW isn't 18 | # found automatically in your system, please adjust the paths manually: 19 | if(EXISTS /usr/i586-mingw32msvc) 20 | set(CMAKE_C_COMPILER i586-mingw32msvc-gcc) 21 | set(CMAKE_CXX_COMPILER i586-mingw32msvc-g++) 22 | set(CMAKE_RC_COMPILER i586-mingw32msvc-windres) 23 | set(CMAKE_FIND_ROOT_PATH /usr/i586-mingw32msvc) 24 | elseif(EXISTS /usr/i686-w64-mingw32) 25 | set(CMAKE_C_COMPILER i686-w64-mingw32-gcc) 26 | set(CMAKE_CXX_COMPILER i686-w64-mingw32-g++) 27 | set(CMAKE_RC_COMPILER i686-w64-mingw32-windres) 28 | set(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32) 29 | set(CMAKE_AR:FILEPATH /usr/bin/i686-w64-mingw32-ar) 30 | elseif(EXISTS /opt/mingw) 31 | set(CMAKE_C_COMPILER /opt/mingw/usr/bin/i686-pc-mingw32-gcc) 32 | set(CMAKE_CXX_COMPILER /opt/mingw/usr/bin/i686-pc-mingw32-g++) 33 | set(CMAKE_RC_COMPILER /opt/mingw/usr/bin/i686-pc-mingw32-windres) 34 | set(CMAKE_FIND_ROOT_PATH /opt/mingw/usr/i686-pc-mingw32) 35 | else() 36 | set(CMAKE_C_COMPILER /usr/local/cross-tools/bin/i386-mingw32-gcc) 37 | set(CMAKE_CXX_COMPILER /usr/local/cross-tools/bin/i386-mingw32-g++) 38 | set(CMAKE_RC_COMPILER /usr/local/cross-tools/bin/i386-mingw32-windres) 39 | set(CMAKE_FIND_ROOT_PATH /usr/local/cross-tools) 40 | endif() 41 | 42 | # Install prefix 43 | set(CMAKE_INSTALL_PREFIX "${CMAKE_FIND_ROOT_PATH}" CACHE PATH "Install path prefix, prepended onto install directories.") 44 | 45 | # Other settings 46 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 47 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 48 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 49 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | docs.opensurge2d.org -------------------------------------------------------------------------------- /docs/download.md: -------------------------------------------------------------------------------- 1 | Download SurgeScript 2 | ==================== 3 | 4 | There are two ways to get SurgeScript: 5 | 6 | - The first is to [get Open Surge](#open-surge). This is recommended for most users. 7 | - The second is to [get the standalone version](#standalone-version) of the language. 8 | 9 | Open Surge 10 | ---------- 11 | 12 | To get Open Surge, visit [opensurge2d.org](http://opensurge2d.org) and follow the instructions there. 13 | 14 | When you get Open Surge, you also get a full game engine featuring SurgeScript. This allows you to create your own scripts and games with plenty of interactivity and ease. 15 | 16 | Once you download Open Surge, the next step is to [create your first script](/tutorials/hello). 17 | 18 | Standalone version 19 | ------------------ 20 | 21 | To get the standalone version, go to the [SurgeScript page on GitHub](https://github.com/alemart/surgescript). There you'll find instructions on how to compile SurgeScript. 22 | 23 | When you compile SurgeScript, you'll end up with a text-only program. There are no graphics and no game engine is attached to it. You can try your scripts using the command line. 24 | 25 | Once you get the standalone version, the next step is to [create your first script](/tutorials/hello). 26 | -------------------------------------------------------------------------------- /docs/engine/actor.md: -------------------------------------------------------------------------------- 1 | Actor 2 | ===== 3 | 4 | The Actor component is used to associate a sprite to a target object. The target object is required to be an [entity](/engine/entity). It's recommended to use only one actor per entity. 5 | 6 | Factory 7 | ------- 8 | 9 | #### Actor 10 | 11 | `Actor(sprite)` 12 | 13 | Spawns a new Actor component with the given sprite name. 14 | 15 | *Arguments* 16 | 17 | * `sprite`: string. The name of the sprite (defined in the *sprites/* folder). 18 | 19 | *Returns* 20 | 21 | An Actor component. 22 | 23 | *Example* 24 | ```cs 25 | using SurgeEngine.Actor; 26 | 27 | object "SurgeTest" is "entity" 28 | { 29 | // spawns an Actor with the SurgeTest sprite 30 | actor = Actor("SurgeTest"); 31 | 32 | state "main" 33 | { 34 | } 35 | } 36 | ``` 37 | 38 | 39 | 40 | Properties 41 | ---------- 42 | 43 | #### anim 44 | 45 | `anim`: number. 46 | 47 | A shortcut to `animation.id`: an integer corresponding to the animation number. Defaults to 0. 48 | 49 | #### animation 50 | 51 | `animation`: [Animation](/engine/animation) object, read-only. 52 | 53 | Reference to the Animation object of the Actor. 54 | 55 | #### entity 56 | 57 | `entity`: object, read-only. 58 | 59 | The entity associated with this component. 60 | 61 | #### hflip 62 | 63 | `hflip`: boolean. 64 | 65 | Should the actor be flipped horizontally? Defaults to `false`. 66 | 67 | #### vflip 68 | 69 | `vflip`: boolean. 70 | 71 | Should the actor be flipped vertically? Defaults to `false`. 72 | 73 | #### visible 74 | 75 | `visible`: boolean. 76 | 77 | Should the actor be rendered? Defaults to `true`. 78 | 79 | #### alpha 80 | 81 | `alpha`: number. 82 | 83 | Opacity value, ranging from zero (0% opaque) to one (100% opaque). Defaults to 1.0. 84 | 85 | #### offset 86 | 87 | `offset`: [Vector2](/engine/vector2) object. 88 | 89 | A *(x,y)* offset relative to the parent object. Defaults to zero. 90 | 91 | #### anchor 92 | 93 | `anchor`: [Vector2](/engine/vector2) object. 94 | 95 | A shortcut to `animation.anchor`. See also: [anchor](/engine/animation#anchor). 96 | 97 | *Available since:* Open Surge 0.6.0 98 | 99 | #### hotSpot 100 | 101 | `hotSpot`: [Vector2](/engine/vector2) object. 102 | 103 | A shortcut to `animation.hotSpot`. See also: [hot spot](/engine/animation#hotspot). 104 | 105 | *Available since:* Open Surge 0.6.0. In versions prior to 0.6.0, you may get the hot spot using the [Animation](/engine/animation#hotspot) object. 106 | 107 | #### actionSpot 108 | 109 | `actionSpot`: [Vector2](/engine/vector2) object. 110 | 111 | A shortcut to `animation.actionSpot`. See also: [action spot](/engine/animation#actionspot). 112 | 113 | *Available since:* Open Surge 0.6.0 114 | 115 | #### actionOffset 116 | 117 | `actionOffset`: [Vector2](/engine/vector2) object, read-only. 118 | 119 | A shortcut to `animation.actionOffset`. See also: [action offset](/engine/animation#actionoffset). 120 | 121 | *Available since:* Open Surge 0.6.0 122 | 123 | #### width 124 | 125 | `width`: number, read-only. 126 | 127 | The width of the actor. 128 | 129 | #### height 130 | 131 | `height`: number, read-only. 132 | 133 | The height of the actor. 134 | 135 | #### zindex 136 | 137 | `zindex`: number. 138 | 139 | Objects with greater zindex are rendered in front of others. Defaults to 0.5. 140 | -------------------------------------------------------------------------------- /docs/engine/androidplatform.md: -------------------------------------------------------------------------------- 1 | AndroidPlatform 2 | =============== 3 | 4 | Routines specific to Android. The functions below do nothing if the engine is not running on it. In order to determine if the engine is running on Android, check [Platform.isAndroid](/engine/platform#isandroid). 5 | 6 | *Available since:* Open Surge 0.6.1 7 | 8 | Functions 9 | --------- 10 | 11 | #### shareText 12 | 13 | `shareText(text)` 14 | 15 | Share a text using the Android Sharesheet, a feature that lets the user pick which app to share data with. You may use it to let the user share a URL with a friend or on social media, for example. 16 | 17 | *Arguments* 18 | 19 | * `text`: string. The text to be shared. 20 | 21 | *Example* 22 | 23 | ```cs 24 | using SurgeEngine.Platform; 25 | using SurgeEngine.Platform.Android; 26 | 27 | // ... 28 | 29 | if(Platform.isAndroid) 30 | Android.shareText("Download the Open Surge Engine at https://opensurge2d.org"); 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/engine/behavior.md: -------------------------------------------------------------------------------- 1 | Behavior 2 | ======== 3 | 4 | A behavior is an object that, when spawned as a child of an [entity](/engine/entity), adds a specific behavior to that entity. Example: you can add a behavior to give a [Directional Movement](/engine/directional_movement) to an entity, so you don't need to code that movement yourself. Although the use of behaviors is not mandatory, they greatly simplify the development of your entities. 5 | 6 | An important aspect of using behaviors is that you can create your own. You can also reuse them in many of your entities and share them with others. Behavior objects should be built in a generic way, so that they can be reused throughout multiple entities. 7 | 8 | Behavior objects must be tagged *behavior* and are supposed to be spawned as direct children of entities. They should also implement the protocol (properties, methods) described below. The engine provides a few behaviors by default, and they have been documented in this manual. 9 | 10 | *Example* 11 | 12 | ```cs 13 | // 14 | // The example below shows an entity with 2 behaviors: 15 | // 16 | // - Enemy: it makes the entity behave like an enemy 17 | // (it can hit the player, or be defeated) 18 | // 19 | // - DirectionalMovement: it makes the entity move 20 | // in a certain direction, with a certain speed 21 | // 22 | using SurgeEngine.Actor; 23 | using SurgeEngine.Vector2; 24 | using SurgeEngine.Behaviors.Enemy; 25 | using SurgeEngine.Behaviors.DirectionalMovement; 26 | 27 | // Mosquito is a flying baddie 28 | object "Mosquito" is "entity", "enemy" 29 | { 30 | actor = Actor("Mosquito"); 31 | enemy = Enemy(); 32 | movement = DirectionalMovement(); 33 | 34 | state "main" 35 | { 36 | actor.hflip = true; // flip the sprite horizontally 37 | movement.direction = Vector2.left; 38 | movement.speed = 60; 39 | } 40 | } 41 | ``` 42 | 43 | Properties 44 | ---------- 45 | 46 | #### entity 47 | 48 | `entity`: object, read-only. 49 | 50 | The [entity](/engine/entity) associated with this behavior. This is a convenient alias to the parent object. 51 | 52 | #### enabled 53 | 54 | `enabled`: boolean. 55 | 56 | Is the behavior enabled? The default value is `true`, i.e., behaviors are enabled by default. 57 | -------------------------------------------------------------------------------- /docs/engine/brick.md: -------------------------------------------------------------------------------- 1 | Brick 2 | ===== 3 | 4 | The Brick component is used to create brick-like objects, or bricks endowed with scripting capabilities. This allows you to create elevators, conditional barriers (e.g., doors), movable platforms with custom trajectories, and much more. 5 | 6 | The Brick component only affects collisions. The object that uses it is required to be an [entity](/engine/entity). **This component won't do any rendering.** Therefore, it's typically used in conjunction with the [Actor](/engine/actor) component. 7 | 8 | *Example* 9 | ```cs 10 | using SurgeEngine.Actor; 11 | using SurgeEngine.Brick; 12 | 13 | object "On/Off Platform" is "entity" 14 | { 15 | actor = Actor("On/Off Platform"); // for rendering 16 | brick = Brick("On/Off Platform"); // for collision 17 | 18 | state "main" 19 | { 20 | if(timeout(2.0)) { 21 | brick.enabled = false; 22 | actor.visible = false; 23 | state = "disabled"; 24 | } 25 | } 26 | 27 | state "disabled" 28 | { 29 | if(timeout(2.0)) { 30 | brick.enabled = true; 31 | actor.visible = true; 32 | state = "main"; 33 | } 34 | } 35 | } 36 | ``` 37 | 38 | 39 | 40 | Factory 41 | ------- 42 | 43 | #### Brick 44 | 45 | `Brick(spriteName)` 46 | 47 | Spawns a new Brick component. Just like regular bricks, a Brick component has a collision mask associated with it. By default, the collision mask will be computed according to the animation 0 of the sprite named `spriteName`. 48 | 49 | *Arguments* 50 | 51 | * `spriteName`: string. The name of a sprite. 52 | 53 | *Returns* 54 | 55 | A new Brick component. 56 | 57 | 58 | Properties 59 | ---------- 60 | 61 | #### enabled 62 | 63 | `enabled`: boolean. 64 | 65 | Whether the Brick component should affect collisions or not. Defaults to `true`. 66 | 67 | #### type 68 | 69 | `type`: string. 70 | 71 | The type of the Brick component specifies how it affects collisions. This value must be either *"solid"* or *"cloud"*. Defaults to *"solid"*. 72 | 73 | #### layer 74 | 75 | `layer`: string. 76 | 77 | Should the Brick component be tied to a specific layer? If so, which layer? This value must be one of the following: *"green"*, *"yellow"*, *"default"*. Defaults to *"default"*. 78 | 79 | #### offset 80 | 81 | `offset`: [Vector2](/engine/vector2) object. 82 | 83 | A *(x,y)* offset relative to the parent object. Defaults to zero. 84 | -------------------------------------------------------------------------------- /docs/engine/camera.md: -------------------------------------------------------------------------------- 1 | Camera 2 | ====== 3 | 4 | The Camera object can be used to control what content, in world space, is rendered to the screen. The Camera is represented by a 2-dimensional point in world space that is mapped to the center of the screen. 5 | 6 | !!! tip "Detached entities" 7 | 8 | Entities tagged *"detached"* do not follow the camera. They are rendered in screen space, not in world space. This is useful for creating HUD elements (*Heads-Up Display*). Read more about [entities](/engine/entity). 9 | 10 | *Example* 11 | 12 | ```cs 13 | // Import the Camera object 14 | using SurgeEngine.Camera; 15 | 16 | // Reading the Camera status 17 | // This object prints the position of the camera at every second 18 | object "Camera Status" is "awake", "entity" 19 | { 20 | state "main" 21 | { 22 | if(timeout(1)) 23 | state = "print"; 24 | } 25 | 26 | state "print" 27 | { 28 | Console.print(Camera.position); 29 | state = "main"; 30 | } 31 | } 32 | ``` 33 | 34 | Properties 35 | ---------- 36 | 37 | #### position 38 | 39 | `position`: [Vector2](/engine/vector2) object. 40 | 41 | The position of the camera in world space. Tip: use [lateUpdate()](/engine/entity) if you need to change it. 42 | 43 | *Example* 44 | ```cs 45 | using SurgeEngine.Camera; 46 | using SurgeEngine.Player; 47 | 48 | object "My Simple Camera" is "awake", "entity" 49 | { 50 | fun lateUpdate() 51 | { 52 | player = Player.active; 53 | Camera.position = player.transform.position; 54 | } 55 | } 56 | ``` 57 | 58 | #### locked 59 | 60 | `locked`: boolean, read-only. 61 | 62 | Is the camera locked to a certain area in space? Defaults to `false`. 63 | 64 | Functions 65 | --------- 66 | 67 | #### lock 68 | 69 | `lock(left, top, right, bottom)` 70 | 71 | Locks the camera to a certain rectangular area in space. All coordinates are given in pixels and represent the boundaries of the rectangular area. They are such that `left` <= `right` and `top` <= `bottom`. 72 | 73 | *Arguments* 74 | 75 | * `left`: number. A x-coordinate in world space. 76 | * `top`: number. A y-coordinate in world space. 77 | * `right`: number. A x-coordinate in world space. 78 | * `bottom`: number. A y-coordinate in world space. 79 | 80 | #### unlock 81 | 82 | `unlock()` 83 | 84 | Unlocks the camera. If unlocked, the camera moves freely throughout the space. 85 | 86 | #### worldToScreen 87 | 88 | `worldToScreen(position)` 89 | 90 | Converts `position` from world space to screen space. Screen coordinates are given in pixels. (0,0) is the top-left of the screen and ([Screen.width](/engine/screen#width),[Screen.height](/engine/screen#height)) is the bottom-right. 91 | 92 | *Available since:* Open Surge 0.5.1 93 | 94 | *Arguments* 95 | 96 | * `position`: [Vector2](/engine/vector2) object. The position to be converted. 97 | 98 | *Returns* 99 | 100 | Returns a [Vector2](/engine/vector2) object corresponding to the converted coordinates. 101 | 102 | #### screenToWorld 103 | 104 | `screenToWorld(position)` 105 | 106 | Converts `position` from screen space to world space. Screen coordinates are given in pixels. (0,0) is the top-left of the screen and ([Screen.width](/engine/screen#width),[Screen.height](/engine/screen#height)) is the bottom-right. 107 | 108 | *Available since:* Open Surge 0.5.1 109 | 110 | *Arguments* 111 | 112 | * `position`: [Vector2](/engine/vector2) object. The position to be converted. 113 | 114 | *Returns* 115 | 116 | Returns a [Vector2](/engine/vector2) object corresponding to the converted coordinates. 117 | -------------------------------------------------------------------------------- /docs/engine/circular_movement.md: -------------------------------------------------------------------------------- 1 | Circular Movement 2 | ================= 3 | 4 | The Circular Movement [behavior](/engine/behavior) makes the associated [entity](/engine/entity) perform a circular orbit on the 2D plane. Its basic parameters are: 5 | 6 | * A radius, given in pixels 7 | * A movement rate, given in cycles per second 8 | 9 | Other parameters include: a movement scale in both X and Y axes (making it an elliptic orbit), a flag telling whether the movement should be clockwise or not, and so on. 10 | 11 | *Example* 12 | 13 | ```cs 14 | // 15 | // The example below shows how to make an entity move along 16 | // a circle of 128 pixels of radius at a rate of 0.25 cycles 17 | // per second (i.e., it takes one second to complete 25% of 18 | // a cycle, or 4 seconds to complete a cycle) 19 | // 20 | using SurgeEngine.Actor; 21 | using SurgeEngine.Vector2; 22 | using SurgeEngine.Behaviors.CircularMovement; 23 | 24 | object "Simple Ball" is "entity" 25 | { 26 | actor = Actor("Simple Ball"); 27 | movement = CircularMovement(); 28 | 29 | state "main" 30 | { 31 | movement.radius = 128; 32 | movement.rate = 0.25; 33 | //movement.scale = Vector2.up; // uncomment to move along the y-axis only 34 | } 35 | } 36 | ``` 37 | 38 | Factory 39 | ------- 40 | 41 | #### Behaviors.CircularMovement 42 | 43 | `CircularMovement()` 44 | 45 | Spawns a CircularMovement. 46 | 47 | *Returns* 48 | 49 | A CircularMovement object. 50 | 51 | Properties 52 | ---------- 53 | 54 | #### radius 55 | 56 | `radius`: number. 57 | 58 | The radius of the movement, in pixels. 59 | 60 | #### rate 61 | 62 | `rate`: number. 63 | 64 | The rate of the movement, given in cycles per second. 65 | 66 | #### clockwise 67 | 68 | `clockwise`: boolean. 69 | 70 | Indicates whether the movement is clockwise (`true`) or counterclockwise (`false`). Defaults to `false`. 71 | 72 | #### scale 73 | 74 | `scale`: [Vector2](/engine/vector2) object. 75 | 76 | Specifies the scale of the movement in both X and Y axes. It is used to distort the circle. `Vector2(1, 1)` means no distortion (default). 77 | 78 | #### center 79 | 80 | `center`: [Vector2](/engine/vector2) object | `null`. 81 | 82 | If not `null`, forces the center of the movement to be at a particular position in world space. Defaults to `null`. 83 | 84 | #### phaseOffset 85 | 86 | `phaseOffset`: number. 87 | 88 | A value in degrees that offsets the current [phase](#phase). Defaults to zero (180 means opposite phase relative to zero). 89 | 90 | #### phase 91 | 92 | `phase`: number, read-only. 93 | 94 | A value in degrees that indicates the current phase of the movement. 95 | -------------------------------------------------------------------------------- /docs/engine/collisionball.md: -------------------------------------------------------------------------------- 1 | CollisionBall 2 | ============= 3 | 4 | A CollisionBall is a special type of [Collider](/engine/collider) that takes the shape of a ball. In 2D space, this is a circle with a specific radius. All functions and properties of [Collider](/engine/collider) apply to this. 5 | 6 | *Example* 7 | 8 | ```cs 9 | using SurgeEngine.Actor; 10 | using SurgeEngine.Collisions.CollisionBall; 11 | 12 | object "CollisionDoll" is "entity" 13 | { 14 | actor = Actor("CollisionDoll"); 15 | collider = CollisionBall(25); // radius = 25px 16 | 17 | state "main" 18 | { 19 | collider.visible = true; // useful for debugging 20 | } 21 | 22 | fun onCollision(otherCollider) 23 | { 24 | Console.print("A collision has occurred."); 25 | } 26 | } 27 | ``` 28 | 29 | Factory 30 | ------- 31 | 32 | #### Collisions.CollisionBall 33 | 34 | `Collisions.CollisionBall(radius)` 35 | 36 | Spawns a new CollisionBall with the specified radius, in pixels. 37 | 38 | *Arguments* 39 | 40 | * `radius`: number. The radius of the CollisionBall. 41 | 42 | *Returns* 43 | 44 | A new CollisionBall with the specified radius. 45 | 46 | Properties 47 | ---------- 48 | 49 | #### center 50 | 51 | `center`: [Vector2](/engine/vector2), read-only. 52 | 53 | The center of the CollisionBall, in world space. 54 | 55 | #### radius 56 | 57 | `radius`: number. 58 | 59 | The radius of the CollisionBall, in pixels. 60 | -------------------------------------------------------------------------------- /docs/engine/collisionbox.md: -------------------------------------------------------------------------------- 1 | CollisionBox 2 | ============ 3 | 4 | A CollisionBox is a special type of [Collider](/engine/collider) that takes the shape of a box. In 2D space, this is a rectangle with a specific width and height. All functions and properties of [Collider](/engine/collider) apply to this. 5 | 6 | *Example* 7 | 8 | ```cs 9 | using SurgeEngine.Actor; 10 | using SurgeEngine.Collisions.CollisionBox; 11 | 12 | object "CollisionDoll" is "entity" 13 | { 14 | actor = Actor("CollisionDoll"); 15 | collider = CollisionBox(32, 64); // width = 32px, height = 64px 16 | 17 | state "main" 18 | { 19 | collider.visible = true; // useful for debugging 20 | } 21 | 22 | fun onCollision(otherCollider) 23 | { 24 | Console.print("A collision has occurred."); 25 | } 26 | } 27 | ``` 28 | 29 | Factory 30 | ------- 31 | 32 | #### Collisions.CollisionBox 33 | 34 | `Collisions.CollisionBox(width, height)` 35 | 36 | Spawns a new CollisionBox with the specified dimensions, in pixels. 37 | 38 | *Arguments* 39 | 40 | * `width`: number. The width of the CollisionBox. 41 | * `height`: number. The height of the CollisionBox. 42 | 43 | *Returns* 44 | 45 | A new CollisionBox with the specified dimensions. 46 | 47 | Properties 48 | ---------- 49 | 50 | #### width 51 | 52 | `width`: number. 53 | 54 | The width of the CollisionBox, in pixels. 55 | 56 | #### height 57 | 58 | `height`: number. 59 | 60 | The height of the CollisionBox, in pixels. 61 | 62 | #### center 63 | 64 | `center`: [Vector2](/engine/vector2), read-only. 65 | 66 | The center of the CollisionBox, in world space. 67 | 68 | #### top 69 | 70 | `top`: number, read-only. 71 | 72 | The y-coordinate of the top border of the CollisionBox, in world space. 73 | 74 | #### right 75 | 76 | `right`: number, read-only. 77 | 78 | The x-coordinate of the right border of the CollisionBox, in world space. 79 | 80 | #### bottom 81 | 82 | `bottom`: number, read-only. 83 | 84 | The y-coordinate of the bottom border of the CollisionBox, in world space. 85 | 86 | #### left 87 | 88 | `left`: number, read-only. 89 | 90 | The x-coordinate of the left border of the CollisionBox, in world space. 91 | -------------------------------------------------------------------------------- /docs/engine/delayedevent.md: -------------------------------------------------------------------------------- 1 | DelayedEvent 2 | ============ 3 | 4 | A DelayedEvent is an [event](/engine/event) that, when triggered, triggers another event after a specified time has passed. 5 | 6 | Factory 7 | ------- 8 | 9 | #### Events.DelayedEvent 10 | 11 | `Events.DelayedEvent(event)` 12 | 13 | Spawns a DelayedEvent. 14 | 15 | *Arguments* 16 | 17 | * `event`: [event](/engine/event) object. The event to be delayed. 18 | 19 | *Returns* 20 | 21 | A new DelayedEvent that, when triggered, will trigger the specified event after a delay. 22 | 23 | *Example* 24 | 25 | ```cs 26 | // This is a level setup object. Make sure to link it in your .lev file! 27 | using SurgeEngine.Level; 28 | using SurgeEngine.Events.EventList; 29 | using SurgeEngine.Events.DelayedEvent; 30 | using SurgeEngine.Events.FunctionEvent; 31 | 32 | object "My Level Setup" 33 | { 34 | fun constructor() 35 | { 36 | Level.setup({ 37 | "Event Trigger 1": { 38 | "onTrigger": EventList([ 39 | FunctionEvent("Print").withArgument("Hello!"), 40 | DelayedEvent( 41 | FunctionEvent("Print").withArgument("This is...") 42 | ).willWait(2.0), // wait 2 seconds before triggering this 43 | DelayedEvent( 44 | FunctionEvent("Print").withArgument("SurgeScript!") 45 | ).willWait(4.0) // wait 4 seconds before triggering this 46 | ]) 47 | } 48 | }); 49 | } 50 | } 51 | ``` 52 | 53 | Functions 54 | --------- 55 | 56 | #### willWait 57 | 58 | `willWait(seconds)` 59 | 60 | Set the delay to trigger the event. 61 | 62 | *Arguments* 63 | 64 | `seconds`: number. The delay, in seconds. 65 | 66 | *Returns* 67 | 68 | The DelayedEvent object. 69 | 70 | #### call 71 | 72 | `call()` 73 | 74 | Triggers the event. -------------------------------------------------------------------------------- /docs/engine/directional_movement.md: -------------------------------------------------------------------------------- 1 | Directional Movement 2 | ==================== 3 | 4 | The Directional Movement [behavior](/engine/behavior) makes the associated [entity](/engine/entity) perform a directional movement on the 2D plane. It features: 5 | 6 | * A direction [vector](/engine/vector2) that specifies the direction of the movement 7 | * A movement speed, a scalar value given in pixels per second 8 | 9 | You may control the direction of the movement using the [direction vector](#direction) or an [angle](#angle) given in degrees. Additionally, you may control the [speed](#speed) of the movement simply by changing its value. 10 | 11 | Directional Movement is very versatile. You can use it to implement many things: different types of baddies, flying objects, racing cars viewed from a top-down view, simple projectiles, and much more. 12 | 13 | *Example* 14 | 15 | ```cs 16 | // 17 | // The example below shows how to make an entity move to the 18 | // right of the screen at a rate of 60 pixels per second 19 | // 20 | using SurgeEngine.Actor; 21 | using SurgeEngine.Vector2; 22 | using SurgeEngine.Behaviors.DirectionalMovement; 23 | 24 | object "Simple Ball" is "entity" 25 | { 26 | actor = Actor("Simple Ball"); 27 | movement = DirectionalMovement(); 28 | 29 | state "main" 30 | { 31 | movement.direction = Vector2.right; 32 | movement.speed = 60; 33 | } 34 | } 35 | ``` 36 | 37 | Factory 38 | ------- 39 | 40 | #### Behaviors.DirectionalMovement 41 | 42 | `DirectionalMovement()` 43 | 44 | Spawns a DirectionalMovement. 45 | 46 | *Returns* 47 | 48 | A DirectionalMovement object. 49 | 50 | Properties 51 | ---------- 52 | 53 | #### speed 54 | 55 | `speed`: number. 56 | 57 | The speed of the movement, in pixels per second. 58 | 59 | #### direction 60 | 61 | `direction`: [Vector2](/engine/vector2) object. 62 | 63 | The direction of the movement. 64 | 65 | #### angle 66 | 67 | `angle`: number. 68 | 69 | The counterclockwise angle of the direction vector, in degrees. 0 means right, 90 means up, etc. 70 | -------------------------------------------------------------------------------- /docs/engine/enemy.md: -------------------------------------------------------------------------------- 1 | Enemy 2 | ===== 3 | 4 | The Enemy [behavior](/engine/behavior) makes the associated [entity](/engine/entity) behave like an enemy. It will hit the player if touched, unless the player is attacking (jumping, rolling, etc.) In this case the enemy will be destroyed with an explosion, giving the player a certain score. 5 | 6 | Although the Enemy object generates the described behavior, it is not a concrete enemy itself. You may use it to script your own baddies. 7 | 8 | *Example* 9 | 10 | ```cs 11 | // 12 | // HOW TO SCRIPT A BADDIE: 13 | // 14 | // 0. Make sure you have the graphics and the sprite file (.spr) ready, 15 | // before you begin with SurgeScript 16 | // 1. Your object should be tagged (at least): "entity", "enemy" 17 | // 2. Spawn an Actor for the graphics and an Enemy object for the behavior. 18 | // 19 | using SurgeEngine.Actor; 20 | using SurgeEngine.Behaviors.Enemy; 21 | using SurgeEngine.Behaviors.Platformer; 22 | 23 | object "My Baddie" is "entity", "enemy" 24 | { 25 | actor = Actor("My Baddie"); // handles the graphics 26 | enemy = Enemy(); // handles the behavior 27 | platformer = Platformer().walk(); // make it walk 28 | 29 | state "main" 30 | { 31 | enemy.score = 100; 32 | } 33 | } 34 | ``` 35 | 36 | Optionally, you may define functions `onEnemyAttack(player)` and `onEnemyDestroy(player)` in your entity if you want to catch the events: the enemy has attacked a player and the enemy has been destroyed by the player, respectively. 37 | 38 | Factory 39 | ------- 40 | 41 | #### Behaviors.Enemy 42 | 43 | `Enemy()` 44 | 45 | Spawns an Enemy behavior. 46 | 47 | *Returns* 48 | 49 | An Enemy behavior object. 50 | 51 | Properties 52 | ---------- 53 | 54 | #### score 55 | 56 | `score`: number. 57 | 58 | The score given to the player when the enemy is defeated. 59 | 60 | #### invincible 61 | 62 | `invincible`: boolean. 63 | 64 | Is the enemy invincible? An invincible enemy hits the player even when jumping, rolling, etc. - except if the player is also invincible. Defaults to `false`. 65 | 66 | #### collider 67 | 68 | `collider`: [Collider](/engine/collider) object, read-only. 69 | 70 | A collider associated with the enemy. 71 | 72 | Functions 73 | --------- 74 | 75 | #### kill 76 | 77 | `kill(player)` 78 | 79 | Destroys the enemy with an explosion, giving score to `player`. 80 | 81 | *Available since:* Open Surge 0.5.1. See the note below. 82 | 83 | *Arguments* 84 | 85 | * `player`: [Player](/engine/player) object. The player who defeats the enemy. 86 | 87 | *Note:* in versions prior to 0.5.1, this function was called `getDestroyed`. 88 | 89 | #### setBounds 90 | 91 | `setBounds(left, top, right, bottom)` 92 | 93 | Set the boundaries of the collider. All coordinates, given in pixels, are relative to the hot spot of the entity. These boundaries are computed automatically, but you may use this function if you need to adjust them. 94 | 95 | *Arguments* 96 | 97 | * `left`: number. Given in pixels. 98 | * `top`: number. Given in pixels. 99 | * `right`: number. Given in pixels. 100 | * `down`: number. Given in pixels. 101 | 102 | *Returns* 103 | 104 | Returns the Enemy behavior itself. 105 | -------------------------------------------------------------------------------- /docs/engine/entityevent.md: -------------------------------------------------------------------------------- 1 | EntityEvent 2 | =========== 3 | 4 | An EntityEvent is an [event](/engine/event) that calls a function of an [entity](/engine/entity) when triggered. 5 | 6 | Factory 7 | ------- 8 | 9 | #### Events.EntityEvent 10 | 11 | `Events.EntityEvent` 12 | 13 | Spawns an EntityEvent. 14 | 15 | *Arguments* 16 | 17 | * `entityID`: string. The ID of an entity. 18 | 19 | *Returns* 20 | 21 | A new EntityEvent linked to the specified entity. 22 | 23 | *Example* 24 | 25 | ```cs 26 | // This is a level setup object. Make sure to link it in your .lev file! 27 | using SurgeEngine.Level; 28 | using SurgeEngine.Events.EntityEvent; 29 | 30 | object "My Level Setup" 31 | { 32 | fun constructor() 33 | { 34 | Level.setup({ 35 | "Event Trigger 1": { 36 | "onTrigger": EntityEvent("aeb587eed1057a5e").willCall("open") 37 | } 38 | }); 39 | } 40 | } 41 | ``` 42 | 43 | Functions 44 | --------- 45 | 46 | #### willCall 47 | 48 | `willCall(functionName)` 49 | 50 | Specifies the name of the function that will be called. 51 | 52 | *Arguments* 53 | 54 | `functionName`: string. The name of the function that will be called when the event is triggered. 55 | 56 | *Returns* 57 | 58 | The EntityEvent object. 59 | 60 | #### withArgument 61 | 62 | `withArgument(data)` 63 | 64 | Adds an argument to the EntityEvent. Arguments added to the EntityEvent will be passed to the entity when the event is triggered - in the order they have been added. To add multiple arguments, call this function multiple times. 65 | 66 | *Arguments* 67 | 68 | `data`: any. The argument to be added. 69 | 70 | *Returns* 71 | 72 | The EntityEvent object. 73 | 74 | #### call 75 | 76 | `call()` 77 | 78 | Triggers the event. -------------------------------------------------------------------------------- /docs/engine/event.md: -------------------------------------------------------------------------------- 1 | Event 2 | ===== 3 | 4 | An event is a [function object](/tutorials/advanced_features/#function-objects) with zero parameters and no return value that is tagged *"event"*. Events are used to run code when triggered. 5 | 6 | Events let you seamlessly connect [entities](/engine/entity) and write cause and effect relationships. Suppose you have an on/off switch in a level. Whenever that switch is pressed by the player, you want something to happen: raise the water level, open a door, make it rain, teleport the player, and so on. Events are important because they let you decouple the source of the happening (the pressing of the switch) from the results that are experienced (e.g., the raising of the water). 7 | 8 | Events let you reuse your entities in multiple ways and for multiple purposes. You may design an entity and make it trigger an event, but you do not need to specify in advance what the event actually is. Rather, the concrete event (what must happen) will be configured in your [level setup](/engine/level/#setup). 9 | 10 | There are multiple types of events. In practice, you'll use specialized events such as [EntityEvent](/engine/entityevent) and [FunctionEvent](/engine/functionevent) when configuring your entities. *Event* is an empty event that does nothing when triggered, but it should be used when designing your entities, as in the example below. 11 | 12 | *Example* 13 | 14 | ```cs 15 | // ----------------------------------------------------------------------------- 16 | // Using Events 17 | // 18 | // Note that cause and effect are split into different scripts! 19 | // ----------------------------------------------------------------------------- 20 | 21 | // This script contains an object that will trigger an event whenever a certain 22 | // button is pressed (e.g., the jump button). 23 | using SurgeEngine.Player; 24 | using SurgeEngine.Events.Event; 25 | 26 | object "Button Detector" is "awake", "entity" 27 | { 28 | public onButtonPress = Event(); 29 | public button = "fire1"; 30 | 31 | state "main" 32 | { 33 | input = Player.active.input; 34 | if(input.buttonPressed(button)) 35 | onButtonPress(); 36 | } 37 | } 38 | 39 | // ----------------------------------------------------------------------------- 40 | 41 | // The code below is a different script containing a level setup object. 42 | // Make sure to link it in your .lev file! 43 | using SurgeEngine.Level; 44 | using SurgeEngine.Events.FunctionEvent; 45 | 46 | object "My Level Setup" 47 | { 48 | fun constructor() 49 | { 50 | Level.setup({ 51 | "Button Detector": { 52 | "button": "fire1", // "fire1" is the jump button 53 | "onButtonPress": FunctionEvent("Print").withArgument("You pressed the button!") 54 | } 55 | }); 56 | } 57 | } 58 | ``` 59 | 60 | Factory 61 | ------- 62 | 63 | #### Events.Event 64 | 65 | `Events.Event()` 66 | 67 | Spawns an empty Event. 68 | 69 | *Returns* 70 | 71 | A new Event. 72 | 73 | Functions 74 | --------- 75 | 76 | #### call 77 | 78 | `call()` 79 | 80 | Triggers the event. All event types implement this function. It takes no arguments and it returns no value other than `null`. 81 | -------------------------------------------------------------------------------- /docs/engine/eventchain.md: -------------------------------------------------------------------------------- 1 | EventChain 2 | ========== 3 | 4 | An EventChain is an [event](/engine/event) that triggers other events sequentially, as in a chain of events. 5 | 6 | Factory 7 | ------- 8 | 9 | #### Events.EventChain 10 | 11 | `Events.EventChain(chain)` 12 | 13 | Spawns an EventChain. 14 | 15 | *Arguments* 16 | 17 | * `chain`: [Array](/reference/array) object. A list containing zero or more events. 18 | 19 | *Returns* 20 | 21 | A new EventChain that triggers the specified events, one at a time. The first time the EventChain is triggered, the first event of the `chain` will be triggered. The second time the EventChain is triggered, the second event of the `chain` will be triggered, and so on. 22 | 23 | **Note:** if the EventChain ever triggers its last event, from that moment onwards it will always trigger its last event (unless you make it loop). 24 | 25 | *Example* 26 | 27 | ```cs 28 | // EventChain example 29 | // This is a level setup object. Make sure to link it in your .lev file! 30 | using SurgeEngine.Level; 31 | using SurgeEngine.Events.EventChain; 32 | using SurgeEngine.Events.FunctionEvent; 33 | 34 | object "My Level Setup" 35 | { 36 | fun constructor() 37 | { 38 | Level.setup({ 39 | "Switch": { 40 | "sticky": false, 41 | "onActivate": EventChain([ 42 | FunctionEvent("Print").withArgument("First time"), 43 | FunctionEvent("Print").withArgument("Second time"), 44 | FunctionEvent("Print").withArgument("Third time"), 45 | FunctionEvent("Print").withArgument("Enough!") 46 | ]) 47 | } 48 | }); 49 | } 50 | } 51 | ``` 52 | 53 | Functions 54 | --------- 55 | 56 | #### willLoop 57 | 58 | `willLoop()` 59 | 60 | Make the EventChain loop. When the last event of the chain is triggered, the next event to be triggered will be the first one. 61 | 62 | *Returns* 63 | 64 | The EventChain object. 65 | 66 | *Example* 67 | 68 | ```cs 69 | // Triggering Alternating Events 70 | // This is a level setup object. Make sure to link it in your .lev file! 71 | using SurgeEngine.Level; 72 | using SurgeEngine.Events.EventChain; 73 | using SurgeEngine.Events.FunctionEvent; 74 | 75 | object "My Level Setup - Alternating Events" 76 | { 77 | fun constructor() 78 | { 79 | Level.setup({ 80 | "Switch": { 81 | "sticky": false, 82 | "onActivate": EventChain([ 83 | FunctionEvent("Print").withArgument("Triggered Event A"), 84 | FunctionEvent("Print").withArgument("Triggered Event B") 85 | ]).willLoop() 86 | } 87 | }); 88 | } 89 | } 90 | ``` 91 | 92 | #### call 93 | 94 | `call()` 95 | 96 | Triggers the event. 97 | -------------------------------------------------------------------------------- /docs/engine/eventlist.md: -------------------------------------------------------------------------------- 1 | EventList 2 | ========= 3 | 4 | An EventList is an [event](/engine/event) that triggers multiple events when triggered. 5 | 6 | Factory 7 | ------- 8 | 9 | #### Events.EventList 10 | 11 | `Events.EventList(list)` 12 | 13 | Spawns an EventList. 14 | 15 | *Arguments* 16 | 17 | * `list`: [Array](/reference/array) object. A list containing zero or more events. 18 | 19 | *Returns* 20 | 21 | A new EventList that triggers the specified events at once, in the order they have been listed. 22 | 23 | *Example* 24 | 25 | ```cs 26 | // This is a level setup object. Make sure to link it in your .lev file! 27 | using SurgeEngine.Level; 28 | using SurgeEngine.Events.EventList; 29 | using SurgeEngine.Events.FunctionEvent; 30 | 31 | object "My Level Setup" 32 | { 33 | fun constructor() 34 | { 35 | Level.setup({ 36 | "Event Trigger 1": { 37 | "onTrigger": EventList([ 38 | FunctionEvent("Print").withArgument("We're triggering"), 39 | FunctionEvent("Print").withArgument("multiple events"), 40 | FunctionEvent("Print").withArgument("at the same time!") 41 | ]) 42 | } 43 | }); 44 | } 45 | } 46 | ``` 47 | 48 | Functions 49 | --------- 50 | 51 | #### call 52 | 53 | `call()` 54 | 55 | Triggers the event. -------------------------------------------------------------------------------- /docs/engine/functionevent.md: -------------------------------------------------------------------------------- 1 | FunctionEvent 2 | ============= 3 | 4 | A FunctionEvent is an [event](/engine/event) that calls a [function object](/tutorials/advanced_features/#function-objects) when triggered. 5 | 6 | Factory 7 | ------- 8 | 9 | #### Events.FunctionEvent 10 | 11 | `Events.FunctionEvent(objectName)` 12 | 13 | Spawns a FunctionEvent. 14 | 15 | *Arguments* 16 | 17 | * `objectName`: string. The name of a function object. 18 | 19 | *Returns* 20 | 21 | A new FunctionEvent that, when triggered, calls the specified function object. 22 | 23 | *Example* 24 | 25 | ```cs 26 | // This is a level setup object. Make 27 | // sure to link it in your .lev file! 28 | using SurgeEngine.Level; 29 | using SurgeEngine.Events.FunctionEvent; 30 | 31 | object "My Level Setup" 32 | { 33 | fun constructor() 34 | { 35 | Level.setup({ 36 | "Event Trigger 1": { 37 | "onTrigger": FunctionEvent("Give 1up") 38 | } 39 | }); 40 | } 41 | } 42 | 43 | // ----------------------------------------- 44 | 45 | // This is a function object that 46 | // gives the player one extra life. 47 | using SurgeEngine.Player; 48 | using SurgeEngine.Audio.Music; 49 | 50 | object "Give 1up" 51 | { 52 | jingle = Music("samples/1up.ogg"); 53 | 54 | fun call() 55 | { 56 | Player.active.lives += 1; 57 | jingle.play(); 58 | } 59 | } 60 | ``` 61 | 62 | Functions 63 | --------- 64 | 65 | #### withArgument 66 | 67 | `withArgument(data)` 68 | 69 | Adds an argument to the FunctionEvent. Arguments added to the FunctionEvent will be passed to the function object when the event is triggered - in the order they have been added. To add multiple arguments, call this function multiple times. 70 | 71 | *Arguments* 72 | 73 | `data`: any. The argument to be added. 74 | 75 | *Returns* 76 | 77 | The FunctionEvent object. 78 | 79 | #### call 80 | 81 | `call()` 82 | 83 | Triggers the event. -------------------------------------------------------------------------------- /docs/engine/game.md: -------------------------------------------------------------------------------- 1 | Game 2 | ==== 3 | 4 | Game settings. These are specified in *surge.cfg*, a file located at the root folder of the game. 5 | 6 | *Available since:* Open Surge 0.6.1 7 | 8 | Properties 9 | ---------- 10 | 11 | #### title 12 | 13 | `title`: string, read-only. 14 | 15 | The title of the game that is running on the engine. If unspecified, an empty string is returned. 16 | 17 | #### version 18 | 19 | `version`: string, read-only. 20 | 21 | The version of the game that is running on the engine. If unspecified, an empty string is returned. Do not confuse it with [SurgeEngine.version](/engine/surgeengine#version). 22 | -------------------------------------------------------------------------------- /docs/engine/input.md: -------------------------------------------------------------------------------- 1 | Input 2 | ===== 3 | 4 | The Input object is used to read input from the user. 5 | 6 | *Example* 7 | ```cs 8 | using SurgeEngine.Player; 9 | 10 | object "Application" 11 | { 12 | player = Player.active; 13 | 14 | state "main" 15 | { 16 | if(player.input.buttonDown("right")) 17 | Console.print("User is holding right"); 18 | } 19 | } 20 | ``` 21 | 22 | Factory 23 | ------- 24 | 25 | #### Input 26 | 27 | `Input(inputMap)` 28 | 29 | Spawns a new Input component with the given input map. 30 | 31 | **Note:** to read input from a specific character, prefer using [Player.input](/engine/player#input) instead. 32 | 33 | *Arguments* 34 | 35 | * `inputMap`: string. The name of the input map. If set to `null`, a default input map will be used. 36 | 37 | *Returns* 38 | 39 | An Input component. 40 | 41 | *Example* 42 | ```cs 43 | using SurgeEngine.Player; 44 | using SurgeEngine.Input; 45 | 46 | object "Application" 47 | { 48 | input = Player.active.input; // this form is preferred (used in most cases) 49 | //input = Input("custom input map"); // unless you need to read a custom input map 50 | 51 | state "main" 52 | { 53 | if(input.buttonDown("right")) 54 | Console.print("User is holding right"); 55 | } 56 | } 57 | ``` 58 | 59 | Properties 60 | ---------- 61 | 62 | #### enabled 63 | 64 | `enabled`: boolean. 65 | 66 | Whether the input object is enabled or not. A disabled object does not receive user input. The default value of this property is `true`. 67 | 68 | 69 | Functions 70 | --------- 71 | 72 | #### buttonDown 73 | 74 | `buttonDown(buttonName)` 75 | 76 | Checks if a button of the input map is currently being held down. 77 | 78 | *Arguments* 79 | 80 | * `buttonName`: string. One of the following: *"up", "down", "left", "right", "fire1", "fire2", ..., "fire8"*. 81 | 82 | *Returns* 83 | 84 | Returns `true` if the specified button is being held down. 85 | 86 | #### buttonPressed 87 | 88 | `buttonPressed(buttonName)` 89 | 90 | Checks if a button has just been pressed. 91 | 92 | *Arguments* 93 | 94 | * `buttonName`: string. One of the following: *"up", "down", "left", "right", "fire1", "fire2", ..., "fire8"*. 95 | 96 | *Returns* 97 | 98 | Returns `true` if the specified button has just been pressed. 99 | 100 | #### buttonReleased 101 | 102 | `buttonReleased(buttonName)` 103 | 104 | Checks if a button has just been released. 105 | 106 | *Arguments* 107 | 108 | * `buttonName`: string. One of the following: *"up", "down", "left", "right", "fire1", "fire2", ..., "fire8"*. 109 | 110 | *Returns* 111 | 112 | Returns `true` if the specified button has just been released. 113 | 114 | #### simulateButton 115 | 116 | `simulateButton(buttonName, down)` 117 | 118 | Changes the input object so that `buttonName` will be identified as being held down, or not being held down, in the current frame. 119 | 120 | *Arguments* 121 | 122 | * `buttonName`: string. One of the following: *"up", "down", "left", "right", "fire1", "fire2", ..., "fire8"*. 123 | * `down`: boolean. Should the button be considered as being held down? 124 | 125 | #### remap 126 | 127 | `remap(inputMap)` 128 | 129 | Changes the input map. 130 | 131 | *Available since:* Open Surge 0.6.1 132 | 133 | *Arguments* 134 | 135 | * `inputMap`: string. The name of the input map. 136 | 137 | *Returns* 138 | 139 | Returns `true` on success, or `false` otherwise. 140 | -------------------------------------------------------------------------------- /docs/engine/lang.md: -------------------------------------------------------------------------------- 1 | Lang 2 | ==== 3 | 4 | Lang is a SurgeEngine element used to read translation-specific strings, as defined in the language files (.lng). 5 | 6 | *Example* 7 | ```cs 8 | using SurgeEngine.Lang; 9 | 10 | // Display the current language 11 | object "Application" 12 | { 13 | state "main" 14 | { 15 | currentLanguage = Lang["LANG_LANGUAGE"]; 16 | Console.print("The current language is " + currentLanguage); 17 | state = "done"; 18 | } 19 | 20 | state "done" 21 | { 22 | } 23 | } 24 | ``` 25 | 26 | Functions 27 | --------- 28 | 29 | #### get 30 | 31 | `get(key)` 32 | 33 | Gets the value of the specified key. Instead of calling `get()` directly, you may equivalently use the `[ ]` operator. 34 | 35 | *Arguments* 36 | 37 | * `key`: string. The key must always be a string. 38 | 39 | *Returns* 40 | 41 | The translation string associated with the specified key. 42 | -------------------------------------------------------------------------------- /docs/engine/mobile_gamepad.md: -------------------------------------------------------------------------------- 1 | MobileGamepad 2 | ============= 3 | 4 | The mobile gamepad is a virtual gamepad that appears on the screen when the engine is launched in [mobile mode](/engine/surgeengine#mobilemode). 5 | 6 | *Available since:* Open Surge 0.6.1 7 | 8 | Properties 9 | ---------- 10 | 11 | #### visible 12 | 13 | `visible`: boolean, read-only. 14 | 15 | Whether or not the mobile gamepad is visible. 16 | 17 | Functions 18 | --------- 19 | 20 | #### fadeIn 21 | 22 | `fadeIn()` 23 | 24 | Makes the mobile gamepad appear smoothly. 25 | 26 | #### fadeOut 27 | 28 | `fadeOut()` 29 | 30 | Makes the mobile gamepad disappear smoothly. 31 | -------------------------------------------------------------------------------- /docs/engine/mouse.md: -------------------------------------------------------------------------------- 1 | Mouse 2 | ===== 3 | 4 | The Mouse object is used to read input from the mouse. 5 | 6 | *Example* 7 | 8 | ```cs 9 | // This example shows how to use a sprite 10 | // as a mouse cursor. Since My Cursor is 11 | // tagged "detached", it will be rendered 12 | // in screen space, not in world space. 13 | 14 | using SurgeEngine.Actor; 15 | using SurgeEngine.Transform; 16 | using SurgeEngine.Input.Mouse; 17 | 18 | object "My Cursor" is "entity", "detached" 19 | { 20 | actor = Actor("My Cursor"); 21 | transform = Transform(); 22 | 23 | state "main" 24 | { 25 | transform.position = Mouse.position; 26 | if(Mouse.buttonPressed("left")) 27 | Console.print("left click"); 28 | } 29 | 30 | fun constructor() 31 | { 32 | actor.zindex = 1.0; 33 | } 34 | } 35 | ``` 36 | 37 | Properties 38 | ---------- 39 | 40 | #### position 41 | 42 | `position`: [Vector2](/engine/vector2) object, read-only. 43 | 44 | The position of the mouse cursor, in screen space. 45 | 46 | #### scrollUp 47 | 48 | `scrollUp`: boolean, read-only. 49 | 50 | Will be `true` at the frame the user scrolls up using the mouse wheel. 51 | 52 | *Available since:* Open Surge 0.5.1 53 | 54 | #### scrollDown 55 | 56 | `scrollDown`: boolean, read-only. 57 | 58 | Will be `true` at the frame the user scrolls down using the mouse wheel. 59 | 60 | *Available since:* Open Surge 0.5.1 61 | 62 | Functions 63 | --------- 64 | 65 | #### buttonDown 66 | 67 | `buttonDown(buttonName)` 68 | 69 | Checks if a mouse button is currently being held down. 70 | 71 | *Arguments* 72 | 73 | * `buttonName`: string. One of the following: *"left"*, *"right"*, *"middle"*. 74 | 75 | *Returns* 76 | 77 | Returns `true` if the specified button is being held down. 78 | 79 | #### buttonPressed 80 | 81 | `buttonPressed(buttonName)` 82 | 83 | Checks if a mouse button has just been pressed. 84 | 85 | *Arguments* 86 | 87 | * `buttonName`: string. One of the following: *"left"*, *"right"*, *"middle"*. 88 | 89 | *Returns* 90 | 91 | Returns `true` if the specified button has just been pressed (i.e., a click has just occurred). 92 | 93 | *Example* 94 | ```cs 95 | using SurgeEngine.Input.Mouse; 96 | using SurgeEngine.Collisions.CollisionBall; 97 | using SurgeEngine.Transform; 98 | using SurgeEngine.Camera; 99 | 100 | // Use the mouse cursor to click on any entity that has a collider. 101 | // Setup: simply place this object on the level. 102 | object "Entity Picker" is "awake", "entity" 103 | { 104 | transform = Transform(); 105 | collider = CollisionBall(8); 106 | 107 | state "main" 108 | { 109 | transform.position = Camera.screenToWorld(Mouse.position); 110 | collider.visible = true; 111 | } 112 | 113 | fun onOverlap(otherCollider) 114 | { 115 | if(Mouse.buttonPressed("left")) 116 | Console.print("Clicked on " + otherCollider.entity.__name); 117 | } 118 | } 119 | ``` 120 | 121 | #### buttonReleased 122 | 123 | `buttonReleased(buttonName)` 124 | 125 | Checks if a mouse button has just been released. 126 | 127 | *Arguments* 128 | 129 | * `buttonName`: string. One of the following: *"left"*, *"right"*, *"middle"*. 130 | 131 | *Returns* 132 | 133 | Returns `true` if the specified button has just been released. 134 | -------------------------------------------------------------------------------- /docs/engine/music.md: -------------------------------------------------------------------------------- 1 | Music 2 | ===== 3 | 4 | The Music object lets you play music. This is meant to handle background music; therefore, only one music can be played at a time. 5 | 6 | Unlike regular [sounds](/engine/sound), musics are streamed, (i.e., not loaded completely in memory). Given the longer nature of musics, this improves memory usage and helps with the loading times. 7 | 8 | *Example* 9 | ```cs 10 | using SurgeEngine.Level; 11 | 12 | // Fades the music in a linear fashion ;) 13 | object "MyMusicFader" 14 | { 15 | public music = Level.music; 16 | prevVolume = music.volume; 17 | fadeTime = 1.0; // given in seconds 18 | 19 | state "main" 20 | { 21 | } 22 | 23 | state "fadeout" 24 | { 25 | music.volume -= Time.delta / fadeTime; 26 | if(music.volume <= 0.0) { 27 | music.pause(); 28 | music.volume = prevVolume; 29 | state = "main"; 30 | } 31 | } 32 | 33 | // call fadeOut() to make the 34 | // music fade smoothly 35 | fun fadeOut(seconds) 36 | { 37 | if(state == "main") 38 | prevVolume = music.volume; 39 | fadeTime = seconds; 40 | state = "fadeout"; 41 | } 42 | } 43 | ``` 44 | 45 | Factory 46 | ------- 47 | 48 | #### Music 49 | 50 | `Audio.Music(path)` 51 | 52 | Creates a Music object associated with a certain file. 53 | 54 | *Arguments* 55 | 56 | * `path`: string. The path of the music - usually a file in the *musics/* folder. 57 | 58 | *Returns* 59 | 60 | A Music object. 61 | 62 | *Example* 63 | ```cs 64 | using SurgeEngine.Audio.Music; 65 | 66 | object "MusicTest" 67 | { 68 | music = Music("musics/options.ogg"); 69 | 70 | state "main" 71 | { 72 | // loop music 73 | if(!music.playing) 74 | music.play(); 75 | } 76 | } 77 | ``` 78 | 79 | Properties 80 | ---------- 81 | 82 | #### playing 83 | 84 | `playing`: boolean, read-only. 85 | 86 | Will be `true` if the music is playing. 87 | 88 | #### volume 89 | 90 | `volume`: number. 91 | 92 | The volume of the music, a value between 0.0 and 1.0, inclusive (zero means silence). 93 | 94 | Functions 95 | --------- 96 | 97 | #### play 98 | 99 | `play()` 100 | 101 | Plays the music (once). To make it loop, play it whenever `music.playing` is `false`. 102 | 103 | #### stop 104 | 105 | `stop()` 106 | 107 | Stops the music. Once the music is stopped, it can only be played again from the beginning. 108 | 109 | #### pause 110 | 111 | `pause()` 112 | 113 | Pauses the music. A paused music can be resumed later with `play()`. 114 | -------------------------------------------------------------------------------- /docs/engine/platform.md: -------------------------------------------------------------------------------- 1 | Platform 2 | ======== 3 | 4 | Routines specific to the platform the game engine is currently running on. 5 | 6 | *Available since*: Open Surge 0.6.1 7 | 8 | *Example* 9 | 10 | ```cs 11 | // Let's find out which platform the game engine is currently running on 12 | using SurgeEngine.Platform; 13 | 14 | object "Application" 15 | { 16 | state "main" 17 | { 18 | Console.print(platformName()); 19 | state = "done"; 20 | } 21 | 22 | state "done" 23 | { 24 | } 25 | 26 | fun platformName() 27 | { 28 | if(Platform.isAndroid) 29 | return "Android"; 30 | else if(Platform.isWindows) 31 | return "Windows"; 32 | else if(Platform.isMacOS) 33 | return "macOS"; 34 | else if(Platform.isUnix) 35 | return "Unix"; 36 | else 37 | return "Unknown"; 38 | } 39 | } 40 | ``` 41 | 42 | Properties 43 | ---------- 44 | 45 | #### isWindows 46 | 47 | `isWindows`: boolean, read-only. 48 | 49 | Will be `true` if the game engine is running on Microsoft Windows. 50 | 51 | #### isUnix 52 | 53 | `isUnix`: boolean, read-only. 54 | 55 | Will be `true` if the game engine is running on a Unix-like operating system such as: Linux, BSD, macOS, Android, etc. 56 | 57 | #### isMacOS 58 | 59 | `isMacOS`: boolean, read-only. 60 | 61 | Will be `true` if the game engine is running on macOS. 62 | 63 | #### isAndroid 64 | 65 | `isAndroid`: boolean, read-only. 66 | 67 | Will be `true` if the game engine is running on Android. Check [SurgeEngine.mobile](/engine/surgeengine#mobile) instead if you want to know if the game engine is running on mobile mode. 68 | -------------------------------------------------------------------------------- /docs/engine/prefs.md: -------------------------------------------------------------------------------- 1 | Prefs 2 | ===== 3 | 4 | Prefs is a SurgeEngine component used to save/load data to/from the disk (permanent storage). Prefs is a (key, value) storage that works like a [Dictionary](/reference/dictionary), but its data can be persisted between game sessions. Each (key, value) pair is called an entry. Prefs holds multiple entries. 5 | 6 | !!! info "Primitive types" 7 | 8 | Each entry can hold a value of any primitive type: string, number, boolean or null. Objects cannot be saved or loaded directly, but you may serialize them. If you try to save an object directly, it will be converted to and saved as a string. 9 | 10 | *Example* 11 | ```cs 12 | using SurgeEngine.Prefs; 13 | 14 | // Run the Application multiple times and see 15 | // how the counter increments 16 | object "Application" 17 | { 18 | state "main" 19 | { 20 | Prefs["counter"] += 1; 21 | Console.print("counter: " + Prefs["counter"]); 22 | 23 | state = "idle"; 24 | } 25 | 26 | state "idle" 27 | { 28 | } 29 | 30 | fun constructor() 31 | { 32 | if(!Prefs.has("counter")) 33 | Prefs["counter"] = 0; 34 | } 35 | } 36 | ``` 37 | 38 | Functions 39 | --------- 40 | 41 | #### get 42 | 43 | `get(key)` 44 | 45 | Gets the value of the specified key. Instead of calling `get()` directly, you may equivalently use the `[ ]` operator. 46 | 47 | *Arguments* 48 | 49 | * `key`: string. The key must always be a string. 50 | 51 | *Returns* 52 | 53 | Returns the value associated with the specified key, or `null` if there is no such value. 54 | 55 | #### set 56 | 57 | `set(key, value)` 58 | 59 | Sets the value of the specified key. Instead of calling `set()` directly, you may equivalently use the `[ ]` operator. 60 | 61 | *Arguments* 62 | 63 | * `key`: string. The key must always be a string. 64 | * `value`: any type. The value you want to store. 65 | 66 | #### clear 67 | 68 | `clear()` 69 | 70 | Removes all entries from Prefs. Use this very carefully, because data will be lost. 71 | 72 | #### delete 73 | 74 | `delete(key)` 75 | 76 | Deletes the entry having the specified key. 77 | 78 | *Arguments* 79 | 80 | * `key`: string. The key of the entry to be removed. 81 | 82 | #### has 83 | 84 | `has(key)` 85 | 86 | Checks if a specific entry exists. 87 | 88 | *Arguments* 89 | 90 | * `key`: string. The key of the entry. 91 | 92 | *Returns* 93 | 94 | Returns `true` if the specified entry exists, `false` otherwise. 95 | 96 | #### save 97 | 98 | `save()` 99 | 100 | Writes the data to secondary storage. The data isn't saved immediately after you set an entry, but it is saved on key moments. Since the data is persisted automatically, normally you don't need to call this. 101 | -------------------------------------------------------------------------------- /docs/engine/screen.md: -------------------------------------------------------------------------------- 1 | Screen 2 | ====== 3 | 4 | Screen settings. The screen represents the backbuffer, i.e., the texture in which things are drawn. 5 | 6 | *Example* 7 | ```cs 8 | // display the size of the screen 9 | using SurgeEngine.Video.Screen; 10 | 11 | object "Application" 12 | { 13 | width = Screen.width; 14 | height = Screen.height; 15 | 16 | state "main" 17 | { 18 | Console.print(width + "x" + height); 19 | state = "done"; 20 | } 21 | 22 | state "done" 23 | { 24 | } 25 | } 26 | ``` 27 | 28 | Properties 29 | ---------- 30 | 31 | #### width 32 | 33 | `width`: number, read-only. 34 | 35 | The width of the screen, in pixels. 36 | 37 | #### height 38 | 39 | `height`: number, read-only. 40 | 41 | The height of the screen, in pixels. 42 | -------------------------------------------------------------------------------- /docs/engine/sensor.md: -------------------------------------------------------------------------------- 1 | Sensor 2 | ====== 3 | 4 | A Sensor is used to detect collisions with bricks. Due to performance optimizations, passable bricks (or bricks that are too far off camera) can't be sensed. 5 | 6 | *Example* 7 | ```cs 8 | using SurgeEngine.Actor; 9 | using SurgeEngine.Collisions.Sensor; 10 | 11 | object "SensorToy" is "entity" 12 | { 13 | actor = Actor("SensorToy"); 14 | sensor = Sensor(0, -25, 1, 50); // a vertical sensor 15 | 16 | state "main" 17 | { 18 | if(sensor.status != null) 19 | Console.print("Got a brick of type " + sensor.status); 20 | } 21 | 22 | fun constructor() 23 | { 24 | sensor.visible = true; 25 | } 26 | } 27 | ``` 28 | 29 | 30 | 31 | Factory 32 | ------- 33 | 34 | #### Sensor 35 | 36 | `Collisions.Sensor(x, y, width, height)` 37 | 38 | Spawns a new Sensor with the specified dimensions and having its top-left corner located at position (*x*, *y*) relative to the parent object. A Sensor is either a vertical or a horizontal bar that is 1-pixel thin. Both *width* and *height* must be positive integers, and at least one of them must be equal to 1. 39 | 40 | *Arguments* 41 | 42 | * `x`: number. The x-position of the top-left corner of the sensor, relative to the parent object. 43 | * `y`: number. The y-position of the top-left corner of the sensor, relative to the parent object. 44 | * `width`: number. The width of the sensor, in pixels. Must be a positive integer. 45 | * `height`: number. The height of the sensor, in pixels. Must be a positive integer. 46 | 47 | *Returns* 48 | 49 | A Sensor with the specified parameters. 50 | 51 | 52 | Properties 53 | ---------- 54 | 55 | #### status 56 | 57 | `status`: string | `null`, read-only. 58 | 59 | The type of the brick colliding with the sensor (either *"solid"* or *"cloud"*). If the sensor isn't colliding with a brick, or if it's disabled, its status will be `null`. 60 | 61 | #### visible 62 | 63 | `visible`: boolean. 64 | 65 | Should the sensor be rendered? Useful for debugging. Defaults to `false`. 66 | 67 | #### enabled 68 | 69 | `enabled`: boolean. 70 | 71 | Indicates whether the sensor is enabled or not. Defaults to `true`. 72 | 73 | #### layer 74 | 75 | `layer`: string. 76 | 77 | The layer of this sensor. This property assumes one of the following values: `"default"`, `"green"` or `"yellow"`. If it's set to `"default"`, then all non-passable bricks and [brick-like objects](/engine/brick) are sensed. If it's set to `"green"`, then all non-passable bricks and brick-like objects are sensed, except the ones in the yellow layer. Conversely, if it's set to `"yellow"`, then all non-passable bricks and brick-like objects are sensed, except the ones in the green layer. 78 | 79 | *Available since:* Open Surge 0.6.1 80 | -------------------------------------------------------------------------------- /docs/engine/sound.md: -------------------------------------------------------------------------------- 1 | Sound 2 | ===== 3 | 4 | The Sound object lets you play samples, which are short sounds like: jump, brake, select, hit, etc. Sounds are loaded entirely in the memory; therefore, this object is meant to be used only with samples. If you need to play longer things like music, consider using [Music](/engine/music) instead. 5 | 6 | *Example* 7 | ```cs 8 | using SurgeEngine.Audio.Sound; 9 | 10 | // will play a sound every 5 seconds 11 | object "SoundTest" 12 | { 13 | sound = Sound("samples/jump.wav"); 14 | 15 | state "main" 16 | { 17 | sound.play(); 18 | state = "wait"; 19 | } 20 | 21 | state "wait" 22 | { 23 | if(timeout(5.0)) 24 | state = "main"; 25 | } 26 | } 27 | ``` 28 | 29 | Factory 30 | ------- 31 | 32 | #### Sound 33 | 34 | `Audio.Sound(path)` 35 | 36 | Creates a Sound object associated with a certain file. 37 | 38 | *Arguments* 39 | 40 | * `path`: string. The path of the sound - usually a file in the *samples/* folder. 41 | 42 | *Returns* 43 | 44 | A Sound object. 45 | 46 | Properties 47 | ---------- 48 | 49 | #### playing 50 | 51 | `playing`: boolean, read-only. 52 | 53 | Will be `true` if the sound is playing. 54 | 55 | #### volume 56 | 57 | `volume`: number. 58 | 59 | The volume of the sound, a value between 0.0 and 1.0, inclusive (zero means silence). 60 | 61 | Functions 62 | --------- 63 | 64 | #### play 65 | 66 | `play()` 67 | 68 | Plays the sound. 69 | 70 | #### stop 71 | 72 | `stop()` 73 | 74 | Stops the sound. 75 | -------------------------------------------------------------------------------- /docs/engine/surgeengine.md: -------------------------------------------------------------------------------- 1 | SurgeEngine 2 | =========== 3 | 4 | The SurgeEngine plugin is the interface between SurgeScript (scripting language) and Open Surge (game engine). 5 | 6 | *Example* 7 | 8 | ```cs 9 | using SurgeEngine; 10 | 11 | // Open Surge version 12 | object "Application" 13 | { 14 | state "main" 15 | { 16 | Console.print(SurgeEngine.version); 17 | state = "blank"; 18 | } 19 | 20 | state "blank" 21 | { 22 | } 23 | } 24 | ``` 25 | 26 | Properties 27 | ---------- 28 | 29 | #### version 30 | 31 | `version`: string, read-only. 32 | 33 | Version of the Open Surge Engine. 34 | 35 | #### mobile 36 | 37 | `mobile`: boolean, read-only. 38 | 39 | Whether or not the engine has been launched in mobile mode. The user may be playing on a mobile device or on a Desktop computer with the mobile mode enabled. 40 | 41 | *Available since:* Open Surge 0.6.1 42 | -------------------------------------------------------------------------------- /docs/engine/text.md: -------------------------------------------------------------------------------- 1 | Text 2 | ==== 3 | 4 | The Text object allows you to display custom texts in the game. The parent object is required to be an [entity](/engine/entity). 5 | 6 | Factory 7 | ------- 8 | 9 | #### Text 10 | 11 | `UI.Text(font)` 12 | 13 | Spawns a new Text object with the given font name. If `null` is provided as the font name, then a default font will be used. 14 | 15 | *Arguments* 16 | 17 | * `font`: string. The name of a font (defined in the *fonts/* folder). 18 | 19 | *Returns* 20 | 21 | A Text object. 22 | 23 | *Example* 24 | ```cs 25 | using SurgeEngine.UI.Text; 26 | using SurgeEngine.Transform; 27 | using SurgeEngine.Player; 28 | 29 | // Place this on your level to display 30 | // the name of the player 31 | object "PlayerName" is "entity", "awake" 32 | { 33 | text = Text("GoodNeighbors"); 34 | transform = Transform(); 35 | 36 | state "main" 37 | { 38 | // position the text 39 | player = Player.active; 40 | transform.position = player.transform.position; 41 | transform.translateBy(0, -50); 42 | 43 | // configure the text 44 | text.align = "center"; 45 | text.text = player.name; 46 | } 47 | } 48 | ``` 49 | 50 | Properties 51 | ---------- 52 | 53 | #### text 54 | 55 | `text`: string. 56 | 57 | The text to be displayed. 58 | 59 | #### font 60 | 61 | `font`: string, read-only. 62 | 63 | The name of the font in use. 64 | 65 | #### size 66 | 67 | `size`: [Vector2](/engine/vector2) object, read-only. 68 | 69 | The size, in pixels, of the rendered text. 70 | 71 | *Available since:* Open Surge 0.5.1 72 | 73 | #### align 74 | 75 | `align`: string. 76 | 77 | The alignment of the text. One of the following: *"left"*, *"center"*, *"right"*. 78 | 79 | #### visible 80 | 81 | `visible`: boolean. 82 | 83 | Is the Text object visible? 84 | 85 | #### maxLength 86 | 87 | `maxLength`: number. 88 | 89 | The maximum number of characters to be displayed, ignoring ** tags and spaces. 90 | 91 | *Available since:* Open Surge 0.5.1 92 | 93 | #### maxWidth 94 | 95 | `maxWidth`: number. 96 | 97 | The maximum width of the text, in pixels. Setting this value will enable wordwrap. 98 | 99 | #### zindex 100 | 101 | `zindex`: number. 102 | 103 | The zindex of the Text object. Defaults to 0.5. 104 | 105 | #### offset 106 | 107 | `offset`: [Vector2](/engine/vector2) object. 108 | 109 | An *(x,y)* offset relative to the parent object. Defaults to zero. 110 | -------------------------------------------------------------------------------- /docs/engine/video.md: -------------------------------------------------------------------------------- 1 | Video 2 | ===== 3 | 4 | Video settings. 5 | 6 | *Example* 7 | 8 | ```cs 9 | // display the current Video mode 10 | using SurgeEngine.Video; 11 | 12 | object "Application" 13 | { 14 | state "main" 15 | { 16 | Console.print(Video.mode); 17 | state = "done"; 18 | } 19 | 20 | state "done" 21 | { 22 | } 23 | } 24 | ``` 25 | 26 | Properties 27 | ---------- 28 | 29 | #### fullscreen 30 | 31 | `fullscreen`: boolean. 32 | 33 | Whether or not the engine is running on fullscreen mode. Use this property to toggle between windowed and fullscreen modes. 34 | 35 | *Available since:* Open Surge 0.6.1 36 | 37 | #### mode 38 | 39 | `mode`: string. 40 | 41 | The current video mode. The following are the valid values: 42 | 43 | * `"default"`: the size of the [screen](#screen) is set to its default. 44 | * `"fill"`: the size of the screen is set to the size of the window. 45 | * `"best-fit"`: similar to `"fill"`, except that the aspect ratio of the default size of the screen is maintained. 46 | 47 | *Available since:* Open Surge 0.6.1 48 | -------------------------------------------------------------------------------- /docs/engine/web.md: -------------------------------------------------------------------------------- 1 | Web 2 | === 3 | 4 | Web routines. 5 | 6 | Functions 7 | --------- 8 | 9 | #### launchURL 10 | 11 | `launchURL(url)` 12 | 13 | Launches a URL using the default web browser. It's mandatory to specify a protocol. The following protocols are currently supported: *http://*, *https://*, *mailto:* 14 | 15 | *Arguments* 16 | 17 | * `url`: string. The URL to be launched. 18 | 19 | *Example* 20 | ```cs 21 | using SurgeEngine.Web; 22 | 23 | object "Application" 24 | { 25 | // Remember to change the state 26 | // after calling launchURL 27 | state "main" 28 | { 29 | Web.launchURL("http://opensurge2d.org"); 30 | state = "done"; 31 | } 32 | 33 | state "done" 34 | { 35 | } 36 | } 37 | ``` 38 | 39 | #### encodeURIComponent 40 | 41 | `encodeURIComponent(str)` 42 | 43 | Encodes a component of a Universal Resource Identifier (URI). It escapes all characters of the input string, except: 44 | 45 | ``` 46 | A–Z a–z 0–9 - _ . ! ~ * ' ( ) 47 | ``` 48 | 49 | *Arguments* 50 | 51 | * `str`: string. The string to be escaped. 52 | 53 | *Returns* 54 | 55 | Returns the input string escaped as above. 56 | 57 | *Example* 58 | 59 | ```cs 60 | using SurgeEngine.Web; 61 | 62 | // ... 63 | 64 | user = "Jane Doe"; 65 | url = "https://my.website.name/?user=" + Web.encodeURIComponent(user); 66 | Console.print(url); 67 | 68 | // output: 69 | // https://my.website.name/?user=Jane%20Doe 70 | ``` 71 | 72 | *Available since:* Open Surge 0.6.1 73 | -------------------------------------------------------------------------------- /docs/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alemart/surgescript/21a9c0696d592b7cc21e07db828fb93a12c95a7e/docs/img/favicon.ico -------------------------------------------------------------------------------- /docs/img/state-machine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alemart/surgescript/21a9c0696d592b7cc21e07db828fb93a12c95a7e/docs/img/state-machine.png -------------------------------------------------------------------------------- /docs/img/surge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alemart/surgescript/21a9c0696d592b7cc21e07db828fb93a12c95a7e/docs/img/surge.png -------------------------------------------------------------------------------- /docs/img/tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alemart/surgescript/21a9c0696d592b7cc21e07db828fb93a12c95a7e/docs/img/tree.png -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | Welcome to SurgeScript! 2 | ======================= 3 | 4 | Surge 5 | 6 | Unleash your creativity! 7 | ------------------------ 8 | 9 | SurgeScript is a scripting language for games. Use it to unleash your creativity and build your own amazing interactive content! It's such a joy to use SurgeScript! You will love it! 10 | 11 | [GET STARTED](/download){ .md-button .md-button--primary } 12 | 13 | How do I learn SurgeScript? 14 | --------------------------- 15 | 16 | Check out the [SurgeScript Crash Course](/tutorials/hello)! Additionally, take a look at the [video tutorials](https://youtube.com/alemart88) and at the examples that come with the software. 17 | 18 | SurgeScript in a nutshell 19 | ------------------------- 20 | 21 | SurgeScript is: 22 | 23 | * A scripting language for games 24 | * Easy for beginners, powerful for experts 25 | * Object-oriented, dynamically typed and based on state machines 26 | * Free and open-source software 27 | * Built in C, which is nearly universal 28 | * Named after a really charismatic character: [Surge the Rabbit](http://opensurge2d.org)! 29 | 30 | Why use SurgeScript? 31 | -------------------- 32 | 33 | Unlike other programming languages, SurgeScript has been designed with the specific needs of games in mind. Its features include: 34 | 35 | - The state-machine pattern: objects are state machines, making it easy to create game entities 36 | - The composition approach: you may design complex objects and behaviors by means of composition 37 | - The hierarchy system: objects have a parent and may have children, in a tree-like structure 38 | - The game loop: it's defined implicitly 39 | - Automatic garbage collection, object tagging and more! 40 | 41 | SurgeScript is meant to be used in games and in interactive applications. It's easy to integrate it into existing code, it's easy to extend it, it features a C-like syntax, and it's free and open-source software. 42 | 43 | SurgeScript has been designed based on the experience of its developer dealing with game engines, applications related to computer graphics and so on. Some of the best practices have been incorporated into the language itself, making things really easy for developers and modders. 44 | 45 | Who created SurgeScript? 46 | ------------------------ 47 | 48 | SurgeScript has been created by [Alexandre Martins](https://github.com/alemart), a computer scientist from Brazil. He has also created the [Open Surge game engine](http://opensurge2d.org), hence the name SurgeScript. 49 | -------------------------------------------------------------------------------- /docs/js/analytics.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | const script = document.createElement('script'); 3 | 4 | script.addEventListener('error', function(e) { 5 | console.log(`Can't load analytics`, e); 6 | }); 7 | 8 | script.type = 'text/javascript'; 9 | script.async = true; 10 | script.dataset.goatcounter = 'https://surgescript.goatcounter.com/count'; 11 | script.src = 'https://gc.zgo.at/count.js'; 12 | 13 | document.body.appendChild(script); 14 | })(); 15 | -------------------------------------------------------------------------------- /docs/js/donate.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function() { 2 | const script = document.createElement('script'); 3 | 4 | script.addEventListener('load', function() { 5 | kofiWidgetOverlay.draw('alemart', { 6 | 'type': 'floating-chat', 7 | 'floating-chat.donateButton.text': 'Support me', 8 | 'floating-chat.donateButton.background-color': '#4051b5', 9 | 'floating-chat.donateButton.text-color': 'white' 10 | }); 11 | }); 12 | 13 | script.addEventListener('error', function(e) { 14 | console.log(`Can't load the Ko-fi widget`, e); 15 | }); 16 | 17 | script.type = 'text/javascript'; 18 | script.async = true; 19 | script.src = 'https://storage.ko-fi.com/cdn/scripts/overlay-widget.js'; 20 | 21 | document.body.appendChild(script); 22 | 23 | const style = document.createElement('style'); 24 | style.appendChild(document.createTextNode(` 25 | .floatingchat-container-wrap, .floatingchat-container-wrap-mobi, 26 | .floating-chat-kofi-popup-iframe, .floating-chat-kofi-popup-iframe-mobi { 27 | right: 16px !important; 28 | left: initial !important; 29 | } 30 | `)); 31 | document.head.appendChild(style); 32 | }); 33 | -------------------------------------------------------------------------------- /docs/reference/application.md: -------------------------------------------------------------------------------- 1 | Application 2 | =========== 3 | 4 | Represents the Application. You do not need to instantiate it, as it is instantiated automatically. This object can be accessed by any other object, in any script, simply by typing `Application`. 5 | 6 | Properties 7 | ---------- 8 | 9 | #### args 10 | 11 | `args`: [Arguments](/reference/arguments) object, read-only. 12 | 13 | Use this property to read the command line arguments. 14 | 15 | Functions 16 | --------- 17 | 18 | #### exit 19 | 20 | `exit()` 21 | 22 | Exits the Application. 23 | 24 | #### crash 25 | 26 | `crash(message)` 27 | 28 | Exits the Application with an error message. 29 | 30 | *Arguments* 31 | 32 | * `message`: string. The message to be displayed to the user. 33 | 34 | #### destroy 35 | 36 | `destroy()` 37 | 38 | A synonym for `Application.exit()`. -------------------------------------------------------------------------------- /docs/reference/arguments.md: -------------------------------------------------------------------------------- 1 | Arguments 2 | ========= 3 | 4 | If you've launched your application via the command-line, this Array-like object can be used to read command-line arguments. This is available at `Application.args`. 5 | 6 | The example below prints all the arguments to the screen: 7 | 8 | ```cs 9 | // Method 1 (foreach) 10 | foreach(argument in Application.args) 11 | Console.print(argument); 12 | 13 | // Method 2 (for loops) 14 | for(i = 0; i < Application.args.length; i++) 15 | Console.print(Application.args[i]); 16 | 17 | // Or, alternatively: 18 | Console.print(Application.args); 19 | ``` 20 | 21 | Properties 22 | ---------- 23 | 24 | #### length 25 | 26 | `length`: number, read-only. 27 | 28 | The number of command-line arguments, including the executable. 29 | 30 | Functions 31 | --------- 32 | 33 | #### get 34 | 35 | `get(index)` 36 | 37 | Gets the specified command-line argument. Instead of calling `get()`, one may use equivalently the `[ ]` operator. 38 | 39 | *Arguments* 40 | 41 | * `index`: integer number between 0 and `Application.args.length - 1`, inclusive. 42 | 43 | *Returns* 44 | 45 | A string with the specified command-line argument, or `null` if there is no such argument. 46 | 47 | *Example* 48 | 49 | ```cs 50 | // Suppose that you run surgescript via the command-line: 51 | // surgescript test_args.ss 52 | executable = Application.args[0]; // "surgescript" 53 | script_file = Application.args[1]; // "test_args.ss" 54 | ``` 55 | 56 | #### option 57 | 58 | `option(optionName)` 59 | 60 | Gets the value of a certain command-line option. 61 | 62 | *Arguments* 63 | 64 | * `optionName`: string. The option you want to read. 65 | 66 | *Returns* 67 | 68 | A string featuring the value of the desired command-line option, or `null` if such an option hasn't been provided by the user. 69 | 70 | *Example* 71 | 72 | ```cs 73 | // Suppose that you run surgescript via the command-line: 74 | // surgescript test_args.ss --my-option 12345 75 | my_option = Application.args.option("--my-option"); 76 | 77 | // Options -p and --port are equivalent 78 | // surgescript test_args.ss -p 80 79 | // surgescript test_args.ss --port 80 80 | port = Application.args.option("--port") || Application.args.option("-p"); 81 | 82 | // Default values (useful if the option is not present) 83 | // surgescript test_args.ss 84 | // surgescript test_args.ss --name alice 85 | name = Application.args.option("--name") || "anonymous"; 86 | ``` 87 | 88 | #### hasOption 89 | 90 | `hasOption(optionName)` 91 | 92 | Checks if the specified option is present in the command-line. 93 | 94 | *Arguments* 95 | 96 | * `optionName`: string. 97 | 98 | *Returns* 99 | 100 | Returns `true` if the specified option is present in the command-line; or `false` otherwise. 101 | 102 | #### iterator 103 | 104 | `iterator()` 105 | 106 | Spawns an iterator. 107 | 108 | *Returns* 109 | 110 | An iterator to iterate over the command-line arguments. 111 | 112 | #### toString 113 | 114 | `toString()` 115 | 116 | Converts the command-line arguments to a string. 117 | 118 | *Returns* 119 | 120 | A string featuring the command-line arguments. 121 | -------------------------------------------------------------------------------- /docs/reference/boolean.md: -------------------------------------------------------------------------------- 1 | Boolean 2 | ======= 3 | 4 | Routines for booleans. The Boolean object is not supposed to be used directly. The functions below are available for primitive values of the boolean type. 5 | 6 | Functions 7 | --------- 8 | 9 | #### valueOf 10 | 11 | `valueOf()` 12 | 13 | The primitive value of the boolean, i.e., the boolean itself. 14 | 15 | *Returns* 16 | 17 | The boolean. 18 | 19 | #### toString 20 | 21 | `toString()` 22 | 23 | Convert boolean to string. 24 | 25 | *Returns* 26 | 27 | The boolean converted to a string. 28 | 29 | #### equals 30 | 31 | `equals(b)` 32 | 33 | Compares the boolean to another boolean `b`. 34 | 35 | *Arguments* 36 | 37 | * `b`: boolean. The value to compare the boolean to. 38 | 39 | *Returns* 40 | 41 | Returns `true` if the booleans are equal. -------------------------------------------------------------------------------- /docs/reference/console.md: -------------------------------------------------------------------------------- 1 | Console 2 | ======= 3 | 4 | The Console is a mechanism that allows users to interact with your app via a text-based interface. You can print data to the user and read data from the user. 5 | 6 | Functions 7 | --------- 8 | 9 | #### print 10 | 11 | `print(line)` 12 | 13 | Prints a line to the console. 14 | 15 | *Arguments* 16 | 17 | * `line`: string. The message to be printed. 18 | 19 | *Example* 20 | 21 | ```cs 22 | // this will print "Hello, there!" and quit 23 | object "Application" 24 | { 25 | state "main" 26 | { 27 | Console.print("Hello, there!"); 28 | Application.exit(); 29 | } 30 | } 31 | ``` 32 | 33 | #### write 34 | 35 | `write(str)` 36 | 37 | Writes a string to the console, without a line break at the end. 38 | 39 | *Arguments* 40 | 41 | * `str`: string. The string to be written. 42 | 43 | #### readline 44 | 45 | `readline()` 46 | 47 | Reads a line from the standard input. 48 | 49 | *Returns* 50 | 51 | Returns the string just read, without a line break at the end. 52 | 53 | *Example* 54 | 55 | ```cs 56 | // will ask the name of the user until a name is given 57 | object "Application" 58 | { 59 | state "main" 60 | { 61 | Console.print("Hey pal, what's your name? "); 62 | name = Console.readline(); 63 | if(name != "") { 64 | Console.print("Nice to meet you, " + name); 65 | Application.exit(); 66 | } 67 | } 68 | } 69 | ``` -------------------------------------------------------------------------------- /docs/reference/date.md: -------------------------------------------------------------------------------- 1 | Date 2 | ==== 3 | 4 | Date is used to retrieve current date and time. You can access this object simply by typing `Date`. 5 | 6 | Example: 7 | 8 | ```cs 9 | // What day is today? 10 | object "Application" 11 | { 12 | // show the day 13 | state "main" 14 | { 15 | today = Date.year + "-" + f(Date.month) + "-" + f(Date.day); 16 | Console.print("Today is " + today); 17 | Application.exit(); 18 | } 19 | 20 | // add a leading zero 21 | fun f(x) 22 | { 23 | if(x >= 10) 24 | return x; 25 | else 26 | return "0" + x; 27 | } 28 | } 29 | ``` 30 | 31 | *Available since:* SurgeScript 0.5.2 32 | 33 | Properties 34 | ---------- 35 | 36 | #### year 37 | 38 | `year`: number, read-only. 39 | 40 | The current year. 41 | 42 | #### month 43 | 44 | `month`: number, read-only. 45 | 46 | Month of the year (1-12). 47 | 48 | #### day 49 | 50 | `day`: number. 51 | 52 | Day of the month (1-31). 53 | 54 | #### hour 55 | 56 | `hour`: number. 57 | 58 | Hours since midnight (0-23). 59 | 60 | #### minute 61 | 62 | `minute`: number. 63 | 64 | Minutes after the hour (0-59). 65 | 66 | #### second 67 | 68 | `second`: number. 69 | 70 | Seconds after the minute (0-59). 71 | 72 | #### weekday 73 | 74 | `weekday`: number. 75 | 76 | Days since Sunday (0-6). 77 | 78 | #### unixtime 79 | 80 | `unixtime`: number. 81 | 82 | Number of seconds since Jan 1st, 1970 00:00:00 UTC. 83 | 84 | Functions 85 | --------- 86 | 87 | #### timezoneOffset 88 | 89 | `timezoneOffset()` 90 | 91 | The difference, in minutes, from the Coordinated Universal Time (UTC) to the timezone of the host. Example: if your timezone is UTC-03:00, this function returns -180. 92 | 93 | *Available since:* SurgeScript 0.5.2 94 | 95 | *Returns* 96 | 97 | The timezone difference in minutes. 98 | 99 | #### toString 100 | 101 | `toString()` 102 | 103 | Converts the current date and time to a string. The string is formatted according to the ISO 8601 standard. 104 | 105 | *Available since:* SurgeScript 0.5.2 106 | 107 | *Returns* 108 | 109 | The current date and time expressed according to ISO 8601. -------------------------------------------------------------------------------- /docs/reference/dictionary.md: -------------------------------------------------------------------------------- 1 | Dictionary 2 | ========== 3 | 4 | A Dictionary is a collection of key-value pairs. Dictionary keys are strings. Their corresponding values can be of any type. To create a Dictionary, use the `{ key_1: value_1, key_2: value_2, ..., key_n: value_n }` syntax rather than the `spawn()` function. 5 | 6 | Example: 7 | 8 | ```cs 9 | object "Application" 10 | { 11 | dictionary = { 12 | "Surge": 35, 13 | "Neon": 20, 14 | "Charge": 37.5, 15 | "Gimacian": 70 16 | }; 17 | 18 | state "main" 19 | { 20 | // usage example 21 | Console.print(dictionary["Surge"]); // will print 35 22 | Console.print(dictionary["Neon"]); // will print 20 23 | 24 | // will print all entries 25 | foreach(entry in dictionary) 26 | Console.print(entry.key + ": " + entry.value); 27 | 28 | // done! 29 | Application.exit(); 30 | } 31 | } 32 | ``` 33 | 34 | Output: 35 | 36 | ``` 37 | 35 38 | 20 39 | Surge: 35 40 | Neon: 20 41 | Charge: 37.5 42 | Gimacian: 70 43 | ``` 44 | 45 | !!! warning "Caution!" 46 | 47 | Whenever you define a dictionary, you spawn a new object. You are advised to **NOT** define dictionaries within states, because the code within the states run continuously. New objects will be created at every frame, not just once. In the above example, `dictionary` is defined as an [object-level variable](/tutorials/variables#scoping). 48 | 49 | 50 | 51 | Properties 52 | ---------- 53 | 54 | #### count 55 | 56 | `count`: number, read-only. 57 | 58 | The number of elements in the Dictionary. 59 | 60 | Functions 61 | --------- 62 | 63 | #### get 64 | 65 | `get(key)` 66 | 67 | Gets the value of the specified key in the Dictionary. Instead of calling `get()` directly, you may equivalently use the `[ ]` operator. 68 | 69 | *Arguments* 70 | 71 | * `key`: string. 72 | 73 | *Returns* 74 | 75 | The value corresponding to the specified key, or `null` if there is no such an entry in the Dictionary. 76 | 77 | *Example* 78 | 79 | ```cs 80 | dict = { "Surge": 10 }; 81 | ten = dict["Surge"]; 82 | ``` 83 | 84 | #### set 85 | 86 | `set(key, value)` 87 | 88 | Sets the value of the specified key in the Dictionary. Instead of calling `set()` directly, you may equivalently use the `[ ]` operator. 89 | 90 | *Arguments* 91 | 92 | * `key`: string. 93 | * `value`: any type. 94 | 95 | *Example* 96 | 97 | ```cs 98 | dict = { }; 99 | dict["Surge"] = 10; 100 | ``` 101 | 102 | #### clear 103 | 104 | `clear()` 105 | 106 | Removes all entries from the Dictionary. 107 | 108 | #### delete 109 | 110 | `delete(key)` 111 | 112 | Deletes the entry having the specified key. 113 | 114 | *Arguments* 115 | 116 | * `key`: string. The key of the entry to be removed. 117 | 118 | #### has 119 | 120 | `has(key)` 121 | 122 | Checks if an entry having the specified key belongs to the Dictionary. 123 | 124 | *Arguments* 125 | 126 | * `key`: string. The key of the entry. 127 | 128 | *Returns* 129 | 130 | Returns `true` if the Dictionary has such an entry. 131 | 132 | #### keys 133 | 134 | `keys()` 135 | 136 | Gets a collection containing the keys of the Dictionary. 137 | 138 | *Returns* 139 | 140 | Returns a new [Array](/reference/array) containing the keys of the Dictionary. 141 | 142 | #### iterator 143 | 144 | `iterator()` 145 | 146 | Spawns an iterator. 147 | 148 | *Returns* 149 | 150 | An iterator to loop through the elements of the Dictionary. 151 | 152 | #### toString 153 | 154 | `toString()` 155 | 156 | Converts the Dictionary to a string. 157 | 158 | *Returns* 159 | 160 | A string. -------------------------------------------------------------------------------- /docs/reference/gc.md: -------------------------------------------------------------------------------- 1 | GC 2 | == 3 | 4 | SurgeScript features a Garbage Collector (GC) that automatically disposes objects that cannot be reached from the root (i.e., their references are lost). The Garbage Collector is available at `System.gc`. Generally, you do not need to modify any of its settings. 5 | 6 | Properties 7 | ---------- 8 | 9 | #### interval 10 | 11 | `interval`: number, read-only. 12 | 13 | Every `interval` seconds, the garbage collector will be called automatically. 14 | 15 | *Note:* this property is read-only since SurgeScript 0.6.0. 16 | 17 | #### objectCount 18 | 19 | `objectCount`: number, read-only. 20 | 21 | How many objects were disposed when the garbage collector was last called. 22 | 23 | Functions 24 | --------- 25 | 26 | #### collect 27 | 28 | `collect()` 29 | 30 | Calls the Garbage Collector manually. You generally don't need to call this. 31 | -------------------------------------------------------------------------------- /docs/reference/iterator.md: -------------------------------------------------------------------------------- 1 | Iterator 2 | ======== 3 | 4 | In SurgeScript, Iterator is an abstract contract, or protocol, that define a set of functions that should be written in concrete implementations. If you're familiar with object oriented programming, Iterator is an interface. Iterators are used to traverse containers / collections / data structures and access its elements. 5 | 6 | Concrete implementations of Iterator include: `ArrayIterator` and `DictionaryIterator`. If you wish to [write your own iterators](/tutorials/advanced_features#iterators), you need to specify the [functions described below](#functions). 7 | 8 | The data structure that you wish to traverse should include an `iterator()` function that spawns the concrete implementation of the Iterator. Thus, the `parent` object of the Iterator will be the structure to be traversed. 9 | 10 | The basic usage of an Iterator is as follows: 11 | 12 | ```cs 13 | // container is an object such as an Array 14 | iterator = container.iterator(); // spawn an iterator to traverse the container 15 | while(iterator.hasNext()) { 16 | element = iterator.next(); 17 | Console.print(element); 18 | } 19 | ``` 20 | 21 | Functions 22 | --------- 23 | 24 | #### hasNext 25 | 26 | `hasNext()` 27 | 28 | Checks if there are more elements to be accessed in the iteration. 29 | 30 | *Returns* 31 | 32 | Returns `true` if there are more elements to be visited, or `false` otherwise. 33 | 34 | #### next 35 | 36 | `next()` 37 | 38 | Gets the next element of the container and advances the iteration. 39 | 40 | *Returns* 41 | 42 | The next element of the container, or `null` if there is no such element. The first call to `next()` returns the first element of the container, and so on. -------------------------------------------------------------------------------- /docs/reference/number.md: -------------------------------------------------------------------------------- 1 | Number 2 | ====== 3 | 4 | Routines for numbers. The Number object is not supposed to be used directly. The functions below are available for primitive values of the number type. 5 | 6 | Example: 7 | 8 | ```cs 9 | x = 2.toString(); // x is "2" 10 | t = typeof(x); // t is "string" 11 | ``` 12 | 13 | **Note:** the SurgeScript Runtime stores numbers as 64-bit floating point values (following the IEEE 754 standard). Integer numbers are accurate up to 15 digits. 14 | 15 | Functions 16 | --------- 17 | 18 | #### valueOf 19 | 20 | `valueOf()` 21 | 22 | The primitive value of the number, i.e., the number itself. 23 | 24 | *Returns* 25 | 26 | The number. 27 | 28 | #### toString 29 | 30 | `toString()` 31 | 32 | Converts the number to a string. 33 | 34 | *Returns* 35 | 36 | The number converted to a string. 37 | 38 | #### equals 39 | 40 | `equals(x)` 41 | 42 | Compares the number to another number `x`. This routine performs a comparison between floating point numbers. It's recommended to use [Math.approximately()](/reference/math#approximately) instead. 43 | 44 | *Arguments* 45 | 46 | * `x`: number. The value to compare the number to. 47 | 48 | *Returns* 49 | 50 | Returns `true` if the numbers are equal. 51 | 52 | #### isFinite 53 | 54 | `isFinite()` 55 | 56 | Checks if the number is finite. 57 | 58 | *Available since:* SurgeScript 0.5.2 59 | 60 | *Returns* 61 | 62 | Returns `true` if the number is finite. 63 | 64 | #### isNaN 65 | 66 | `isNaN()` 67 | 68 | Checks if the value is NaN (Not-a-Number). 69 | 70 | *Available since:* SurgeScript 0.5.2 71 | 72 | *Returns* 73 | 74 | Returns `true` if the value is NaN. 75 | 76 | #### isInteger 77 | 78 | `isInteger()` 79 | 80 | Checks if the number is an integer. 81 | 82 | *Available since:* SurgeScript 0.5.2 83 | 84 | *Returns* 85 | 86 | Returns `true` if the number is an integer. -------------------------------------------------------------------------------- /docs/reference/plugin.md: -------------------------------------------------------------------------------- 1 | Plugin 2 | ====== 3 | 4 | SurgeScript features a plugin system that allows you to extend the functionalities of the language. Known as plugins or [packages](/tutorials/packages), these objects can be imported and accessed anywhere in the code. They are imported using a `using` statement. The plugin system can be accessed simply by typing `Plugin`. 5 | 6 | Example: 7 | 8 | ```cs 9 | // File: app.ss 10 | // An application that uses StringUtils, defined in another file 11 | using StringUtils; 12 | 13 | object "Application" 14 | { 15 | str = "alucard"; 16 | 17 | state "main" 18 | { 19 | Console.print("Reverse a string:"); 20 | Console.print(str); 21 | Console.print(StringUtils.reverse(str)); 22 | Application.exit(); 23 | } 24 | } 25 | ``` 26 | 27 | ```cs 28 | // File: string_utils.ss 29 | // String utilities 30 | 31 | @Package 32 | object "StringUtils" 33 | { 34 | fun reverse(str) 35 | { 36 | buf = ""; 37 | for(i = str.length - 1; i >= 0; i--) 38 | buf += str[i]; 39 | return buf; 40 | } 41 | } 42 | ``` 43 | 44 | *Available since:* SurgeScript 0.5.2 45 | 46 | Properties 47 | ---------- 48 | 49 | #### count 50 | 51 | `count`: number, read-only. 52 | 53 | The number of plugins. 54 | 55 | Functions 56 | --------- 57 | 58 | #### spawn 59 | 60 | `spawn(objectName)` 61 | 62 | Spawns an object called `objectName` as a plugin. This function is not to be used directly, as SurgeScript spawns the plugins automatically for you. 63 | 64 | *Arguments* 65 | 66 | * `objectName`: string. The name of the object to be spawned as a plugin. It's not recommended to include special characters in this name. 67 | 68 | #### get 69 | 70 | `get(objectName)` 71 | 72 | Gets a reference to the plugin named `objectName`. The `[ ]` operator can be used instead of the `get()` function, as in `Plugin[objectName]`. 73 | 74 | Rather than using this function, it's recommended to import the desired object using the `using MyObject;` statement at the beginning of your code. Your object will be available as `MyObject`. 75 | 76 | *Arguments* 77 | 78 | * `objectName`: string. The name of the plugin. 79 | 80 | *Example* 81 | 82 | ```cs 83 | using StringUtils; 84 | 85 | // ... 86 | 87 | assert(Plugin["StringUtils"] === StringUtils); 88 | assert(Plugin.StringUtils === StringUtils); 89 | ``` -------------------------------------------------------------------------------- /docs/reference/surgescript.md: -------------------------------------------------------------------------------- 1 | SurgeScript 2 | =========== 3 | 4 | Data related to the scripting language itself. You can access this object simply by typing `SurgeScript`. 5 | 6 | Example: 7 | 8 | ```cs 9 | // Prints the version of the SurgeScript runtime 10 | object "Application" 11 | { 12 | state "main" 13 | { 14 | Console.print(SurgeScript.version); 15 | } 16 | } 17 | ``` 18 | 19 | *Available since:* SurgeScript 0.5.2 20 | 21 | Properties 22 | ---------- 23 | 24 | #### version 25 | 26 | `version`: string, read-only. 27 | 28 | Version number of the SurgeScript runtime. -------------------------------------------------------------------------------- /docs/reference/system.md: -------------------------------------------------------------------------------- 1 | System 2 | ====== 3 | 4 | The root object. Used to gather data from the language and to access special objects. It can be accessed by typing `System`. 5 | 6 | Properties 7 | ---------- 8 | 9 | #### tags 10 | 11 | `tags`: [Tag System](/reference/tags) object, read-only. 12 | 13 | A reference to the Tag System. 14 | 15 | #### gc 16 | 17 | `gc`: [Garbage Collector](/reference/gc) object, read-only. 18 | 19 | A reference to the Garbage Collector object. 20 | 21 | #### objectCount 22 | 23 | `objectCount`: number, read-only. 24 | 25 | The total number of objects at this moment. 26 | 27 | Functions 28 | --------- 29 | 30 | #### exit 31 | 32 | `exit()` 33 | 34 | Exits the Application. 35 | 36 | #### destroy 37 | 38 | `destroy()` 39 | 40 | The same as `exit()`. -------------------------------------------------------------------------------- /docs/reference/tags.md: -------------------------------------------------------------------------------- 1 | TagSystem 2 | ========= 3 | 4 | Utility functions for dealing with object tags. This object is available at `System.tags` and shouldn't be instantiated directly. 5 | 6 | Functions 7 | --------- 8 | 9 | #### list 10 | 11 | `list()` 12 | 13 | Lists all tags used in all objects. 14 | 15 | *Returns* 16 | 17 | A new [Array](/reference/array) of strings with all tags used in all objects. 18 | 19 | #### select 20 | 21 | `select(tagName)` 22 | 23 | Selects all objects that are tagged `tagName`. 24 | 25 | *Arguments* 26 | 27 | * `tagName`: string. 28 | 29 | *Returns* 30 | 31 | A new [Array](/reference/array) of strings with the names of the objects tagged with `tagName`. If there are no such objects, an empty array is returned. 32 | 33 | #### tagsOf 34 | 35 | `tagsOf(objectName)` 36 | 37 | Returns the tags of the objects named `objectName`. 38 | 39 | *Available since:* SurgeScript 0.6.0 40 | 41 | *Arguments* 42 | 43 | * `objectName`: string. 44 | 45 | *Returns* 46 | 47 | A new [Array](/reference/array) of strings with the names of the tags associated with the objects named `objectName`. If the objects are untagged or do not exist, an empty array is returned. 48 | 49 | #### hasTag 50 | 51 | `hasTag(objectName, tagName)` 52 | 53 | Checks if objects named `objectName` are tagged `tagName`. Prefer using [Object.hasTag()](/reference/object#hastag) if possible. 54 | 55 | See also: [Object.hasTag()](/reference/object#hastag). 56 | 57 | *Available since:* SurgeScript 0.6.0 58 | 59 | *Arguments* 60 | 61 | * `objectName`: string. 62 | * `tagName`: string. 63 | 64 | *Returns* 65 | 66 | Returns `true` if the objects are tagged as specified, or `false` otherwise. 67 | -------------------------------------------------------------------------------- /docs/reference/time.md: -------------------------------------------------------------------------------- 1 | Time 2 | ==== 3 | 4 | Time utilities. This object is available simply by typing `Time`. 5 | 6 | Properties 7 | ---------- 8 | 9 | #### time 10 | 11 | `time`: number, read-only. 12 | 13 | Elapsed time, in seconds, since the application was started and measured at the beginning of the current frame. 14 | 15 | #### delta 16 | 17 | `delta`: number, read-only. 18 | 19 | The time, in seconds, taken to complete the last frame of the application. Use this value to make your application behave consistently regardless of the frame rate. 20 | 21 | #### now 22 | 23 | `now`: number, read-only. 24 | 25 | Elapsed time, in seconds, since the application was started and measured at the moment this property is evaluated. 26 | 27 | *Available since:* SurgeScript 0.5.4 28 | 29 | !!! tip 30 | 31 | It's generally advisable to use [Time.time](#time) instead, because [Time.now](#now) may return different values in the same frame of your application. -------------------------------------------------------------------------------- /docs/tutorials/best_practices.md: -------------------------------------------------------------------------------- 1 | Best Practices 2 | ============== 3 | 4 | - Read the [Components](/tutorials/components) section. It's crucial that you understand it. 5 | - Follow the golden rule: objects should **not** mess with each others' internals! 6 | - Objects should **not** change others' internal variables or states directly (not allowed!) 7 | - Objects should define [functions](/tutorials/functions) that can be operated upon by the external world (API) 8 | - Use a consistent coding style. Suggestion: 9 | - Use *camelCase* names for both variables and functions. 10 | - Use *4 spaces* when indenting your code. 11 | - Combine related [packages](/tutorials/packages) into a single one: don't pollute the global namespace. 12 | - Read the [SurgeScript documentation](/) often. 13 | - **Practice, practice, practice! - and have fun!** -------------------------------------------------------------------------------- /docs/tutorials/comments.md: -------------------------------------------------------------------------------- 1 | Comments 2 | ======== 3 | 4 | Comments are used to make your code more human-readable. They are ignored by the computer. SurgeScript allows two kinds of comments: single-line comments and multi-line comments. 5 | 6 | Single-line comments 7 | -------------------- 8 | 9 | Single-line comments start with a `//`. Example: 10 | 11 | ```cs 12 | // This line has no effect on the code (it's just for improved readability) 13 | x = 3 + 4; // x is now 7 14 | ``` 15 | 16 | Multi-line comments 17 | ------------------- 18 | 19 | Multi-line comments start with a `/*` and end with a `*/`. Example: 20 | 21 | ```cs 22 | /* 23 | * Comments can, but don't have to, take 24 | * multiple lines if you use this form. 25 | */ 26 | x = 3 + 4; /* x is now 7 */ 27 | ``` 28 | 29 | Comments of this form cannot be nested. -------------------------------------------------------------------------------- /docs/tutorials/components.md: -------------------------------------------------------------------------------- 1 | Components 2 | ========== 3 | 4 | Introduction 5 | ------------ 6 | 7 | Entity Component System (ECS) is a software pattern used in game development. The idea is that in-game objects (called *entities*) can be customized by adding or removing objects (called *components*) during runtime. Components add functionalities or behaviors to the entities to which they are attached to. In SurgeScript, both entities and components are objects - the difference is conceptual. 8 | 9 | As an example, consider an in-game object called **Parrot**. Objects by themselves are empty; they do nothing. However, an interesting behavior of parrots is that they are blabbers: they keep repeating the same thing over and over again. So, let's create an empty object called **Parrot**, tag it as an *entity* and spawn the **Blabber** component on it: 10 | 11 | ```cs 12 | object "Parrot" is "entity" 13 | { 14 | blabber = spawn("Blabber"); 15 | 16 | state "main" 17 | { 18 | } 19 | } 20 | 21 | object "Blabber" 22 | { 23 | state "main" 24 | { 25 | if(timeout(2)) // blab every 2 seconds 26 | state = "blab"; 27 | } 28 | 29 | state "blab" 30 | { 31 | Console.print("Hello!"); 32 | state = "main"; 33 | } 34 | } 35 | ``` 36 | 37 | Now, whenever you spawn a Parrot, it will keep blabbing (*parroting*) unceasingly: 38 | 39 | ``` 40 | Hello! 41 | Hello! 42 | Hello! 43 | ... 44 | ``` 45 | 46 | Suppose now that your Parrot is a Kamikaze Robot: it blabs so much that it will explode itself after some time. We'll attach a **Time Bomb** to the parroting robot, so that it will stop blabbing after a while: 47 | 48 | ```cs 49 | object "Time Bomb" 50 | { 51 | state "main" 52 | { 53 | if(timeout(15)) // explode after 15 seconds 54 | state = "explode"; 55 | } 56 | 57 | state "explode" 58 | { 59 | Console.print("BOOOM!"); 60 | parent.destroy(); // destroy the parent object 61 | } 62 | } 63 | 64 | object "Parrot" is "entity" 65 | { 66 | blabber = spawn("Blabber"); 67 | bomb = spawn("Time Bomb"); 68 | 69 | state "main" 70 | { 71 | } 72 | } 73 | ``` 74 | 75 | Now, here's the output: 76 | 77 | ``` 78 | Hello! 79 | Hello! 80 | Hello! 81 | Hello! 82 | Hello! 83 | Hello! 84 | Hello! 85 | BOOOM! 86 | ``` 87 | 88 | In this example, **Parrot** is an entity and **Blabber** and **Time Bomb** are its components. Once the entity is destroyed, its components (its children) are also destroyed automatically. 89 | 90 | Design considerations 91 | --------------------- 92 | 93 | In some implementations of ECS, entities are implemented as integers and components consist of raw data only. The game logic is executed by the System layer, which iterates throughout all entities continuously and executes the logic according to the components attached to them. 94 | 95 | In SurgeScript, components execute their own code and can be attached to entities simply by spawning them as children. Still, you can use the former approach if you wish to do so. 96 | 97 | Composition over inheritance 98 | ---------------------------- 99 | 100 | SurgeScript does not explicitly support inheritance, a feature found in other object-oriented languages. The usage of components is encouraged instead. SurgeScript favors composition over inheritance, allowing for greater flexibility when defining in-game objects. 101 | -------------------------------------------------------------------------------- /docs/tutorials/conditionals.md: -------------------------------------------------------------------------------- 1 | Conditionals 2 | ============ 3 | 4 | Introduction 5 | ------------ 6 | 7 | Conditionals are `if-then` statements. If a certain `condition` evaluates to `true`, execute a block of code. If not, don't execute it. 8 | 9 | ```cs 10 | if(condition) { 11 | // this will be executed only if 12 | // the condition is true 13 | } 14 | ``` 15 | 16 | Alternatively, we may include an `else` statement followed by a block of code that will only be executed if the condition is **not** true: 17 | 18 | ```cs 19 | if(condition) { 20 | // this will be executed only if 21 | // the condition is true 22 | } 23 | else { 24 | // this will be executed only if 25 | // the condition is false 26 | } 27 | ``` 28 | 29 | Example 30 | ------- 31 | 32 | The following example will print *underaged* if variable `age` is less than 18, or *adult* otherwise: 33 | 34 | ```cs 35 | object "Application" 36 | { 37 | age = 23; 38 | 39 | state "main" 40 | { 41 | if(age < 18) { 42 | // variable age is less than 18 43 | Console.print("underaged"); 44 | } 45 | else { 46 | // variable age is not less than 18 47 | Console.print("adult"); 48 | } 49 | } 50 | } 51 | ``` 52 | 53 | 54 | Inline conditionals 55 | ------------------- 56 | 57 | Just like other languages with C-based syntax, the expression `condition ? true_value : false_value` evaluates to `true_value` if `condition` is `true` and to `false_value` if `condition` is `false`. 58 | 59 | For example, the script below will print *underaged* if variable `age` is less than 18, or *adult* otherwise: 60 | 61 | ```cs 62 | object "Application" 63 | { 64 | age = 23; 65 | message = age < 18 ? "underaged" : "adult"; 66 | 67 | state "main" 68 | { 69 | Console.print(message); 70 | } 71 | } 72 | ``` 73 | -------------------------------------------------------------------------------- /docs/tutorials/hello.md: -------------------------------------------------------------------------------- 1 | Hello, World! 2 | ============= 3 | 4 | SurgeScript creates automatically an object called **Application**. That object is defined by the user. Let's see how we can use that to make a simple program: 5 | 6 | ```cs 7 | object "Application" 8 | { 9 | state "main" 10 | { 11 | Console.print("Hello, world!"); 12 | Application.exit(); 13 | } 14 | } 15 | ``` 16 | 17 | In SurgeScript, each object defines a state machine (more on that later). The initial state is called **main**. In the code just presented, we display a *Hello, world!* message and then exit the app. 18 | 19 | Now let's [test your scripts](/tutorials/testing). 20 | -------------------------------------------------------------------------------- /docs/tutorials/object_tree.md: -------------------------------------------------------------------------------- 1 | Object tree 2 | =========== 3 | 4 | Introduction 5 | ------------ 6 | 7 | In SurgeScript, objects have a hierarchical relationship. Suppose that object P *spawns* (or *instantiates*) object C. We say that object P is the *parent* of C. Similarly, object C is a *child* of P. 8 | 9 | An object may spawn many children. However, all objects have only one parent. This relationship between objects forms a hierarchy (a tree). The Figure below shows an example: 10 | 11 | ![An object tree](/img/tree.png) 12 | 13 | In this example, Level is the parent of GameItem1 and GameItem2. Components A and B are children of GameItem1, but not of GameItem2. Level has two children and GameItem2 has zero. Finally, GameItem1, GameItem2, Component A and Component B are all *descendants* of Level. 14 | 15 | In SurgeScript, the root of the hierarchy is a predefined object called `System`. Its parent is itself. All other objects are descendants of `System`. 16 | 17 | Spawning objects 18 | ---------------- 19 | 20 | You can use `spawn()` to instantiate an object. Example: 21 | 22 | ```cs 23 | object "Parent" 24 | { 25 | child = spawn("Child"); 26 | 27 | state "main" 28 | { 29 | } 30 | } 31 | 32 | object "Child" 33 | { 34 | state "main" 35 | { 36 | } 37 | } 38 | ``` 39 | 40 | Function `spawn()` may be invoked on objects other than the caller. In this case, the caller won't be the parent of the newly created object: 41 | 42 | ```cs 43 | object "Parent" 44 | { 45 | child = spawn("Child"); 46 | grandChild = child.spawn("Child"); 47 | 48 | state "main" 49 | { 50 | } 51 | } 52 | ``` 53 | 54 | !!! tip "Automatic Garbage Collection" 55 | 56 | When you spawn an object, make sure you store a reference to it somewhere. 57 | 58 | If an object cannot be reached from the root (no reachable object has any references to it), it will be automatically destroyed by SurgeScript's built-in garbage collector. 59 | 60 | 61 | 62 | Destroying objects 63 | ------------------ 64 | 65 | Objects can be destroyed manually by calling `destroy()`. Whenever an object is destroyed, its children are destroyed as well. 66 | 67 | ```cs 68 | object "Foo" 69 | { 70 | state "main" 71 | { 72 | Console.print("This object does nothing."); 73 | destroy(); 74 | } 75 | } 76 | ``` 77 | 78 | Traversing the hierarchy 79 | ------------------------ 80 | 81 | Relevant data about the object hierarchy can be obtained using the following properties and functions (find out more about them at the [Object reference](/reference/object)): 82 | 83 | Function / property|Description 84 | -------------------|----------- 85 | `obj.parent` | The parent object 86 | `obj.child(name)` | Gets a child object named `name` 87 | `obj.findObject(name)` | Finds a descendant named `name` 88 | `obj.__childCount` | Number of immediate children 89 | 90 | Example: 91 | 92 | ```cs 93 | object "Parent" 94 | { 95 | child = spawn("Child"); 96 | otherChild = spawn("Child"); 97 | 98 | state "main" 99 | { 100 | Console.print("This object has " + this.__childCount + " children."); 101 | destroy(); 102 | } 103 | } 104 | ``` 105 | 106 | The output is as follows: 107 | 108 | ``` 109 | This object has 2 children. 110 | ``` 111 | -------------------------------------------------------------------------------- /docs/tutorials/objects.md: -------------------------------------------------------------------------------- 1 | Introduction to objects 2 | ======================= 3 | 4 | Introduction 5 | ------------ 6 | 7 | In SurgeScript, objects are units of code and data. Each object defines a finite state machine, a mathematical construct used to describe the behavior of in-game objects. 8 | 9 | !!! info "Did you know?" 10 | 11 | Games implement what is called a game loop. In SurgeScript, the game loop is defined implicitly via state machines. State machines are one of the key features of SurgeScript. 12 | 13 | State machines 14 | -------------- 15 | 16 | A finite state machine is a mathematical abstraction composed of a finite number of **states** and by **transitions** between these states. Only one state can be active at any given time (we'll call it the **active state**). There must be one **initial state** (i.e., the first one to be active). A transition is a change of the active state that is triggered when a certain condition is met. 17 | 18 | As a concrete example, suppose that you want to create a door in your game. You, the developer, may open or close the door at will. But what is a door? We have just given *informal* description of the problem. However, we need to transform it in something more rigorous. Example: 19 | 20 | A door is an object with two states (see the Figure below): 21 | 22 | - Opened (initial state) 23 | - Closed 24 | 25 | ![State machine](../img/state-machine.png) 26 | 27 | From the Opened state, only one transition is possible: Close. Once the Close transition is called, the door will go to the Closed state. Conversely, from the Closed state, only one transition is available: Open. When the Open transition is executed, the door will return to the Opened state. 28 | 29 | Objects in SurgeScript 30 | ---------------------- 31 | 32 | In SurgeScript, each object has a name. Objects may have any number of states you'd like. The initial state is always called **main**. The syntax is as follows: 33 | 34 | ```cs 35 | object "name of the object" 36 | { 37 | state "state name" 38 | { 39 | // code goes here 40 | } 41 | } 42 | ``` 43 | 44 | The following code shows an example of a door that opens and closes (it keep changing states) every 2 seconds: 45 | 46 | ```cs 47 | object "Cosmic Door" 48 | { 49 | state "main" 50 | { 51 | // the object starts at the main state 52 | state = "opened"; // go to the opened state 53 | } 54 | 55 | state "opened" 56 | { 57 | if(timeout(2)) // if we have been on the opened state for 2+ seconds 58 | state = "closed"; // go to the closed state 59 | } 60 | 61 | state "closed" 62 | { 63 | if(timeout(2)) 64 | state = "opened"; 65 | } 66 | } 67 | ``` 68 | 69 | Notice how the code just shown defines states and transitions between these states. Each state contains its own code. 70 | 71 | **Note:** once a state is active, its code will be repeated at every frame of the application until the state changes or until the object is destroyed. 72 | -------------------------------------------------------------------------------- /docs/tutorials/properties.md: -------------------------------------------------------------------------------- 1 | Properties 2 | ========== 3 | 4 | Introduction 5 | ------------ 6 | 7 | In SurgeScript, [object-level variables](/tutorials/variables) are private. This means that these variables can only be accessed from the objects that defined them. However, SurgeScript features a *syntactic sugar* that allows objects to read and/or modify other objects' data in a way that looks like dealing with regular (public) variables. We'll call these "variables" **properties**. 8 | 9 | Defining properties 10 | ------------------- 11 | 12 | Suppose you have an object called `Animal` with an object-level variable called `sound` and a function named `speak()`: 13 | 14 | ```cs 15 | object "Animal" 16 | { 17 | sound = "meow!"; 18 | 19 | fun speak() 20 | { 21 | Console.print(sound); 22 | } 23 | } 24 | ``` 25 | 26 | This object can only speak *meow!* Let's see: 27 | 28 | ```cs 29 | object "Application" 30 | { 31 | animal = spawn("Animal"); 32 | 33 | state "main" 34 | { 35 | animal.speak(); 36 | } 37 | } 38 | ``` 39 | 40 | Run this script and you'll see: 41 | 42 | ``` 43 | meow! 44 | meow! 45 | meow! 46 | meow! 47 | ... 48 | ``` 49 | 50 | What if an external object could modify the sound of the animal? Trying to access `animal.sound` externally will trigger an error, unless you add the `public` specifier to your variable: 51 | 52 | ```cs 53 | object "Animal" 54 | { 55 | public sound = "meow!"; 56 | 57 | fun speak() 58 | { 59 | Console.print(sound); 60 | } 61 | } 62 | ``` 63 | 64 | Now, external objects may access (read and write) the `sound` variable (or *property*): 65 | 66 | ```cs 67 | object "Application" 68 | { 69 | animal = spawn("Animal"); 70 | 71 | state "main" 72 | { 73 | animal.sound = "woof!"; 74 | animal.speak(); 75 | } 76 | } 77 | ``` 78 | 79 | Since SurgeScript 0.5.3, you may add the `readonly` modifier after the `public` specifier. Doing so disallows the modification of the property by external objects: 80 | 81 | ```cs 82 | object "Animal" 83 | { 84 | public readonly sound = "meow!"; 85 | 86 | fun speak() 87 | { 88 | Console.print(sound); 89 | } 90 | } 91 | 92 | object "Application" 93 | { 94 | animal = spawn("Animal"); 95 | 96 | state "main" 97 | { 98 | //animal.sound = "woof!"; // will trigger an error 99 | //Console.print(animal.sound); // this is allowed 100 | animal.speak(); 101 | } 102 | } 103 | ``` 104 | 105 | Using getters and setters 106 | ------------------------- 107 | 108 | In reality, however, there are no public variables in SurgeScript. Behind the scenes, the language defines special functions called *getters* and *setters* that will perform the read/write logic for you. Rather than using `public`, you may want to define the getters and the setters yourself: 109 | 110 | ```cs 111 | object "Animal" 112 | { 113 | sound = "meow!"; 114 | 115 | fun speak() 116 | { 117 | Console.print(sound); 118 | } 119 | 120 | fun set_sound(value) 121 | { 122 | sound = value; 123 | } 124 | 125 | fun get_sound() 126 | { 127 | return sound; 128 | } 129 | } 130 | ``` 131 | 132 | This code is semantically the same as setting `sound` to be `public`; this is just a bit longer. 133 | 134 | An advantage of defining getters and setters by yourself is that you control how the data passes through the objects. You may want to validate the data before changing the internal variables of the objects. Example: 135 | 136 | ```cs 137 | // lives must not be a negative number 138 | fun set_lives(value) 139 | { 140 | if(value >= 0) 141 | lives = value; 142 | else 143 | lives = 0; 144 | } 145 | ``` -------------------------------------------------------------------------------- /docs/tutorials/tags.md: -------------------------------------------------------------------------------- 1 | Tags 2 | ==== 3 | 4 | You may tag objects with as many tags as you want. Tags are a way of attributing categories to objects. 5 | 6 | Syntax 7 | ------ 8 | 9 | Tags should be placed right after the object name. Example: 10 | 11 | ```cs 12 | object "Horse" is "animal", "vehicle" 13 | { 14 | state "main" 15 | { 16 | } 17 | } 18 | 19 | object "Cat" is "animal" 20 | { 21 | state "main" 22 | { 23 | } 24 | } 25 | 26 | object "Car" is "vehicle" 27 | { 28 | state "main" 29 | { 30 | } 31 | } 32 | ``` 33 | 34 | Using tags 35 | ---------- 36 | 37 | You may check if an object has a particular tag with the `hasTag()` function (see the [Object reference](/reference/object#hastag) for more details): 38 | 39 | ```cs 40 | object "Application" 41 | { 42 | horse = spawn("Horse"); 43 | cat = spawn("Cat"); 44 | car = spawn("Car"); 45 | 46 | state "main" 47 | { 48 | // Horse is both an animal and a vehicle 49 | Console.print(horse.hasTag("animal")); // true 50 | Console.print(horse.hasTag("vehicle")); // true 51 | 52 | // Cat is an animal, but not a vehicle 53 | Console.print(cat.hasTag("animal")); // true 54 | Console.print(cat.hasTag("vehicle")); // false 55 | 56 | // Car is a vehicle, but not an animal 57 | Console.print(car.hasTag("animal")); // false 58 | Console.print(car.hasTag("vehicle")); // true 59 | } 60 | } 61 | ``` -------------------------------------------------------------------------------- /docs/tutorials/testing.md: -------------------------------------------------------------------------------- 1 | Testing your scripts 2 | ==================== 3 | 4 | There are two main ways to test your scripts: 5 | 6 | - using the [Open Surge](#using-open-surge) game engine; 7 | - using the [SurgeScript standalone runtime](#using-the-standalone-version) (i.e., the version without a game engine). 8 | 9 | Using Open Surge 10 | ---------------- 11 | 12 | To test a script in Open Surge, place it on the *scripts/* folder and start the engine. Your test script must include an object called *Application*. Make sure to remove the script after you're done with the testing. 13 | 14 | As an example, save the following script to *scripts/hello.ss* and start the engine: 15 | ```cs 16 | // hello.ss: test script 17 | // Please remove this file after you're done 18 | object "Application" 19 | { 20 | state "main" 21 | { 22 | Console.print("Hello, world!"); 23 | state = "done"; 24 | } 25 | 26 | state "done" 27 | { 28 | } 29 | } 30 | ``` 31 | 32 | You should see the *Hello, world!* message as a result. 33 | 34 | **Linux users:** when using a system-wide installation, you may place your scripts on *~/.local/share/opensurge/scripts/* (i.e., *$XDG_DATA_HOME/opensurge/scripts/*). 35 | 36 | Ready to proceed? Let's go to [Introduction to objects](/tutorials/objects)! 37 | 38 | Using the standalone version 39 | ---------------------------- 40 | 41 | If you've downloaded the standalone version of the language: 42 | 43 | - First of all, save the following script to a file named *hello.ss*. For testing purposes, you may place the file on the same directory as the surgescript executable. 44 | ```cs 45 | // hello.ss: test script 46 | object "Application" 47 | { 48 | state "main" 49 | { 50 | Console.print("Hello, world!"); 51 | Application.exit(); 52 | } 53 | } 54 | ``` 55 | - Then, open up a Terminal and type: 56 | ```sh 57 | cd /path/to/surgescript 58 | ./surgescript hello.ss 59 | ``` 60 | - If you're using Microsoft Windows, open up a Command Prompt and type: 61 | ``` 62 | cd C:\path\to\surgescript 63 | surgescript.exe hello.ss 64 | ``` 65 | - You should see the output of the script as a result: 66 | ``` 67 | Hello, world! 68 | ``` 69 | 70 | To begin our learning adventure, let's go to [Introduction to objects](/tutorials/objects). 71 | -------------------------------------------------------------------------------- /examples/alfred_the_npc.ss: -------------------------------------------------------------------------------- 1 | // 2 | // alfred_the_npc.ss 3 | // Talk to Alfred, the NPC. 4 | // Copyright 2017 Alexandre Martins 5 | // 6 | 7 | object "Alfred" 8 | { 9 | // Alfred will ask a series of questions and 10 | // answer according to the answers of the user. 11 | state "main" 12 | { 13 | say("Hey! I'm Alfred, the NPC. Let's talk!"); 14 | state = "question 1"; 15 | } 16 | 17 | // --- Question 1: Pizza --- 18 | state "question 1" 19 | { 20 | x = ask("I enjoy pizza a lot. Do you?"); 21 | if(x == "y") 22 | state = "question 1 - yes"; 23 | else if(x == "n") 24 | state = "question 1 - no"; 25 | } 26 | 27 | state "question 1 - yes" 28 | { 29 | say("Cool! Who doesn't?"); 30 | state = "question 2"; 31 | } 32 | 33 | state "question 1 - no" 34 | { 35 | say("Well, too much pizza is bad for you anyway."); 36 | state = "question 2"; 37 | } 38 | 39 | // --- Question 2: Coke --- 40 | state "question 2" 41 | { 42 | x = ask("How about coke? Do you like it?"); 43 | if(x == "y") 44 | state = "question 2 - yes"; 45 | else if(x == "n") 46 | state = "question 2 - no"; 47 | } 48 | 49 | state "question 2 - yes" 50 | { 51 | say("Yikes! Gives me hickups!"); 52 | state = "question 3"; 53 | } 54 | 55 | state "question 2 - no" 56 | { 57 | say("Too bad!"); 58 | state = "question 3"; 59 | } 60 | 61 | // --- Question 3: Your name --- 62 | state "question 3" 63 | { 64 | say("What's your name, pal?"); 65 | name = Console.readline(); 66 | if(name != "") { 67 | say("It's been a pleasure talking to you, " + name); 68 | Application.exit(); 69 | } 70 | } 71 | 72 | 73 | // say() 74 | // Say something! 75 | fun say(message) 76 | { 77 | Console.print(message); 78 | } 79 | 80 | // ask() 81 | // Asks a question on the console. 82 | // Returns "y" (yes), "n" (no) or "" (no answer) 83 | fun ask(question) 84 | { 85 | Console.write(question); 86 | Console.write(" (y/n) "); 87 | answer = Console.readline(); 88 | 89 | if(answer == "y" || answer == "Y" || answer == "yes" || answer == "YES") 90 | return "y"; 91 | else if(answer == "n" || answer == "N" || answer == "no" || answer == "NO") 92 | return "n"; 93 | else 94 | return ""; 95 | } 96 | } 97 | 98 | object "Application" 99 | { 100 | alfred = spawn("Alfred"); 101 | 102 | // do nothing. 103 | state "main" 104 | { 105 | } 106 | } -------------------------------------------------------------------------------- /examples/arguments.ss: -------------------------------------------------------------------------------- 1 | // 2 | // arguments.ss 3 | // Print the command line arguments 4 | // Copyright 2018 Alexandre Martins 5 | // 6 | 7 | object "Application" 8 | { 9 | state "main" 10 | { 11 | // this app will print the command line arguments 12 | Console.print("Command line arguments: " + Application.args.length); 13 | 14 | // using foreach 15 | Console.print("Using foreach:"); 16 | foreach(argument in Application.args) 17 | Console.print(argument); 18 | 19 | // using for loops 20 | Console.print("Using for loops:"); 21 | for(i = 0; i < Application.args.length; i++) 22 | Console.print(Application.args[i]); 23 | 24 | // done! 25 | Application.exit(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/array.ss: -------------------------------------------------------------------------------- 1 | // 2 | // array.ss 3 | // Arrays in SurgeScript 4 | // Copyright 2017 Alexandre Martins 5 | // 6 | 7 | // The following program will print all the elements of the array 8 | // using different pieces of code 9 | object "Application" 10 | { 11 | array = [1, 2, 3, 4, 5]; 12 | 13 | state "main" 14 | { 15 | Console.print("The array has " + array.length + " elements."); 16 | 17 | // Loop with for 18 | for(i = 0; i < array.length; i++) 19 | Console.print(array[i]); 20 | 21 | // Loop with foreach 22 | foreach(element in array) 23 | Console.print(element); 24 | 25 | // Loop with iterators 26 | it = array.iterator(); 27 | while(it.hasNext()) { 28 | element = it.next(); 29 | Console.print(element); 30 | } 31 | 32 | Application.exit(); 33 | } 34 | } -------------------------------------------------------------------------------- /examples/component.ss: -------------------------------------------------------------------------------- 1 | // 2 | // component.ss 3 | // Basic Component usage 4 | // Copyright 2018 Alexandre Martins 5 | // 6 | 7 | // Object Parrot has two components: 8 | // Blabber and Time Bomb. 9 | object "Parrot" 10 | { 11 | blabber = spawn("Blabber"); 12 | bomb = spawn("Time Bomb"); 13 | 14 | state "main" 15 | { 16 | } 17 | } 18 | 19 | object "Blabber" 20 | { 21 | state "main" 22 | { 23 | if(timeout(2)) // blab every 2 seconds 24 | state = "blab"; 25 | } 26 | 27 | state "blab" 28 | { 29 | Console.print("Hello!"); 30 | state = "main"; 31 | } 32 | } 33 | 34 | object "Time Bomb" 35 | { 36 | state "main" 37 | { 38 | if(timeout(15)) // explode after 15 seconds 39 | state = "explode"; 40 | } 41 | 42 | state "explode" 43 | { 44 | Console.print("BOOOM!"); 45 | parent.destroy(); // destroy the parent object 46 | Application.exit(); 47 | } 48 | } 49 | 50 | object "Application" 51 | { 52 | parrot = spawn("Parrot"); 53 | 54 | state "main" 55 | { 56 | } 57 | } -------------------------------------------------------------------------------- /examples/count_to_10.ss: -------------------------------------------------------------------------------- 1 | // 2 | // count_to_10.ss 3 | // Count to 10 SurgeScript 4 | // Copyright 2017 Alexandre Martins 5 | // 6 | 7 | object "Application" 8 | { 9 | state "main" 10 | { 11 | // x will go from 1 to 10 12 | for(x = 1; x <= 10; x++) { 13 | Console.print(x); 14 | } 15 | 16 | // done! 17 | Application.exit(); 18 | } 19 | } -------------------------------------------------------------------------------- /examples/date.ss: -------------------------------------------------------------------------------- 1 | // 2 | // date.ss 3 | // Current date in SurgeScript 4 | // Copyright 2018 Alexandre Martins 5 | // 6 | 7 | // What day is today? 8 | object "Application" 9 | { 10 | nameOf = [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ]; 11 | 12 | // show the day 13 | state "main" 14 | { 15 | weekday = nameOf[Date.weekday]; 16 | today = Date.year + "-" + f(Date.month) + "-" + f(Date.day); 17 | Console.print("Today is " + today + ", a " + weekday + "!"); 18 | Application.exit(); 19 | } 20 | 21 | // add a leading zero 22 | fun f(x) 23 | { 24 | return ((x >= 10) ? "" : "0") + x; 25 | } 26 | } -------------------------------------------------------------------------------- /examples/dictionary.ss: -------------------------------------------------------------------------------- 1 | // 2 | // dictionary.ss 3 | // How to use the Dictionary in SurgeScript 4 | // Copyright 2017-2018 Alexandre Martins 5 | // 6 | 7 | object "Application" 8 | { 9 | // a Dictionary is a set of (key, value) pairs 10 | weight = { 11 | "Surge": 35, 12 | "Neon": 20, 13 | "Charge": 37.5, 14 | "Gimacian": 70 15 | }; 16 | 17 | // main state 18 | state "main" 19 | { 20 | // change some weights ("weight" as in everyday use, that is) 21 | weight["Neon"] = 25; 22 | weight["Charge"] += 3; 23 | 24 | // print the weights 25 | Console.print("Surge weighs " + weight["Surge"] + " kg."); 26 | Console.print("Neon weighs " + weight["Neon"] + " kg."); 27 | Console.print("Charge weighs " + weight["Charge"] + " kg."); 28 | Console.print("Gimacian weighs " + weight["Gimacian"] + " kg."); 29 | 30 | // sum up 31 | totalWeight = computeTotalWeight(); 32 | Console.print("Together, they weigh a total of " + totalWeight + " kg."); 33 | 34 | // done! 35 | Application.exit(); 36 | } 37 | 38 | // this function will add all weights stored in the Dictionary. 39 | fun computeTotalWeight() 40 | { 41 | sum = 0; 42 | 43 | foreach(entry in weight) 44 | sum += entry.value; 45 | 46 | return sum; 47 | } 48 | } -------------------------------------------------------------------------------- /examples/factory.ss: -------------------------------------------------------------------------------- 1 | // 2 | // factory.ss 3 | // Factory example 4 | // Copyright 2018 Alexandre Martins 5 | // 6 | using Greeter; // import the factory 7 | 8 | object "Application" 9 | { 10 | state "main" 11 | { 12 | // This will print: 13 | // Hello, alex! 14 | g = Greeter("alex"); 15 | g.greet(); 16 | exit(); 17 | } 18 | } 19 | 20 | object "Greeting" 21 | { 22 | public name = "anon"; 23 | 24 | fun greet() 25 | { 26 | Console.print("Hello, " + name + "!"); 27 | } 28 | } 29 | 30 | @Package 31 | object "Greeter" 32 | { 33 | // Greeter is a factory. It spawns and configures 34 | // a Greeting object for you. Being a package, 35 | // Greeter can be imported and used anywhere. 36 | fun call(name) 37 | { 38 | g = spawn("Greeting"); 39 | g.name = name; 40 | return g; 41 | } 42 | } -------------------------------------------------------------------------------- /examples/garbage_collector.ss: -------------------------------------------------------------------------------- 1 | // 2 | // garbage_collector.ss 3 | // Garbage Collector test 4 | // Copyright 2018 Alexandre Martins 5 | // 6 | 7 | object "Application" 8 | { 9 | count = 0; 10 | arr = null; 11 | 12 | state "main" 13 | { 14 | // this will allocate a lot of phony arrays 15 | // the Garbage Collector should release them 16 | phonyAlloc(); 17 | 18 | // print the garbage stats every once in a while 19 | if(timeout(0.5)) { 20 | Console.print("\nObjects before release: " + System.objectCount); 21 | System.gc.collect(); 22 | Console.print("Released objects: " + System.gc.objectCount); 23 | state = "wait"; 24 | } 25 | } 26 | 27 | state "wait" 28 | { 29 | if(timeout(0.5)) 30 | state = "print"; 31 | } 32 | 33 | state "print" 34 | { 35 | Console.print("Objects after release: " + System.objectCount); 36 | 37 | if(++count >= 20) 38 | Application.exit(); 39 | 40 | state = "main"; 41 | } 42 | 43 | fun constructor() 44 | { 45 | // intro text 46 | Console.print("Garbage Collector Test"); 47 | Console.print("Usage: surgescript /path/to/garbage_collector.ss -- --surgescript-gc-interval "); 48 | 49 | // disable automatic garbage collection 50 | //System.gc.interval = Math.infinity; // obsolete since SurgeScript 0.6.0 51 | } 52 | 53 | fun phonyAlloc() 54 | { 55 | if(count < 15) 56 | arr = []; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /examples/getters_setters.ss: -------------------------------------------------------------------------------- 1 | // 2 | // getters_setters.ss 3 | // getters & setters in SurgeScript 4 | // Copyright 2017 Alexandre Martins 5 | // 6 | 7 | object "Application" 8 | { 9 | obj = spawn("Skull"); 10 | 11 | state "main" 12 | { 13 | hello(); 14 | showStatus(); 15 | obj.eyes = 4; // the same as obj.set_eyes(4) 16 | //obj.name = "master"; // will crash; no setter defined. Try uncommenting this. 17 | showStatus(); 18 | Application.exit(); 19 | } 20 | 21 | fun hello() 22 | { 23 | // typing obj.name is the same as obj.get_name() 24 | Console.print("Hello, " + obj.name); 25 | } 26 | 27 | fun showStatus() 28 | { 29 | Console.print("Skull " + obj.name + " has " + obj.eyes + " eyes."); 30 | } 31 | } 32 | 33 | object "Skull" 34 | { 35 | name = "kid"; 36 | eyes = 2; 37 | 38 | state "main" 39 | { 40 | } 41 | 42 | // get_eyes() 43 | // Note: typing obj.eyes yields the same as obj.get_eyes() 44 | fun get_eyes() 45 | { 46 | return eyes; 47 | } 48 | 49 | // set_eyes() 50 | // Syntactic sugar to obj.eyes = value (will call obj.set_eyes(value) behind the scenes) 51 | fun set_eyes(value) 52 | { 53 | eyes = value; 54 | } 55 | 56 | // get_name() 57 | // obj.name will return the [private] variable name. Note that we did not define a setter. 58 | fun get_name() 59 | { 60 | return name; 61 | } 62 | } -------------------------------------------------------------------------------- /examples/hello.ss: -------------------------------------------------------------------------------- 1 | // 2 | // hello.ss 3 | // Hello World in SurgeScript 4 | // Copyright 2017 Alexandre Martins 5 | // 6 | 7 | object "Application" 8 | { 9 | state "main" 10 | { 11 | Console.print("Hello, world!"); 12 | Application.exit(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/package.ss: -------------------------------------------------------------------------------- 1 | // 2 | // package.ss 3 | // Package example 4 | // Copyright 2018-2019 Alexandre Martins 5 | // 6 | 7 | // import the package 8 | using StringUtils; 9 | 10 | // An application that uses the imported package 11 | object "Application" 12 | { 13 | str = "alucard"; 14 | 15 | state "main" 16 | { 17 | Console.print("Reverse a string:"); 18 | Console.print(str); 19 | Console.print(StringUtils.reverse(str)); 20 | Application.exit(); 21 | } 22 | } 23 | 24 | // Packages are annotated with "@Package" 25 | @Package 26 | object "StringUtils" 27 | { 28 | fun constructor() 29 | { 30 | Console.print("Spawned StringUtils."); 31 | } 32 | 33 | fun reverse(str) 34 | { 35 | buf = ""; 36 | for(i = str.length - 1; i >= 0; i--) 37 | buf += str[i]; 38 | return buf; 39 | } 40 | } -------------------------------------------------------------------------------- /examples/performance.ss: -------------------------------------------------------------------------------- 1 | // 2 | // performance.ss 3 | // Performance measurement in SurgeScript 4 | // Copyright 2018 Alexandre Martins 5 | // 6 | 7 | // 8 | // A functor is an object that behaves like a function. 9 | // SurgeScript has a syntactic sugar that allows an object to be "called" like a function. 10 | // Example: given an object f, writing 11 | // y = f(x); 12 | // is the same as writing 13 | // y = f.call(x); 14 | // 15 | 16 | // Main Application 17 | object "Application" 18 | { 19 | benchmark = spawn("Benchmark"); 20 | fib = spawn("Fibonacci"); 21 | 22 | state "main" 23 | { 24 | t = benchmark(fib(1)); 25 | t += benchmark(fib(5)); 26 | t += benchmark(fib(10)); 27 | t += benchmark(fib(25)); 28 | t += benchmark(fib(32)); 29 | Console.print("Total time: " + t + " seconds."); 30 | Application.exit(); 31 | } 32 | } 33 | 34 | // This object measures the performance of functor f 35 | object "Benchmark" 36 | { 37 | fun call(f) 38 | { 39 | Console.write("Computing " + f + " = "); 40 | start = Time.now; 41 | result = f(); 42 | elapsed = Time.now - start; 43 | Console.print(result + " \t\t done in " + elapsed + " seconds."); 44 | return elapsed; 45 | } 46 | } 47 | 48 | // This functor computes the Fibonacci sequence using an exponential algorithm 49 | object "ExponentialFibonacci" 50 | { 51 | public n = 1; 52 | 53 | fun call() 54 | { 55 | return fib(n); 56 | } 57 | 58 | fun fib(n) 59 | { 60 | if(n > 2) 61 | return fib(n-1) + fib(n-2); 62 | else 63 | return 1; 64 | } 65 | 66 | fun toString() 67 | { 68 | return "ExpFib(" + n + ")"; 69 | } 70 | } 71 | 72 | // This object generates a Fibonacci functor 73 | object "Fibonacci" 74 | { 75 | fun call(n) 76 | { 77 | fib = spawn("ExponentialFibonacci"); 78 | fib.n = n; 79 | return fib; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /examples/sort_array.ss: -------------------------------------------------------------------------------- 1 | // 2 | // sort_array.ss 3 | // Sorting arrays in SurgeScript 4 | // Copyright 2017 Alexandre Martins 5 | // 6 | 7 | object "Application" 8 | { 9 | arr = [3, 7, 1, 5, 9, 2, 4, 6, 8, 0]; 10 | 11 | state "main" 12 | { 13 | Console.print("Original array:"); 14 | printNumbers(); 15 | 16 | Console.print("Sorting in ascending order..."); 17 | arr.sort(null); 18 | printNumbers(); 19 | 20 | Console.print("Sorting in descending order..."); 21 | arr.reverse(); 22 | printNumbers(); 23 | 24 | Console.print("Sorting in custom order (odds first)..."); 25 | arr.sort(spawn("SortStrategy.OddsFirst")); 26 | printNumbers(); 27 | 28 | Application.exit(); 29 | } 30 | 31 | fun printNumbers() 32 | { 33 | str = ""; 34 | for(i = 0; i < arr.length; i++) 35 | str += arr[i] + " "; 36 | Console.print(str); 37 | } 38 | } 39 | 40 | // A custom sorting strategy that puts odd numbers first 41 | object "SortStrategy.OddsFirst" 42 | { 43 | // 44 | // The call() method compares two numbers. 45 | // 46 | // call(a, b) will return: 47 | // -1 if a should come BEFORE b 48 | // 1 if a should come AFTER b 49 | // 0 if a and b share the same relative order 50 | // 51 | fun call(a, b) 52 | { 53 | aIsOdd = (Math.mod(a, 2) != 0); 54 | bIsOdd = (Math.mod(b, 2) != 0); 55 | 56 | if(aIsOdd && !bIsOdd) 57 | return -1; 58 | else if(!aIsOdd && bIsOdd) 59 | return 1; 60 | else if(a < b) 61 | return -1; 62 | else if(a > b) 63 | return 1; 64 | else 65 | return 0; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /examples/switch.ss: -------------------------------------------------------------------------------- 1 | // 2 | // switch.ss 3 | // Switch statement example 4 | // Copyright 2024 Alexandre Martins 5 | // 6 | 7 | object "Application" 8 | { 9 | state "main" 10 | { 11 | Console.print("The Full Name Game"); 12 | Console.print("------------------"); 13 | 14 | Console.print("I can tell you the full name of some characters."); 15 | Console.print("Type the name of a character to know its full name or type 'x' to quit the program."); 16 | Console.print("Known characters: Surge, Neon, Charge, Gimacian, Tux."); 17 | 18 | for(;;) { 19 | // read input 20 | Console.write("> "); 21 | input = Console.readline(); 22 | 23 | // quit the program? 24 | if(input == "x" || input == "X") 25 | break; 26 | 27 | // repeat the prompt if the input is empty 28 | if(input == "") 29 | continue; 30 | 31 | // print the full name and repeat the prompt 32 | printFullName(input); 33 | } 34 | 35 | Console.print("Bye!"); 36 | Application.exit(); 37 | } 38 | 39 | fun printFullName(name) 40 | { 41 | switch(name.toLowerCase()) { 42 | case "surge": 43 | Console.print("Surge the Rabbit"); 44 | break; 45 | 46 | case "neon": 47 | Console.print("Neon the Squirrel"); 48 | break; 49 | 50 | case "charge": 51 | Console.print("Charge the Badger"); 52 | break; 53 | 54 | case "gimacian": 55 | Console.print("Gimacian the Dark"); 56 | break; 57 | 58 | case "tux": 59 | Console.print("Tux the Penguin"); 60 | break; 61 | 62 | default: 63 | Console.print("Sorry, I don't recognize this name. Try again!"); 64 | break; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /examples/tags.ss: -------------------------------------------------------------------------------- 1 | // 2 | // tags.ss 3 | // Tags in SurgeScript 4 | // Copyright 2017-2018 Alexandre Martins 5 | // 6 | 7 | object "Application" 8 | { 9 | banana = spawn("Banana"); 10 | coin = spawn("Coin"); 11 | 12 | state "main" 13 | { 14 | Console.print("Welcome!"); 15 | showStatus(banana); 16 | showStatus(coin); 17 | Application.exit(); 18 | } 19 | 20 | fun showStatus(obj) 21 | { 22 | if(obj.hasTag("fruit")) 23 | Console.print("Object " + obj.__name + " is a fruit."); 24 | else 25 | Console.print("Object " + obj.__name + " is not a fruit."); 26 | } 27 | } 28 | 29 | object "Banana" is "pickup", "fruit" 30 | { 31 | state "main" 32 | { 33 | } 34 | } 35 | 36 | object "Coin" is "pickup" 37 | { 38 | state "main" 39 | { 40 | } 41 | } -------------------------------------------------------------------------------- /examples/timeout.ss: -------------------------------------------------------------------------------- 1 | // 2 | // timeout.ss 3 | // Timeout in SurgeScript 4 | // Copyright 2017 Alexandre Martins 5 | // 6 | 7 | object "Application" 8 | { 9 | state "main" 10 | { 11 | Console.print("Now on the main state. Please wait 4 seconds..."); 12 | state = "wait1"; 13 | } 14 | 15 | state "wait1" 16 | { 17 | if(timeout(4.0)) // will wait 4 seconds to change the state 18 | state = "cool"; 19 | } 20 | 21 | state "cool" 22 | { 23 | Console.print("Cool! Now wait for more 8 seconds..."); 24 | state = "wait2"; 25 | } 26 | 27 | state "wait2" 28 | { 29 | if(timeout(8.0)) 30 | state = "done"; 31 | } 32 | 33 | state "done" 34 | { 35 | Console.print("You're done!"); 36 | Application.exit(); 37 | } 38 | } -------------------------------------------------------------------------------- /examples/type_a_number.ss: -------------------------------------------------------------------------------- 1 | // 2 | // type_a_number.ss 3 | // Type a number plaything 4 | // Copyright 2017 Alexandre Martins 5 | // 6 | 7 | object "Application" 8 | { 9 | number = 0; // we declare the variable "number" here, so it 10 | // will be accessible throughout the whole object 11 | 12 | // the Application will be locked in state "main", and will 13 | // only leave it if the user types a number between 1 and 9 14 | state "main" 15 | { 16 | Console.write("Type a number between 1 and 9: "); 17 | number = Number(Console.readline()); 18 | if(number >= 1 && number <= 9) 19 | state = "done"; 20 | } 21 | 22 | // display the typed number and exit the app 23 | state "done" 24 | { 25 | Console.print("Congratulations! You typed " + number); 26 | Application.exit(); 27 | } 28 | } -------------------------------------------------------------------------------- /src/surgescript.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * surgescript.h 19 | * SurgeScript main header 20 | */ 21 | 22 | #ifndef _SURGESCRIPT_H 23 | #define _SURGESCRIPT_H 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | #include "surgescript/runtime/vm.h" 30 | #include "surgescript/runtime/program.h" 31 | #include "surgescript/runtime/object.h" 32 | #include "surgescript/runtime/program_pool.h" 33 | #include "surgescript/runtime/object_manager.h" 34 | #include "surgescript/runtime/tag_system.h" 35 | #include "surgescript/runtime/vm_time.h" 36 | #include "surgescript/runtime/heap.h" 37 | #include "surgescript/runtime/stack.h" 38 | #include "surgescript/runtime/variable.h" 39 | #include "surgescript/compiler/parser.h" 40 | #include "surgescript/util/transform.h" 41 | #include "surgescript/util/ssarray.h" 42 | #include "surgescript/util/util.h" 43 | #include "surgescript/util/version.h" 44 | 45 | #ifdef __cplusplus 46 | } 47 | #endif 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /src/surgescript/compiler/lexer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * compiler/lexer.h 19 | * SurgeScript compiler: lexical analyzer 20 | */ 21 | 22 | #ifndef _SURGESCRIPT_COMPILER_LEXER_H 23 | #define _SURGESCRIPT_COMPILER_LEXER_H 24 | 25 | #include 26 | 27 | typedef struct surgescript_lexer_t surgescript_lexer_t; 28 | struct surgescript_token_t; 29 | 30 | surgescript_lexer_t* surgescript_lexer_create(); 31 | surgescript_lexer_t* surgescript_lexer_destroy(surgescript_lexer_t* lexer); 32 | 33 | void surgescript_lexer_set(surgescript_lexer_t* lexer, const char* code); /* sets the code to be read */ 34 | struct surgescript_token_t* surgescript_lexer_scan(surgescript_lexer_t* lexer); /* scans the next token */ 35 | bool surgescript_lexer_unscan(surgescript_lexer_t* lexer, struct surgescript_token_t* token); /* puts a token back into the lexer */ 36 | 37 | #endif -------------------------------------------------------------------------------- /src/surgescript/compiler/nodecontext.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * compiler/nodecontext.h 19 | * SurgeScript compiler: node context utility (for the parser) 20 | */ 21 | 22 | #ifndef _SURGESCRIPT_COMPILER_NODECONTEXT_H 23 | #define _SURGESCRIPT_COMPILER_NODECONTEXT_H 24 | 25 | #include "../runtime/program.h" 26 | 27 | struct surgescript_symtable_t; 28 | 29 | /* node context */ 30 | typedef struct surgescript_nodecontext_t 31 | { 32 | const char* source_file; 33 | const char* object_name; 34 | const char* program_name; /* may be NULL */ 35 | struct surgescript_symtable_t* symtable; 36 | surgescript_program_t* program; 37 | surgescript_program_label_t loop_continue; /* continue statement helper; inner-most loop */ 38 | surgescript_program_label_t loop_break; /* break statement helper; inner-most loop or switch statement */ 39 | } surgescript_nodecontext_t; 40 | 41 | /* node context constructor */ 42 | static inline surgescript_nodecontext_t nodecontext(const char* source_file, const char* object_name, const char* program_name, struct surgescript_symtable_t* symbol_table, surgescript_program_t* program) 43 | { 44 | surgescript_nodecontext_t ctx = { source_file, object_name, program_name, symbol_table, program, SURGESCRIPT_PROGRAM_UNDEFINED_LABEL, SURGESCRIPT_PROGRAM_UNDEFINED_LABEL }; 45 | return ctx; 46 | } 47 | 48 | #endif -------------------------------------------------------------------------------- /src/surgescript/compiler/symtable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * runtime/symtable.h 19 | * SurgeScript Compiler: symbol table 20 | */ 21 | 22 | #ifndef _SURGESCRIPT_COMPILER_SYMTABLE_H 23 | #define _SURGESCRIPT_COMPILER_SYMTABLE_H 24 | 25 | #include 26 | #include "../runtime/heap.h" 27 | #include "../runtime/stack.h" 28 | 29 | typedef struct surgescript_symtable_t surgescript_symtable_t; 30 | struct surgescript_program_t; 31 | 32 | /* create & destroy a symbol table */ 33 | surgescript_symtable_t* surgescript_symtable_create(surgescript_symtable_t* parent); /* parent symbolizes the parent scope and may be NULL */ 34 | surgescript_symtable_t* surgescript_symtable_destroy(surgescript_symtable_t* symtable); 35 | 36 | /* put a new symbol on the table */ 37 | void surgescript_symtable_put_heap_symbol(surgescript_symtable_t* symtable, const char* symbol, surgescript_heapptr_t address); 38 | void surgescript_symtable_put_stack_symbol(surgescript_symtable_t* symtable, const char* symbol, surgescript_stackptr_t address); 39 | void surgescript_symtable_put_accessor_symbol(surgescript_symtable_t* symtable, const char* symbol); 40 | void surgescript_symtable_put_plugin_symbol(surgescript_symtable_t* symtable, const char* path, const char* filename); 41 | void surgescript_symtable_put_static_symbol(surgescript_symtable_t* symtable, const char* symbol); 42 | 43 | /* emit surgescript program code so that t[k] is written to the address of the symbol */ 44 | void surgescript_symtable_emit_write(surgescript_symtable_t* symtable, const char* symbol, struct surgescript_program_t* program, unsigned k); 45 | 46 | /* emit surgescript program code so that the content stored by the symbol is read to t[k] */ 47 | void surgescript_symtable_emit_read(surgescript_symtable_t* symtable, const char* symbol, struct surgescript_program_t* program, unsigned k); 48 | 49 | /* does the table have a certain symbol? */ 50 | bool surgescript_symtable_has_symbol(surgescript_symtable_t* symtable, const char* symbol); 51 | bool surgescript_symtable_has_local_symbol(surgescript_symtable_t* symtable, const char* symbol); 52 | 53 | /* count the number of symbols */ 54 | int surgescript_symtable_local_count(surgescript_symtable_t* symtable); /* not including parents */ 55 | int surgescript_symtable_count(surgescript_symtable_t* symtable); /* including parents */ 56 | 57 | /* does this table have a parent? */ 58 | bool surgescript_symtable_has_parent(surgescript_symtable_t* symtable); 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /src/surgescript/compiler/token.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * compiler/token.c 19 | * SurgeScript compiler: tokens 20 | */ 21 | 22 | #include "token.h" 23 | #include "../util/util.h" 24 | 25 | /* what's a token? */ 26 | struct surgescript_token_t 27 | { 28 | surgescript_tokentype_t type; 29 | char* lexeme; 30 | int linenumber; 31 | const void* data; 32 | }; 33 | 34 | /* the names of the tokens */ 35 | static const char* token_name[] = { 36 | #define TOKEN_NAME(x, y) y, 37 | SURGESCRIPT_TOKEN_TYPES(TOKEN_NAME) 38 | }; 39 | 40 | /* 41 | * surgescript_token_create() 42 | * Creates a new token, given a type and a lexeme (plus user-defined data) 43 | */ 44 | surgescript_token_t* surgescript_token_create(surgescript_tokentype_t type, const char* lexeme, int linenumber, const void* data) 45 | { 46 | surgescript_token_t* token = ssmalloc(sizeof *token); 47 | token->type = type; 48 | token->lexeme = ssstrdup(lexeme); 49 | token->linenumber = linenumber; 50 | token->data = data; 51 | return token; 52 | } 53 | 54 | /* 55 | * surgescript_token_destroy() 56 | * Destroys an existing token 57 | */ 58 | surgescript_token_t* surgescript_token_destroy(surgescript_token_t* token) 59 | { 60 | ssfree(token->lexeme); 61 | return ssfree(token); 62 | } 63 | 64 | /* 65 | * surgescript_token_type() 66 | * What's the type of the token? 67 | */ 68 | surgescript_tokentype_t surgescript_token_type(const surgescript_token_t* token) 69 | { 70 | return token ? token->type : SSTOK_UNKNOWN; 71 | } 72 | 73 | /* 74 | * surgescript_token_lexeme() 75 | * The lexeme (data) of the token 76 | */ 77 | const char* surgescript_token_lexeme(const surgescript_token_t* token) 78 | { 79 | return token ? token->lexeme : ""; 80 | } 81 | 82 | /* 83 | * surgescript_token_linenumber() 84 | * The number of the line in which this token has appeared 85 | */ 86 | int surgescript_token_linenumber(const surgescript_token_t* token) 87 | { 88 | return token ? token->linenumber : 0; 89 | } 90 | 91 | /* 92 | * surgescript_token_data() 93 | * User-defined token data 94 | */ 95 | const void* surgescript_token_data(const surgescript_token_t* token) 96 | { 97 | return token ? token->data : NULL; 98 | } 99 | 100 | 101 | /* 102 | * surgescript_tokentype_name() 103 | * The name of a token type 104 | */ 105 | const char* surgescript_tokentype_name(surgescript_tokentype_t type) 106 | { 107 | return token_name[type]; 108 | } 109 | 110 | 111 | /* 112 | * surgescript_token_clone() 113 | * Clones a token 114 | */ 115 | surgescript_token_t* surgescript_token_clone(surgescript_token_t* token) 116 | { 117 | surgescript_token_t* clone = ssmalloc(sizeof *clone); 118 | clone->type = token->type; 119 | clone->lexeme = ssstrdup(token->lexeme); 120 | clone->linenumber = token->linenumber; 121 | clone->data = token->data; 122 | return clone; 123 | } -------------------------------------------------------------------------------- /src/surgescript/misc/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alemart/surgescript/21a9c0696d592b7cc21e07db828fb93a12c95a7e/src/surgescript/misc/icon.png -------------------------------------------------------------------------------- /src/surgescript/misc/iconwin.rc: -------------------------------------------------------------------------------- 1 | SURGESCRIPT_ICON ICON "src/surgescript/misc/surgescript.ico" -------------------------------------------------------------------------------- /src/surgescript/misc/info.c.in: -------------------------------------------------------------------------------- 1 | /* SurgeScript info */ 2 | #include "../util/version.h" 3 | 4 | #cmakedefine PROJECT_YEARS "@PROJECT_YEARS@" 5 | #if !defined(PROJECT_YEARS) 6 | #error Undefined PROJECT_YEARS 7 | #endif 8 | 9 | const char SURGESCRIPT_AUTHOR[] = "Alexandre Martins"; 10 | const char SURGESCRIPT_WEBSITE[] = "https://github.com/alemart/surgescript"; 11 | const char SURGESCRIPT_VERSION[] = SURGESCRIPT_VERSION_STR; 12 | const char SURGESCRIPT_YEARS[] = PROJECT_YEARS; 13 | -------------------------------------------------------------------------------- /src/surgescript/misc/pack-windows.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This utility packs the Windows build of SurgeScript 3 | 4 | UNIX2DOS="todos" #"unix2dos" 5 | SOURCE_FOLDER="../../.." 6 | BUILD_FOLDER="$SOURCE_FOLDER/build" 7 | OUTPUT_FOLDER="/tmp" 8 | 9 | # File surgescript.exe must be present before packaging 10 | if [ ! -f "$BUILD_FOLDER/surgescript.exe" ]; then 11 | echo "File surgescript.exe not found" 12 | exit 1 13 | fi 14 | 15 | # Extract the SurgeScript version 16 | VERSION=$(wine "$BUILD_FOLDER/surgescript.exe" -v | tr -cd [:digit:][:punct:]) 17 | PACKAGE="surgescript-$VERSION-win" 18 | echo "Found SurgeScript version $VERSION." 19 | 20 | # Create a temporary folder for packaging 21 | TMP_FOLDER="/tmp/$PACKAGE" 22 | rm -rf "$TMP_FOLDER" 2>/dev/null 23 | mkdir -p "$TMP_FOLDER" 24 | 25 | # Write a README for Windows 26 | cat > "$TMP_FOLDER/README-Windows.txt" << EOF 27 | -------------------------------------------------- 28 | SurgeScript 29 | A scripting language for games 30 | Copyright (C) 2016-$(date +%Y) Alexandre Martins 31 | -------------------------------------------------- 32 | This is the Windows build of SurgeScript $VERSION. 33 | 34 | To test SurgeScript, run the surgescript executable via the Command Prompt. 35 | Pass the scripts you want to test via the command line, as in the examples: 36 | 37 | ** See the available options: ** 38 | C:\path\to\surgescript> surgescript 39 | 40 | ** Run a test script: ** 41 | C:\path\to\surgescript> surgescript examples\hello.ss 42 | 43 | ** Run another test script: ** 44 | C:\path\to\surgescript> surgescript examples\count_to_10.ss 45 | 46 | There are many example scripts to try out. Check the examples folder for 47 | more information. 48 | 49 | Visit the SurgeScript website at: https://github.com/alemart/surgescript/ 50 | EOF 51 | 52 | # Copy files 53 | for file in surgescript.exe libsurgescript-static.a libsurgescript.dll.a libsurgescript.dll surgescript.pc surgescript-static.pc; do 54 | echo "Copying $file..." 55 | cp "$BUILD_FOLDER/$file" "$TMP_FOLDER" 56 | done 57 | 58 | for file in LICENSE README.md CHANGES.md CMakeLists.txt mkdocs.yml; do 59 | echo "Copying $file..." 60 | cp "$SOURCE_FOLDER/$file" "$TMP_FOLDER" 61 | done 62 | 63 | for folder in examples src cmake; do 64 | echo "Copying $folder/ ..." 65 | cp -r "$SOURCE_FOLDER/$folder" "$TMP_FOLDER" 66 | done 67 | 68 | mv "$TMP_FOLDER/LICENSE" "$TMP_FOLDER/LICENSE.txt" 69 | 70 | # Converting newlines of all text files 71 | for f in `find "$TMP_FOLDER" -type f -exec grep -Iq . {} \; -print`; do 72 | ${UNIX2DOS} $f 73 | done 74 | 75 | # Generate the docs 76 | pushd "$SOURCE_FOLDER" 77 | mkdocs build 78 | popd 79 | 80 | # Copying the docs 81 | for folder in docs docs_html; do 82 | echo "Copying $folder/ ..." 83 | cp -r "$SOURCE_FOLDER/$folder" "$TMP_FOLDER" 84 | done 85 | 86 | # Create the .zip package 87 | pushd "$TMP_FOLDER" 88 | echo "Packaging..." 89 | zip -r "$OUTPUT_FOLDER/$PACKAGE.zip" ./* 90 | echo "Packaged to $OUTPUT_FOLDER/$PACKAGE.zip" 91 | popd 92 | #rm -rf "${TMP_FOLDER}" -------------------------------------------------------------------------------- /src/surgescript/misc/surgescript.appdata.xml.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.opensurge2d.SurgeScript 4 | SurgeScript 5 | Alexandre Martins 6 | alemartf_at_gmail.com 7 | Apache-2.0 8 | Apache-2.0 9 | A scripting language for games 10 | 11 |

SurgeScript is a scripting language for games. Use it to unleash your creativity and build your own amazing interactive content! It's such a joy to use SurgeScript! Its features include:

12 |
    13 |
  • The state-machine pattern: objects are state machines, making it easy to create in-game entities
  • 14 |
  • The composition approach: you may design complex objects and behaviors by means of composition
  • 15 |
  • The hierarchy system: objects have a parent and may have children, in a tree-like structure
  • 16 |
  • The game loop: it's defined implicitly
  • 17 |
  • Automatic garbage collection, object tagging and more!
  • 18 |
19 |

SurgeScript is meant to be used in games and in interactive applications. It's easy to integrate it into existing code, it's easy to extend, it features a C-like syntax, and it's free and open-source software.

20 |
21 | https://github.com/alemart/surgescript 22 | http://opensurge2d.org/contribute 23 | https://github.com/alemart/surgescript/issues 24 | 25 | Game 26 | Development 27 | 28 | @ICON_FILEPATH@ 29 | 30 | surgescript 31 | 32 |
33 | -------------------------------------------------------------------------------- /src/surgescript/misc/surgescript.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alemart/surgescript/21a9c0696d592b7cc21e07db828fb93a12c95a7e/src/surgescript/misc/surgescript.ico -------------------------------------------------------------------------------- /src/surgescript/misc/surgescript.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@CMAKE_INSTALL_PREFIX@ 2 | exec_prefix=${prefix} 3 | libdir=${exec_prefix}/lib@LIB_SUFFIX@ 4 | includedir=${prefix}/include 5 | version=@PROJECT_VERSION@ 6 | suffix=@LIB_LINKAGE@ 7 | 8 | Name: surgescript 9 | Description: A scripting language for games 10 | Version: ${version} 11 | Libs: -L${libdir} -lsurgescript${suffix} 12 | Libs.private: -lm 13 | Cflags: -I${includedir} 14 | -------------------------------------------------------------------------------- /src/surgescript/misc/surgescript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alemart/surgescript/21a9c0696d592b7cc21e07db828fb93a12c95a7e/src/surgescript/misc/surgescript.png -------------------------------------------------------------------------------- /src/surgescript/runtime/heap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * runtime/heap.h 19 | * SurgeScript heap 20 | */ 21 | 22 | #ifndef _SURGESCRIPT_RUNTIME_HEAP_H 23 | #define _SURGESCRIPT_RUNTIME_HEAP_H 24 | 25 | #include 26 | #include 27 | 28 | /* types */ 29 | typedef struct surgescript_heap_t surgescript_heap_t; 30 | struct surgescript_heap_t; 31 | typedef unsigned surgescript_heapptr_t; 32 | 33 | /* forward declarations */ 34 | struct surgescript_var_t; 35 | 36 | /* public methods */ 37 | surgescript_heap_t* surgescript_heap_create(); 38 | surgescript_heap_t* surgescript_heap_destroy(surgescript_heap_t* heap); 39 | surgescript_heapptr_t surgescript_heap_malloc(surgescript_heap_t* heap); 40 | surgescript_heapptr_t surgescript_heap_free(surgescript_heap_t* heap, surgescript_heapptr_t ptr); 41 | struct surgescript_var_t* surgescript_heap_at(const surgescript_heap_t* heap, surgescript_heapptr_t ptr); 42 | void surgescript_heap_scan_objects(surgescript_heap_t* heap, void* userdata, bool (*callback)(unsigned,void*)); 43 | bool surgescript_heap_scan_all(surgescript_heap_t* heap, void* userdata, bool (*callback)(struct surgescript_var_t*,surgescript_heapptr_t,void*)); 44 | size_t surgescript_heap_size(const surgescript_heap_t* heap); 45 | bool surgescript_heap_validaddress(const surgescript_heap_t* heap, surgescript_heapptr_t ptr); 46 | size_t surgescript_heap_memspent(const surgescript_heap_t* heap); 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/surgescript/runtime/managed_string.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * runtime/managed_string.h 19 | * Fast immutable strings 20 | */ 21 | 22 | #ifndef _SURGESCRIPT_RUNTIME_MANAGED_STRING_H 23 | #define _SURGESCRIPT_RUNTIME_MANAGED_STRING_H 24 | 25 | typedef struct surgescript_managedstring_t surgescript_managedstring_t; 26 | 27 | /* create & destroy */ 28 | surgescript_managedstring_t* surgescript_managedstring_create(const char* string); 29 | surgescript_managedstring_t* surgescript_managedstring_destroy(surgescript_managedstring_t* managed_string); 30 | surgescript_managedstring_t* surgescript_managedstring_clone(const surgescript_managedstring_t* managed_string); 31 | 32 | /* quickly read the string */ 33 | #define surgescript_managedstring_data(managed_string) (*((const char**)managed_string)) 34 | 35 | /* string pool */ 36 | void surgescript_managedstring_init_pool(); 37 | void surgescript_managedstring_release_pool(); 38 | 39 | #endif -------------------------------------------------------------------------------- /src/surgescript/runtime/program_pool.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * runtime/program_pool.h 19 | * SurgeScript program pool 20 | */ 21 | 22 | #ifndef _SURGESCRIPT_RUNTIME_PROGRAMPOOL_H 23 | #define _SURGESCRIPT_RUNTIME_PROGRAMPOOL_H 24 | 25 | #include 26 | 27 | /* types */ 28 | typedef struct surgescript_programpool_t surgescript_programpool_t; 29 | 30 | /* forward declarations */ 31 | struct surgescript_program_t; 32 | 33 | /* public methods */ 34 | surgescript_programpool_t* surgescript_programpool_create(); 35 | surgescript_programpool_t* surgescript_programpool_destroy(surgescript_programpool_t* pool); 36 | bool surgescript_programpool_put(surgescript_programpool_t* pool, const char* object_name, const char* program_name, struct surgescript_program_t* program); /* adds a program to an object */ 37 | struct surgescript_program_t* surgescript_programpool_get(surgescript_programpool_t* pool, const char* object_name, const char* program_name); /* may return NULL */ 38 | bool surgescript_programpool_exists(surgescript_programpool_t* pool, const char* object_name, const char* program_name); /* program exists? */ 39 | bool surgescript_programpool_shallowcheck(surgescript_programpool_t* pool, const char* object_name, const char* program_name); /* program exists? (shallow check) */ 40 | void surgescript_programpool_foreach(surgescript_programpool_t* pool, const char* object_name, void (*callback)(const char*)); /* for each program of object_name... */ 41 | void surgescript_programpool_foreach_ex(surgescript_programpool_t* pool, const char* object_name, void* data, void (*callback)(const char*, void*)); /* same as above with an added data parameter */ 42 | void surgescript_programpool_foreach_object(surgescript_programpool_t* pool, void (*callback)(const char*)); /* for each object named object_name... */ 43 | void surgescript_programpool_foreach_object_ex(surgescript_programpool_t* pool, void* data, void (*callback)(const char*, void*)); /* same as above with an added data parameter */ 44 | bool surgescript_programpool_replace(surgescript_programpool_t* pool, const char* object_name, const char* program_name, struct surgescript_program_t* program); /* replaces a program */ 45 | void surgescript_programpool_delete(surgescript_programpool_t* pool, const char* object_name, const char* program_name); /* deletes a programs from the specified object */ 46 | void surgescript_programpool_purge(surgescript_programpool_t* pool, const char* object_name); /* deletes all programs from the specified object */ 47 | bool surgescript_programpool_is_compiled(surgescript_programpool_t* pool, const char* object_name); /* is there any code for object_name? */ 48 | void surgescript_programpool_lock(surgescript_programpool_t* pool); /* locks the program pool, so that no (programs of) new objects can be added to it */ 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/surgescript/runtime/renv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * runtime/renv.c 19 | * SurgeScript runtime environment (used to execute surgescript programs) 20 | */ 21 | 22 | #include "renv.h" 23 | #include "variable.h" 24 | #include "heap.h" 25 | #include "stack.h" 26 | #include "object.h" 27 | #include "program_pool.h" 28 | #include "object_manager.h" 29 | #include "../util/util.h" 30 | 31 | /* how many temporary vars does a runtime environment have? */ 32 | static const int MAX_TMPVARS = 4; /* used for calculations */ 33 | static surgescript_renv_t* full_destructor(surgescript_renv_t* runtime_environment); 34 | static surgescript_renv_t* partial_destructor(surgescript_renv_t* runtime_environment); 35 | 36 | 37 | /* 38 | * surgescript_renv_create() 39 | * Creates a runtime environment 40 | */ 41 | surgescript_renv_t* surgescript_renv_create(surgescript_object_t* owner, surgescript_stack_t* stack, surgescript_heap_t* heap, surgescript_programpool_t* program_pool, surgescript_objectmanager_t* object_manager, surgescript_var_t** tmp) 42 | { 43 | surgescript_renv_t* runtime_environment = ssmalloc(sizeof *runtime_environment); 44 | 45 | runtime_environment->owner = owner; 46 | runtime_environment->stack = stack; 47 | runtime_environment->heap = heap; 48 | runtime_environment->program_pool = program_pool; 49 | runtime_environment->object_manager = object_manager; 50 | runtime_environment->parent = NULL; 51 | 52 | if(!tmp) { 53 | int i; 54 | runtime_environment->tmp = ssmalloc(MAX_TMPVARS * sizeof *(runtime_environment->tmp)); 55 | for(i = 0; i < MAX_TMPVARS; i++) 56 | runtime_environment->tmp[i] = surgescript_var_create(); 57 | runtime_environment->_destructor = full_destructor; 58 | } 59 | else { 60 | runtime_environment->tmp = tmp; 61 | surgescript_var_set_null(runtime_environment->tmp[3]); 62 | runtime_environment->_destructor = partial_destructor; 63 | } 64 | 65 | return runtime_environment; 66 | } 67 | 68 | /* 69 | * surgescript_renv_destroy() 70 | * Destroys a runtime environment 71 | */ 72 | surgescript_renv_t* surgescript_renv_destroy(surgescript_renv_t* runtime_environment) 73 | { 74 | return runtime_environment->_destructor(runtime_environment); 75 | } 76 | 77 | 78 | /* privates */ 79 | 80 | surgescript_renv_t* full_destructor(surgescript_renv_t* runtime_environment) 81 | { 82 | for(int i = 0; i < MAX_TMPVARS; i++) 83 | surgescript_var_destroy(runtime_environment->tmp[i]); 84 | ssfree(runtime_environment->tmp); 85 | return ssfree(runtime_environment); 86 | } 87 | 88 | surgescript_renv_t* partial_destructor(surgescript_renv_t* runtime_environment) 89 | { 90 | return ssfree(runtime_environment); 91 | } -------------------------------------------------------------------------------- /src/surgescript/runtime/renv.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * runtime/renv.h 19 | * SurgeScript runtime environment (used to execute surgescript programs) 20 | */ 21 | 22 | #ifndef _SURGESCRIPT_RUNTIME_RENV_H 23 | #define _SURGESCRIPT_RUNTIME_RENV_H 24 | 25 | /* types */ 26 | struct surgescript_object_t; 27 | struct surgescript_stack_t; 28 | struct surgescript_heap_t; 29 | struct surgescript_programpool_t; 30 | struct surgescript_objectmanager_t; 31 | 32 | /* a program, to be run, needs a runtime environment (renv) */ 33 | /* this is composed by an owner object, plus heap-stack-etc, plus some unique temporary variables */ 34 | /* --- instead of messing with this directly, use the functions below --- */ 35 | typedef struct surgescript_renv_t 36 | { 37 | struct surgescript_object_t* owner; /* pointer to the object the program refers to (i.e., the "owner") */ 38 | struct surgescript_stack_t* stack; /* pointer to the stack */ 39 | struct surgescript_heap_t* heap; /* pointer to the heap */ 40 | struct surgescript_programpool_t* program_pool; /* pointer to the program pool */ 41 | struct surgescript_objectmanager_t* object_manager; /* pointer to the object manager */ 42 | struct surgescript_var_t** tmp; /* temporary variables */ 43 | struct surgescript_renv_t* (*_destructor)(struct surgescript_renv_t*); /* internal destructor */ 44 | const struct surgescript_renv_t* parent; /* runtime environment of the caller, if any (possibly NULL) */ 45 | } surgescript_renv_t ; 46 | 47 | /* creates a new renv (the tmp parameter may be NULL) */ 48 | surgescript_renv_t* surgescript_renv_create(struct surgescript_object_t* owner, struct surgescript_stack_t* stack, struct surgescript_heap_t* heap, struct surgescript_programpool_t* program_pool, struct surgescript_objectmanager_t* object_manager, struct surgescript_var_t** tmp); 49 | 50 | /* destroys a renv */ 51 | surgescript_renv_t* surgescript_renv_destroy(surgescript_renv_t* runtime_environment); 52 | 53 | /* getters */ 54 | #define surgescript_renv_owner(renv) ((renv)->owner) 55 | #define surgescript_renv_stack(renv) ((renv)->stack) 56 | #define surgescript_renv_heap(renv) ((renv)->heap) 57 | #define surgescript_renv_programpool(renv) ((renv)->program_pool) 58 | #define surgescript_renv_objectmanager(renv) ((renv)->object_manager) 59 | #define surgescript_renv_tmp(renv) ((renv)->tmp) 60 | #define surgescript_renv_caller(renv) ((renv)->parent != NULL ? surgescript_object_handle((renv)->parent->owner) : surgescript_objectmanager_null((renv)->object_manager)) 61 | 62 | #endif -------------------------------------------------------------------------------- /src/surgescript/runtime/sslib/application.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * runtime/sslib/application.c 19 | * SurgeScript standard library: routines for the Application object 20 | */ 21 | 22 | #include 23 | #include "../vm.h" 24 | #include "../heap.h" 25 | #include "../object.h" 26 | #include "../object_manager.h" 27 | #include "../../util/util.h" 28 | 29 | /* private stuff */ 30 | static surgescript_var_t* fun_exit(surgescript_object_t* object, const surgescript_var_t** param, int num_params); 31 | static surgescript_var_t* fun_crash(surgescript_object_t* object, const surgescript_var_t** param, int num_params); 32 | static surgescript_var_t* fun_destroy(surgescript_object_t* object, const surgescript_var_t** param, int num_params); 33 | static surgescript_var_t* fun_getargs(surgescript_object_t* object, const surgescript_var_t** param, int num_params); 34 | 35 | 36 | /* 37 | * surgescript_sslib_register_application() 38 | * Register methods 39 | */ 40 | void surgescript_sslib_register_application(surgescript_vm_t* vm) 41 | { 42 | surgescript_vm_bind(vm, "Application", "exit", fun_exit, 0); 43 | surgescript_vm_bind(vm, "Application", "crash", fun_crash, 1); 44 | surgescript_vm_bind(vm, "Application", "destroy", fun_destroy, 0); /* overloads Object's destroy() */ 45 | surgescript_vm_bind(vm, "Application", "get_args", fun_getargs, 0); 46 | } 47 | 48 | 49 | 50 | /* my functions */ 51 | 52 | /* exits the app */ 53 | surgescript_var_t* fun_exit(surgescript_object_t* object, const surgescript_var_t** param, int num_params) 54 | { 55 | /* this will destroy the root object and stop the VM */ 56 | surgescript_objectmanager_t* manager = surgescript_object_manager(object); 57 | surgescript_objecthandle_t root_handle = surgescript_objectmanager_root(manager); 58 | surgescript_object_t* root = surgescript_objectmanager_get(manager, root_handle); 59 | surgescript_object_call_function(root, "exit", NULL, 0, NULL); 60 | surgescript_object_kill(object); 61 | return NULL; 62 | } 63 | 64 | /* destroys the app */ 65 | surgescript_var_t* fun_destroy(surgescript_object_t* object, const surgescript_var_t** param, int num_params) 66 | { 67 | /* this is the same as exiting the app */ 68 | return fun_exit(object, param, num_params); 69 | } 70 | 71 | /* crashes the app with a message */ 72 | surgescript_var_t* fun_crash(surgescript_object_t* object, const surgescript_var_t** param, int num_params) 73 | { 74 | const surgescript_objectmanager_t* manager = surgescript_object_manager(object); 75 | char* text = surgescript_var_get_string(param[0], manager); 76 | ssfatal("Script Error: %s", text); /* change ssfatal to something else? */ 77 | ssfree(text); 78 | return fun_exit(object, NULL, 0); 79 | } 80 | 81 | /* command line arguments */ 82 | surgescript_var_t* fun_getargs(surgescript_object_t* object, const surgescript_var_t** param, int num_params) 83 | { 84 | surgescript_objectmanager_t* manager = surgescript_object_manager(object); 85 | surgescript_objecthandle_t this_handle = surgescript_object_handle(object); 86 | surgescript_objecthandle_t args_handle = surgescript_object_child(object, "Arguments"); 87 | surgescript_objecthandle_t null_handle = surgescript_objectmanager_null(manager); 88 | 89 | /* lazy spawn */ 90 | if(args_handle == null_handle) 91 | args_handle = surgescript_objectmanager_spawn(manager, this_handle, "Arguments", NULL); 92 | 93 | /* done! */ 94 | return surgescript_var_set_objecthandle(surgescript_var_create(), args_handle); 95 | } -------------------------------------------------------------------------------- /src/surgescript/runtime/sslib/sslib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * runtime/sslib/sslib.h 19 | * SurgeScript Standard Library 20 | */ 21 | 22 | #ifndef _SURGESCRIPT_RUNTIME_STDLIB_STDLIB_H 23 | #define _SURGESCRIPT_RUNTIME_STDLIB_STDLIB_H 24 | 25 | /* forward declarations */ 26 | struct surgescript_vm_t; 27 | 28 | /* Register common methods to all objects */ 29 | void surgescript_sslib_register_object(struct surgescript_vm_t* vm); 30 | void surgescript_sslib_register_array(struct surgescript_vm_t* vm); 31 | void surgescript_sslib_register_arguments(struct surgescript_vm_t* vm); 32 | void surgescript_sslib_register_application(struct surgescript_vm_t* vm); 33 | void surgescript_sslib_register_system(struct surgescript_vm_t* vm); 34 | void surgescript_sslib_register_boolean(struct surgescript_vm_t* vm); 35 | void surgescript_sslib_register_number(struct surgescript_vm_t* vm); 36 | void surgescript_sslib_register_string(struct surgescript_vm_t* vm); 37 | void surgescript_sslib_register_console(struct surgescript_vm_t* vm); 38 | void surgescript_sslib_register_math(struct surgescript_vm_t* vm); 39 | void surgescript_sslib_register_dictionary(struct surgescript_vm_t* vm); 40 | void surgescript_sslib_register_time(struct surgescript_vm_t* vm); 41 | void surgescript_sslib_register_date(struct surgescript_vm_t* vm); 42 | void surgescript_sslib_register_temp(struct surgescript_vm_t* vm); 43 | void surgescript_sslib_register_gc(struct surgescript_vm_t* vm); 44 | void surgescript_sslib_register_tagsystem(struct surgescript_vm_t* vm); 45 | void surgescript_sslib_register_surgescript(struct surgescript_vm_t* vm); 46 | void surgescript_sslib_register_plugin(struct surgescript_vm_t* vm); 47 | 48 | #endif -------------------------------------------------------------------------------- /src/surgescript/runtime/sslib/surgescript.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * runtime/sslib/surgescript.c 19 | * SurgeScript standard library: SurgeScript object 20 | */ 21 | 22 | #include "../vm.h" 23 | #include "../object.h" 24 | #include "../../util/util.h" 25 | 26 | /* private stuff */ 27 | static surgescript_var_t* fun_destroy(surgescript_object_t* object, const surgescript_var_t** param, int num_params); 28 | static surgescript_var_t* fun_spawn(surgescript_object_t* object, const surgescript_var_t** param, int num_params); 29 | static surgescript_var_t* fun_getversion(surgescript_object_t* object, const surgescript_var_t** param, int num_params); 30 | static surgescript_var_t* fun_main(surgescript_object_t* object, const surgescript_var_t** param, int num_params); 31 | 32 | /* 33 | * surgescript_sslib_register_surgescript() 34 | * Register methods 35 | */ 36 | void surgescript_sslib_register_surgescript(surgescript_vm_t* vm) 37 | { 38 | surgescript_vm_bind(vm, "SurgeScript", "destroy", fun_destroy, 0); 39 | surgescript_vm_bind(vm, "SurgeScript", "spawn", fun_spawn, 1); 40 | surgescript_vm_bind(vm, "SurgeScript", "get_version", fun_getversion, 0); 41 | surgescript_vm_bind(vm, "SurgeScript", "state:main", fun_main, 0); 42 | } 43 | 44 | 45 | 46 | /* my functions */ 47 | 48 | /* destroy function */ 49 | surgescript_var_t* fun_destroy(surgescript_object_t* object, const surgescript_var_t** param, int num_params) 50 | { 51 | /* do nothing */ 52 | return NULL; 53 | } 54 | 55 | /* spawn function */ 56 | surgescript_var_t* fun_spawn(surgescript_object_t* object, const surgescript_var_t** param, int num_params) 57 | { 58 | /* do nothing; you can't spawn children on this object */ 59 | return NULL; 60 | } 61 | 62 | /* main state */ 63 | surgescript_var_t* fun_main(surgescript_object_t* object, const surgescript_var_t** param, int num_params) 64 | { 65 | surgescript_object_set_active(object, false); /* we don't need to spend time updating this object */ 66 | return NULL; 67 | } 68 | 69 | /* SurgeScript version */ 70 | surgescript_var_t* fun_getversion(surgescript_object_t* object, const surgescript_var_t** param, int num_params) 71 | { 72 | return surgescript_var_set_string(surgescript_var_create(), surgescript_util_version()); 73 | } -------------------------------------------------------------------------------- /src/surgescript/runtime/sslib/temp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * runtime/sslib/temp.c 19 | * SurgeScript standard library: Temporary Storage Area (holds arrays, dicts, etc.) 20 | */ 21 | 22 | #include 23 | #include "../vm.h" 24 | #include "../object.h" 25 | 26 | /* private stuff */ 27 | static surgescript_var_t* fun_main(surgescript_object_t* object, const surgescript_var_t** param, int num_params); 28 | static surgescript_var_t* fun_destroy(surgescript_object_t* object, const surgescript_var_t** param, int num_params); 29 | 30 | /* 31 | * surgescript_sslib_register_temp() 32 | * Register methods 33 | */ 34 | void surgescript_sslib_register_temp(surgescript_vm_t* vm) 35 | { 36 | surgescript_vm_bind(vm, "__Temp", "state:main", fun_main, 0); 37 | surgescript_vm_bind(vm, "__Temp", "destroy", fun_destroy, 0); 38 | } 39 | 40 | 41 | 42 | /* my functions */ 43 | 44 | /* main state */ 45 | surgescript_var_t* fun_main(surgescript_object_t* object, const surgescript_var_t** param, int num_params) 46 | { 47 | /* we reduce the time of tree traversal by deactivating __Temp. As a consequence, 48 | descendants of __Temp (e.g., Arrays & Dictionaries spawned as its children) 49 | won't be updated / traversed. __Temp may hold hundreds or thousands of objects, 50 | and so the benefit of this optimization outweights its cost (as I see it at the 51 | time of this writing). */ 52 | surgescript_object_set_active(object, false); 53 | return NULL; 54 | } 55 | 56 | /* destroy */ 57 | surgescript_var_t* fun_destroy(surgescript_object_t* object, const surgescript_var_t** param, int num_params) 58 | { 59 | return NULL; 60 | } 61 | -------------------------------------------------------------------------------- /src/surgescript/runtime/stack.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * runtime/stack.h 19 | * SurgeScript stack 20 | */ 21 | 22 | #ifndef _SURGESCRIPT_RUNTIME_STACK_H 23 | #define _SURGESCRIPT_RUNTIME_STACK_H 24 | 25 | #include 26 | #include 27 | 28 | /* types */ 29 | typedef struct surgescript_stack_t surgescript_stack_t; 30 | struct surgescript_stack_t; 31 | typedef int surgescript_stackptr_t; 32 | 33 | /* forward declarations */ 34 | struct surgescript_var_t; 35 | 36 | /* public methods */ 37 | surgescript_stack_t* surgescript_stack_create(); 38 | surgescript_stack_t* surgescript_stack_destroy(surgescript_stack_t* stack); 39 | void surgescript_stack_push(surgescript_stack_t* stack, struct surgescript_var_t* data); /* pushes data to the stack */ 40 | void surgescript_stack_pop(surgescript_stack_t* stack); /* pops and deallocates a var from the stack */ 41 | void surgescript_stack_pushenv(surgescript_stack_t* stack); /* pushes an environment */ 42 | void surgescript_stack_popenv(surgescript_stack_t* stack); /* pops an environment */ 43 | void surgescript_stack_pushn(surgescript_stack_t* stack, size_t n); /* pushes n empty variables to the stack */ 44 | void surgescript_stack_popn(surgescript_stack_t* stack, size_t n); /* pops n variables from the stack */ 45 | const struct surgescript_var_t* surgescript_stack_top(const surgescript_stack_t* stack); /* gets the topmost element */ 46 | const struct surgescript_var_t* surgescript_stack_peek(const surgescript_stack_t* stack, surgescript_stackptr_t offset); /* reads stack[base + offset] */ 47 | void surgescript_stack_poke(surgescript_stack_t* stack, surgescript_stackptr_t offset, const struct surgescript_var_t* data); /* writes data on stack[base + offset] */ 48 | int surgescript_stack_empty(const surgescript_stack_t* stack); /* is the stack empty? */ 49 | void surgescript_stack_scan_objects(surgescript_stack_t* stack, void* userdata, bool (*callback)(unsigned,void*)); 50 | size_t surgescript_stack_size(const surgescript_stack_t* stack); /* stack size */ 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/surgescript/runtime/tag_system.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * runtime/tag_system.h 19 | * SurgeScript Tag System 20 | */ 21 | 22 | #ifndef _SURGESCRIPT_RUNTIME_TAG_SYSTEM_H 23 | #define _SURGESCRIPT_RUNTIME_TAG_SYSTEM_H 24 | 25 | typedef struct surgescript_tagsystem_t surgescript_tagsystem_t; 26 | typedef struct surgescript_boundtagsystem_t surgescript_boundtagsystem_t; 27 | 28 | /* tag system */ 29 | surgescript_tagsystem_t* surgescript_tagsystem_create(); 30 | surgescript_tagsystem_t* surgescript_tagsystem_destroy(surgescript_tagsystem_t* tag_system); 31 | 32 | /* add & check tags */ 33 | void surgescript_tagsystem_add_tag(surgescript_tagsystem_t* tag_system, const char* object_name, const char* tag_name); /* add tag_name to a certain class of objects */ 34 | bool surgescript_tagsystem_has_tag(const surgescript_tagsystem_t* tag_system, const char* object_name, const char* tag_name); /* is object_name tagged tag_name? */ 35 | 36 | /* iteration */ 37 | void surgescript_tagsystem_foreach_tag(const surgescript_tagsystem_t* tag_system, void* data, void (*callback)(const char*,void*)); /* for each registered tag, calls callback(tag_name, data) */ 38 | void surgescript_tagsystem_foreach_tagged_object(const surgescript_tagsystem_t* tag_system, const char* tag_name, void* data, void (*callback)(const char*,void*)); /* for each object tagged tag_name, calls callback(object_name, data) */ 39 | void surgescript_tagsystem_foreach_tag_of_object(const surgescript_tagsystem_t* tag_system, const char* object_name, void* data, void (*callback)(const char*,void*)); /* for each tag of object named object_name, calls callback(tag_name, data) */ 40 | 41 | /* bound tag system */ 42 | const surgescript_boundtagsystem_t* surgescript_tagsystem_bind(surgescript_tagsystem_t* tag_system, const char* object_name); /* get a bound tag system bound to object_name */ 43 | bool surgescript_boundtagsystem_has_tag(const surgescript_boundtagsystem_t* bound_tag_system, const char* tag_name); /* super quick tag test */ 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/surgescript/runtime/vm_time.c: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * runtime/vm_time.c 19 | * SurgeScript Virtual Machine Time - this is used to count time 20 | */ 21 | 22 | #include "vm_time.h" 23 | #include "../util/util.h" 24 | 25 | /* VM time */ 26 | struct surgescript_vmtime_t { 27 | uint64_t time; /* in ms */ 28 | uint64_t ticks_at_last_update; 29 | bool is_paused; 30 | }; 31 | 32 | /* 33 | * surgescript_vmtime_create() 34 | * Create a VM time object 35 | */ 36 | surgescript_vmtime_t* surgescript_vmtime_create() 37 | { 38 | surgescript_vmtime_t* vmtime = ssmalloc(sizeof *vmtime); 39 | 40 | vmtime->time = 0; 41 | vmtime->ticks_at_last_update = surgescript_util_gettickcount(); 42 | vmtime->is_paused = false; 43 | 44 | return vmtime; 45 | } 46 | 47 | /* 48 | * surgescript_vmtime_destroy() 49 | * Destroy a VM time object 50 | */ 51 | surgescript_vmtime_t* surgescript_vmtime_destroy(surgescript_vmtime_t* vmtime) 52 | { 53 | ssfree(vmtime); 54 | return NULL; 55 | } 56 | 57 | /* 58 | * surgescript_vmtime_update() 59 | * Update the VM time object 60 | */ 61 | void surgescript_vmtime_update(surgescript_vmtime_t* vmtime) 62 | { 63 | uint64_t now = surgescript_util_gettickcount(); 64 | uint64_t delta_time = now > vmtime->ticks_at_last_update ? now - vmtime->ticks_at_last_update : 0; 65 | vmtime->time += vmtime->is_paused ? 0 : delta_time; 66 | vmtime->ticks_at_last_update = now; 67 | } 68 | 69 | /* 70 | * surgescript_vmtime_pause() 71 | * Pause the VM time 72 | */ 73 | void surgescript_vmtime_pause(surgescript_vmtime_t* vmtime) 74 | { 75 | /* nothing to do */ 76 | if(vmtime->is_paused) 77 | return; 78 | 79 | /* pause the time */ 80 | vmtime->is_paused = true; 81 | } 82 | 83 | /* 84 | * surgescript_vmtime_resume() 85 | * Resume the VM time 86 | */ 87 | void surgescript_vmtime_resume(surgescript_vmtime_t* vmtime) 88 | { 89 | /* nothing to do */ 90 | if(!vmtime->is_paused) 91 | return; 92 | 93 | /* resume the time */ 94 | vmtime->ticks_at_last_update = surgescript_util_gettickcount(); 95 | vmtime->is_paused = false; 96 | } 97 | 98 | /* 99 | * surgescript_vmtime_time() 100 | * Get the time, in milliseconds, at the beginning of the current update cycle 101 | */ 102 | uint64_t surgescript_vmtime_time(const surgescript_vmtime_t* vmtime) 103 | { 104 | return vmtime->time; 105 | } 106 | 107 | /* 108 | * surgescript_vmtime_is_paused() 109 | * Is the VM time paused? 110 | */ 111 | bool surgescript_vmtime_is_paused(const surgescript_vmtime_t* vmtime) 112 | { 113 | return vmtime->is_paused; 114 | } -------------------------------------------------------------------------------- /src/surgescript/runtime/vm_time.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * runtime/vm_time.h 19 | * SurgeScript Virtual Machine Time - this is used to count time 20 | */ 21 | 22 | #ifndef _SURGESCRIPT_RUNTIME_VM_TIME_H 23 | #define _SURGESCRIPT_RUNTIME_VM_TIME_H 24 | 25 | #include 26 | #include 27 | 28 | typedef struct surgescript_vmtime_t surgescript_vmtime_t; 29 | 30 | surgescript_vmtime_t* surgescript_vmtime_create(); /* create a VM time object */ 31 | surgescript_vmtime_t* surgescript_vmtime_destroy(surgescript_vmtime_t* vmtime); /* destroy a VM time object */ 32 | 33 | void surgescript_vmtime_update(surgescript_vmtime_t* vmtime); /* update the VM time object */ 34 | void surgescript_vmtime_pause(surgescript_vmtime_t* vmtime); /* pause the VM time */ 35 | void surgescript_vmtime_resume(surgescript_vmtime_t* vmtime); /* resume the VM time */ 36 | 37 | uint64_t surgescript_vmtime_time(const surgescript_vmtime_t* vmtime); /* the time at the beginning of the current update cycle */ 38 | bool surgescript_vmtime_is_paused(const surgescript_vmtime_t* vmtime); /* is the VM time paused? */ 39 | 40 | #endif -------------------------------------------------------------------------------- /src/surgescript/third_party/gettimeofday.h: -------------------------------------------------------------------------------- 1 | /* 2 | MIT License 3 | Copyright (c) 2019 win32ports 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 | SOFTWARE. 19 | */ 20 | 21 | #ifndef GETTIMEOFDAY_H 22 | #define GETTIMEOFDAY_H 23 | 24 | #ifndef _WIN32 25 | #include 26 | #else 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif /* __cplusplus */ 31 | 32 | #if !defined(_WINSOCK2API_) && !defined(_WINSOCKAPI_) 33 | #include /* timeval */ 34 | #endif /* !defined(_WINSOCK2API_) && !defined(_WINSOCKAPI_) */ 35 | 36 | #include 37 | 38 | #ifndef _TIMEZONE_DEFINED 39 | struct timezone 40 | { 41 | int tz_minuteswest; 42 | int tz_dsttime; 43 | }; 44 | #endif 45 | 46 | static int gettimeofday(struct timeval *tp, struct timezone *tzp) 47 | { 48 | typedef void (__stdcall * pfnGetSystemTimePreciseAsFileTime)(LPFILETIME lpSystemTimeAsFileTime); 49 | HMODULE hKernel32 = NULL; 50 | pfnGetSystemTimePreciseAsFileTime fnGetSystemTimePreciseAsFileTime = NULL; 51 | FILETIME time; 52 | hKernel32 = GetModuleHandleW(L"kernel32.dll"); 53 | #if defined(__GNUC__) && (__GNUC__ == 8) 54 | #pragma GCC diagnostic push 55 | #pragma GCC diagnostic ignored "-Wcast-function-type" 56 | #endif 57 | if (hKernel32) 58 | fnGetSystemTimePreciseAsFileTime = (pfnGetSystemTimePreciseAsFileTime) GetProcAddress(hKernel32, "GetSystemTimePreciseAsFileTime"); 59 | #if defined(__GNUC__) && (__GNUC__ == 8) 60 | #pragma GCC diagnostic pop 61 | #endif 62 | 63 | if (fnGetSystemTimePreciseAsFileTime) 64 | fnGetSystemTimePreciseAsFileTime(&time); 65 | else 66 | GetSystemTimeAsFileTime(&time); 67 | 68 | uint64_t time64 = ((uint64_t)time.dwHighDateTime << 32) | time.dwLowDateTime; 69 | time64 = (time64 / 10 - 11644473600ULL * 1000000ULL); 70 | 71 | if (tp) 72 | { 73 | tp->tv_sec = (long) (time64 / 1000000ULL); 74 | tp->tv_usec = (long) (time64 % 1000000ULL); 75 | } 76 | if (tzp) 77 | { 78 | /* The use of the timezone structure is obsolete; the tz argument should normally be specified as NULL. */ 79 | TIME_ZONE_INFORMATION tzi; 80 | GetTimeZoneInformation(&tzi); 81 | 82 | tzp->tz_minuteswest = tzi.Bias; 83 | tzp->tz_dsttime = 0; 84 | } 85 | 86 | /* The gettimeofday() function returns 0 and no value is reserved to indicate an error. */ 87 | return 0; 88 | } 89 | 90 | #ifdef __cplusplus 91 | } 92 | #endif /* __cplusplus */ 93 | 94 | #endif /* _WIN32 */ 95 | 96 | #endif /* GETTIMEOFDAY_H */ 97 | -------------------------------------------------------------------------------- /src/surgescript/third_party/xoroshiro128plus.c: -------------------------------------------------------------------------------- 1 | /* Written in 2016-2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) 2 | 3 | To the extent possible under law, the author has dedicated all copyright 4 | and related and neighboring rights to this software to the public domain 5 | worldwide. This software is distributed without any warranty. 6 | 7 | See . */ 8 | 9 | #include 10 | 11 | /* This is xoroshiro128+ 1.0, our best and fastest small-state generator 12 | for floating-point numbers. We suggest to use its upper bits for 13 | floating-point generation, as it is slightly faster than 14 | xoroshiro128**. It passes all tests we are aware of except for the four 15 | lower bits, which might fail linearity tests (and just those), so if 16 | low linear complexity is not considered an issue (as it is usually the 17 | case) it can be used to generate 64-bit outputs, too; moreover, this 18 | generator has a very mild Hamming-weight dependency making our test 19 | (http://prng.di.unimi.it/hwd.php) fail after 5 TB of output; we believe 20 | this slight bias cannot affect any application. If you are concerned, 21 | use xoroshiro128++, xoroshiro128** or xoshiro256+. 22 | 23 | We suggest to use a sign test to extract a random Boolean value, and 24 | right shifts to extract subsets of bits. 25 | 26 | The state must be seeded so that it is not everywhere zero. If you have 27 | a 64-bit seed, we suggest to seed a splitmix64 generator and use its 28 | output to fill s. 29 | 30 | NOTE: the parameters (a=24, b=16, b=37) of this version give slightly 31 | better results in our test than the 2016 version (a=55, b=14, c=36). 32 | */ 33 | 34 | static inline uint64_t rotl(const uint64_t x, int k) { 35 | return (x << k) | (x >> (64 - k)); 36 | } 37 | 38 | 39 | static uint64_t s[2]; 40 | 41 | 42 | uint64_t next(void) { 43 | const uint64_t s0 = s[0]; 44 | uint64_t s1 = s[1]; 45 | const uint64_t result = s0 + s1; 46 | 47 | s1 ^= s0; 48 | s[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16); // a, b 49 | s[1] = rotl(s1, 37); // c 50 | 51 | return result; 52 | } 53 | 54 | 55 | /* This is the jump function for the generator. It is equivalent 56 | to 2^64 calls to next(); it can be used to generate 2^64 57 | non-overlapping subsequences for parallel computations. */ 58 | 59 | void jump(void) { 60 | static const uint64_t JUMP[] = { 0xdf900294d8f554a5, 0x170865df4b3201fc }; 61 | 62 | uint64_t s0 = 0; 63 | uint64_t s1 = 0; 64 | for(int i = 0; i < sizeof JUMP / sizeof *JUMP; i++) 65 | for(int b = 0; b < 64; b++) { 66 | if (JUMP[i] & UINT64_C(1) << b) { 67 | s0 ^= s[0]; 68 | s1 ^= s[1]; 69 | } 70 | next(); 71 | } 72 | 73 | s[0] = s0; 74 | s[1] = s1; 75 | } 76 | 77 | 78 | /* This is the long-jump function for the generator. It is equivalent to 79 | 2^96 calls to next(); it can be used to generate 2^32 starting points, 80 | from each of which jump() will generate 2^32 non-overlapping 81 | subsequences for parallel distributed computations. */ 82 | 83 | void long_jump(void) { 84 | static const uint64_t LONG_JUMP[] = { 0xd2a98b26625eee7b, 0xdddf9b1090aa7ac1 }; 85 | 86 | uint64_t s0 = 0; 87 | uint64_t s1 = 0; 88 | for(int i = 0; i < sizeof LONG_JUMP / sizeof *LONG_JUMP; i++) 89 | for(int b = 0; b < 64; b++) { 90 | if (LONG_JUMP[i] & UINT64_C(1) << b) { 91 | s0 ^= s[0]; 92 | s1 ^= s[1]; 93 | } 94 | next(); 95 | } 96 | 97 | s[0] = s0; 98 | s[1] = s1; 99 | } 100 | 101 | uint64_t* xor_seed = s; 102 | uint64_t (*xor_next)(void) = next; -------------------------------------------------------------------------------- /src/surgescript/third_party/xxhash.c: -------------------------------------------------------------------------------- 1 | /* 2 | * xxHash - Extremely Fast Hash algorithm 3 | * Copyright (C) 2012-2020 Yann Collet 4 | * 5 | * BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php) 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are 9 | * met: 10 | * 11 | * * Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * * Redistributions in binary form must reproduce the above 14 | * copyright notice, this list of conditions and the following disclaimer 15 | * in the documentation and/or other materials provided with the 16 | * distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | * 30 | * You can contact the author at: 31 | * - xxHash homepage: https://www.xxhash.com 32 | * - xxHash source repository: https://github.com/Cyan4973/xxHash 33 | */ 34 | 35 | 36 | /* 37 | * xxhash.c instantiates functions defined in xxhash.h 38 | */ 39 | 40 | #define XXH_STATIC_LINKING_ONLY /* access advanced declarations */ 41 | #define XXH_IMPLEMENTATION /* access definitions */ 42 | 43 | #include "xxhash.h" 44 | -------------------------------------------------------------------------------- /src/surgescript/util/fasthash.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * util/fasthash.h 19 | * A fast hash table with integer keys and linear probing 20 | */ 21 | 22 | #ifndef _SURGESCRIPT_FASTHASH_H 23 | #define _SURGESCRIPT_FASTHASH_H 24 | 25 | #include 26 | #include 27 | 28 | /* Inline usage: 29 | 30 | #define FASTHASH_INLINE 31 | #include "fasthash.h" 32 | 33 | No need to compile fasthash.c separately */ 34 | #if defined(FASTHASH_INLINE) 35 | #define FASTHASH_API static inline 36 | #else 37 | #define FASTHASH_API 38 | #endif 39 | 40 | typedef struct fasthash_t fasthash_t; 41 | FASTHASH_API fasthash_t* fasthash_create(void (*element_destructor)(void*), int lg2_cap); 42 | FASTHASH_API fasthash_t* fasthash_destroy(fasthash_t* hashtable); 43 | FASTHASH_API void* fasthash_get(fasthash_t* hashtable, uint64_t key); 44 | FASTHASH_API void fasthash_put(fasthash_t* hashtable, uint64_t key, void* value); 45 | FASTHASH_API bool fasthash_delete(fasthash_t* hashtable, uint64_t key); 46 | FASTHASH_API void* fasthash_find(fasthash_t* hashtable, bool (*predicate)(const void*,void*), void* data); 47 | 48 | #if defined(FASTHASH_INLINE) 49 | #include "fasthash.c" 50 | #endif 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /src/surgescript/util/perfect_hash.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * util/perfect_hash.h 19 | * Perfect hashing utility 20 | */ 21 | 22 | #ifndef _SURGESCRIPT_PERFECTHASH_H 23 | #define _SURGESCRIPT_PERFECTHASH_H 24 | 25 | #include 26 | #include 27 | 28 | /* We use 32-bit hashes */ 29 | typedef uint32_t surgescript_perfecthashkey_t; 30 | typedef uint32_t surgescript_perfecthashseed_t; 31 | typedef surgescript_perfecthashkey_t (*surgescript_perfecthashfunction_t)(const char*,surgescript_perfecthashseed_t); 32 | 33 | /* given a family H = { h_s(x) | s } of hash functions and a set K of strings, 34 | find a seed value s such that h_s(x) is a perfect hash function for K (i.e., no coliisions). 35 | Note: you must ensure that there are no repeated strings in the key[] array. */ 36 | surgescript_perfecthashseed_t surgescript_perfecthash_find_seed(surgescript_perfecthashfunction_t hash_fn, const char** key, size_t key_count); 37 | 38 | #endif -------------------------------------------------------------------------------- /src/surgescript/util/ssarray.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2024 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * util/ssarray.h 19 | * SurgeScript expandable arrays 20 | */ 21 | 22 | #ifndef _SURGESCRIPT_SSARRAY_H 23 | #define _SURGESCRIPT_SSARRAY_H 24 | 25 | #include "util.h" 26 | 27 | /* 28 | * SSARRAY() 29 | * declares an array of a certain type 30 | */ 31 | #define SSARRAY(type, arr) type* arr; size_t arr##_len, arr##_cap 32 | 33 | /* 34 | * ssarray_init() 35 | * initializes the array 36 | */ 37 | #define ssarray_init(arr) ssarray_init_ex(arr, 0) 38 | 39 | /* 40 | * ssarray_init_ex() 41 | * initializes the array with a pre-defined initial capacity 42 | */ 43 | #define ssarray_init_ex(arr, cap) (arr##_len = 0, arr##_cap = ((cap) > 0 ? (cap) : 4), arr = ssmalloc(arr##_cap * sizeof(*(arr)))) 44 | 45 | /* 46 | * ssarray_release() 47 | * releases the array 48 | */ 49 | #define ssarray_release(arr) (arr##_len = arr##_cap = 0, arr = (arr ? ssfree(arr) : NULL)) 50 | 51 | /* 52 | * ssarray_push() 53 | * pushes element 'x' into the array, returning the new length of the array 54 | */ 55 | #define ssarray_push(arr, x) \ 56 | (*(((arr##_len >= arr##_cap) ? (arr = ssrealloc(arr, (arr##_cap *= 2) * sizeof(*(arr)))) : arr) + (arr##_len)) = (x), ++arr##_len) 57 | 58 | /* 59 | * ssarray_pop() 60 | * pops the last element from the array, writing its contents to variable dst 61 | */ 62 | #define ssarray_pop(arr, dst) \ 63 | do { if(arr##_len > 0) dst = arr[--arr##_len]; } while(0) 64 | 65 | /* 66 | * ssarray_remove() 67 | * removes the index-th element from the array 68 | */ 69 | #define ssarray_remove(arr, index) \ 70 | do { if((index) < arr##_len && (index) >= 0) { memmove((arr) + (index), (arr) + ((index) + 1), (arr##_len - ((index) + 1)) * sizeof(*(arr))); arr##_len--; } } while(0) 71 | 72 | /* 73 | * ssarray_length() 74 | * returns the length of the array 75 | */ 76 | #define ssarray_length(arr) (arr##_len) 77 | 78 | /* 79 | * ssarray_reset() 80 | * sets the length of the array to zero, without freeing anything 81 | */ 82 | #define ssarray_reset(arr) (arr##_len = 0) 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /src/surgescript/util/version.h.in: -------------------------------------------------------------------------------- 1 | /* 2 | * SurgeScript 3 | * A scripting language for games 4 | * Copyright 2016-2023 Alexandre Martins 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | * 18 | * util/version.h 19 | * SurgeScript version: available at compile time 20 | */ 21 | 22 | #ifndef _SURGESCRIPT_VERSION_H 23 | #define _SURGESCRIPT_VERSION_H 24 | 25 | /* Import SurgeScript version */ 26 | #define SURGESCRIPT_VERSION_SUP @PROJECT_VERSION_MAJOR@ 27 | #define SURGESCRIPT_VERSION_SUB @PROJECT_VERSION_MINOR@ 28 | #define SURGESCRIPT_VERSION_WIP @PROJECT_VERSION_PATCH@ 29 | #cmakedefine SURGESCRIPT_VERSION_FIX @PROJECT_VERSION_TWEAK@ 30 | 31 | #if !defined(SURGESCRIPT_VERSION_FIX) 32 | #define SURGESCRIPT_VERSION_FIX 0 33 | #endif 34 | 35 | /* Generate version string */ 36 | #define SURGESCRIPT_VERSION_STR "@PROJECT_VERSION@" 37 | 38 | /* Convert a version tuple into an integer */ 39 | #define SURGESCRIPT_VERSION_CODE(x, y, z, w) \ 40 | (((x) << 24) | ((y) << 16) | ((z) << 8) | (w)) 41 | 42 | /* Compare a version tuple to the current version of SurgeScript */ 43 | #define SURGESCRIPT_VERSION_COMPARE(x, y, z, w) ( \ 44 | SURGESCRIPT_VERSION_CODE( \ 45 | SURGESCRIPT_VERSION_SUP, \ 46 | SURGESCRIPT_VERSION_SUB, \ 47 | SURGESCRIPT_VERSION_WIP, \ 48 | SURGESCRIPT_VERSION_FIX \ 49 | ) - \ 50 | SURGESCRIPT_VERSION_CODE((x), (y), (z), (w)) \ 51 | ) 52 | 53 | /* Check if the current version of SurgeScript is x.y.z.w or newer */ 54 | #define SURGESCRIPT_VERSION_IS_AT_LEAST(x, y, z, w) \ 55 | (SURGESCRIPT_VERSION_COMPARE((x), (y), (z), (w)) >= 0) 56 | 57 | #endif --------------------------------------------------------------------------------