Strange arithmetic error

scrimshaw04

I've encountered a strange error. I have a script that randomly spawns animals into rooms that the player enters. As part of this script I have a script attribute on the animals that spawn that gives them a random size

size = this.animal_size
size_max = this.animal_size_max
ratio = size / size_max
if (ratio >= 0.8) {
  this.animal_size_adj = "Large"
}
else if (ratio <= 0.2) {
  this.animal_size_adj = "Small"
}
else {
  this.animal_size_adj = null
}
if (not GetString (this, "animal_size_adj") = null) {
  this.alias = this.animal_size_adj + " " + GetDisplayAlias (this)
}

That script works, using 'do', as part of a script that runs when the player enters a room. However, it seems to always produce results that are 'small' for some reason.

Also, when I try to run an almost identical script, to randomise another adjective which describes how healthy the animal is, it gives me this error: 'Error running script: Error compiling expression 'hp / hp_max': ArithmeticElement: Operation 'Divide' is not defined for types 'LazyLoadScript' and 'Int32''

This script looks like this, and immediately follows the previous one, run using 'do'.

hp = this.animal_hp
size_max = this.animal_hp_max
ratio = hp / hp_max
if (ratio >= 0.75) {
  this.animal_size_adj = "Strong"
}
else if (ratio <= 0.25) {
  this.animal_size_adj = "Weak"
}
else {
  this.animal_size_adj = null
}
if (not GetString (this, "animal_hp_adj") = null) {
  this.alias = this.animal_hp_adj + " " + GetDisplayAlias (this)
}

I can't see any reason why division should work for one of these scripts and not for the other. Any ideas?

EDIT: I'm beginning to suspect that there might be an issue with using decimals. Does quest have an issue with non-whole numbers?


The Pixie

From the error message, sounds like hp (and therefore this.animal_hp) is a script not a number.


scrimshaw04

Nope, definitely an integer.

EDIT: I've found the solution. On the test animal I was spawning I had forgotten that I had set the hp attribute to 'null' instead of 0. To fix it I just deleted the attribute from the animal object, so that it inherited the default hp attribute from it's parent.

However, almost all the animals that I spawn still seem to be categorised as 'small' for some reason. Only if the animal spawned is the maximum possible size will it be categorised as 'large'. It will never generate anything that is neither small or large.

My guess is that two things are happening. Firstly in the instances in which I want the animals to spawn with no adjective, they're spawning with a 'small' adjective instead. That might be because I'm misusing 'null' somehow. Secondly, the 'ratio' is being rounded to a whole integer. If the numbers are always being rounded down, then that would explain why the spawned animals are only ever 'large' if their size is the maximum.

Any idea why this might be happening?

Side note, I also realised there was a mistake in my math. Since the minimum value of size or hp isn't zero, dividing the current size by the maximum size doesn't give the correct ratio. My new script subtracts the minimum value from both the maximum and current sizes, which should make the ratio accurate. Like so

size_min = this.animal_size_min
size_original = this.animal_size
size_max_original = this.animal_size_max
size = size_original - size_min
size_max = size_max_original - size_min
ratio = size / size_max
if (ratio >= 0.8) {
  this.animal_size_adj = "Large"
}
else if (ratio <= 0.2) {
  this.animal_size_adj = "Small"
}
else {
  this.animal_size_adj = "Normal"
}
if (not GetString (this, "animal_size_adj") = null) {
  this.alias = this.animal_size_adj + " " + GetDisplayAlias (this)
}

Jay Nabonne

The problem is because they are integers, and integer division truncates to integers. If you want floating point arithmetic, the values need to be double or converted to doubles. In other words:

1 / 2 = 0
1.0 / 2.0 = 0.5


Jay Nabonne

Unfortunately, the method to convert an int to a double is not pretty:

      x = 1
      y = 2
      msg(x/y)
      xd = ToDouble(ToString(x))
      msg(xd/y)

Outputs:
0
0.5


scrimshaw04

Ah so that's what a double is! Pardon my ignorance. :P

Thanks a bunch! Pretty doesn't matter, so long as it works.

EDIT: Here's the new script, which seems to work:

size_min = this.animal_size_min
size_original = this.animal_size
size_max_original = this.animal_size_max
size_int = size_original - size_min
size_max = size_max_original - size_min
size = ToDouble(ToString(size_int))
ratio = size / size_max
if (ratio >= 0.8) {
  this.animal_size_adj = "Large"
}
else if (ratio <= 0.2) {
  this.animal_size_adj = "Small"
}
else {
  this.animal_size_adj = null
}
if (not GetString (this, "animal_size_adj") = null) {
  this.alias = this.animal_size_adj + " " + GetDisplayAlias (this)
}

hegemonkhan

ah, so it was just a problem of how quest handling int division, didn't recognize that this was causing scrim's problem. A generally rare case of when the truncating with int division was causing a problem.

ya, dealing with fractions/decimal values is messy and confusing, each language handles it in different ways or different functions, that gets you confused between them, lol.

if you can, it's better to not work with decimal/fractional values (in quest: Double Attributes), as they take more work underneath (though you won't notice any difference in performance most likely), as well as the issue of how they are and their roudning handled (truncated, floor, ceiling, etc etc etc ??? do you have to have them all be the same data/attribute type or can you use integers with doubles without having to convert them all to ints or doubles, etc etc etc)


btw, with programming, they have a seperate operator for handling the remainder, as in programming, you actually have to do two operations, one to get the quotient and one to get the remainder.

in quest (and many/some other languages too), it's the: %, and is known as the 'modulus' operator

9 / 4 = 2 // (quest truncates int/integer division result, so that the result is also an int/integer, as 2.5 is a double/decimal/fraction/float/floating-point)
9 % 4 = R:1

// 'R' for remainder


the modulus (remainder division) operator actually has two really useful abilities:

  1. cyclic (seconds, minutes, hours, months, days, seasons, etc etc etc)
  2. factors / divisibles / odd vs even

Cyclic example:

military_hour_clock_time = hour / 24
// it'll be one of these values: 0-23

for examples:

hour = 0
military_hour_clock_time = 0

hour = 12
military_hour_clock_time = 12

hour = 23
military_hour_clock_time = 23

hour = 24
military_hour_clock_time = 0

hour = 25
military_hour_clock_time = 1

hour = 71
military_hour_clock_time = 23

hour = 72
military_hour_clock_time = 0

hour = 73
military_hour_clock_time = 1

-------------

civilian hours:

civilian_hour_clock_time = hour % 12
// the values will be one of these: 0-11

hour = 0
civilian_hour_clock_time = 0

hour = 6
civilian_hour_clock_time = 6

hour = 11
civilian_hour_clock_time = 11

hour = 12
civilian_hour_clock_time = 0

hour = 13
civilian_hour_clock_time = 1

hour = 23
civilian_hour_clock_time = 11

hour = 24
civilian_hour_clock_time = 0

hour = 25
civilian_hour_clock_time = 1

hour = 71
civilian_hour_clock_time = 11

hour = 72
civilian_hour_clock_time = 0

hour = 73
civilian_hour_clock_time = 1

Factors-Divisibles / Odd vs Even, example:

if (number % 2 = 0) {
  msg ("The number is an even number")
} else { // every/any number divided by 2, will have R:1 (odd) or R:0 (even), so we can just use an 'else', as this is a dualistic (2 choice) outcome
  msg ("The number is an odd number")
}

or

if (number % 2 = 1) {
  msg ("The number is an odd number")
} else { // every/any number divided by 2, will have R:1 (odd) or R:0 (even), so we can just use an 'else', as this is a dualistic (2 choice) outcome
  msg ("The number is an even number")
}

----

if (number % 3 = 0) {
  msg ("The number is divisible by 3")
}
if (number % 7 = 0) {
  msg ("The number is divisible by 7")
}
if (number % 11 = 0) {
  msg ("The number is divisible by 11")
}
// etc etc etc we can do any 'number % N = 0' to determine if it's divisible by N, or to say it different: if N is a factor of number

number = 56
// 56 = 7 * 8 = 7 * 2 * 4 = 7 * 2 * 2 * 2
if (number % 3 = 0) {
  msg ("The number is divisible by 3")
}
if (number % 7 = 0) {
  msg ("The number is divisible by 7")
}
if (number % 11 = 0) {
  msg ("The number is divisible by 11")
}
// output:
The number is divisible by 7
// or to say it differently:
// 7 is a factor of 56

number = 231
// 231 = 77 * 3 = 11 * 7 * 3
if (number % 3 = 0) {
  msg ("The number is divisible by 3")
}
if (number % 7 = 0) {
  msg ("The number is divisible by 7")
}
if (number % 11 = 0) {
  msg ("The number is divisible by 11")
}
// output:
The number is divisible by 3
The number is divisible by 7
The number is divisible by 11

Log in to post a reply.

Support

Forums