diff --git a/.vscode/plus.code-snippets.disable b/.vscode/plus.code-snippets.disable deleted file mode 100644 index 9f1e6a3..0000000 --- a/.vscode/plus.code-snippets.disable +++ /dev/null @@ -1 +0,0 @@ -{"jjActiveGameTicks": {"prefix": "jjActiveGameTicks", "body": "jjActiveGameTicks", "description": "How long the game has been actively running, at a rate of 70 ticks per second. Unlike jjGameTicks, this value is not incremented when the game is paused, stopped, or in pregame. This is a local value that counts up from 0 except in online Race games, where it is used to track lap times and is therefore synced between server and clients. "}, "jjAllowsFireball": {"prefix": "jjAllowsFireball", "body": "jjAllowsFireball", "description": "Whether weapon 8 is fireball instead pepper spray, as set by the /fireball command. "}, "jjAllowsMouseAim": {"prefix": "jjAllowsMouseAim", "body": "jjAllowsMouseAim", "description": "Whether the server (or the SP level) allows mouse aim, as set by the /allowmouseaim command. "}, "jjAllowsReady": {"prefix": "jjAllowsReady", "body": "jjAllowsReady", "description": "Whether the server allows players to use the /ready command, as set by the /allowready command. "}, "jjAllowsWalljump": {"prefix": "jjAllowsWalljump", "body": "jjAllowsWalljump", "description": "Whether the server allows players to use the \"walljumping\" bug, as set by the /allowwalljump command. "}, "jjAlwaysRunning": {"prefix": "jjAlwaysRunning", "body": "jjAlwaysRunning", "description": "Whether always running is enabled, as set by the /run command. "}, "jjAnimatedTiles": {"prefix": "jjAnimatedTiles", "body": "jjAnimatedTiles", "description": "Animated tiles defined by the level. For every tileID,jjAnimatedTiles[tileID] is jjTiles[tileID | TILE::ANIMATED]. See also jjTiles. "}, "jjAnimations": {"prefix": "jjAnimations", "body": "jjAnimations", "description": "Loaded animations. See the jjANIMATION class description for more information. "}, "jjAnimFrames": {"prefix": "jjAnimFrames", "body": "jjAnimFrames", "description": "Loaded animation frames. See the jjANIMFRAME class description for more information. "}, "jjAnimSets": {"prefix": "jjAnimSets", "body": "jjAnimSets", "description": "Loaded animation sets. See the jjANIMSET class description for more information. "}, "jjAutoWeaponChange": {"prefix": "jjAutoWeaponChange", "body": "jjAutoWeaponChange", "description": "Whether automatic weapon change is locally enabled, as set by the /weaponchange command. "}, "jjBackupPalette": {"prefix": "jjBackupPalette", "body": "jjBackupPalette", "description": "The tileset's original palette. See the jjPAL documentation above for further details. "}, "jjBorderHeight": {"prefix": "jjBorderHeight", "body": "jjBorderHeight", "description": "The size of the black borders that appear at the edges of each local player's subscreen when a subscreen is larger than the level/server's maximum resolution, when a subscreen is larger than Layer 4 (and Layer 4 does not have Tile Width/Tile Height checked), and/or when the F3 key has been used. Useful for deciding where to draw HUD/UI elements. Note that these values refer to the size of each border, not the overall size of the black space, so for instance if jjBorderWidth is 80, there will be 80 columns of black pixels on the left side of the subscreen and an additional 80 columns on the right side. "}, "jjBorderWidth": {"prefix": "jjBorderWidth", "body": "jjBorderWidth", "description": "The size of the black borders that appear at the edges of each local player's subscreen when a subscreen is larger than the level/server's maximum resolution, when a subscreen is larger than Layer 4 (and Layer 4 does not have Tile Width/Tile Height checked), and/or when the F3 key has been used. Useful for deciding where to draw HUD/UI elements. Note that these values refer to the size of each border, not the overall size of the black space, so for instance if jjBorderWidth is 80, there will be 80 columns of black pixels on the left side of the subscreen and an additional 80 columns on the right side. "}, "jjBottomFeeder": {"prefix": "jjBottomFeeder", "body": "jjBottomFeeder", "description": "In Roast Tag game mode, the player who is currently the bottom feeder or null if none. For the other special role in Roast Tag, see jjTokenOwner. "}, "jjCharacters": {"prefix": "jjCharacters", "body": "jjCharacters", "description": "Character profiles. Use either CHAR::JAZZ, CHAR::SPAZ, CHAR::LORI, CHAR::BIRD, CHAR::FROG or CHAR::BIRD2 as an index. Refer to the jjCHARACTER section for more information. "}, "jjColorDepth": {"prefix": "jjColorDepth", "body": "jjColorDepth", "description": "Color depth in bits per pixel. Either 8 or 16. "}, "jjControlPoints": {"prefix": "jjControlPoints", "body": "jjControlPoints", "description": "An array containing all Domination control points in the level. See the jjCONTROLPOINT section for further details. "}, "jjDeactivatingBecauseOfDeath": {"prefix": "jjDeactivatingBecauseOfDeath", "body": "jjDeactivatingBecauseOfDeath", "description": "When the player dies in Single Player mode, this property is set to true before all jjOBJs have their state property set to DEACTIVATE. Since DEACTIVATE is also used for when an object goes too far off-screen, this property is how to discover the reason for the state change. In practice, is probably only ever consulted by destruct scenery and trigger scenery. "}, "jjDebugF10": {"prefix": "jjDebugF10", "body": "jjDebugF10", "description": "Only ever true in single player, specifically when the player has pressed the F10 key to enable debug mode. Among other peculiarities during this time, neither onPlayer nor onPlayerInput nor any of the various non-layer-based jjCANVAS onDraw hook functions will be called, because JJ2+ will be ignoring all normal player interactions. "}, "jjDelayGeneratedCrateOrigins": {"prefix": "jjDelayGeneratedCrateOrigins", "body": "jjDelayGeneratedCrateOrigins", "description": "If set to true, box objects (trigger crates, all wooden crates, bird morph monitors, and also bird cages) spawned from Generator objects will derive their parameters from the tile they begin at, not the tile they are created at. If the Generator object is in the air, the crate will appear on top of the nearest solid tile below the Generator, and will get its parameters from the tile there. "}, "jjDifficulty": {"prefix": "jjDifficulty", "body": "jjDifficulty", "description": "The current difficulty level. 1 for Normal difficulty; 0 and below for Easy; 2 for Hard; 3 and above for Turbo. Numerous enemies base their speeds at least partially on the difficulty, so numbers outside of the well-tested 0-3 range may have unexpected or undesirable effects with certain enemies; still, it's worth a try! This property cannot be used to determine whether to load events specified in JCS as Easy or Hard, since that has already been checked by the time AngelScript starts running in a level. When you set this property, jjDifficultyNext will also be set to the new value. So for example, if you want to make enemies move a little faster in this level without affecting the difficulty of the next level in the series, try: jjDifficulty += 1; jjDifficultyNext = jjDifficultyOrig; "}, "jjDifficultyNext": {"prefix": "jjDifficultyNext", "body": "jjDifficultyNext", "description": "The difficulty for the next level. Normally this will be the same as jjDifficulty, but the /difficulty command can set this property independently. Setting this does not accomplish anything for clients, because clients will have their difficulty updated by the server upon cycling. "}, "jjDifficultyOrig": {"prefix": "jjDifficultyOrig", "body": "jjDifficultyOrig", "description": "The difficulty at the start of the level, prior to it being potentially changed by scripts setting jjDifficulty. In online servers, clients who join this level partway through will be sent this value for their difficulty, so they will remove the same events from the event map that everyone else in the server did. "}, "jjDoZombiesAlreadyExist": {"prefix": "jjDoZombiesAlreadyExist", "body": "jjDoZombiesAlreadyExist", "description": "In Pestilence game mode, whether any player is already a zombie. "}, "jjEcho": {"prefix": "jjEcho", "body": "jjEcho", "description": "The current degree of echo, as set by the \"Echo\" event. "}, "jjEnabledASFunctions": {"prefix": "jjEnabledASFunctions", "body": "jjEnabledASFunctions", "description": "Usually all true. When a Text event is touched with AngelScript=1,Vanish=1, the jjEnabledASFunctions[#] bool for that Text event's TextID value will be set to false and the corresponding onFunction# will be uncallable by other Text events until the bool is set to true again. "}, "jjEnabledTeams": {"prefix": "jjEnabledTeams", "body": "jjEnabledTeams", "description": "Currently enabled teams. Possible indices are TEAM::BLUE, TEAM::RED, TEAM::GREEN, and TEAM::YELLOW. "}, "jjEnforceLighting": {"prefix": "jjEnforceLighting", "body": "jjEnforceLighting", "description": "This setting defines the minimal ambient lighting options required from the game. It will not change game settings if they don't fulfill the requirements but it will display lights as if the settings were changed. Allowed values are:\n\t\t\t\tOPTIONAL: The default value; ambient lighting can be freely disabled and enabled with no limits.\n\t\t\t\tBASIC: Ambient lighting can be disabled but basic lights, such as those emitted by objects, players and laser shields, have to be drawn. This only affects the game if ambient lighting is disabled and low detail is enabled, because that's when basic lights stop being drawn.\n\t\t\t\tCOMPLETE: Ambient lighting cannot be disabled, all lights have to be drawn.\n\t\t\t\t "}, "jjEventAtLastMaskedPixel": {"prefix": "jjEventAtLastMaskedPixel", "body": "jjEventAtLastMaskedPixel", "description": "Whenever one of the mask-detection functions, e.g. jjMaskedHLine, finds a masked pixel in layer 4, this property will be set to the event at the tile containing that pixel. This allows you to write code for object like seeker missiles, which ignore masked pixels on tiles with the AREA::ONEWAY, AREA::HOOK, or AREA::VINE events. There's not much reason to edit it manually, since JJ2 changes its value all but constantly, but you can if you want. "}, "jjFPS": {"prefix": "jjFPS", "body": "jjFPS", "description": "The current frames per second rate, as viewable by pressing F9 twice. "}, "jjFriendlyFire": {"prefix": "jjFriendlyFire", "body": "jjFriendlyFire", "description": "Whether friendly fire is enabled, as set by the /friendlyfire command. "}, "jjGameConnection": {"prefix": "jjGameConnection", "body": "jjGameConnection", "description": "Is this game joinable by players from other computers, and if so, must they be connected to the same network or just the internet? Options are LOCAL, ONLINE, and LAN. "}, "jjGameCustom": {"prefix": "jjGameCustom", "body": "jjGameCustom", "description": "If using a custom gamemode, what is it? Options are NOCUSTOM, RT, LRS, XLRS, PEST, TB, JB, DCTF, FR, TLRS, DOM, and HEAD. "}, "jjGameMode": {"prefix": "jjGameMode", "body": "jjGameMode", "description": "What is the current base gamemode, irrespective of whether there is a custom gamemode or not? Options are SP, COOP, BATTLE, CTF, TREASURE, and RACE. "}, "jjGameState": {"prefix": "jjGameState", "body": "jjGameState", "description": "In an online/network server, is the game started, stopped, or some other variation? Options are. STOPPED, STARTED, PAUSED (only possible if there is a time limit), PREGAME, and OVERTIME. "}, "jjGameTicks": {"prefix": "jjGameTicks", "body": "jjGameTicks", "description": "How long the game has been actively running, at a rate of 70 ticks per second. "}, "jjHelpStrings": {"prefix": "jjHelpStrings", "body": "jjHelpStrings", "description": "Help strings as set in level properties and used by Text events and end bosses. These can be modified but are limited to 511 characters each, so longer strings will be truncated. For the standard function to display these strings, see showText. "}, "jjIsAdmin": {"prefix": "jjIsAdmin", "body": "jjIsAdmin", "description": "Whether the current game executable is logged in as a Remote Admin in the current online server. To check this property for any client in the server, use jjPLAYER property isAdmin instead. "}, "jjIsServer": {"prefix": "jjIsServer", "body": "jjIsServer", "description": "Whether the current game executable is hosting an online server. "}, "jjIsSnowing": {"prefix": "jjIsSnowing", "body": "jjIsSnowing", "description": "Whether there's any active weather effect. The type of the effect is determined by jjSnowingType. "}, "jjIsSnowingOutdoorsOnly": {"prefix": "jjIsSnowingOutdoorsOnly", "body": "jjIsSnowingOutdoorsOnly", "description": "Whether the current weather effect is specified to only take effect on transparent tiles, i.e. appear to be limited to outdoors areas. "}, "jjIsTSF": {"prefix": "jjIsTSF", "body": "jjIsTSF", "description": "Whether the current game executable is 1.23+ or 1.24+. Useful for Lori, XMas enemies, etc. "}, "jjKey": {"prefix": "jjKey", "body": "jjKey", "description": "Whether any given key on the keyboard is currently pressed, assuming JJ2 is able to check it, including the left and right mouse buttons. Uses virtual key codes for indexation. Note that jjKey[1] and jjKey[2] refer to the primary and secondary mouse buttons respectively, rather than left and right. "}, "jjKeyChat": {"prefix": "jjKeyChat", "body": "jjKeyChat", "description": "The current virtual key used to open the chat prompt in a multiplayer game, default value 0x54 ('T'). No matter the key (or mouse button), pressing the Shift key at the same time will open the chat prompt in Team Chat mode (in CTF games). Note that as a workaround to allow players to cycle and whatnot, pressing Ctrl+T will always open the chat prompt, even if jjKeyChat is set to 0 or something similarly inaccessible. "}, "jjLayerHasTiles": {"prefix": "jjLayerHasTiles", "body": "jjLayerHasTiles", "description": "Shortcut global properties for the same-named jjLAYER properties on the same-indexed jjLayers objects. "}, "jjLayerHeight": {"prefix": "jjLayerHeight", "body": "jjLayerHeight", "description": "Shortcut global properties for the same-named jjLAYER properties on the same-indexed jjLayers objects. "}, "jjLayerLimitVisibleRegion": {"prefix": "jjLayerLimitVisibleRegion", "body": "jjLayerLimitVisibleRegion", "description": "Shortcut global properties for the same-named jjLAYER properties on the same-indexed jjLayers objects. "}, "jjLayerTileHeight": {"prefix": "jjLayerTileHeight", "body": "jjLayerTileHeight", "description": "Shortcut global properties for the same-named jjLAYER properties on the same-indexed jjLayers objects. "}, "jjLayerTileWidth": {"prefix": "jjLayerTileWidth", "body": "jjLayerTileWidth", "description": "Shortcut global properties for the same-named jjLAYER properties on the same-indexed jjLayers objects. "}, "jjLayerWidth": {"prefix": "jjLayerWidth", "body": "jjLayerWidth", "description": "Shortcut global properties for the same-named jjLAYER properties on the same-indexed jjLayers objects. "}, "jjLayerWidthReal": {"prefix": "jjLayerWidthReal", "body": "jjLayerWidthReal", "description": "Shortcut global properties for the same-named jjLAYER properties on the same-indexed jjLayers objects. "}, "jjLayerWidthRounded": {"prefix": "jjLayerWidthRounded", "body": "jjLayerWidthRounded", "description": "Shortcut global properties for the same-named jjLAYER properties on the same-indexed jjLayers objects. "}, "jjLayerXAutoSpeed": {"prefix": "jjLayerXAutoSpeed", "body": "jjLayerXAutoSpeed", "description": "Shortcut global properties for the same-named jjLAYER properties on the same-indexed jjLayers objects. "}, "jjLayerYAutoSpeed": {"prefix": "jjLayerYAutoSpeed", "body": "jjLayerYAutoSpeed", "description": "Shortcut global properties for the same-named jjLAYER properties on the same-indexed jjLayers objects. "}, "jjLayerXOffset": {"prefix": "jjLayerXOffset", "body": "jjLayerXOffset", "description": "Shortcut global properties for the same-named jjLAYER properties on the same-indexed jjLayers objects. "}, "jjLayerYOffset": {"prefix": "jjLayerYOffset", "body": "jjLayerYOffset", "description": "Shortcut global properties for the same-named jjLAYER properties on the same-indexed jjLayers objects. "}, "jjLayerXSpeed": {"prefix": "jjLayerXSpeed", "body": "jjLayerXSpeed", "description": "Shortcut global properties for the same-named jjLAYER properties on the same-indexed jjLayers objects. "}, "jjLayerYSpeed": {"prefix": "jjLayerYSpeed", "body": "jjLayerYSpeed", "description": "Shortcut global properties for the same-named jjLAYER properties on the same-indexed jjLayers objects. "}, "jjLayers": {"prefix": "jjLayers", "body": "jjLayers", "description": "The original eight layers placed in this level (i.e. jjLevelFileName) in JCS or some other level editor, 1-indexed to match the JCS numbers, e.g. jjLayers[4] for the main sprite layer or jjLayers[8] for the final background layer, regardless of what other code may have done to create new layers or alter their order. See the jjLAYER documentation above for further details. "}, "jjLevelFileName": {"prefix": "jjLevelFileName", "body": "jjLevelFileName", "description": "File name of the current level, e.g. castle1.j2l, all lowercase. The file extension (.j2l) will be included, but not the folder structure. "}, "jjLevelName": {"prefix": "jjLevelName", "body": "jjLevelName", "description": "Title of the current level, e.g. Dungeon Dilemma. "}, "jjLocalPlayerCount": {"prefix": "jjLocalPlayerCount", "body": "jjLocalPlayerCount", "description": "The number of local players. "}, "jjLocalPlayers": {"prefix": "jjLocalPlayers", "body": "jjLocalPlayers", "description": "The local players. "}, "jjLowDetail": {"prefix": "jjLowDetail", "body": "jjLowDetail", "description": "Whether the Low Detail video setting is enabled. When true, only jjLayers[8] and layers whose xSpeed/ySpeed both equal exactly 1 and whose xSpeedModel/ySpeedModel both equal LAYERSPEEDMODEL::NORMAL will be drawn, and even those only if hasTileMap and hasTiles are both true. "}, "jjMaxHealth": {"prefix": "jjMaxHealth", "body": "jjMaxHealth", "description": "The most health a player can ever have, as set by the /maxhealth command. Defaults to 5 in Single Player/Cooperative/Battle, or 3 in Capture The Flag. "}, "jjMaxScore": {"prefix": "jjMaxScore", "body": "jjMaxScore", "description": "In competitive game modes, the score required to win, as set by the /maxscore command. "}, "jjMouseAim": {"prefix": "jjMouseAim", "body": "jjMouseAim", "description": "Whether mouse aim is locally enabled, as set by the /mouseaim command. "}, "jjMouseX": {"prefix": "jjMouseX", "body": "jjMouseX", "description": "The current position of the mouse cursor relative to the top left corner of the game window. To convert these coordinates to coordinates within layer 4, you'll need to use the jjPLAYER cameraX and cameraY properties. "}, "jjMouseY": {"prefix": "jjMouseY", "body": "jjMouseY", "description": "The current position of the mouse cursor relative to the top left corner of the game window. To convert these coordinates to coordinates within layer 4, you'll need to use the jjPLAYER cameraX and cameraY properties. "}, "jjMusicActive": {"prefix": "jjMusicActive", "body": "jjMusicActive", "description": "Mute Music, as seen in the Sound & Music Properties window. "}, "jjMusicFileName": {"prefix": "jjMusicFileName", "body": "jjMusicFileName", "description": "File name of the music file currently playing, e.g. 3ddemo.mod, all lowercase. The file extension will be included (even if not included by the level or user, e.g. this string will be \"castle.j2b\" if \"castle\" was written in Level Properties), but not the folder structure. This is a const property. To change it, use jjMusicLoad. "}, "jjMusicVolume": {"prefix": "jjMusicVolume", "body": "jjMusicVolume", "description": "Music Volume, as seen in the Sound & Music Properties window. "}, "jjNoBlink": {"prefix": "jjNoBlink", "body": "jjNoBlink", "description": "Whether the no blink mode is enabled, as set by the /noblink command. "}, "jjNoMovement": {"prefix": "jjNoMovement", "body": "jjNoMovement", "description": "Whether the game blocks movement during stopped games, as set by the /nomovement command. "}, "jjObjectCount": {"prefix": "jjObjectCount", "body": "jjObjectCount", "description": "When looping through jjObjects, this is the endpoint; there should never exist a jjOBJ with an object ID higher than jjObjectCount. It is not however the number of distinct jjOBJs in existence at any given time, since for instance jjObjects[1] and jjObjects[3] may both be active but jjObjects[2] inactive, but jjObjectCount would still equal 4. "}, "jjObjectMax": {"prefix": "jjObjectMax", "body": "jjObjectMax", "description": "The most jjOBJs that can ever exist at the same time. This equals 2048 in local Single Player/Coop, or 4096 otherwise. "}, "jjObjectPresets": {"prefix": "jjObjectPresets", "body": "jjObjectPresets", "description": "The templates from which each object is built. Tends to contain default xSpeed, ySpeed, points, curAnim, and so on. Make changes here in onLevelLoad for maximum efficiency. "}, "jjObjects": {"prefix": "jjObjects", "body": "jjObjects", "description": "All the objects currently in memory. "}, "jjP": {"prefix": "jjP", "body": "jjP", "description": "The current player. "}, "jjPalette": {"prefix": "jjPalette", "body": "jjPalette", "description": "The current palette. See the jjPAL documentation above for further details. "}, "jjParticles": {"prefix": "jjParticles", "body": "jjParticles", "description": "All the particles currently in memory. See the jjPARTICLE documentation above for further details. "}, "jjPlayerCount": {"prefix": "jjPlayerCount", "body": "jjPlayerCount", "description": "Doesn't work! Check back later. "}, "jjPlayers": {"prefix": "jjPlayers", "body": "jjPlayers", "description": "All the players in the game, local or otherwise. "}, "jjQuirks": {"prefix": "jjQuirks", "body": "jjQuirks", "description": "Whether the quirks mode is enabled, as set by the /quirks command. "}, "jjRenderFrame": {"prefix": "jjRenderFrame", "body": "jjRenderFrame", "description": "How long the game has been running. Unlike jjGameTicks, jjRenderFrame updates when the game is paused. This is the value used for drawing layers with automatic x/y speeds. "}, "jjResolutionHeight": {"prefix": "jjResolutionHeight", "body": "jjResolutionHeight", "description": "The size of the current game window in pixels, usually 640 by 480. "}, "jjResolutionWidth": {"prefix": "jjResolutionWidth", "body": "jjResolutionWidth", "description": "The size of the current game window in pixels, usually 640 by 480. "}, "jjResolutionMaxHeight": {"prefix": "jjResolutionMaxHeight", "body": "jjResolutionMaxHeight", "description": "The maximum size the game window is allowed to be in the current level/server. "}, "jjResolutionMaxWidth": {"prefix": "jjResolutionMaxWidth", "body": "jjResolutionMaxWidth", "description": "The maximum size the game window is allowed to be in the current level/server. "}, "jjScriptModuleID": {"prefix": "jjScriptModuleID", "body": "jjScriptModuleID", "description": "Each script module (including mutators) will see this property as equalling a different value: 0 for the .j2as script (if any), and 1 or higher for all mutators (loaded in alphabetical order). For use only as parameters of function jjSendPacket and jjPLAYER method hasPrivilege. "}, "jjShowMaxHealth": {"prefix": "jjShowMaxHealth", "body": "jjShowMaxHealth", "description": "Whether the show max health option from the Plus menu is enabled. "}, "jjSnowingIntensity": {"prefix": "jjSnowingIntensity", "body": "jjSnowingIntensity", "description": "Intensity of the current weather effect. Note that that this setting only influences the game if jjIsSnowing is true. "}, "jjSnowingType": {"prefix": "jjSnowingType", "body": "jjSnowingType", "description": "Type of the current weather effect. Note that that this setting only influences the game if jjIsSnowing is true. Possible values are SNOW, FLOWER, RAIN, and LEAF, each spawning particles of the corresponding PARTICLE::Type. "}, "jjSoundEnabled": {"prefix": "jjSoundEnabled", "body": "jjSoundEnabled", "description": "Whether JJ2 should produce any form of audio at all. "}, "jjSoundFXActive": {"prefix": "jjSoundFXActive", "body": "jjSoundFXActive", "description": "Mute Sound, as seen in the Sound & Music Properties window. "}, "jjSoundFXVolume": {"prefix": "jjSoundFXVolume", "body": "jjSoundFXVolume", "description": "Sound Volume, as seen in the Sound & Music Properties window. "}, "jjStartHealth": {"prefix": "jjStartHealth", "body": "jjStartHealth", "description": "How much health a player starts with, as set by the /starthealth command. Defaults to 5 in Single Player/Cooperative/Battle, or 3 in Capture The Flag. "}, "jjStrongPowerups": {"prefix": "jjStrongPowerups", "body": "jjStrongPowerups", "description": "Whether strong powerups is enabled, as set by the /strongpowerups command. "}, "jjSubscreenHeight": {"prefix": "jjSubscreenHeight", "body": "jjSubscreenHeight", "description": "The size of a player's subscreen in pixels. If there is only one local player and the game is not being viewed in 3D, these will be equal to jjResolutionHeight and jjResolutionWidth -- otherwise, either or both may be cut in half. The subscreen size includes, and is therefore not changed by the values of, jjBorderHeight and jjBorderWidth. "}, "jjSubscreenWidth": {"prefix": "jjSubscreenWidth", "body": "jjSubscreenWidth", "description": "The size of a player's subscreen in pixels. If there is only one local player and the game is not being viewed in 3D, these will be equal to jjResolutionHeight and jjResolutionWidth -- otherwise, either or both may be cut in half. The subscreen size includes, and is therefore not changed by the values of, jjBorderHeight and jjBorderWidth. "}, "jjSugarRushAllowed": {"prefix": "jjSugarRushAllowed", "body": "jjSugarRushAllowed", "description": "In online multiplayer levels where this is false for the host, clients with sugar rushes will be kicked for hacking. This property is set to true between onLevelLoad and onLevelBegin if there are any events in the level that will spawn food objects. If you need to allow sugar rushes for another reason, e.g. jjPLAYER::startSugarRush, your script should set this property to true in onLevelBegin at the earliest. (See the description of jjWEAPON::allowed for more technical details, but as applied to the list of food events instead.) "}, "jjTeamScore": {"prefix": "jjTeamScore", "body": "jjTeamScore", "description": "Each team's current score in team-based game modes and undefined value in other modes. Available indexes are BLUE, RED, GREEN and YELLOW. "}, "jjTexturedBGFadePositionX": {"prefix": "jjTexturedBGFadePositionX", "body": "jjTexturedBGFadePositionX", "description": "Shortcut global properties for corresponding jjLAYER or jjLAYER::warpHorizon properties of the background layer, i.e. jjLayers[8]. "}, "jjTexturedBGFadePositionY": {"prefix": "jjTexturedBGFadePositionY", "body": "jjTexturedBGFadePositionY", "description": "Shortcut global properties for corresponding jjLAYER or jjLAYER::warpHorizon properties of the background layer, i.e. jjLayers[8]. "}, "jjTexturedBGStars": {"prefix": "jjTexturedBGStars", "body": "jjTexturedBGStars", "description": "Shortcut global properties for corresponding jjLAYER or jjLAYER::warpHorizon properties of the background layer, i.e. jjLayers[8]. "}, "jjTexturedBGStyle": {"prefix": "jjTexturedBGStyle", "body": "jjTexturedBGStyle", "description": "Shortcut global properties for corresponding jjLAYER or jjLAYER::warpHorizon properties of the background layer, i.e. jjLayers[8]. "}, "jjTexturedBGTexture": {"prefix": "jjTexturedBGTexture", "body": "jjTexturedBGTexture", "description": "Shortcut global properties for corresponding jjLAYER or jjLAYER::warpHorizon properties of the background layer, i.e. jjLayers[8]. "}, "jjTexturedBGUsed": {"prefix": "jjTexturedBGUsed", "body": "jjTexturedBGUsed", "description": "A shortcut property for jjLayers[8]'s textureSurface property. Returns true iff the property is anything other than SURFACE::UNTEXTURED. Set jjTexturedBGUsed to true to set to SURFACE::LEGACY, or to false to set to SURFACE::UNTEXTURED. "}, "jjTileCount": {"prefix": "jjTileCount", "body": "jjTileCount", "description": "The number of (non-animated, non-flipped) tiles currently defined in the level, usually a multiple of 10. Can be increased using jjTilesFromTileset. "}, "jjTiles": {"prefix": "jjTiles", "body": "jjTiles", "description": "Static and animated tiles corresponding to tile IDs. See also jjAnimatedTiles. "}, "jjTilesetFileName": {"prefix": "jjTilesetFileName", "body": "jjTilesetFileName", "description": "File name of the tileset used by the current level, e.g. castle1.j2t, all lowercase. The file extension (.j2t) will be included, but not the folder structure. "}, "jjTileType": {"prefix": "jjTileType", "body": "jjTileType", "description": "Each tile's tile type: 0 for normal, 1 for translucent, 3 for invisible, and so on. Refer to your JCS.ini for the full list. "}, "jjTriggers": {"prefix": "jjTriggers", "body": "jjTriggers", "description": "The triggers, as set by the Trigger Zone and Trigger Crate events. "}, "jjTokenOwner": {"prefix": "jjTokenOwner", "body": "jjTokenOwner", "description": "In Roast Tag game mode, the player who is currently \"it\" or null if none. For the other special role in Roast Tag, see jjBottomFeeder. "}, "jjUseLayer8Speeds": {"prefix": "jjUseLayer8Speeds", "body": "jjUseLayer8Speeds", "description": "A shortcut property for jjLayers[8]'s xSpeedModel/ySpeedModel properties. Returns true iff at least one of the two properties is anything other than LAYERSPEEDMODEL::LAYER8. Set jjUseLayer8Speeds to true to set both properties to LAYERSPEEDMODEL::NORMAL, or to false to set both properties to LAYERSPEEDMODEL::LAYER8. "}, "jjVerticalSplitscreen": {"prefix": "jjVerticalSplitscreen", "body": "jjVerticalSplitscreen", "description": "If there are exactly two local players, how the window is divided into their two subscreens. "}, "jjWarpsTransmuteCoins": {"prefix": "jjWarpsTransmuteCoins", "body": "jjWarpsTransmuteCoins", "description": "If set to false, using a coin warp in Single Player mode will not turn all remaining coins into red and green gems. "}, "jjWaterChangeSpeed": {"prefix": "jjWaterChangeSpeed", "body": "jjWaterChangeSpeed", "description": "How fast water moves up or down when the water level is set (by event or function) with the \"Instant\" parameter set to false. Defaults to 1. "}, "jjWaterInteraction": {"prefix": "jjWaterInteraction", "body": "jjWaterInteraction", "description": "How local players react to being underwater. If this property is set to SWIM, they will swim; if LOWGRAVITY, they will use regular physics but will fall more slowly than usual. If this property is set to POSITIONBASED (the default), the game will choose between the effects of SWIM or LOWGRAVITY depending on whether jjWaterLevel is lower or greater than 32*128. This property has no effects on other objects or on sound effects, which always move more slowly/sound different underwater. "}, "jjWaterLayer": {"prefix": "jjWaterLayer", "body": "jjWaterLayer", "description": "Which layer, 1-8, water is drawn in front of when visible. Defaults to 1. Set to any non-existing layer number to make water invisible. Note that this is a purely visual setting, and putting water behind the sprite layer will not prevent players from swimming in it. If the order of layers has been changed, this property's distance from 4 is its distance from the sprite layer, e.g. leaving it at 1 means that it will be drawn in front of the third layer in front of the sprite layer. (And therefore, if the sprite layer is the first, second, or third layer in the drawing order, water will not be drawn at all.) "}, "jjWaterLevel": {"prefix": "jjWaterLevel", "body": "jjWaterLevel", "description": "How high the water currently is, in pixels. This is a constant value; use the jjSetWaterLevel helper function instead for changing it. "}, "jjWaterLighting": {"prefix": "jjWaterLighting", "body": "jjWaterLighting", "description": "The current way that water and ambient lighting interact in the level. (Ambient lighting varies by local player and as such is a jjPLAYER property.) The following constants are permissible values:\n\t\t\t\t\n\t\t\t\t\tWATERLIGHT::NONE: The default. When water is activated, the level will display at lighting 100, regardless of the current settings.\n\t\t\t\t\tWATERLIGHT::GLOBAL: The entire level will be lit according to the current ambient lighting settings, both above and below the water line.\n\t\t\t\t\tWATERLIGHT::LAGUNICUS: The current ambient lighting setting is ignored. Above the water, the level will display at lighting 100. Below the water, the level will display darker and darker depending on how far below the water line the player is.\n\t\t\t\t "}, "jjWaterTarget": {"prefix": "jjWaterTarget", "body": "jjWaterTarget", "description": "The height the water is moving towards, in pixels. If the water level is set (by event or function) with the \"Instant\" parameter set to false, there will be a period in which jjWaterLevel and jjWaterTarget are two distinct values. This is a constant value; use the jjSetWaterLevel helper function instead for changing it. "}, "jjWeapons": {"prefix": "jjWeapons", "body": "jjWeapons", "description": "Various properties of the nine different weapons available to a player; see the jjWEAPON section. Possible constants appear in the appendix below, or you may use simple 1-indexed numbers instead. "}, "p": {"prefix": "p", "body": "p", "description": "The current player; an alias of jjP, and the only property not to begin with the jj prefix, provided solely for convenience value. "}, "jjAddObject": {"prefix": "jjAddObject", "body": "int jjAddObject(uint8 eventID, float xPixel, float yPixel, uint16 creatorID = 0, CREATOR::Type\ncreatorType = CREATOR::OBJECT, jjBEHAVIOR behavior = BEHAVIOR::DEFAULT)", "description": "Adds and initiates an object of type eventID at xOrg xPixel and yOrg yPixel. Possible values for creatorType are CREATOR::OBJECT, CREATOR::LEVEL, and CREATOR::PLAYER. Useful values for eventID can be found in the appendix at the bottom of the page. Returns the object ID of the new object, or 0 if the function fails for whatever reason.\nThe difference between jjAddObject(1, 0, 0, CREATOR::OBJECT, 0, BEHAVIOR::BOUNCERBULLET); and jjObjects[jjAddObject(1, 0, 0)].behavior = BEHAVIOR::BOUNCERBULLET; is that jjAddObject calls the object's behavior function as part of creating it. The first version will call BEHAVIOR::BOUNCERBULLET while the object's state is still STATE::START; the second version will call jjObjectPresets[1].behavior and only switch the object's behavior to BEHAVIOR::BOUNCERBULLET after it has already been initialized and its state likely changed to something else. The same distinction applies to setting the object's xOrg/yOrg, creatorType, and creatorID properties as parameters to the function or later on. See jjBEHAVIORINTERFACE.\n"}, "jjAddParticle": {"prefix": "jjAddParticle", "body": "jjPARTICLE@ jjAddParticle(PARTICLE::Type type)", "description": "Creates and returns a new particle object, or a null pointer if unsuccessful. See the jjPARTICLE documentation above for full details.\n"}, "jjAddParticlePixelExplosion": {"prefix": "jjAddParticlePixelExplosion", "body": "void jjAddParticlePixelExplosion(float xPixel, float yPixel, int curFrame, int direction, int mode)", "description": "Creates an explosion of particles based on the shape and possibly colors of the specified curFrame. Use a mode value of 0 for a normal explosion, 1 for a fire explosion caused by a toaster or fire shield bullet, or 2 for an explosion caused by a special move. Values in the range of 15-255 will create fire explosions whose particles will use palette index equal to mode - this effect is currently used by weapons such as powered-up toaster and laser shield to create blue explosions. Value 14 creates a fire explosion whose particles use individually random colors. Values in the range of 3-13 and higher than 255 are undefined and - to preserve backward compatibility - shouldn't be used.\n"}, "jjAddParticleTileExplosion": {"prefix": "jjAddParticleTileExplosion", "body": "void jjAddParticleTileExplosion(uint16 xTile, uint16 yTile, uint16 tile, bool collapseSceneryStyle)", "description": "Creates four fragments of a tile falling from a specified location, like when destroying a destructable scenery block. Does not produce a sound effect; use jjSample or jjSamplePriority for that instead. The fragments will continue to be drawn until they fall off the screen. If you want more control over the fragments' positions, speeds, etc., use jjAddParticle instead.\n"}, "jjAlert": {"prefix": "jjAlert", "body": "void jjAlert(const string &in text, bool sendToAll = false, STRING::Size size = STRING::SMALL)", "description": "Writes text to the chatlogger window, and also displays it ingame for the local player. Uses size to determine size and positioning of text. If sendToAll is true and the function is called by the server, text will be sent to all clients as well.\n"}, "jjChat": {"prefix": "jjChat", "body": "void jjChat(const string &in text, bool teamchat = false)", "description": "In online play, sends text to the server as a line of chat. If text is a command (e.g. \"/spectate on\" or \"/ready\"), it will be interpreted as such to the extent that the local player is allowed to use that command in the server.\nIn offline play, JJ2+ will try to parse text as a command but will not display it as chat because there is no chat in offline mode. If you want to simulate chatting in a local game, use jjAlert instead.\n"}, "jjConsole": {"prefix": "jjConsole", "body": "void jjConsole(const string &in text, bool sendToAll = false)", "description": "Writes text as a console message to the chatlogger window, and also displays it ingame for the local player. If sendToAll is true and the function is called by the server, text will be sent to all clients as well.\n"}, "jjCos": {"prefix": "jjCos", "body": "float jjCos(uint angle)", "description": "Returns the cosine of angle with a range of 0.0-1.0 and a domain of 0-1023. Numbers outside the domain will be seemlessly moduloed. You may prefer AngelScript's native cos function.\n"}, "jjCRC32": {"prefix": "jjCRC32", "body": "uint jjCRC32(const jjSTREAM &in input, uint crc = 0)", "description": "Computes cyclic redundancy check of input with optional initial value crc. The checksum is computed according to the CRC-32 standard (as used in the zlib library and all JJ2 data files that use CRC).\n"}, "jjDebug": {"prefix": "jjDebug", "body": "void jjDebug(const string &in text, bool timestamp = false)", "description": "Writes text to the chatlogger window (but not ingame), but only if [General]AngelscriptDebug equals True in plus.ini. If timestamp is true, adds a timestamp before the text.\n"}, "jjDeleteObject": {"prefix": "jjDeleteObject", "body": "void jjDeleteObject(int objectID)", "description": "Permanently deletes an object. Like jjAddObject, this function is purely local in its scope.\n"}, "jjDrawPixel": {"prefix": "jjDrawPixel", "body": "void jjDrawPixel(float xPixel, float yPixel, uint8 color, SPRITE::Mode mode = SPRITE::NORMAL, int param = 0, int8 layerZ = 4, uint8 layerXY = 4, int8 playerID = -1)", "description": "Global function versions of the jjCANVAS methods as applied to onDrawLayer# hooks, differing in that the jjCANVAS methods are executed instantly, whereas these functions create instructions for JJ2 to perform the drawing operations later on, at the proper time. For example, a swinging platform will call jjDrawSpriteFromCurFrame many times over, once for each of its chain links, in the middle of its behavior function, but the links won't actually get drawn to the screen until later in the game cycle. Native JJ2 code uses this method for everything but HUD graphics.\nThe layerZ parameter specifies which layer, 1-8, the graphic should be drawn in front of as its Z-index. Unlike the jjCANVAS hooks, this can be used even for layers that don't have any tiles. JJ2 draws sprites exclusively(?) in front of layers 3, 4, and 5, but you're welcome to experiment.\nThe layerXY parameter specifies which layer, 1-8, the graphic should be positioned relative to the top left corner of. JJ2 always, always does layer 4, but you can vary it up a bit. Unfortunately the game cycle is ordered so that the layers besides layer 4 may actually move around a little after the instruction is registered but before the graphic is drawn, so these drawing instructions will always be one frame behind. Here the jjCANVAS methods have a clear advantage.\nIf the order of layers has been changed, then layerZ and layerXY's distance from 4 are their distance from the sprite layer, e.g. 3 means not necessarily jjLayers[3], but rather 4-1, the first layer in front of the sprite layer, whichever jjLAYER that happens to be.\nThe playerID parameter specifies which player should see the drawn graphic, 0-31, or -1 for all of them (restricted only to players with true isLocal). Drawing for one player a time is used by JJ2+ to, for example, draw fastfire pickups as green/blue or normal/powered-up depending on the charCurr and powerup[1] values of each jjPLAYER viewing them. When spectating, sprites are drawn for the player ID of the spectator, not the spectatee.\n"}, "jjDrawRectangle": {"prefix": "jjDrawRectangle", "body": "void jjDrawRectangle(float xPixel, float yPixel, int width, int height, uint8 color, SPRITE::Mode mode = SPRITE::NORMAL, int param = 0, int8 layerZ = 4, uint8 layerXY = 4, int8 playerID = -1)", "description": "Global function versions of the jjCANVAS methods as applied to onDrawLayer# hooks, differing in that the jjCANVAS methods are executed instantly, whereas these functions create instructions for JJ2 to perform the drawing operations later on, at the proper time. For example, a swinging platform will call jjDrawSpriteFromCurFrame many times over, once for each of its chain links, in the middle of its behavior function, but the links won't actually get drawn to the screen until later in the game cycle. Native JJ2 code uses this method for everything but HUD graphics.\nThe layerZ parameter specifies which layer, 1-8, the graphic should be drawn in front of as its Z-index. Unlike the jjCANVAS hooks, this can be used even for layers that don't have any tiles. JJ2 draws sprites exclusively(?) in front of layers 3, 4, and 5, but you're welcome to experiment.\nThe layerXY parameter specifies which layer, 1-8, the graphic should be positioned relative to the top left corner of. JJ2 always, always does layer 4, but you can vary it up a bit. Unfortunately the game cycle is ordered so that the layers besides layer 4 may actually move around a little after the instruction is registered but before the graphic is drawn, so these drawing instructions will always be one frame behind. Here the jjCANVAS methods have a clear advantage.\nIf the order of layers has been changed, then layerZ and layerXY's distance from 4 are their distance from the sprite layer, e.g. 3 means not necessarily jjLayers[3], but rather 4-1, the first layer in front of the sprite layer, whichever jjLAYER that happens to be.\nThe playerID parameter specifies which player should see the drawn graphic, 0-31, or -1 for all of them (restricted only to players with true isLocal). Drawing for one player a time is used by JJ2+ to, for example, draw fastfire pickups as green/blue or normal/powered-up depending on the charCurr and powerup[1] values of each jjPLAYER viewing them. When spectating, sprites are drawn for the player ID of the spectator, not the spectatee.\n"}, "jjDrawResizedSprite": {"prefix": "jjDrawResizedSprite", "body": "void jjDrawResizedSprite(float xPixel, float yPixel, int setID, uint8 animation, uint8 frame, float xScale, float yScale, SPRITE::Mode mode = SPRITE::NORMAL, int param = 0, int8 layerZ = 4, uint8 layerXY = 4, int8 playerID = -1)", "description": "Global function versions of the jjCANVAS methods as applied to onDrawLayer# hooks, differing in that the jjCANVAS methods are executed instantly, whereas these functions create instructions for JJ2 to perform the drawing operations later on, at the proper time. For example, a swinging platform will call jjDrawSpriteFromCurFrame many times over, once for each of its chain links, in the middle of its behavior function, but the links won't actually get drawn to the screen until later in the game cycle. Native JJ2 code uses this method for everything but HUD graphics.\nThe layerZ parameter specifies which layer, 1-8, the graphic should be drawn in front of as its Z-index. Unlike the jjCANVAS hooks, this can be used even for layers that don't have any tiles. JJ2 draws sprites exclusively(?) in front of layers 3, 4, and 5, but you're welcome to experiment.\nThe layerXY parameter specifies which layer, 1-8, the graphic should be positioned relative to the top left corner of. JJ2 always, always does layer 4, but you can vary it up a bit. Unfortunately the game cycle is ordered so that the layers besides layer 4 may actually move around a little after the instruction is registered but before the graphic is drawn, so these drawing instructions will always be one frame behind. Here the jjCANVAS methods have a clear advantage.\nIf the order of layers has been changed, then layerZ and layerXY's distance from 4 are their distance from the sprite layer, e.g. 3 means not necessarily jjLayers[3], but rather 4-1, the first layer in front of the sprite layer, whichever jjLAYER that happens to be.\nThe playerID parameter specifies which player should see the drawn graphic, 0-31, or -1 for all of them (restricted only to players with true isLocal). Drawing for one player a time is used by JJ2+ to, for example, draw fastfire pickups as green/blue or normal/powered-up depending on the charCurr and powerup[1] values of each jjPLAYER viewing them. When spectating, sprites are drawn for the player ID of the spectator, not the spectatee.\n"}, "jjDrawResizedSpriteFromCurFrame": {"prefix": "jjDrawResizedSpriteFromCurFrame", "body": "void jjDrawResizedSpriteFromCurFrame(float xPixel, float yPixel, uint sprite, float xScale, float yScale, SPRITE::Mode mode = SPRITE::NORMAL, int param = 0, int8 layerZ = 4, uint8 layerXY = 4, int8 playerID = -1)", "description": "Global function versions of the jjCANVAS methods as applied to onDrawLayer# hooks, differing in that the jjCANVAS methods are executed instantly, whereas these functions create instructions for JJ2 to perform the drawing operations later on, at the proper time. For example, a swinging platform will call jjDrawSpriteFromCurFrame many times over, once for each of its chain links, in the middle of its behavior function, but the links won't actually get drawn to the screen until later in the game cycle. Native JJ2 code uses this method for everything but HUD graphics.\nThe layerZ parameter specifies which layer, 1-8, the graphic should be drawn in front of as its Z-index. Unlike the jjCANVAS hooks, this can be used even for layers that don't have any tiles. JJ2 draws sprites exclusively(?) in front of layers 3, 4, and 5, but you're welcome to experiment.\nThe layerXY parameter specifies which layer, 1-8, the graphic should be positioned relative to the top left corner of. JJ2 always, always does layer 4, but you can vary it up a bit. Unfortunately the game cycle is ordered so that the layers besides layer 4 may actually move around a little after the instruction is registered but before the graphic is drawn, so these drawing instructions will always be one frame behind. Here the jjCANVAS methods have a clear advantage.\nIf the order of layers has been changed, then layerZ and layerXY's distance from 4 are their distance from the sprite layer, e.g. 3 means not necessarily jjLayers[3], but rather 4-1, the first layer in front of the sprite layer, whichever jjLAYER that happens to be.\nThe playerID parameter specifies which player should see the drawn graphic, 0-31, or -1 for all of them (restricted only to players with true isLocal). Drawing for one player a time is used by JJ2+ to, for example, draw fastfire pickups as green/blue or normal/powered-up depending on the charCurr and powerup[1] values of each jjPLAYER viewing them. When spectating, sprites are drawn for the player ID of the spectator, not the spectatee.\n"}, "jjDrawRotatedSprite": {"prefix": "jjDrawRotatedSprite", "body": "void jjDrawRotatedSprite(float xPixel, float yPixel, int setID, uint8 animation, uint8 frame, int angle, float xScale = 1, float yScale = 1, SPRITE::Mode mode = SPRITE::NORMAL, int param = 0, int8 layerZ = 4, uint8 layerXY = 4, int8 playerID = -1)", "description": "Global function versions of the jjCANVAS methods as applied to onDrawLayer# hooks, differing in that the jjCANVAS methods are executed instantly, whereas these functions create instructions for JJ2 to perform the drawing operations later on, at the proper time. For example, a swinging platform will call jjDrawSpriteFromCurFrame many times over, once for each of its chain links, in the middle of its behavior function, but the links won't actually get drawn to the screen until later in the game cycle. Native JJ2 code uses this method for everything but HUD graphics.\nThe layerZ parameter specifies which layer, 1-8, the graphic should be drawn in front of as its Z-index. Unlike the jjCANVAS hooks, this can be used even for layers that don't have any tiles. JJ2 draws sprites exclusively(?) in front of layers 3, 4, and 5, but you're welcome to experiment.\nThe layerXY parameter specifies which layer, 1-8, the graphic should be positioned relative to the top left corner of. JJ2 always, always does layer 4, but you can vary it up a bit. Unfortunately the game cycle is ordered so that the layers besides layer 4 may actually move around a little after the instruction is registered but before the graphic is drawn, so these drawing instructions will always be one frame behind. Here the jjCANVAS methods have a clear advantage.\nIf the order of layers has been changed, then layerZ and layerXY's distance from 4 are their distance from the sprite layer, e.g. 3 means not necessarily jjLayers[3], but rather 4-1, the first layer in front of the sprite layer, whichever jjLAYER that happens to be.\nThe playerID parameter specifies which player should see the drawn graphic, 0-31, or -1 for all of them (restricted only to players with true isLocal). Drawing for one player a time is used by JJ2+ to, for example, draw fastfire pickups as green/blue or normal/powered-up depending on the charCurr and powerup[1] values of each jjPLAYER viewing them. When spectating, sprites are drawn for the player ID of the spectator, not the spectatee.\n"}, "jjDrawRotatedSpriteFromCurFrame": {"prefix": "jjDrawRotatedSpriteFromCurFrame", "body": "void jjDrawRotatedSpriteFromCurFrame(float xPixel, float yPixel, uint sprite, int angle, float xScale = 1, float yScale = 1, SPRITE::Mode mode = SPRITE::NORMAL, int param = 0, int8 layerZ = 4, uint8 layerXY = 4, int8 playerID = -1)", "description": "Global function versions of the jjCANVAS methods as applied to onDrawLayer# hooks, differing in that the jjCANVAS methods are executed instantly, whereas these functions create instructions for JJ2 to perform the drawing operations later on, at the proper time. For example, a swinging platform will call jjDrawSpriteFromCurFrame many times over, once for each of its chain links, in the middle of its behavior function, but the links won't actually get drawn to the screen until later in the game cycle. Native JJ2 code uses this method for everything but HUD graphics.\nThe layerZ parameter specifies which layer, 1-8, the graphic should be drawn in front of as its Z-index. Unlike the jjCANVAS hooks, this can be used even for layers that don't have any tiles. JJ2 draws sprites exclusively(?) in front of layers 3, 4, and 5, but you're welcome to experiment.\nThe layerXY parameter specifies which layer, 1-8, the graphic should be positioned relative to the top left corner of. JJ2 always, always does layer 4, but you can vary it up a bit. Unfortunately the game cycle is ordered so that the layers besides layer 4 may actually move around a little after the instruction is registered but before the graphic is drawn, so these drawing instructions will always be one frame behind. Here the jjCANVAS methods have a clear advantage.\nIf the order of layers has been changed, then layerZ and layerXY's distance from 4 are their distance from the sprite layer, e.g. 3 means not necessarily jjLayers[3], but rather 4-1, the first layer in front of the sprite layer, whichever jjLAYER that happens to be.\nThe playerID parameter specifies which player should see the drawn graphic, 0-31, or -1 for all of them (restricted only to players with true isLocal). Drawing for one player a time is used by JJ2+ to, for example, draw fastfire pickups as green/blue or normal/powered-up depending on the charCurr and powerup[1] values of each jjPLAYER viewing them. When spectating, sprites are drawn for the player ID of the spectator, not the spectatee.\n"}, "jjDrawSprite": {"prefix": "jjDrawSprite", "body": "void jjDrawSprite(float xPixel, float yPixel, int setID, uint8 animation, uint8 frame, int direction = 0, SPRITE::Mode mode = SPRITE::NORMAL, int param = 0, int8 layerZ = 4, uint8 layerXY = 4, int8 playerID = -1)", "description": "Global function versions of the jjCANVAS methods as applied to onDrawLayer# hooks, differing in that the jjCANVAS methods are executed instantly, whereas these functions create instructions for JJ2 to perform the drawing operations later on, at the proper time. For example, a swinging platform will call jjDrawSpriteFromCurFrame many times over, once for each of its chain links, in the middle of its behavior function, but the links won't actually get drawn to the screen until later in the game cycle. Native JJ2 code uses this method for everything but HUD graphics.\nThe layerZ parameter specifies which layer, 1-8, the graphic should be drawn in front of as its Z-index. Unlike the jjCANVAS hooks, this can be used even for layers that don't have any tiles. JJ2 draws sprites exclusively(?) in front of layers 3, 4, and 5, but you're welcome to experiment.\nThe layerXY parameter specifies which layer, 1-8, the graphic should be positioned relative to the top left corner of. JJ2 always, always does layer 4, but you can vary it up a bit. Unfortunately the game cycle is ordered so that the layers besides layer 4 may actually move around a little after the instruction is registered but before the graphic is drawn, so these drawing instructions will always be one frame behind. Here the jjCANVAS methods have a clear advantage.\nIf the order of layers has been changed, then layerZ and layerXY's distance from 4 are their distance from the sprite layer, e.g. 3 means not necessarily jjLayers[3], but rather 4-1, the first layer in front of the sprite layer, whichever jjLAYER that happens to be.\nThe playerID parameter specifies which player should see the drawn graphic, 0-31, or -1 for all of them (restricted only to players with true isLocal). Drawing for one player a time is used by JJ2+ to, for example, draw fastfire pickups as green/blue or normal/powered-up depending on the charCurr and powerup[1] values of each jjPLAYER viewing them. When spectating, sprites are drawn for the player ID of the spectator, not the spectatee.\n"}, "jjDrawSpriteFromCurFrame": {"prefix": "jjDrawSpriteFromCurFrame", "body": "void jjDrawSpriteFromCurFrame(float xPixel, float yPixel, uint sprite, int direction = 0, SPRITE::Mode mode = SPRITE::NORMAL, int param = 0, int8 layerZ = 4, uint8 layerXY = 4, int8 playerID = -1)", "description": "Global function versions of the jjCANVAS methods as applied to onDrawLayer# hooks, differing in that the jjCANVAS methods are executed instantly, whereas these functions create instructions for JJ2 to perform the drawing operations later on, at the proper time. For example, a swinging platform will call jjDrawSpriteFromCurFrame many times over, once for each of its chain links, in the middle of its behavior function, but the links won't actually get drawn to the screen until later in the game cycle. Native JJ2 code uses this method for everything but HUD graphics.\nThe layerZ parameter specifies which layer, 1-8, the graphic should be drawn in front of as its Z-index. Unlike the jjCANVAS hooks, this can be used even for layers that don't have any tiles. JJ2 draws sprites exclusively(?) in front of layers 3, 4, and 5, but you're welcome to experiment.\nThe layerXY parameter specifies which layer, 1-8, the graphic should be positioned relative to the top left corner of. JJ2 always, always does layer 4, but you can vary it up a bit. Unfortunately the game cycle is ordered so that the layers besides layer 4 may actually move around a little after the instruction is registered but before the graphic is drawn, so these drawing instructions will always be one frame behind. Here the jjCANVAS methods have a clear advantage.\nIf the order of layers has been changed, then layerZ and layerXY's distance from 4 are their distance from the sprite layer, e.g. 3 means not necessarily jjLayers[3], but rather 4-1, the first layer in front of the sprite layer, whichever jjLAYER that happens to be.\nThe playerID parameter specifies which player should see the drawn graphic, 0-31, or -1 for all of them (restricted only to players with true isLocal). Drawing for one player a time is used by JJ2+ to, for example, draw fastfire pickups as green/blue or normal/powered-up depending on the charCurr and powerup[1] values of each jjPLAYER viewing them. When spectating, sprites are drawn for the player ID of the spectator, not the spectatee.\n"}, "jjDrawString": {"prefix": "jjDrawString", "body": "void jjDrawString(float xPixel, float yPixel, const string &in text, const jjANIMATION &in animation, STRING::Mode mode = STRING::NORMAL, uint8 param = 0, int8 layerZ = 4, uint8 layerXY = 4, int8 playerID = -1)", "description": "Global function versions of the jjCANVAS methods as applied to onDrawLayer# hooks, differing in that the jjCANVAS methods are executed instantly, whereas these functions create instructions for JJ2 to perform the drawing operations later on, at the proper time. For example, a swinging platform will call jjDrawSpriteFromCurFrame many times over, once for each of its chain links, in the middle of its behavior function, but the links won't actually get drawn to the screen until later in the game cycle. Native JJ2 code uses this method for everything but HUD graphics.\nThe layerZ parameter specifies which layer, 1-8, the graphic should be drawn in front of as its Z-index. Unlike the jjCANVAS hooks, this can be used even for layers that don't have any tiles. JJ2 draws sprites exclusively(?) in front of layers 3, 4, and 5, but you're welcome to experiment.\nThe layerXY parameter specifies which layer, 1-8, the graphic should be positioned relative to the top left corner of. JJ2 always, always does layer 4, but you can vary it up a bit. Unfortunately the game cycle is ordered so that the layers besides layer 4 may actually move around a little after the instruction is registered but before the graphic is drawn, so these drawing instructions will always be one frame behind. Here the jjCANVAS methods have a clear advantage.\nIf the order of layers has been changed, then layerZ and layerXY's distance from 4 are their distance from the sprite layer, e.g. 3 means not necessarily jjLayers[3], but rather 4-1, the first layer in front of the sprite layer, whichever jjLAYER that happens to be.\nThe playerID parameter specifies which player should see the drawn graphic, 0-31, or -1 for all of them (restricted only to players with true isLocal). Drawing for one player a time is used by JJ2+ to, for example, draw fastfire pickups as green/blue or normal/powered-up depending on the charCurr and powerup[1] values of each jjPLAYER viewing them. When spectating, sprites are drawn for the player ID of the spectator, not the spectatee.\n"}, "jjDrawSwingingVineSpriteFromCurFrame": {"prefix": "jjDrawSwingingVineSpriteFromCurFrame", "body": "void jjDrawSwingingVineSpriteFromCurFrame(float xPixel, float yPixel, uint sprite, int length, int curvature, SPRITE::Mode mode = SPRITE::NORMAL, int param = 0, int8 layerZ = 4, uint8 layerXY = 4, int8 playerID = -1)", "description": "Global function versions of the jjCANVAS methods as applied to onDrawLayer# hooks, differing in that the jjCANVAS methods are executed instantly, whereas these functions create instructions for JJ2 to perform the drawing operations later on, at the proper time. For example, a swinging platform will call jjDrawSpriteFromCurFrame many times over, once for each of its chain links, in the middle of its behavior function, but the links won't actually get drawn to the screen until later in the game cycle. Native JJ2 code uses this method for everything but HUD graphics.\nThe layerZ parameter specifies which layer, 1-8, the graphic should be drawn in front of as its Z-index. Unlike the jjCANVAS hooks, this can be used even for layers that don't have any tiles. JJ2 draws sprites exclusively(?) in front of layers 3, 4, and 5, but you're welcome to experiment.\nThe layerXY parameter specifies which layer, 1-8, the graphic should be positioned relative to the top left corner of. JJ2 always, always does layer 4, but you can vary it up a bit. Unfortunately the game cycle is ordered so that the layers besides layer 4 may actually move around a little after the instruction is registered but before the graphic is drawn, so these drawing instructions will always be one frame behind. Here the jjCANVAS methods have a clear advantage.\nIf the order of layers has been changed, then layerZ and layerXY's distance from 4 are their distance from the sprite layer, e.g. 3 means not necessarily jjLayers[3], but rather 4-1, the first layer in front of the sprite layer, whichever jjLAYER that happens to be.\nThe playerID parameter specifies which player should see the drawn graphic, 0-31, or -1 for all of them (restricted only to players with true isLocal). Drawing for one player a time is used by JJ2+ to, for example, draw fastfire pickups as green/blue or normal/powered-up depending on the charCurr and powerup[1] values of each jjPLAYER viewing them. When spectating, sprites are drawn for the player ID of the spectator, not the spectatee.\n"}, "jjDrawTile": {"prefix": "jjDrawTile", "body": "void jjDrawTile(float xPixel, float yPixel, uint16 tile, TILE::Quadrant tileQuadrant = TILE::ALLQUADRANTS, int8 layerZ = 4, uint8 layerXY = 4, int8 playerID = -1)", "description": "Global function versions of the jjCANVAS methods as applied to onDrawLayer# hooks, differing in that the jjCANVAS methods are executed instantly, whereas these functions create instructions for JJ2 to perform the drawing operations later on, at the proper time. For example, a swinging platform will call jjDrawSpriteFromCurFrame many times over, once for each of its chain links, in the middle of its behavior function, but the links won't actually get drawn to the screen until later in the game cycle. Native JJ2 code uses this method for everything but HUD graphics.\nThe layerZ parameter specifies which layer, 1-8, the graphic should be drawn in front of as its Z-index. Unlike the jjCANVAS hooks, this can be used even for layers that don't have any tiles. JJ2 draws sprites exclusively(?) in front of layers 3, 4, and 5, but you're welcome to experiment.\nThe layerXY parameter specifies which layer, 1-8, the graphic should be positioned relative to the top left corner of. JJ2 always, always does layer 4, but you can vary it up a bit. Unfortunately the game cycle is ordered so that the layers besides layer 4 may actually move around a little after the instruction is registered but before the graphic is drawn, so these drawing instructions will always be one frame behind. Here the jjCANVAS methods have a clear advantage.\nIf the order of layers has been changed, then layerZ and layerXY's distance from 4 are their distance from the sprite layer, e.g. 3 means not necessarily jjLayers[3], but rather 4-1, the first layer in front of the sprite layer, whichever jjLAYER that happens to be.\nThe playerID parameter specifies which player should see the drawn graphic, 0-31, or -1 for all of them (restricted only to players with true isLocal). Drawing for one player a time is used by JJ2+ to, for example, draw fastfire pickups as green/blue or normal/powered-up depending on the charCurr and powerup[1] values of each jjPLAYER viewing them. When spectating, sprites are drawn for the player ID of the spectator, not the spectatee.\n"}, "jjEnableEachASFunction": {"prefix": "jjEnableEachASFunction", "body": "void jjEnableEachASFunction()", "description": "Resets all 256 bools in jjEnabledASFunctions to true.\n\t\t\t\n"}, "jjEventGet": {"prefix": "jjEventGet", "body": "int jjEventGet(uint16 xTile, uint16 yTile)", "description": "Gets the Event ID at tile xTile,yTile, as seen in JCS.ini. This number can also be compared to the OBJECT or AREA constants listed in the appendix at the bottom of this file.\n"}, "jjEventSet": {"prefix": "jjEventSet", "body": "void jjEventSet(uint16 xTile, uint16 yTile, uint8 newEventID)", "description": "Sets the event at tile xTile,yTile to newEventID. Possible OBJECT or AREA constants are listed in the appendix at the bottom of this file.\nCaution: this is a permanent change and will subsist even after death in offline play.\n"}, "jjGenerateSettableTileArea": {"prefix": "jjGenerateSettableTileArea", "body": "void jjGenerateSettableTileArea(uint8 layer, int xTile, int yTile, int width, int height)", "description": "Shortcut global function for jjLAYER::generateSettableTileArea on the same-indexed jjLayers objects.\n"}, "jjGetFadeColors": {"prefix": "jjGetFadeColors", "body": "jjPALCOLOR jjGetFadeColors()", "description": "Calls and returns the result of jjLayers[8].getFadeColor().\n"}, "jjGetModOrder": {"prefix": "jjGetModOrder", "body": "int jjGetModOrder()", "description": "Returns the current order in the currently playing module music, or -1 if the currently playing music is not a module, a module not handled by BASS or no music is playing.\n"}, "jjGetModRow": {"prefix": "jjGetModRow", "body": "int jjGetModRow()", "description": "Returns the current row in the currently playing module music, or -1 if the currently playing music is not a module, a module not handled by BASS or no music is playing.\n"}, "jjGetModSpeed": {"prefix": "jjGetModSpeed", "body": "int jjGetModSpeed()", "description": "Returns the \"speed\" parameter (ticks per row) of the currently playing module music, or -1 if the currently playing music is not a module, a module not handled by BASS or no music is playing.\n"}, "jjGetModTempo": {"prefix": "jjGetModTempo", "body": "int jjGetModTempo()", "description": "Returns the tempo of the currently playing module music, or -1 if the currently playing music is not a module, a module not handled by BASS or no music is playing.\n"}, "jjGetPublicInterface": {"prefix": "jjGetPublicInterface", "body": "jjPUBLICINTERFACE@ jjGetPublicInterface(const string &in moduleName)", "description": "If moduleName is a name of a currently running script module that registers the onGetPublicInterface hook, calls that hook and returns its result, otherwise returns null. Module names are the same as names of files that contain the modules, including the file extension \".j2as\" or \".mut\", and the comparison is not case sensitive. In the target module, onGetPublicInterface must be a global function with the following signature:\n\t\t\tjjPUBLICINTERFACE@ onGetPublicInterface()\n\t\t\tThe exact return type may differ as long as it is a handle to a class or interface that implements jjPUBLICINTERFACE. This function should not be called earlier than in onLevelLoad, i.e. it should not be used to initialize a global variable, as the target module may not be available at that point yet. More details about usage of this function may be found in the dedicated section of this document.\n"}, "jjGetStaticTile": {"prefix": "jjGetStaticTile", "body": "uint16 jjGetStaticTile(uint16 tileID)", "description": "If tileID is animated, i.e. (tileID & TILE::ANIMATED) != 0, returns tile ID of the current animation frame of the tile corresponding to tileID. Otherwise returns tileID.\nLike animated tiles themselves, this function relies on system time rather than game ticks, which means that subsequent calls during the same frame may return different results, and that results may insignificantly differ compared to the effective state of the animation. This behavior may change in the future.\nThis function never returns tile ID of animated tiles. If its result would be animated, which may happen in levels edited by other means than JCS, the function is called recursively on the result until a static tile is obtained.\n"}, "jjGetStringWidth": {"prefix": "jjGetStringWidth", "body": "int jjGetStringWidth(const string &in text, const jjANIMATION &in animation, const jjTEXTAPPEARANCE &in style)", "description": "Returns width, in pixels, that text would have if it was drawn in specified size (or animation) and style. If style allows multi-line text and text is multi-line, width of the longest line is returned.\n"}, "jjIsValidCheat": {"prefix": "jjIsValidCheat", "body": "bool jjIsValidCheat(const string &in text)", "description": "Returns true if text is interpreted by the game as a cheat code.\n"}, "jjKillObject": {"prefix": "jjKillObject", "body": "void jjKillObject(int objectID)", "description": "Permanently deletes an object, but first calls its native STATE::KILL code (if any). Probably functionally identical to jjDeleteObject in most cases, but might work a little better sometimes.\n"}, "jjLayerOrderGet": {"prefix": "jjLayerOrderGet", "body": "array@ jjLayerOrderGet()", "description": "A pair of functions for accessing or changing the ordered list of layers drawn to the screen. (In most cases it should be simpler to keep the jjLAYER@ array around in your script as a variable, rather than retrieving it using jjLayerOrderGet, but that function is there just in case you need it.) The arrays are ordered so that the first jjLAYER is in front and the last is in back, meaning that writing jjLayerOrderSet(array = {jjLayers[1], jjLayers[2], jjLayers[3], jjLayers[4], jjLayers[5], jjLayers[6], jjLayers[7], jjLayers[8]}); should have no visible effect in a previously unaltered level.\nThe array passed to jjLayerOrderSet must include jjLayers[4] (the gameplay/sprite layer) as one of its entries and must not include any null handles, or else the function will return false and cause a debug error. Including multiple handles to the same jjLAYER is allowed but not very useful.\nFollowing a call to jjLayerOrderSet, it takes some extra thought and understanding to figure out how to refer to individual layers in other sections of the code. Specifically there are two different patterns (which happen to come to the same thing if the layer order is never changed at all):\nAll global properties or functions with a 1-indexed layer argument\u00e2\u20ac\u201de.g. jjLayers, jjLayerYSpeed, or jjTileGet\u00e2\u20ac\u201d refer exclusively to the level's original eight layers as defined in the level editor. jjLayers[1] will always refer to the same layer no matter which layer ends up being drawn foremost in the foreground. To read or write the size, speeds, etc. of any layer besides those eight, use the properties and methods of its jjLAYER instance. Similarly, the jjCANVAS onDrawLayer# hooks are (currently) only available for those original eight layers, and jjLayers[1] will always call onDrawLayer1 (if defined) no matter its position in the drawing order.\nWhen calling jjDrawSprite or any of its related functions with their layerZ and layerXY arguments, those arguments refer to the list of layers from jjLayerOrderGet, relative to Layer 4's position in that list. The default layerZ value is 4 and will always draw sprites to jjLayers[4]. If layerZ equals 3, 4-1, the sprite will be drawn to whichever jjLAYER is ordered one in front of jjLayers[4]. If 6, 4+2, the layer two behind jjLayers[4]. And so on. The same principle applies to jjWaterLayer.\n"}, "jjLayerOrderSet": {"prefix": "jjLayerOrderSet", "body": "bool jjLayerOrderSet(const array& in order)", "description": "A pair of functions for accessing or changing the ordered list of layers drawn to the screen. (In most cases it should be simpler to keep the jjLAYER@ array around in your script as a variable, rather than retrieving it using jjLayerOrderGet, but that function is there just in case you need it.) The arrays are ordered so that the first jjLAYER is in front and the last is in back, meaning that writing jjLayerOrderSet(array = {jjLayers[1], jjLayers[2], jjLayers[3], jjLayers[4], jjLayers[5], jjLayers[6], jjLayers[7], jjLayers[8]}); should have no visible effect in a previously unaltered level.\nThe array passed to jjLayerOrderSet must include jjLayers[4] (the gameplay/sprite layer) as one of its entries and must not include any null handles, or else the function will return false and cause a debug error. Including multiple handles to the same jjLAYER is allowed but not very useful.\nFollowing a call to jjLayerOrderSet, it takes some extra thought and understanding to figure out how to refer to individual layers in other sections of the code. Specifically there are two different patterns (which happen to come to the same thing if the layer order is never changed at all):\nAll global properties or functions with a 1-indexed layer argument\u00e2\u20ac\u201de.g. jjLayers, jjLayerYSpeed, or jjTileGet\u00e2\u20ac\u201d refer exclusively to the level's original eight layers as defined in the level editor. jjLayers[1] will always refer to the same layer no matter which layer ends up being drawn foremost in the foreground. To read or write the size, speeds, etc. of any layer besides those eight, use the properties and methods of its jjLAYER instance. Similarly, the jjCANVAS onDrawLayer# hooks are (currently) only available for those original eight layers, and jjLayers[1] will always call onDrawLayer1 (if defined) no matter its position in the drawing order.\nWhen calling jjDrawSprite or any of its related functions with their layerZ and layerXY arguments, those arguments refer to the list of layers from jjLayerOrderGet, relative to Layer 4's position in that list. The default layerZ value is 4 and will always draw sprites to jjLayers[4]. If layerZ equals 3, 4-1, the sprite will be drawn to whichever jjLAYER is ordered one in front of jjLayers[4]. If 6, 4+2, the layer two behind jjLayers[4]. And so on. The same principle applies to jjWaterLayer.\n"}, "jjLayersFromLevel": {"prefix": "jjLayersFromLevel", "body": "array@ jjLayersFromLevel(const string &in filename, const array &in layerIDs, int tileIDAdjustmentFactor = 0)", "description": "Returns an array containing a number of handles of new jjLAYER instances built from the layers defined in the level filename, specifically those requested in the 1-indexed layerIDs. (Passing numbers not in the range of 1\u00e2\u20ac\u201c8 in layerIDs is undefined behavior.) For example, jjLayersFromLevel(\"castle1.j2l\", array = {5,6}); returns an array with two layers, one of width 23 and height 25 and the other of width 20 and height 11, containing different sets of pillars as defined in Layer 5 and Layer 6 of castle1.j2l. These new layer objects may then be inserted into the set of layers drawn to the screen by use of jjLayerOrderSet.\nBy default, the tile IDs of the tiles in these layers will be unchanged, meaning that unless the tileset used by the level filename is the same as is used by this level, the results will likely look very peculiar. (Similarly, any animated tiles used in those layers should probably match those used in this level.) In fact, you may want to make a special unplayable level just for the sake of taking its miscellaneous background or foreground layers into this one (and if you do, remember to tick \"Hide level in Home Cooked Levels list\" in its level properties). Alternatively, the optional tileIDAdjustmentFactor parameter is a value added to the tile IDs of any non-zero, non-animated tiles in the layer/s imported from filename, so for instance, if tileIDAdjustmentFactor equals 10, then a series of tiles 5,6,0,0,3 would become 15,16,0,0,13. (This option is intended for use in conjunction with jjTilesFromTileset, though you may find other uses for it as well.)\nLike in other sections of JJ2+ code, levels saved in either the TSF or regular JCSes work equally well. It does not matter whether the level is passworded. If the file does not exist or does not have the file extension \".j2l\" then the returned array will have zero length. If the file is not a valid level then the game may or may not crash. As with other dependent files, it is recommended to use #pragma require if the level being mined for layers is not a default level.\n"}, "jjMaskedHLine": {"prefix": "jjMaskedHLine", "body": "bool jjMaskedHLine(int xPixel, int lineLength, int yPixel, uint8 layer)", "description": "Shortcut global functions for the same-named jjLAYER methods on the same-indexed jjLayers objects.\n"}, "jjMaskedPixel": {"prefix": "jjMaskedPixel", "body": "bool jjMaskedPixel(int xPixel, int yPixel, uint8 layer)", "description": "Shortcut global functions for the same-named jjLAYER methods on the same-indexed jjLayers objects.\n"}, "jjMaskedTopVLine": {"prefix": "jjMaskedTopVLine", "body": "int jjMaskedTopVLine(int xPixel, int yPixel, int lineLength, uint8 layer)", "description": "Shortcut global functions for the same-named jjLAYER methods on the same-indexed jjLayers objects.\n"}, "jjMaskedVLine": {"prefix": "jjMaskedVLine", "body": "bool jjMaskedVLine(int xPixel, int yPixel, int lineLength, uint8 layer)", "description": "Shortcut global functions for the same-named jjLAYER methods on the same-indexed jjLayers objects.\n"}, "jjMusicLoad": {"prefix": "jjMusicLoad", "body": "bool jjMusicLoad(string filename, bool forceReload = false, bool temporary = false)", "description": "Loads and starts playing a new music file, of any type supported by JJ2+. Returns false if the file cannot be found in either the main game folder or the cache subfolder, or if the specified music file is already playing and forceReload is false. The temporary parameter is useful only in local single player games, where it is used to load a music file only until the player's death, at which point the non-temporary music file will resume playing: this is how the Activate Boss event works.\n"}, "jjMusicPause": {"prefix": "jjMusicPause", "body": "void jjMusicPause()", "description": "Pauses the current music track. May not work with .mp3 files.\n"}, "jjMusicPlay": {"prefix": "jjMusicPlay", "body": "void jjMusicPlay()", "description": "(Re)starts the current music track.\n"}, "jjMusicResume": {"prefix": "jjMusicResume", "body": "void jjMusicResume()", "description": "Resumes the current music track, once paused. May not work with .mp3 files.\n"}, "jjMusicStop": {"prefix": "jjMusicStop", "body": "void jjMusicStop()", "description": "Stops the current music track.\n"}, "jjNxt": {"prefix": "jjNxt", "body": "void jjNxt(const string& filename = \"\", bool warp = false, bool fast = false)", "description": "Ends the level and skips to the next one, or to filename if specified and of length>0. Only works in Single Player and Cooperative.\n"}, "jjParameterGet": {"prefix": "jjParameterGet", "body": "int jjParameterGet(uint16 xTile, uint16 yTile, int8 offset, int8 length)", "description": "Gets one of the parameters at tile xTile,yTile. Follow JCS.ini's lead in figuring out how to write the offset and length parameters.\nlength is the simplest: use the exact same formatting JCS.ini does. To get the speed of a belt event, for instance, length should be -8. To get the number of blue gems in a gem crate, length should be 4. And so on.\noffset is calculated by adding the absolute values of every parameter on the tile prior to the one you want. The first (bottommost) parameter will always have offset 0. To get the parameter \"Blue\" in Gem Crate, offset should be 8 (4+4). To get the Y-Speed of a Rotating Rock, offset should be 12 (8+abs(-4)). And so on.\nSet length to 2 and offset to -4 to get the difficulty of an event (normal, easy, hard, multiplayer-only).\n"}, "jjParameterSet": {"prefix": "jjParameterSet", "body": "void jjParameterSet(uint16 xTile, uint16 yTile, int8 offset, int8 length, int newValue)", "description": "Sets one of the parameters at tile xTile,yTile. length and offset work exactly as they do for jjParameterGet; the only change is newValue, which should be a valid number for the length setting. Trying to assign a negative number to an unsigned length parameter doesn't really make sense, for example, nor can you reasonably assign a newValue of 100 to a length of 3.\nNote that this is not quite as powerful as it may seem, since some objects read and process their parameters into memory when they are first created, rather than continually reading them again and again as the game continues. The function will however work fine for zones that affect the player, such as Warp or Sucker Tube or Wind, and it will also successfully set parameters for any such new objects created after the function is called.\nCaution: this is a permanent change and will subsist even after death in offline play.\n"}, "jjPlayersWithClientID": {"prefix": "jjPlayersWithClientID", "body": "array@ jjPlayersWithClientID(int clientID)", "description": "Convenience function; creates and returns an array containing handles of all active players with a given clientID. The result is an empty array if the client is not connected or if clientID is not a valid ID. The result is a null handle if the function is called by a client.\n"}, "jjPrint": {"prefix": "jjPrint", "body": "void jjPrint(const string &in text, bool timestamp = false)", "description": "Writes text to the chatlogger window but does not display it ingame. If timestamp is true, adds a timestamp before the text.\n"}, "jjRandom": {"prefix": "jjRandom", "body": "uint jjRandom()", "description": "Provides a random number.\n"}, "jjRegexIsValid": {"prefix": "jjRegexIsValid", "body": "bool jjRegexIsValid(const string &in expression)", "description": "Returns true if expression is a valid regular expression and false otherwise. This is the only regex function that doesn't cause debug errors when the input is an invalid expression and as such it should be always used before calling other regex functions when expression comes from an untrusted source (such as from user input rather than from a constant string in the script). Expressions will be parsed according to modified ECMAScript regular expression grammar.\n"}, "jjRegexMatch": {"prefix": "jjRegexMatch", "body": "bool jjRegexMatch(const string &in text, const string &in expression, bool ignoreCase = false)", "description": "Returns true if expression is a valid regular expression that matches text entirely and false if no match is found. Where the second overload is used, results will contain match results in a standard order. If ignoreCase is true, the matching will be case insensitive. If expression is not a valid regular expression, a debug message will be printed to the chatlogger and the return value will be undefined. In future versions of JJ2+ this might have further consequences including complete script shutdown. For this reason, jjRegexIsValid should always be used to validate untrusted input. Note that this function only returns true if expression matches the entire string, whereas jjRegexSearch accepts substring matches.\n"}, "jjRegexReplace": {"prefix": "jjRegexReplace", "body": "string jjRegexReplace(const string &in text, const string &in expression, const string &in replacement, bool ignoreCase = false)", "description": "Returns a string that is the result of replacement of all substrings of text that are matched by expression with replacement. If ignoreCase is true, the matching will be case insensitive. Capture results ($1, $2, etc., $0 always being the entire matched substring) can be successfully used in the replacement string. If expression is not a valid regular expression, a debug message will be printed to the chatlogger and the return value will be undefined. In future versions of JJ2+ this might have further consequences including complete script shutdown. For this reason, jjRegexIsValid should always be used to validate untrusted input.\n"}, "jjRegexSearch": {"prefix": "jjRegexSearch", "body": "bool jjRegexSearch(const string &in text, const string &in expression, bool ignoreCase = false)", "description": "Returns true if expression is a valid regular expression that matches any substring of text and false if no match is found. Where the second overload is used, results will contain match results in a standard order. If ignoreCase is true, the matching will be case insensitive. If expression is not a valid regular expression, a debug message will be printed to the chatlogger and the return value will be undefined. In future versions of JJ2+ this might have further consequences including complete script shutdown. For this reason, jjRegexIsValid should always be used to validate untrusted input. Note that this function returns true if expression matches any character subsequence of text, whereas jjRegexMatch will only look for matches with the entire string.\n"}, "jjResetWaterGradient": {"prefix": "jjResetWaterGradient", "body": "void jjResetWaterGradient()", "description": "Restores 16-bit water to its natural colors.\n"}, "jjSample": {"prefix": "jjSample", "body": "void jjSample(float xPixel, float yPixel, SOUND::Sample sample, int volume = 63, int frequency = 0)", "description": "Plays a sound from anims.j2a at pixel xPixel, yPixel. Possible values for sample are listed in the appendix at the bottom of this file.\nvolume ranges from 1-63, and 0 will default to 63. Higher values of frequency result in higher frequencies, or leaving it at 0 will use the sample's unique default frequency.\n"}, "jjSampleIsLoaded": {"prefix": "jjSampleIsLoaded", "body": "bool jjSampleIsLoaded(SOUND::Sample sample)", "description": "Returns whether sample is loaded or not.\n"}, "jjSampleLoad": {"prefix": "jjSampleLoad", "body": "bool jjSampleLoad(SOUND::Sample sample, string &in filename)", "description": "Attempts to load sample from a .wav file filename and returns true on success or false otherwise. If there is already a loaded sample corresponding to this SOUND::Sample constant, it will be overwritten.\n"}, "jjSampleLooped": {"prefix": "jjSampleLooped", "body": "int jjSampleLooped(float xPixel, float yPixel, SOUND::Sample sample, int channel, int volume = 63, int frequency = 0)", "description": "Plays a looped sound from anims.j2a at pixel xPixel, yPixel. For every source of sound (e.g. a jjOBJ instance), channel should be 0 on the first call and in later calls should be replaced with the value returned from the previous call of this function.\nvolume ranges from 1-63, and 0 will default to 63. Higher values of frequency result in higher frequencies, or leaving it at 0 will use the sample's unique default frequency.\n"}, "jjSamplePriority": {"prefix": "jjSamplePriority", "body": "void jjSamplePriority(SOUND::Sample sample)", "description": "Plays a sound from anims.j2a, no matter what any local players' positions are. This is the function used to play the sugar rush jingle. Possible values for sample are listed in the appendix at the bottom of this file.\n"}, "jjSendPacket": {"prefix": "jjSendPacket", "body": "bool jjSendPacket(jjSTREAM &in packet, int toClientID = 0, uint toScriptModuleID = jjScriptModuleID)", "description": "Sends packet from client to server (in case if you're a client) or from server to client (in case if you're a server). Returns true on success and false on failure. If toClientID is a positive value, the packet will be sent only to the client with the appropriate jjPLAYER::clientID. If it's negative, it will be sent to all clients with the exception of the one indicated by toClientID. Using the default value of 0 results in sending the packet to all clients. For a script to receive packet, you will need to declare an onReceive hook, which has the following signature:\n\t\t\tvoid onReceive(jjSTREAM &in packet, int fromClientID)\n\t\t\tNotice that packets can't be sent between two clients but only between the server and a client; if the function is called client-side, the toClientID argument is completely ignored. If a client is meant to send a packet to another client, they have to send the packet to the server first and the server should resend it to the other client from onReceive.\nIf there are multiple distinct script modules running (two or more mutators, or one mutator and a level's primary script), the packet will only be received by the module whose jjScriptModuleID global value matches the toScriptModuleID parameter. By leaving this parameter as the default value, you can ensure that a packet sent from foo.j2mut will always be read by (the onReceive hook defined in) foo.j2mut, rather than another, simultaneously running module that wouldn't know what to do with the data. Passing 0 instead will send the packet to the level's primary script (if any), and is rarely a good idea. Other values are even more rarely a good idea.\n"}, "jjSetDarknessColor": {"prefix": "jjSetDarknessColor", "body": "void jjSetDarknessColor(jjPALCOLOR color = jjPALCOLOR(0, 0, 0))", "description": "Sets the color of darkness used with ambient lighting.\n"}, "jjSetFadeColors": {"prefix": "jjSetFadeColors", "body": "void jjSetFadeColors(uint8 red, uint8 green, uint8 blue)", "description": "Sets the fade colors of the level's textured background, as seen in the Layer properties window for layer 8 in JCS. Has no effect if there is no textured background on layer 8.\nExactly equivalent to jjLayers[8].setFadeColor(color).\nA simpler one (or zero!) parameter version of the function also exists to set the fade colors to the same RGB values as used by one of the entries in jjPalette. This defaults to 207, which is the last color of the most common textured background gradient and thus, not infrequently, the fade color used in 8-bit color.\n"}, "jjSetLayerXSpeed": {"prefix": "jjSetLayerXSpeed", "body": "void jjSetLayerXSpeed(uint8 layerID, float newspeed, bool newSpeedIsAnAutoSpeed)", "description": "Shortcut global functions for setXSpeed and setYSpeed on the same-indexed jjLayers objects.\n"}, "jjSetLayerYSpeed": {"prefix": "jjSetLayerYSpeed", "body": "void jjSetLayerYSpeed(uint8 layerID, float newspeed, bool newSpeedIsAnAutoSpeed)", "description": "Shortcut global functions for setXSpeed and setYSpeed on the same-indexed jjLayers objects.\n"}, "jjSetModPosition": {"prefix": "jjSetModPosition", "body": "void jjSetModPosition(int order, int row, bool reset)", "description": "Jumps to a specific row of a specific order in the currently playing module file. If reset is true, also stops all notes and resets the module's global volume, tempo, etc. to their original values.\nCalling this function with an invalid order or row number, or while BASS is not playing a module file, will have no effect.\n"}, "jjSetModSpeed": {"prefix": "jjSetModSpeed", "body": "void jjSetModSpeed(uint8 speed)", "description": "Sets the \"speed\" of the currently playing module music file. Does nothing if BASS is not currently playing a module file. Note that the module may change its own speed, overwriting your change.\n"}, "jjSetModTempo": {"prefix": "jjSetModTempo", "body": "void jjSetModTempo(uint8 tempo)", "description": "Sets the tempo of the currently playing module music file. Does nothing if BASS is not currently playing a module file. Note that the module may change its own tempo, overwriting your change.\n"}, "jjSetWaterGradient": {"prefix": "jjSetWaterGradient", "body": "void jjSetWaterGradient(uint8 red1, uint8 green1, uint8 blue1, uint8 red2, uint8 green2, uint8 blue2)", "description": "Changes the colors used by water in 16-bit color. If no parameters are included, the gradient will be generated from palette entries 176 and 207 instead, the most typical textured background colors (and most of the colors used by 8-bit water).\n"}, "jjSetWaterLevel": {"prefix": "jjSetWaterLevel", "body": "void jjSetWaterLevel(float yPixel, bool instant)", "description": "Sets jjWaterTarget to yPixel. If instant is true, jjWaterLevel will also be set to yPixel; otherwise, it will move slowly up or down from its current height until it reaches its new target.\nCaution: this function is not identical to the Water Level event in JCS. The event measures in tiles, but this function measures in pixels. Multiply by thirty-two to get the same effect.\n"}, "jjSin": {"prefix": "jjSin", "body": "float jjSin(uint angle)", "description": "Returns the sine of angle with a range of 0.0-1.0 and a domain of 0-1023. Numbers outside the domain will be seemlessly moduloed. This is the sine function used by JJ2 for spinning platforms and the like, though you may prefer AngelScript's native sin function.\n"}, "jjSlideModChannelVolume": {"prefix": "jjSlideModChannelVolume", "body": "void jjSlideModChannelVolume(int channel, float volume, int milliseconds)", "description": "In currently playing module music, slide the volume of channel to volume over a chosen number of milliseconds. Does nothing if BASS is not currently playing a module file or channel does not exist. volume is 1.0 for the module's channel volume, 0.0 for silent. If you give a higher or lower value, the slide will stop when it reaches one of these boundaries. Volume slides continue while the music is paused. If you begin sliding the volume of a channel that is already sliding, the old slide will immediately stop.\n"}, "jjSpriteModeFirstFreeMapping": {"prefix": "jjSpriteModeFirstFreeMapping", "body": "int jjSpriteModeFirstFreeMapping()", "description": "Returns the minimum index from the range 0\u00e2\u20ac\u201c255 such that jjSpriteModeIsMappingUsed(index) is false, or -1 if none exist.\n"}, "jjSpriteModeGetColorMapping": {"prefix": "jjSpriteModeGetColorMapping", "body": "jjPAL@ jjSpriteModeGetColorMapping(uint8 index)", "description": "Returns a copy of the mapping provided as the rgbMapping argument during the most recent call to jjSpriteModeSetMapping with the same value of index. If the most recent call didn't provide the rgbMapping argument, instead the indexMapping argument is used in conjunction with jjPalette to determine the result. The returned handle is never null\u00e2\u20ac\u201deven if the mapping corresponding to index is unused, the returned handle is still a valid palette but all its colors are black.\n"}, "jjSpriteModeGetIndexMapping": {"prefix": "jjSpriteModeGetIndexMapping", "body": "array@ jjSpriteModeGetIndexMapping(uint8 index)", "description": "Returns a copy of the mapping provided as the indexMapping argument during the most recent call to jjSpriteModeSetMapping with the same value of index. The returned handle is never null and the array it holds is always of size 256. If the mapping corresponding to index is unused, all elements of the array will be 0.\n"}, "jjSpriteModeIsMappingUsed": {"prefix": "jjSpriteModeIsMappingUsed", "body": "bool jjSpriteModeIsMappingUsed(uint8 index)", "description": "Returns whether a mapping with the given index (as used by SPRITE::MAPPING and SPRITE::TRANSLUCENTMAPPING) has been previously successfully registered with use of jjSpriteModeSetMapping.\n"}, "jjSpriteModeSetMapping": {"prefix": "jjSpriteModeSetMapping", "body": "void jjSpriteModeSetMapping(uint8 index, const array &in indexMapping, const jjPAL &in rgbMapping)", "description": "Sets a mapping with the given index (as used by SPRITE::MAPPING and SPRITE::TRANSLUCENTMAPPING) to the provided values. indexMapping will be used in 8-bit color mode. If it is shorter than 256 elements, it will be padded with values corresponding to their indices (i.e., if an empty array is provided, the corresponding SPRITE::MAPPING will act exactly like SPRITE::NORMAL in 8-bit color mode). rgbMapping, if provided, will be used in 16-bit color mode, ignoring the level's palette\u00e2\u20ac\u201dotherwise indexMapping will be used, to the same effect as in 8-bit color mode.\n"}, "jjSpy": {"prefix": "jjSpy", "body": "void jjSpy(const string &in text)", "description": "Prints text to the game's built-in spy window activated by running it with the -spy command line parameter, and also writes it to your jazz2.log file.\n"}, "jjSwitchTrigger": {"prefix": "jjSwitchTrigger", "body": "bool jjSwitchTrigger(uint8 id)", "description": "Toggles jjTriggers[id] from true to false, or vice versa, like the \"switch\" parameter on the Trigger Zone and Trigger Crate events.\n"}, "jjTakeScreenshot": {"prefix": "jjTakeScreenshot", "body": "bool jjTakeScreenshot(const string &in filename = \"\")", "description": "Takes a screenshot of the game as if F12 was pressed. Returns true if the screenshot request was successfully handled without being dismissed by timing or other restrictions, otherwise returns false.\nThe optional parameter filename can be used to define a custom filename for the screenshot file to be saved. When a custom filename is passed as a parameter, the .png suffix can be omitted, since the suffix will be always ensured. Omitting the custom filename parameter or defining it as an empty string will make the game use the default pattern for screenshot filenames, like Jazz2-[level_filename]-001.png, etc.\nNote that this feature has restrictions on how often it can be used effectively. Calling it more often than once a second won't do anything and will cause the function to return false, as an indicator that the call to take a screenshot was dismissed. There is also a one second delay for using this function successfully after the user presses F12. This is due to the possibility of this feature being able to fill up available diskspace on the calling machine rapidly (and making the game too sluggish to play anyway).\nNote that this feature may only be used to save screenshots into the folder running JJ2 itself. Also, to avoid conflict with system reserved filenames, etc. all custom filenames receive an enforced prefix in their filename as Jazz2_as-, which also helps to differentiate custom screenshot filenames from the default ones (Jazz2-).\nNote that only legal characters for filenames may be used in the custom screenshot filenames to ensure their integrity. Using any illegal characters in the filename will result in the screenshot saving to fail and making this function return false.\n"}, "jjTileGet": {"prefix": "jjTileGet", "body": "uint16 jjTileGet(uint8 layer, int xTile, int yTile)", "description": "Shortcut global functions for the same-named jjLAYER methods on the same-indexed jjLayers objects.\n"}, "jjTileSet": {"prefix": "jjTileSet", "body": "uint16 jjTileSet(uint8 layer, int xTile, int yTile, uint16 newTile)", "description": "Shortcut global functions for the same-named jjLAYER methods on the same-indexed jjLayers objects.\n"}, "jjTilesFromTileset": {"prefix": "jjTilesFromTileset", "body": "bool jjTilesFromTileset(const string &in filename, uint firstTileID, uint tileCount, const array@ paletteColorMapping = null)", "description": "Opens the tileset filename, extracts tileCount tiles from it starting at tile ID firstTileID, and appends them to the end of the currently loaded tileset, increasing jjTileCount by tileCount. If paletteColorMapping is not null and is of length 256 or greater, it will be used to recolor the imported tiles in a way that better fits the palette you are currently using, e.g. pixels of color 10 will be changed to paletteColorMapping[10] instead. Returns false upon various reasons for failure.\njjTilesFromTileset is primarily intended to be combined with jjLayersFromLevel and jjLayerOrderSet, and the three should ideally be called in that order, so that jjLayersFromLevel has the right tiles to use in its new layers. Here is a sample script that imports the background pillars from Dungeon Dilemma (into any level using any tileset) and recolors them to use colors from the textured background:\n\t\t\tvoid onLevelLoad() {\n\tconst int oldTileCount = jjTileCount; //the number of tiles in the level's tileset before jjTilesFromTileset increases the number\n\tarray pillarColorMapping(256);\n\tfor (int i = 0; i < 16; ++i)\n\t\tpillarColorMapping[i + 128] = i + 192; //map pillars' colors (stored in palette indices 128 through 143) to the (second row of) textured background colors\n\tjjTilesFromTileset( //appends tiles to the end of the internal copy of the tileset used by the current level\n\t\t\"Castle1.j2t\", //filename to take tiles from\n\t\t420, //first tile ID in tileset to take\n\t\t60, //number of tiles to take\n\t\tpillarColorMapping //an array(256) that maps colors in the source tileset to colors in the destination tileset, here only working on a single 16-color gradient because that's all that is used in those particular two layers\n\t);\n\tarray castleLayers = jjLayersFromLevel( //builds new jjLAYER instances from the layers defined in this level\n\t\t\"Castle1.j2l\", //filename to take layers from\n\t\tarray = {5,6}, //which layers to grab\n\t\toldTileCount - 420 //a number to offset the non-zero tileIDs by: the pillars started at tile 420 in castle1.j2t, but here start at the end of the old tileset, aka oldTileCount\n\t);\n\tjjLayerOrderSet(array = {jjLayers[1], jjLayers[2], jjLayers[3], jjLayers[4], castleLayers[0], castleLayers[1], jjLayers[5], jjLayers[6], jjLayers[7], jjLayers[8]}); //insert the two layers from castle1.j2l between Layer 4 and Layer 5\n}\n"}, "jjTriggerRock": {"prefix": "jjTriggerRock", "body": "void jjTriggerRock(uint8 id)", "description": "Activates all Rotating Rock events with the \"RockID\" parameter set to id, exactly like the Trigger Rock event.\n"}, "jjUnixTimeMs": {"prefix": "jjUnixTimeMs", "body": "uint64 jjUnixTimeMs()", "description": "Returns unix time in milliseconds, i.e. the number of milliseconds that have elapsed since 00:00:00 UTC, Thursday, 1 January 1970, not counting leap seconds.\n"}, "jjUnixTimeSec": {"prefix": "jjUnixTimeSec", "body": "uint64 jjUnixTimeSec()", "description": "Returns unix time in seconds, i.e. the number of seconds that have elapsed since 00:00:00 UTC, Thursday, 1 January 1970, not counting leap seconds.\n"}, "jjUpdateTexturedBG": {"prefix": "jjUpdateTexturedBG", "body": "void jjUpdateTexturedBG()", "description": "Forces JJ2+ to reconstruct the textured background from its relevant properties. This should be handled automatically now.\n"}, "jjZlibCompress": {"prefix": "jjZlibCompress", "body": "bool jjZlibCompress(const jjSTREAM &in input, jjSTREAM &out output)", "description": "Compresses data in input using the zlib library. The compression result is placed into output. Returns whether successful, which should almost always be true.\n"}, "jjZlibUncompress": {"prefix": "jjZlibUncompress", "body": "bool jjZlibUncompress(const jjSTREAM &in input, jjSTREAM &out output, uint size)", "description": "Attempts to uncompresses data in input using the zlib library. The decompression result is placed into output. For successful decompression, size must be at least the same value as the amount of bytes of the predicted output. Returns whether successful. The function can fail if input is not a valid compressed stream or size is too small to accomodate the output or too large to allocate memory required for performing the operation, as well as, rarely, for other reasons.\n"}} \ No newline at end of file diff --git a/levels/cycling/STVcycling.j2as b/levels/cycling/STVcycling.j2as new file mode 100644 index 0000000..c74c54e --- /dev/null +++ b/levels/cycling/STVcycling.j2as @@ -0,0 +1,156 @@ +#pragma require "STVutil.asc" + +#include "STVutil.asc" + +#pragma region perlin noise +class PerlinNoise +{ + array p(256); + + PerlinNoise() + { + for (int i = 0; i < 256; i++) + { + p[i] = i; + } + + for (int i = 0; i < 256; i++) + { + int j = gameRNG() & 255; + int temp = p[i]; + p[i] = p[j]; + p[j] = temp; + } + } + + float lerp(float a, float b, float t) + { + return a + t * (b - a); + } + + float fade(float t) + { + return t * t * t * (t * (t * 6 - 15) + 10); + } + + float noise(float x) + { + // return 1; + int X = int(x) & 255; + x -= int(x); + float u = fade(x); + + int A = p[X]; + int B = p[X + 1]; + return lerp(A, B, u) / 255.0f; + } +}; +#pragma endregion + +// drawing +int screenWidth = 640; +int screenHeight = 480; + +jjPIXELMAP@ gamePixelMap = jjPIXELMAP(screenWidth, screenHeight); +jjPAL gamePalette = jjPAL(); + +// logic +jjRNG gameRNG = jjRNG(); +PerlinNoise@ gamePerlin = PerlinNoise(); + +int playerX = 0; + +void onLevelLoad() { + jjConsole("Started!"); + + // grass + gamePalette.color[1] = jjPALCOLOR(0, 255, 0); // green + gamePalette.color[2] = jjPALCOLOR(50, 205, 50); // dark green + + // road + gamePalette.color[3] = jjPALCOLOR(255, 0, 0); // red + gamePalette.color[4] = jjPALCOLOR(255, 255, 255); // white + + // sky + gamePalette.color[5] = jjPALCOLOR(176, 224, 230); // powder blue + gamePalette.color[6] = jjPALCOLOR(73, 216, 230); // light blue + + // ground + gamePalette.color[7] = jjPALCOLOR(127, 127, 127); // gray + + array indexMapping; + indexMapping.insertLast(0); + indexMapping.insertLast(1); + indexMapping.insertLast(2); + indexMapping.insertLast(3); + indexMapping.insertLast(4); + indexMapping.insertLast(5); + indexMapping.insertLast(6); + + jjSpriteModeSetMapping(1, indexMapping, gamePalette); + jjConsole("INIT: Mappings"); +} + +int quarterScreenHeight = screenHeight/8; + +void setTerrainPoint(int pos, int height, int color = -1) { + // 1 == bright, 2 == dark + // jjConsole("Setting pos: " + pos + " height: " + height); + // } + // if(playerX >= 10800) { + // jjSpy("" + playerX); + // return; + // } + + for (int y = screenHeight - 1; y >= height; y--) + gamePixelMap[pos, y] = (color == -1 ? ((y >= height + quarterScreenHeight) ? 2 : 1) : color); +} + + +const float frequency = 0.001; +const float amplitude = 100; +const int terrainOffset = screenWidth/2; + +int difference = 2; +int timeDifference = 4; + +void onMain() { + if(jjGameTicks % timeDifference == 0) { + // Clear! this crashes the game with an access violation after a few seconds + // if only we could delete gamePixelMap; + @gamePixelMap = jjPIXELMAP(screenWidth, screenHeight); + + for (int x = 0; x < screenWidth; x += difference) { + for(int i = 0; i < difference; i++) { + setTerrainPoint(x + i, int( + terrainOffset - ( + amplitude * gamePerlin.noise( + (x + i + playerX) * frequency + ) + ) + )); + } + } + } + + playerX += timeDifference*4; +} + +bool onDrawAmmo(jjPLAYER@ player, jjCANVAS@ screen) { + gamePixelMap.save(jjAnimFrames[jjAnimations[jjAnimSets[ANIM::CUSTOM[0]].firstAnim].firstFrame]); + + screen.drawRectangle(0, 0, jjResolutionWidth, jjResolutionHeight, 0); + screen.drawSprite(0, 0, ANIM::CUSTOM[0], 0, 0, /* direction */ 0, SPRITE::MAPPING, 1); + screen.drawString(10, 30, "screenWidth: " + screenWidth + " - screenHeight: " + screenHeight); + screen.drawString(10, 45, "frequency: " + frequency + " - amplitude: " + amplitude + " - terrainOffset: " + terrainOffset); + screen.drawString(10, 60, "difference: " + difference + " - timeDifference: " + timeDifference); + screen.drawString(10, 75, "playerX: " + playerX); + + return true; +} + +bool onDrawHealth(jjPLAYER@ player, jjCANVAS@ canvas) { return true; } +bool onDrawLives(jjPLAYER@ player, jjCANVAS@ canvas) { return true; } +bool onDrawPlayerTimer(jjPLAYER@ player, jjCANVAS@ canvas) { return true; } +bool onDrawScore(jjPLAYER@ player, jjCANVAS@ canvas) { return true; } +bool onDrawGameModeHUD(jjPLAYER@ player, jjCANVAS@ canvas) { return true; } diff --git a/levels/cycling/STVcycling.j2l b/levels/cycling/STVcycling.j2l new file mode 100644 index 0000000..78de377 Binary files /dev/null and b/levels/cycling/STVcycling.j2l differ diff --git a/levels/cycling/run.bat b/levels/cycling/run.bat new file mode 100644 index 0000000..69c588c --- /dev/null +++ b/levels/cycling/run.bat @@ -0,0 +1,41 @@ +@echo off + +REM Read variables from run.ini +for /f "tokens=1* delims==" %%a in ('type "..\..\run.ini" ^| find "="') do ( + if /i "%%a"=="GAME_DIRECTORY" set "GAME_DIRECTORY=%%b" + if /i "%%a"=="GAME_NAME" set "GAME_NAME=%%b" +) + +echo Copying files... +copy "../../scripts/" "%GAME_DIRECTORY%" /y + +for %%i in (*.j2l *.j2t) do ( + copy "%%i" "%GAME_DIRECTORY%" /y +) +for %%i in (./assets/*.*) do ( + copy ".\assets\%%i" "%GAME_DIRECTORY%\STVcycling.j2as_%%i" /y +) +for %%i in (*.j2as *.mut *.asc) do ( + python ../../experiments/angelscriptpp/angelscriptpp.py "%%i" "%GAME_DIRECTORY%\%%i" +) + +set "J2L_LEVEL=" +set "MUTATOR=" + +echo Starting +for %%i in (*.j2l) do ( + set "J2L_LEVEL=%%i" + goto :check_mutator +) + +:check_mutator +for %%i in (*.mut) do ( + set "MUTATOR=-mutators=%%i" + goto :start_game +) + +:start_game +if not defined J2L_LEVEL set "J2L_LEVEL=battle1" +"%GAME_DIRECTORY%%GAME_NAME%" -server %MUTATOR% %J2L_LEVEL% +@echo on +