New OHRRPGCE scripting features in Ichorescent

Make games! Discuss those games here.

Moderators: Bob the Hamster, marionline, SDHawk

Post Reply
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

New OHRRPGCE scripting features in Ichorescent

Post by TMC »

Ichorescent's release is coming up very soon which means, of course, lots of last minute features! My release TODO list is growing fast. When it reaches peak length it'll be necessary to release so I can get a clean slate!

Although there are other major features in ichorescent (James added spiffy battle features like player-controlled enemies (and why doesn't he capitalize release codenames??)), there's more than enough to justify a thread on this theme. And more to come.

Extra data arrays
HamsterSpeak effectively has arrays now that you can resize slice, NPC, zone and menu item extra data arrays, even if it is a bit clunky. Extra data always defaults to length 3, while the max is currently 1,000,000 5,000,000. The slice and zone editors let you resize the extra data for a slice or zone but resizing is mostly intended for scripting. Menu items will pass up to 32 args to a script.

A new set of generic array commands act on NPC references or slice/zone/menu item handles:
  • get extra
  • set extra
  • resize extra
  • extra length
  • append extra
(Zone handles are returned by the new get zone command. They have no other use (except see "slice is valid" below).)

I'll add some soon more for operations that are inefficient to implement as scripts, but I won't add every common array method because I want to add actual arrays in the not-too-distant future, and I already feel like I'm working on the wrong thing.

Python-style array indexing
Access extra data arrays from the end. Index -1 is the last item, -2 the second last...

Code: Select all

sl := create container
append extra(sl, 100)
#...
get extra(sl, -1)  # The last thing that was appended
show values, show value of
show value is a staple of script debugging... but it was frustrating that it only displayed one number. So now you can show multiple values. Also, show values is an alias to (variant spelling of) "show value".

Code: Select all

show values(hero X, hero Y, read zone(5, hero X, hero Y))
Also, if you like trace value you now use show value of which is formatted like "trace value", but shows on-screen. It wraps over the screen edge to fit.

Code: Select all

# Shows something like "coins=0, hero X(me)=3, hero Y(me)=14" at the bottom of the screen
show value of(coins, hero X(me), hero Y(me))
(I added trace value of as an alias to "trace value" to try to unify the naming)

lookup next slice, next slice in tree
Certain persons complained about lack of way to organise slices into a group, aside from making them the children of a parent. Now you can give them all the same lookup code to loop over them:

Code: Select all

variable(sl)
while (true) do (
  sl := lookup next slice(sli:particle, sl, sprite layer)  # Search all descendents of sprite layer
  if (sl == 0) then (break)
  particle updater(sl)
)
Or if you don't want to use lookup codes, next slice in tree makes it easy to write your own search.

I considered adding "slice groups" too. But I've never yet found use for Node groups in Godot rather than just use an array.

exit
exit is a new HS keyword which is equivalent to "return" in other programming langauges. exit(x) is equivalent to "exit returning(x)" and exit is equivalent to "exit script".

slice is valid
I removed the huge warnings not to use this command, because it's now (almost entirely) reliable. Slice handles have changed (they don't count up starting from 1) so that they won't be reused, unless you do "free slice(create container)" 1,024,256 times. Unless you keep around handles to deleted slices for hours you can now take the easy way out to avoid "invalid slice handle" errors by checking first with "if (slice is valid(sl)) then (something pretty(sl))".

As a bonus the engine now can recognise different types of script handles. In future the script debugger will show you that a variable/global contains a handle to a certain sprite slice or NPC or menu, etc, rather than just showing "14". A few error messages already now do this when you pass in the wrong kind of handle. Hmm, maybe I should add string handles...

Show slice in debugger
When a slice error occurs there's a shortcut to jump to it in the slice editor/debugger.

Commandline games?
(Unix only, because Windows GUI applications can't print to the terminal -- they have to create a new terminal window.)

If you use trace/trace value of but don't want to have to open g_debug.txt all the time you can now use --print or --printonly commandline args and it'll be conveniently printed to the terminal (stdout).

Noone else will care, but I wanted to run scripting tests and benchmarks straight from the commandline so I made it possible for a game to run without a window and print to the terminal. Pass --nogfx --printonly while using --gfx fb or (not included in default builds) --gfx console. Key input even works, though only gfx_fb supports non-printing keys like Left, F1, ESC. gfx_fb sure crashes a lot in this mode though. This is very crude, because only scripts will print to the terminal, so if a script error occurs the game appears to freeze.
User avatar
Bob the Hamster
Lord of the Slimes
Posts: 7658
Joined: Tue Oct 16, 2007 2:34 pm
Location: Hamster Republic (Ontario Enclave)
Contact:

Re: New OHRRPGCE scripting features in Ichorescent

Post by Bob the Hamster »

I have nothing to add except that I am very happy about all of the above
User avatar
kylekrack
Liquid Metal Slime
Posts: 1240
Joined: Mon Jun 16, 2014 8:58 am
Location: USA
Contact:

Re: New OHRRPGCE scripting features in Ichorescent

Post by kylekrack »

Wow. In love with every single thing here. I new extra data arrays were game changing, but these other additions are incredible as well. As someone who constantly uses show value, I really appreciate being able to use multiple values. It's the quickest, best way to debug most things, and now I don't have to reserve string ids for debugging purposes!

Also hooray about the negative array indexing. That's pretty fun. Time to rewrite array.hss!
My pronouns are they/them
Ps. I love my wife
User avatar
Feenicks
Metal Slime
Posts: 696
Joined: Tue Aug 10, 2010 9:23 pm
Location: ON THE AIR IN THE AIR
Contact:

Re: New OHRRPGCE scripting features in Ichorescent

Post by Feenicks »

Oh man, variable amounts of extra data. This'll make a ton of the stuff I could make in the future a lot easier to do.
Being able to have multiple values written via show value will be very useful, too.
User avatar
SwordPlay
Chemical Slime
Posts: 966
Joined: Sun Jan 22, 2017 9:32 am
Location: London, England
Contact:

Re: New OHRRPGCE scripting features in Ichorescent

Post by SwordPlay »

i love it. any idea how it works out performance wise?
"Imagination. Life is your creation."
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

Re: New OHRRPGCE scripting features in Ichorescent

Post by TMC »

Extra arrays have no runtime cost at all for simply existing (unlike slice arrays), even if huge. Reading slice extra data (although now slightly slower than it used to be) is the same speed as using "read global" to read a globals array, and much faster than using slice arrays, though I didn't time those. Here are timings (on this 12-year-old AMD CPU, pretty slow today) for these benchmarks. For example looping over a slice extra array to sum it costs 165ns per iteration (nearly half of that is the 'for' loop overhead), so 6 million per second. For comparison with equivalent benchmarks in other scripting languages: Python 2: 38ns, Python 3: 51ns, Squirrel: 35ns. Other benchmarks are more favourable: a bubble sort is less than 2x slower than Python 3.
Also, note that "get/set extra" are about 1/6th slower than "get/set slice extra".
kylekrack wrote: Sat Apr 23, 2022 8:23 pmnow I don't have to reserve string ids for debugging purposes!
Strings are one of the bigger annoyances in HS. I'm tempted to add something quick to try to make them easier, but I think the main thing needed is automatic allocation of new strings, and that requires automatic deletion too: garbage collection. The best two ideas I have are temporary string IDs that get freed when the script exits (but what if you have a for/while loop? Then they will just build up), or constant strings which can go in some global pool and don't need to be freed (but these only cover a subset of needs). But it's bad enough that we'll have two different types of strings once we get real strings, so I think I better not spend time creating a third.
User avatar
Rue
Slime Knight
Posts: 135
Joined: Sun Dec 09, 2007 4:01 am
Location: Bellevue, WA
Contact:

Re: New OHRRPGCE scripting features in Ichorescent

Post by Rue »

;_; I'm so proud of you guys. We have arrays! Mostly!

Time to... rewrite everything.
User avatar
SwordPlay
Chemical Slime
Posts: 966
Joined: Sun Jan 22, 2017 9:32 am
Location: London, England
Contact:

Re: New OHRRPGCE scripting features in Ichorescent

Post by SwordPlay »

very cutting edge. better than RPGMaker
"Imagination. Life is your creation."
User avatar
polkakitty
Red Slime
Posts: 83
Joined: Tue Aug 11, 2020 1:21 pm

Re: New OHRRPGCE scripting features in Ichorescent

Post by polkakitty »

This seems to overlap very well with the features that I've been feeling HamsterSpeak needed, and that I've tried to implement myself in scripts. I made a set of scripts that let you mark a range of global variables as an array or a matrix, and that implement all the basic array and matrix methods using those variables, because I needed that functionality to make a pathfinding algorithm. And, when I started experimenting with HamsterSpeak, I noticed pretty quickly that "show value" wasn't adequate for debugging the kinds of things I wanted to do, so what I ended up doing is, in all of my current projects, I have 4 text slices, that are shown above everything else because they're the only slices that aren't parented to anything, and I've been basically using those as console output, using "append number" to put several values into one string and then displaying them.

This isn't a complaint about any scripts that I've made being made obsolete! I think that, the more people have tried to implement any given feature as a script, the better a candidate it is to be made into an official engine feature. And, when you make something an official engine feature, that will make it easier to work with, and for new users to learn, rather than having to rely on including some random hss file that some guy made.

In particular, I think letting slices have more extra variables is the best thing that could be done to make them more useful, since it means that whenever you're using slices to represent moving objects in a game, you have an easy and intuitive way for all the necessary properties or statistics for each object to be contained in the slice itself. You don't need to deal with the awkwardness of saving the properties for each object in global variables (and having to keep track of which variables correspond to each slice and how many slices there will ever be,) or saving them in invisible child slices that otherwise do nothing. And there's no need to worry about deallocating any variables when you remove an object from the game, because the slice extra variables are automatically deallocated when the slice is freed.
TMC wrote: Sat Apr 23, 2022 12:55 pmexit
exit is a new HS keyword which is equivalent to "return" in other programming langauges. exit(x) is equivalent to "exit returning(x)" and exit is equivalent to "exit script".
I think this is an underrated feature as well. It's a completely petty thing, but it always seemed weird to me to have to use a command that was as verbose as "exit returning".
"It was right through those trees; I'm not insane
That's where the fin tried to drag me in
Don't look at me, look at where I'm pointing
Close your eyes, see what I see, Canajoharie..."
-- They Might Be Giants
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

Re: New OHRRPGCE scripting features in Ichorescent

Post by TMC »

polkakitty wrote: Wed Apr 27, 2022 2:36 pmI made a set of scripts that let you mark a range of global variables as an array or a matrix, and that implement all the basic array and matrix methods using those variables, because I needed that functionality to make a pathfinding algorithm.
Matrices? Did you really use them only for pathfinding? I don't know of any way to apply linear algebra to pathfinding, so I'm wondering how you used them. (Also, do you know about Boulderbeast?)
This isn't a complaint about any scripts that I've made being made obsolete!
Speaking of, I saw you wrote a set of trigonometry scripts too! I wonder whether you knew about the trig scripts I wrote.
It's a completely petty thing, but it always seemed weird to me to have to use a command that was as verbose as "exit returning".
In isolation each of the steps that led to picking such a verbose name seemed reasonable, but that doesn't excuse it. QuickBasic was the influence that led to "return" working the way it does.
User avatar
polkakitty
Red Slime
Posts: 83
Joined: Tue Aug 11, 2020 1:21 pm

Re: New OHRRPGCE scripting features in Ichorescent

Post by polkakitty »

TMC wrote: Fri Apr 29, 2022 1:09 amMatrices? Did you really use them only for pathfinding? I don't know of any way to apply linear algebra to pathfinding, so I'm wondering how you used them.
Well, what I wrote isn't advanced enough to actually support matrix math operations, it only supports matrices in the sense of "2D arrays", and it's intended to serve as a convenient way to store and refer to a set of data with x and y coordinates. The pathfinding algorithm was the first thing I wrote where I really needed that, but I tried to write it in such a way that it would be reusable for any other games that needed something similar (and I've since reused it in another game project where the player is exploring a procedurally generated dungeon, that's divided into rooms which are initially invisible and are revealed when the player moves into a room adjacent to them. I needed an efficient way to keep track of all the information about each room before I created slices for any rooms, and a way that information could be saved and reloaded.)

The algorithm I wrote is a pretty standard naive pathfinding algorithm, except that because of the design of the game it was made for, it works on a triangular grid instead of a square grid, so unfortunately, it couldn't be easily reused for any other game. (I don't know if there's a standard way to handle this in programming, but the way I handled it is by coming up with a scheme to map the triangular grid onto a square grid. Basically, I consider each cell in the square grid to only be connected to 3 of its neighbors: if the sum of the cell's x and y coordinates is even, it's connected to the cells to the north, south, and east, and if the sum of the cell's x and y coordinates is odd, it's connected to the cells to the north, south, and west. And every time the pathfinding algorithm needs to check the neighbors of a cell, it calls a script that writes the x and y coordinates of the 3 neighbors into global variables set aside for that purpose, instead of just adding and subtracting 1 from both the x and y coordinates of the original cell.)

So, the problem the pathfinding algorithm needs to solve is to take a character who is at a given position on the triangular grid, to tell whether there's a possible path from there to a collectable resource or an exit door, and to figure out what sequence of triangular cells the character needs to move through to reach their goal. To help with this, there is a matrix with numbers representing the terrain of each triangle on the map, and a "steps" matrix, which is initialized with all zeroes every time the algorithm runs. Whenever a number is put into the "steps" matrix, it represents the number of steps from the character's starting position it takes to get to that triangle (and it also represents confirmation that that triangle is reachable from the starting position.)

The pathfinding algorithm starts by writing the number 1 in the "steps" matrix in the character's starting position. It checks the terrain in each of the 3 neighbors of that triangle, and for each neighbor that has passable terrain in it, it adds the x and y coordinates of that neighbor to an array that represents the cells to look at in the next iteration of the algorithm. When it starts the second iteration, it copies the list of neighbor coordinates into a second array, clears the first array, and cycles through each set of neighbor coordinates that it found in the previous step. It writes the number 2 in each of those positions in the "steps" matrix, and for each neighbor of those positions that's reachable and that doesn't already have a number in the "steps" matrix, it adds the coordinates of that neighbor to the "positions to check on the next iteration" array.

This continues until either the algorithm finds the resource it's looking for, or it starts an iteration with an empty "starting positions" array, which indicates there is no way that resource can be found from the character's position. If it found the resource it wanted to find, then in the "steps" matrix, there will be a sequence of numbers that starts with the 1 at the starting position, adds 1 with each step, and finishes at the resource. So the algorithm works backwards, starting at the goal and looking at which neighbor of that cell in the grid has a number that's 1 less, and it gets the path the character can take to reach the resource, starting at the end of the path and ending at the beginning. It copies each set of coordinates on that path into an array, and then the game moves the character through each set of coordinates in the array, from the end of the array to the beginning.
TMC wrote: Fri Apr 29, 2022 1:09 am(Also, do you know about Boulderbeast?)
I found the Boulderbeast demo in the game list, and I think it's a very interesting idea, to make a character out of several different sprites, and to use an algorithm to position them to simulate movement in a 3D space. The funny thing is, you see that technique used all the time for bosses in early-90s-era games, but you never seem to see it used for a controllable character. (One of the few exceptions being a game called Earnest Evans. Which, while I wouldn't call it a *good* game by any means, I honestly think it's a game more people should play, because it's an experience that I can guarantee you is different from anything else you've ever experienced in a game, and you might get some ideas about how to do what that game is trying to do, only without things being so prone to breaking in weird, unpredictable ways. Or perhaps you could use the real power move of writing a backstory for your game where it's all taking place in a malfunctioning computer simulation, thus justifying any jank the player might encounter!)
TMC wrote: Fri Apr 29, 2022 1:09 amSpeaking of, I saw you wrote a set of trigonometry scripts too! I wonder whether you knew about the trig scripts I wrote.
No, I hadn't seen those before. It's interesting that, despite both making functions to handle the same math operations, we organized them in completely different ways.

If people are going to use the geometry.hss file I made, though, I'd prefer that they use this updated version that I'm using for my current projects. The original was one of the first things I made in HamsterSpeak, I just kind of threw it together as quickly as possible to provide some specific functions my team needed for our entry in the random collab contest, and it had some really dumb design flaws in it. (Like, the functions that covert an angle and a distance to subpixel velocities had a failsafe so they could still give valid results if you gave them an angle that was less than 0 or greater than 359, but the same thing didn't apply to the basic sine and cosine functions. In the updated version, all the functions that take angles can work with angles outside of the 0 ~ 359 range.)

I've also been thinking that, at some point, I'd like to make an rpg file specifically to be an interactive demonstration of a collection of utility functions I've made, like those geometry functions and a text writer I've made that supports control codes to change the color and font style (plain, bold, or italic) at any point in a text string, and to insert symbols in the form of backdrop images. All of the functions, of course, would be packaged with the rpg file, and would be free for anyone in the community to use.
"It was right through those trees; I'm not insane
That's where the fin tried to drag me in
Don't look at me, look at where I'm pointing
Close your eyes, see what I see, Canajoharie..."
-- They Might Be Giants
TMC
Metal King Slime
Posts: 4308
Joined: Sun Apr 10, 2011 9:19 am

Re: New OHRRPGCE scripting features in Ichorescent

Post by TMC »

These mammoth replies are kind of intimidating!

Ah, that meaning of matrix. I was primed for linear algebra because I've been thinking of using quaternions in the OHR... about 17 years too late to be topical :) Even after HS gains native arrays I expected we'll add a dedicated 2D array type you can use rather than needing nested arrays (which are inefficient). Could add an actual matrix class too, although few users would have a use for that.
polkakitty wrote: Fri Apr 29, 2022 1:46 pmI've since reused it in another game project where the player is exploring a procedurally generated dungeon
Cool, you have some interesting projects!
it works on a triangular grid instead of a square grid, so unfortunately, it couldn't be easily reused for any other game. (I don't know if there's a standard way to handle this in programming, but the way I handled it is by coming up with a scheme to map the triangular grid onto a square grid.
Yes, the standard way to handle triangular, hexagonal or isometric (slanted) grids is to give each cell an integer x/y coordinate like a square grid, and use a different neighbour rule. Triangular grids are rarer though.
The pathfinding algorithm starts by...
The algorithm you very precisely described is breath-first search, or as the special case of Dijkstra's algorithm where all the edge costs are 1, so you can use an array (or FIFO) rather than a priority queue, which you would need if tiles/edges could have varying costs.

Copying one array into another and then clearing it would be inefficient, if that's what you're doing. You can instead swap the two arrays. (If they're arrays of globals you can use two variables pointing to the start of the arrays)

Also, Bena's been urging me to add scripting commands to access the OHR's builtin A* pathfinding, but of course that won't help for triangular grids.
a game called Earnest Evans
Wow, I hadn't heard of it. Interesting. I haven't played it myself yet, but didn't notice it "breaking in weird, unpredictable ways" in the videos I looked at.
Or perhaps you could use the real power move of writing a backstory for your game where it's all taking place in a malfunctioning computer simulation, thus justifying any jank the player might encounter!
That's perfect!
I've also been thinking that, at some point, I'd like to make an rpg file specifically to be an interactive demonstration of a collection of utility functions I've made, like those geometry functions and a text writer I've made that supports control codes to change the color and font style (plain, bold, or italic) at any point in a text string, and to insert symbols in the form of backdrop images. All of the functions, of course, would be packaged with the rpg file, and would be free for anyone in the community to use.
That sounds really nice! Custom text systems is another thing that a lot of people have scripted but it sounds like yours is one of the best. Did you write yours from scratch or start with Prifurin's? Again it's about time the engine had better text support rather than people needing to script it. That's my plan for first thing after Ichorescent though my intention isn't to reduce anyone's achievements. I haven't implemented bold, light or italic yet but I wanted to attempt that using automatic transformations of the font, as well as optional hand-drawn variants.

Trig and other math functions is meant to be the next thing I'm posting about. Already intended to implement it months ago.
lennyhome
Slime Knight
Posts: 115
Joined: Fri Feb 14, 2020 6:07 am

Re: New OHRRPGCE scripting features in Ichorescent

Post by lennyhome »

polkakitty wrote: Fri Apr 29, 2022 1:46 pmangle that was less than 0 or greater than 359
If I may give you a quick advice on that, it's easier to define angles in 256 degrees if you're working with fixed point numbers. You can "and" any value with 255 and do the lookup. You get wrap around and bounds check essentially for free that way.
User avatar
MorpheusKitami
Slime Knight
Posts: 218
Joined: Wed Nov 30, 2016 8:23 pm
Location: Somewhere in America

Re: New OHRRPGCE scripting features in Ichorescent

Post by MorpheusKitami »

Clarifying because I don't use slices a lot. Does this mean that slices effectively have a ton of variables? If so that's quite convenient for me, because I put a game on a backburner because part of the basic gameplay would have required thousands of global variables before even going past anything but the basic combat.
User avatar
pjbebi
Slime Knight
Posts: 112
Joined: Mon Jul 31, 2017 7:22 am
Location: Florida
Contact:

Re: New OHRRPGCE scripting features in Ichorescent

Post by pjbebi »

MorpheusKitami wrote: Tue May 24, 2022 1:18 am Clarifying because I don't use slices a lot. Does this mean that slices effectively have a ton of variables? If so that's quite convenient for me, because I put a game on a backburner because part of the basic gameplay would have required thousands of global variables before even going past anything but the basic combat.
Yes. It means exactly that. It's super helpful for storing stats galore.
Post Reply