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