View Single Post
Violet CLM Violet CLM's Avatar

JCF Éminence Grise

Joined: Mar 2001

Posts: 10,978

Violet CLM has disabled reputation

Aug 20, 2016, 02:29 PM
Violet CLM is offline
Reply With Quote
Here's something y'all might find amusing: my in-forum documentation of the very first internal JJ2+ build to contain angelscript, and the full list of features it included. Note that nearly everything got renamed after this--we hadn't figured out the jj naming scheme yet, or namespaces for enums--and also back then it was possible to embed angelscript in help strings as well as .j2as files but that idea was dropped prior to 4.0's release.

Quote:
Originally Posted by Violet CLM
Angelscript can live in two places: the help strings, like before, or in .j2as files with the same filename (other than extension) as their associated .j2l. I'm not going to go into how to write Angelscript, since that's what the manual is for, but I'll list JJ2-specific stuff.

The Text event commands are understood as functions void hstr_{TEXTID}_{OFFSET}(). For example, when you trigger a Text event with TextID=2, Command=1, Offset=4, this will call the void hstr_2_4() function. Since these are somewhat limited by the help strings' length limits (both JCS-imposed and .j2l-imposed), it's also possible to define an hstr_#_# function in the accompanying .j2as file. In that case, the numbers you choose are pretty much completely arbitrary, you just make sure to choose the same ones when setting up the Text event. Alternatively, you could define a less arbitrarily named function within the .j2as file and use the .j2l-internal hstr_#_# function to call that. Whichever you feel more comfortable with.

Help strings are sorted into two camps: those for showing text to the player, and those used for angelscript. To reserve a help string for angelscript storage, the first character must be a semicolon ( ; ). A help string that does not begin with a semicolon will not be parsed as code, and a help string that begins with a semicolon but contains non-code will break the angelscript engine.

Besides the hstr_#_# functions, JJ2 will also automatically call several other functions, although only if you've defined them in the .j2as file (by default they don't exist):
  • void main(): called once per loop.
  • void onPlayer(): called once per local player per loop
  • void onLevelLoad(): called after the level is done loading for the first time
  • void onLevelReload(): in SP, called after the player has died and all the objects have been reinitiated
(there's certainly room for others, but those are the only ones that are actually firing right now.)

The hstr_#_# and onPlayer functions each set a global variable uint8 CurrentPlayerID to, uh, the current player ID. 0-3. This can be used in conjunction with the global function player getPlayer(uint8) to return a player object, i.e.:
Code:
@player curPlayer = getPlayer(CurrentPlayerID);
Because this is likely to be such a common action, it can be shortened considerably, using the dedicated player object p and the shortcut function player CP():
Code:
@p=CP();
Player objects have a decent number of their properties exposed to Angelscript, namely int score, int16 xPos, int16 yPos, int16 xAcc, int16 yAcc, int16 xSpeed, int16 ySpeed, int8 frozen, int8 health, int fastfire, int currWeapon, int lives, int invincibility, int food, int coins, int redGems, int greenGems, int blueGems, int purpleGems, int shieldType, int shieldTime, and const pTimerState playerTimerState, const int clientID and const int localPlayerID. All can be read and (except for the last three) written to using dot notation, e.g. p.currWeapon or whatever.
(NOTE: xPos, yPos, xAcc, yAcc, xSpeed, and ySpeed all use the user-friendly versions of their values, measuring in pixels. Prepend an underscore to their names to get the full int (not int16) versions, e.g. p._xPos.)
(more could easily be added; I just grabbed whichever I thought might be immediately be useful.)
(pTimerState is an enum with possible values timerSTOPPED, timerSTARTED, timerPAUSED)

Players also have property accessors for bool noFire, bool antiGrav, and int playerTimerTime. For the most part these work just the same as the real properties and you shouldn't need to worry about the distinction.

Players also have the following methods:
  • bool getPowerup(uint8 gun)
  • bool setPowerup(uint8 gun, bool poweredUp)
  • int getAmmo(uint8 gun)
  • int setAmmo(uint8 gun, int bulletCount) (these two functions use user-friendly numbers for toaster, so setAmmo(5, 64) will show the player as having 64 toaster ammo, not 2.)
  • bool offsetPosition(int xTileOffset, int yTileOffset) instantly moves the player (xTileOffset) tiles to the right and (yTileOffset) tiles down. Hands down the best way of implementing looping levels.
  • bool warpToTile(int xTile, int yTile, bool fastWarp)
  • bool warpToID(uint8 warpID, bool fastWarp)
  • void jjk()
  • pTimerState startPlayerTimer(int time, bool startPaused)
  • pTimerState pausePlayerTimer()
  • pTimerState resumePlayerTimer()
  • pTimerState stopPlayerTimer()
  • void setPlayerTimerFunction(const string functionName) chooses which (void, zero-parametered) function is called when the timer runs out. This defaults to hstr_0_0. CurrentPlayerID will be set accordingly when this function is called.
  • bool activateBoss() (doesn't change the music)
  • void showText(string &in)

There are also a fair number of global functions:
  • void echo(const string text) writes a line to the chatlogger, and displays it ingame as well if in a server
  • void debug(const string text) does the same as echo, but only if the [General]AngelscriptDebug flag in plus.ini is set to True. (Turning this flag on will also give you error information if your Angelscript isn't quite right, but you probably don't want to leave it on when you're not busy developing.)
  • void chat(const string text) sends a line of chat to the server. This can be a command, if you have admin powers or if the level is being played in SP.
  • bool loadMusic(string filename) returns "false" if the file doesn't exist in the main or cache directories, plays the new music file once it's loaded
  • void stopMusic()
  • void playMusic()
  • bool loadPaletteFromJ2T(string filename)
  • bool loadPaletteFromRawFile(string filename) (File saved as "Color Map" in palsuite, or totally raw file only 1024 bytes long.)
  • void resetPalette() returns the level's palette to the tileset's native palette
  • void tintPaletteSection(uint8 red, uint8 green, uint8 blue, float alpha, uint8 start, uint8 length)
  • void tintPalette(uint8 red, uint8 green, uint8blue, float alpha is a wrapper for tintPaletteSection with start=1 and length=255. (Tinting color 0 temporarily messes up transparency.)
  • void replacePaletteSectionWithGradient(uint8 red1, uint8 green1, uint8 blue1, uint8 red2, uint8 green2, uint8 blue2, uint8 start, uint8 length
  • void replaceTexturedBackgroundGradient(uint8 red1, uint8 green1, uint8 blue1, uint8 red2, uint8 green2, uint8 blue2) is a wrapper for replacePaletteSectionWithGradient with start=76 and length=32.
  • void updatePalette() should be called after all other palette-modifying functions have been called. None of them call it by themselves, and if it's not called, you get unexpected results. (BUG: textured backgrounds in 16-bit don't have their colors updated. Thoughts, Jerry?)
  • uint16 getTileAt(uint8 layer, int x, int y)
  • uint16 setTileAt(uint8 layer, int x, int y, uint16 newTile)
  • void updateTexturedBG() refreshes the textured background to see which tiles are now used in it, in case you've used setTileAt on layer 8. Otherwise the changes won't show up.
  • bool getTrigger(uint8 id)
  • bool setTrigger(uint8 id, bool setTo)
  • bool switchTrigger(uint8 id) (for those who don't want to type setTrigger(x, !getTrigger(x));)


P.S. Jerry, here's your level's TextID0 in the new syntax:
Code:
;@p=CP();p.startPlayerTimer(7,false);p.setPlayerTimerFunction("hstr_0_2");|;|@p=CP();p.warpToID(1,false);
P.P.S. Major to-dos are a) providing ways to access some of the GameGlobals/LevelGlobals/GeneralGlobals stuff, e.g. water level, layer properties, multiplayer scores, etc.) and b) getting the .j2as file to be sent along with the level/tileset/music files in MP
__________________