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