ifdef's for future py3 support, after this adding py3 can mostly be done with defines...
[blender.git] / source / gameengine / GameLogic / SCA_ISensor.cpp
1 /**
2  * Abstract class for sensor logic bricks
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 "SCA_ISensor.h"
33 #include "SCA_EventManager.h"
34 #include "SCA_LogicManager.h"
35 // needed for IsTriggered()
36 #include "SCA_PythonController.h"
37
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 /* Native functions */
43 void    SCA_ISensor::ReParent(SCA_IObject* parent)
44 {
45         SCA_ILogicBrick::ReParent(parent);
46         // will be done when the sensor is activated
47         //m_eventmgr->RegisterSensor(this);
48         this->SetActive(false);
49 }
50
51
52 SCA_ISensor::SCA_ISensor(SCA_IObject* gameobj,
53                                                  class SCA_EventManager* eventmgr,
54                                                  PyTypeObject* T ) :
55         SCA_ILogicBrick(gameobj,T),
56         m_triggered(false)
57 {
58         m_links = 0;
59         m_suspended = false;
60         m_invert = false;
61         m_level = false;
62         m_reset = false;
63         m_pos_ticks = 0;
64         m_neg_ticks = 0;
65         m_pos_pulsemode = false;
66         m_neg_pulsemode = false;
67         m_pulse_frequency = 0;
68         
69         m_eventmgr = eventmgr;
70 }
71
72
73 SCA_ISensor::~SCA_ISensor()  
74 {
75         // intentionally empty
76 }
77
78 bool SCA_ISensor::IsPositiveTrigger() { 
79         bool result = false;
80         
81         if (m_eventval) {
82                 result = (m_eventval->GetNumber() != 0.0);
83         }
84         if (m_invert) {
85                 result = !result;
86         }
87         
88         return result;
89 }
90
91 void SCA_ISensor::SetPulseMode(bool posmode, 
92                                                            bool negmode,
93                                                            int freq) {
94         m_pos_pulsemode = posmode;
95         m_neg_pulsemode = negmode;
96         m_pulse_frequency = freq;
97 }
98
99 void SCA_ISensor::SetInvert(bool inv) {
100         m_invert = inv;
101 }
102
103 void SCA_ISensor::SetLevel(bool lvl) {
104         m_level = lvl;
105 }
106
107
108 double SCA_ISensor::GetNumber() {
109         return IsPositiveTrigger();
110 }
111
112 void SCA_ISensor::Suspend() {
113         m_suspended = true;
114 }
115
116 bool SCA_ISensor::IsSuspended() {
117         return m_suspended;
118 }
119
120 void SCA_ISensor::Resume() {
121         m_suspended = false;
122 }
123
124 void SCA_ISensor::Init() {
125         printf("Sensor %s has no init function, please report this bug to Blender.org\n", m_name.Ptr());
126 }
127
128 void SCA_ISensor::DecLink() {
129         m_links--;
130         if (m_links < 0) 
131         {
132                 printf("Warning: sensor %s has negative m_links: %d\n", m_name.Ptr(), m_links);
133                 m_links = 0;
134         }
135         if (!m_links)
136         {
137                 // sensor is detached from all controllers, remove it from manager
138                 UnregisterToManager();
139         }
140 }
141
142 void SCA_ISensor::RegisterToManager()
143 {
144         // sensor is just activated, initialize it
145         Init();
146         m_newControllers.erase(m_newControllers.begin(), m_newControllers.end());
147         m_eventmgr->RegisterSensor(this);
148 }
149
150 void SCA_ISensor::UnregisterToManager()
151 {
152         m_eventmgr->RemoveSensor(this);
153 }
154
155 void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr,      CValue* event)
156 {
157         
158         // calculate if a __triggering__ is wanted
159         // don't evaluate a sensor that is not connected to any controller
160         if (m_links && !m_suspended) {
161                 bool result = this->Evaluate(event);
162                 if (result) {
163                         logicmgr->AddActivatedSensor(this);     
164                         // reset these counters so that pulse are synchronized with transition
165                         m_pos_ticks = 0;
166                         m_neg_ticks = 0;
167                 } else
168                 {
169                         /* First, the pulsing behaviour, if pulse mode is
170                          * active. It seems something goes wrong if pulse mode is
171                          * not set :( */
172                         if (m_pos_pulsemode) {
173                                 m_pos_ticks++;
174                                 if (m_pos_ticks > m_pulse_frequency) {
175                                         if ( this->IsPositiveTrigger() )
176                                         {
177                                                 logicmgr->AddActivatedSensor(this);
178                                         }
179                                         m_pos_ticks = 0;
180                                 } 
181                         }
182                         
183                         if (m_neg_pulsemode)
184                         {
185                                 m_neg_ticks++;
186                                 if (m_neg_ticks > m_pulse_frequency) {
187                                         if (!this->IsPositiveTrigger() )
188                                         {
189                                                 logicmgr->AddActivatedSensor(this);
190                                         }
191                                         m_neg_ticks = 0;
192                                 }
193                         }
194                 }
195                 if (!m_newControllers.empty())
196                 {
197                         if (!IsActive() && m_level)
198                         {
199                                 // This level sensor is connected to at least one controller that was just made 
200                                 // active but it did not generate an event yet, do it now to those controllers only 
201                                 for (std::vector<SCA_IController*>::iterator ci=m_newControllers.begin();
202                                          ci != m_newControllers.end(); ci++)
203                                 {
204                                         logicmgr->AddTriggeredController(*ci, this);
205                                 }
206                         }
207                         // clear the list. Instead of using clear, which also release the memory,
208                         // use erase, which keeps the memory available for next time.
209                         m_newControllers.erase(m_newControllers.begin(), m_newControllers.end());
210                 }
211         } 
212 }
213 /* ----------------------------------------------- */
214 /* Python Functions                                                        */
215 /* ----------------------------------------------- */
216
217 //Deprecated Functions ------>
218 const char SCA_ISensor::IsPositive_doc[] = 
219 "isPositive()\n"
220 "\tReturns whether the sensor is in an active state.\n";
221 PyObject* SCA_ISensor::PyIsPositive()
222 {
223         ShowDeprecationWarning("isPositive()", "the read-only positive property");
224         int retval = IsPositiveTrigger();
225         return PyInt_FromLong(retval);
226 }
227
228 const char SCA_ISensor::IsTriggered_doc[] = 
229 "isTriggered()\n"
230 "\tReturns whether the sensor has triggered the current controller.\n";
231 PyObject* SCA_ISensor::PyIsTriggered()
232 {
233         ShowDeprecationWarning("isTriggered()", "the read-only triggered property");
234         // check with the current controller
235         int retval = 0;
236         if (SCA_PythonController::m_sCurrentController)
237                 retval = SCA_PythonController::m_sCurrentController->IsTriggered(this);
238         return PyInt_FromLong(retval);
239 }
240
241 /**
242  * getUsePulseMode: getter for the pulse mode (KX_TRUE = on)
243  */
244 const char SCA_ISensor::GetUsePosPulseMode_doc[] = 
245 "getUsePosPulseMode()\n"
246 "\tReturns whether positive pulse mode is active.\n";
247 PyObject* SCA_ISensor::PyGetUsePosPulseMode()
248 {
249         ShowDeprecationWarning("getUsePosPulseMode()", "the usePosPulseMode property");
250         return BoolToPyArg(m_pos_pulsemode);
251 }
252
253 /**
254  * setUsePulseMode: setter for the pulse mode (KX_TRUE = on)
255  */
256 const char SCA_ISensor::SetUsePosPulseMode_doc[] = 
257 "setUsePosPulseMode(pulse?)\n"
258 "\t - pulse? : Pulse when a positive event occurs?\n"
259 "\t            (KX_TRUE, KX_FALSE)\n"
260 "\tSet whether to do pulsing when positive pulses occur.\n";
261 PyObject* SCA_ISensor::PySetUsePosPulseMode(PyObject* args)
262 {
263         ShowDeprecationWarning("setUsePosPulseMode()", "the usePosPulseMode property");
264         int pyarg = 0;
265         if(!PyArg_ParseTuple(args, "i:setUsePosPulseMode", &pyarg)) { return NULL; }
266         m_pos_pulsemode = PyArgToBool(pyarg);
267         Py_RETURN_NONE;
268 }
269
270 /**
271  * getFrequency: getter for the pulse mode interval
272  */
273 const char SCA_ISensor::GetFrequency_doc[] = 
274 "getFrequency()\n"
275 "\tReturns the frequency of the updates in pulse mode.\n" ;
276 PyObject* SCA_ISensor::PyGetFrequency()
277 {
278         ShowDeprecationWarning("getFrequency()", "the frequency property");
279         return PyInt_FromLong(m_pulse_frequency);
280 }
281
282 /**
283  * setFrequency: setter for the pulse mode (KX_TRUE = on)
284  */
285 const char SCA_ISensor::SetFrequency_doc[] = 
286 "setFrequency(pulse_frequency)\n"
287 "\t- pulse_frequency: The frequency of the updates in pulse mode (integer)"
288 "\tSet the frequency of the updates in pulse mode.\n"
289 "\tIf the frequency is negative, it is set to 0.\n" ;
290 PyObject* SCA_ISensor::PySetFrequency(PyObject* args)
291 {
292         ShowDeprecationWarning("setFrequency()", "the frequency property");
293         int pulse_frequencyArg = 0;
294
295         if(!PyArg_ParseTuple(args, "i:setFrequency", &pulse_frequencyArg)) {
296                 return NULL;
297         }
298         
299         /* We can do three things here: clip, ignore and raise an exception.  */
300         /* Exceptions don't work yet, ignoring is not desirable now...        */
301         if (pulse_frequencyArg < 0) {
302                 pulse_frequencyArg = 0;
303         };      
304         m_pulse_frequency = pulse_frequencyArg;
305
306         Py_RETURN_NONE;
307 }
308
309
310 const char SCA_ISensor::GetInvert_doc[] = 
311 "getInvert()\n"
312 "\tReturns whether or not pulses from this sensor are inverted.\n" ;
313 PyObject* SCA_ISensor::PyGetInvert()
314 {
315         ShowDeprecationWarning("getInvert()", "the invert property");
316         return BoolToPyArg(m_invert);
317 }
318
319 const char SCA_ISensor::SetInvert_doc[] = 
320 "setInvert(invert?)\n"
321 "\t- invert?: Invert the event-values? (KX_TRUE, KX_FALSE)\n"
322 "\tSet whether to invert pulses.\n";
323 PyObject* SCA_ISensor::PySetInvert(PyObject* args)
324 {
325         ShowDeprecationWarning("setInvert()", "the invert property");
326         int pyarg = 0;
327         if(!PyArg_ParseTuple(args, "i:setInvert", &pyarg)) { return NULL; }
328         m_invert = PyArgToBool(pyarg);
329         Py_RETURN_NONE;
330 }
331
332 const char SCA_ISensor::GetLevel_doc[] = 
333 "getLevel()\n"
334 "\tReturns whether this sensor is a level detector or a edge detector.\n"
335 "\tIt makes a difference only in case of logic state transition (state actuator).\n"
336 "\tA level detector will immediately generate a pulse, negative or positive\n"
337 "\tdepending on the sensor condition, as soon as the state is activated.\n"
338 "\tA edge detector will wait for a state change before generating a pulse.\n";
339 PyObject* SCA_ISensor::PyGetLevel()
340 {
341         ShowDeprecationWarning("getLevel()", "the level property");
342         return BoolToPyArg(m_level);
343 }
344
345 const char SCA_ISensor::SetLevel_doc[] = 
346 "setLevel(level?)\n"
347 "\t- level?: Detect level instead of edge? (KX_TRUE, KX_FALSE)\n"
348 "\tSet whether to detect level or edge transition when entering a state.\n";
349 PyObject* SCA_ISensor::PySetLevel(PyObject* args)
350 {
351         ShowDeprecationWarning("setLevel()", "the level property");
352         int pyarg = 0;
353         if(!PyArg_ParseTuple(args, "i:setLevel", &pyarg)) { return NULL; }
354         m_level = PyArgToBool(pyarg);
355         Py_RETURN_NONE;
356 }
357
358 const char SCA_ISensor::GetUseNegPulseMode_doc[] = 
359 "getUseNegPulseMode()\n"
360 "\tReturns whether negative pulse mode is active.\n";
361 PyObject* SCA_ISensor::PyGetUseNegPulseMode()
362 {
363         ShowDeprecationWarning("getUseNegPulseMode()", "the useNegPulseMode property");
364         return BoolToPyArg(m_neg_pulsemode);
365 }
366
367 const char SCA_ISensor::SetUseNegPulseMode_doc[] = 
368 "setUseNegPulseMode(pulse?)\n"
369 "\t - pulse? : Pulse when a negative event occurs?\n"
370 "\t            (KX_TRUE, KX_FALSE)\n"
371 "\tSet whether to do pulsing when negative pulses occur.\n";
372 PyObject* SCA_ISensor::PySetUseNegPulseMode(PyObject* args)
373 {
374         ShowDeprecationWarning("setUseNegPulseMode()", "the useNegPulseMode property");
375         int pyarg = 0;
376         if(!PyArg_ParseTuple(args, "i:setUseNegPulseMode", &pyarg)) { return NULL; }
377         m_neg_pulsemode = PyArgToBool(pyarg);
378         Py_RETURN_NONE;
379 }
380 //<------Deprecated
381
382 KX_PYMETHODDEF_DOC_NOARGS(SCA_ISensor, reset,
383 "reset()\n"
384 "\tReset sensor internal state, effect depends on the type of sensor and settings.\n"
385 "\tThe sensor is put in its initial state as if it was just activated.\n")
386 {
387         Init();
388         Py_RETURN_NONE;
389 }
390
391 /* ----------------------------------------------- */
392 /* Python Integration Hooks                                            */
393 /* ----------------------------------------------- */
394
395 PyTypeObject SCA_ISensor::Type = {
396 #if (PY_VERSION_HEX >= 0x02060000)
397         PyVarObject_HEAD_INIT(NULL, 0)
398 #else
399         /* python 2.5 and below */
400         PyObject_HEAD_INIT( NULL )  /* required py macro */
401         0,                          /* ob_size */
402 #endif
403         "SCA_ISensor",
404         sizeof(PyObjectPlus_Proxy),
405         0,
406         py_base_dealloc,
407         0,
408         0,
409         0,
410         0,
411         py_base_repr,
412         0,0,0,0,0,0,
413         py_base_getattro,
414         py_base_setattro,
415         0,0,0,0,0,0,0,0,0,
416         Methods
417 };
418
419 PyParentObject SCA_ISensor::Parents[] = {
420         &SCA_ISensor::Type,
421         &SCA_ILogicBrick::Type,
422         &CValue::Type,
423         NULL
424 };
425 PyMethodDef SCA_ISensor::Methods[] = {
426         //Deprecated functions ----->
427         {"isPositive", (PyCFunction) SCA_ISensor::sPyIsPositive, 
428          METH_NOARGS, (PY_METHODCHAR)IsPositive_doc},
429         {"isTriggered", (PyCFunction) SCA_ISensor::sPyIsTriggered, 
430          METH_VARARGS, (PY_METHODCHAR)IsTriggered_doc},
431         {"getUsePosPulseMode", (PyCFunction) SCA_ISensor::sPyGetUsePosPulseMode, 
432          METH_NOARGS, (PY_METHODCHAR)GetUsePosPulseMode_doc},
433         {"setUsePosPulseMode", (PyCFunction) SCA_ISensor::sPySetUsePosPulseMode, 
434          METH_VARARGS, (PY_METHODCHAR)SetUsePosPulseMode_doc},
435         {"getFrequency", (PyCFunction) SCA_ISensor::sPyGetFrequency, 
436          METH_NOARGS, (PY_METHODCHAR)GetFrequency_doc},
437         {"setFrequency", (PyCFunction) SCA_ISensor::sPySetFrequency, 
438          METH_VARARGS, (PY_METHODCHAR)SetFrequency_doc},
439         {"getUseNegPulseMode", (PyCFunction) SCA_ISensor::sPyGetUseNegPulseMode, 
440          METH_NOARGS, (PY_METHODCHAR)GetUseNegPulseMode_doc},
441         {"setUseNegPulseMode", (PyCFunction) SCA_ISensor::sPySetUseNegPulseMode, 
442          METH_VARARGS, (PY_METHODCHAR)SetUseNegPulseMode_doc},
443         {"getInvert", (PyCFunction) SCA_ISensor::sPyGetInvert, 
444          METH_NOARGS, (PY_METHODCHAR)GetInvert_doc},
445         {"setInvert", (PyCFunction) SCA_ISensor::sPySetInvert, 
446          METH_VARARGS, (PY_METHODCHAR)SetInvert_doc},
447         {"getLevel", (PyCFunction) SCA_ISensor::sPyGetLevel, 
448          METH_NOARGS, (PY_METHODCHAR)GetLevel_doc},
449         {"setLevel", (PyCFunction) SCA_ISensor::sPySetLevel, 
450          METH_VARARGS, (PY_METHODCHAR)SetLevel_doc},
451          //<----- Deprecated
452         KX_PYMETHODTABLE_NOARGS(SCA_ISensor, reset),
453         {NULL,NULL} //Sentinel
454 };
455
456 PyAttributeDef SCA_ISensor::Attributes[] = {
457         KX_PYATTRIBUTE_BOOL_RW("usePosPulseMode",SCA_ISensor,m_pos_pulsemode),
458         KX_PYATTRIBUTE_BOOL_RW("useNegPulseMode",SCA_ISensor,m_neg_pulsemode),
459         KX_PYATTRIBUTE_INT_RW("frequency",0,100000,true,SCA_ISensor,m_pulse_frequency),
460         KX_PYATTRIBUTE_BOOL_RW("invert",SCA_ISensor,m_invert),
461         KX_PYATTRIBUTE_BOOL_RW("level",SCA_ISensor,m_level),
462         KX_PYATTRIBUTE_RO_FUNCTION("triggered", SCA_ISensor, pyattr_get_triggered),
463         KX_PYATTRIBUTE_RO_FUNCTION("positive", SCA_ISensor, pyattr_get_positive),
464         //KX_PYATTRIBUTE_TODO("links"),
465         //KX_PYATTRIBUTE_TODO("posTicks"),
466         //KX_PYATTRIBUTE_TODO("negTicks"),
467         { NULL }        //Sentinel
468 };
469
470 PyObject* SCA_ISensor::py_getattro(PyObject *attr)
471 {
472         py_getattro_up(SCA_ILogicBrick);
473 }
474
475 PyObject* SCA_ISensor::py_getattro_dict() {
476         py_getattro_dict_up(SCA_ILogicBrick);
477 }
478
479 int SCA_ISensor::py_setattro(PyObject *attr, PyObject *value)
480 {
481         py_setattro_up(SCA_ILogicBrick);
482 }
483
484 PyObject* SCA_ISensor::pyattr_get_triggered(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
485 {
486         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
487         int retval = 0;
488         if (SCA_PythonController::m_sCurrentController)
489                 retval = SCA_PythonController::m_sCurrentController->IsTriggered(self);
490         return PyInt_FromLong(retval);
491 }
492
493 PyObject* SCA_ISensor::pyattr_get_positive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
494 {
495         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
496         return PyInt_FromLong(self->IsPositiveTrigger());
497 }
498
499 /* eof */