ifdef's for future py3 support, after this adding py3 can mostly be done with defines...
[blender.git] / source / gameengine / Ketsji / KX_NearSensor.cpp
1 /**
2  * Sense if other objects are near
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 "KX_NearSensor.h"
33 #include "SCA_LogicManager.h"
34 #include "KX_GameObject.h"
35 #include "KX_TouchEventManager.h"
36 #include "KX_Scene.h" // needed to create a replica
37 #include "PHY_IPhysicsEnvironment.h"
38 #include "PHY_IPhysicsController.h"
39
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43 KX_NearSensor::KX_NearSensor(SCA_EventManager* eventmgr,
44                                                          KX_GameObject* gameobj,
45                                                          float margin,
46                                                          float resetmargin,
47                                                          bool bFindMaterial,
48                                                          const STR_String& touchedpropname,
49                                                          class KX_Scene* scene,
50                                                          PHY_IPhysicsController*        ctrl,
51                                                          PyTypeObject* T)
52                          :KX_TouchSensor(eventmgr,
53                                                          gameobj,
54                                                          bFindMaterial,
55                                                          false,
56                                                          touchedpropname,
57                                                          /* scene, */
58                                                          T),
59                          m_Margin(margin),
60                          m_ResetMargin(resetmargin)
61
62 {
63
64         gameobj->getClientInfo()->m_sensors.remove(this);
65         m_client_info = new KX_ClientObjectInfo(gameobj, KX_ClientObjectInfo::NEAR);
66         m_client_info->m_sensors.push_back(this);
67         
68         //DT_ShapeHandle shape = (DT_ShapeHandle) vshape;
69         m_physCtrl = ctrl;
70         if (m_physCtrl)
71         {
72                 m_physCtrl->SetMargin(m_Margin);
73                 m_physCtrl->setNewClientInfo(m_client_info);
74         }
75         SynchronizeTransform();
76 }
77
78 void KX_NearSensor::SynchronizeTransform()
79 {
80         // The near and radar sensors are using a different physical object which is 
81         // not linked to the parent object, must synchronize it.
82         if (m_physCtrl)
83         {
84                 KX_GameObject* parent = ((KX_GameObject*)GetParent());
85                 MT_Vector3 pos = parent->NodeGetWorldPosition();
86                 MT_Quaternion orn = parent->NodeGetWorldOrientation().getRotation();
87                 m_physCtrl->setPosition(pos.x(),pos.y(),pos.z());
88                 m_physCtrl->setOrientation(orn.x(),orn.y(),orn.z(),orn.w());
89                 m_physCtrl->calcXform();
90         }
91 }
92
93 void KX_NearSensor::RegisterSumo(KX_TouchEventManager *touchman)
94 {
95         if (m_physCtrl)
96         {
97                 touchman->GetPhysicsEnvironment()->addSensor(m_physCtrl);
98         }
99 }
100
101 void KX_NearSensor::UnregisterSumo(KX_TouchEventManager* touchman)
102 {
103         if (m_physCtrl)
104         {
105                 touchman->GetPhysicsEnvironment()->removeSensor(m_physCtrl);
106         }
107 }
108
109 CValue* KX_NearSensor::GetReplica()
110 {
111         KX_NearSensor* replica = new KX_NearSensor(*this);
112         replica->ProcessReplica();
113         return replica;
114 }
115
116 void KX_NearSensor::ProcessReplica()
117 {
118         KX_TouchSensor::ProcessReplica();
119         
120         m_client_info = new KX_ClientObjectInfo(m_client_info->m_gameobject, KX_ClientObjectInfo::NEAR);
121         
122         if (m_physCtrl)
123         {
124                 m_physCtrl = m_physCtrl->GetReplica();
125                 if (m_physCtrl)
126                 {
127                         //static_cast<KX_TouchEventManager*>(m_eventmgr)->GetPhysicsEnvironment()->addSensor(replica->m_physCtrl);
128                         m_physCtrl->SetMargin(m_Margin);
129                         m_physCtrl->setNewClientInfo(m_client_info);
130                 }
131                 
132         }
133 }
134
135 void KX_NearSensor::ReParent(SCA_IObject* parent)
136 {
137         m_client_info->m_gameobject = static_cast<KX_GameObject*>(parent); 
138         m_client_info->m_sensors.push_back(this);
139         //Synchronize here with the actual parent.
140         SynchronizeTransform();
141         SCA_ISensor::ReParent(parent);
142 }
143
144
145
146 KX_NearSensor::~KX_NearSensor()
147 {
148         // for nearsensor, the sensor is the 'owner' of sumoobj
149         // for touchsensor, it's the parent
150         if (m_physCtrl)
151         {
152                 //static_cast<KX_TouchEventManager*>(m_eventmgr)->GetPhysicsEnvironment()->removeSensor(m_physCtrl);
153                 delete m_physCtrl;
154                 m_physCtrl = NULL;
155         }
156         
157                 
158         if (m_client_info)
159                 delete m_client_info;
160 }
161
162
163 bool KX_NearSensor::Evaluate(CValue* event)
164 {
165         bool result = false;
166 //      KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
167
168         if (m_bTriggered != m_bLastTriggered)
169         {
170                 m_bLastTriggered = m_bTriggered;
171                 if (m_bTriggered)
172                 {
173                         if (m_physCtrl)
174                         {
175                                 m_physCtrl->SetRadius(m_ResetMargin);
176                         }
177                 } else
178                 {
179                         if (m_physCtrl)
180                         {
181                                 m_physCtrl->SetRadius(m_Margin);
182                         }
183
184                 }
185                 result = true;
186         }
187
188         return result;
189 }
190
191 // this function is called at broad phase stage to check if the two controller
192 // need to interact at all. It is used for Near/Radar sensor that don't need to
193 // check collision with object not included in filter
194 bool    KX_NearSensor::BroadPhaseFilterCollision(void*obj1,void*obj2)
195 {
196         KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
197         
198         // need the mapping from PHY_IPhysicsController to gameobjects now
199         assert(obj1==m_physCtrl && obj2);
200         KX_ClientObjectInfo* client_info = static_cast<KX_ClientObjectInfo*>((static_cast<PHY_IPhysicsController*>(obj2))->getNewClientInfo());
201
202         KX_GameObject* gameobj = ( client_info ? 
203                         client_info->m_gameobject :
204                         NULL);
205         
206         if (gameobj && (gameobj != parent))
207         {
208                 // only take valid colliders
209                 if (client_info->m_type == KX_ClientObjectInfo::ACTOR)
210                 {
211                         if ((m_touchedpropname.Length() == 0) || 
212                                 (gameobj->GetProperty(m_touchedpropname)))
213                         {
214                                 return true;
215                         }
216                 }
217         }
218
219         return false;
220 }
221
222 bool    KX_NearSensor::NewHandleCollision(void* obj1,void* obj2,const PHY_CollData * coll_data)
223 {
224 //      KX_TouchEventManager* toucheventmgr = static_cast<KX_TouchEventManager*>(m_eventmgr);
225 //      KX_GameObject* parent = static_cast<KX_GameObject*>(GetParent());
226         
227         // need the mapping from PHY_IPhysicsController to gameobjects now
228         
229         KX_ClientObjectInfo* client_info =static_cast<KX_ClientObjectInfo*> (obj1 == m_physCtrl? 
230                                         ((PHY_IPhysicsController*)obj2)->getNewClientInfo() : 
231                                         ((PHY_IPhysicsController*)obj1)->getNewClientInfo());
232
233         KX_GameObject* gameobj = ( client_info ? 
234                         client_info->m_gameobject :
235                         NULL);
236         
237         // Add the same check as in SCA_ISensor::Activate(), 
238         // we don't want to record collision when the sensor is not active.
239         if (m_links && !m_suspended &&
240                 gameobj /* done in BroadPhaseFilterCollision() && (gameobj != parent)*/)
241         {
242                 if (!m_colliders->SearchValue(gameobj))
243                         m_colliders->Add(gameobj->AddRef());
244                 // only take valid colliders
245                 // These checks are done already in BroadPhaseFilterCollision()
246                 //if (client_info->m_type == KX_ClientObjectInfo::ACTOR)
247                 //{
248                 //      if ((m_touchedpropname.Length() == 0) || 
249                 //              (gameobj->GetProperty(m_touchedpropname)))
250                 //      {
251                                 m_bTriggered = true;
252                                 m_hitObject = gameobj;
253                 //      }
254                 //}
255         }
256         
257         return false; // was DT_CONTINUE; but this was defined in Sumo as false
258 }
259
260
261 /* ------------------------------------------------------------------------- */
262 /* Python Functions                                                                                                                      */
263 /* ------------------------------------------------------------------------- */
264
265 //No methods
266
267 /* ------------------------------------------------------------------------- */
268 /* Python Integration Hooks                                                  */
269 /* ------------------------------------------------------------------------- */
270
271 PyTypeObject KX_NearSensor::Type = {
272 #if (PY_VERSION_HEX >= 0x02060000)
273         PyVarObject_HEAD_INIT(NULL, 0)
274 #else
275         /* python 2.5 and below */
276         PyObject_HEAD_INIT( NULL )  /* required py macro */
277         0,                          /* ob_size */
278 #endif
279         "KX_NearSensor",
280         sizeof(PyObjectPlus_Proxy),
281         0,
282         py_base_dealloc,
283         0,
284         0,
285         0,
286         0,
287         py_base_repr,
288         0,0,0,0,0,0,
289         py_base_getattro,
290         py_base_setattro,
291         0,0,0,0,0,0,0,0,0,
292         Methods
293 };
294
295
296
297 PyParentObject KX_NearSensor::Parents[] = {
298         &KX_NearSensor::Type,
299         &KX_TouchSensor::Type,
300         &SCA_ISensor::Type,
301         &SCA_ILogicBrick::Type,
302         &CValue::Type,
303         NULL
304 };
305
306
307
308 PyMethodDef KX_NearSensor::Methods[] = {
309         //No methods
310         {NULL,NULL} //Sentinel
311 };
312
313 PyAttributeDef KX_NearSensor::Attributes[] = {
314         KX_PYATTRIBUTE_FLOAT_RW_CHECK("distance", 0, 100, KX_NearSensor, m_Margin, CheckResetDistance),
315         KX_PYATTRIBUTE_FLOAT_RW_CHECK("resetDistance", 0, 100, KX_NearSensor, m_ResetMargin, CheckResetDistance),
316         {NULL} //Sentinel
317 };
318
319
320 PyObject* KX_NearSensor::py_getattro(PyObject *attr)
321 {
322         py_getattro_up(KX_TouchSensor);
323 }
324
325 PyObject* KX_NearSensor::py_getattro_dict() {
326         py_getattro_dict_up(KX_TouchSensor);
327 }
328
329 int KX_NearSensor::py_setattro(PyObject*attr, PyObject* value)
330 {
331         py_setattro_up(KX_TouchSensor);
332 }