aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/engine/kmath.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/engine/kmath.cpp')
-rw-r--r--engines/sci/engine/kmath.cpp201
1 files changed, 201 insertions, 0 deletions
diff --git a/engines/sci/engine/kmath.cpp b/engines/sci/engine/kmath.cpp
new file mode 100644
index 0000000000..4c8ebb8ec5
--- /dev/null
+++ b/engines/sci/engine/kmath.cpp
@@ -0,0 +1,201 @@
+/***************************************************************************
+ kmath.c Copyright (C) 1999 Christoph Reichenbach
+
+
+ This program may be modified and copied freely according to the terms of
+ the GNU general public license (GPL), as long as the above copyright
+ notice and the licensing information contained herein are preserved.
+
+ Please refer to www.gnu.org for licensing details.
+
+ This work is provided AS IS, without warranty of any kind, expressed or
+ implied, including but not limited to the warranties of merchantibility,
+ noninfringement, and fitness for a specific purpose. The author will not
+ be held liable for any damage caused by this work or derivatives of it.
+
+ By using this source code, you agree to the licensing terms as stated
+ above.
+
+
+ Please contact the maintainer for bug reports or inquiries.
+
+ Current Maintainer:
+
+ Christoph Reichenbach (CJR) [jameson@linuxgames.com]
+
+***************************************************************************/
+
+#include "sci/include/engine.h"
+
+
+reg_t
+kRandom(state_t *s, int funct_nr, int argc, reg_t *argv)
+{
+ return make_reg(0,
+ SKPV(0) + (int) ((SKPV(1) + 1.0 - SKPV(0)) * (rand() / (RAND_MAX + 1.0))));
+}
+
+
+reg_t
+kAbs(state_t *s, int funct_nr, int argc, reg_t *argv)
+{
+ /* This is a hack, but so is the code in Hoyle1 that needs it. */
+ if (argv[0].segment)
+ return make_reg(0, 0x3e8); /* Yes people, this is an object */
+ return make_reg(0, abs(SKPV(0)));
+}
+
+
+reg_t
+kSqrt(state_t *s, int funct_nr, int argc, reg_t *argv)
+{
+ return make_reg(0, (gint16) sqrt((float) abs(SKPV(0))));
+}
+
+
+int
+get_angle(int xrel, int yrel)
+{
+ if ((xrel == 0) && (yrel == 0))
+ return 0;
+ else {
+ int val = (int) (180.0/PI * atan2(xrel, -yrel));
+ if (val < 0)
+ val += 360;
+
+ /* Take care of OB1 differences between SSCI and
+ FSCI. SCI games sometimes check for equality with
+ "round" angles */
+ if (val % 45 == 44)
+ val++;
+ else if (val % 45 == 1)
+ val--;
+
+ return val;
+ }
+}
+
+reg_t
+kGetAngle(state_t *s, int funct_nr, int argc, reg_t *argv)
+{
+ /* Based on behavior observed with a test program created with
+ ** SCI Studio.
+ */
+ int x1 = SKPV(0);
+ int y1 = SKPV(1);
+ int x2 = SKPV(2);
+ int y2 = SKPV(3);
+ int xrel = x2 - x1;
+ int yrel = y1 - y2; /* y-axis is mirrored. */
+ int angle;
+
+ /* Move (xrel, yrel) to first quadrant. */
+ if (y1 < y2)
+ yrel = -yrel;
+ if (x2 < x1)
+ xrel = -xrel;
+
+ /* Compute angle in grads. */
+ if (yrel == 0 && xrel == 0)
+ angle = 0;
+ else
+ angle = 100 * xrel / (xrel + yrel);
+
+ /* Fix up angle for actual quadrant of (xrel, yrel). */
+ if (y1 < y2)
+ angle = 200 - angle;
+ if (x2 < x1)
+ angle = 400 - angle;
+
+ /* Convert from grads to degrees by merging grad 0 with grad 1,
+ ** grad 10 with grad 11, grad 20 with grad 21, etc. This leads to
+ ** "degrees" that equal either one or two grads.
+ */
+ angle -= (angle + 9) / 10;
+
+ return make_reg(0, angle);
+}
+
+
+reg_t
+kGetDistance(state_t *s, int funct_nr, int argc, reg_t *argv)
+{
+ int xrel = (int) (((float) SKPV(1) - SKPV_OR_ALT(3, 0))/cos(SKPV_OR_ALT(5, 0)* PI / 180.0)); /* This works because cos(0)==1 */
+ int yrel = SKPV(0) - SKPV_OR_ALT(2, 0);
+
+ return make_reg(0, (gint16)sqrt((float) xrel*xrel + yrel*yrel));
+}
+
+reg_t
+kTimesSin(state_t *s, int funct_nr, int argc, reg_t *argv)
+{
+ int angle = SKPV(0);
+ int factor = SKPV(1);
+
+ return make_reg(0, (int) (factor * 1.0 * sin(angle * PI / 180.0)));
+}
+
+
+reg_t
+kTimesCos(state_t *s, int funct_nr, int argc, reg_t *argv)
+{
+ int angle = SKPV(0);
+ int factor = SKPV(1);
+
+ return make_reg(0, (int) (factor * 1.0 * cos(angle * PI / 180.0)));
+}
+
+reg_t
+kCosDiv(state_t *s, int funct_nr, int argc, reg_t *argv)
+{
+ int angle = SKPV(0);
+ int value = SKPV(1);
+ double cosval = cos(angle * PI / 180.0);
+
+ if ((cosval < 0.0001) && (cosval > 0.0001)) {
+ SCIkwarn(SCIkWARNING,"Attepted division by zero\n");
+ return make_reg(0, (gint16)0x8000);
+ } else
+ return make_reg(0, (gint16) (value/cosval));
+}
+
+reg_t
+kSinDiv(state_t *s, int funct_nr, int argc, reg_t *argv)
+{
+ int angle = SKPV(0);
+ int value = SKPV(1);
+ double sinval = sin(angle * PI / 180.0);
+
+ if ((sinval < 0.0001) && (sinval > 0.0001)) {
+ SCIkwarn(SCIkWARNING,"Attepted division by zero\n");
+ return make_reg(0, (gint16)0x8000);
+ } else
+ return make_reg(0, (gint16) (value/sinval));
+}
+
+reg_t
+kTimesTan(state_t *s, int funct_nr, int argc, reg_t *argv)
+{
+ int param = SKPV(0);
+ int scale = SKPV_OR_ALT(1, 1);
+
+ param -= 90;
+ if ((param % 90) == 0) {
+ SCIkwarn(SCIkWARNING, "Attempted tan(pi/2)");
+ return make_reg(0, (gint16)0x8000);
+ } else
+ return make_reg(0, (gint16) -(tan(param * PI / 180.0) * scale));
+}
+
+reg_t
+kTimesCot(state_t *s, int funct_nr, int argc, reg_t *argv)
+{
+ int param = SKPV(0);
+ int scale = SKPV_OR_ALT(1, 1);
+
+ if ((param % 90) == 0) {
+ SCIkwarn(SCIkWARNING, "Attempted tan(pi/2)");
+ return make_reg(0, (gint16)0x8000);
+ } else
+ return make_reg(0, (gint16) (tan(param * PI / 180.0) * scale));
+}