Spelling Cleanup
[blender.git] / source / gameengine / GameLogic / SCA_ISensor.cpp
1 /*
2  * Abstract class for sensor logic bricks
3  *
4  *
5  * ***** BEGIN GPL LICENSE BLOCK *****
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
22  * All rights reserved.
23  *
24  * The Original Code is: all of this file.
25  *
26  * Contributor(s): none yet.
27  *
28  * ***** END GPL LICENSE BLOCK *****
29  */
30
31 /** \file gameengine/GameLogic/SCA_ISensor.cpp
32  *  \ingroup gamelogic
33  */
34
35
36 #include <stddef.h>
37
38 #include "SCA_ISensor.h"
39 #include "SCA_EventManager.h"
40 #include "SCA_LogicManager.h"
41 // needed for IsTriggered()
42 #include "SCA_PythonController.h"
43
44 #include <stdio.h>
45
46 /* Native functions */
47 void    SCA_ISensor::ReParent(SCA_IObject* parent)
48 {
49         SCA_ILogicBrick::ReParent(parent);
50         // will be done when the sensor is activated
51         //m_eventmgr->RegisterSensor(this);
52         //this->SetActive(false);
53 }
54
55
56 SCA_ISensor::SCA_ISensor(SCA_IObject* gameobj,
57                                                  class SCA_EventManager* eventmgr) :
58         SCA_ILogicBrick(gameobj)
59 {
60         m_links = 0;
61         m_suspended = false;
62         m_invert = false;
63         m_level = false;
64         m_tap = false;
65         m_reset = false;
66         m_pos_ticks = 0;
67         m_neg_ticks = 0;
68         m_pos_pulsemode = false;
69         m_neg_pulsemode = false;
70         m_pulse_frequency = 0;
71         m_state = false;
72         m_prev_state = false;
73         
74         m_eventmgr = eventmgr;
75 }
76
77
78 SCA_ISensor::~SCA_ISensor()  
79 {
80         // intentionally empty
81 }
82
83 void SCA_ISensor::ProcessReplica()
84 {
85         SCA_ILogicBrick::ProcessReplica();
86         m_linkedcontrollers.clear();
87 }
88
89 bool SCA_ISensor::IsPositiveTrigger()
90 {
91         bool result = false;
92         
93         if (m_eventval) {
94                 result = (m_eventval->GetNumber() != 0.0);
95         }
96         if (m_invert) {
97                 result = !result;
98         }
99         
100         return result;
101 }
102
103 void SCA_ISensor::SetPulseMode(bool posmode, 
104                                                            bool negmode,
105                                                            int freq) {
106         m_pos_pulsemode = posmode;
107         m_neg_pulsemode = negmode;
108         m_pulse_frequency = freq;
109 }
110
111 void SCA_ISensor::SetInvert(bool inv)
112 {
113         m_invert = inv;
114 }
115
116 void SCA_ISensor::SetLevel(bool lvl)
117 {
118         m_level = lvl;
119 }
120
121 void SCA_ISensor::SetTap(bool tap)
122 {
123         m_tap = tap;
124 }
125
126
127 double SCA_ISensor::GetNumber()
128 {
129         return GetState();
130 }
131
132 void SCA_ISensor::Suspend()
133 {
134         m_suspended = true;
135 }
136
137 bool SCA_ISensor::IsSuspended()
138 {
139         return m_suspended;
140 }
141
142 void SCA_ISensor::Resume()
143 {
144         m_suspended = false;
145 }
146
147 void SCA_ISensor::Init()
148 {
149         printf("Sensor %s has no init function, please report this bug to Blender.org\n", m_name.Ptr());
150 }
151
152 void SCA_ISensor::DecLink()
153 {
154         m_links--;
155         if (m_links < 0) 
156         {
157                 printf("Warning: sensor %s has negative m_links: %d\n", m_name.Ptr(), m_links);
158                 m_links = 0;
159         }
160         if (!m_links)
161         {
162                 // sensor is detached from all controllers, remove it from manager
163                 UnregisterToManager();
164         }
165 }
166
167 void SCA_ISensor::RegisterToManager()
168 {
169         // sensor is just activated, initialize it
170         Init();
171         m_state = false;
172         m_eventmgr->RegisterSensor(this);
173 }
174
175 void SCA_ISensor::Replace_EventManager(class SCA_LogicManager* logicmgr)
176 {
177         if(m_links) { /* true if we're used currently */
178
179                 m_eventmgr->RemoveSensor(this);
180                 m_eventmgr= logicmgr->FindEventManager(m_eventmgr->GetType());
181                 m_eventmgr->RegisterSensor(this);
182         }
183         else {
184                 m_eventmgr= logicmgr->FindEventManager(m_eventmgr->GetType());
185         }
186 }
187
188 void SCA_ISensor::LinkToController(SCA_IController* controller)
189 {
190         m_linkedcontrollers.push_back(controller);
191 }
192
193 void SCA_ISensor::UnlinkController(SCA_IController* controller)
194 {
195         std::vector<class SCA_IController*>::iterator contit;
196         for (contit = m_linkedcontrollers.begin();!(contit==m_linkedcontrollers.end());++contit)
197         {
198                 if ((*contit) == controller)
199                 {
200                         *contit = m_linkedcontrollers.back();
201                         m_linkedcontrollers.pop_back();
202                         return;
203                 }
204         }
205         printf("Missing link from sensor %s:%s to controller %s:%s\n", 
206                 m_gameobj->GetName().ReadPtr(), GetName().ReadPtr(), 
207                 controller->GetParent()->GetName().ReadPtr(), controller->GetName().ReadPtr());
208 }
209
210 void SCA_ISensor::UnlinkAllControllers()
211 {
212         std::vector<class SCA_IController*>::iterator contit;
213         for (contit = m_linkedcontrollers.begin();!(contit==m_linkedcontrollers.end());++contit)
214         {
215                 (*contit)->UnlinkSensor(this);
216         }
217         m_linkedcontrollers.clear();
218 }
219
220 void SCA_ISensor::UnregisterToManager()
221 {
222         m_eventmgr->RemoveSensor(this);
223         m_links = 0;
224 }
225
226 void SCA_ISensor::ActivateControllers(class SCA_LogicManager* logicmgr)
227 {
228         for(vector<SCA_IController*>::const_iterator c= m_linkedcontrollers.begin();
229             c!=m_linkedcontrollers.end();++c)
230         {
231                 SCA_IController* contr = *c;
232                 if (contr->IsActive())
233                         logicmgr->AddTriggeredController(contr, this);
234         }
235 }
236
237 void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr)
238 {
239         
240         // calculate if a __triggering__ is wanted
241         // don't evaluate a sensor that is not connected to any controller
242         if (m_links && !m_suspended) {
243                 bool result = this->Evaluate();
244                 // store the state for the rest of the logic system
245                 m_prev_state = m_state;
246                 m_state = this->IsPositiveTrigger();
247                 if (result) {
248                         // the sensor triggered this frame
249                         if (m_state || !m_tap) {
250                                 ActivateControllers(logicmgr);  
251                                 // reset these counters so that pulse are synchronized with transition
252                                 m_pos_ticks = 0;
253                                 m_neg_ticks = 0;
254                         } else
255                         {
256                                 result = false;
257                         }
258                 } else
259                 {
260                         /* First, the pulsing behavior, if pulse mode is
261                          * active. It seems something goes wrong if pulse mode is
262                          * not set :( */
263                         if (m_pos_pulsemode) {
264                                 m_pos_ticks++;
265                                 if (m_pos_ticks > m_pulse_frequency) {
266                                         if ( m_state )
267                                         {
268                                                 ActivateControllers(logicmgr);
269                                                 result = true;
270                                         }
271                                         m_pos_ticks = 0;
272                                 } 
273                         }
274                         // negative pulse doesn't make sense in tap mode, skip
275                         if (m_neg_pulsemode && !m_tap)
276                         {
277                                 m_neg_ticks++;
278                                 if (m_neg_ticks > m_pulse_frequency) {
279                                         if (!m_state )
280                                         {
281                                                 ActivateControllers(logicmgr);
282                                                 result = true;
283                                         }
284                                         m_neg_ticks = 0;
285                                 }
286                         }
287                 }
288                 if (m_tap)
289                 {
290                         // in tap mode: we send always a negative pulse immediately after a positive pulse
291                         if (!result)
292                         {
293                                 // the sensor did not trigger on this frame
294                                 if (m_prev_state)
295                                 {
296                                         // but it triggered on previous frame => send a negative pulse
297                                         ActivateControllers(logicmgr);
298                                         result = true;
299                                 }
300                                 // in any case, absence of trigger means sensor off
301                                 m_state = false;
302                         }
303                 }
304                 if (!result && m_level)
305                 {
306                         // This level sensor is connected to at least one controller that was just made 
307                         // active but it did not generate an event yet, do it now to those controllers only 
308                         for(vector<SCA_IController*>::const_iterator c= m_linkedcontrollers.begin();
309                                 c!=m_linkedcontrollers.end();++c)
310                         {
311                                 SCA_IController* contr = *c;
312                                 if (contr->IsJustActivated())
313                                         logicmgr->AddTriggeredController(contr, this);
314                         }
315                 }
316         } 
317 }
318
319 #ifdef WITH_PYTHON
320
321 /* ----------------------------------------------- */
322 /* Python Functions                                                        */
323 /* ----------------------------------------------- */
324
325 KX_PYMETHODDEF_DOC_NOARGS(SCA_ISensor, reset,
326 "reset()\n"
327 "\tReset sensor internal state, effect depends on the type of sensor and settings.\n"
328 "\tThe sensor is put in its initial state as if it was just activated.\n")
329 {
330         Init();
331         m_prev_state = false;
332         Py_RETURN_NONE;
333 }
334
335 /* ----------------------------------------------- */
336 /* Python Integration Hooks                                            */
337 /* ----------------------------------------------- */
338
339 PyTypeObject SCA_ISensor::Type = {
340         PyVarObject_HEAD_INIT(NULL, 0)
341         "SCA_ISensor",
342         sizeof(PyObjectPlus_Proxy),
343         0,
344         py_base_dealloc,
345         0,
346         0,
347         0,
348         0,
349         py_base_repr,
350         0,0,0,0,0,0,0,0,0,
351         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
352         0,0,0,0,0,0,0,
353         Methods,
354         0,
355         0,
356         &SCA_ILogicBrick::Type,
357         0,0,0,0,0,0,
358         py_base_new
359 };
360
361 PyMethodDef SCA_ISensor::Methods[] = {
362         KX_PYMETHODTABLE_NOARGS(SCA_ISensor, reset),
363         {NULL,NULL} //Sentinel
364 };
365
366 PyAttributeDef SCA_ISensor::Attributes[] = {
367         KX_PYATTRIBUTE_BOOL_RW("usePosPulseMode",SCA_ISensor,m_pos_pulsemode),
368         KX_PYATTRIBUTE_BOOL_RW("useNegPulseMode",SCA_ISensor,m_neg_pulsemode),
369         KX_PYATTRIBUTE_INT_RW("frequency",0,100000,true,SCA_ISensor,m_pulse_frequency),
370         KX_PYATTRIBUTE_BOOL_RW("invert",SCA_ISensor,m_invert),
371         KX_PYATTRIBUTE_BOOL_RW_CHECK("level",SCA_ISensor,m_level,pyattr_check_level),
372         KX_PYATTRIBUTE_BOOL_RW_CHECK("tap",SCA_ISensor,m_tap,pyattr_check_tap),
373         KX_PYATTRIBUTE_RO_FUNCTION("triggered", SCA_ISensor, pyattr_get_triggered),
374         KX_PYATTRIBUTE_RO_FUNCTION("positive", SCA_ISensor, pyattr_get_positive),
375         KX_PYATTRIBUTE_RO_FUNCTION("status", SCA_ISensor, pyattr_get_status),
376         KX_PYATTRIBUTE_RO_FUNCTION("pos_ticks", SCA_ISensor, pyattr_get_posTicks),
377         KX_PYATTRIBUTE_RO_FUNCTION("neg_ticks", SCA_ISensor, pyattr_get_negTicks),
378         { NULL }        //Sentinel
379 };
380
381
382 PyObject* SCA_ISensor::pyattr_get_triggered(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
383 {
384         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
385         int retval = 0;
386         if (SCA_PythonController::m_sCurrentController)
387                 retval = SCA_PythonController::m_sCurrentController->IsTriggered(self);
388         return PyLong_FromSsize_t(retval);
389 }
390
391 PyObject* SCA_ISensor::pyattr_get_positive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
392 {
393         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
394         return PyLong_FromSsize_t(self->GetState());
395 }
396
397 PyObject* SCA_ISensor::pyattr_get_status(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
398 {
399         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
400         int status = 0;
401         if (self->GetState()) 
402         {
403                 if (self->GetState() == self->GetPrevState()) 
404                 {
405                         status = 2;
406                 }
407                 else 
408                 {
409                         status = 1;
410                 }
411         }
412         else if (self->GetState() != self->GetPrevState()) 
413         {
414                 status = 3;
415         }
416         return PyLong_FromSsize_t(status);
417 }
418
419 PyObject* SCA_ISensor::pyattr_get_posTicks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
420 {
421         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
422         return PyLong_FromLong(self->GetPosTicks());
423 }
424
425 PyObject* SCA_ISensor::pyattr_get_negTicks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
426 {
427         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
428         return PyLong_FromLong(self->GetNegTicks());
429 }
430
431 int SCA_ISensor::pyattr_check_level(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
432 {
433         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
434         if (self->m_level)
435                 self->m_tap = false;
436         return 0;
437 }
438
439 int SCA_ISensor::pyattr_check_tap(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
440 {
441         SCA_ISensor* self= static_cast<SCA_ISensor*>(self_v);
442         if (self->m_tap)
443                 self->m_level = false;
444         return 0;
445 }
446 #endif // WITH_PYTHON
447
448 /* eof */