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