]> git.llucax.com Git - z.facultad/75.07/algowars.git/blob - src/modelo/ov/naves/NavePropia.pas
Se expanden keywords del svn.
[z.facultad/75.07/algowars.git] / src / modelo / ov / naves / NavePropia.pas
1 {** Es la nave que será controlada por el jugador.<br>\r
2     <i>Cambios:</i>\r
3     <PRE>\r
4     05/10/00: Se corrigió el método mAcelerar porque tenía algunos bugs cuando la velocidad llegaba a cero.\r
5     01/12/00: Se implementan los disparon sobreescribiendo el método mDisparar de cNave y agregando algunos\r
6               atributos (aArmaSelect, aDisparando y aLockeado) y algunos métodos (mIntentarDisparo,\r
7               mSeleccionarArma, mSeleccionarArmaSig, mGetArmaSelect, mSetLockeado, mGetLockeado).\r
8               Se cambiaron las dimensiones de la nave para que los disparos sean mas "jugables".\r
9               Se cambia el orden de los argumentos de mDisparar para aprovechar los argumentos por defecto.\r
10               Se arreglaron un par de BUGs con punteros que apuntaba a objetos destruidos (aLockeado).\r
11     08/12/00: Se arregló una falla en el constructor que permitia crear la nave con una velocidad superior\r
12               a la máxima.\r
13     09/12/00: Se cambia el atributo disparando por un puntero a un arma que se disparara en el proximo turno.\r
14               También se cambia los métodos que lo utilizan y en particular se convierte el método\r
15               mIntentarDisparo en una función que devuelve dicho puntero para implementar la cámara en el arma.\r
16     </PRE>}\r
17 unit NavePropia;\r
18 \r
19 interface\r
20 \r
21 uses\r
22   Tipos,\r
23   Vectores,\r
24   Nave,\r
25   ObjetoVolador,\r
26   Meteorito,\r
27   Coordenadas,\r
28   Classes,\r
29   Filtros,\r
30   Armas;\r
31 \r
32 type\r
33   {** Es la nave que será controlada por el jugador.\r
34       <u>Características:</u>\r
35       <PRE>\r
36       Dimensión:            15        metros\r
37       Potencia:             5         Cantidad de daño que hace por intervalo de tiempo\r
38       Energía:              100       Cantidad de daño que soporta antes de ser destruída\r
39       Velocidad máxima:     0,17      metros/milisegundos (612 km/h)\r
40       Misiles:              10\r
41       Misiles Dirigidos:    5\r
42       </PRE>}\r
43   cNavePropia = class( cNave )\r
44     private\r
45       aLockeado:   cObjetoVolador; // Objeto Volador Lockeado\r
46       aArmaSelec:  tArma;          // Arma seleccionada por el usuario\r
47       aDisparando: cArma;          // Indica si en este momento se esta disparando o no\r
48       aLockFiltro: cFiltroLock;    // Filtro para saber que objetos voladores se puede lockear\r
49     public\r
50       {** Crea una nave controlada por un jugador}\r
51       constructor create( pos: cVector = nil; vel: cVector = nil ); overload;\r
52       {** Hace que se dispare un arma (todavía no está implementado)}\r
53       function mDisparar( dT: tTiempo; ov : cObjetoVolador = nil ): cArma; override;\r
54       {** Obtiene el objetivo lockeado}\r
55       function mGetLockeado: cObjetoVolador;\r
56       {** Setea el objetivo lockeado}\r
57       procedure mSetLockeado( ov: cObjetoVolador );\r
58       {** Cambia el objetivo lockeado}\r
59       procedure mCambiarLockeado( lEnemigos: TList );\r
60       {** Permite a la nave rotar a la izquierda sobre su eje X}\r
61       procedure mRotarIzquierda( angulo: tAngulo );\r
62       {** Permite a la nave rotar a la derecha sobre su eje X}\r
63       procedure mRotarDerecha( angulo: tAngulo );\r
64       {** Permite a la nave girar hacia la izquierda (sobre su eje Z)}\r
65       procedure mGirarIzquierda( angulo: tAngulo );\r
66       {** Permite a la nave girar hacia la derecha (sobre su eje Z)}\r
67       procedure mGirarDerecha( angulo: tAngulo );\r
68       {** Permite a la nave girar hacia arriba (sobre su eje Y)}\r
69       procedure mGirarArriba( angulo: tAngulo );\r
70       {** Permite a la nave girar hacia abajo (sobre su eje Y)}\r
71       procedure mGirarAbajo( angulo: tAngulo );\r
72       {** Aumenta el modulo de la velocidad (sin cambiar su dirección ni\r
73           sentido y sin sobrepasar la velocidad maxima)}\r
74       procedure mAcelerar( modulo: tLongitud );\r
75       {** Disminuye el modulo de la velocidad (sin cambiar su dirección ni sentido)}\r
76       procedure mDesacelerar( modulo: tLongitud );\r
77       {** Intenta disparar. Si las condiciones son las correctas, el proximo turno\r
78           saldrá el disparo, si no, no hace nada}\r
79       function mIntentarDisparo: cArma;\r
80       {** Selecciona un arma determinada. Si tiene municiones, la selecciona, si no,\r
81           no hace nada.}\r
82       procedure mSeleccionarArma( a: tArma );\r
83       {** Selecciona el proximo arma con municiones}\r
84       procedure mSeleccionarArmaSig;\r
85       {** Obtiene el arma seleccionada actualmente}\r
86       function mGetArmaSelec: tArma;\r
87       {** Obtiene un puntero a la último arma disparada}\r
88       function mGetUltimoArmaDisparado: cArma;\r
89       {** Método heredado, se sobreescribe porque se dibuja de forma distinta}\r
90       function mDibujar: tObjetosVoladores; override;\r
91       // SERIALIZACION\r
92       {** Devuelve una cadena de texto con el objeto serializado.}\r
93       function mSerializar: string; override;\r
94       {** Recrea el objeto a partir de una cadena de texto con el objeto\r
95           serializado.}\r
96       procedure mDesSerializar( str: string ); override;\r
97   end;\r
98 \r
99 implementation\r
100 \r
101 uses\r
102   RegExpr,\r
103   ObjetoPersistente,\r
104   SerializacionUtils,\r
105   Sysutils;\r
106 \r
107 { cNavePropia }\r
108 \r
109 {** @param pos Posición Inicial\r
110     @param vel Velocidad Inicial}\r
111 constructor cNavePropia.create(pos: cVector; vel: cVector);\r
112 begin\r
113   if vel <> nil then // Si no es nula la velocidad ...\r
114     vel.mSetModulo( 0.17 ); // Setea la velocidad como la máxima\r
115   // La dimensión es 15 m de radio, la potencia 5, la energía 100, tiene 10 misiles comunes,\r
116   //  5 dirigidos y su velocidad maxima es 0,17 m/mseg (612 km/h)\r
117   // El retardo del laser es de .5 segundos.\r
118   inherited create( pos, vel, 15 {dim}, 5 {pot}, 100 {ene}, 10 {mis}, 5 {misdir},\r
119                     0.17 {velmax}, 50 {retlas}, 1000 {retmis}, 2500 {retmisdir} );\r
120   aArmaSelec  := OV_LASER;\r
121   aDisparando := nil;\r
122   aLockeado   := nil;\r
123   aLockFiltro := cFiltroLock.create( self {observador}, 0.8 {angulo}, 2000 {maximo} );\r
124 end;\r
125 \r
126 {** Hace que aumente el modulo de la velocidad\r
127     @param modulo Modulo de la velocidad a sumar}\r
128 procedure cNavePropia.mAcelerar(modulo: tLongitud);\r
129 begin\r
130   modulo := mGetVelModulo + modulo;\r
131   if modulo <= mGetVelMax then\r
132     mSetVelModulo( modulo );\r
133 end;\r
134 \r
135 {** Hace que disminuya el modulo de la velocidad\r
136     @param modulo Modulo de la velocidad a restar}\r
137 procedure cNavePropia.mDesacelerar(modulo: tLongitud);\r
138 begin\r
139   modulo := mGetVelModulo - modulo;\r
140   mSetVelModulo( modulo );\r
141 end;\r
142 \r
143 {** Método heredado, se sobreescribe porque se dibuja de forma distinta}\r
144 function cNavePropia.mDibujar: tObjetosVoladores;\r
145 begin\r
146   result := OV_NAVEPROPIA;\r
147 end;\r
148 \r
149 {** Hace que se dispare un arma\r
150     @param  ov Objetivo del disparo\r
151     @param  dT Intervalo de tiempo\r
152     @return Arma disparada (o <i>nil</i> si no se puede disparar ningún arma)}\r
153 function cNavePropia.mDisparar( dT: tTiempo; ov : cObjetoVolador ): cArma;\r
154 begin\r
155   result := nil;\r
156   mActualizarRetardadores( dT );\r
157   if aDisparando <> nil then begin // Si esta disparando ...\r
158     result := aDisparando; // Se devuleve el arma disparada\r
159     aDisparando := nil;    // Deja de disparar\r
160   end;\r
161 end;\r
162 \r
163 {** Permite a la nave girar hacia abajo (sobre su eje Y)\r
164     @param angulo Ángulo a girar}\r
165 procedure cNavePropia.mGirarAbajo(angulo: tAngulo);\r
166 begin\r
167   mRotarEnJ( - angulo ); // Rota el sistema de coordenadas\r
168 end;\r
169 \r
170 {** Permite a la nave girar hacia arriba (sobre su eje Y)\r
171     @param angulo Ángulo a girar}\r
172 procedure cNavePropia.mGirarArriba(angulo: tAngulo);\r
173 begin\r
174   mRotarEnJ( angulo ); // Rota el sistema de coordenadas\r
175 end;\r
176 \r
177 {** Permite a la nave girar hacia la derecha (sobre su eje Z)\r
178     @param angulo Ángulo a girar}\r
179 procedure cNavePropia.mGirarDerecha(angulo: tAngulo);\r
180 begin\r
181   mRotarEnK( - angulo ); // Rota el sistema de coordenadas\r
182 end;\r
183 \r
184 {** Permite a la nave girar hacia la izquierda (sobre su eje Z)\r
185     @param angulo Ángulo a girar}\r
186 procedure cNavePropia.mGirarIzquierda(angulo: tAngulo);\r
187 begin\r
188   mRotarEnK( angulo ); // Rota el sistema de coordenadas\r
189 end;\r
190 \r
191 {** Permite a la nave rotar hacia la derecha (sobre su eje I)\r
192     @param angulo Ángulo a rotar}\r
193 procedure cNavePropia.mRotarDerecha(angulo: tAngulo);\r
194 begin\r
195   mRotarEnI( angulo ); // Rota el sistema de coordenadas\r
196 end;\r
197 \r
198 {** Permite a la nave rotar hacia la izquierda (sobre su eje I)\r
199     @param angulo Ángulo a rotar}\r
200 procedure cNavePropia.mRotarIzquierda(angulo: tAngulo);\r
201 begin\r
202   mRotarEnI( - angulo ); // Rota el sistema de coordenadas\r
203 end;\r
204 \r
205 {** Intenta disparar. Si las condiciones son las correctas, el proximo turno\r
206     saldrá el disparo, si no, no hace nada\r
207     @return Arma proximamente disparada}\r
208 function cNavePropia.mIntentarDisparo: cArma;\r
209 var\r
210   vel:     cVector;\r
211   ok:      boolean;\r
212 begin\r
213   result := nil;\r
214   if aDisparando = nil then // Si no esta disparando se fija si puede hacerlo\r
215     case aArmaSelec of\r
216       OV_LASER: if mPuedeDispararLaser( nil ) then begin // si puede disparar...\r
217                   aDisparando := mCrearLaserDisparado;\r
218                   result := aDisparando;\r
219                 end;\r
220       OV_MISIL: if mPuedeDispararMisil( nil ) then begin // si puede disparar...\r
221                   aDisparando := mCrearMisilDisparado;\r
222                   result := aDisparando;\r
223                 end;\r
224       OV_MISDIR: begin\r
225                   try // Prueba si aLockeado no fue destruido...\r
226                     ok := mPuedeDispararMisDir( aLockeado );\r
227                   except\r
228                     on e: EAccessViolation do begin // Si el objetivo lockeado esta destruido...\r
229                       aLockeado := nil;                        // Lo setea a nil\r
230                       ok := mPuedeDispararMisDir( aLockeado ); // Se fija de nuevo si puede disparar\r
231                     end;\r
232                   end;\r
233                   if ok then begin  // Si puede disparar ...\r
234                     aDisparando := mCrearMisDirDisparado( aLockeado ); // Utiliza como objetivo a aLockeado\r
235                     if aLockeado = nil then begin // Si no hay ninguno lockeado se setea la direccion\r
236                       vel := mGetI;               //  de la velocidad igual que la de la nave propia.\r
237                       aDisparando.mSetVelDir( vel );\r
238                       vel.free;\r
239                     end;\r
240                     result := aDisparando;\r
241                   end;\r
242                  end;\r
243     end;\r
244 end;\r
245 \r
246 {** Selecciona un arma determinada. Si tiene municiones, la selecciona, si no,\r
247     no hace nada.}\r
248 procedure cNavePropia.mSeleccionarArma(a: tArma);\r
249 begin\r
250   case a of\r
251     OV_LASER:\r
252       aArmaSelec := a;\r
253     OV_MISIL:\r
254       if mTieneMisil then\r
255         aArmaSelec := a;\r
256     OV_MISDIR:\r
257       if mTieneMisilDirigido then\r
258         aArmaSelec := a;\r
259   end;\r
260 end;\r
261 \r
262 {** Selecciona el proximo arma con municiones}\r
263 procedure cNavePropia.mSeleccionarArmaSig;\r
264 begin\r
265   case aArmaSelec of\r
266     OV_LASER:\r
267       if mTieneMisil then\r
268         aArmaSelec := OV_MISIL\r
269       else if mTieneMisilDirigido then\r
270         aArmaSelec := OV_MISDIR;\r
271     OV_MISIL:\r
272       if mTieneMisilDirigido then\r
273         aArmaSelec := OV_MISDIR\r
274       else\r
275         aArmaSelec := OV_LASER;\r
276     OV_MISDIR:\r
277       aArmaSelec := OV_LASER;\r
278   end;\r
279 end;\r
280 \r
281 {** Obtiene el arma seleccionada actualmente\r
282     @return Arma seleccionada}\r
283 function cNavePropia.mGetArmaSelec: tArma;\r
284 begin\r
285   result := aArmaSelec;\r
286 end;\r
287 \r
288 {** Obtiene el objetivo lockeado\r
289     @return Objeto volador lockeado}\r
290 function cNavePropia.mGetLockeado: cObjetoVolador;\r
291 begin\r
292   result := aLockeado;\r
293   if aLockeado <> nil then // Si no es nil...\r
294     try // Primero se fija que no esté destruido\r
295       aLockeado.mGetID;\r
296     except\r
297       on e: EAccessViolation do begin // Si lo está...\r
298         aLockeado := nil; // Lo setea a nil\r
299         result := aLockeado;\r
300       end;\r
301     end;\r
302 end;\r
303 \r
304 {** Setea el objetivo lockeado\r
305     @param ov Objeto volador lockeado}\r
306 procedure cNavePropia.mSetLockeado(ov: cObjetoVolador);\r
307 begin\r
308   aLockeado := ov;\r
309 end;\r
310 \r
311 {** Cambia el objetivo lockeado}\r
312 procedure cNavePropia.mCambiarLockeado(lEnemigos: TList);\r
313 var\r
314   lFiltrados: TList;\r
315   i: integer;\r
316 begin\r
317   lFiltrados := aLockFiltro.mFiltrar( lEnemigos );\r
318   if lFiltrados.Count = 0 then\r
319     aLockeado := nil\r
320   else\r
321     if aLockeado = nil then\r
322       aLockeado := lFiltrados.First // Asigna el primero\r
323     else begin\r
324       i := lFiltrados.IndexOf( aLockeado );\r
325       if i < 0 then // No esta en la lista\r
326         aLockeado := lFiltrados.First // Asigna el primero\r
327       else\r
328         if i = (lFiltrados.Count - 1) then // Es el ultimo objeto de la lista\r
329           aLockeado := lFiltrados.First // Asigna el primero\r
330         else\r
331           aLockeado := lFiltrados.Items[i+1]; // Asigna el proximo\r
332     end;\r
333   lFiltrados.free;\r
334 end;\r
335 \r
336 {** Recrea el objeto a partir de una cadena de texto con el objeto\r
337     serializado.\r
338     @param str Cadena de texto con el objeto serializado.}\r
339 procedure cNavePropia.mDesSerializar(str: string);\r
340 var\r
341   r: TRegExpr;\r
342 begin\r
343   inherited mDesSerializar( str ); // SIEMPRE el ID debe ser el PRIMER atributo\r
344   r := TRegExpr.create;\r
345   // LOCKEADO\r
346   try // se fija si hay errores al extraer los datos\r
347     r.Expression := '<lockeado\s+class=([\w\d]+)\s*>\s*(.+)\s*</lockeado>'; // contruye la expresion regular a buscar\r
348     if r.Exec ( str ) then // Ejecuta la expresion. Si la encuentra...\r
349       if r.Match[1] <> '0' then // Si tiene una clase determinada...\r
350         if aLockeado <> nil then // Si no es nulo\r
351           // Puede caer en una EAccessViolation si esta destruido\r
352           aLockeado.mDesSerializar( r.Match[2] ) // Lo deserializa\r
353         else // si es nulo\r
354           aLockeado := restaurarObjeto( r.Match[1], r.Match[2] ) // lo crea segun su clase\r
355       else // Si no tiene una clase determinada, entonces se lo pone en nil\r
356         aLockeado := nil\r
357     else // si no encontro la experesion...\r
358       raise ESerializacion.create( 'No se encontro el objetivo lockeado' ); // cae en una excepcion\r
359   except // Si hubieron errores ...\r
360     on e: ESerializacion do begin // Si fueron de serializacion...\r
361       r.Free; // libera memoria\r
362       raise ESerializacion.create( ClassName + ': Error al deserializar el objetivo lockeado: ' + e.Message ); // cae en una excepcion\r
363     end;\r
364     on e: ERegExpr do begin // si fueron de expresiones regulares...\r
365       r.Free; // libera memoria\r
366       raise ESerializacion.create( ClassName + ': Error al extraer el objetivo lockeado utilizando expresiones regulares: ' + e.Message ); // cae en una excepcion\r
367     end;\r
368     on e: EAccessViolation do begin // si el Objetivo fue destruido...\r
369       aLockeado := restaurarObjeto( r.Match[1], r.Match[2] ) // lo crea segun su clase\r
370     end;\r
371   end;\r
372   // ARMASELEC\r
373   try // se fija si hay errores al extraer los datos\r
374     r.Expression := '<armaselec>\s*(\d+)\s*</armaselec>'; // contruye la expresion regular a buscar\r
375     if r.Exec ( str ) then // Ejecuta la expresion. Si la encuentra...\r
376       aArmaSelec := tArma( StrToInt( r.Match[1] ) )\r
377     else // si no encontro la experesion...\r
378       raise ESerializacion.create( 'No se encontro el arma seleccionada' ); // cae en una excepcion\r
379   except // Si hubieron errores ...\r
380     on e: ERegExpr do begin // si fueron de expresiones regulares...\r
381       r.Free; // libera memoria\r
382       raise ESerializacion.create( ClassName + ': Error al extraer el arma seleccionada utilizando expresiones regulares: ' + e.Message ); // cae en una excepcion\r
383     end;\r
384   end;\r
385   // LOCKFILTRO\r
386   try // se fija si hay errores al extraer los datos\r
387     r.Expression := '<lockfiltro>\s*(.+)\s*</lockfiltro>'; // contruye la expresion regular a buscar\r
388     if r.Exec ( str ) then // Ejecuta la expresion. Si la encuentra...\r
389       if aLockFiltro <> nil then // Si no es nulo\r
390         aLockFiltro.mDesSerializar( r.Match[1] ) // Lo deserializa\r
391       else // si es nulo\r
392         aLockFiltro := cFiltroLock.crearDeSerializado( r.Match[1] ) // lo crea\r
393     else // si no encontro la experesion...\r
394       raise ESerializacion.create( ClassName + ': No se pudieron extraer el filtro de lockeo' ); // cae en una excepcion\r
395   except // Si hubieron errores ...\r
396     on e: ESerializacion do begin // Si fueron de serializacion...\r
397       r.Free; // libera memoria\r
398       raise ESerializacion.create( ClassName + ': Error al deserializar el filtro de lockeo: ' + e.Message ); // cae en una excepcion\r
399     end;\r
400     on e: ERegExpr do begin // si fueron de expresiones regulares...\r
401       r.Free; // libera memoria\r
402       raise ESerializacion.create( ClassName + ': Error al extraer el filtro de lockeo utilizando expresiones regulares: ' + e.Message ); // cae en una excepcion\r
403     end;\r
404   end;\r
405   // El observador del filtro va a ser siempre la nave propia, es por esto\r
406   //  que debemos eliminar la copia del observador que se creo y asignarle self\r
407   aLockFiltro.mGetObservador.free;\r
408   aLockFiltro.mSetObservador( self );\r
409   r.free;\r
410 end;\r
411 \r
412 {** Devuelve una cadena de texto con el objeto serializado.\r
413     @return Cadena de texto con el objeto serializado.}\r
414 function cNavePropia.mSerializar: string;\r
415 var\r
416   clase,\r
417   lockeado:  string;\r
418   meteorito: cMeteorito;\r
419 begin\r
420   // Si el objetivo es nil o está destruido, se setea el atributo class del\r
421   // TAG objetivo como '0' y entre el TAG se indica que es nil. Si no se\r
422   // setea como el nombre de la clase y su expresion serializada respectivamente\r
423   lockeado := 'nil';\r
424   clase    := '0';\r
425   if aLockeado <> nil then\r
426     try\r
427       lockeado := aLockeado.mSerializar;\r
428       clase    := aLockeado.ClassName;\r
429     except // Si esta destruido cambia la cadena de texto\r
430       on e: EAccessViolation do begin\r
431         lockeado := 'nil';\r
432         clase    := '0';\r
433       end;\r
434     end;\r
435   // Hoy que modificar el observador del filtro porque de otra forma esta funcion\r
436   //  se volveria infinitamente recursiva, ya que cuando quiere serializar el\r
437   //  filtro, necesita serializar el observador quien necesita serializar el\r
438   //  filtro y asi ad infinitum.\r
439   meteorito := cMeteorito.create;\r
440   aLockFiltro.mSetObservador( meteorito );\r
441   result := inherited mSerializar +\r
442             '<lockeado class=' + clase  + '>' + lockeado + '</lockeado>' +\r
443             '<armaselec>' + IntToStr( ord( aArmaSelec ) ) + '</armaselec>' +\r
444             '<lockfiltro>' + aLockFiltro.mSerializar + '</lockfiltro>';\r
445   // Se vuelve a establecer como observador a la nave propia.\r
446   aLockFiltro.mSetObservador( self );\r
447   meteorito.free;\r
448 end;\r
449 \r
450 {** Obtiene un puntero a la último arma disparada\r
451     @return Último arma disparado}\r
452 function cNavePropia.mGetUltimoArmaDisparado: cArma;\r
453 begin\r
454   result := aDisparando;\r
455   if aDisparando <> nil then // Si no es nil...\r
456     try // Primero se fija que no esté destruido\r
457       aDisparando.mGetID;\r
458     except\r
459       on e: EAccessViolation do begin // Si lo está...\r
460         aDisparando := nil; // Lo setea a nil\r
461         result := aDisparando;\r
462       end;\r
463     end;\r
464 end;\r
465 \r
466 end.\r