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