NLA SoC: Merge from 2.5
[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 {
57         m_links = 0;
58         m_suspended = false;
59         m_invert = false;
60         m_level = false;
61         m_tap = 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         m_state = false;
69         m_prev_state = false;
70         
71         m_eventmgr = eventmgr;
72 }
73
74
75 SCA_ISensor::~SCA_ISensor()  
76 {
77         // intentionally empty
78 }
79
80 void SCA_ISensor::ProcessReplica()
81 {
82         SCA_ILogicBrick::ProcessReplica();
83         m_linkedcontrollers.clear();
84 }
85
86 bool SCA_ISensor::IsPositiveTrigger() { 
87         bool result = false;
88         
89         if (m_eventval) {
90                 result = (m_eventval->GetNumber() != 0.0);
91         }
92         if (m_invert) {
93                 result = !result;
94         }
95         
96         return result;
97 }
98
99 void SCA_ISensor::SetPulseMode(bool posmode, 
100                                                            bool negmode,
101                                                            int freq) {
102         m_pos_pulsemode = posmode;
103         m_neg_pulsemode = negmode;
104         m_pulse_frequency = freq;
105 }
106
107 void SCA_ISensor::SetInvert(bool inv) {
108         m_invert = inv;
109 }
110
111 void SCA_ISensor::SetLevel(bool lvl) {
112         m_level = lvl;
113 }
114
115 void SCA_ISensor::SetTap(bool tap) {
116         m_tap = tap;
117 }
118
119
120 double SCA_ISensor::GetNumber() {
121         return GetState();
122 }
123
124 void SCA_ISensor::Suspend() {
125         m_suspended = true;
126 }
127
128 bool SCA_ISensor::IsSuspended() {
129         return m_suspended;
130 }
131
132 void SCA_ISensor::Resume() {
133         m_suspended = false;
134 }
135
136 void SCA_ISensor::Init() {
137         printf("Sensor %s has no init function, please report this bug to Blender.org\n", m_name.Ptr());
138 }
139
140 void SCA_ISensor::DecLink() {
141         m_links--;
142         if (m_links < 0) 
143         {
144                 printf("Warning: sensor %s has negative m_links: %d\n", m_name.Ptr(), m_links);
145                 m_links = 0;
146         }
147         if (!m_links)
148         {
149                 // sensor is detached from all controllers, remove it from manager
150                 UnregisterToManager();
151         }
152 }
153
154 void SCA_ISensor::RegisterToManager()
155 {
156         // sensor is just activated, initialize it
157         Init();
158         m_state = false;
159         m_eventmgr->RegisterSensor(this);
160 }
161
162 void SCA_ISensor::LinkToController(SCA_IController* controller)
163 {
164         m_linkedcontrollers.push_back(controller);
165 }
166
167 void SCA_ISensor::UnlinkController(SCA_IController* controller)
168 {
169         std::vector<class SCA_IController*>::iterator contit;
170         for (contit = m_linkedcontrollers.begin();!(contit==m_linkedcontrollers.end());++contit)
171         {
172                 if ((*contit) == controller)
173                 {
174                         *contit = m_linkedcontrollers.back();
175                         m_linkedcontrollers.pop_back();
176                         return;
177                 }
178         }
179         printf("Missing link from sensor %s:%s to controller %s:%s\n", 
180                 m_gameobj->GetName().ReadPtr(), GetName().ReadPtr(), 
181                 controller->GetParent()->GetName().ReadPtr(), controller->GetName().ReadPtr());
182 }
183
184 void SCA_ISensor::UnlinkAllControllers()
185 {
186         std::vector<class SCA_IController*>::iterator contit;
187         for (contit = m_linkedcontrollers.begin();!(contit==m_linkedcontrollers.end());++contit)
188         {
189                 (*contit)->UnlinkSensor(this);
190         }
191         m_linkedcontrollers.clear();
192 }
193
194 void SCA_ISensor::UnregisterToManager()
195 {
196         m_eventmgr->RemoveSensor(this);
197         m_links = 0;
198 }
199
200 void SCA_ISensor::ActivateControllers(class SCA_LogicManager* logicmgr)
201 {
202     for(vector<SCA_IController*>::const_iterator c= m_linkedcontrollers.begin();
203                 c!=m_linkedcontrollers.end();++c)
204         {
205                 SCA_IController* contr = *c;
206                 if (contr->IsActive())
207                         logicmgr->AddTriggeredController(contr, this);
208         }
209 }
210
211 void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr)
212 {
213         
214         // calculate if a __triggering__ is wanted
215         // don't evaluate a sensor that is not connected to any controller
216         if (m_links && !m_suspended) {
217                 bool result = this->Evaluate();
218                 // store the state for the rest of the logic system
219                 m_prev_state = m_state;
220                 m_state = this->IsPositiveTrigger();
221                 if (result) {
222                         // the sensor triggered this frame
223                         if (m_state || !m_tap) {
224                                 ActivateControllers(logicmgr);  
225                                 // reset these counters so that pulse are synchronized with transition
226                                 m_pos_ticks = 0;
227                                 m_neg_ticks = 0;
228                         } else
229                         {
230                                 result = false;
231                         }
232                 } else
233                 {
234                         /* First, the pulsing behaviour, if pulse mode is
235                          * active. It seems something goes wrong if pulse mode is
236                          * not set :( */
237                         if (m_pos_pulsemode) {
238                                 m_pos_ticks++;
239                                 if (m_pos_ticks > m_pulse_frequency) {
240                                         if ( m_state )
241                                         {
242                                                 ActivateControllers(logicmgr);
243                                                 result = true;
244                                         }
245                                         m_pos_ticks = 0;
246                                 } 
247                         }
248                         // negative pulse doesn't make sense in tap mode, skip
249                         if (m_neg_pulsemode && !m_tap)
250                         {
251                                 m_neg_ticks++;
252                                 if (m_neg_ticks > m_pulse_frequency) {
253                                         if (!m_state )
254                                         {
255                                                 ActivateControllers(logicmgr);
256                                                 result = true;
257                                         }
258                                         m_neg_ticks = 0;
259                                 }
260                         }
261                 }
262                 if (m_tap)
263                 {
264                         // in tap mode: we send always a negative pulse immediately after a positive pulse
265                         if (!result)
266                         {
267                                 // the sensor did not trigger on this frame
268                                 if (m_prev_state)
269                                 {
270                                         // but it triggered on previous frame => send a negative pulse
271                                         ActivateControllers(logicmgr);
272                                         result = true;
273                                 }
274                                 // in any case, absence of trigger means sensor off
275                                 m_state = false;
276                         }
277                 }
278                 if (!result && m_level)
279                 {
280                         // This level sensor is connected to at least one controller that was just made 
281                         // active but it did not generate an event yet, do it now to those controllers only 
282                         for(vector<SCA_IController*>::const_iterator c= m_linkedcontrollers.begin();
283                                 c!=m_linkedcontrollers.end();++c)
284                         {
285                                 SCA_IController* contr = *c;
286                                 if (contr->IsJustActivated())
287                                         logicmgr->AddTriggeredController(contr, this);
288                         }
289                 }
290         } 
291 }
292 /* ----------------------------------------------- */
293 /* Python Functions                                                        */
294 /* ----------------------------------------------- */
295
296 //Deprecated Functions ------>
297 const char SCA_ISensor::IsPositive_doc[] = 
298 "isPositive()\n"
299 "\tReturns whether the sensor is in an active state.\n";
300 PyObject* SCA_ISensor::PyIsPositive()
301 {
302         ShowDeprecationWarning("isPositive()", "the read-only positive property");
303         int retval = GetState();
304         return PyInt_FromLong(retval);
305 }
306
307 const char SCA_ISensor::IsTriggered_doc[] = 
308 "isTriggered()\n"
309 "\tReturns whether the sensor has triggered the current controller.\n";
310 PyObject* SCA_ISensor::PyIsTriggered()
311 {
312         ShowDeprecationWarning("isTriggered()", "the read-only triggered property");
313         // check with the current controller
314         int retval = 0;
315         if (SCA_PythonController::m_sCurrentController)
316                 retval = SCA_PythonController::m_sCurrentController->IsTriggered(this);
317         return PyInt_FromLong(retval);
318 }
319
320 /**
321  * getUsePulseMode: getter for the pulse mode (KX_TRUE = on)
322  */
323 const char SCA_ISensor::GetUsePosPulseMode_doc[] = 
324 "getUsePosPulseMode()\n"
325 "\tReturns whether positive pulse mode is active.\n";
326 PyObject* SCA_ISensor::PyGetUsePosPulseMode()
327 {
328         ShowDeprecationWarning("getUsePosPulseMode()", "the usePosPulseMode property");
329         return BoolToPyArg(m_pos_pulsemode);
330 }
331
332 /**
333  * setUsePulseMode: setter for the pulse mode (KX_TRUE = on)
334  */
335 const char SCA_ISensor::SetUsePosPulseMode_doc[] = 
336 "setUsePosPulseMode(pulse?)\n"
337 "\t - pulse? : Pulse when a positive event occurs?\n"
338 "\t            (KX_TRUE, KX_FALSE)\n"
339 "\tSet whether to do pulsing when positive pulses occur.\n";
340 PyObject* SCA_ISensor::PySetUsePosPulseMode(PyObject* args)
341 {
342         ShowDeprecationWarning("setUsePosPulseMode()", "the usePosPulseMode property");
343         int pyarg = 0;
344         if(!PyArg_ParseTuple(args, "i:setUsePosPulseMode", &pyarg)) { return NULL; }
345         m_pos_pulsemode = PyArgToBool(pyarg);
346         Py_RETURN_NONE;
347 }
348
349 /**
350  * getFrequency: getter for the pulse mode interval
351  */
352 const char SCA_ISensor::GetFrequency_doc[] = 
353 "getFrequency()\n"
354 "\tReturns the frequency of the updates in pulse mode.\n" ;
355 PyObject* SCA_ISensor::PyGetFrequency()
356 {
357         ShowDeprecationWarning("getFrequency()", "the frequency property");
358         return PyInt_FromLong(m_pulse_frequency);
359 }
360
361 /**
362  * setFrequency: setter for the pulse mode (KX_TRUE = on)
363  */
364 const char SCA_ISensor::SetFrequency_doc[] = 
365 "setFrequency(pulse_frequency)\n"
366 "\t- pulse_frequency: The frequency of the updates in pulse mode (integer)"
367 "\tSet the frequency of the updates in pulse mode.\n"
368 "\tIf the frequency is negative, it is set to 0.\n" ;
369 PyObject* SCA_ISensor::PySetFrequency(PyObject* args)
370 {
371         ShowDeprecationWarning("setFrequency()", "the frequency property");
372         int pulse_frequencyArg = 0;
373
374         if(!PyArg_ParseTuple(args, "i:setFrequency", &pulse_frequencyArg)) {
375                 return NULL;
376         }
377         
378         /* We can do three things here: clip, ignore and raise an exception.  */
379         /* Exceptions don't work yet, ignoring is not desirable now...        */
380         if (pulse_frequencyArg < 0) {
381                 pulse_frequencyArg = 0;
382         };      
383         m_pulse_frequency = pulse_frequencyArg;
384
385         Py_RETURN_NONE;
386 }
387
388
389 const char SCA_ISensor::GetInvert_doc[] = 
390 "getInvert()\n"
391 "\tReturns whether or not pulses from this sensor are inverted.\n" ;
392 PyObject* SCA_ISensor::PyGetInvert()
393 {
394         ShowDeprecationWarning("getInvert()", "the invert property");
395         return BoolToPyArg(m_invert);
396 }
397
398 const char SCA_ISensor::SetInvert_doc[] = 
399 "setInvert(invert?)\n"
400 "\t- invert?: Invert the event-values? (KX_TRUE, KX_FALSE)\n"
401 "\tSet whether to invert pulses.\n";
402 PyObject* SCA_ISensor::PySetInvert(PyObject* args)
403 {
404         ShowDeprecationWarning("setInvert()", "the invert property");
405         int pyarg = 0;
406         if(!PyArg_ParseTuple(args, "i:setInvert", &pyarg)) { return NULL; }
407         m_invert = PyArgToBool(pyarg);
408         Py_RETURN_NONE;
409 }
410
411 const char SCA_ISensor::GetLevel_doc[] = 
412 "getLevel()\n"
413 "\tReturns whether this sensor is a level detector or a edge detector.\n"
414 "\tIt makes a difference only in case of logic state transition (state actuator).\n"
415 "\tA level detector will immediately generate a pulse, negative or positive\n"
416 "\tdepending on the sensor condition, as soon as the state is activated.\n"
417 "\tA edge detector will wait for a state change before generating a pulse.\n";
418 PyObject* SCA_ISensor::PyGetLevel()
419 {
420         ShowDeprecationWarning("getLevel()", "the level property");
421         return BoolToPyArg(m_level);
422 }
423
424 const char SCA_ISensor::SetLevel_doc[] = 
425 "setLevel(level?)\n"
426 "\t- level?: Detect level instead of edge? (KX_TRUE, KX_FALSE)\n"
427 "\tSet whether to detect level or edge transition when entering a state.\n";
428 PyObject* SCA_ISensor::PySetLevel(PyObject* args)
429 {
430         ShowDeprecationWarning("setLevel()", "the level property");
431         int pyarg = 0;
432         if(!PyArg_ParseTuple(args, "i:setLevel", &pyarg)) { return NULL; }
433         m_level = PyArgToBool(pyarg);
434         Py_RETURN_NONE;
435 }
436
437 const char SCA_ISensor::GetUseNegPulseMode_doc[] = 
438 "getUseNegPulseMode()\n"
439 "\tReturns whether negative pulse mode is active.\n";
440 PyObject* SCA_ISensor::PyGetUseNegPulseMode()
441 {
442         ShowDeprecationWarning("getUseNegPulseMode()", "the useNegPulseMode property");
443         return BoolToPyArg(m_neg_pulsemode);
444 }
445
446 const char SCA_ISensor::SetUseNegPulseMode_doc[] = 
447 "setUseNegPulseMode(pulse?)\n"
448 "\t - pulse? : Pulse when a negative event occurs?\n"
449 "\t            (KX_TRUE, KX_FALSE)\n"
450 "\tSet whether to do pulsing when negative pulses occur.\n";
451 PyObject* SCA_ISensor::PySetUseNegPulseMode(PyObject* args)
452 {
453         ShowDeprecationWarning("setUseNegPulseMode()", "the useNegPulseMode property");
454         int pyarg = 0;
455         if(!PyArg_ParseTuple(args, "i:setUseNegPulseMode", &pyarg)) { return NULL; }
456         m_neg_pulsemode = PyArgToBool(pyarg);
457         Py_RETURN_NONE;
458 }
459 //<------Deprecated
460
461 KX_PYMETHODDEF_DOC_NOARGS(SCA_ISensor, reset,
462 "reset()\n"
463 "\tReset sensor internal state, effect depends on the type of sensor and settings.\n"
464 "\tThe sensor is put in its initial state as if it was just activated.\n")
465 {
466         Init();
467         m_prev_state = false;
468         Py_RETURN_NONE;
469 }
470
471 /* ----------------------------------------------- */
472 /* Python Integration Hooks                                            */
473 /* ----------------------------------------------- */
474
475 PyTypeObject SCA_ISensor::Type = {
476 #if (PY_VERSION_HEX >= 0x02060000)
477         PyVarObject_HEAD_INIT(NULL, 0)
478 #else
479         /* python 2.5 and below */
480         PyObject_HEAD_INIT( NULL )  /* required py macro */
481         0,                          /* ob_size */
482 #endif
483         "SCA_ISensor",
484         sizeof(PyObjectPlus_Proxy),
485         0,
486         py_base_dealloc,
487         0,
488         0,
489         0,
490         0,
491         py_base_repr,
492         0,0,0,0,0,0,
493         py_base_getattro,
494         py_base_setattro,
495         0,0,0,0,0,0,0,0,0,
496         Methods
497 };
498
499 PyParentObject SCA_ISensor::Parents[] = {
500         &SCA_ISensor::Type,
501         &SCA_ILogicBrick::Type,
502         &CValue::Type,
503         NULL
504 };
505 PyMethodDef SCA_ISensor::Methods[] = {
506         //Deprecated functions ----->
507         {"isPositive", (PyCFunction) SCA_ISensor::sPyIsPositive, 
508          METH_NOARGS, (PY_METHODCHAR)IsPositive_doc},
509         {"isTriggered", (PyCFunction) SCA_ISensor::sPyIsTriggered, 
510          METH_VARARGS, (PY_METHODCHAR)IsTriggered_doc},
511         {"getUsePosPulseMode", (PyCFunction) SCA_ISensor::sPyGetUsePosPulseMode, 
512          METH_NOARGS, (PY_METHODCHAR)GetUsePosPulseMode_doc},
513         {"setUsePosPulseMode", (PyCFunction) SCA_ISensor::sPySetUsePosPulseMode, 
514          METH_VARARGS, (PY_METHODCHAR)SetUsePosPulseMode_doc},
515         {"getFrequency", (PyCFunction) SCA_ISensor::sPyGetFrequency, 
516          METH_NOARGS, (PY_METHODCHAR)GetFrequency_doc},
517         {"setFrequency", (PyCFunction) SCA_ISensor::sPySetFrequency, 
518          METH_VARARGS, (PY_METHODCHAR)SetFrequency_doc},
519         {"getUseNegPulseMode", (PyCFunction) SCA_ISensor::sPyGetUseNegPulseMode, 
520          METH_NOARGS, (PY_METHODCHAR)GetUseNegPulseMode_doc},
521         {"setUseNegPulseMode", (PyCFunction) SCA_ISensor::sPySetUseNegPulseMode, 
522          METH_VARARGS, (PY_METHODCHAR)SetUseNegPulseMode_doc},
523         {"getInvert", (PyCFunction) SCA_ISensor::sPyGetInvert, 
524          METH_NOARGS, (PY_METHODCHAR)GetInvert_doc},
525         {"setInvert", (PyCFunction) SCA_ISensor::sPySetInvert, 
526          METH_VARARGS, (PY_METHODCHAR)SetInvert_doc},
527         {"getLevel", (PyCFunction) SCA_ISensor::sPyGetLevel, 
528          METH_NOARGS, (PY_METHODCHAR)GetLevel_doc},
529         {"setLevel", (PyCFunction) SCA_ISensor::sPySetLevel, 
530          METH_VARARGS, (PY_METHODCHAR)SetLevel_doc},
531          //<----- Deprecated
532         KX_PYMETHODTABLE_NOARGS(SCA_ISensor, reset),
533         {NULL,NULL} //Sentinel
534 };
535
536 PyAttributeDef SCA_ISensor::Attributes[] = {
537         KX_PYATTRIBUTE_BOOL_RW("usePosPulseMode",SCA_ISensor,m_pos_pulsemode),
538         KX_PYATTRIBUTE_BOOL_RW("useNegPulseMode",SCA_ISensor,m_neg_pulsemode),
539         KX_PYATTRIBUTE_INT_RW("frequency",0,100000,true,SCA_ISensor,m_pulse_frequency),
540         KX_PYATTRIBUTE_BOOL_RW("invert",SCA_ISensor,m_invert),
541         KX_PYATTRIBUTE_BOOL_RW_CHECK("level",SCA_ISensor,m_level,pyattr_check_level),
542         KX_PYATTRIBUTE_BOOL_RW_CHECK("tap",SCA_ISensor,m_tap,pyattr_check_tap),
543         KX_PYATTRIBUTE_RO_FUNCTION("triggered", SCA_ISensor, pyattr_get_triggered),
544         KX_PYATTRIBUTE_RO_FUNCTION("positive", SCA_ISensor, pyattr_get_positive),
545         //KX_PYATTRIBUTE_TODO("links"),
546         //KX_PYATTRIBUTE_TODO("posTicks"),
547         //KX_PYATTRIBUTE_TODO("negTicks"),
548         { NULL }        //Sentinel
549 };
550
551 PyObject* SCA_ISensor::py_getattro(PyObject *attr)
552 {
553         py_getattro_up(SCA_ILogicBrick);
554 }
555
556 PyObject* SCA_ISensor::py_getattro_dict() {
557         py_getattro_dict_up(SCA_ILogicBrick);
558 }
559
560 int SCA_ISensor::py_setattro(PyObject *attr, PyObject *value)
561 {
562         py_setattro_up(SCA_ILogicBrick);
563 }
564
565 PyObject* SCA_ISensor::pyattr_get_triggered(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
566 {
567         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
568         int retval = 0;
569         if (SCA_PythonController::m_sCurrentController)
570                 retval = SCA_PythonController::m_sCurrentController->IsTriggered(self);
571         return PyInt_FromLong(retval);
572 }
573
574 PyObject* SCA_ISensor::pyattr_get_positive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
575 {
576         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
577         return PyInt_FromLong(self->GetState());
578 }
579
580 int SCA_ISensor::pyattr_check_level(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
581 {
582         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
583         if (self->m_level)
584                 self->m_tap = false;
585         return 0;
586 }
587
588 int SCA_ISensor::pyattr_check_tap(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
589 {
590         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
591         if (self->m_tap)
592                 self->m_level = false;
593         return 0;
594 }
595
596 /* eof */