Last of the config.h mods...
[blender.git] / source / gameengine / GameLogic / SCA_RandomActuator.cpp
1 /**
2  * Set random/camera stuff
3  *
4  * $Id$
5  *
6  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version. The Blender
12  * Foundation also sells licenses for use in proprietary software under
13  * the Blender License.  See http://www.blender.org/BL/ for information
14  * about this.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  *
25  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
26  * All rights reserved.
27  *
28  * The Original Code is: all of this file.
29  *
30  * Contributor(s): none yet.
31  *
32  * ***** END GPL/BL DUAL LICENSE BLOCK *****
33  */
34
35 #include "BoolValue.h"
36 #include "IntValue.h"
37 #include "FloatValue.h"
38 #include "SCA_IActuator.h"
39 #include "SCA_RandomActuator.h"
40 #include "math.h"
41 #include "MT_Transform.h"
42
43 #ifdef HAVE_CONFIG_H
44 #include <config.h>
45 #endif
46
47 /* ------------------------------------------------------------------------- */
48 /* Native functions                                                          */
49 /* ------------------------------------------------------------------------- */
50
51 SCA_RandomActuator::SCA_RandomActuator(SCA_IObject *gameobj, 
52                                                                          long seed,
53                                                                          SCA_RandomActuator::KX_RANDOMACT_MODE mode,
54                                                                          float para1,
55                                                                          float para2,
56                                                                          const STR_String &propName,
57                                                                          PyTypeObject* T)
58         : SCA_IActuator(gameobj, T),
59           m_distribution(mode),
60           m_propname(propName),
61           m_parameter1(para1),
62           m_parameter2(para2) 
63 {
64         m_base = new SCA_RandomNumberGenerator(seed);
65         m_counter = 0;
66         enforceConstraints();
67
68
69
70
71 SCA_RandomActuator::~SCA_RandomActuator()
72 {
73         /* intentionally empty */ 
74
75
76
77
78 CValue* SCA_RandomActuator::GetReplica()
79 {
80         SCA_RandomActuator* replica = new SCA_RandomActuator(*this);
81         replica->ProcessReplica();
82         CValue::AddDataToReplica(replica);
83
84         return replica;
85 }
86
87
88
89 bool SCA_RandomActuator::Update(double curtime,double deltatime)
90 {
91         bool result = false;    
92         bool bNegativeEvent = IsNegativeEvent();
93
94         RemoveAllEvents();
95
96
97         CValue *tmpval;
98
99         if (bNegativeEvent)
100                 return false; // do nothing on negative events
101
102         switch (m_distribution) {
103         case KX_RANDOMACT_BOOL_CONST: {
104                 /* un petit peu filthy */
105                 bool res = !(m_parameter1 < 0.5);
106                 tmpval = new CBoolValue(res);
107         }
108         break;
109         case KX_RANDOMACT_BOOL_UNIFORM: {
110                 /* flip a coin */
111                 bool res; 
112                 if (m_counter > 31) {
113                         m_previous = m_base->Draw();
114                         res = ((m_previous & 0x1) == 0);
115                         m_counter = 1;
116                 } else {
117                         res = (((m_previous >> m_counter) & 0x1) == 0);
118                         m_counter++;
119                 }
120                 tmpval = new CBoolValue(res);
121         }
122         break;
123         case KX_RANDOMACT_BOOL_BERNOUILLI: {
124                 /* 'percentage' */
125                 bool res;
126                 res = (m_base->DrawFloat() < m_parameter1);
127                 tmpval = new CBoolValue(res);
128         }
129         break;
130         case KX_RANDOMACT_INT_CONST: {
131                 /* constant */
132                 tmpval = new CIntValue((int) floor(m_parameter1));
133         }
134         break;
135         case KX_RANDOMACT_INT_UNIFORM: {
136                 /* uniform (toss a die) */
137                 int res; 
138                 /* The [0, 1] interval is projected onto the [min, max+1] domain,    */
139                 /* and then rounded.                                                 */
140                 res = (int) floor( ((m_parameter2 - m_parameter1 + 1) * m_base->DrawFloat())
141                                                    + m_parameter1);
142                 tmpval = new CIntValue(res);
143         }
144         break;
145         case KX_RANDOMACT_INT_POISSON: {
146                 /* poisson (queues) */
147                 /* If x_1, x_2, ... is a sequence of random numbers with uniform     */
148                 /* distribution between zero and one, k is the first integer for     */
149                 /* which the product x_1*x_2*...*x_k < exp(-\lamba).                 */
150                 float a = 0.0, b = 0.0;
151                 int res = 0;
152                 /* The - sign is important here! The number to test for, a, must be  */
153                 /* between 0 and 1.                                                  */
154                 a = exp(-m_parameter1);
155                 /* a quickly reaches 0.... so we guard explicitly for that.          */
156                 if (a < FLT_MIN) a = FLT_MIN;
157                 b = m_base->DrawFloat();
158                 while (b >= a) {
159                         b = b * m_base->DrawFloat();
160                         res++;
161                 };      
162                 tmpval = new CIntValue(res);
163         }
164         break;
165         case KX_RANDOMACT_FLOAT_CONST: {
166                 /* constant */
167                 tmpval = new CFloatValue(m_parameter1);
168         }
169         break;
170         case KX_RANDOMACT_FLOAT_UNIFORM: {
171                 float res = ((m_parameter2 - m_parameter1) * m_base->DrawFloat())
172                         + m_parameter1;
173                 tmpval = new CFloatValue(res);
174         }
175         break;
176         case KX_RANDOMACT_FLOAT_NORMAL: {
177                 /* normal (big numbers): para1 = mean, para2 = std dev               */
178
179                 /* 
180
181                    070301 - nzc - Changed the termination condition. I think I 
182                    made a small mistake here, but it only affects distro's where
183                    the seed equals 0. In that case, the algorithm locks. Let's
184                    just guard that case separately.
185
186                 */
187
188                 float x = 0.0, y = 0.0, s = 0.0, t = 0.0;
189                 if (m_base->GetSeed() == 0) {
190                         /*
191
192                           070301 - nzc 
193                           Just taking the mean here seems reasonable.
194
195                          */
196                         tmpval = new CFloatValue(m_parameter1);
197                 } else {
198                         /*
199
200                           070301 - nzc 
201                           Now, with seed != 0, we will most assuredly get some
202                           sensible values. The termination condition states two 
203                           things: 
204                           1. s >= 0 is not allowed: to prevent the distro from 
205                              getting a bias towards high values. This is a small 
206                                  correction, really, and might also be left out.
207                           2. s == 0 is not allowed: to prevent a division by zero
208                              when renormalising the drawn value to the desired 
209                                  distribution shape. As a side effect, the distro will
210                                  never yield the exact mean. 
211                           I am not sure whether this is consistent, since the error 
212                           cause by #2 is of the same magnitude as the one 
213                           prevented by #1. The error introduced into the SD will be 
214                           improved, though. By how much? Hard to say... If you like
215                           the maths, feel free to analyse. Be aware that this is 
216                           one of the really old standard algorithms. I think the 
217                           original came in Fortran, was translated to Pascal, and 
218                           then someone came up with the C code. My guess it that
219                           this will be quite sufficient here.
220
221                          */
222                         do 
223                         {
224                                 x = 2.0 * m_base->DrawFloat() - 1.0;
225                                 y = 2.0 * m_base->DrawFloat() - 1.0;
226                                 s = x*x + y*y;
227                         } while ( (s >= 1.0) || (s == 0.0) );
228                         t = x * sqrt( (-2.0 * log(s)) / s);
229                         tmpval = new CFloatValue(m_parameter1 + m_parameter2 * t);
230                 }
231         }
232         break;
233         case KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL: {
234                 /* 1st order fall-off. I am very partial to using the half-life as    */
235                 /* controlling parameter. Using the 'normal' exponent is not very     */
236                 /* intuitive...                                                       */
237                 /* tmpval = new CFloatValue( (1.0 / m_parameter1)                     */
238                 tmpval = new CFloatValue( (m_parameter1) 
239                                                                   * (-log(1.0 - m_base->DrawFloat())) );
240
241         }
242         break;
243         default:
244                 ; /* unknown distribution... */
245         }
246
247         /* Round up: assign it */
248         CValue *prop = GetParent()->GetProperty(m_propname);
249         if (prop) {
250                 prop->SetValue(tmpval);
251         }
252         tmpval->Release();
253
254         return false;
255 }
256
257 void SCA_RandomActuator::enforceConstraints() {
258         /* The constraints that are checked here are the ones fundamental to     */
259         /* the various distributions. Limitations of the algorithms are checked  */
260         /* elsewhere (or they should be... ).                                    */
261         switch (m_distribution) {
262         case KX_RANDOMACT_BOOL_CONST:
263         case KX_RANDOMACT_BOOL_UNIFORM:
264         case KX_RANDOMACT_INT_CONST:
265         case KX_RANDOMACT_INT_UNIFORM:
266         case KX_RANDOMACT_FLOAT_UNIFORM:
267         case KX_RANDOMACT_FLOAT_CONST:
268                 ; /* Nothing to be done here. We allow uniform distro's to have      */
269                 /* 'funny' domains, i.e. max < min. This does not give problems.     */
270                 break;
271         case KX_RANDOMACT_BOOL_BERNOUILLI: 
272                 /* clamp to [0, 1] */
273                 if (m_parameter1 < 0.0) {
274                         m_parameter1 = 0.0;
275                 } else if (m_parameter1 > 1.0) {
276                         m_parameter1 = 1.0;
277                 }
278                 break;
279         case KX_RANDOMACT_INT_POISSON: 
280                 /* non-negative */
281                 if (m_parameter1 < 0.0) {
282                         m_parameter1 = 0.0;
283                 }
284                 break;
285         case KX_RANDOMACT_FLOAT_NORMAL: 
286                 /* standard dev. is non-negative */
287                 if (m_parameter2 < 0.0) {
288                         m_parameter2 = 0.0;
289                 }
290                 break;
291         case KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL: 
292                 /* halflife must be non-negative */
293                 if (m_parameter1 < 0.0) {
294                         m_parameter1 = 0.0;
295                 }
296                 break;
297         default:
298                 ; /* unknown distribution... */
299         }
300 }
301
302 /* ------------------------------------------------------------------------- */
303 /* Python functions                                                          */
304 /* ------------------------------------------------------------------------- */
305
306 /* Integration hooks ------------------------------------------------------- */
307 PyTypeObject SCA_RandomActuator::Type = {
308         PyObject_HEAD_INIT(&PyType_Type)
309         0,
310         "SCA_RandomActuator",
311         sizeof(SCA_RandomActuator),
312         0,
313         PyDestructor,
314         0,
315         __getattr,
316         __setattr,
317         0, //&MyPyCompare,
318         __repr,
319         0, //&cvalue_as_number,
320         0,
321         0,
322         0,
323         0
324 };
325
326 PyParentObject SCA_RandomActuator::Parents[] = {
327         &SCA_RandomActuator::Type,
328         &SCA_IActuator::Type,
329         &SCA_ILogicBrick::Type,
330         &CValue::Type,
331         NULL
332 };
333
334 PyMethodDef SCA_RandomActuator::Methods[] = {
335         {"setSeed",         (PyCFunction) SCA_RandomActuator::sPySetSeed, METH_VARARGS, SetSeed_doc},
336         {"getSeed",         (PyCFunction) SCA_RandomActuator::sPyGetSeed, METH_VARARGS, GetSeed_doc},
337         {"getPara1",        (PyCFunction) SCA_RandomActuator::sPyGetPara1, METH_VARARGS, GetPara1_doc},
338         {"getPara2",        (PyCFunction) SCA_RandomActuator::sPyGetPara2, METH_VARARGS, GetPara2_doc},
339         {"getDistribution", (PyCFunction) SCA_RandomActuator::sPyGetDistribution, METH_VARARGS, GetDistribution_doc},
340         {"setProperty",     (PyCFunction) SCA_RandomActuator::sPySetProperty, METH_VARARGS, SetProperty_doc},
341         {"getProperty",     (PyCFunction) SCA_RandomActuator::sPyGetProperty, METH_VARARGS, GetProperty_doc},
342         {"setBoolConst",    (PyCFunction) SCA_RandomActuator::sPySetBoolConst, METH_VARARGS, SetBoolConst_doc},
343         {"setBoolUniform",  (PyCFunction) SCA_RandomActuator::sPySetBoolUniform, METH_VARARGS, SetBoolUniform_doc},
344         {"setBoolBernouilli",(PyCFunction) SCA_RandomActuator::sPySetBoolBernouilli, METH_VARARGS, SetBoolBernouilli_doc},
345         {"setIntConst",     (PyCFunction) SCA_RandomActuator::sPySetIntConst, METH_VARARGS, SetIntConst_doc},
346         {"setIntUniform",   (PyCFunction) SCA_RandomActuator::sPySetIntUniform, METH_VARARGS, SetIntUniform_doc},
347         {"setIntPoisson",   (PyCFunction) SCA_RandomActuator::sPySetIntPoisson, METH_VARARGS, SetIntPoisson_doc},
348         {"setFloatConst",   (PyCFunction) SCA_RandomActuator::sPySetFloatConst, METH_VARARGS, SetFloatConst_doc},
349         {"setFloatUniform", (PyCFunction) SCA_RandomActuator::sPySetFloatUniform, METH_VARARGS, SetFloatUniform_doc},
350         {"setFloatNormal",  (PyCFunction) SCA_RandomActuator::sPySetFloatNormal, METH_VARARGS, SetFloatNormal_doc},
351         {"setFloatNegativeExponential", (PyCFunction) SCA_RandomActuator::sPySetFloatNegativeExponential, METH_VARARGS, SetFloatNegativeExponential_doc},
352         {NULL,NULL} //Sentinel
353 };
354
355 PyObject* SCA_RandomActuator::_getattr(char* attr) {
356         _getattr_up(SCA_IActuator);
357 }
358
359 /* 1. setSeed                                                            */
360 char SCA_RandomActuator::SetSeed_doc[] = 
361 "setSeed(seed)\n"
362 "\t- seed: integer\n"
363 "\tSet the initial seed of the generator. Equal seeds produce\n"
364 "\tequal series. If the seed is 0, the generator will produce\n"
365 "\tthe same value on every call.\n";
366 PyObject* SCA_RandomActuator::PySetSeed(PyObject* self, PyObject* args, PyObject* kwds) {
367         long seedArg;
368         if(!PyArg_ParseTuple(args, "i", &seedArg)) {
369                 return NULL;
370         }
371         
372         m_base->SetSeed(seedArg);
373         
374         Py_Return;
375 }
376 /* 2. getSeed                                                            */
377 char SCA_RandomActuator::GetSeed_doc[] = 
378 "getSeed()\n"
379 "\tReturns the initial seed of the generator. Equal seeds produce\n"
380 "\tequal series.\n";
381 PyObject* SCA_RandomActuator::PyGetSeed(PyObject* self, PyObject* args, PyObject* kwds) {
382         return PyInt_FromLong(m_base->GetSeed());
383 }
384
385 /* 4. getPara1                                                           */
386 char SCA_RandomActuator::GetPara1_doc[] = 
387 "getPara1()\n"
388 "\tReturns the first parameter of the active distribution. Refer\n"
389 "\tto the documentation of the generator types for the meaning\n"
390 "\tof this value.";
391 PyObject* SCA_RandomActuator::PyGetPara1(PyObject* self, PyObject* args, PyObject* kwds) {
392         return PyFloat_FromDouble(m_parameter1);
393 }
394
395 /* 6. getPara2                                                           */
396 char SCA_RandomActuator::GetPara2_doc[] = 
397 "getPara2()\n"
398 "\tReturns the first parameter of the active distribution. Refer\n"
399 "\tto the documentation of the generator types for the meaning\n"
400 "\tof this value.";
401 PyObject* SCA_RandomActuator::PyGetPara2(PyObject* self, PyObject* args, PyObject* kwds) {
402         return PyFloat_FromDouble(m_parameter2);
403 }
404
405 /* 8. getDistribution                                                    */
406 char SCA_RandomActuator::GetDistribution_doc[] = 
407 "getDistribution()\n"
408 "\tReturns the type of the active distribution.\n";
409 PyObject* SCA_RandomActuator::PyGetDistribution(PyObject* self, PyObject* args, PyObject* kwds) {
410         return PyInt_FromLong(m_distribution);
411 }
412
413 /* 9. setProperty                                                        */
414 char SCA_RandomActuator::SetProperty_doc[] = 
415 "setProperty(name)\n"
416 "\t- name: string\n"
417 "\tSet the property to which the random value is assigned. If the \n"
418 "\tgenerator and property types do not match, the assignment is ignored.\n";
419 PyObject* SCA_RandomActuator::PySetProperty(PyObject* self, PyObject* args, PyObject* kwds) {
420         char *nameArg;
421         if (!PyArg_ParseTuple(args, "s", &nameArg)) {
422                 return NULL;
423         }
424
425         CValue* prop = GetParent()->FindIdentifier(nameArg);
426
427         if (prop) {
428                 m_propname = nameArg;
429                 prop->Release();
430         } else {
431                 ; /* not found ... */
432         }
433         
434         Py_Return;
435 }
436 /* 10. getProperty                                                       */
437 char SCA_RandomActuator::GetProperty_doc[] = 
438 "getProperty(name)\n"
439 "\tReturn the property to which the random value is assigned. If the \n"
440 "\tgenerator and property types do not match, the assignment is ignored.\n";
441 PyObject* SCA_RandomActuator::PyGetProperty(PyObject* self, PyObject* args, PyObject* kwds) {
442         return PyString_FromString(m_propname);
443 }
444
445 /* 11. setBoolConst */
446 char SCA_RandomActuator::SetBoolConst_doc[] = 
447 "setBoolConst(value)\n"
448 "\t- value: 0 or 1\n"
449 "\tSet this generator to produce a constant boolean value.\n";
450 PyObject* SCA_RandomActuator::PySetBoolConst(PyObject* self, 
451                                                                                         PyObject* args, 
452                                                                                         PyObject* kwds) {
453         int paraArg;
454         if(!PyArg_ParseTuple(args, "i", &paraArg)) {
455                 return NULL;
456         }
457         
458         m_distribution = KX_RANDOMACT_BOOL_CONST;
459         if (paraArg == KX_TRUE) {
460                 m_parameter1 = 1;
461         }
462         
463         Py_Return;
464 }
465 /* 12. setBoolUniform, */
466 char SCA_RandomActuator::SetBoolUniform_doc[] = 
467 "setBoolUniform()\n"
468 "\tSet this generator to produce true and false, each with 50%% chance of occuring\n";
469 PyObject* SCA_RandomActuator::PySetBoolUniform(PyObject* self, 
470                                                                                           PyObject* args, 
471                                                                                           PyObject* kwds) {
472         /* no args */
473         m_distribution = KX_RANDOMACT_BOOL_UNIFORM;
474         enforceConstraints();
475         Py_Return;
476 }
477 /* 13. setBoolBernouilli,  */
478 char SCA_RandomActuator::SetBoolBernouilli_doc[] = 
479 "setBoolBernouilli(value)\n"
480 "\t- value: a float between 0 and 1\n"
481 "\tReturn false value * 100%% of the time.\n";
482 PyObject* SCA_RandomActuator::PySetBoolBernouilli(PyObject* self, 
483                                                                                                  PyObject* args, 
484                                                                                                  PyObject* kwds) {
485         float paraArg;
486         if(!PyArg_ParseTuple(args, "f", &paraArg)) {
487                 return NULL;
488         }
489         
490         m_distribution = KX_RANDOMACT_BOOL_CONST;
491         m_parameter1 = paraArg; 
492         enforceConstraints();
493         Py_Return;
494 }
495 /* 14. setIntConst,*/
496 char SCA_RandomActuator::SetIntConst_doc[] = 
497 "setIntConst(value)\n"
498 "\t- value: integer\n"
499 "\tAlways return value\n";
500 PyObject* SCA_RandomActuator::PySetIntConst(PyObject* self, 
501                                                                                    PyObject* args, 
502                                                                                    PyObject* kwds) {
503         int paraArg;
504         if(!PyArg_ParseTuple(args, "i", &paraArg)) {
505                 return NULL;
506         }
507         
508         m_distribution = KX_RANDOMACT_INT_CONST;
509         m_parameter1 = paraArg;
510         enforceConstraints();
511         Py_Return;
512 }
513 /* 15. setIntUniform,*/
514 char SCA_RandomActuator::SetIntUniform_doc[] = 
515 "setIntUniform(lower_bound, upper_bound)\n"
516 "\t- lower_bound: integer\n"
517 "\t- upper_bound: integer\n"
518 "\tReturn a random integer between lower_bound and\n"
519 "\tupper_bound. The boundaries are included.\n";
520 PyObject* SCA_RandomActuator::PySetIntUniform(PyObject* self, 
521                                                                                          PyObject* args, 
522                                                                                          PyObject* kwds) {
523         int paraArg1, paraArg2;
524         if(!PyArg_ParseTuple(args, "ii", &paraArg1, &paraArg2)) {
525                 return NULL;
526         }
527         
528         m_distribution = KX_RANDOMACT_INT_UNIFORM;
529         m_parameter1 = paraArg1;
530         m_parameter2 = paraArg2;
531         enforceConstraints();
532         Py_Return;
533 }
534 /* 16. setIntPoisson,           */
535 char SCA_RandomActuator::SetIntPoisson_doc[] = 
536 "setIntPoisson(value)\n"
537 "\t- value: float\n"
538 "\tReturn a Poisson-distributed number. This performs a series\n"
539 "\tof Bernouilli tests with parameter value. It returns the\n"
540 "\tnumber of tries needed to achieve succes.\n";
541 PyObject* SCA_RandomActuator::PySetIntPoisson(PyObject* self, 
542                                                                                          PyObject* args, 
543                                                                                          PyObject* kwds) {
544         float paraArg;
545         if(!PyArg_ParseTuple(args, "f", &paraArg)) {
546                 return NULL;
547         }
548         
549         m_distribution = KX_RANDOMACT_INT_POISSON;
550         m_parameter1 = paraArg; 
551         enforceConstraints();
552         Py_Return;
553 }
554 /* 17. setFloatConst,*/
555 char SCA_RandomActuator::SetFloatConst_doc[] = 
556 "setFloatConst(value)\n"
557 "\t- value: float\n"
558 "\tAlways return value\n";
559 PyObject* SCA_RandomActuator::PySetFloatConst(PyObject* self, 
560                                                                                          PyObject* args, 
561                                                                                          PyObject* kwds) {
562         float paraArg;
563         if(!PyArg_ParseTuple(args, "f", &paraArg)) {
564                 return NULL;
565         }
566         
567         m_distribution = KX_RANDOMACT_FLOAT_CONST;
568         m_parameter1 = paraArg; 
569         enforceConstraints();
570         Py_Return;
571 }
572 /* 18. setFloatUniform, */
573 char SCA_RandomActuator::SetFloatUniform_doc[] = 
574 "setFloatUniform(lower_bound, upper_bound)\n"
575 "\t- lower_bound: float\n"
576 "\t- upper_bound: float\n"
577 "\tReturn a random integer between lower_bound and\n"
578 "\tupper_bound.\n";
579 PyObject* SCA_RandomActuator::PySetFloatUniform(PyObject* self, 
580                                                                                            PyObject* args, 
581                                                                                            PyObject* kwds) {
582         float paraArg1, paraArg2;
583         if(!PyArg_ParseTuple(args, "ff", &paraArg1, &paraArg2)) {
584                 return NULL;
585         }
586         
587         m_distribution = KX_RANDOMACT_FLOAT_UNIFORM;
588         m_parameter1 = paraArg1;
589         m_parameter2 = paraArg2;
590         enforceConstraints();
591         Py_Return;
592 }
593 /* 19. setFloatNormal, */
594 char SCA_RandomActuator::SetFloatNormal_doc[] = 
595 "setFloatNormal(mean, standard_deviation)\n"
596 "\t- mean: float\n"
597 "\t- standard_deviation: float\n"
598 "\tReturn normal-distributed numbers. The average is mean, and the\n"
599 "\tdeviation from the mean is characterized by standard_deviation.\n";
600 PyObject* SCA_RandomActuator::PySetFloatNormal(PyObject* self, 
601                                                                                           PyObject* args, 
602                                                                                           PyObject* kwds) {
603         float paraArg1, paraArg2;
604         if(!PyArg_ParseTuple(args, "ff", &paraArg1, &paraArg2)) {
605                 return NULL;
606         }
607         
608         m_distribution = KX_RANDOMACT_FLOAT_NORMAL;
609         m_parameter1 = paraArg1;
610         m_parameter2 = paraArg2;
611         enforceConstraints();
612         Py_Return;
613 }
614 /* 20. setFloatNegativeExponential, */
615 char SCA_RandomActuator::SetFloatNegativeExponential_doc[] = 
616 "setFloatNegativeExponential(half_life)\n"
617 "\t- half_life: float\n"
618 "\tReturn negative-exponentially distributed numbers. The half-life 'time'\n"
619 "\tis characterized by half_life.\n";
620 PyObject* SCA_RandomActuator::PySetFloatNegativeExponential(PyObject* self, 
621                                                                                                                    PyObject* args, 
622                                                                                                                    PyObject* kwds) {
623         float paraArg;
624         if(!PyArg_ParseTuple(args, "f", &paraArg)) {
625                 return NULL;
626         }
627         
628         m_distribution = KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL;
629         m_parameter1 = paraArg; 
630         enforceConstraints();
631         Py_Return;
632 }
633         
634 /* eof */