BGE patch: add state engine support in the logic bricks.
[blender.git] / source / gameengine / GameLogic / SCA_PropertySensor.cpp
1 /**
2  * Property sensor
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 <iostream>
33 #include "SCA_PropertySensor.h"
34 #include "Operator2Expr.h"
35 #include "ConstExpr.h"
36 #include "InputParser.h"
37 #include "StringValue.h"
38 #include "SCA_EventManager.h"
39 #include "SCA_LogicManager.h"
40
41 #ifdef HAVE_CONFIG_H
42 #include <config.h>
43 #endif
44
45 SCA_PropertySensor::SCA_PropertySensor(SCA_EventManager* eventmgr,
46                                                                          SCA_IObject* gameobj,
47                                                                          const STR_String& propname,
48                                                                          const STR_String& propval,
49                                                                          const STR_String& propmaxval,
50                                                                          KX_PROPSENSOR_TYPE checktype,
51                                                                          PyTypeObject* T )
52         : SCA_ISensor(gameobj,eventmgr,T),
53           m_checktype(checktype),
54           m_checkpropval(propval),
55           m_checkpropmaxval(propmaxval),
56           m_checkpropname(propname),
57           m_lastresult(false),
58           m_range_expr(NULL)
59 {
60         //CParser pars;
61         //pars.SetContext(this->AddRef());
62         //CValue* resultval = m_rightexpr->Calculate();
63
64         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
65         if (!orgprop->IsError())
66         {
67                 m_previoustext = orgprop->GetText();
68         }
69         orgprop->Release();
70
71         if (m_checktype==KX_PROPSENSOR_INTERVAL)
72         {
73                 PrecalculateRangeExpression();
74         }
75         Init();
76 }
77
78 void SCA_PropertySensor::Init()
79 {
80         m_recentresult = false;
81 }
82
83 void SCA_PropertySensor::PrecalculateRangeExpression()
84 {
85                 CParser pars;
86                 //The context is needed to retrieve the property at runtime but it creates
87                 //loop of references
88                 pars.SetContext(this->AddRef());
89                 STR_String checkstr = "(" + m_checkpropval + " <= " 
90                                                         + m_checkpropname + ") && ( " 
91                                                         + m_checkpropname + " <= " 
92                                                         + m_checkpropmaxval + ")";
93
94                 m_range_expr = pars.ProcessText(checkstr);
95 }
96
97 // Forced deletion of precalculated range expression to break reference loop
98 // Use this function when you know that you won't use the sensor anymore
99 void SCA_PropertySensor::Delete()
100 {
101         if (m_range_expr)
102         {
103                 m_range_expr->Release();
104                 m_range_expr = NULL;
105         }
106         Release();
107 }
108
109 CValue* SCA_PropertySensor::GetReplica()
110 {
111         SCA_PropertySensor* replica = new SCA_PropertySensor(*this);
112         // m_range_expr must be recalculated on replica!
113         CValue::AddDataToReplica(replica);
114
115         replica->m_range_expr = NULL;
116         if (replica->m_checktype==KX_PROPSENSOR_INTERVAL)
117         {
118                 replica->PrecalculateRangeExpression();
119         }
120         
121         
122         return replica;
123 }
124
125
126
127 bool SCA_PropertySensor::IsPositiveTrigger()
128 {
129         bool result = m_recentresult;//CheckPropertyCondition();
130         if (m_invert)
131                 result = !result;
132
133         return result;
134 }
135
136
137
138 SCA_PropertySensor::~SCA_PropertySensor()
139 {
140         //if (m_rightexpr)
141         //      m_rightexpr->Release();
142
143         if (m_range_expr)
144         {
145                 m_range_expr->Release();
146                 m_range_expr=NULL;
147         }
148
149 }
150
151
152
153 bool SCA_PropertySensor::Evaluate(CValue* event)
154 {
155         bool result = CheckPropertyCondition();
156         
157         if (m_lastresult!=result)
158         {
159                 m_lastresult = result;
160                 return true;
161         }
162
163         return false;
164 }
165
166
167 bool    SCA_PropertySensor::CheckPropertyCondition()
168 {
169
170         m_recentresult=false;
171         bool result=false;
172         bool reverse = false;
173         switch (m_checktype)
174         {
175         case KX_PROPSENSOR_NOTEQUAL:
176                 reverse = true;
177         case KX_PROPSENSOR_EQUAL:
178                 {
179                         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
180                         if (!orgprop->IsError())
181                         {
182                                 STR_String testprop = orgprop->GetText();
183                                 // Force strings to upper case, to avoid confusion in
184                                 // bool tests. It's stupid the prop's identity is lost
185                                 // on the way here...
186                                 if ((testprop == "TRUE") || (testprop == "FALSE")) {
187                                         STR_String checkprop = m_checkpropval;
188                                         checkprop.Upper();
189                                         result = (testprop == checkprop);
190                                 } else {
191                                         result = (orgprop->GetText() == m_checkpropval);
192                                 }
193                         }
194                         orgprop->Release();
195
196                         if (reverse)
197                                 result = !result;
198                         break;
199
200                 }
201
202         case KX_PROPSENSOR_EXPRESSION:
203                 {
204                         /*
205                         if (m_rightexpr)
206                         {
207                                 CValue* resultval = m_rightexpr->Calculate();
208                                 if (resultval->IsError())
209                                 {
210                                         int i=0;
211                                         STR_String errortest = resultval->GetText();
212                                         printf(errortest);
213
214                                 } else
215                                 {
216                                         result = resultval->GetNumber() != 0;
217                                 }
218                         }
219                         */
220                         break;
221                 }
222         case KX_PROPSENSOR_INTERVAL:
223                 {
224                         //CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
225                         //if (orgprop)
226                         //{
227                                 if (m_range_expr)
228                                 {
229                                         CValue* vallie = m_range_expr->Calculate();
230                                         if (vallie)
231                                         {
232                                                 STR_String errtext = vallie->GetText();
233                                                 if (errtext == "TRUE")
234                                                 {
235                                                         result = true;
236                                                 } else
237                                                 {
238                                                         if (vallie->IsError())
239                                                         {
240                                                                 //printf (errtext.ReadPtr());
241                                                         } 
242                                                 }
243                                                 
244                                                 vallie->Release();
245                                         }
246                                 }
247
248                                 
249                         //}
250                         
251                 //cout << " \nSens:Prop:interval!"; /* need implementation here!!! */
252
253                 break;
254                 }
255         case KX_PROPSENSOR_CHANGED:
256                 {
257                         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
258                                 
259                         if (!orgprop->IsError())
260                         {
261                                 if (m_previoustext != orgprop->GetText())
262                                 {
263                                         m_previoustext = orgprop->GetText();
264                                         result = true;
265                                 }
266                         }
267                         orgprop->Release();
268
269                         //cout << " \nSens:Prop:changed!"; /* need implementation here!!! */
270                         break;
271                 }
272         default:
273                 ; /* error */
274         }
275
276         //the concept of Edge and Level triggering has unwanted effect for KX_PROPSENSOR_CHANGED
277         //see Game Engine bugtracker [ #3809 ]
278         if (m_checktype != KX_PROPSENSOR_CHANGED)
279         {
280                 m_recentresult=result;
281         } else
282         {
283                 m_recentresult=result;//true;
284         }
285         return result;
286 }
287
288 CValue* SCA_PropertySensor::FindIdentifier(const STR_String& identifiername)
289 {
290         return  GetParent()->FindIdentifier(identifiername);
291 }
292
293 bool SCA_PropertySensor::validValueForProperty(char *val, STR_String &prop)
294 {
295         bool result = true;
296         /*  There is no type checking at this moment, unfortunately...           */
297         return result;
298 }
299
300 /* ------------------------------------------------------------------------- */
301 /* Python functions                                                          */
302 /* ------------------------------------------------------------------------- */
303
304 /* Integration hooks ------------------------------------------------------- */
305 PyTypeObject SCA_PropertySensor::Type = {
306         PyObject_HEAD_INIT(&PyType_Type)
307         0,
308         "SCA_PropertySensor",
309         sizeof(SCA_PropertySensor),
310         0,
311         PyDestructor,
312         0,
313         __getattr,
314         __setattr,
315         0, //&MyPyCompare,
316         __repr,
317         0, //&cvalue_as_number,
318         0,
319         0,
320         0,
321         0
322 };
323
324 PyParentObject SCA_PropertySensor::Parents[] = {
325         &SCA_PropertySensor::Type,
326         &SCA_ISensor::Type,
327         &SCA_ILogicBrick::Type,
328         &CValue::Type,
329         NULL
330 };
331
332 PyMethodDef SCA_PropertySensor::Methods[] = {
333         {"getType", (PyCFunction) SCA_PropertySensor::sPyGetType, METH_VARARGS, GetType_doc},
334         {"setType", (PyCFunction) SCA_PropertySensor::sPySetType, METH_VARARGS, SetType_doc},
335         {"getProperty", (PyCFunction) SCA_PropertySensor::sPyGetProperty, METH_VARARGS, GetProperty_doc},
336         {"setProperty", (PyCFunction) SCA_PropertySensor::sPySetProperty, METH_VARARGS, SetProperty_doc},
337         {"getValue", (PyCFunction) SCA_PropertySensor::sPyGetValue, METH_VARARGS, GetValue_doc},
338         {"setValue", (PyCFunction) SCA_PropertySensor::sPySetValue, METH_VARARGS, SetValue_doc},
339         {NULL,NULL} //Sentinel
340 };
341
342 PyObject* SCA_PropertySensor::_getattr(const STR_String& attr) {
343         _getattr_up(SCA_ISensor); /* implicit return! */
344 }
345
346 /* 1. getType */
347 char SCA_PropertySensor::GetType_doc[] = 
348 "getType()\n"
349 "\tReturns the type of check this sensor performs.\n";
350 PyObject* SCA_PropertySensor::PyGetType(PyObject* self, PyObject* args, PyObject* kwds)
351 {
352         return PyInt_FromLong(m_checktype);
353 }
354
355 /* 2. setType */
356 char SCA_PropertySensor::SetType_doc[] = 
357 "setType(type)\n"
358 "\t- type: KX_PROPSENSOR_EQUAL, KX_PROPSENSOR_NOTEQUAL,\n"
359 "\t        KX_PROPSENSOR_INTERVAL, KX_PROPSENSOR_CHANGED,\n"
360 "\t        or KX_PROPSENSOR_EXPRESSION.\n"
361 "\tSet the type of check to perform.\n";
362 PyObject* SCA_PropertySensor::PySetType(PyObject* self, PyObject* args, PyObject* kwds) 
363 {
364         int typeArg;
365         
366         if (!PyArg_ParseTuple(args, "i", &typeArg)) {
367                 return NULL;
368         }
369         
370         if ( (typeArg > KX_PROPSENSOR_NODEF) 
371                  && (typeArg < KX_PROPSENSOR_MAX) ) {
372                 m_checktype =  typeArg;
373         }
374         
375         Py_Return;
376 }
377
378 /* 3. getProperty */
379 char SCA_PropertySensor::GetProperty_doc[] = 
380 "getProperty()\n"
381 "\tReturn the property with which the sensor operates.\n";
382 PyObject* SCA_PropertySensor::PyGetProperty(PyObject* self, PyObject* args, PyObject* kwds) 
383 {
384         return PyString_FromString(m_checkpropname);
385 }
386
387 /* 4. setProperty */
388 char SCA_PropertySensor::SetProperty_doc[] = 
389 "setProperty(name)\n"
390 "\t- name: string\n"
391 "\tSets the property with which to operate. If there is no property\n"
392 "\tof this name, the call is ignored.\n";
393 PyObject* SCA_PropertySensor::PySetProperty(PyObject* self, PyObject* args, PyObject* kwds) 
394 {
395         /* We should query whether the name exists. Or should we create a prop   */
396         /* on the fly?                                                           */
397         char *propNameArg = NULL;
398
399         if (!PyArg_ParseTuple(args, "s", &propNameArg)) {
400                 return NULL;
401         }
402
403         CValue *prop = FindIdentifier(STR_String(propNameArg));
404         if (!prop->IsError()) {
405                 m_checkpropname = propNameArg;
406         } else {
407                 ; /* error: bad property name */
408         }
409         prop->Release();
410         Py_Return;
411 }
412
413 /* 5. getValue */
414 char SCA_PropertySensor::GetValue_doc[] = 
415 "getValue()\n"
416 "\tReturns the value with which the sensor operates.\n";
417 PyObject* SCA_PropertySensor::PyGetValue(PyObject* self, PyObject* args, PyObject* kwds) 
418 {
419         return PyString_FromString(m_checkpropval);
420 }
421
422 /* 6. setValue */
423 char SCA_PropertySensor::SetValue_doc[] = 
424 "setValue(value)\n"
425 "\t- value: string\n"
426 "\tSet the value with which the sensor operates. If the value\n"
427 "\tis not compatible with the type of the property, the subsequent\n"
428 "\t action is ignored.\n";
429 PyObject* SCA_PropertySensor::PySetValue(PyObject* self, PyObject* args, PyObject* kwds) 
430 {
431         /* Here, we need to check whether the value is 'valid' for this property.*/
432         /* We know that the property exists, or is NULL.                         */
433         char *propValArg = NULL;
434
435         if(!PyArg_ParseTuple(args, "s", &propValArg)) {
436                 return NULL;
437         }
438
439         if (validValueForProperty(propValArg, m_checkpropname)) {
440                 m_checkpropval = propValArg;
441         }       
442
443         Py_Return;
444 }
445
446 /* eof */