Initial revision
[blender.git] / source / gameengine / GameLogic / SCA_PropertySensor.cpp
1 /**
2  * Property sensor
3  *
4  * $Id$
5  *
6  * ***** BEGIN GPL/BL DUAL 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. The Blender
12  * Foundation also sells licenses for use in proprietary software under
13  * the Blender License.  See http://www.blender.org/BL/ for information
14  * about this.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  *
25  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
26  * All rights reserved.
27  *
28  * The Original Code is: all of this file.
29  *
30  * Contributor(s): none yet.
31  *
32  * ***** END GPL/BL DUAL LICENSE BLOCK *****
33  */
34
35 #include <iostream>
36 #include "SCA_PropertySensor.h"
37 #include "Operator2Expr.h"
38 #include "ConstExpr.h"
39 #include "InputParser.h"
40 #include "StringValue.h"
41 #include "SCA_EventManager.h"
42 #include "SCA_LogicManager.h"
43
44 SCA_PropertySensor::SCA_PropertySensor(SCA_EventManager* eventmgr,
45                                                                          SCA_IObject* gameobj,
46                                                                          const STR_String& propname,
47                                                                          const STR_String& propval,
48                                                                          const STR_String& propmaxval,
49                                                                          KX_PROPSENSOR_TYPE checktype,
50                                                                          PyTypeObject* T )
51         : SCA_ISensor(gameobj,eventmgr,T),
52           m_checkpropname(propname),
53           m_checkpropval(propval),
54           m_checkpropmaxval(propmaxval),
55           m_checktype(checktype),
56           m_range_expr(NULL),
57           m_lastresult(false)
58 {
59         m_recentresult=false;
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)
66         {
67                 m_previoustext = orgprop->GetText();
68                 orgprop->Release();
69         }
70
71         if (m_checktype==KX_PROPSENSOR_INTERVAL)
72         {
73                 PrecalculateRangeExpression();
74         }
75
76 }
77
78 void SCA_PropertySensor::PrecalculateRangeExpression()
79 {
80                 CParser pars;
81                 pars.SetContext(this->AddRef());
82                 STR_String checkstr = "(" + m_checkpropval + " <= " 
83                                                         + m_checkpropname + ") && ( " 
84                                                         + m_checkpropname + " <= " 
85                                                         + m_checkpropmaxval;
86
87                 m_range_expr = pars.ProcessText(checkstr);
88 }
89
90
91
92 CValue* SCA_PropertySensor::GetReplica()
93 {
94         SCA_PropertySensor* replica = new SCA_PropertySensor(*this);
95         // m_range_expr must be recalculated on replica!
96         CValue::AddDataToReplica(replica);
97
98         replica->m_range_expr = NULL;
99         if (replica->m_checktype==KX_PROPSENSOR_INTERVAL)
100         {
101                 replica->PrecalculateRangeExpression();
102         }
103         
104         
105         return replica;
106 }
107
108
109
110 bool SCA_PropertySensor::IsPositiveTrigger()
111 {
112         bool result = m_recentresult;//CheckPropertyCondition();
113         if (m_invert)
114                 result = !result;
115
116         return result;
117 }
118
119
120
121 SCA_PropertySensor::~SCA_PropertySensor()
122 {
123         //if (m_rightexpr)
124         //      m_rightexpr->Release();
125
126         if (m_range_expr)
127         {
128                 m_range_expr->Release();
129                 m_range_expr=NULL;
130         }
131
132 }
133
134
135
136 bool SCA_PropertySensor::Evaluate(CValue* event)
137 {
138         bool result = CheckPropertyCondition();
139         
140         if (m_lastresult!=result)
141         {
142                 m_lastresult = result;
143                 return true;
144         }
145
146         return false;
147 }
148
149
150 bool    SCA_PropertySensor::CheckPropertyCondition()
151 {
152
153         m_recentresult=false;
154         bool result=false;
155         bool reverse = false;
156         switch (m_checktype)
157         {
158         case KX_PROPSENSOR_NOTEQUAL:
159                 reverse = true;
160         case KX_PROPSENSOR_EQUAL:
161                 {
162                         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
163                         if (orgprop)
164                         {
165                                 STR_String testprop = orgprop->GetText();
166                                 // Force strings to upper case, to avoid confusion in
167                                 // bool tests. It's stupid the prop's identity is lost
168                                 // on the way here...
169                                 if ((testprop == "TRUE") || (testprop == "FALSE")) {
170                                         STR_String checkprop = m_checkpropval;
171                                         checkprop.Upper();
172                                         result = (testprop == checkprop);
173                                 } else {
174                                         result = (orgprop->GetText() == m_checkpropval);
175                                 }
176                                 orgprop->Release();
177
178                         }
179
180                         if (reverse)
181                                 result = !result;
182                         break;
183
184                 }
185
186         case KX_PROPSENSOR_EXPRESSION:
187                 {
188                         /*
189                         if (m_rightexpr)
190                         {
191                                 CValue* resultval = m_rightexpr->Calculate();
192                                 if (resultval->IsError())
193                                 {
194                                         int i=0;
195                                         STR_String errortest = resultval->GetText();
196                                         printf(errortest);
197
198                                 } else
199                                 {
200                                         result = resultval->GetNumber() != 0;
201                                 }
202                         }
203                         */
204                         break;
205                 }
206         case KX_PROPSENSOR_INTERVAL:
207                 {
208                         //CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
209                         //if (orgprop)
210                         //{
211                                 if (m_range_expr)
212                                 {
213                                         CValue* vallie = m_range_expr->Calculate();
214                                         if (vallie)
215                                         {
216                                                 STR_String errtext = vallie->GetText();
217                                                 if (errtext == "TRUE")
218                                                 {
219                                                         result = true;
220                                                 } else
221                                                 {
222                                                         if (vallie->IsError())
223                                                         {
224                                                                 //printf (errtext.ReadPtr());
225                                                         } 
226                                                 }
227                                                 
228                                                 vallie->Release();
229                                         }
230                                 }
231
232                                 
233                         //}
234                         
235                 //cout << " \nSens:Prop:interval!"; /* need implementation here!!! */
236
237                 break;
238                 }
239         case KX_PROPSENSOR_CHANGED:
240                 {
241                         CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
242                                 
243                         if (orgprop)
244                         {
245                                 if (m_previoustext != orgprop->GetText())
246                                 {
247                                         m_previoustext = orgprop->GetText();
248                                         result = true;
249                                 }
250                                 orgprop->Release();
251                         }
252
253                         //cout << " \nSens:Prop:changed!"; /* need implementation here!!! */
254                         break;
255                 }
256         default:
257                 ; /* error */
258         }
259         m_recentresult=result;
260         return result;
261 }
262
263 CValue* SCA_PropertySensor::FindIdentifier(const STR_String& identifiername)
264 {
265         return  GetParent()->FindIdentifier(identifiername);
266 }
267
268 bool SCA_PropertySensor::validValueForProperty(char *val, STR_String &prop)
269 {
270         bool result = true;
271         /*  There is no type checking at this moment, unfortunately...           */
272         return result;
273 }
274
275 /* ------------------------------------------------------------------------- */
276 /* Python functions                                                          */
277 /* ------------------------------------------------------------------------- */
278
279 /* Integration hooks ------------------------------------------------------- */
280 PyTypeObject SCA_PropertySensor::Type = {
281         PyObject_HEAD_INIT(&PyType_Type)
282         0,
283         "SCA_PropertySensor",
284         sizeof(SCA_PropertySensor),
285         0,
286         PyDestructor,
287         0,
288         __getattr,
289         __setattr,
290         0, //&MyPyCompare,
291         __repr,
292         0, //&cvalue_as_number,
293         0,
294         0,
295         0,
296         0
297 };
298
299 PyParentObject SCA_PropertySensor::Parents[] = {
300         &SCA_PropertySensor::Type,
301         &SCA_ISensor::Type,
302         &SCA_ILogicBrick::Type,
303         &CValue::Type,
304         NULL
305 };
306
307 PyMethodDef SCA_PropertySensor::Methods[] = {
308         {"getType", (PyCFunction) SCA_PropertySensor::sPyGetType, METH_VARARGS, GetType_doc},
309         {"setType", (PyCFunction) SCA_PropertySensor::sPySetType, METH_VARARGS, SetType_doc},
310         {"getProperty", (PyCFunction) SCA_PropertySensor::sPyGetProperty, METH_VARARGS, GetProperty_doc},
311         {"setProperty", (PyCFunction) SCA_PropertySensor::sPySetProperty, METH_VARARGS, SetProperty_doc},
312         {"getValue", (PyCFunction) SCA_PropertySensor::sPyGetValue, METH_VARARGS, GetValue_doc},
313         {"setValue", (PyCFunction) SCA_PropertySensor::sPySetValue, METH_VARARGS, SetValue_doc},
314         {NULL,NULL} //Sentinel
315 };
316
317 PyObject* SCA_PropertySensor::_getattr(char* attr) {
318         _getattr_up(SCA_ISensor); /* implicit return! */
319 }
320
321 /* 1. getType */
322 char SCA_PropertySensor::GetType_doc[] = 
323 "getType()\n"
324 "\tReturns the type of check this sensor performs.\n";
325 PyObject* SCA_PropertySensor::PyGetType(PyObject* self, PyObject* args, PyObject* kwds)
326 {
327         return PyInt_FromLong(m_checktype);
328 }
329
330 /* 2. setType */
331 char SCA_PropertySensor::SetType_doc[] = 
332 "setType(type)\n"
333 "\t- type: KX_PROPSENSOR_EQUAL, KX_PROPSENSOR_NOTEQUAL,\n"
334 "\t        KX_PROPSENSOR_INTERVAL, KX_PROPSENSOR_CHANGED,\n"
335 "\t        or KX_PROPSENSOR_EXPRESSION.\n"
336 "\tSet the type of check to perform.\n";
337 PyObject* SCA_PropertySensor::PySetType(PyObject* self, PyObject* args, PyObject* kwds) 
338 {
339         int typeArg;
340         
341         if (!PyArg_ParseTuple(args, "i", &typeArg)) {
342                 return NULL;
343         }
344         
345         if ( (typeArg > KX_PROPSENSOR_NODEF) 
346                  && (typeArg < KX_PROPSENSOR_MAX) ) {
347                 m_checktype =  typeArg;
348         }
349         
350         Py_Return;
351 }
352
353 /* 3. getProperty */
354 char SCA_PropertySensor::GetProperty_doc[] = 
355 "getProperty()\n"
356 "\tReturn the property with which the sensor operates.\n";
357 PyObject* SCA_PropertySensor::PyGetProperty(PyObject* self, PyObject* args, PyObject* kwds) 
358 {
359         return PyString_FromString(m_checkpropname);
360 }
361
362 /* 4. setProperty */
363 char SCA_PropertySensor::SetProperty_doc[] = 
364 "setProperty(name)\n"
365 "\t- name: string\n"
366 "\tSets the property with which to operate. If there is no property\n"
367 "\tof this name, the call is ignored.\n";
368 PyObject* SCA_PropertySensor::PySetProperty(PyObject* self, PyObject* args, PyObject* kwds) 
369 {
370         /* We should query whether the name exists. Or should we create a prop   */
371         /* on the fly?                                                           */
372         char *propNameArg = NULL;
373
374         if (!PyArg_ParseTuple(args, "s", &propNameArg)) {
375                 return NULL;
376         }
377
378         if (FindIdentifier(STR_String(propNameArg))) {
379                 m_checkpropname = propNameArg;
380         } else {
381                 ; /* error: bad property name */
382         }
383
384         Py_Return;
385 }
386
387 /* 5. getValue */
388 char SCA_PropertySensor::GetValue_doc[] = 
389 "getValue()\n"
390 "\tReturns the value with which the sensor operates.\n";
391 PyObject* SCA_PropertySensor::PyGetValue(PyObject* self, PyObject* args, PyObject* kwds) 
392 {
393         return PyString_FromString(m_checkpropval);
394 }
395
396 /* 6. setValue */
397 char SCA_PropertySensor::SetValue_doc[] = 
398 "setValue(value)\n"
399 "\t- value: string\n"
400 "\tSet the value with which the sensor operates. If the value\n"
401 "\tis not compatible with the type of the property, the subsequent\n"
402 "\t action is ignored.\n";
403 PyObject* SCA_PropertySensor::PySetValue(PyObject* self, PyObject* args, PyObject* kwds) 
404 {
405         /* Here, we need to check whether the value is 'valid' for this property.*/
406         /* We know that the property exists, or is NULL.                         */
407         char *propValArg = NULL;
408
409         if(!PyArg_ParseTuple(args, "s", &propValArg)) {
410                 return NULL;
411         }
412
413         if (validValueForProperty(propValArg, m_checkpropname)) {
414                 m_checkpropval = propValArg;
415         }       
416
417         Py_Return;
418 }
419
420 /* eof */