BGE Py API using python3 c/api calls. include bpy_compat.h to support py2.x
[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,
335         NULL, //py_base_getattro,
336         NULL, //py_base_setattro,
337         0,
338         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
339         0,0,0,0,0,0,0,
340         Methods,
341         0,
342         0,
343         &SCA_IActuator::Type
344 };
345
346 PyMethodDef SCA_RandomActuator::Methods[] = {
347         //Deprecated functions ------>
348         {"setSeed",         (PyCFunction) SCA_RandomActuator::sPySetSeed, METH_VARARGS, (PY_METHODCHAR)SetSeed_doc},
349         {"getSeed",         (PyCFunction) SCA_RandomActuator::sPyGetSeed, METH_NOARGS, (PY_METHODCHAR)GetSeed_doc},
350         {"getPara1",        (PyCFunction) SCA_RandomActuator::sPyGetPara1, METH_NOARGS, (PY_METHODCHAR)GetPara1_doc},
351         {"getPara2",        (PyCFunction) SCA_RandomActuator::sPyGetPara2, METH_NOARGS, (PY_METHODCHAR)GetPara2_doc},
352         {"getDistribution", (PyCFunction) SCA_RandomActuator::sPyGetDistribution, METH_NOARGS, (PY_METHODCHAR)GetDistribution_doc},
353         {"setProperty",     (PyCFunction) SCA_RandomActuator::sPySetProperty, METH_VARARGS, (PY_METHODCHAR)SetProperty_doc},
354         {"getProperty",     (PyCFunction) SCA_RandomActuator::sPyGetProperty, METH_NOARGS, (PY_METHODCHAR)GetProperty_doc},
355         //<----- Deprecated
356         KX_PYMETHODTABLE(SCA_RandomActuator, setBoolConst),
357         KX_PYMETHODTABLE_NOARGS(SCA_RandomActuator, setBoolUniform),
358         KX_PYMETHODTABLE(SCA_RandomActuator, setBoolBernouilli),
359
360         KX_PYMETHODTABLE(SCA_RandomActuator, setIntConst),
361         KX_PYMETHODTABLE(SCA_RandomActuator, setIntUniform),
362         KX_PYMETHODTABLE(SCA_RandomActuator, setIntPoisson),
363
364         KX_PYMETHODTABLE(SCA_RandomActuator, setFloatConst),
365         KX_PYMETHODTABLE(SCA_RandomActuator, setFloatUniform),
366         KX_PYMETHODTABLE(SCA_RandomActuator, setFloatNormal),
367         KX_PYMETHODTABLE(SCA_RandomActuator, setFloatNegativeExponential),
368         {NULL,NULL} //Sentinel
369 };
370
371 PyAttributeDef SCA_RandomActuator::Attributes[] = {
372         KX_PYATTRIBUTE_FLOAT_RO("para1",SCA_RandomActuator,m_parameter1),
373         KX_PYATTRIBUTE_FLOAT_RO("para2",SCA_RandomActuator,m_parameter2),
374         KX_PYATTRIBUTE_ENUM_RO("distribution",SCA_RandomActuator,m_distribution),
375         KX_PYATTRIBUTE_STRING_RW_CHECK("propName",0,100,false,SCA_RandomActuator,m_propname,CheckProperty),
376         KX_PYATTRIBUTE_RW_FUNCTION("seed",SCA_RandomActuator,pyattr_get_seed,pyattr_set_seed),
377         { NULL }        //Sentinel
378 };      
379
380 PyObject* SCA_RandomActuator::pyattr_get_seed(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
381 {
382         SCA_RandomActuator* act = static_cast<SCA_RandomActuator*>(self);
383         return PyLong_FromSsize_t(act->m_base->GetSeed());
384 }
385
386 int SCA_RandomActuator::pyattr_set_seed(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
387 {
388         SCA_RandomActuator* act = static_cast<SCA_RandomActuator*>(self);
389         if (PyLong_Check(value))        {
390                 int ival = PyLong_AsSsize_t(value);
391                 act->m_base->SetSeed(ival);
392                 return PY_SET_ATTR_SUCCESS;
393         } else {
394                 PyErr_SetString(PyExc_TypeError, "actuator.seed = int: Random Actuator, expected an integer");
395                 return PY_SET_ATTR_FAIL;
396         }
397 }
398
399 /* 1. setSeed                                                            */
400 const char SCA_RandomActuator::SetSeed_doc[] = 
401 "setSeed(seed)\n"
402 "\t- seed: integer\n"
403 "\tSet the initial seed of the generator. Equal seeds produce\n"
404 "\tequal series. If the seed is 0, the generator will produce\n"
405 "\tthe same value on every call.\n";
406 PyObject* SCA_RandomActuator::PySetSeed(PyObject* args) {
407         ShowDeprecationWarning("setSeed()", "the seed property");
408         long seedArg;
409         if(!PyArg_ParseTuple(args, "i:setSeed", &seedArg)) {
410                 return NULL;
411         }
412         
413         m_base->SetSeed(seedArg);
414         
415         Py_RETURN_NONE;
416 }
417 /* 2. getSeed                                                            */
418 const char SCA_RandomActuator::GetSeed_doc[] = 
419 "getSeed()\n"
420 "\tReturns the initial seed of the generator. Equal seeds produce\n"
421 "\tequal series.\n";
422 PyObject* SCA_RandomActuator::PyGetSeed()
423 {
424         ShowDeprecationWarning("getSeed()", "the seed property");
425         return PyLong_FromSsize_t(m_base->GetSeed());
426 }
427
428 /* 4. getPara1                                                           */
429 const char SCA_RandomActuator::GetPara1_doc[] = 
430 "getPara1()\n"
431 "\tReturns the first parameter of the active distribution. Refer\n"
432 "\tto the documentation of the generator types for the meaning\n"
433 "\tof this value.";
434 PyObject* SCA_RandomActuator::PyGetPara1()
435 {
436         ShowDeprecationWarning("getPara1()", "the para1 property");
437         return PyFloat_FromDouble(m_parameter1);
438 }
439
440 /* 6. getPara2                                                           */
441 const char SCA_RandomActuator::GetPara2_doc[] = 
442 "getPara2()\n"
443 "\tReturns the first parameter of the active distribution. Refer\n"
444 "\tto the documentation of the generator types for the meaning\n"
445 "\tof this value.";
446 PyObject* SCA_RandomActuator::PyGetPara2()
447 {
448         ShowDeprecationWarning("getPara2()", "the para2 property");
449         return PyFloat_FromDouble(m_parameter2);
450 }
451
452 /* 8. getDistribution                                                    */
453 const char SCA_RandomActuator::GetDistribution_doc[] = 
454 "getDistribution()\n"
455 "\tReturns the type of the active distribution.\n";
456 PyObject* SCA_RandomActuator::PyGetDistribution()
457 {
458         ShowDeprecationWarning("getDistribution()", "the distribution property");
459         return PyLong_FromSsize_t(m_distribution);
460 }
461
462 /* 9. setProperty                                                        */
463 const char SCA_RandomActuator::SetProperty_doc[] = 
464 "setProperty(name)\n"
465 "\t- name: string\n"
466 "\tSet the property to which the random value is assigned. If the \n"
467 "\tgenerator and property types do not match, the assignment is ignored.\n";
468 PyObject* SCA_RandomActuator::PySetProperty(PyObject* args) {
469         ShowDeprecationWarning("setProperty()", "the 'propName' property");
470         char *nameArg;
471         if (!PyArg_ParseTuple(args, "s:setProperty", &nameArg)) {
472                 return NULL;
473         }
474
475         CValue* prop = GetParent()->FindIdentifier(nameArg);
476
477         if (!prop->IsError()) {
478                 m_propname = nameArg;
479         } else {
480                 ; /* not found ... */
481         }
482         prop->Release();
483         
484         Py_RETURN_NONE;
485 }
486 /* 10. getProperty                                                       */
487 const char SCA_RandomActuator::GetProperty_doc[] = 
488 "getProperty(name)\n"
489 "\tReturn the property to which the random value is assigned. If the \n"
490 "\tgenerator and property types do not match, the assignment is ignored.\n";
491 PyObject* SCA_RandomActuator::PyGetProperty()
492 {
493         ShowDeprecationWarning("getProperty()", "the 'propName' property");
494         return PyUnicode_FromString(m_propname);
495 }
496
497 /* 11. setBoolConst */
498 KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setBoolConst,
499 "setBoolConst(value)\n"
500 "\t- value: 0 or 1\n"
501 "\tSet this generator to produce a constant boolean value.\n") 
502 {
503         int paraArg;
504         if(!PyArg_ParseTuple(args, "i:setBoolConst", &paraArg)) {
505                 return NULL;
506         }
507         
508         m_distribution = KX_RANDOMACT_BOOL_CONST;
509         m_parameter1 = (paraArg) ? 1.0 : 0.0;
510         
511         Py_RETURN_NONE;
512 }
513 /* 12. setBoolUniform, */
514 KX_PYMETHODDEF_DOC_NOARGS(SCA_RandomActuator, setBoolUniform,
515 "setBoolUniform()\n"
516 "\tSet this generator to produce true and false, each with 50%% chance of occuring\n") 
517 {
518         /* no args */
519         m_distribution = KX_RANDOMACT_BOOL_UNIFORM;
520         enforceConstraints();
521         Py_RETURN_NONE;
522 }
523 /* 13. setBoolBernouilli,  */
524 KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setBoolBernouilli,
525 "setBoolBernouilli(value)\n"
526 "\t- value: a float between 0 and 1\n"
527 "\tReturn false value * 100%% of the time.\n")
528 {
529         float paraArg;
530         if(!PyArg_ParseTuple(args, "f:setBoolBernouilli", &paraArg)) {
531                 return NULL;
532         }
533         
534         m_distribution = KX_RANDOMACT_BOOL_BERNOUILLI;
535         m_parameter1 = paraArg; 
536         enforceConstraints();
537         Py_RETURN_NONE;
538 }
539 /* 14. setIntConst,*/
540 KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setIntConst,
541 "setIntConst(value)\n"
542 "\t- value: integer\n"
543 "\tAlways return value\n") 
544 {
545         int paraArg;
546         if(!PyArg_ParseTuple(args, "i:setIntConst", &paraArg)) {
547                 return NULL;
548         }
549         
550         m_distribution = KX_RANDOMACT_INT_CONST;
551         m_parameter1 = paraArg;
552         enforceConstraints();
553         Py_RETURN_NONE;
554 }
555 /* 15. setIntUniform,*/
556 KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setIntUniform,
557 "setIntUniform(lower_bound, upper_bound)\n"
558 "\t- lower_bound: integer\n"
559 "\t- upper_bound: integer\n"
560 "\tReturn a random integer between lower_bound and\n"
561 "\tupper_bound. The boundaries are included.\n")
562 {
563         int paraArg1, paraArg2;
564         if(!PyArg_ParseTuple(args, "ii:setIntUniform", &paraArg1, &paraArg2)) {
565                 return NULL;
566         }
567         
568         m_distribution = KX_RANDOMACT_INT_UNIFORM;
569         m_parameter1 = paraArg1;
570         m_parameter2 = paraArg2;
571         enforceConstraints();
572         Py_RETURN_NONE;
573 }
574 /* 16. setIntPoisson,           */
575 KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setIntPoisson,
576 "setIntPoisson(value)\n"
577 "\t- value: float\n"
578 "\tReturn a Poisson-distributed number. This performs a series\n"
579 "\tof Bernouilli tests with parameter value. It returns the\n"
580 "\tnumber of tries needed to achieve succes.\n")
581 {
582         float paraArg;
583         if(!PyArg_ParseTuple(args, "f:setIntPoisson", &paraArg)) {
584                 return NULL;
585         }
586         
587         m_distribution = KX_RANDOMACT_INT_POISSON;
588         m_parameter1 = paraArg; 
589         enforceConstraints();
590         Py_RETURN_NONE;
591 }
592 /* 17. setFloatConst */
593 KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setFloatConst,
594 "setFloatConst(value)\n"
595 "\t- value: float\n"
596 "\tAlways return value\n")
597 {
598         float paraArg;
599         if(!PyArg_ParseTuple(args, "f:setFloatConst", &paraArg)) {
600                 return NULL;
601         }
602         
603         m_distribution = KX_RANDOMACT_FLOAT_CONST;
604         m_parameter1 = paraArg; 
605         enforceConstraints();
606         Py_RETURN_NONE;
607 }
608 /* 18. setFloatUniform, */
609 KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setFloatUniform,
610 "setFloatUniform(lower_bound, upper_bound)\n"
611 "\t- lower_bound: float\n"
612 "\t- upper_bound: float\n"
613 "\tReturn a random integer between lower_bound and\n"
614 "\tupper_bound.\n")
615 {
616         float paraArg1, paraArg2;
617         if(!PyArg_ParseTuple(args, "ff:setFloatUniform", &paraArg1, &paraArg2)) {
618                 return NULL;
619         }
620         
621         m_distribution = KX_RANDOMACT_FLOAT_UNIFORM;
622         m_parameter1 = paraArg1;
623         m_parameter2 = paraArg2;
624         enforceConstraints();
625         Py_RETURN_NONE;
626 }
627 /* 19. setFloatNormal, */
628 KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setFloatNormal,
629 "setFloatNormal(mean, standard_deviation)\n"
630 "\t- mean: float\n"
631 "\t- standard_deviation: float\n"
632 "\tReturn normal-distributed numbers. The average is mean, and the\n"
633 "\tdeviation from the mean is characterized by standard_deviation.\n")
634 {
635         float paraArg1, paraArg2;
636         if(!PyArg_ParseTuple(args, "ff:setFloatNormal", &paraArg1, &paraArg2)) {
637                 return NULL;
638         }
639         
640         m_distribution = KX_RANDOMACT_FLOAT_NORMAL;
641         m_parameter1 = paraArg1;
642         m_parameter2 = paraArg2;
643         enforceConstraints();
644         Py_RETURN_NONE;
645 }
646 /* 20. setFloatNegativeExponential, */
647 KX_PYMETHODDEF_DOC_VARARGS(SCA_RandomActuator, setFloatNegativeExponential, 
648 "setFloatNegativeExponential(half_life)\n"
649 "\t- half_life: float\n"
650 "\tReturn negative-exponentially distributed numbers. The half-life 'time'\n"
651 "\tis characterized by half_life.\n")
652 {
653         float paraArg;
654         if(!PyArg_ParseTuple(args, "f:setFloatNegativeExponential", &paraArg)) {
655                 return NULL;
656         }
657         
658         m_distribution = KX_RANDOMACT_FLOAT_NEGATIVE_EXPONENTIAL;
659         m_parameter1 = paraArg; 
660         enforceConstraints();
661         Py_RETURN_NONE;
662 }
663         
664 /* eof */