```
md = mo.GeGetMoData(op)
mode = md.GetBlendID()
if mode == c4d.ID_MG_BASEEFFECTOR_SCALE:
rVal = 1
else:
rVal = 0
```

Fairly basic

And you know, the first *if* is never *true*. Despite ID_MG_BASEEFFECTOR_POSITION is working.

I tried ID_MG_BASEEFFECTOR_SCALE_ACTIVE but nothing changed.

Than I checked what *mode* is. Whatever I do it's always returning the same:

```
1010
1011
1012
1013
1013
1013
1065
1066
1067
1064
1068
1069
1020
19
20
```

There are all kinds of the modes enumerations (can be found in \resource\modules\objects\description\obaseeffector.h) despite only Scale (1013) is active. So I don't understand what is that.

Why doesn't it work? And how should it?

I am sorry, I hate it myself when people talk in acronyms, assuming everyone knows what they are referring to. PNG stands for Pseudo-random Number Generator. Here is an example for a simple trigonometric pseudo random hash function.

Cheers,

zipit

```
"""A simple example for a very simple "one-at-a-time" Pseudo-random Number
Generator (PNG).
It is basically just one line of code, which you can find on line 32.
"""
import c4d
import math
def hash_11(x, seed=1234, magic=(1234.4567, 98765.4321)):
"""Returns a pseudo random floating point hash for a floating point number.
The hash will lie int the interval [-1, 1] and the function is a very
simple generator that exploits the periodicity of the trigonometric
functions. A more sophisticated approach would be to exploit avalanche
behavior in bit-shift operations on binary data, like the Jenkins
Rotation does for example.
The postfix in the name (_11) is a common way to denote the inputs and
outputs for PNGs. 11 means that it will take one (real) number and return
one (real) number. 13 means that it takes one and returns three, i.e. returns
an (euclidean) vector.
Args:
x (float): The value to hash into a pseudo random number.
seed (int, optional): The seed value. This could also be a float.
magic (tuple, optional): The magic numbers. The second one should be
bigger then the first and both should be real numbers.
Returns:
float: The pseudo random hash for x in the interval [-1, 1].
"""
return math.modf(math.sin(x + seed + magic[0]) * magic[1])[0]
def hash_13(x, seed=1234, magic=(1234.4567, 98765.4321)):
"""Returns a pseudo random vector hash for a floating point number.
Wraps around hash_11.
Returns:
c4d.Vector: The pseudo random hash for x in the interval [-1, 1].
"""
vx = hash_11(x, seed, magic)
vy = hash_11(x + vx, seed, magic)
vz = hash_11(x + vy, seed, magic)
return c4d.Vector(vx, vy, vz)
def main():
"""Entry point.
"""
# Some very crude statistics for the hashes.
samples = int(1E6)
# Generate 1E6 of each
numbers = {i: hash_11(i) for i in range(samples)}
vectors = {i: hash_13(i) for i in range(samples)}
# Compute their arithmetic mean.
amean_numbers = sum(numbers.values()) * (1./samples)
amean_vectors = sum(vectors.values()) * (1./samples)
# Report the results.
print "First three random numbers: ", numbers.values()[:3]
print "First three random vectors: ", vectors.values()[:3]
msg = "Arithmetic mean of all random numbers (should converge to zero): "
print msg, amean_numbers
msg = "Arithmetic mean of all random vectors (should converge to zero): "
print msg, amean_vectors
if __name__ == "__main__":
main()
```

```
First three random numbers: [-0.8036933662078809, 0.20401213006516628, 0.6249060598929645]
First three random vectors: [Vector(-0.804, -0.022, -0.872), Vector(0.204, 0.541, 0.115), Vector(0.625, 0.782, 0.896)]
Arithmetic mean of all random numbers (should converge to zero): -0.000127638074863
Arithmetic mean of all random vectors (should converge to zero): Vector(0, 0, 0)
```

]]>I'm slightly confused by the topic you cover, can't find what PNG is.

What should I do with random.seed than if I rely on unique random number generated for the particular clone? I can't move it out of main() because only there ID is accessible.

Make some class to store there those random numbers as globals and check should I generate it again or use as before based on user data seed and clone count?

I am glad that it worked out for you, but since you posted your code now, I spotted a few problems around your random number generation, specifically in this line:

```
random.seed(md.GetCount() * index * op[c4d.ID_USERDATA,1])
```

Only a minor detail is that `md.GetCount() * index * op[c4d.ID_USERDATA,1]`

might cause an integer overflow, since this is effectively some large number to the power of three. An overflow is unlikely, but could lead to unexpected behaviour.

More important is that `random.seed`

is a expensive function, because it will build the permutation table of Python's Mersenne-Twister random number sequence generator each time it is being called. You calling `random.seed`

inside the `main`

function means that this is being done potentially millions of times per frame. You should:

- either call
`random.seed`

only once outside the`main`

function - or, if you want your random values seed to be animatable via the user data value, at least safeguard the
`random.seed`

so that it is only being called when needed.

There is also the problem that the state of your PNG permutation table is dependent on the order in which the particles are being queried, due to the fact that you call the global random instance inside a conditional statement (`random.choice([-1, 1])`

) and the general design of using a sequence based PNG here in the first place.

You could solve all the above by using a custom PNG, the common trigonometric one-liner PNG would be enough. It also would be much more performant.

Cheers,

zipit

I am a bit confused, because the integer value for the symbol in question, is right there in your print out (1011 is integer value for `c4d.ID_MG_BASEEFFECTOR_SCALE `

Sorry, that's my typo of course.

My code actually looks like this:

```
import c4d
from c4d.modules import mograph as mo
import random
#Welcome to the world of Python
def main():
md = mo.GeGetMoData(op)
if md is None: return 1.0
mode = md.GetBlendID()
index = md.GetCurrentIndex()
random.seed(md.GetCount() * index * op[c4d.ID_USERDATA,1])
rIndex = random.randint(0,2)
if mode == c4d.ID_MG_BASEEFFECTOR_SCALE:
rVal = 1
else:
rVal = random.choice([-1, 1])
weights = md.GetArray(c4d.MODATA_WEIGHT)
#print rVal
vector = c4d.Vector()
vector[rIndex] = rVal * weights[index]
if mode == c4d.ID_MG_BASEEFFECTOR_POSITION or mode == c4d.ID_MG_BASEEFFECTOR_ROTATION or mode == c4d.ID_MG_BASEEFFECTOR_SCALE:
return vector
else: return 1.0
```

It's point is to randomly choose the axis which the value will be added to. It can give results as in attached image

But to avoid negative scale I check if the Scale is active. But weirdly my code with the same check as yours never worked. For some reason I copied your and despite it's the same letter to letter now it works.

I'm confused...

But thanks for your answer anyway!

]]>I am a bit confused, because the integer value for the symbol in question, is right there in your print out (1011 is integer value for `c4d.ID_MG_BASEEFFECTOR_SCALE `

). So it is unclear to me, what you would consider not working, since you did not give us the whole script. Anyways, here is a short example:

```
""" This snippet is intended for a Python Effector in "Parameter Control"
mode. Things will change fundamently when in "Full Control" mode.
"""
import c4d
from c4d.modules import mograph
def main():
# Get the MoData or get out when we could not access the data.
md = mograph.GeGetMoData(op)
if md is None:
return 1.0
# Get the category for which the effector is being polled.
mode = md.GetBlendID()
# The effector is being polled for Parameter/Position.
if mode == c4d.ID_MG_BASEEFFECTOR_POSITION:
# The component wise product of this returned vector and the vector
# specified by the user in the interface will be the final value
# for the current particle. E.g., if the user specified (0, 50, 0),
# then the final result would be (0, 50, 0) ^ (2, 2, 2), i.e.
# (0, 100, 0).
return c4d.Vector(2)
# The effector is being polled for Parameter/Scale.
elif mode == c4d.ID_MG_BASEEFFECTOR_SCALE:
# For the scale parameter things work analogously, this would ensure that
# only half of the value specified by the user will apply.
return c4d.Vector(.5)
# When we reached this point, we do not want to change anything and return
# `1` to indicate that.
return 1.0
```

Cheers,

zipit