This project provides a library of several mathematical functions, from such fields as linear algebra, computational geometry and pseudo-random number generation, and a support for homogeneous, variable-length lists.
A demo module is provided.
DESCRIPTION
Functions provided by this project are divided thematically between four include scripts:
math_include_b
: base math functionsmath_include_l
: list support functionsmath_include_g
: computational geometry functionsmath_include_v
: variable support functionsNames of all provided functions start with "MATH_" and all of them have their documentation accessible in the script editor of the toolset.
math_include_b
contains the base math functions of this project: fast pseudo-random generation of ints and floats from uniform and normal (Gaussian / bell curve) distributions, float and vector component truncation, rounding, flooring and ceiling, sign, min, max and clipping (making sure they belong to certain range) of ints, floats and vector components, component-wise sum and multiplication between vectors or vectors and scalars, vector dot and cross products.math_include_l
contains functions for handling homogeneous lists of int, float, vector and string variable types. Custom, complex list item types are also supported, but they require additional programming.math_include_g
contains functions useful for vector manipulation and discovery of spatial relations between in-game objects: planar angle calculation, 2D and 3D rotations, projection of point onto line segment / line segments, projection of point onto sphere / spheres, calculation of line / line and sphere / sphere intersections, checking whether a point lies on a line, checking whether a point lies on / in a sphere, checking whether a point lies on / in a polygon.math_include_v
contains various functions useful for dealing with variables: conversion of vectors into <x, y, z> strings, setting / getting / deleting of vectors and lists as local variables, quick displaying and logging of all basic variable types (string, int, float, vector, location and object) and contents of lists.CHANGELOG
2.0 (2019-02-19)
1.0 (2019-02-05)
INSTALLATION
This project is aimed at module builders only. Players will not benefit from it directly (if some module uses it, it will contain it already). Though even if you are a player, be sure to check out the demo module for examples of some amusing use cases of this project.
Attachment | Size |
---|---|
auxiliary_math_library_2.0.7z (253) | 47.58 KB |
auxiliary_math_library_2.0.txt | 11.23 KB |
auxiliary_math_library_2.0.html | 110.83 KB |
Over 1000 lines of enterprise-level code only because some time ago I decided to make a bit more useful random function.
Be sure to check out the demo module, but watch out for you CPU as some of the scripts have sub-second call intervals.
really great work. you get my vote for king. :D
these will be very useful, i've no longer got an excuse to put off some of my projects.
i'm glad to see you've included stuff to work around the max int/float conversion bug... ['how/why could they have ever allowed that?!' he asks incredulously.]
thank you !
Thanks. Hopefully somebody can put this to some good use in a real module.
I did a bit of research before and it appears NWN's PRNG is not skewed (i.e. a C rand() passthrough, no dirty tricks), so the MATH_Rand* function family provided here should work flawlessly under "normal" conditions.
But to clarify, the problems with floats aren't really bugs per se, though from user's persepective they definitely can be seen as such. In order to save CPU ticks, NWN uses single-precision (32-bit) float, which can represent ints exactly only in -224 to 224 range (assuming IEEE 754) and will start rounding numbers above that. You may also end up in a + b = a situations. With doubles we'd be hitting problems much later, but then not many people are going to need to go over 16 millions, so no big deal.
Guess I spoke too soon. Like usual, bugs show up after release.
There is a minor issue in MATH_RandInt. Fixed version should be out by the weekend... probably with something extra.
This library is a beautiful thing. High five for being capslock prefix buddies!
Here to drop off ideas and suggestions, for this or for future projects (take with grain of salt, is likely to be 90% nonsense):
- Catapult / Boomerang trajectories.
A "location GetProjectileNextStep()" function could be used to step-by-step generate a flight path for simulating throwing a placeable or applying VFX and damage in spells.
- Percentages.
Percentage calculation functions would go well with the idea of having a comprehensive math library.
- High score sorting, or sorting algorithms in general.
I could see functions to sort objects or strings according to some determinant value being very useful to people. Think: Add 10 objects to a list. Call function to retrieve the object that, among them, has the highest value of local int "CAKE" set on it. Or, add 10 strings to a list. Check local ints stored on module under the names of the strings on the list, return the name for the string with the highest (or lowest) value. Optionally, remove string from list.
- Collision detection / Object-to-Object proximity detection.
This is already demonstrated in the demo module, but explicit convenience functions for it might be nice to have even so. A lot of newbie modulebuilders struggle with scripting as is; a "GetIsObjectBetween(object oCheckFor, location lStart, location lEnd, float fRadius=0.5)" function would be easier for the user than having to learn linear algebra if they aren't already familiar with it. Same thing with "GetIsObjectInFrontOf(object oCheck, object oTarget, float fDistance=1.0)", or "GetIsObjectBehind()", or "GetIsObjectToLeftOf()"/"GetIsObjectToRightOf()"; those are difficult to set up for newbie scripters.
- "Safe" incrementing and decrementing, with an optional cap.
Incrementing and decrementing functions for incrementing/decrementing local integers, with maximum or minimum values. I've got these in my data management library, to handle local values that go from 0-100 or -100 to 100, and I've grown very fond of them. Capping values is all over the place in the Bioware spell scripts, too; having the cap be automatic part of the incrementation/decrementation saves a few lines of code over and over again.
- "Default to" values.
Another thing I found very practical was a function to set up "default to" values during setup/initialization of placeables. If the builder did not specify a value for local int/string/float, but that variable is required for the whatever-it-is to work as planned, default to value X. This isn't exactly the direction you're going in, but it's a thought.
- Random positions in shapes.
Running with the thought of making the random position generation functions easier to use, setting up a "GetRandomPositionInShape" function might work well, too. Expand the Bioware SHAPE_* constants, make retrieving a random position within a given shape of a given size a one-line kind of thing. It'd simplify the code on the "practical ingame application"-end, and make it immediately and unambiguously readable to anyone. One of the biggest problems of some of the best libraries for NWN is that they're too difficult for newbies to figure out how to use, so they often lie around underutilized.
I'll drop off a couple of links to things you might enjoy taking a look at if you haven't already:
https://neverwintervault.org/project/nwn1/script/psc-pentagrams-summonin...
https://neverwintervault.org/project/nwn1/script/gestalt-cutscene-script...
Thanks for suggestions and the links, Barbar. I actually got inspired by your function names to do the CAPS_ style prefix. I even went back and modified NCTS to have them too... It really improves readability.
I'm almost done with adding a list support to the module. I rewrote the line intersection and projection algorithms to accept lists of vertices instead of tags. This is much better - you'll be able to test multiple shapes at once, with self-intersecting segments or not. I have a quicksort implementation (tried mergesort too, but it was hitting TMI before that), so the lists will be sortable. Direct lexicographic string sorting is technically possible via extra 2DA but its performance will probably be very poor...
Calculating trajectories (or curves in general) may be possible. Same with collision detection... Colliding with polygons is done, but I may add sphere / circle collision / intersection - good suggestion.
I think the safe incrementation can be already done with:
You are correct that functions need to usable as is. If you have any suggestions, you can post or PM me their declarations. I'll also think of some.
I'll try to post 2.0 version (with list support) in this week. Then I'll look into your timestamp library.
You are correct - checking clicks on ground (or triggers) is possible with AML. You still need to keep the zone vertices somewhere... Too bad its not possible to retrieve the vertices of a trigger with NWScript. Technically, someone could write a program that extracts them from module binary and produce a parseable list...
Thanks for the link to that projectile detection script. At glance, it may be doing something similar to me, but it's core logic seems to be quite... intertwined with the spellcasting. I haven't tried the demo yet.
I have an idea for a check if object is between other objects using the line projection. It can even accept a tolerance parameter (i.e. how far you are from the line). I'll also add sphere collision and intersection functions (perhaps with cone parameters). Compared to the polygon-related ones, these are easy.
Unlike real sorting, in NWN we are bound by Too Many Instructions, which is highly dependant on how we sort but also how much extra work we need to perform while doing so. If you don't plan on sorting thousands of items at once, then everything should be fine (i.e. stay at several hundreds).
Yes, I promised to look at your library. But I'll be mostly focusing on timestamp algebra, if you don't mind. I plan on releasing the update to AML on this Sunday. Let me know if there are any special list functions you may find useful.
BTW: NWN call stack limit is 127 (i.e. 125 recursive functions calls from main are OK, next one fails).
There it is - finally the 2.0 update with list support. Please read the change log above if you're interested in it.
Here I express my thanks to TheBarbarian for fruitful discussion about the project and various improvement suggestions. Some of them were added to this version, some may be added in the future.
Contact me if you'd like to contribute or request a feature.
I'll add new screenshots tomorrow, but they won't be spectacular.