BGE patch: add state engine support in the logic bricks.
[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
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 /* Native functions */
41 void    SCA_ISensor::ReParent(SCA_IObject* parent)
42 {
43         SCA_ILogicBrick::ReParent(parent);
44         m_eventmgr->RegisterSensor(this);
45         this->SetActive(false);
46 }
47
48
49 SCA_ISensor::SCA_ISensor(SCA_IObject* gameobj,
50                                                  class SCA_EventManager* eventmgr,
51                                                  PyTypeObject* T ) :
52         SCA_ILogicBrick(gameobj,T),
53         m_triggered(false)
54 {
55         m_links = 0;
56         m_suspended = false;
57         m_invert = false;
58         m_pos_ticks = 0;
59         m_neg_ticks = 0;
60         m_pos_pulsemode = false;
61         m_neg_pulsemode = false;
62         m_pulse_frequency = 0;
63         
64         m_eventmgr = eventmgr;
65 }
66
67
68 SCA_ISensor::~SCA_ISensor()  
69 {
70         // intentionally empty
71 }
72
73 bool SCA_ISensor::IsPositiveTrigger() { 
74         bool result = false;
75         
76         if (m_eventval) {
77                 result = (m_eventval->GetNumber() != 0.0);
78         }
79         if (m_invert) {
80                 result = !result;
81         }
82         
83         return result;
84 }
85
86 void SCA_ISensor::SetPulseMode(bool posmode, 
87                                                            bool negmode,
88                                                            int freq) {
89         m_pos_pulsemode = posmode;
90         m_neg_pulsemode = negmode;
91         m_pulse_frequency = freq;
92 }
93
94 void SCA_ISensor::SetInvert(bool inv) {
95         m_invert = inv;
96 }
97
98
99 float SCA_ISensor::GetNumber() {
100         return IsPositiveTrigger();
101 }
102
103 void SCA_ISensor::Suspend() {
104         m_suspended = true;
105 }
106
107 bool SCA_ISensor::IsSuspended() {
108         return m_suspended;
109 }
110
111 void SCA_ISensor::Resume() {
112         m_suspended = false;
113 }
114
115 void SCA_ISensor::Init() {
116         printf("Sensor %s has no init function, please report this bug to Blender.org\n", m_name);
117 }
118
119 void SCA_ISensor::DecLink() {
120         m_links--;
121         if (m_links < 0) 
122         {
123                 printf("Warning: sensor %s has negative m_links: %d\n", m_name.Ptr(), m_links);
124                 m_links = 0;
125         }
126         if (!m_links)
127         {
128                 // sensor is detached from all controllers, initialize it so that it
129                 // is fresh as at startup when it is reattached again.
130                 Init();
131         }
132 }
133
134 /* python integration */
135
136 PyTypeObject SCA_ISensor::Type = {
137         PyObject_HEAD_INIT(&PyType_Type)
138         0,
139         "SCA_ISensor",
140         sizeof(SCA_ISensor),
141         0,
142         PyDestructor,
143         0,
144         __getattr,
145         __setattr,
146         0, //&MyPyCompare,
147         __repr,
148         0, //&cvalue_as_number,
149         0,
150         0,
151         0,
152         0
153 };
154
155 PyParentObject SCA_ISensor::Parents[] = {
156         &SCA_ISensor::Type,
157         &SCA_ILogicBrick::Type,
158         &CValue::Type,
159         NULL
160 };
161 PyMethodDef SCA_ISensor::Methods[] = {
162         {"isPositive", (PyCFunction) SCA_ISensor::sPyIsPositive, 
163          METH_VARARGS, IsPositive_doc},
164         {"getUsePosPulseMode", (PyCFunction) SCA_ISensor::sPyGetUsePosPulseMode, 
165          METH_VARARGS, GetUsePosPulseMode_doc},
166         {"setUsePosPulseMode", (PyCFunction) SCA_ISensor::sPySetUsePosPulseMode, 
167          METH_VARARGS, SetUsePosPulseMode_doc},
168         {"getFrequency", (PyCFunction) SCA_ISensor::sPyGetFrequency, 
169          METH_VARARGS, GetFrequency_doc},
170         {"setFrequency", (PyCFunction) SCA_ISensor::sPySetFrequency, 
171          METH_VARARGS, SetFrequency_doc},
172         {"getUseNegPulseMode", (PyCFunction) SCA_ISensor::sPyGetUseNegPulseMode, 
173          METH_VARARGS, GetUseNegPulseMode_doc},
174         {"setUseNegPulseMode", (PyCFunction) SCA_ISensor::sPySetUseNegPulseMode, 
175          METH_VARARGS, SetUseNegPulseMode_doc},
176         {"getInvert", (PyCFunction) SCA_ISensor::sPyGetInvert, 
177          METH_VARARGS, GetInvert_doc},
178         {"setInvert", (PyCFunction) SCA_ISensor::sPySetInvert, 
179          METH_VARARGS, SetInvert_doc},
180         {NULL,NULL} //Sentinel
181 };
182
183
184 PyObject*
185 SCA_ISensor::_getattr(const STR_String& attr)
186 {
187   _getattr_up(SCA_ILogicBrick);
188 }
189
190
191 void SCA_ISensor::RegisterToManager()
192 {
193         m_eventmgr->RegisterSensor(this);
194 }
195
196 void SCA_ISensor::Activate(class SCA_LogicManager* logicmgr,      CValue* event)
197 {
198         
199         // calculate if a __triggering__ is wanted
200         // don't evaluate a sensor that is not connected to any controller
201         if (m_links && !m_suspended) {
202                 bool result = this->Evaluate(event);
203                 if (result) {
204                         logicmgr->AddActivatedSensor(this);     
205                 } else
206                 {
207                         /* First, the pulsing behaviour, if pulse mode is
208                          * active. It seems something goes wrong if pulse mode is
209                          * not set :( */
210                         if (m_pos_pulsemode) {
211                                 m_pos_ticks++;
212                                 if (m_pos_ticks > m_pulse_frequency) {
213                                         if ( this->IsPositiveTrigger() )
214                                         {
215                                                 logicmgr->AddActivatedSensor(this);
216                                         }
217                                         m_pos_ticks = 0;
218                                 } 
219                         }
220                         
221                         if (m_neg_pulsemode)
222                         {
223                                 m_neg_ticks++;
224                                 if (m_neg_ticks > m_pulse_frequency) {
225                                         if (!this->IsPositiveTrigger() )
226                                         {
227                                                 logicmgr->AddActivatedSensor(this);
228                                         }
229                                         m_neg_ticks = 0;
230                                 }
231                         }
232                 }
233         } 
234 }
235
236 /* Python functions: */
237 char SCA_ISensor::IsPositive_doc[] = 
238 "isPositive()\n"
239 "\tReturns whether the sensor is registered a positive event.\n";
240 PyObject* SCA_ISensor::PyIsPositive(PyObject* self, PyObject* args, PyObject* kwds)
241 {
242         int retval = IsPositiveTrigger();
243         return PyInt_FromLong(retval);
244 }
245
246 /**
247  * getUsePulseMode: getter for the pulse mode (KX_TRUE = on)
248  */
249 char SCA_ISensor::GetUsePosPulseMode_doc[] = 
250 "getUsePosPulseMode()\n"
251 "\tReturns whether positive pulse mode is active.\n";
252 PyObject* SCA_ISensor::PyGetUsePosPulseMode(PyObject* self, PyObject* args, PyObject* kwds)
253 {
254         return BoolToPyArg(m_pos_pulsemode);
255 }
256
257 /**
258  * setUsePulseMode: setter for the pulse mode (KX_TRUE = on)
259  */
260 char SCA_ISensor::SetUsePosPulseMode_doc[] = 
261 "setUsePosPulseMode(pulse?)\n"
262 "\t - pulse? : Pulse when a positive event occurs?\n"
263 "\t            (KX_TRUE, KX_FALSE)\n"
264 "\tSet whether to do pulsing when positive pulses occur.\n";
265 PyObject* SCA_ISensor::PySetUsePosPulseMode(PyObject* self, PyObject* args, PyObject* kwds)
266 {
267         int pyarg = 0;
268         if(!PyArg_ParseTuple(args, "i", &pyarg)) { return NULL; }
269         m_pos_pulsemode = PyArgToBool(pyarg);
270         Py_Return;
271 }
272
273 /**
274  * getFrequency: getter for the pulse mode interval
275  */
276 char SCA_ISensor::GetFrequency_doc[] = 
277 "getFrequency()\n"
278 "\tReturns the frequency of the updates in pulse mode.\n" ;
279 PyObject* SCA_ISensor::PyGetFrequency(PyObject* self, PyObject* args, PyObject* kwds)
280 {
281         return PyInt_FromLong(m_pulse_frequency);
282 }
283
284 /**
285  * setFrequency: setter for the pulse mode (KX_TRUE = on)
286  */
287 char SCA_ISensor::SetFrequency_doc[] = 
288 "setFrequency(pulse_frequency)\n"
289 "\t- pulse_frequency: The frequency of the updates in pulse mode (integer)"
290 "\tSet the frequency of the updates in pulse mode.\n"
291 "\tIf the frequency is negative, it is set to 0.\n" ;
292 PyObject* SCA_ISensor::PySetFrequency(PyObject* self, PyObject* args, PyObject* kwds)
293 {
294         int pulse_frequencyArg = 0;
295
296         if(!PyArg_ParseTuple(args, "i", &pulse_frequencyArg)) {
297                 return NULL;
298         }
299         
300         /* We can do three things here: clip, ignore and raise an exception.  */
301         /* Exceptions don't work yet, ignoring is not desirable now...        */
302         if (pulse_frequencyArg < 0) {
303                 pulse_frequencyArg = 0;
304         };      
305         m_pulse_frequency = pulse_frequencyArg;
306
307         Py_Return;
308 }
309
310
311 char SCA_ISensor::GetInvert_doc[] = 
312 "getInvert()\n"
313 "\tReturns whether or not pulses from this sensor are inverted.\n" ;
314 PyObject* SCA_ISensor::PyGetInvert(PyObject* self, PyObject* args, PyObject* kwds)
315 {
316         return BoolToPyArg(m_invert);
317 }
318
319 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* self, PyObject* args, PyObject* kwds)
324 {
325         int pyarg = 0;
326         if(!PyArg_ParseTuple(args, "i", &pyarg)) { return NULL; }
327         m_invert = PyArgToBool(pyarg);
328         Py_Return;
329 }
330
331 char SCA_ISensor::GetUseNegPulseMode_doc[] = 
332 "getUseNegPulseMode()\n"
333 "\tReturns whether negative pulse mode is active.\n";
334 PyObject* SCA_ISensor::PyGetUseNegPulseMode(PyObject* self, PyObject* args, PyObject* kwds)
335 {
336         return BoolToPyArg(m_neg_pulsemode);
337 }
338
339 char SCA_ISensor::SetUseNegPulseMode_doc[] = 
340 "setUseNegPulseMode(pulse?)\n"
341 "\t - pulse? : Pulse when a negative event occurs?\n"
342 "\t            (KX_TRUE, KX_FALSE)\n"
343 "\tSet whether to do pulsing when negative pulses occur.\n";
344 PyObject* SCA_ISensor::PySetUseNegPulseMode(PyObject* self, PyObject* args, PyObject* kwds)
345 {
346         int pyarg = 0;
347         if(!PyArg_ParseTuple(args, "i", &pyarg)) { return NULL; }
348         m_neg_pulsemode = PyArgToBool(pyarg);
349         Py_Return;
350 }
351
352 /* eof */