synched with trunk at revision 32129
[blender.git] / source / gameengine / Ketsji / KX_SCA_AddObjectActuator.cpp
1 //
2 // Add an object when this actuator is triggered
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 // Previously existed as:
31
32 // \source\gameengine\GameLogic\SCA_AddObjectActuator.cpp
33
34 // Please look here for revision history.
35
36
37 #include "KX_SCA_AddObjectActuator.h"
38 #include "SCA_IScene.h"
39 #include "KX_GameObject.h"
40 #include "KX_IPhysicsController.h"
41 #include "PyObjectPlus.h" 
42
43 /* ------------------------------------------------------------------------- */
44 /* Native functions                                                          */
45 /* ------------------------------------------------------------------------- */
46
47 KX_SCA_AddObjectActuator::KX_SCA_AddObjectActuator(SCA_IObject *gameobj,
48                                                                                                    SCA_IObject *original,
49                                                                                                    int time,
50                                                                                                    SCA_IScene* scene,
51                                                                                                    const float *linvel,
52                                                                                                    bool linv_local,
53                                                                                                    const float *angvel,
54                                                                                                    bool angv_local)
55         : 
56         SCA_IActuator(gameobj, KX_ACT_ADD_OBJECT),
57         m_OriginalObject(original),
58         m_scene(scene),
59         
60         m_localLinvFlag(linv_local),
61         m_localAngvFlag(angv_local)
62 {
63         m_linear_velocity[0] = linvel[0];
64         m_linear_velocity[1] = linvel[1];
65         m_linear_velocity[2] = linvel[2];
66         m_angular_velocity[0] = angvel[0];
67         m_angular_velocity[1] = angvel[1];
68         m_angular_velocity[2] = angvel[2];
69
70         if (m_OriginalObject)
71                 m_OriginalObject->RegisterActuator(this);
72
73         m_lastCreatedObject = NULL;
74         m_timeProp = time;
75
76
77
78
79 KX_SCA_AddObjectActuator::~KX_SCA_AddObjectActuator()
80
81         if (m_OriginalObject)
82                 m_OriginalObject->UnregisterActuator(this);
83         if (m_lastCreatedObject)
84                 m_lastCreatedObject->UnregisterActuator(this);
85
86
87
88
89 bool KX_SCA_AddObjectActuator::Update()
90 {
91         //bool result = false;  /*unused*/
92         bool bNegativeEvent = IsNegativeEvent();
93         RemoveAllEvents();
94         
95         if (bNegativeEvent) return false; // do nothing on negative events
96
97         InstantAddObject();
98
99         
100         return false;
101 }
102
103
104
105
106 SCA_IObject* KX_SCA_AddObjectActuator::GetLastCreatedObject() const 
107 {
108         return m_lastCreatedObject;
109 }
110
111
112
113 CValue* KX_SCA_AddObjectActuator::GetReplica() 
114 {
115         KX_SCA_AddObjectActuator* replica = new KX_SCA_AddObjectActuator(*this);
116
117         if (replica == NULL)
118                 return NULL;
119
120         // this will copy properties and so on...
121         replica->ProcessReplica();
122
123         return replica;
124 }
125
126 void KX_SCA_AddObjectActuator::ProcessReplica()
127 {
128         if (m_OriginalObject)
129                 m_OriginalObject->RegisterActuator(this);
130         m_lastCreatedObject=NULL;
131         SCA_IActuator::ProcessReplica();
132 }
133
134 bool KX_SCA_AddObjectActuator::UnlinkObject(SCA_IObject* clientobj)
135 {
136         if (clientobj == m_OriginalObject)
137         {
138                 // this object is being deleted, we cannot continue to track it.
139                 m_OriginalObject = NULL;
140                 return true;
141         }
142         if (clientobj == m_lastCreatedObject)
143         {
144                 // this object is being deleted, we cannot continue to track it.
145                 m_lastCreatedObject = NULL;
146                 return true;
147         }
148         return false;
149 }
150
151 void KX_SCA_AddObjectActuator::Relink(GEN_Map<GEN_HashedPtr, void*> *obj_map)
152 {
153         void **h_obj = (*obj_map)[m_OriginalObject];
154         if (h_obj) {
155                 if (m_OriginalObject)
156                         m_OriginalObject->UnregisterActuator(this);
157                 m_OriginalObject = (SCA_IObject*)(*h_obj);
158                 m_OriginalObject->RegisterActuator(this);
159         }
160 }
161
162 #ifndef DISABLE_PYTHON
163
164 /* ------------------------------------------------------------------------- */
165 /* Python functions                                                          */
166 /* ------------------------------------------------------------------------- */
167
168 /* Integration hooks ------------------------------------------------------- */
169 PyTypeObject KX_SCA_AddObjectActuator::Type = {
170         PyVarObject_HEAD_INIT(NULL, 0)
171         "KX_SCA_AddObjectActuator",
172         sizeof(PyObjectPlus_Proxy),
173         0,
174         py_base_dealloc,
175         0,
176         0,
177         0,
178         0,
179         py_base_repr,
180         0,0,0,0,0,0,0,0,0,
181         Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
182         0,0,0,0,0,0,0,
183         Methods,
184         0,
185         0,
186         &SCA_IActuator::Type,
187         0,0,0,0,0,0,
188         py_base_new
189 };
190
191 PyMethodDef KX_SCA_AddObjectActuator::Methods[] = {
192   {"instantAddObject", (PyCFunction) KX_SCA_AddObjectActuator::sPyInstantAddObject, METH_NOARGS,"instantAddObject() : immediately add object without delay\n"},
193   {NULL,NULL} //Sentinel
194 };
195
196 PyAttributeDef KX_SCA_AddObjectActuator::Attributes[] = {
197         KX_PYATTRIBUTE_RW_FUNCTION("object",KX_SCA_AddObjectActuator,pyattr_get_object,pyattr_set_object),
198         KX_PYATTRIBUTE_RO_FUNCTION("objectLastCreated",KX_SCA_AddObjectActuator,pyattr_get_objectLastCreated),
199         KX_PYATTRIBUTE_INT_RW("time",0,2000,true,KX_SCA_AddObjectActuator,m_timeProp),
200         KX_PYATTRIBUTE_FLOAT_ARRAY_RW("linearVelocity",-FLT_MAX,FLT_MAX,KX_SCA_AddObjectActuator,m_linear_velocity,3),
201         KX_PYATTRIBUTE_FLOAT_ARRAY_RW("angularVelocity",-FLT_MAX,FLT_MAX,KX_SCA_AddObjectActuator,m_angular_velocity,3),
202         { NULL }        //Sentinel
203 };
204
205 PyObject* KX_SCA_AddObjectActuator::pyattr_get_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
206 {
207         KX_SCA_AddObjectActuator* actuator = static_cast<KX_SCA_AddObjectActuator*>(self);
208         if (!actuator->m_OriginalObject)        
209                 Py_RETURN_NONE;
210         else
211                 return actuator->m_OriginalObject->GetProxy();
212 }
213
214 int KX_SCA_AddObjectActuator::pyattr_set_object(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
215 {
216         KX_SCA_AddObjectActuator* actuator = static_cast<KX_SCA_AddObjectActuator*>(self);
217         KX_GameObject *gameobj;
218                 
219         if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_SCA_AddObjectActuator"))
220                 return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
221                 
222         if (actuator->m_OriginalObject != NULL)
223                 actuator->m_OriginalObject->UnregisterActuator(actuator);       
224
225         actuator->m_OriginalObject = (SCA_IObject*)gameobj;
226                 
227         if (actuator->m_OriginalObject)
228                 actuator->m_OriginalObject->RegisterActuator(actuator);
229                 
230         return PY_SET_ATTR_SUCCESS;
231 }
232
233 PyObject* KX_SCA_AddObjectActuator::pyattr_get_objectLastCreated(void *self, const struct KX_PYATTRIBUTE_DEF *attrdef)
234 {
235         KX_SCA_AddObjectActuator* actuator = static_cast<KX_SCA_AddObjectActuator*>(self);
236         if (!actuator->m_lastCreatedObject)
237                 Py_RETURN_NONE;
238         else
239                 return actuator->m_lastCreatedObject->GetProxy();
240 }
241
242 PyObject* KX_SCA_AddObjectActuator::PyInstantAddObject()
243 {
244         InstantAddObject();
245
246         Py_RETURN_NONE;
247 }
248
249 #endif // DISABLE_PYTHON
250
251 void    KX_SCA_AddObjectActuator::InstantAddObject()
252 {
253         if (m_OriginalObject)
254         {
255                 // Add an identical object, with properties inherited from the original object  
256                 // Now it needs to be added to the current scene.
257                 SCA_IObject* replica = m_scene->AddReplicaObject(m_OriginalObject,GetParent(),m_timeProp );
258                 KX_GameObject * game_obj = static_cast<KX_GameObject *>(replica);
259                 game_obj->setLinearVelocity(m_linear_velocity ,m_localLinvFlag);
260                 game_obj->setAngularVelocity(m_angular_velocity,m_localAngvFlag);
261                 game_obj->ResolveCombinedVelocities(m_linear_velocity, m_angular_velocity, m_localLinvFlag, m_localAngvFlag);
262
263                 // keep a copy of the last object, to allow python scripters to change it
264                 if (m_lastCreatedObject)
265                 {
266                         //Let's not keep a reference to the object: it's bad, if the object is deleted
267                         //this will force to keep a "zombie" in the game for no good reason.
268                         //m_scene->DelayedReleaseObject(m_lastCreatedObject);
269                         //m_lastCreatedObject->Release();
270
271                         //Instead we use the registration mechanism
272                         m_lastCreatedObject->UnregisterActuator(this);
273                         m_lastCreatedObject = NULL;
274                 }
275                 
276                 m_lastCreatedObject = replica;
277                 // no reference
278                 //m_lastCreatedObject->AddRef();
279                 // but registration
280                 m_lastCreatedObject->RegisterActuator(this);
281                 // finished using replica? then release it
282                 replica->Release();
283         }
284 }