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