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