]> git.llucax.com Git - z.facultad/75.07/algowars.git/blob - src/modelo/Espacio.pas
Import inicial después del "/var incident". :(
[z.facultad/75.07/algowars.git] / src / modelo / Espacio.pas
1 {** Se encarga de controlar la interacción entre\r
2     las naves y el responsable de manejar el tiempo.<br>\r
3     <i>Cambios:</i>\r
4     <PRE>\r
5     05/10/00: Se corrigió para que utilice los nuevos metodos de cNaveEnemiga y cObjetoVolador\r
6               Se corrigió el método mComunicarPosicion para que solo se comunique la posicion\r
7               a las naves que estan en el campo de radar de la nave espia.\r
8     07/10/00: Se agregaron los métodos mDestruir y mActualizarObjetoVolador. Se modificó el\r
9               método mActualizar (para usar los nuevos) y el método mDetectarColisiones para\r
10               manejar de forma más eficiente y clara la destrucción de objetos sin energía.\r
11     03/11/00: Se sacan los metodos mIniciay y mParar, ya que el control del tiempo y el encargado\r
12               de actualizar el espacio sera el Controlador (Controller).\r
13               Se agregaron métodos para facilitar la manipulación del espacio:\r
14               mQuitarObjeto, mGetObjetos, mSetObjetos y mSetNavePropia\r
15     05/11/00: Se corrigió un BUG que hacia que siempre el espacio se inicialice con una lista vacia\r
16               y una nave propia estandar (en el constructor).\r
17     09/11/00: Se corrigió un BUG que hacía que la nave espia no pueda escapar, ya que se avisaba a si misma.\r
18               Tambien se hace que ignore otras naves espias que esten avisando para evitar problemas similares.\r
19               (en el método mComunicarPosicion).\r
20     10/11/00: Se reemplaza el método mNavePropiaDestruida por una excepción (ENavePropiaDestruida).\r
21               Es lanzada por el método mActualizar y otros metodos privados que utilizan la nave propia.\r
22     27/11/00: Se agrega el control de disparos de las naves enemigas en el método mActualizar\r
23     29/11/00: Se elimina el método temporal mActualizarNavePropia.\r
24     01/12/00: Se modifica el método mActualizar para manejar los disparos de la nave propia.\r
25     </PRE>}\r
26 unit Espacio;\r
27 \r
28 interface\r
29 \r
30 uses\r
31   Tipos,\r
32   ObjetoPersistente,\r
33   ObjetoVolador,\r
34   Nave,\r
35   Vectores,\r
36   Armas,\r
37   NaveEnemiga,\r
38   NavesEnemigas,\r
39   NavePropia,\r
40   Classes,\r
41   Sysutils,\r
42   Meteorito;\r
43 \r
44 type\r
45   {** Excepcion producida por el espacio si la nave propia fue destruido}\r
46   ENavePropiaDestruida = class( Exception )\r
47     public\r
48       {** Constructor}\r
49       constructor create;\r
50   end;\r
51 \r
52   {** Se encarga de controlar la interacción entre\r
53       las naves y el responsable de manejar el tiempo.}\r
54   cEspacio = class( cObjetoPersistente )\r
55     private\r
56       aDeltaT:  tTiempo;        // Intervalo de tiempo (en milisegundos) que pasa entre ciclo y ciclo\r
57       aNavePropia: cNavePropia; // Nave del jugador, tambien esta en la lista, pero se lo\r
58                                 //  pone a parte para poder ser referenciado más fácilmente\r
59       aObjetos: TList;          // Lista con los objetos presentes en el espacio\r
60     protected\r
61       {** Procedimiento que evalua las posiciones de los Objetos Voladores que se encuentran en el espacio,\r
62           verificando 2 a 2 si hay una colisión.}\r
63       procedure mDetectarColision;\r
64       {** Método que se encarga de avisar al resto de las naves enemigas que estan cerca de una\r
65           espia sobre la ultima posicion de la nave propia.}\r
66       procedure mComunicarPosicion( nEsp: cNaveEspia );\r
67       {** Destruye un Objeto Volador}\r
68       procedure mDestruir( ov: cObjetoVolador );\r
69       {** Actualiza el estado de un objeto según sea tu tipo}\r
70       procedure mActualizarObjetoVolador( ov: cObjetoVolador );\r
71       {** Elimina los objetos duplicados después de recuperarlos de una serialización}\r
72       procedure mEliminarDuplicados;\r
73       {** Busca el duplicado de un objeto volador}\r
74       function mBuscarDuplicado( ov: cObjetoVolador ): cObjetoVolador;\r
75     public\r
76       {** Constructor. La lista que se pasa NO debe incluir la nave propia}\r
77       constructor create( np: cNavePropia = nil; objetos: TList = nil; dt: tTiempo = 25 );\r
78       {** Actualiza el Espacio. En esto se incluye mover las naves, detectar colisiones y tomar las\r
79           desiciones necesarias según sea el caso.}\r
80       procedure mActualizar;\r
81       {** Agrega un Objeto Volador al Espacio}\r
82       procedure mAgregarObjeto( ov: cObjetoVolador );\r
83       {** Quita un Objeto Volador del Espacio. Devuelve true si lo saco y false si no existia}\r
84       function mQuitarObjeto( ov: cObjetoVolador ): boolean;\r
85       {** Obtiene la lista de Objetos Voladores del Espacio}\r
86       function mGetObjetos: TList;\r
87       {** Cambia la lista de Objetos Voladores del Espacio, devolviendo un puntero a la lista vieja}\r
88       function mSetObjetos( l: TList ): TList;\r
89       {$IFDEF DebugAlgoWars}\r
90       {** Método heredado que devuelve un string con el estado del Objeto. Se utiliza para depurar\r
91           y la información entregada depende del parámetro tDebugInfo.}\r
92       function mGetDebugInfo( debugLevel: tDebugInfo = DI_MINI ): string; override;\r
93       {$ENDIF}\r
94       {** Método que obtiene la nave propia del espacio (este método es probable que deje de exstir)}\r
95       function mGetNavePropia: cNavePropia;\r
96       {** Método para cambiar la nave propia. Devuelve un puntero a la nave propia vieja.}\r
97       function mSetNavePropia( np: cNavePropia ): cNavePropia;\r
98       {** Destructor}\r
99       destructor destroy; override;\r
100       // SERIALIZACION\r
101       {** Devuelve una cadena de texto con el objeto serializado.}\r
102       function mSerializar: string; override;\r
103       {** Recrea el objeto a partir de una cadena de texto con el objeto\r
104           serializado.}\r
105       procedure mDesSerializar( str: string ); override;\r
106     end;\r
107 \r
108 implementation\r
109 \r
110 uses\r
111   RegExpr,\r
112   SerializacionUtils;\r
113 \r
114 { cEspacio }\r
115 \r
116 {** Constructor\r
117     @param np      Nave propia a utilizar\r
118     @param objetos Lista de objetos voladores (sin incluir la nave propia!)\r
119     @param dt      Intervalo de tiempo}\r
120 constructor cEspacio.create(np: cNavePropia; objetos: TList; dt: tTiempo);\r
121 begin\r
122   inherited create;\r
123   if objetos <> nil then\r
124     aObjetos := objetos\r
125   else // Si no se pasó nada como argumento, crea una nueva lista.\r
126     aObjetos := TList.create;\r
127   // inicializa la nave propia y la inserta en la lista.\r
128   if np <> nil then\r
129     aNavePropia := np\r
130   else // Si no se pasó nada como argumento, crea una nueva nave propia.\r
131     aNavePropia := cNavePropia.create;\r
132   aObjetos.Add( aNavePropia );\r
133   // Define el intervalo de tiempo\r
134   aDeltaT := dt;\r
135 end;\r
136 \r
137 {** Destructor}\r
138 destructor cEspacio.destroy;\r
139 var\r
140   oOV: cObjetoVolador;\r
141 begin\r
142   // Recorre la lista, liberando los Objetos Voladores en ella\r
143   while aObjetos.Count > 0 do begin\r
144     oOV := aObjetos.First;\r
145     aObjetos.Remove( oOV );\r
146     oOV.free;\r
147   end;\r
148   aObjetos.free; // Libera la memoria de la lista\r
149   inherited;\r
150 end;\r
151 \r
152 {** Actualiza el Espacio. En esto se incluye mover las naves, detectar colisiones y tomar las\r
153     desiciones necesarias según sea el caso.}\r
154 procedure cEspacio.mActualizar;\r
155 var\r
156   i:     integer;        // contador para el bucle\r
157   oOV:   cObjetoVolador; // objeto volador para apuntar al de la lista\r
158   oArma: cArma;          // Arma disparada\r
159 begin\r
160   for i:=0 to aObjetos.count -1 do begin // recorre la lista de objetos\r
161     oOV:= aObjetos.items[i]; // obtiene el ObjetoVolador actual\r
162     mActualizarObjetoVolador( oOV ); // Actualiza el estado del objeto segun su tipo\r
163     oOV.mMover( aDeltaT );  // Se mueve la objeto volador actual sin importar de que clase sea\r
164     if oOV is cNave then begin // Si es una nave, maneja los disparos\r
165       with oOV as cNave do begin  // Convierte el puntero a cNave\r
166         if oOV is cNaveEnemiga then                   // Si es una nave enemiga\r
167           oArma := mDisparar( aDeltaT, aNavePropia )  // Dispara con la NavePropia como objetivo\r
168         else                                   // Si es otra nave (inclusive la nave propia)\r
169           oArma := mDisparar( aDeltaT )   // dispara con nil como objetivo (el objetivo es\r
170       end;                                     // manejado por la propia nave)\r
171       if oArma <> nil then        // Si efectivamente se disparo un arma\r
172         mAgregarObjeto( oArma );  // Se la agrega a la lista\r
173     end;\r
174   end;\r
175   mDetectarColision; // Se detectan las colisiones\r
176   if aNavePropia = nil then\r
177     raise ENavePropiaDestruida.create;\r
178 end;\r
179 \r
180 {** Actualiza el estado de un objeto volador, dependiendo de que tipo de objeto sea.\r
181     @param ov Objeto Volador a actualizar}\r
182 procedure cEspacio.mActualizarObjetoVolador(ov: cObjetoVolador);\r
183 begin\r
184   if ov is cNaveEnemiga then begin // si es una nave enemiga...\r
185     with ov as cNaveEnemiga do // "Transforma el puntero" a uno de clase NaveEnemiga\r
186     if aNavePropia = nil then\r
187       raise ENavePropiaDestruida.create\r
188     else\r
189       if mDetectado( aNavePropia ) then // si la nave propia esta en el campo de radar de la nave enemiga...\r
190         mReaccionar( aNavePropia );  // se manda un mensaje a la nave enemiga de atacar a la propia\r
191       // Si es una nave espia, nos fijamos si esta avisando\r
192       if ov is cNaveEspia then begin\r
193         with ov as cNaveEspia do // "Transforma el puntero" a uno de clase NaveEspia\r
194         if mAvisando then\r
195           mComunicarPosicion( ov as cNaveEspia );\r
196       end;\r
197   end;\r
198 end;\r
199 \r
200 {** Agrega un Objeto Volador al Espacio\r
201     @param ov Objeto volador a agregar}\r
202 procedure cEspacio.mAgregarObjeto(ov: cObjetoVolador);\r
203 begin\r
204   aObjetos.Add( ov );\r
205 end;\r
206 \r
207 {** Método que se encarga de avisar al resto de las naves enemigas que estan cerca de una\r
208     espia sobre la ultima posicion de la nave propia.\r
209     @param nEsp Nave espía que está avisando}\r
210 procedure cEspacio.mComunicarPosicion(nEsp: cNaveEspia);\r
211 var\r
212   i:   integer;        // contador para el bucle\r
213   oOV: cObjetoVolador; // objeto volador para apuntar al de la lista\r
214 begin\r
215   for i := 0 to aObjetos.Count - 1 do begin  // recorre la lista\r
216     oOV := aObjetos.Items[i]; // obteniendo el primer objeto volador\r
217     if oOV = nEsp then // Si es la misma nave propia...\r
218       continue;        //  la pasa por alto\r
219     if oOV is cNaveEnemiga then begin // si es una nave enemiga...\r
220       if oOV is cNaveEspia then    // Si es una nave espia, se fija si esta avisando\r
221         with oOV as cNaveEspia do\r
222           if mAvisando then        // Si esta avisando:\r
223             continue;              // la pasa por alto\r
224       if nEsp.mDetectado( oOV ) then // Si esta dentro del radar de la nave espia...\r
225         with oOV as cNaveEnemiga do\r
226           mIrA( nEsp.mGetPosicionEnemiga );   // Le indica que vaya a la ultima posicion\r
227                                               //  en donde vio a la nave propia\r
228     end;\r
229   end;\r
230 end;\r
231 \r
232 {** Destruye un objeto volador, liberando memoria y eliminandolo de la lista\r
233     @param ov Objeto Volador a destruir}\r
234 procedure cEspacio.mDestruir(ov: cObjetoVolador);\r
235 begin\r
236   aObjetos.Remove( ov );\r
237   if ov is cNavePropia then\r
238     aNavePropia := nil;\r
239   ov.Free;\r
240 end;\r
241 \r
242 {** Procedimiento que evalua las posiciones de los Objetos Voladores que se encuentran en el espacio,\r
243     verificando si hay una colisión.}\r
244 procedure cEspacio.mDetectarColision;\r
245 var\r
246   i,                    // contador\r
247   j: integer;           // contador\r
248   oOV1,                 // variables para apuntar a los dos objetos voladores\r
249   oOV2: cObjetoVolador; //  que queremos evaluar si colisionaron\r
250   oRotos: TList;        // lista que contiene todos los objetos voladores destruidos\r
251 \r
252 begin\r
253   oRotos := TList.create;\r
254   for i := 0 to aObjetos.Count - 1 do begin  // recorre la lista\r
255     oOV1 := aObjetos.Items[i]; // obteniendo el primer objeto volador\r
256     for j := i + 1 to aObjetos.Count - 1 do begin // recorre la lista a partir del objeto volador anterior (excluyentemente)\r
257       oOV2 := aObjetos.Items[j]; // obteniendo el segundo objeto volador\r
258       if oOV1.mColisiono( oOV2 ) then begin // Si colisionaron los Objetos Voladores...\r
259         oOV1.mRestarEnergia( oOV2.mGetPotencia ); // Le resta la energia al primer objeto volador\r
260         oOV2.mRestarEnergia( oOV1.mGetPotencia ); // Le resta la energia al segundo objeto volador\r
261       end;\r
262     end;\r
263     // Una vez que termina de restarle toda la energia por choques, verifica si esta destruido\r
264     if oOV1.mGetEnergia <= 0 then // Si quedo con energia negativa,\r
265       oRotos.Add( oOV1 );         //  lo agrega a la lista de objetos rotos\r
266   end;\r
267   // Destruye todos los objetos voladores rotos\r
268   while oRotos.Count > 0 do begin // Extra un objeto volador destruido de la lista (mientras que haya alguno)\r
269     oOV1 := oRotos.First;\r
270     oRotos.Remove( oOV1 ); // Elimina el objeto de la lista de objetos rotos\r
271     mDestruir( oOV1 ); // Destruye el objeto volador\r
272   end;\r
273   oRotos.free; // Libera la memoria de la lista\r
274 end;\r
275 \r
276 {$IFDEF DebugAlgoWars}\r
277 {** Devuelve el estado del objeto basandose en la cantidad de datos requeridos.\r
278     @return            Cadena de texto con el estado del Objeto.\r
279     @param   debugLevel Cantidad de información requerida}\r
280 function cEspacio.mGetDebugInfo( debugLevel: tDebugInfo ): string;\r
281 var\r
282   i:  integer;         // contador\r
283   oOV: cObjetoVolador; // variable temporal para obtener info del OV\r
284 begin\r
285   result := '';\r
286   // Genera el string con el estado del Espacio\r
287   if debugLevel > DI_NORMAL then\r
288     result := result + 'Delta de T = ' + FloatToStrF( aDeltaT, ffNumber, 10, 0 ) + #13 + #10;\r
289   // Genera el string con el estado de los objetos dentro del Espacio\r
290   for i := 0 to aObjetos.Count - 1 do begin\r
291     oOV := aObjetos.Items[i];\r
292     result := result + #13 + #10 +\r
293               'ObjetoVolador' + IntToStr( i ) + ' (' + oOV.ClassName + '): ' + #13 + #10 +\r
294               oOV.mGetDebugInfo( debugLevel ) + #13 + #10\r
295               + '----';\r
296   end;\r
297 end;\r
298 {$ENDIF}\r
299 \r
300 {** Método que obtiene la nave propia del espacio (este método es probable que deje de exstir)\r
301     @return Instancia de la nave propia que se encuentra en el espacio (como puntero)}\r
302 function cEspacio.mGetNavePropia: cNavePropia;\r
303 begin\r
304   result := aNavePropia;\r
305 end;\r
306 \r
307 {** Quita un Objeto Volador del Espacio. Devuelve true si lo saco y false si no existia\r
308     (esto lo quita del espacio, no lo destruye)\r
309     @param  ov Objeto a quitar del espacio\r
310     @return    <i>true</i> si se quitó, <i>false</i> si no estaba en el espacio}\r
311 function cEspacio.mQuitarObjeto( ov: cObjetoVolador ): boolean;\r
312 var\r
313   index: integer;\r
314 begin\r
315   result := false;\r
316   index := aObjetos.IndexOf( ov );\r
317   if index >= 0 then begin\r
318     aObjetos.Delete( index );\r
319     result := true;\r
320   end;\r
321 end;\r
322 \r
323 {** Obtiene la lista de Objetos Voladores del Espacio\r
324     @return Lista de objetos del espacio (como puntero)}\r
325 function cEspacio.mGetObjetos: TList;\r
326 begin\r
327   result := aObjetos;\r
328 end;\r
329 \r
330 {** Cambia la lista de Objetos Voladores del Espacio, devolviendo un puntero a la lista vieja\r
331     @param  l Nueva lista de objetos a asignarle al espacio\r
332     @return   Vieja lista de objetos del espacio}\r
333 function cEspacio.mSetObjetos( l: TList ): TList;\r
334 begin\r
335   result := aObjetos;\r
336   aObjetos := l;\r
337 end;\r
338 \r
339 {** Método para cambiar la nave propia. Devuelve un puntero a la nave propia vieja.\r
340     @return Lista de objetos del espacio (como puntero)}\r
341 function cEspacio.mSetNavePropia( np: cNavePropia ): cNavePropia;\r
342 begin\r
343   result := aNavePropia;\r
344   aNavePropia := np;\r
345 end;\r
346 \r
347 {** Recrea el objeto a partir de una cadena de texto con el objeto\r
348     serializado.\r
349     @param str Cadena de texto con el objeto serializado.}\r
350 procedure cEspacio.mDesSerializar(str: string);\r
351 var\r
352   total,\r
353   i:       integer;\r
354   objetos: string;\r
355   r:       TRegExpr;\r
356   ov:      cObjetoVolador;\r
357 begin\r
358   // Crea la lista de ser necesario\r
359   if aObjetos = nil then\r
360     aObjetos := TList.create;\r
361   // Libera la lista los objetos existentes...\r
362   while aObjetos.Count > 0 do begin\r
363     ov := aObjetos.First;\r
364     aObjetos.Remove( ov );\r
365     ov.free;\r
366   end;\r
367   aNavePropia := nil;\r
368   inherited mDesSerializar( str ); // SIEMPRE el ID debe ser el PRIMER atributo\r
369   r := TRegExpr.create;\r
370   // DELTAT\r
371   try // se fija si hay errores al extraer los datos\r
372     r.Expression := '<deltat>\s*([+\-]?\d+(\,\d+)?([eE][+\-]?\d+)?)\s*</deltat>'; // contruye la expresion regular a buscar\r
373     if r.Exec ( str ) then // Ejecuta la expresion. Si la encuentra...\r
374       aDeltaT := StrToFloat( r.Match[1] )\r
375     else // si no encontro la experesion...\r
376       raise ESerializacion.create( 'No se encontro el intervalo de actualizacion' ); // cae en una excepcion\r
377   except // Si hubieron errores ...\r
378     on e: ERegExpr do begin // si fueron de expresiones regulares...\r
379       r.Free; // libera memoria\r
380       raise ESerializacion.create( ClassName + ': Error al extraer el intervalo de actualizacion utilizando expresiones regulares: ' + e.Message ); // cae en una excepcion\r
381     end;\r
382   end;\r
383   // OBJETOS\r
384   try // se fija si hay errores al extraer los datos\r
385     r.Expression := '<objetos\s+total=(\d+)\s*>\s*(.+)\s*</objetos>'; // contruye la expresion regular a buscar\r
386     if r.Exec ( str ) then begin // Ejecuta la expresion. Si la encuentra...\r
387       total := StrToInt( r.Match[1] );\r
388       objetos := r.Match[2];\r
389       for i := 0 to total - 1 do begin\r
390         // OBJETO N\r
391         try // se fija si hay errores al extraer los datos\r
392           r.Expression := '<objeto' + IntToStr( i ) + '\s+class=([\w\d]+)\s*>\s*(.+)\s*</objeto' + IntToStr( i ) + '>'; // contruye la expresion regular a buscar\r
393           if r.Exec ( objetos ) then begin // Ejecuta la expresion. Si la encuentra...\r
394             // lo crea segun su clase y lo agrega a la lista\r
395             ov := restaurarObjeto( r.Match[1], r.Match[2] );\r
396             aObjetos.Add( ov );\r
397             if ov is cNavePropia then // Si es la nave propia\r
398               aNavePropia := ov as cNavePropia; // Asigna el atributo NavePropia\r
399           end else // si no encontro la experesion...\r
400             raise ESerializacion.create( 'No se encontro el objeto ' + IntToStr( i ) ); // cae en una excepcion\r
401         except // Si hubieron errores ...\r
402           on e: ESerializacion do begin // Si fueron de serializacion...\r
403             r.Free; // libera memoria\r
404             raise ESerializacion.create( ClassName + ': Error al deserializar el objeto '\r
405                                          + IntToStr( i ) + ': ' + e.Message ); // cae en una excepcion\r
406           end;\r
407           on e: ERegExpr do begin // si fueron de expresiones regulares...\r
408             r.Free; // libera memoria\r
409             raise ESerializacion.create( ClassName + ': Error al extraer el objeto ' + IntToStr( i ) + ' utilizando expresiones regulares: ' + e.Message ); // cae en una excepcion\r
410           end;\r
411         end;\r
412       end;\r
413     end else // si no encontro la experesion...\r
414       raise ESerializacion.create( 'No se encontro la potencia' ); // cae en una excepcion\r
415   except // Si hubieron errores ...\r
416     on e: ERegExpr do begin // si fueron de expresiones regulares...\r
417       r.Free; // libera memoria\r
418       raise ESerializacion.create( ClassName + ': Error al extraer la potencia utilizando expresiones regulares: ' + e.Message ); // cae en una excepcion\r
419     end;\r
420   end;\r
421   mEliminarDuplicados;\r
422   if aNavePropia = nil then // Si no se deserializo una nave propia ...\r
423     raise ESerializacion.create( ClassName + ': No se encontro la nave propia' ); // cae en una excepcion\r
424   r.free;\r
425 end;\r
426 \r
427 {** Devuelve una cadena de texto con el objeto serializado.\r
428     @return Cadena de texto con el objeto serializado.}\r
429 function cEspacio.mSerializar: string;\r
430 var\r
431   i:  integer;\r
432   ov: cObjetoVOlador;\r
433 begin\r
434   result := inherited mSerializar +\r
435             '<deltat>' + FloatToStrF( aDeltaT, ffGeneral, 18, 0 ) + '</deltat>' +\r
436             '<objetos total=' + IntToStr( aObjetos.Count ) + '>';\r
437   for i := 0 to aObjetos.Count - 1 do begin  // recorre la lista\r
438     ov := aObjetos.Items[i]; // obteniendo el primer objeto volador\r
439       // Serializa el objeto actual\r
440       result := result + '<objeto' + IntToStr( i ) + ' class=' + ov.ClassName + '>' + ov.mSerializar + '</objeto' + IntToStr( i ) + '>';\r
441   end;\r
442   result := result + '</objetos>';\r
443 end;\r
444 \r
445 {** Elimina los objetos duplicados después de recuperarlos de una serialización}\r
446 procedure cEspacio.mEliminarDuplicados;\r
447 var\r
448   i:    integer;\r
449   oOV,\r
450   oAux: cObjetoVolador;\r
451 begin\r
452   for i := 0 to aObjetos.Count - 1 do begin\r
453     oOV  := aObjetos.Items[i];\r
454     if oOV is cNavePropia then begin\r
455       // Busca el duplicado del objetivo\r
456       oAux := mBuscarDuplicado( (oOV as cNavePropia).mGetLockeado );\r
457       (oOV as cNavePropia).mGetLockeado.free; // Libera la copia que tiene como objetivo\r
458       (oOV as cNavePropia).mSetLockeado( oAux ); // Setea como nuevo objetivo al objeto de la lista\r
459     end;\r
460     if oOV is cMisilDirigido then begin\r
461       // Busca el duplicado del objetivo\r
462       oAux := mBuscarDuplicado( (oOV as cMisilDirigido).mGetObjetivo );\r
463       (oOV as cMisilDirigido).mGetObjetivo.free; // Libera la copia que tiene como objetivo\r
464       (oOV as cMisilDirigido).mSetObjetivo( oAux ); // Setea como nuevo objetivo al objeto de la lista\r
465     end;\r
466   end;\r
467 end;\r
468 \r
469 {** Busca el duplicado de un objeto volador\r
470     @param  ov Objeto volador al cual se le quiere encontrar un duplicado\r
471     @return Objeto Volador duplicado de ov}\r
472 function cEspacio.mBuscarDuplicado(ov: cObjetoVolador): cObjetoVolador;\r
473 var\r
474   i:   integer;\r
475   oOV: cObjetoVolador;\r
476 begin\r
477   result := nil;\r
478   if ov <> nil then\r
479     for i := 0 to aObjetos.Count - 1 do begin\r
480       oOV  := aObjetos.Items[i];\r
481       if oOV.mGetID = ov.mGetID then // Si tienen el mismo ID...\r
482         result := oOV; // Devulve el duplicado\r
483     end;\r
484 end;\r
485 \r
486 { ENavePropiaDestruida }\r
487 \r
488 constructor ENavePropiaDestruida.create;\r
489 begin\r
490   inherited create( 'La Nave Propia fue destruida.' );\r
491 end;\r
492 \r
493 end.\r