1 {** Contiene las armas que pueden ser usadas por las diferentes naves.<br>
\r
4 10/11/00: Se agrega el manejo de excepciones para evitar un BUG en cMisilDirigido. Si el objetivo del misil
\r
5 dirigido es destruido, la velocidad permanece constante y en mGetDebugInfo se informa que esta destruido.
\r
6 27/11/00: Se le agrega el manejo de la velocidad maxima a la clase cArma y se agrega el Alcance del arma, cambiando
\r
7 el anterior por la Duracion.
\r
8 01/12/00: Se cambiaron las dimensiones de las armas para que los disparos sean mas "jugables".
\r
20 {** La clase cArma esta pensada como una clase abtracta. En ella se encuentran
\r
21 características comunes a todas las armas.}
\r
22 cArma = class( cObjetoVolador )
\r
24 aDuracion: tTiempo; // Este alcance determina cuanto tiempo tiene que pasar
\r
25 // para que el arma se autodestruya.
\r
26 aAlcance: tLongitud; // Alcance en metros del arma
\r
27 aVelMaxima: tLongitud; // Velocidad máxima del arma
\r
29 {** Actualiza el alcance del arma, que va disminuyendo a medida que pasa el tiempo}
\r
30 procedure mActualizarDuracion( dt: tTiempo );
\r
31 {** Devuelve true si el arma todavia tiene alcance}
\r
32 function mActivo: boolean;
\r
33 {** Método para obtener el alcance del arma}
\r
34 procedure mSetAlcance( alc: tLongitud );
\r
37 constructor create( pos: cVector = nil; vel: cVector = nil; dim: tLongitud = 1;
\r
38 pot: tEnergia = 1; ene: tEnergia = 1; duracion: tTiempo = 2500;
\r
39 velMax: tLongitud = 0.25 ); overload;
\r
40 {$IFDEF DebugAlgoWars}
\r
41 {** Método heredado que devuelve un string con el estado del Objeto. Se utiliza para depurar
\r
42 y la información entregada depende del parámetro tDebugInfo.}
\r
43 function mGetDebugInfo( debugLevel: tDebugInfo = DI_MINI ): string; override;
\r
45 {** Método para obtener el alcance del arma}
\r
46 function mGetAlcance: tLongitud;
\r
47 {** Método para obtener el alcance del arma}
\r
48 function mGetVelMax: tLongitud;
\r
49 {** Método heredado, se sobreescribe porque se le agrega alguna funcionalidad}
\r
50 procedure mMover( dt: tTiempo ); override;
\r
52 {** Devuelve una cadena de texto con el objeto serializado.}
\r
53 function mSerializar: string; override;
\r
54 {** Recrea el objeto a partir de una cadena de texto con el objeto
\r
56 procedure mDesSerializar( str: string ); override;
\r
59 {** El laser es un tipo de arma básica. Es la que menos daño hace pero la que más rápido viaja<br>
\r
60 <u>Características:</u>
\r
62 Dimensión 0,1 metros (10 cm)
\r
63 Potencia: 1 Cantidad de daño que hace por intervalo de tiempo
\r
64 Energía: 1 Cantidad de daño que soporta antes de ser destruída
\r
65 Velocidad: 0,4 metros/milisegundos (1440 km/h)
\r
66 Alcance: 3000 milisegundos (3 segundos, 1,2 km)
\r
68 cLaser = class( cArma )
\r
71 constructor create( pos: cVector = nil; vel: cVector = nil ); overload;
\r
72 {** Método heredado, se sobreescribe porque se dibuja de forma distinta}
\r
73 function mDibujar: tObjetosVoladores; override;
\r
76 {** El misil es un tipo de arma básica. Hace un daño considerable y su velocidad también es alta<br>
\r
77 <u>Características:</u>
\r
79 Dimensión 0,5 metros (50 cm)
\r
80 Potencia: 20 Cantidad de daño que hace por intervalo de tiempo
\r
81 Energía: 1 Cantidad de daño que soporta antes de ser destruída
\r
82 Velocidad: 0,3 metros/milisegundos (1080 km/h)
\r
83 Alcance: 5000 milisegundos (5 segundos, 1,5 km)
\r
85 cMisil = class( cArma )
\r
88 constructor create( pos: cVector = nil; vel: cVector = nil ); overload;
\r
89 // Método heredado, se sobreescribe porque se dibuja de forma distinta
\r
90 function mDibujar: tObjetosVoladores; override;
\r
93 {** El misil dirigido es un tipo de arma avanzada. Persigue a su objetivo hasta que lo alcanza o
\r
94 hasta que se le acaba el alcance. Hace un daño alto, su velocidad es mediana y tiene un gran alcance.<br>
\r
95 <u>Características:</u>
\r
97 Dimensión 0,7 metros (70 cm)
\r
98 Potencia: 30 Cantidad de daño que hace por intervalo de tiempo
\r
99 Energía: 1 Cantidad de daño que soporta antes de ser destruída
\r
100 Velocidad: 0,25 metros/milisegundos (900 km/h)
\r
101 Alcance: 20000 milisegundos (20 segundos, 5 km)
\r
102 Area de Lock: 2000 metros (2 km)
\r
104 cMisilDirigido = class( cMisil )
\r
106 aObjetivo: cObjetoVolador; // Objetivo del misil
\r
107 aLockArea: tLongitud; // Maxima distancia a la que se debe encontrar
\r
108 // el objetivo para poder ser disparado
\r
110 {** Método que calcula la nueva velocidad basandose en al posicion del objetivo}
\r
111 procedure mModificarVelocidad;
\r
114 constructor create( obj: cObjetoVolador; pos: cVector = nil ); overload;
\r
115 {$IFDEF DebugAlgoWars}
\r
116 {** Método heredado que devuelve un string con el estado del Objeto. Se utiliza para depurar
\r
117 y la información entregada depende del parámetro tDebugInfo.}
\r
118 function mGetDebugInfo( debugLevel: tDebugInfo = DI_MINI ): string; override;
\r
120 {** Método heredado, se sobreescribe porque se le agrega alguna funcionalidad}
\r
121 procedure mMover( dt: tTiempo ); override;
\r
122 {** Obtiene el objetivo del misil dirigido}
\r
123 function mGetObjetivo: cObjetoVolador;
\r
124 {** Establece el objetivo del misil dirigido}
\r
125 procedure mSetObjetivo( ov: cObjetoVolador );
\r
126 {** Método heredado, se sobreescribe porque se dibuja de forma distinta}
\r
127 function mDibujar: tObjetosVoladores; override;
\r
129 {** Devuelve una cadena de texto con el objeto serializado.}
\r
130 function mSerializar: string; override;
\r
131 {** Recrea el objeto a partir de una cadena de texto con el objeto
\r
133 procedure mDesSerializar( str: string ); override;
\r
141 SerializacionUtils,
\r
146 {** Este constructor es protegido porque solo va a ser utilizado por subclases
\r
147 @param pos Posicion inicial
\r
148 @param vel Velocidad inicial
\r
149 @param dim Dimensión del objeto volador (radio, en metros)
\r
150 @param pot Potencia del objeto volador (cantidad de daño que hace por intervalode tiempo)
\r
151 @param ene Energía del objeto volador(cantidad de daño que soporta antes de ser destruido)
\r
152 @param alcance Tiempo que debe pasar para que el arma se destruya si no impactó con ningún objeto volador}
\r
153 constructor cArma.create(pos: cVector; vel: cVector; dim: tLongitud;
\r
154 pot, ene: tEnergia; duracion: tTiempo; velMax: tLongitud);
\r
158 inherited create( pos, vel, dim, pot, ene );
\r
159 aDuracion := duracion;
\r
160 aVelMaxima := velMax;
\r
161 aAlcance := aDuracion * aVelMaxima;
\r
162 // Setea el modulo de la velocidad a la maxima
\r
163 v := mGetVelocidad.mSetModulo( aVelMaxima );
\r
164 mSetVelocidad( v );
\r
168 {** Chequea si el arma todavia tiene alcance
\r
169 @return <i>true</i> si todavía tiene alcance, <i>false</i> si no}
\r
170 function cArma.mActivo: boolean;
\r
172 result := ( aDuracion > 0 );
\r
175 {** Método para obtener el alcance del arma
\r
176 @return Alcance del arma}
\r
177 function cArma.mGetAlcance: tLongitud;
\r
179 result := aAlcance;
\r
182 {** Método para establecer el alcance del arma
\r
183 @param alc Alcance del arma}
\r
184 procedure cArma.mSetAlcance(alc: tLongitud);
\r
189 {** Método para obtener la velocidad maxima del arma
\r
190 @return Velocidad maxima del arma}
\r
191 function cArma.mGetVelMax: tLongitud;
\r
193 result := aVelMaxima;
\r
196 {** Actualiza el alcance del arma, que va disminuyendo a medida que pasa el tiempo
\r
197 @param dt Intervalo de tiempo}
\r
198 procedure cArma.mActualizarDuracion(dt: tTiempo);
\r
200 aDuracion := aDuracion - dt;
\r
203 {$IFDEF DebugAlgoWars}
\r
204 {** Devuelve el estado del objeto basandose en la cantidad de datos requeridos.
\r
205 @return Cadena de texto con el estado del Objeto.
\r
206 @param debugLevel Cantidad de información requerida}
\r
207 function cArma.mGetDebugInfo(debugLevel: tDebugInfo): string;
\r
209 // Genera el string con el estado del Arma
\r
210 result := inherited mGetDebugInfo( debugLevel );
\r
211 if debugLevel > DI_MINI then
\r
212 result := result + ' | Alcance: ' + FloatToStr( aDuracion );
\r
216 {** Mueve el arma basado en su posición y velocidad actual y un intervalo de tiempo
\r
217 @param dt Intervalo de tiempo}
\r
218 procedure cArma.mMover(dt: tTiempo);
\r
220 inherited mMover( dt ); // Mueve el arma de la forma convencional
\r
221 mActualizarDuracion( dt ); // Actualiza el alcance
\r
222 if not mActivo then // Si se quedó sin alcance...
\r
223 mSetEnergia( -1 ); // pone energia en negativo, lo que significa que se destruyó...
\r
226 {** Recrea el objeto a partir de una cadena de texto con el objeto
\r
228 @param str Cadena de texto con el objeto serializado.}
\r
229 procedure cArma.mDesSerializar(str: string);
\r
233 inherited mDesSerializar( str ); // SIEMPRE el ID debe ser el PRIMER atributo
\r
234 r := TRegExpr.create;
\r
236 try // se fija si hay errores al extraer los datos
\r
237 r.Expression := '<duracion>\s*([+-]?\d+)\s*</duracion>'; // contruye la expresion regular a buscar
\r
238 if r.Exec ( str ) then // Ejecuta la expresion. Si la encuentra...
\r
239 aDuracion := StrToFloat( r.Match[1] )
\r
240 else // si no encontro la experesion...
\r
241 raise ESerializacion.create( 'No se encontro la duracion' ); // cae en una excepcion
\r
242 except // Si hubieron errores ...
\r
243 on e: ERegExpr do begin // si fueron de expresiones regulares...
\r
244 r.Free; // libera memoria
\r
245 raise ESerializacion.create( ClassName + ': Error al extraer la duracion utilizando expresiones regulares: ' + e.Message ); // cae en una excepcion
\r
249 try // se fija si hay errores al extraer los datos
\r
250 r.Expression := '<alcance>\s*([+\-]?\d+(\,\d+)?([eE][+\-]?\d+)?)\s*</alcance>'; // contruye la expresion regular a buscar
\r
251 if r.Exec ( str ) then // Ejecuta la expresion. Si la encuentra...
\r
252 aAlcance := StrToFloat( r.Match[1] )
\r
253 else // si no encontro la experesion...
\r
254 raise ESerializacion.create( 'No se encontro el alcance' ); // cae en una excepcion
\r
255 except // Si hubieron errores ...
\r
256 on e: ERegExpr do begin // si fueron de expresiones regulares...
\r
257 r.Free; // libera memoria
\r
258 raise ESerializacion.create( ClassName + ': Error al extraer el alcance utilizando expresiones regulares: ' + e.Message ); // cae en una excepcion
\r
262 try // se fija si hay errores al extraer los datos
\r
263 r.Expression := '<velmaxima>\s*([+\-]?\d+(\,\d+)?([eE][+\-]?\d+)?)\s*</velmaxima>'; // contruye la expresion regular a buscar
\r
264 if r.Exec ( str ) then // Ejecuta la expresion. Si la encuentra...
\r
265 aVelMaxima := StrToFloat( r.Match[1] )
\r
266 else // si no encontro la experesion...
\r
267 raise ESerializacion.create( 'No se encontro la velocidad maxima' ); // cae en una excepcion
\r
268 except // Si hubieron errores ...
\r
269 on e: ERegExpr do begin // si fueron de expresiones regulares...
\r
270 r.Free; // libera memoria
\r
271 raise ESerializacion.create( ClassName + ': Error al extraer la velocidad maxima utilizando expresiones regulares: ' + e.Message ); // cae en una excepcion
\r
277 {** Devuelve una cadena de texto con el objeto serializado.
\r
278 @return Cadena de texto con el objeto serializado.}
\r
279 function cArma.mSerializar: string;
\r
281 result := inherited mSerializar +
\r
282 '<duracion>' + FloatToStrF( aDuracion, ffGeneral, 18, 0 ) + '</duracion>' +
\r
283 '<alcance>' + FloatToStrF( aAlcance, ffGeneral, 18, 0 ) + '</alcance>' +
\r
284 '<velmaxima>' + FloatToStrF( aVelMaxima, ffGeneral, 18, 0 ) + '</velmaxima>';
\r
289 {** Crea una nueva instancia.
\r
290 @param pos Vector posición
\r
291 @param vel Dirección del vector velocidad}
\r
292 constructor cLaser.create(pos: cVector = nil; vel: cVector = nil);
\r
294 // El laser tiene 10 cm de radio, 1 punto de potencia, 1 punto de energia y 3 seg de alcance (1,2 km)
\r
295 // Setea el modulo de la velocidad a 0,4 m/mseg (1440 km/h)
\r
296 inherited create( pos, vel, 0.1 {dim}, 1 {pot}, 1 {ene}, 3000 {dur}, 0.4 {velmax} );
\r
299 {** Método heredado, se sobreescribe porque se dibuja de forma distinta}
\r
300 function cLaser.mDibujar: tObjetosVoladores;
\r
302 result := OV_LASER;
\r
307 {** Crea una nueva instancia.
\r
308 @param pos Vector posición
\r
309 @param vel Dirección del vector velocidad}
\r
310 constructor cMisil.create(pos: cVector = nil; vel: cVector = nil);
\r
312 // El misil tiene 50 cm de radio, 20 puntos de potencia, 1 punto de energia y 5 seg de alcance (1,5 km)
\r
313 // Setea el modulo de la velocidad a 0,3 m/mseg (1080 km/h)
\r
314 inherited create( pos, vel, 0.5 {dim}, 20 {pot}, 1 {ene}, 5000 {dur}, 0.3 {velmax} );
\r
317 {** Método heredado, se sobreescribe porque se dibuja de forma distinta}
\r
318 function cMisil.mDibujar: tObjetosVoladores;
\r
320 result := OV_MISIL;
\r
325 {** Crea una nueva instancia.
\r
326 @param obj Objeto volador al que perseguirá (objetivo)
\r
327 @param pos Vector posición}
\r
328 constructor cMisilDirigido.create( obj: cObjetoVolador; pos: cVector = nil );
\r
330 // El misil dirigido tiene 70 m de radio, 30 puntos de potencia, 1 punto de energia y 20 seg de alcance (5 km)
\r
331 inherited create( pos, cVector.create, 0.7 {dim}, 30 {pot}, 1 {ene}, 20000 {dur}, 0.25 {velmax} );
\r
333 aLockArea := 2000; // 2 km
\r
334 mSetAlcance( aLockArea ); // Setea como alcance al area de lockeo.
\r
335 mModificarVelocidad; // Modifica la velocidad de forma tal que apunte al objetivo
\r
336 // y tenga un modulo constante
\r
339 {** Método que calcula la nueva velocidad basandose en al posicion del objetivo}
\r
340 procedure cMisilDirigido.mModificarVelocidad;
\r
342 pos, // Vector temporal para hacer calculos
\r
343 vel: cVector; // Vector temporal para hacer calculos
\r
347 if aObjetivo <> nil then // Si no es nulo ...
\r
348 try // Probamos que el objetivo no este destruido
\r
349 // Le resta la posicion propia a la del objetivo, obteniendo la nueva direccion de la velocidad
\r
350 pos := mGetPosicion;
\r
351 vel := aObjetivo.mGetPosicion.mRestar( pos );
\r
352 vel.mSetModulo( mGetVelMax ); // Setea el modulo al de la velocidad maxima: 0,25 m/mseg (900 km/h)
\r
353 mSetVelocidad( vel ); // Modifica la velocidad basado en el vector v
\r
354 except // Si esta destruido queda la velocidad constante y libera los vectores
\r
355 on e: EAccessViolation do begin
\r
356 mSetVelModulo( mGetVelMax ); // Setea el modulo de la velocidad como la maxima
\r
357 // (no cambia su direccion ni sentido)
\r
358 aObjetivo := nil; // Lo seteamos a nil
\r
359 vel.free; // libera la memoria del vector temporal
\r
360 pos.free; // libera la memoria del vector temporal
\r
363 // Si es nulo no modifica la velocidad ...
\r
366 {** Mueve el arma basado en su posición y velocidad actual, su objetivo y un intervalo de tiempo
\r
367 @param dt Intervalo de tiempo}
\r
368 procedure cMisilDirigido.mMover(dt: tTiempo);
\r
370 mModificarVelocidad; // Modifica la velocidad segun su objetivo
\r
371 inherited mMover( dt ); // Se mueve al igual que el resto de las armas
\r
374 {$IFDEF DebugAlgoWars}
\r
375 {** Devuelve el estado del objeto basandose en la cantidad de datos requeridos.
\r
376 @return Cadena de texto con el estado del Objeto.
\r
377 @param debugLevel Cantidad de información requerida}
\r
378 function cMisilDirigido.mGetDebugInfo(debugLevel: tDebugInfo): string;
\r
382 // Genera el string con el estado del Misil Dirigido
\r
383 result := inherited mGetDebugInfo( debugLevel );
\r
384 if debugLevel > DI_MINI then
\r
385 result := result + ' | LockArea: ' + FloatToStr( aLockArea );
\r
386 if aObjetivo <> nil then // Si no es nulo ...
\r
387 try // Probamos que el objetivo no este destruido
\r
388 objInfo := aObjetivo.mGetDebugInfo( DI_MINI );
\r
389 except // Si esta destruido cambia la cadena de texto
\r
390 on e: EAccessViolation do begin
\r
391 objInfo := 'DESTRUIDO';
\r
395 else // Si es nulo ...
\r
396 objInfo := 'DESTRUIDO';
\r
397 if debugLevel > DI_NORMAL then
\r
398 result := result + #13 + #10 + 'Objetivo: ' + objInfo;
\r
402 {** Obtiene el objetivo del misil dirigido.
\r
403 @return Objetivo del misil dirigido.}
\r
404 function cMisilDirigido.mGetObjetivo: cObjetoVolador;
\r
406 result := aObjetivo;
\r
407 if aObjetivo <> nil then // Si no es nil...
\r
408 try // Primero se fija que no esté destruido
\r
411 on e: EAccessViolation do begin // Si lo está...
\r
412 aObjetivo := nil; // Lo setea a nil
\r
413 result := aObjetivo;
\r
418 {** Establece el objetivo del misil dirigido
\r
419 @param ov Nuevo objetivo}
\r
420 procedure cMisilDirigido.mSetObjetivo( ov: cObjetoVolador );
\r
425 {** Método heredado, se sobreescribe porque se dibuja de forma distinta}
\r
426 function cMisilDirigido.mDibujar: tObjetosVoladores;
\r
428 result := OV_MISDIR;
\r
431 {** Recrea el objeto a partir de una cadena de texto con el objeto
\r
433 @param str Cadena de texto con el objeto serializado.}
\r
434 procedure cMisilDirigido.mDesSerializar(str: string);
\r
438 inherited mDesSerializar( str ); // SIEMPRE el ID debe ser el PRIMER atributo
\r
439 r := TRegExpr.create;
\r
441 try // se fija si hay errores al extraer los datos
\r
442 r.Expression := '<objetivo\s+class=([\w\d]+)\s*>\s*(.+)\s*</objetivo>'; // contruye la expresion regular a buscar
\r
443 if r.Exec ( str ) then // Ejecuta la expresion. Si la encuentra...
\r
444 if r.Match[1] <> '0' then // Si tiene una clase determinada...
\r
445 if aObjetivo <> nil then // Si no es nulo
\r
446 // Puede caer en una EAccessViolation si esta destruido
\r
447 aObjetivo.mDesSerializar( r.Match[2] ) // Lo deserializa
\r
449 aObjetivo := restaurarObjeto( r.Match[1], r.Match[2] ) // lo crea segun su clase
\r
450 else // Si no tiene una clase determinada, entonces se lo pone en nil
\r
452 else // si no encontro la experesion...
\r
453 raise ESerializacion.create( 'No se encontro el objetivo' ); // cae en una excepcion
\r
454 except // Si hubieron errores ...
\r
455 on e: ESerializacion do begin // Si fueron de serializacion...
\r
456 r.Free; // libera memoria
\r
457 raise ESerializacion.create( ClassName + ': Error al deserializar el objetivo: ' + e.Message ); // cae en una excepcion
\r
459 on e: ERegExpr do begin // si fueron de expresiones regulares...
\r
460 r.Free; // libera memoria
\r
461 raise ESerializacion.create( ClassName + ': Error al extraer el objetivo utilizando expresiones regulares: ' + e.Message ); // cae en una excepcion
\r
463 on e: EAccessViolation do begin // si el Objetivo fue destruido...
\r
464 aObjetivo := restaurarObjeto( r.Match[1], r.Match[2] ) // lo crea segun su clase
\r
468 try // se fija si hay errores al extraer los datos
\r
469 r.Expression := '<lockarea>\s*([+\-]?\d+(\,\d+)?([eE][+\-]?\d+)?)\s*</lockarea>'; // contruye la expresion regular a buscar
\r
470 if r.Exec ( str ) then // Ejecuta la expresion. Si la encuentra...
\r
471 aLockArea := StrToFloat( r.Match[1] )
\r
472 else // si no encontro la experesion...
\r
473 raise ESerializacion.create( 'No se encontro el area de lockeo' ); // cae en una excepcion
\r
474 except // Si hubieron errores ...
\r
475 on e: ERegExpr do begin // si fueron de expresiones regulares...
\r
476 r.Free; // libera memoria
\r
477 raise ESerializacion.create( ClassName + ': Error al extraer el area de lockeo utilizando expresiones regulares: ' + e.Message ); // cae en una excepcion
\r
483 {** Devuelve una cadena de texto con el objeto serializado.
\r
484 @return Cadena de texto con el objeto serializado.}
\r
485 function cMisilDirigido.mSerializar: string;
\r
490 // Si el objetivo es nil o está destruido, se setea el atributo class del
\r
491 // TAG objetivo como '0' y entre el TAG se indica que es nil. Si no se
\r
492 // setea como el nombre de la clase y su expresion serializada respectivamente
\r
495 if aObjetivo <> nil then
\r
497 objetivo := aObjetivo.mSerializar;
\r
498 clase := aObjetivo.ClassName;
\r
499 except // Si esta destruido cambia la cadena de texto
\r
500 on e: EAccessViolation do begin
\r
506 result := inherited mSerializar +
\r
507 '<objetivo class=' + clase + '>' + objetivo + '</objetivo>' +
\r
508 '<lockarea>' + FloatToStrF( aLockArea, ffGeneral, 18, 0 ) + '</lockarea>';
\r