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