Filling in branch from trunk
[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_propname(propName),
60           m_parameter1(para1),
61           m_parameter2(para2),
62           m_distribution(mode)
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()
90 {
91         //bool result = false;  /*unused*/
92         bool bNegativeEvent = IsNegativeEvent();
93
94         RemoveAllEvents();
95
96
97         CValue *tmpval = NULL;
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         {
245                 /* unknown distribution... */
246                 static bool randomWarning = false;
247                 if (!randomWarning) {
248                         randomWarning = true;
249                         std::cout << "RandomActuator '" << GetName() << "' has an unknown distribution." << std::endl;
250                 }
251                 return false;
252         }
253         }
254
255         /* Round up: assign it */
256         CValue *prop = GetParent()->GetProperty(m_propname);
257         if (prop) {
258                 prop->SetValue(tmpval);
259         }
260         tmpval->Release();
261
262         return false;
263 }
264
265 void SCA_RandomActuator::enforceConstraints() {
266         /* The constraints that are checked here are the ones fundamental to     */
267         /* the various distributions. Limitations of the algorithms are checked  */
268         /* elsewhere (or they should be... ).                                    */
269         switch (m_distribution) {
270         case KX_RANDOMACT_BOOL_CONST:
271         case KX_RANDOMACT_BOOL_UNIFORM:
272         case KX_RANDOMACT_INT_CONST:
273         case KX_RANDOMACT_INT_UNIFORM:
274         case KX_RANDOMACT_FLOAT_UNIFORM:
275         case KX_RANDOMACT_FLOAT_CONST:
276                 ; /* Nothing to be done here. We allow uniform distro's to have      */
277                 /* 'funny' domains, i.e. max < min. This does not give problems.     */
278                 break;
279         case KX_RANDOMACT_BOOL_BERNOUILLI: 
280                 /* clamp to [0, 1] */
281                 if (m_parameter1 < 0.0) {
282                         m_parameter1 = 0.0;
283                 } else if (m_parameter1 > 1.0) {
284                         m_parameter1 = 1.0;
285                 }
286                 break;
287         case KX_RANDOMACT_INT_POISSON: 
288                 /* non-negative */
289                 if (m_parameter1 < 0.0) {
290                         m_parameter1 = 0.0;
291                 }
292                 break;
293         case KX_RANDOMACT_FLOAT_NORMAL: 
294                 /* standard dev. is non-negative */
295                 if (m_parameter2 < 0.0) {
296                         m_parameter2 = 0.0;
297                 }
298                 break;
299         case KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL: 
300                 /* halflife must be non-negative */
301                 if (m_parameter1 < 0.0) {
302                         m_parameter1 = 0.0;
303                 }
304                 break;
305         default:
306                 ; /* unknown distribution... */
307         }
308 }
309
310 /* ------------------------------------------------------------------------- */
311 /* Python functions                                                          */
312 /* ------------------------------------------------------------------------- */
313
314 /* Integration hooks ------------------------------------------------------- */
315 PyTypeObject SCA_RandomActuator::Type = {
316         PyObject_HEAD_INIT(&PyType_Type)
317         0,
318         "SCA_RandomActuator",
319         sizeof(SCA_RandomActuator),
320         0,
321         PyDestructor,
322         0,
323         __getattr,
324         __setattr,
325         0, //&MyPyCompare,
326         __repr,
327         0, //&cvalue_as_number,
328         0,
329         0,
330         0,
331         0
332 };
333
334 PyParentObject SCA_RandomActuator::Parents[] = {
335         &SCA_RandomActuator::Type,
336         &SCA_IActuator::Type,
337         &SCA_ILogicBrick::Type,
338         &CValue::Type,
339         NULL
340 };
341
342 PyMethodDef SCA_RandomActuator::Methods[] = {
343         {"setSeed",         (PyCFunction) SCA_RandomActuator::sPySetSeed, METH_VARARGS, SetSeed_doc},
344         {"getSeed",         (PyCFunction) SCA_RandomActuator::sPyGetSeed, METH_VARARGS, GetSeed_doc},
345         {"getPara1",        (PyCFunction) SCA_RandomActuator::sPyGetPara1, METH_VARARGS, GetPara1_doc},
346         {"getPara2",        (PyCFunction) SCA_RandomActuator::sPyGetPara2, METH_VARARGS, GetPara2_doc},
347         {"getDistribution", (PyCFunction) SCA_RandomActuator::sPyGetDistribution, METH_VARARGS, GetDistribution_doc},
348         {"setProperty",     (PyCFunction) SCA_RandomActuator::sPySetProperty, METH_VARARGS, SetProperty_doc},
349         {"getProperty",     (PyCFunction) SCA_RandomActuator::sPyGetProperty, METH_VARARGS, GetProperty_doc},
350         {"setBoolConst",    (PyCFunction) SCA_RandomActuator::sPySetBoolConst, METH_VARARGS, SetBoolConst_doc},
351         {"setBoolUniform",  (PyCFunction) SCA_RandomActuator::sPySetBoolUniform, METH_VARARGS, SetBoolUniform_doc},
352         {"setBoolBernouilli",(PyCFunction) SCA_RandomActuator::sPySetBoolBernouilli, METH_VARARGS, SetBoolBernouilli_doc},
353         {"setIntConst",     (PyCFunction) SCA_RandomActuator::sPySetIntConst, METH_VARARGS, SetIntConst_doc},
354         {"setIntUniform",   (PyCFunction) SCA_RandomActuator::sPySetIntUniform, METH_VARARGS, SetIntUniform_doc},
355         {"setIntPoisson",   (PyCFunction) SCA_RandomActuator::sPySetIntPoisson, METH_VARARGS, SetIntPoisson_doc},
356         {"setFloatConst",   (PyCFunction) SCA_RandomActuator::sPySetFloatConst, METH_VARARGS, SetFloatConst_doc},
357         {"setFloatUniform", (PyCFunction) SCA_RandomActuator::sPySetFloatUniform, METH_VARARGS, SetFloatUniform_doc},
358         {"setFloatNormal",  (PyCFunction) SCA_RandomActuator::sPySetFloatNormal, METH_VARARGS, SetFloatNormal_doc},
359         {"setFloatNegativeExponential", (PyCFunction) SCA_RandomActuator::sPySetFloatNegativeExponential, METH_VARARGS, SetFloatNegativeExponential_doc},
360         {NULL,NULL} //Sentinel
361 };
362
363 PyObject* SCA_RandomActuator::_getattr(const STR_String& attr) {
364         _getattr_up(SCA_IActuator);
365 }
366
367 /* 1. setSeed                                                            */
368 char SCA_RandomActuator::SetSeed_doc[] = 
369 "setSeed(seed)\n"
370 "\t- seed: integer\n"
371 "\tSet the initial seed of the generator. Equal seeds produce\n"
372 "\tequal series. If the seed is 0, the generator will produce\n"
373 "\tthe same value on every call.\n";
374 PyObject* SCA_RandomActuator::PySetSeed(PyObject* self, PyObject* args, PyObject* kwds) {
375         long seedArg;
376         if(!PyArg_ParseTuple(args, "i", &seedArg)) {
377                 return NULL;
378         }
379         
380         m_base->SetSeed(seedArg);
381         
382         Py_Return;
383 }
384 /* 2. getSeed                                                            */
385 char SCA_RandomActuator::GetSeed_doc[] = 
386 "getSeed()\n"
387 "\tReturns the initial seed of the generator. Equal seeds produce\n"
388 "\tequal series.\n";
389 PyObject* SCA_RandomActuator::PyGetSeed(PyObject* self, PyObject* args, PyObject* kwds) {
390         return PyInt_FromLong(m_base->GetSeed());
391 }
392
393 /* 4. getPara1                                                           */
394 char SCA_RandomActuator::GetPara1_doc[] = 
395 "getPara1()\n"
396 "\tReturns the first parameter of the active distribution. Refer\n"
397 "\tto the documentation of the generator types for the meaning\n"
398 "\tof this value.";
399 PyObject* SCA_RandomActuator::PyGetPara1(PyObject* self, PyObject* args, PyObject* kwds) {
400         return PyFloat_FromDouble(m_parameter1);
401 }
402
403 /* 6. getPara2                                                           */
404 char SCA_RandomActuator::GetPara2_doc[] = 
405 "getPara2()\n"
406 "\tReturns the first parameter of the active distribution. Refer\n"
407 "\tto the documentation of the generator types for the meaning\n"
408 "\tof this value.";
409 PyObject* SCA_RandomActuator::PyGetPara2(PyObject* self, PyObject* args, PyObject* kwds) {
410         return PyFloat_FromDouble(m_parameter2);
411 }
412
413 /* 8. getDistribution                                                    */
414 char SCA_RandomActuator::GetDistribution_doc[] = 
415 "getDistribution()\n"
416 "\tReturns the type of the active distribution.\n";
417 PyObject* SCA_RandomActuator::PyGetDistribution(PyObject* self, PyObject* args, PyObject* kwds) {
418         return PyInt_FromLong(m_distribution);
419 }
420
421 /* 9. setProperty                                                        */
422 char SCA_RandomActuator::SetProperty_doc[] = 
423 "setProperty(name)\n"
424 "\t- name: string\n"
425 "\tSet the property to which the random value is assigned. If the \n"
426 "\tgenerator and property types do not match, the assignment is ignored.\n";
427 PyObject* SCA_RandomActuator::PySetProperty(PyObject* self, PyObject* args, PyObject* kwds) {
428         char *nameArg;
429         if (!PyArg_ParseTuple(args, "s", &nameArg)) {
430                 return NULL;
431         }
432
433         CValue* prop = GetParent()->FindIdentifier(nameArg);
434
435         if (prop) {
436                 m_propname = nameArg;
437                 prop->Release();
438         } else {
439                 ; /* not found ... */
440         }
441         
442         Py_Return;
443 }
444 /* 10. getProperty                                                       */
445 char SCA_RandomActuator::GetProperty_doc[] = 
446 "getProperty(name)\n"
447 "\tReturn the property to which the random value is assigned. If the \n"
448 "\tgenerator and property types do not match, the assignment is ignored.\n";
449 PyObject* SCA_RandomActuator::PyGetProperty(PyObject* self, PyObject* args, PyObject* kwds) {
450         return PyString_FromString(m_propname);
451 }
452
453 /* 11. setBoolConst */
454 char SCA_RandomActuator::SetBoolConst_doc[] = 
455 "setBoolConst(value)\n"
456 "\t- value: 0 or 1\n"
457 "\tSet this generator to produce a constant boolean value.\n";
458 PyObject* SCA_RandomActuator::PySetBoolConst(PyObject* self, 
459                                                                                         PyObject* args, 
460                                                                                         PyObject* kwds) {
461         int paraArg;
462         if(!PyArg_ParseTuple(args, "i", &paraArg)) {
463                 return NULL;
464         }
465         
466         m_distribution = KX_RANDOMACT_BOOL_CONST;
467         if (paraArg) {
468                 m_parameter1 = 1;
469         }
470         
471         Py_Return;
472 }
473 /* 12. setBoolUniform, */
474 char SCA_RandomActuator::SetBoolUniform_doc[] = 
475 "setBoolUniform()\n"
476 "\tSet this generator to produce true and false, each with 50%% chance of occuring\n";
477 PyObject* SCA_RandomActuator::PySetBoolUniform(PyObject* self, 
478                                                                                           PyObject* args, 
479                                                                                           PyObject* kwds) {
480         /* no args */
481         m_distribution = KX_RANDOMACT_BOOL_UNIFORM;
482         enforceConstraints();
483         Py_Return;
484 }
485 /* 13. setBoolBernouilli,  */
486 char SCA_RandomActuator::SetBoolBernouilli_doc[] = 
487 "setBoolBernouilli(value)\n"
488 "\t- value: a float between 0 and 1\n"
489 "\tReturn false value * 100%% of the time.\n";
490 PyObject* SCA_RandomActuator::PySetBoolBernouilli(PyObject* self, 
491                                                                                                  PyObject* args, 
492                                                                                                  PyObject* kwds) {
493         float paraArg;
494         if(!PyArg_ParseTuple(args, "f", &paraArg)) {
495                 return NULL;
496         }
497         
498         m_distribution = KX_RANDOMACT_BOOL_BERNOUILLI;
499         m_parameter1 = paraArg; 
500         enforceConstraints();
501         Py_Return;
502 }
503 /* 14. setIntConst,*/
504 char SCA_RandomActuator::SetIntConst_doc[] = 
505 "setIntConst(value)\n"
506 "\t- value: integer\n"
507 "\tAlways return value\n";
508 PyObject* SCA_RandomActuator::PySetIntConst(PyObject* self, 
509                                                                                    PyObject* args, 
510                                                                                    PyObject* kwds) {
511         int paraArg;
512         if(!PyArg_ParseTuple(args, "i", &paraArg)) {
513                 return NULL;
514         }
515         
516         m_distribution = KX_RANDOMACT_INT_CONST;
517         m_parameter1 = paraArg;
518         enforceConstraints();
519         Py_Return;
520 }
521 /* 15. setIntUniform,*/
522 char SCA_RandomActuator::SetIntUniform_doc[] = 
523 "setIntUniform(lower_bound, upper_bound)\n"
524 "\t- lower_bound: integer\n"
525 "\t- upper_bound: integer\n"
526 "\tReturn a random integer between lower_bound and\n"
527 "\tupper_bound. The boundaries are included.\n";
528 PyObject* SCA_RandomActuator::PySetIntUniform(PyObject* self, 
529                                                                                          PyObject* args, 
530                                                                                          PyObject* kwds) {
531         int paraArg1, paraArg2;
532         if(!PyArg_ParseTuple(args, "ii", &paraArg1, &paraArg2)) {
533                 return NULL;
534         }
535         
536         m_distribution = KX_RANDOMACT_INT_UNIFORM;
537         m_parameter1 = paraArg1;
538         m_parameter2 = paraArg2;
539         enforceConstraints();
540         Py_Return;
541 }
542 /* 16. setIntPoisson,           */
543 char SCA_RandomActuator::SetIntPoisson_doc[] = 
544 "setIntPoisson(value)\n"
545 "\t- value: float\n"
546 "\tReturn a Poisson-distributed number. This performs a series\n"
547 "\tof Bernouilli tests with parameter value. It returns the\n"
548 "\tnumber of tries needed to achieve succes.\n";
549 PyObject* SCA_RandomActuator::PySetIntPoisson(PyObject* self, 
550                                                                                          PyObject* args, 
551                                                                                          PyObject* kwds) {
552         float paraArg;
553         if(!PyArg_ParseTuple(args, "f", &paraArg)) {
554                 return NULL;
555         }
556         
557         m_distribution = KX_RANDOMACT_INT_POISSON;
558         m_parameter1 = paraArg; 
559         enforceConstraints();
560         Py_Return;
561 }
562 /* 17. setFloatConst,*/
563 char SCA_RandomActuator::SetFloatConst_doc[] = 
564 "setFloatConst(value)\n"
565 "\t- value: float\n"
566 "\tAlways return value\n";
567 PyObject* SCA_RandomActuator::PySetFloatConst(PyObject* self, 
568                                                                                          PyObject* args, 
569                                                                                          PyObject* kwds) {
570         float paraArg;
571         if(!PyArg_ParseTuple(args, "f", &paraArg)) {
572                 return NULL;
573         }
574         
575         m_distribution = KX_RANDOMACT_FLOAT_CONST;
576         m_parameter1 = paraArg; 
577         enforceConstraints();
578         Py_Return;
579 }
580 /* 18. setFloatUniform, */
581 char SCA_RandomActuator::SetFloatUniform_doc[] = 
582 "setFloatUniform(lower_bound, upper_bound)\n"
583 "\t- lower_bound: float\n"
584 "\t- upper_bound: float\n"
585 "\tReturn a random integer between lower_bound and\n"
586 "\tupper_bound.\n";
587 PyObject* SCA_RandomActuator::PySetFloatUniform(PyObject* self, 
588                                                                                            PyObject* args, 
589                                                                                            PyObject* kwds) {
590         float paraArg1, paraArg2;
591         if(!PyArg_ParseTuple(args, "ff", &paraArg1, &paraArg2)) {
592                 return NULL;
593         }
594         
595         m_distribution = KX_RANDOMACT_FLOAT_UNIFORM;
596         m_parameter1 = paraArg1;
597         m_parameter2 = paraArg2;
598         enforceConstraints();
599         Py_Return;
600 }
601 /* 19. setFloatNormal, */
602 char SCA_RandomActuator::SetFloatNormal_doc[] = 
603 "setFloatNormal(mean, standard_deviation)\n"
604 "\t- mean: float\n"
605 "\t- standard_deviation: float\n"
606 "\tReturn normal-distributed numbers. The average is mean, and the\n"
607 "\tdeviation from the mean is characterized by standard_deviation.\n";
608 PyObject* SCA_RandomActuator::PySetFloatNormal(PyObject* self, 
609                                                                                           PyObject* args, 
610                                                                                           PyObject* kwds) {
611         float paraArg1, paraArg2;
612         if(!PyArg_ParseTuple(args, "ff", &paraArg1, &paraArg2)) {
613                 return NULL;
614         }
615         
616         m_distribution = KX_RANDOMACT_FLOAT_NORMAL;
617         m_parameter1 = paraArg1;
618         m_parameter2 = paraArg2;
619         enforceConstraints();
620         Py_Return;
621 }
622 /* 20. setFloatNegativeExponential, */
623 char SCA_RandomActuator::SetFloatNegativeExponential_doc[] = 
624 "setFloatNegativeExponential(half_life)\n"
625 "\t- half_life: float\n"
626 "\tReturn negative-exponentially distributed numbers. The half-life 'time'\n"
627 "\tis characterized by half_life.\n";
628 PyObject* SCA_RandomActuator::PySetFloatNegativeExponential(PyObject* self, 
629                                                                                                                    PyObject* args, 
630                                                                                                                    PyObject* kwds) {
631         float paraArg;
632         if(!PyArg_ParseTuple(args, "f", &paraArg)) {
633                 return NULL;
634         }
635         
636         m_distribution = KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL;
637         m_parameter1 = paraArg; 
638         enforceConstraints();
639         Py_Return;
640 }
641         
642 /* eof */