unknown property fixed in sensor/actuators
[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 is never deleted, probably a memory leak!
65         m_base = new SCA_RandomNumberGenerator(seed);
66         m_counter = 0;
67         enforceConstraints();
68
69
70
71
72 SCA_RandomActuator::~SCA_RandomActuator()
73 {
74         /* intentionally empty */ 
75
76
77
78
79 CValue* SCA_RandomActuator::GetReplica()
80 {
81         SCA_RandomActuator* replica = new SCA_RandomActuator(*this);
82         // replication just copy the m_base pointer => common random generator
83         replica->ProcessReplica();
84         CValue::AddDataToReplica(replica);
85
86         return replica;
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         PyObject_HEAD_INIT(&PyType_Type)
319         0,
320         "SCA_RandomActuator",
321         sizeof(SCA_RandomActuator),
322         0,
323         PyDestructor,
324         0,
325         __getattr,
326         __setattr,
327         0, //&MyPyCompare,
328         __repr,
329         0, //&cvalue_as_number,
330         0,
331         0,
332         0,
333         0
334 };
335
336 PyParentObject SCA_RandomActuator::Parents[] = {
337         &SCA_RandomActuator::Type,
338         &SCA_IActuator::Type,
339         &SCA_ILogicBrick::Type,
340         &CValue::Type,
341         NULL
342 };
343
344 PyMethodDef SCA_RandomActuator::Methods[] = {
345         {"setSeed",         (PyCFunction) SCA_RandomActuator::sPySetSeed, METH_VARARGS, SetSeed_doc},
346         {"getSeed",         (PyCFunction) SCA_RandomActuator::sPyGetSeed, METH_VARARGS, GetSeed_doc},
347         {"getPara1",        (PyCFunction) SCA_RandomActuator::sPyGetPara1, METH_VARARGS, GetPara1_doc},
348         {"getPara2",        (PyCFunction) SCA_RandomActuator::sPyGetPara2, METH_VARARGS, GetPara2_doc},
349         {"getDistribution", (PyCFunction) SCA_RandomActuator::sPyGetDistribution, METH_VARARGS, GetDistribution_doc},
350         {"setProperty",     (PyCFunction) SCA_RandomActuator::sPySetProperty, METH_VARARGS, SetProperty_doc},
351         {"getProperty",     (PyCFunction) SCA_RandomActuator::sPyGetProperty, METH_VARARGS, GetProperty_doc},
352         {"setBoolConst",    (PyCFunction) SCA_RandomActuator::sPySetBoolConst, METH_VARARGS, SetBoolConst_doc},
353         {"setBoolUniform",  (PyCFunction) SCA_RandomActuator::sPySetBoolUniform, METH_VARARGS, SetBoolUniform_doc},
354         {"setBoolBernouilli",(PyCFunction) SCA_RandomActuator::sPySetBoolBernouilli, METH_VARARGS, SetBoolBernouilli_doc},
355         {"setIntConst",     (PyCFunction) SCA_RandomActuator::sPySetIntConst, METH_VARARGS, SetIntConst_doc},
356         {"setIntUniform",   (PyCFunction) SCA_RandomActuator::sPySetIntUniform, METH_VARARGS, SetIntUniform_doc},
357         {"setIntPoisson",   (PyCFunction) SCA_RandomActuator::sPySetIntPoisson, METH_VARARGS, SetIntPoisson_doc},
358         {"setFloatConst",   (PyCFunction) SCA_RandomActuator::sPySetFloatConst, METH_VARARGS, SetFloatConst_doc},
359         {"setFloatUniform", (PyCFunction) SCA_RandomActuator::sPySetFloatUniform, METH_VARARGS, SetFloatUniform_doc},
360         {"setFloatNormal",  (PyCFunction) SCA_RandomActuator::sPySetFloatNormal, METH_VARARGS, SetFloatNormal_doc},
361         {"setFloatNegativeExponential", (PyCFunction) SCA_RandomActuator::sPySetFloatNegativeExponential, METH_VARARGS, SetFloatNegativeExponential_doc},
362         {NULL,NULL} //Sentinel
363 };
364
365 PyObject* SCA_RandomActuator::_getattr(const STR_String& attr) {
366         _getattr_up(SCA_IActuator);
367 }
368
369 /* 1. setSeed                                                            */
370 char SCA_RandomActuator::SetSeed_doc[] = 
371 "setSeed(seed)\n"
372 "\t- seed: integer\n"
373 "\tSet the initial seed of the generator. Equal seeds produce\n"
374 "\tequal series. If the seed is 0, the generator will produce\n"
375 "\tthe same value on every call.\n";
376 PyObject* SCA_RandomActuator::PySetSeed(PyObject* self, PyObject* args, PyObject* kwds) {
377         long seedArg;
378         if(!PyArg_ParseTuple(args, "i", &seedArg)) {
379                 return NULL;
380         }
381         
382         m_base->SetSeed(seedArg);
383         
384         Py_Return;
385 }
386 /* 2. getSeed                                                            */
387 char SCA_RandomActuator::GetSeed_doc[] = 
388 "getSeed()\n"
389 "\tReturns the initial seed of the generator. Equal seeds produce\n"
390 "\tequal series.\n";
391 PyObject* SCA_RandomActuator::PyGetSeed(PyObject* self, PyObject* args, PyObject* kwds) {
392         return PyInt_FromLong(m_base->GetSeed());
393 }
394
395 /* 4. getPara1                                                           */
396 char SCA_RandomActuator::GetPara1_doc[] = 
397 "getPara1()\n"
398 "\tReturns the first parameter of the active distribution. Refer\n"
399 "\tto the documentation of the generator types for the meaning\n"
400 "\tof this value.";
401 PyObject* SCA_RandomActuator::PyGetPara1(PyObject* self, PyObject* args, PyObject* kwds) {
402         return PyFloat_FromDouble(m_parameter1);
403 }
404
405 /* 6. getPara2                                                           */
406 char SCA_RandomActuator::GetPara2_doc[] = 
407 "getPara2()\n"
408 "\tReturns the first parameter of the active distribution. Refer\n"
409 "\tto the documentation of the generator types for the meaning\n"
410 "\tof this value.";
411 PyObject* SCA_RandomActuator::PyGetPara2(PyObject* self, PyObject* args, PyObject* kwds) {
412         return PyFloat_FromDouble(m_parameter2);
413 }
414
415 /* 8. getDistribution                                                    */
416 char SCA_RandomActuator::GetDistribution_doc[] = 
417 "getDistribution()\n"
418 "\tReturns the type of the active distribution.\n";
419 PyObject* SCA_RandomActuator::PyGetDistribution(PyObject* self, PyObject* args, PyObject* kwds) {
420         return PyInt_FromLong(m_distribution);
421 }
422
423 /* 9. setProperty                                                        */
424 char SCA_RandomActuator::SetProperty_doc[] = 
425 "setProperty(name)\n"
426 "\t- name: string\n"
427 "\tSet the property to which the random value is assigned. If the \n"
428 "\tgenerator and property types do not match, the assignment is ignored.\n";
429 PyObject* SCA_RandomActuator::PySetProperty(PyObject* self, PyObject* args, PyObject* kwds) {
430         char *nameArg;
431         if (!PyArg_ParseTuple(args, "s", &nameArg)) {
432                 return NULL;
433         }
434
435         CValue* prop = GetParent()->FindIdentifier(nameArg);
436
437         if (!prop->IsError()) {
438                 m_propname = nameArg;
439         } else {
440                 ; /* not found ... */
441         }
442         prop->Release();
443         
444         Py_Return;
445 }
446 /* 10. getProperty                                                       */
447 char SCA_RandomActuator::GetProperty_doc[] = 
448 "getProperty(name)\n"
449 "\tReturn the property to which the random value is assigned. If the \n"
450 "\tgenerator and property types do not match, the assignment is ignored.\n";
451 PyObject* SCA_RandomActuator::PyGetProperty(PyObject* self, PyObject* args, PyObject* kwds) {
452         return PyString_FromString(m_propname);
453 }
454
455 /* 11. setBoolConst */
456 char SCA_RandomActuator::SetBoolConst_doc[] = 
457 "setBoolConst(value)\n"
458 "\t- value: 0 or 1\n"
459 "\tSet this generator to produce a constant boolean value.\n";
460 PyObject* SCA_RandomActuator::PySetBoolConst(PyObject* self, 
461                                                                                         PyObject* args, 
462                                                                                         PyObject* kwds) {
463         int paraArg;
464         if(!PyArg_ParseTuple(args, "i", &paraArg)) {
465                 return NULL;
466         }
467         
468         m_distribution = KX_RANDOMACT_BOOL_CONST;
469         if (paraArg) {
470                 m_parameter1 = 1;
471         }
472         
473         Py_Return;
474 }
475 /* 12. setBoolUniform, */
476 char SCA_RandomActuator::SetBoolUniform_doc[] = 
477 "setBoolUniform()\n"
478 "\tSet this generator to produce true and false, each with 50%% chance of occuring\n";
479 PyObject* SCA_RandomActuator::PySetBoolUniform(PyObject* self, 
480                                                                                           PyObject* args, 
481                                                                                           PyObject* kwds) {
482         /* no args */
483         m_distribution = KX_RANDOMACT_BOOL_UNIFORM;
484         enforceConstraints();
485         Py_Return;
486 }
487 /* 13. setBoolBernouilli,  */
488 char SCA_RandomActuator::SetBoolBernouilli_doc[] = 
489 "setBoolBernouilli(value)\n"
490 "\t- value: a float between 0 and 1\n"
491 "\tReturn false value * 100%% of the time.\n";
492 PyObject* SCA_RandomActuator::PySetBoolBernouilli(PyObject* self, 
493                                                                                                  PyObject* args, 
494                                                                                                  PyObject* kwds) {
495         float paraArg;
496         if(!PyArg_ParseTuple(args, "f", &paraArg)) {
497                 return NULL;
498         }
499         
500         m_distribution = KX_RANDOMACT_BOOL_BERNOUILLI;
501         m_parameter1 = paraArg; 
502         enforceConstraints();
503         Py_Return;
504 }
505 /* 14. setIntConst,*/
506 char SCA_RandomActuator::SetIntConst_doc[] = 
507 "setIntConst(value)\n"
508 "\t- value: integer\n"
509 "\tAlways return value\n";
510 PyObject* SCA_RandomActuator::PySetIntConst(PyObject* self, 
511                                                                                    PyObject* args, 
512                                                                                    PyObject* kwds) {
513         int paraArg;
514         if(!PyArg_ParseTuple(args, "i", &paraArg)) {
515                 return NULL;
516         }
517         
518         m_distribution = KX_RANDOMACT_INT_CONST;
519         m_parameter1 = paraArg;
520         enforceConstraints();
521         Py_Return;
522 }
523 /* 15. setIntUniform,*/
524 char SCA_RandomActuator::SetIntUniform_doc[] = 
525 "setIntUniform(lower_bound, upper_bound)\n"
526 "\t- lower_bound: integer\n"
527 "\t- upper_bound: integer\n"
528 "\tReturn a random integer between lower_bound and\n"
529 "\tupper_bound. The boundaries are included.\n";
530 PyObject* SCA_RandomActuator::PySetIntUniform(PyObject* self, 
531                                                                                          PyObject* args, 
532                                                                                          PyObject* kwds) {
533         int paraArg1, paraArg2;
534         if(!PyArg_ParseTuple(args, "ii", &paraArg1, &paraArg2)) {
535                 return NULL;
536         }
537         
538         m_distribution = KX_RANDOMACT_INT_UNIFORM;
539         m_parameter1 = paraArg1;
540         m_parameter2 = paraArg2;
541         enforceConstraints();
542         Py_Return;
543 }
544 /* 16. setIntPoisson,           */
545 char SCA_RandomActuator::SetIntPoisson_doc[] = 
546 "setIntPoisson(value)\n"
547 "\t- value: float\n"
548 "\tReturn a Poisson-distributed number. This performs a series\n"
549 "\tof Bernouilli tests with parameter value. It returns the\n"
550 "\tnumber of tries needed to achieve succes.\n";
551 PyObject* SCA_RandomActuator::PySetIntPoisson(PyObject* self, 
552                                                                                          PyObject* args, 
553                                                                                          PyObject* kwds) {
554         float paraArg;
555         if(!PyArg_ParseTuple(args, "f", &paraArg)) {
556                 return NULL;
557         }
558         
559         m_distribution = KX_RANDOMACT_INT_POISSON;
560         m_parameter1 = paraArg; 
561         enforceConstraints();
562         Py_Return;
563 }
564 /* 17. setFloatConst,*/
565 char SCA_RandomActuator::SetFloatConst_doc[] = 
566 "setFloatConst(value)\n"
567 "\t- value: float\n"
568 "\tAlways return value\n";
569 PyObject* SCA_RandomActuator::PySetFloatConst(PyObject* self, 
570                                                                                          PyObject* args, 
571                                                                                          PyObject* kwds) {
572         float paraArg;
573         if(!PyArg_ParseTuple(args, "f", &paraArg)) {
574                 return NULL;
575         }
576         
577         m_distribution = KX_RANDOMACT_FLOAT_CONST;
578         m_parameter1 = paraArg; 
579         enforceConstraints();
580         Py_Return;
581 }
582 /* 18. setFloatUniform, */
583 char SCA_RandomActuator::SetFloatUniform_doc[] = 
584 "setFloatUniform(lower_bound, upper_bound)\n"
585 "\t- lower_bound: float\n"
586 "\t- upper_bound: float\n"
587 "\tReturn a random integer between lower_bound and\n"
588 "\tupper_bound.\n";
589 PyObject* SCA_RandomActuator::PySetFloatUniform(PyObject* self, 
590                                                                                            PyObject* args, 
591                                                                                            PyObject* kwds) {
592         float paraArg1, paraArg2;
593         if(!PyArg_ParseTuple(args, "ff", &paraArg1, &paraArg2)) {
594                 return NULL;
595         }
596         
597         m_distribution = KX_RANDOMACT_FLOAT_UNIFORM;
598         m_parameter1 = paraArg1;
599         m_parameter2 = paraArg2;
600         enforceConstraints();
601         Py_Return;
602 }
603 /* 19. setFloatNormal, */
604 char SCA_RandomActuator::SetFloatNormal_doc[] = 
605 "setFloatNormal(mean, standard_deviation)\n"
606 "\t- mean: float\n"
607 "\t- standard_deviation: float\n"
608 "\tReturn normal-distributed numbers. The average is mean, and the\n"
609 "\tdeviation from the mean is characterized by standard_deviation.\n";
610 PyObject* SCA_RandomActuator::PySetFloatNormal(PyObject* self, 
611                                                                                           PyObject* args, 
612                                                                                           PyObject* kwds) {
613         float paraArg1, paraArg2;
614         if(!PyArg_ParseTuple(args, "ff", &paraArg1, &paraArg2)) {
615                 return NULL;
616         }
617         
618         m_distribution = KX_RANDOMACT_FLOAT_NORMAL;
619         m_parameter1 = paraArg1;
620         m_parameter2 = paraArg2;
621         enforceConstraints();
622         Py_Return;
623 }
624 /* 20. setFloatNegativeExponential, */
625 char SCA_RandomActuator::SetFloatNegativeExponential_doc[] = 
626 "setFloatNegativeExponential(half_life)\n"
627 "\t- half_life: float\n"
628 "\tReturn negative-exponentially distributed numbers. The half-life 'time'\n"
629 "\tis characterized by half_life.\n";
630 PyObject* SCA_RandomActuator::PySetFloatNegativeExponential(PyObject* self, 
631                                                                                                                    PyObject* args, 
632                                                                                                                    PyObject* kwds) {
633         float paraArg;
634         if(!PyArg_ParseTuple(args, "f", &paraArg)) {
635                 return NULL;
636         }
637         
638         m_distribution = KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL;
639         m_parameter1 = paraArg; 
640         enforceConstraints();
641         Py_Return;
642 }
643         
644 /* eof */