doxygen: prevent GPL license block from being parsed as doxygen comment.
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 <stddef.h>
33
34 #include "SCA_ISensor.h"
35 #include "SCA_EventManager.h"
36 #include "SCA_LogicManager.h"
37 // needed for IsTriggered()
38 #include "SCA_PythonController.h"
39
40 #include <stdio.h>
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::Replace_EventManager(class SCA_LogicManager* logicmgr)
162 {
163         if(m_links) { /* true if we're used currently */
164
165                 m_eventmgr->RemoveSensor(this);
166                 m_eventmgr= logicmgr->FindEventManager(m_eventmgr->GetType());
167                 m_eventmgr->RegisterSensor(this);
168         }
169         else {
170                 m_eventmgr= logicmgr->FindEventManager(m_eventmgr->GetType());
171         }
172 }
173
174 void SCA_ISensor::LinkToController(SCA_IController* controller)
175 {
176         m_linkedcontrollers.push_back(controller);
177 }
178
179 void SCA_ISensor::UnlinkController(SCA_IController* controller)
180 {
181         std::vector<class SCA_IController*>::iterator contit;
182         for (contit = m_linkedcontrollers.begin();!(contit==m_linkedcontrollers.end());++contit)
183         {
184                 if ((*contit) == controller)
185                 {
186                         *contit = m_linkedcontrollers.back();
187                         m_linkedcontrollers.pop_back();
188                         return;
189                 }
190         }
191         printf("Missing link from sensor %s:%s to controller %s:%s\n", 
192                 m_gameobj->GetName().ReadPtr(), GetName().ReadPtr(), 
193                 controller->GetParent()->GetName().ReadPtr(), controller->GetName().ReadPtr());
194 }
195
196 void SCA_ISensor::UnlinkAllControllers()
197 {
198         std::vector<class SCA_IController*>::iterator contit;
199         for (contit = m_linkedcontrollers.begin();!(contit==m_linkedcontrollers.end());++contit)
200         {
201                 (*contit)->UnlinkSensor(this);
202         }
203         m_linkedcontrollers.clear();
204 }
205
206 void SCA_ISensor::UnregisterToManager()
207 {
208         m_eventmgr->RemoveSensor(this);
209         m_links = 0;
210 }
211
212 void SCA_ISensor::ActivateControllers(class SCA_LogicManager* logicmgr)
213 {
214     for(vector<SCA_IController*>::const_iterator c= m_linkedcontrollers.begin();
215                 c!=m_linkedcontrollers.end();++c)
216         {
217                 SCA_IController* contr = *c;
218                 if (contr->IsActive())
219                         logicmgr->AddTriggeredController(contr, this);
220         }
221 }
222
223 void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr)
224 {
225         
226         // calculate if a __triggering__ is wanted
227         // don't evaluate a sensor that is not connected to any controller
228         if (m_links && !m_suspended) {
229                 bool result = this->Evaluate();
230                 // store the state for the rest of the logic system
231                 m_prev_state = m_state;
232                 m_state = this->IsPositiveTrigger();
233                 if (result) {
234                         // the sensor triggered this frame
235                         if (m_state || !m_tap) {
236                                 ActivateControllers(logicmgr);  
237                                 // reset these counters so that pulse are synchronized with transition
238                                 m_pos_ticks = 0;
239                                 m_neg_ticks = 0;
240                         } else
241                         {
242                                 result = false;
243                         }
244                 } else
245                 {
246                         /* First, the pulsing behaviour, if pulse mode is
247                          * active. It seems something goes wrong if pulse mode is
248                          * not set :( */
249                         if (m_pos_pulsemode) {
250                                 m_pos_ticks++;
251                                 if (m_pos_ticks > m_pulse_frequency) {
252                                         if ( m_state )
253                                         {
254                                                 ActivateControllers(logicmgr);
255                                                 result = true;
256                                         }
257                                         m_pos_ticks = 0;
258                                 } 
259                         }
260                         // negative pulse doesn't make sense in tap mode, skip
261                         if (m_neg_pulsemode && !m_tap)
262                         {
263                                 m_neg_ticks++;
264                                 if (m_neg_ticks > m_pulse_frequency) {
265                                         if (!m_state )
266                                         {
267                                                 ActivateControllers(logicmgr);
268                                                 result = true;
269                                         }
270                                         m_neg_ticks = 0;
271                                 }
272                         }
273                 }
274                 if (m_tap)
275                 {
276                         // in tap mode: we send always a negative pulse immediately after a positive pulse
277                         if (!result)
278                         {
279                                 // the sensor did not trigger on this frame
280                                 if (m_prev_state)
281                                 {
282                                         // but it triggered on previous frame => send a negative pulse
283                                         ActivateControllers(logicmgr);
284                                         result = true;
285                                 }
286                                 // in any case, absence of trigger means sensor off
287                                 m_state = false;
288                         }
289                 }
290                 if (!result && m_level)
291                 {
292                         // This level sensor is connected to at least one controller that was just made 
293                         // active but it did not generate an event yet, do it now to those controllers only 
294                         for(vector<SCA_IController*>::const_iterator c= m_linkedcontrollers.begin();
295                                 c!=m_linkedcontrollers.end();++c)
296                         {
297                                 SCA_IController* contr = *c;
298                                 if (contr->IsJustActivated())
299                                         logicmgr->AddTriggeredController(contr, this);
300                         }
301                 }
302         } 
303 }
304
305 #ifdef WITH_PYTHON
306
307 /* ----------------------------------------------- */
308 /* Python Functions                                                        */
309 /* ----------------------------------------------- */
310
311 KX_PYMETHODDEF_DOC_NOARGS(SCA_ISensor, reset,
312 "reset()\n"
313 "\tReset sensor internal state, effect depends on the type of sensor and settings.\n"
314 "\tThe sensor is put in its initial state as if it was just activated.\n")
315 {
316         Init();
317         m_prev_state = false;
318         Py_RETURN_NONE;
319 }
320
321 /* ----------------------------------------------- */
322 /* Python Integration Hooks                                            */
323 /* ----------------------------------------------- */
324
325 PyTypeObject SCA_ISensor::Type = {
326         PyVarObject_HEAD_INIT(NULL, 0)
327         "SCA_ISensor",
328         sizeof(PyObjectPlus_Proxy),
329         0,
330         py_base_dealloc,
331         0,
332         0,
333         0,
334         0,
335         py_base_repr,
336         0,0,0,0,0,0,0,0,0,
337         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
338         0,0,0,0,0,0,0,
339         Methods,
340         0,
341         0,
342         &SCA_ILogicBrick::Type,
343         0,0,0,0,0,0,
344         py_base_new
345 };
346
347 PyMethodDef SCA_ISensor::Methods[] = {
348         KX_PYMETHODTABLE_NOARGS(SCA_ISensor, reset),
349         {NULL,NULL} //Sentinel
350 };
351
352 PyAttributeDef SCA_ISensor::Attributes[] = {
353         KX_PYATTRIBUTE_BOOL_RW("usePosPulseMode",SCA_ISensor,m_pos_pulsemode),
354         KX_PYATTRIBUTE_BOOL_RW("useNegPulseMode",SCA_ISensor,m_neg_pulsemode),
355         KX_PYATTRIBUTE_INT_RW("frequency",0,100000,true,SCA_ISensor,m_pulse_frequency),
356         KX_PYATTRIBUTE_BOOL_RW("invert",SCA_ISensor,m_invert),
357         KX_PYATTRIBUTE_BOOL_RW_CHECK("level",SCA_ISensor,m_level,pyattr_check_level),
358         KX_PYATTRIBUTE_BOOL_RW_CHECK("tap",SCA_ISensor,m_tap,pyattr_check_tap),
359         KX_PYATTRIBUTE_RO_FUNCTION("triggered", SCA_ISensor, pyattr_get_triggered),
360         KX_PYATTRIBUTE_RO_FUNCTION("positive", SCA_ISensor, pyattr_get_positive),
361         KX_PYATTRIBUTE_RO_FUNCTION("status", SCA_ISensor, pyattr_get_status),
362         KX_PYATTRIBUTE_RO_FUNCTION("pos_ticks", SCA_ISensor, pyattr_get_posTicks),
363         KX_PYATTRIBUTE_RO_FUNCTION("neg_ticks", SCA_ISensor, pyattr_get_negTicks),
364         { NULL }        //Sentinel
365 };
366
367
368 PyObject* SCA_ISensor::pyattr_get_triggered(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
369 {
370         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
371         int retval = 0;
372         if (SCA_PythonController::m_sCurrentController)
373                 retval = SCA_PythonController::m_sCurrentController->IsTriggered(self);
374         return PyLong_FromSsize_t(retval);
375 }
376
377 PyObject* SCA_ISensor::pyattr_get_positive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
378 {
379         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
380         return PyLong_FromSsize_t(self->GetState());
381 }
382
383 PyObject* SCA_ISensor::pyattr_get_status(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
384 {
385         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
386         int status = 0;
387         if (self->GetState()) 
388         {
389                 if (self->GetState() == self->GetPrevState()) 
390                 {
391                         status = 2;
392                 }
393                 else 
394                 {
395                         status = 1;
396                 }
397         }
398         else if (self->GetState() != self->GetPrevState()) 
399         {
400                 status = 3;
401         }
402         return PyLong_FromSsize_t(status);
403 }
404
405 PyObject* SCA_ISensor::pyattr_get_posTicks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
406 {
407         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
408         return PyLong_FromLong(self->GetPosTicks());
409 }
410
411 PyObject* SCA_ISensor::pyattr_get_negTicks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
412 {
413         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
414         return PyLong_FromLong(self->GetNegTicks());
415 }
416
417 int SCA_ISensor::pyattr_check_level(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
418 {
419         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
420         if (self->m_level)
421                 self->m_tap = false;
422         return 0;
423 }
424
425 int SCA_ISensor::pyattr_check_tap(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
426 {
427         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
428         if (self->m_tap)
429                 self->m_level = false;
430         return 0;
431 }
432 #endif // WITH_PYTHON
433
434 /* eof */