Motor de batallas, código fuente (muy técnico me temo)

Artículos en plan blog acerca de temas relacionados con ogArena, aunque no tan importantes como para estar en los apartados principales. Digamos, para curiosos.
Andurino
Mensajes: 67
Registrado: 18 Dic 2008 05:22

Re: Motor de batallas, código fuente (muy técnico me temo)

Mensaje por Andurino »

Andurino escribió:QUE PARTE DE VOSOTROS ME ESTAIS FALTADO NO ENTIENDES.

QUE ME BANEES YA!!
que me banees YA!!
Avatar de Usuario
Kramagon
Mensajes: 2570
Registrado: 03 Jun 2008 19:57
Alianza: Los Chungos
Ubicación: En la caja con Locke

Re: Motor de batallas, código fuente (muy técnico me temo)

Mensaje por Kramagon »

Estás pasando de ser una posible colaboración muy interesante y un tio que viene con una propuesta que realmente intenta mejorar cosas serias del juego a estar dando pena y verguenza ajena.
No me gusta crear mártires, pero si sigues por este camino no me vas a dejar más remedio que darte unas minivacaciones para que te relajes y reflexiones sobre tu actitud alejado del foro.
Imagen
Imagen
Andurino
Mensajes: 67
Registrado: 18 Dic 2008 05:22

Re: Motor de batallas, código fuente (muy técnico me temo)

Mensaje por Andurino »

Andurino escribió:
Andurino escribió:QUE PARTE DE VOSOTROS ME ESTAIS FALTADO NO ENTIENDES.

QUE ME BANEES YA!!
que me banees YA!!
Que parte de que me banees ya no entiendes. Enterado

HABER SI TE CREES QUE OS DEBO ALGO.
Avatar de Usuario
Kramagon
Mensajes: 2570
Registrado: 03 Jun 2008 19:57
Alianza: Los Chungos
Ubicación: En la caja con Locke

Re: Motor de batallas, código fuente (muy técnico me temo)

Mensaje por Kramagon »

Ok
Deseo concedido.
Dejo el hilo abierto, pero por favor, corramos todos un tupido velo sobre este individuo que no merece la pena darle más vueltas a sus acciones/palabras.

Saludos
Imagen
Imagen
Avatar de Usuario
It's KoRn
Mensajes: 1081
Registrado: 06 Nov 2008 04:39
Alianza: Vago y AtorranTe
Ubicación: Vago y AtorranTe

Re: Motor de batallas, código fuente (muy técnico me temo)

Mensaje por It's KoRn »

Que pena :cry: no me dejaron abrir un hilo para hacer las votaciones.
de todos modos esa actitud tuya te llevo a donde estas ahora.
saludos y espero reflexiones ;)
no hay aplausos... pero haganse la idea :D
Imagen
Imagen
apokalypse
Helper Programación
Helper Programación
Mensajes: 207
Registrado: 25 Jun 2008 03:31

Re: Motor de batallas, código fuente (muy técnico me temo)

Mensaje por apokalypse »

asturcon3 escribió:Siempre que sale el tema de hacer un simulador y yo respondo que paso mucho de mantener un programa para eso, saltan uno o varios que dicen que si tuvieran el algoritmo de las batallas podrían hacerlo. Bueno, vamos a verlo.

Primero, culturilla. El motor de batallas actual es un proyecto de Visual C++ que genera un ejecutable con un diálogo donde lo único útil que hay es un cuadro de texto grande donde se va mostrando lo que hace el programa (un log). Hay un timer, que cuando se pasa el tiempo comprueba si hay una batalla pendiente de ejecutar. Si no la hay, reprograma el timer a un número fijo de segundos o a lo que queda hasta la siguiente flota (el menor de ambos). Si hay batalla, el programa recupera de la base de datos una cadena tocha que contiene, separados por caracteres |, todos los elementos que intervienen en la batalla.

Con esa cadena, dividiéndola, genera su propia representación interna de la batalla y la ejecuta. Cuando acaba, y basándose en esa misma representación interna, genera llamadas a la base de datos para computar el robo, la creación de luna, y los reportes de batalla.

Bueno, pues voy a publicar aquí la parte del timer (una rutina en el diálogo) y la clase Motor.cpp que realiza toda la batalla. En principio creo que cualquier programador que realmente pretenda hacer un simulador debería tener más que suficiente con eso. Pero si no es así, comentádmelo.

A ver, el timer del diálogo:
Oculto:

Código: Seleccionar todo

void CogArenaMonitorDlg::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: Agregue aquí su código de controlador de mensajes o llame al valor predeterminado
	KillTimer(m_nTimer);
	while (1) {
		CString tS,tId;
#ifdef _DEBUG
		if (0) { 
			tS="BATALLA|460|[4:48:12]|6090925| 000.00| 000.30|0|100000|0|-|A|827|CaPRiCoRN|217902|[4:47:18]|24|23|24|F|6090925|206|5425709|1360|165|9180|213|2043025|6800|1650|37400||D|92|asturcon3|460|[4:48:12]|25|22|24|P|460|202|4699776|18|32|1360|203|2125067|18|80|4080|206|301|1400|160|9180|207|16|3500|640|20400|208|14000|175|320|10200|209|1003|4|32|5440|210|1499834|0|3|340|214|1|700000|160000|3060000|221|1|35000000|32000000|1|401|691444|280|64|680|402|1939217|350|80|680|403|4527|875|320|2720|404|902|3850|640|11900|405|450|525|1600|2720|406|49242|10500|960|34000|407|1|4|6400|6800|408|1|4|32000|34000|";
		} else 
#endif
		{
			while (_T("ERROR") == (tId=theApp.callDelay())) {
				log(_T("reconectar"));
				conectar();
			}
			int segs=_ttoi(tId);
			if (segs>=0) {
				log(_T("."));
				m_nTimer=SetTimer(0,segs*(long)1000+1,NULL);
				return;
			}

			time_t osBinaryTime;  // C run-time time (defined in <time.h>)
			time( &osBinaryTime );
			CTime ahora(osBinaryTime);
			tId=tId.Mid(1);
			tS.Format(_T("idF=%s %s\r\n"),tId,ahora.Format("%d/%m %H:%M:%S"));
			log(tS);
			tS=theApp.callFlotaEvent(tId);
			// tS=theApp.callProcP(_T("flotaEvent"),tId);
		}
		if (tS.Left(8)=="BATALLA|") {
			log(tS.Trim());
			m_motor.batallar(tS);
		}
	}
}
Sintaxis de la cadena que toma como entrada:
Oculto:
(| es el separador, lo de (...)+ que hay en cada flota indica que lo de dentro de los paréntesis se repite tantas veces como tipos de naves haya)

Código: Seleccionar todo

BATALLA|códigoDePlanetaVíctima|Coordenadas|idFlotaQueLlega|IndicadorDeDefensaAEscombros(0/1)|PorcentajeEscombros|SePodríaCrearLunaAqui(0/1)|EscombrosPara1%luna|-|
Flota1: Bando(A de Atacante,D de Defensor)|idJugador|nick|planetaBase|coordenadas|tecno1|tecno2|tecno3|tipoId(F de Flota,P de Planeta)|idFlota/Planeta|
(tipoNave|numDeNaves|Ataque|Defensa|Blindaje|)+|
Flota 2:...
...
Como comentario, en la flota defensora se pasan también las defensas, del mismo modo (código de tipo, número, tecnos)
Y ya por fin, en todas partes del juego los elementos (edificios, naves, defensas, tecnos, objetos) se identifican con un código numérico, habitualmente llamado gid (GraphicID, supongo), se ve perfectamente en el juego al picar el nombre de una nave para ver su descripción)
El código principal de motor4.cpp (no me deja adjuntarlo como tal, asíq ue copio y pego)
Oculto:

Código: Seleccionar todo

// Motor4.cpp: archivo de implementación
//
#include "stdafx.h"
#include "ogArenaMonitor.h"
#include "Motor4.h"


// CMotor

CMotor4::CMotor4()
{
}

CMotor4::~CMotor4()
{
	if (m_pFuegoRapido) {
		for (int i=0;i<300;i++) if (m_pFuegoRapido[i]) free(m_pFuegoRapido[i]);
		free(m_pFuegoRapido);
	}
	if (m_costes) free(m_costes);


}

int orden4(const void *na, const void *nb)
{
	const TNave *a,*b;
	a=(const TNave *)na;
	b=(const TNave *)nb;
	if (!a->nGrupo) return b->nGrupo ? 1:0;
	if (a->rondaMuerta!=b->rondaMuerta) return (a->rondaMuerta > b->rondaMuerta) ? -1:1;
	if (a->capturada!=b->capturada) return (a->capturada<b->capturada) ? -1:1;
	if (a->blindaje!=b->blindaje) return (a->blindaje<b->blindaje) ? -1:1;
	if (a->escudo!=b->escudo) return (a->escudo<b->escudo) ? -1:1;
	return 0;
}

int ordenIndice(const void *na, const void *nb)
{
	const TIndiceGrupos *a,*b;
	a=(const TIndiceGrupos *)na;
	b=(const TIndiceGrupos *)nb;
	if (a->capturada!=b->capturada) return (a->capturada<b->capturada) ? -1:1;
	if (a->blindaje!=b->blindaje) return (a->blindaje<b->blindaje) ? -1:1;
	if (a->escudo!=b->escudo) return (a->escudo<b->escudo) ? -1:1;
	return 0;
}

int checkIndex(TIndiceGrupos *base,int nGrupos,TNave *grupos)
{
#ifdef _DEBUG
	int i;
	TNave *n; 
	for (i=0;i<nGrupos;i++) {
		if (i) ASSERT(ordenIndice(base+i-1,base+i)<=0);
		ASSERT(base[i].grupo>=0);
//		ASSERT(base[i].grupo<nGrupos); -- No es correcto, no se trata del mismo contador
		n=grupos+base[i].grupo;
		if (base[i].capturada!=-1) { // Flag grupo muerto antes
			ASSERT( n->escudo==base[i].escudo);
			ASSERT( n->blindaje==base[i].blindaje);
			ASSERT( n->capturada==base[i].capturada);
		}
	}
	return 1;
#else 
	return 1;
#endif
}

int buscaIndiceGrupos(TIndiceGrupos *base,int nGrupos,int capturada,int escudo,int blindaje,int buscar,int numGrupo=-1)
{
	TIndiceGrupos test;
	int inf,sup,centro,comp;
	TIndiceGrupos *p;
	test.capturada=capturada;
	test.escudo=escudo;
	test.blindaje=blindaje;
	inf=0;
	sup=nGrupos-1;
	while (inf<=sup) {
		centro=(inf+sup)/2;
		p=&base[centro];
		comp=ordenIndice(&test,p);
		if (!comp) { // Encontrado valor
			if (numGrupo==-1) return centro;
			inf=centro; // si se busca grupo concreto buscar atras y alante
			while (true) {
				if (base[inf].grupo==numGrupo) return inf;
				if (!inf) break;
				inf--;
				if (ordenIndice(&test,&base[inf])) break;
			}
			sup=centro;
			while (true) {
				sup++;
				if (sup>=nGrupos) break;
				if (ordenIndice(&test,&base[sup])) break;
				if (base[sup].grupo==numGrupo) return sup;
			}
			return -1;
		}
		if (comp<0) sup=centro-1;
		else inf=centro+1;
	}
	if (buscar==0) return -1;
	if (comp<0) return centro; // test es menor que centro, almacenar en centro
	return centro+1; // test es mayor que centro, devolver siguiente
}

void moveIndex(TIndiceGrupos *base,int nGrupos,int lPos,int newPos)
{
	TIndiceGrupos t;
	ASSERT(lPos>=0);
	ASSERT(newPos>=0);
	if (lPos==newPos) return;
	memcpy(&t,base+lPos,sizeof(TIndiceGrupos));
	if (newPos>lPos) {
		memcpy(base+lPos,base+lPos+1,sizeof(TIndiceGrupos)*(newPos-lPos));
	} else if (newPos<lPos) {
		memcpy(base+newPos+1,base+newPos,sizeof(TIndiceGrupos)*(lPos-newPos));
	}
	memcpy(base+newPos,&t,sizeof(TIndiceGrupos));
}

void CMotor4::batallar(CString &txt) 
{
	CString reporte,tS;
	int i,j,iFlota,iLin,m,n,nToks,gid,bando,nFlotas;
	__int64 navesA,navesD;
	int soloSondas=1,numSondasA=0,bEstampadaSondas=0; // Comprobacion rápida solosondas && numFR>numSondas->muerte directa
	__int64 numFRASondas=0;
	int talismanes;
	__int64 escombros1pc;
	DWORD inicio,fin;
	unsigned int seed;
	inicio=GetTickCount();
	seed=(unsigned int)inicio;
	tS.Format("srand(%u)",seed);
	log(tS);
	srand(seed);
#ifdef _DEBUG
	 srand(44505125);
#endif

	m_perdidas[0]=0;
	m_perdidas[1]=0;
	m_escombros[0] =m_escombros[1]=0;
	CString *toks=split("|",txt,n);
	ASSERT(n>6);
	CString batCP=toks[1];
	CString batCoords=toks[2];
	int idF=atoi(toks[3]);
	m_defEscombros=atof(toks[4]);
	m_porcEscombros=atof(toks[5]);
	int lunable=atoi(toks[6]);
	escombros1pc=_atoi64(toks[7]);
	if (n>8) talismanes=atoi(toks[8]);
	else talismanes=0;
	delete []toks;

	toks=split("|-|",txt,n);
	CString t=toks[1];
	delete []toks;
	CString *flotaStr=split("||",t,nFlotas);
	m_flotas[0]=new TFlotas[nFlotas]; m_flotas[1]=new TFlotas[nFlotas];
	time_t ahora; time(&ahora); reporte.Format("%li",ahora);
	m_totNaves=0;
	navesA=navesD=0;
	m_nFlotas[0]=m_nFlotas[1]=0;
	// comprobar muerte de sondas
	for (iFlota=0;iFlota<nFlotas;iFlota++) {
		toks=split("|",flotaStr[iFlota],nToks);
		bando=toks[0]=='A' ? 0:1;
		for (n=10;n<nToks-3;n+=5) {
			j=atoi(toks[n]); // gid
			i=atoi(toks[n+1]); // cant
			if (!bando) {
				if (j!=210) soloSondas=0; 
				else numSondasA+=i;
			}
			if (!soloSondas) break;
			if (bando) {
				if (m_pFuegoRapido[j-200]) 
					numFRASondas+=(__int64)i*m_pFuegoRapido[j-200][210-200];
			}
		}
		delete []toks;
	}
	bEstampadaSondas=soloSondas && numFRASondas>numSondasA;
	// Crear flotas y grupos de naves
	for (iFlota=0;iFlota<nFlotas;iFlota++) {
		toks=split("|",flotaStr[iFlota],nToks);
		bando=toks[0]=='A' ? 0:1;
		for (n=10;n<nToks-3;n+=5) {
			i=atoi(toks[n+1]);
			m_totNaves+=i;
			if (!bando) navesA+=i;
			else navesD+=i;
		}
		delete []toks;
	}
	m_batDivisor=1;
	while (m_totNaves>10000000 && navesA>100000 && navesD>100000) {
		m_batDivisor*=2;
		m_totNaves/=2; navesA/=2; navesD/=2;
	}
	m_totNaves=0; navesA=0; navesD=0;
	for (iFlota=0;iFlota<nFlotas;iFlota++) {
		toks=split("|",flotaStr[iFlota],nToks);
		bando=toks[0]=='A' ? 0:1;
		i=m_nFlotas[bando];
		m_flotas[bando][i].idJug=atoi(toks[1]);
		m_flotas[bando][i].nick=toks[2];
		m_flotas[bando][i].CP=atoi(toks[3]);
		m_flotas[bando][i].coords=toks[4];
		m_flotas[bando][i].tipoIdPlan=toks[8][0];
		m_flotas[bando][i].idJuego=atoi(toks[9]);
//		m_flotas[bando][i].ataques=(int *)calloc(500,sizeof(int));
//		m_flotas[bando][i].maxEscudos =(int *)calloc(500,sizeof(int));
//		m_flotas[bando][i].maxBlind=(int *)calloc(500,sizeof(int));
//		m_flotas[bando][i].tocadas=(TTocadas **)calloc(500,sizeof(TTocadas*));
		m_flotas[bando][i].capturas=(int *)calloc(500,sizeof(int));
		m_flotas[bando][i].vCapturas=m_flotas[bando][i].vPerdidas=0;
//		m_flotas[bando][i].blindajeIntacto=(int *)calloc(500,sizeof(int));
		m_flotas[bando][i].lineas=(TLinea *)calloc(50,sizeof(TLinea)); m_flotas[bando][i].nLineas=0;
		m_flotas[bando][i].ataques=(int *)calloc(500,sizeof(int));
		m_flotas[bando][i].escudos=(int *)calloc(500,sizeof(int));
		m_flotas[bando][i].blindajes=(int *)calloc(500,sizeof(int));
		for (n=10,iLin=0;n<nToks-3;n+=5,iLin++) {
			// t.Format("Flota %i %s %s*%s",iFlota,toks[0],toks[n],toks[n+1]);
			// log(t);
			gid=atoi(toks[n]);
			m_flotas[bando][i].lineas[iLin].gid=gid;
			m_flotas[bando][i].ataques[gid]=m_flotas[bando][i].lineas[iLin].ataques=atoi(toks[n+2]);
			m_flotas[bando][i].escudos[gid]=m_flotas[bando][i].lineas[iLin].maxEscudo=atoi(toks[n+3]);
			m_flotas[bando][i].blindajes[gid]=m_flotas[bando][i].lineas[iLin].maxBlindaje=atoi(toks[n+4]);
			m=atoi(toks[n+1]);
			m_flotas[bando][i].lineas[iLin].nGrupoOrig=m;
			m=m/m_batDivisor;
			if (!m) m=1;
			m_totNaves+=m;
			if (!bando) navesA+=m;
			else navesD+=m;
			m_flotas[bando][i].lineas[iLin].nGrupo=m_flotas[bando][i].lineas[iLin].nGrupoOrigDiv=m;
			if (m<5000000 && !bEstampadaSondas) { // Lineal
				m_flotas[bando][i].lineas[iLin].maxGrupos=-1;
				m_flotas[bando][i].lineas[iLin].grupos=(TNave *)calloc(m ? m:1,sizeof(TNave));
				m_flotas[bando][i].lineas[iLin].grupos[0].nGrupo=1;
				m_flotas[bando][i].lineas[iLin].grupos[0].blindaje=m_flotas[bando][i].lineas[iLin].maxBlindaje;
				for (j=1;j<m;j++) memcpy(&m_flotas[bando][i].lineas[iLin].grupos[j],&m_flotas[bando][i].lineas[iLin].grupos[0],sizeof(TNave));
				m_flotas[bando][i].lineas[iLin].nGrupos=m;
			} else { // Agrupado
				m_flotas[bando][i].lineas[iLin].maxGrupos=100;
				m_flotas[bando][i].lineas[iLin].grupos=(TNave *)calloc(100,sizeof(TNave));
				m_flotas[bando][i].lineas[iLin].grupos[0].nGrupo=m_flotas[bando][i].lineas[iLin].nGrupo;
				m_flotas[bando][i].lineas[iLin].grupos[0].blindaje=m_flotas[bando][i].lineas[iLin].maxBlindaje;
				m_flotas[bando][i].lineas[iLin].nGrupos=1;
				if (!bando && bEstampadaSondas) m_flotas[bando][i].lineas[iLin].grupos[0].blindaje=-1,m_flotas[bando][i].lineas[iLin].grupos[0].rondaMuerta=1;
			}
		}
		m_flotas[bando][i].nLineas=iLin;
		m_nFlotas[bando]++;
		reporte+="/"+toks[0]; for (n=2;n<=7;n++) reporte+="/"+toks[n];
		delete []toks;
	}
	delete []flotaStr;

	int ganador=0,ronda=1;
	int bAtaque=0;

	if (bEstampadaSondas) ganador=2,ronda=2;

//	fin=GetTickCount(); t.Format(_T("call cronoIns('%s',%f);"),_T("IniRondas"),(fin-inicio)/1000.0); log(t);
	for (;ronda<=7 && !ganador;ronda++) {
		TNave *iNave;
		//t.Format("Ronda %i ",ronda); 
		// log(t);
		m_navBandos[0]=m_navBandos[1]=0;
		for (bando=0;bando<=1;bando++) {
			for (iFlota=0;iFlota<m_nFlotas[bando];iFlota++) {
				for (iLin=0;iLin<m_flotas[bando][iFlota].nLineas;iLin++) {
					m_flotas[bando][iFlota].lineas[iLin].nGrupo=0;
					if (ronda==1) m_flotas[bando][iFlota].lineas[iLin].nav2grupos=NULL;
				}
			}
		}
		bAtaque=0;
		// maxEscudos+comprobar ataque
		for (bando=0;bando<=1;bando++) {
			for (iFlota=0;iFlota<m_nFlotas[bando];iFlota++) {
				for (iLin=0;iLin<m_flotas[bando][iFlota].nLineas;iLin++) {
					if (m_flotas[bando][iFlota].lineas[iLin].maxGrupos==-1) { // Lineal
						iNave=m_flotas[bando][iFlota].lineas[iLin].grupos;
						n=m_flotas[bando][iFlota].lineas[iLin].maxEscudo;
						m=0;
						for (i=m_flotas[bando][iFlota].lineas[iLin].nGrupos;i;i--,iNave++) {
							if (iNave->blindaje>=0) {
								iNave->escudo=n;
								m++;
							} else {
								if (!iNave->rondaMuerta) iNave->rondaMuerta=ronda-1;
							}
						}
						m_flotas[bando][iFlota].lineas[iLin].nGrupo=m;
						m_navBandos[bando]+=m;
						if (!bAtaque && !bando && m) bAtaque=m_flotas[bando][iFlota].lineas[iLin].ataques;
					} else {
						if (m_flotas[bando][iFlota].lineas[iLin].nav2grupos) { 
							free(m_flotas[bando][iFlota].lineas[iLin].nav2grupos);
							m_flotas[bando][iFlota].lineas[iLin].nav2grupos=NULL;
						}
						for (i=0;i<m_flotas[bando][iFlota].lineas[iLin].nGrupos;i++) {
							iNave=&m_flotas[bando][iFlota].lineas[iLin].grupos[i];
							if (iNave->blindaje>=0) {
								iNave->escudo=m_flotas[bando][iFlota].lineas[iLin].maxEscudo;
								m_flotas[bando][iFlota].lineas[iLin].nGrupo+=iNave->nGrupo;
								m_navBandos[bando]+=iNave->nGrupo;
								if (!bAtaque && !bando) bAtaque=m_flotas[bando][iFlota].lineas[iLin].ataques;
							} else {
								if (!iNave->rondaMuerta) iNave->rondaMuerta=ronda-1;
							}
						}
						qsort(&m_flotas[bando][iFlota].lineas[iLin].grupos[0],m_flotas[bando][iFlota].lineas[iLin].nGrupos,sizeof(TNave),orden4);
						for (n=0,i=1;i<m_flotas[bando][iFlota].lineas[iLin].nGrupos;i++) {
							if (m_flotas[bando][iFlota].lineas[iLin].grupos[i].nGrupo) {
								if (!m_flotas[bando][iFlota].lineas[iLin].grupos[i].rondaMuerta 
									&& !m_flotas[bando][iFlota].lineas[iLin].grupos[n].rondaMuerta
									&& m_flotas[bando][iFlota].lineas[iLin].grupos[i].capturada==m_flotas[bando][iFlota].lineas[iLin].grupos[n].capturada
									&& m_flotas[bando][iFlota].lineas[iLin].grupos[i].blindaje==m_flotas[bando][iFlota].lineas[iLin].grupos[n].blindaje) {
										m_flotas[bando][iFlota].lineas[iLin].grupos[n].nGrupo+=m_flotas[bando][iFlota].lineas[iLin].grupos[i].nGrupo;
										m_flotas[bando][iFlota].lineas[iLin].grupos[i].nGrupo=0;
								} else {
									n++;
									if (i!=n) 
										memcpy(&m_flotas[bando][iFlota].lineas[iLin].grupos[n],&m_flotas[bando][iFlota].lineas[iLin].grupos[i],sizeof(TNave));
								}
							}
						}
						m_flotas[bando][iFlota].lineas[iLin].nGrupos=n+1;
					}
				}
			}
		}
		if (!m_navBandos[0]) ganador=2;
		else if (!m_navBandos[1] && bAtaque) ganador=1;
		if (ganador) break;
		if (ronda==7) break;

		if (!batDispara(ronda)) break;
//		fin=GetTickCount(); t.Format(_T("call cronoIns('%s',%f);"),_T("Disparos"),(fin-inicio)/1000.0); log(t);
		if (bAtaque==0 && m_navBandos[1]==0) break; // Empate si nada contra nada, despues de batDispara para q saque disparos en reporte
	}
	//t.Format("Fin de batalla, rondas=%i, atacantes=%i, defensores=%i\r\n",ronda,m_navBandos[0],m_navBandos[1]); 
	// log(t);
	for (bando=0; bando<=1; bando++) 
		for (iFlota=0;iFlota<m_nFlotas[bando];iFlota++)
			navesMuertas(bando,iFlota);
//	fin=GetTickCount(); t.Format(_T("call cronoIns('%s',%f);"),_T("Muertas"),(fin-inicio)/1000.0); log(t);

	for (i=1;i<=ronda;i++) {
		t.Format("/%i",i); reporte+=t;
		for (bando=0;bando<=1;bando++) 
			for (iFlota=0;iFlota<m_nFlotas[bando];iFlota++) 
				reporte+="/"+battFl(bando,iFlota,i==1,i);
		if ((ganador && i==ronda) || i==7) break;
		for (n=0;n<2;n++) {
			t.Format("/%s/%I64i/%I64i/%I64i",n ? "DD":"DA",m_rondas[i].disparos[n],m_rondas[i].fuerza[n],m_rondas[i].absor[n]);
			reporte+=t;
		}
	}
	i=reporte.GetLength();
	t.Format("/F/%i",ganador); reporte+=t;
//	fin=GetTickCount(); t.Format(_T("call cronoIns('%s',%f);"),_T("Info1"),(fin-inicio)/1000.0); log(t);
	if (ganador==1) {
		// Robo
		t.Format("%i",idF);
		t=theApp.callRobo(t);
		toks=split("|",t,n);
		reporte+="/R";
		for (i=0;i<n;i++) reporte+="/"+toks[i];
		delete []toks;
	}
	t.Format("/PA/%I64i",m_perdidas[0]);
	reporte+=t;
	t.Format("/PD/%I64i",m_perdidas[1]);
	reporte+=t;
	t.Format("/ES/%I64i/%I64i",m_escombros[0],m_escombros[1]);
	reporte+=t;
	__int64 esc=m_escombros[0] +m_escombros[1];
	int diamLuna=0,porcLuna;
	if (lunable && esc>=escombros1pc) {
		if (esc>20*escombros1pc) porcLuna=20;
		else porcLuna=(int)(esc/escombros1pc);
		porcLuna=porcLuna > 20 ? 20:porcLuna;
		t.Format("/L/%i",porcLuna); reporte+=t;
		// Check creacion luna
		do {
			if ((rand()*1.0/RAND_MAX)<porcLuna/100.0) {
				reporte+="/NL";
				diamLuna=400*porcLuna;
				break;
			}
		} while (talismanes--);
	}
//	fin=GetTickCount(); t.Format(_T("call cronoIns('%s',%f);"),_T("Info2"),(fin-inicio)/1000.0); log(t);
	if (reporte.GetLength()>1024) {
		theApp.callProc("reporteIni","","reporteIni");
		for (i=0;i<reporte.GetLength();i+=1024) 
			theApp.callProc("reporteAdd","'"+reporte.Mid(i,1024)+"'","reporteAdd");
		reporte="REPORTE";
	}


	t.Format("%i,%i,'%s',%I64i,%I64i,%I64i,%I64i,%i,%i",
		idF,ganador,reporte,m_escombros[0],m_escombros[1],m_perdidas[0],m_perdidas[1],diamLuna,ronda);
	theApp.callProc("eg_FinBatalla",t,"eg_FinBatalla");
//	fin=GetTickCount(); t.Format(_T("call cronoIns('%s',%f);"),_T("Fin"),(fin-inicio)/1000.0); log(t);
	log("Finalizado\r\n");
	for (bando=0;bando<2;bando++) {
		for (iFlota=0;iFlota<m_nFlotas[bando];iFlota++) {
			for (iLin=0;iLin<m_flotas[bando][iFlota].nLineas;iLin++) {
				delete []m_flotas[bando][iFlota].lineas[iLin].grupos;
			}
			delete []m_flotas[bando][iFlota].capturas;
			delete []m_flotas[bando][iFlota].lineas;
			delete []m_flotas[bando][iFlota].ataques;
			delete []m_flotas[bando][iFlota].escudos;
			delete []m_flotas[bando][iFlota].blindajes;
		}
		delete []m_flotas[bando];
	}

	fin=GetTickCount();
	t.Format(_T("'Batalla',%f"),(fin-inicio)/1000.0);
	theApp.callProc("cronoIns",t,"cronos");
	log(t);
}

CString CMotor4::battFl(int bando,int iFlota,bool bExtraInfo,int ronda)
{
	int *gids=(int *)calloc(600,sizeof(int));
	int *tot=(int *)calloc(600,sizeof(int));
	int *nGrupo=(int *)calloc(600,sizeof(int));
	int *nOrig=(int *)calloc(600,sizeof(int));

	int nNave,i,iLin;
	for (iLin=0;iLin<m_flotas[bando][iFlota].nLineas;iLin++) {
		nGrupo[m_flotas[bando][iFlota].lineas[iLin].gid]+=m_flotas[bando][iFlota].lineas[iLin].nGrupoOrigDiv;
		nOrig[m_flotas[bando][iFlota].lineas[iLin].gid]+=m_flotas[bando][iFlota].lineas[iLin].nGrupoOrig;
		for (nNave=0;nNave<m_flotas[bando][iFlota].lineas[iLin].nGrupos;nNave++) {
			TNave *iNave=&m_flotas[bando][iFlota].lineas[iLin].grupos[nNave];
			if (bExtraInfo) {
				if (iNave->rondaMuerta)
					tot[m_flotas[bando][iFlota].lineas[iLin].gid]+=iNave->nGrupo;
			}
			if (!iNave->rondaMuerta || iNave->rondaMuerta>=ronda) 
				gids[m_flotas[bando][iFlota].lineas[iLin].gid]+=iNave->nGrupo;
		}
	}
	if (m_batDivisor>1) {
		for (i=0;i<600;i++) {
			if (nOrig[i]) {
				if (tot[i]==nGrupo[i]) tot[i]=nOrig[i];
				else tot[i]*=m_batDivisor;
				if (gids[i]==nGrupo[i]) gids[i]=nOrig[i];
				else gids[i]*=m_batDivisor;
			}
		}
	}
	CString ret,t;
	for (i=0;i<600;i++) if (gids[i]) { t.Format("%i/",i); ret+=t; }
	if (ret=="") {
		ret="0";
	} else {
		ret+="/";
		for (i=0;i<600;i++) if (gids[i]) { t.Format("%i/",gids[i]); ret+=t; }
		ret+="/";
		if (bExtraInfo) {
			for (i=0;i<600;i++) if (gids[i]) { t.Format("%i/",m_flotas[bando][iFlota].ataques[i]); ret+=t; }
			ret+="/";
			for (i=0;i<600;i++) if (gids[i]) { t.Format("%i/",m_flotas[bando][iFlota].escudos[i]); ret+=t; }
			ret+="/";
			for (i=0;i<600;i++) if (gids[i]) { t.Format("%i/",m_flotas[bando][iFlota].blindajes[i]); ret+=t; }
			ret+="/";
			for (i=0;i<600;i++) if (gids[i]) { t.Format("%i/",tot[i]); ret+=t; }
			ret+="/";
			if (m_flotas[bando][iFlota].vPerdidas) { t.Format("P/%I64i/",m_flotas[bando][iFlota].vPerdidas); ret+=t; }
			if (m_flotas[bando][iFlota].vCapturas) { t.Format("C/%I64i/",m_flotas[bando][iFlota].vCapturas); ret+=t; }
		}
	}
	free(gids); free(tot); 
	return ret;
}

void CMotor4::init(void) 
{
	CRecordset r(&theApp.m_db);
	CDBVariant v;
	m_pFuegoRapido=(int **)calloc(300,sizeof(int *));
	for (int i=0;i<300;i++) m_pFuegoRapido[i]=NULL;
	r.Open(-1,_T("select * from fuegoRapido"));
	while (!r.IsEOF()) {
//		r.GetFieldValue((short)0,v);
		r.GetFieldValue((short)0,v,SQL_C_SLONG);
		int gidA=v.m_iVal;
		if (!m_pFuegoRapido[gidA-200]) m_pFuegoRapido[gidA-200]=(int *)calloc(300,sizeof(int));
		r.GetFieldValue(1,v,SQL_C_SLONG);
		int gidD=v.m_iVal;
		r.GetFieldValue(2,v,SQL_C_SLONG);
		int n=v.m_iVal;
		m_pFuegoRapido[gidA-200][gidD-200]=n;
		r.MoveNext();
	}
	r.Close();
	log(_T("Cargados fuegos rápidos\r\n"));

	m_costes=(TCoste *)calloc(300,sizeof(TCoste));
	r.Open(-1,_T("select gid,costeM_gid,costeC_gid,costeD_gid from gids where gid between 200 and 499"));
	while (!r.IsEOF()) {
		r.GetFieldValue((short)0,v,SQL_C_SLONG);
		int gid=v.m_iVal;
		r.GetFieldValue(1,v,SQL_C_SLONG); 
		m_costes[gid-200].costeM=v.m_lVal;
		r.GetFieldValue(2,v,SQL_C_SLONG); 
		m_costes[gid-200].costeC=v.m_lVal;
		r.GetFieldValue(3,v,SQL_C_SLONG); 
		m_costes[gid-200].costeD=v.m_lVal;
		r.MoveNext();
	}
	r.Close();
	log(_T("Cargados costes\r\n"));
}

void CMotor4::log(CString txt)
{
	theApp.log(txt);
}

void CMotor4::navesMuertas(int bando,int iFlota)
{
	int *muertas=(int *)calloc(600,sizeof(int));
	int *capturadas=(int *)calloc(600,sizeof(int));
	int *grupo=(int *)calloc(600,sizeof(int));
	int *reales=(int *)calloc(600,sizeof(int));
	int nNave,iLin,gid,i;
	__int64 n,muertasi,nPerd;

	for (iLin=0;iLin<m_flotas[bando][iFlota].nLineas;iLin++) {
		for (nNave=0;nNave<m_flotas[bando][iFlota].lineas[iLin].nGrupos;nNave++) {
			gid=m_flotas[bando][iFlota].lineas[iLin].gid;
			TNave *iNave=&m_flotas[bando][iFlota].lineas[iLin].grupos[nNave];
			if (iNave->rondaMuerta) {
				if (iNave->capturada) 
					capturadas[gid]+=iNave->nGrupo;
				else muertas[gid]+=iNave->nGrupo;
			}
		}
		grupo[gid]+=m_flotas[bando][iFlota].lineas[iLin].nGrupoOrigDiv;
		reales[gid]+=m_flotas[bando][iFlota].lineas[iLin].nGrupoOrig;
	}
	CString ret,t,sql;
	for (i=0;i<600;i++) {
		if (muertas[i]+capturadas[i]) { 
			n=(__int64)(muertas[i]+capturadas[i]);
			muertasi=(__int64)muertas[i];
			if (m_batDivisor>1) {
				if (n==grupo[i]) n=reales[i];
				else n*=m_batDivisor;
				if (muertasi==grupo[i]) muertasi=reales[i];
				else muertasi*=m_batDivisor;
			}
			nPerd=n*(m_costes[i-200].costeM+m_costes[i-200].costeC+m_costes[i-200].costeD);
			m_perdidas[bando]+=nPerd;
			m_flotas[bando][iFlota].vPerdidas+=nPerd;
			if (i<400) {
				m_escombros[0]+=(__int64)(muertasi*(m_costes[i-200].costeM*m_porcEscombros));
				m_escombros[1]+=(__int64)(muertasi*(m_costes[i-200].costeC*m_porcEscombros));
			} else {
				m_escombros[0]+=(__int64)(muertasi*(m_costes[i-200].costeM*m_defEscombros));
				m_escombros[1]+=(__int64)(muertasi*(m_costes[i-200].costeC*m_defEscombros));
			}
			sql.Format("'%c',%i,%i,%i",
				m_flotas[bando][iFlota].tipoIdPlan,m_flotas[bando][iFlota].idJuego,i,n);
			theApp.callProc("eg_FinBatFl",sql,"FinBatFl");
		}
	}
	for (i=0;i<500;i++) {
		if(n=m_flotas[bando][iFlota].capturas[i]) {
			if (m_batDivisor>1) {
				if (n==grupo[i]) n=reales[i];
				else n*=m_batDivisor;
			}
			sql.Format("'%c',%i,%i,%i",
				m_flotas[bando][iFlota].tipoIdPlan,m_flotas[bando][iFlota].idJuego,i,-n);
			m_flotas[bando][iFlota].vCapturas+=(__int64)(n*(m_costes[i-200].costeM+m_costes[i-200].costeC+m_costes[i-200].costeD));
			theApp.callProc("eg_FinBatFl",sql,"FinCapturas");
		}
	}
	sql.Format("'%c',%i,%i,%i",
		m_flotas[bando][iFlota].tipoIdPlan,m_flotas[bando][iFlota].idJuego,-1,0);
	theApp.callProc("eg_FinBatFl",sql,"FinCapturas");
	free(muertas); free(capturadas);
	free(grupo); free(reales);
}

int CMotor4::fuegoRapido(int gidA,int gidD)
{
	if (!m_pFuegoRapido[gidA-200]) return 0;
	int n=m_pFuegoRapido[gidA-200][gidD-200];
	if (!n) return 0;
	if (!(rand()%n)) {
		return 0;
	}
	return 1;
}

int CMotor4::almacenar(TLinea * pvLinea,TNave *vNave,int iGrV,int iVict,
	int escudo,int blinda,unsigned __int8 capturada) 
{
	int iH,vAGrupo,n,m;
	TIndiceGrupos *pig;
	TNave * tNave;
	if (vNave->blindaje<0) { // Ya estaba muerta de antes
		;
	} else {
		if (pvLinea->maxGrupos==-1) { // Array lineal
			vNave->blindaje=blinda;
			vNave->escudo=escudo;
			vNave->capturada=capturada;
		} else {
			iH=-1; vAGrupo=-1;
			if (vNave->nGrupo==1) {
				n=-1;
				if (pig=pvLinea->indiceGrupos) {
					n=buscaIndiceGrupos(pvLinea->indiceGrupos,pvLinea->nIndiceGrupos,vNave->capturada,vNave->escudo,vNave->blindaje,0,iGrV);
					ASSERT(pvLinea->grupos[pig[n].grupo].blindaje==vNave->blindaje);
					ASSERT(pvLinea->grupos[pig[n].grupo].escudo==vNave->escudo);
					ASSERT(pvLinea->grupos[pig[n].grupo].capturada==vNave->capturada);
					DEBUG_ONLY(checkIndex(pvLinea->indiceGrupos,pvLinea->nIndiceGrupos,pvLinea->grupos));
				}
				vNave->blindaje=blinda;
				vNave->escudo=escudo;
				vNave->capturada=capturada;
				if (n!=-1) {
					m=buscaIndiceGrupos(pvLinea->indiceGrupos,pvLinea->nIndiceGrupos,vNave->capturada,vNave->escudo,vNave->blindaje,-1);
					pig[n].blindaje=blinda;
					pig[n].capturada=capturada;
					pig[n].escudo=escudo;
					moveIndex(pvLinea->indiceGrupos,pvLinea->nGrupos,n,m);
					DEBUG_ONLY(checkIndex(pvLinea->indiceGrupos,pvLinea->nIndiceGrupos,pvLinea->grupos));
				}
			} else {
				if (pvLinea->indiceGrupos) {
					vAGrupo=buscaIndiceGrupos(pvLinea->indiceGrupos,pvLinea->nIndiceGrupos,capturada,escudo,blinda,0);
					if (vAGrupo!=-1) {
						vAGrupo=pvLinea->indiceGrupos[vAGrupo].grupo; tNave=&pvLinea->grupos[vAGrupo];
						n=0;
						if (tNave->escudo == escudo)
						if (tNave->blindaje ==blinda) 
						if (!tNave->rondaMuerta) 
						if (tNave->capturada==capturada) 
							n=1;
						if (n==0) 
							ASSERT(0);
					}
				} else {
					for (vAGrupo=0,tNave=&pvLinea->grupos[0];vAGrupo<pvLinea->nGrupos;vAGrupo++,tNave++) {
						if (!tNave->nGrupo) {
							if (iH==-1) iH=vAGrupo;
						} else {
							if (tNave->escudo == escudo)
							if (tNave->blindaje ==blinda) 
							if (!tNave->rondaMuerta) 
							if (tNave->capturada==capturada) 
								break;
						}
					}
					if (vAGrupo>=pvLinea->nGrupos) vAGrupo=-1;
				}
				if (vAGrupo!=-1) { // traspasar
					pvLinea->grupos[vAGrupo].nGrupo++;
					vNave->nGrupo--;
					if (pvLinea->nav2grupos) pvLinea->nav2grupos[-iVict-1]=vAGrupo;
				} else { // Nuevo grupo
					if (iH==-1) { // no hay sitio, ampliar
						iH=pvLinea->nGrupos;
						pvLinea->nGrupos++;
						if (iH>=pvLinea->maxGrupos) {
							pvLinea->maxGrupos+=1000;
							pvLinea->grupos=(TNave *)realloc(pvLinea->grupos,(pvLinea->maxGrupos)*sizeof(TNave));
							if (!pvLinea->grupos) { log("Sin memoria"); return 0; }
							memset(&pvLinea->grupos[iH],0,1000*sizeof(TNave));
							vNave=NULL; // en principio no me hace falta. Ojo movido
							if (pig=pvLinea->indiceGrupos) {
								pig=(TIndiceGrupos *)realloc(pig,(pvLinea->maxGrupos)*sizeof(TIndiceGrupos));
								if (!pig) free(pvLinea->indiceGrupos);
								pvLinea->indiceGrupos=pig;
							}
						}
					}
					memcpy(&pvLinea->grupos[iH],&pvLinea->grupos[iGrV],sizeof(TNave));
					pvLinea->grupos[iGrV].nGrupo--;
					pvLinea->grupos[iH].nGrupo=1;
					pvLinea->grupos[iH].blindaje=blinda;
					pvLinea->grupos[iH].escudo=escudo;
					pvLinea->grupos[iH].capturada=capturada;
					if (pvLinea->nav2grupos) 
						pvLinea->nav2grupos[-iVict-1]=iH;
					if (pig=pvLinea->indiceGrupos) {
						n=buscaIndiceGrupos(pvLinea->indiceGrupos,pvLinea->nIndiceGrupos,capturada,escudo,blinda,1);
						if (n>0) {
							if ((pig[n-1].blindaje>blinda && pig[n-1].capturada==capturada) || pig[n-1].blindaje<-1) 
								ASSERT(0);
						}
						if (n<pvLinea->nIndiceGrupos-1) {
							if ((pig[n+1].blindaje<blinda && pig[n+1].capturada==capturada) || pig[n+1].blindaje<-1)
								ASSERT(0);
						}


						if (n<pvLinea->nIndiceGrupos) memmove(pig+n+1,pig+n,sizeof(TIndiceGrupos)*(pvLinea->nIndiceGrupos-n));
						pig[n].blindaje=blinda;
						pig[n].escudo=escudo;
						pig[n].capturada=capturada;
						pig[n].grupo=iH;
						pvLinea->nIndiceGrupos++;
						DEBUG_ONLY(checkIndex(pvLinea->indiceGrupos,pvLinea->nIndiceGrupos,pvLinea->grupos));
						ASSERT(n==buscaIndiceGrupos(pvLinea->indiceGrupos,pvLinea->nIndiceGrupos,capturada,escudo,blinda,0,iH));
					}
				}
			}
		}
	}
	return 1;
}

int CMotor4::batDispara(int ronda)
{
	int fuego,fuego2;
	int navesMuertas[2];
	int nGrupo;
	int navesAhorro=0;
	int iH,iVict,bando,fr,n,*pi;

	int iFl,iLin,iGr; TFlotas *pFlota; TLinea *pLinea; TNave *iNave;
	int iFlV,iLiV,iGrV; TFlotas *pvFlota; TLinea *pvLinea; TNave * vNave;
	TIndiceGrupos *pig;

	unsigned __int8 capturada;
	bool bMuerta;
	TRondas *pRonda=&m_rondas[ronda];
	DWORD inicio,fin;

	pRonda->n=ronda;
	pRonda->disparos[0]=pRonda->disparos[1]=0;
	pRonda->fuerza[0]=pRonda->fuerza[1]=0;
	pRonda->absor[0]=pRonda->absor[1]=0;
	navesMuertas[0]=navesMuertas[1]=0;
	for (bando=0;bando<2;bando++) {
		TRACE("Ronda %d bando %d",ronda,bando);
		inicio=GetTickCount();
		for (iFl=0;iFl<m_nFlotas[1-bando];iFl++) {
			pFlota=&m_flotas[1-bando][iFl];
			for (iLin=0;iLin<pFlota->nLineas;iLin++) {
				pLinea=&pFlota->lineas[iLin];
				pLinea->nav2grupos=NULL;
				if (pLinea->nGrupo>=10000000) TRACE(" Uf(%d)",pLinea->nGrupo);
				if (pLinea->maxGrupos==-1) { // Array lineal de naves
					pLinea->indiceGrupos=NULL;
					n=sizeof(int)*pLinea->nGrupo;
					pi=pLinea->nav2grupos=(int *)malloc(n);
					if (pi) {
						for (iGrV=0;iGrV<pLinea->nGrupos;iGrV++) {
							if (!pLinea->grupos[iGrV].rondaMuerta)
								*(pi++)=iGrV;
						}
					}
				} else { // Naves agrupadas
					if (pLinea->nGrupo<25000000 && pLinea->nGrupo>0) { // Array directo
						n=sizeof(int)*pLinea->nGrupo;
						pi=pLinea->nav2grupos=(int *)malloc(n);
						if (pi) {
							for (iGrV=0;iGrV<pLinea->nGrupos;iGrV++) {
								if (!pLinea->grupos[iGrV].rondaMuerta)
									for (n=pLinea->grupos[iGrV].nGrupo;n;n--) *(pi++)=iGrV;
							}
						}
						n=sizeof(TIndiceGrupos)*pLinea->maxGrupos;
						pig=pLinea->indiceGrupos=(TIndiceGrupos *)malloc(n);
						pLinea->nIndiceGrupos=0;
						if (pig) {
							for (iGrV=0;iGrV<pLinea->nGrupos;iGrV++) {
								if (!pLinea->grupos[iGrV].rondaMuerta) {
									pig[iGrV].blindaje=pLinea->grupos[iGrV].blindaje;
									pig[iGrV].escudo=pLinea->grupos[iGrV].escudo;
									pig[iGrV].capturada=pLinea->grupos[iGrV].capturada;
								} else {
									pig[iGrV].blindaje=0;
									pig[iGrV].escudo=0;
									pig[iGrV].capturada=-1; // que no se mezcle con otros grupos
									pig[iGrV].grupo=iGrV;
								}
								pig[iGrV].grupo=iGrV;
								pLinea->nIndiceGrupos++;
							}
							qsort(pig,pLinea->nIndiceGrupos,sizeof(TIndiceGrupos),ordenIndice);
						}
					}
				}
			}
		}
		for (iFl=0;iFl<m_nFlotas[bando];iFl++) {
			pFlota=&m_flotas[bando][iFl];
			for (iLin=0;iLin<pFlota->nLineas;iLin++) {
				pLinea=&pFlota->lineas[iLin];
				for (iGr=0;iGr<pLinea->nGrupos;iGr++) {
					iNave=&pLinea->grupos[iGr];
					if (!iNave->rondaMuerta) {
						if (navesMuertas[1-bando]>=m_navBandos[1-bando]) continue; // No hay naves enemigas vivas, paso
						nGrupo=iNave->nGrupo; if (!nGrupo) nGrupo=1;
						ASSERT(nGrupo>=0);
						for (;nGrupo;nGrupo--) {
							fuego=fuego2=m_flotas[bando][iFl].lineas[iLin].ataques;
							if (!fuego) break;
							for (fr=0;;fr++) {
								fuego=fuego2=m_flotas[bando][iFl].lineas[iLin].ataques;
								iVict=rand();
								if (m_navBandos[1-bando]>RAND_MAX) iVict=iVict*(1+RAND_MAX)+rand(); 
								iVict%=m_navBandos[1-bando];
								iH=iVict;
								iVict=iH;

								for (iFlV=0;iFlV<m_nFlotas[1-bando];iFlV++) {
									pvFlota=&m_flotas[1-bando][iFlV];
									for (iLiV=0;iLiV<pvFlota->nLineas;iLiV++) {
										pvLinea=&pvFlota->lineas[iLiV];
										if (pvLinea->nGrupo>iVict) {
											if (pvLinea->maxGrupos==-1) { //Array lineal
												iGrV=pvLinea->nav2grupos[iVict];
												iVict=-1;
											} else {
												if (pvLinea->nav2grupos) {
													iGrV=pvLinea->nav2grupos[iVict];
													iVict=-iVict-1;
												} else {
													n=0;
													for (iGrV=0;iGrV<pvLinea->nGrupos;iGrV++) {
														if (!pvLinea->grupos[iGrV].rondaMuerta) {
															iVict-=pvLinea->grupos[iGrV].nGrupo;
															n+=pvLinea->grupos[iGrV].nGrupo;
															if (n>pvLinea->nGrupo)
																ASSERT(0);
															if (iVict<0) break;
														}
														else 
															iVict=iVict;
													}
												}
											}
											if (iVict>=0)
												ASSERT(0);
											if (iVict<0) break;
										} else {
											iVict-=pvLinea->nGrupo;
										}
									}
									if (iVict<0) break;
								}
								if (pvLinea->maxGrupos==-1) vNave=&pvLinea->grupos[iGrV];
								else vNave=&m_flotas[1-bando][iFlV].lineas[iLiV].grupos[iGrV];
								// mina térmica
								if (pLinea->gid==223) {
									// victima coste igual o inferior a crucero
									if (m_costes[pvLinea->gid-200].costeM+m_costes[pvLinea->gid-200].costeC+m_costes[pvLinea->gid-200].costeD<=29000) {
										fuego=fuego2=2*(vNave->escudo+vNave->blindaje);
										almacenar(pLinea,iNave,iGr,-iGr-1,0,-1,0); 
										navesMuertas[bando]++;
									} else {
										fuego=fuego2=0;
									}
								}
								pRonda->disparos[bando]++;
								pRonda->fuerza[bando]+=fuego;
								int escudo,blinda,maxBlinda,maxEscudo;
								capturada=vNave->capturada;
								maxEscudo=pvLinea->maxEscudo;
								maxBlinda=pvLinea->maxBlindaje;
								escudo=vNave->escudo;
								blinda=vNave->blindaje;
								if (escudo>0) {
									if (fuego<escudo) {
										pRonda->absor[bando]+=fuego;
									} else {
										pRonda->absor[bando]+=escudo;
									}
								}
								if (fuego<escudo) {
									int perc=(int)((100.0*fuego)/maxEscudo);
									fuego=maxEscudo*perc;
									fuego/=100;
									fuego2=fuego;
								}
								if (escudo<=0 || fuego>0) {
									fuego-=escudo;
									escudo-=fuego2;
									if (fuego<0) fuego=0;
								} else fuego=0;
								if (escudo<0) escudo=0;
								bMuerta=false;
								if (fuego>0) {
									if (blinda>=0) {
										if ((blinda-=fuego)<0) blinda=-1;
										else {
											if (blinda<0.7*maxBlinda) {
												if ((rand()%100) >(100*blinda)/maxBlinda) blinda=-1;
											}
										}
										if (blinda==-1) { // Nave murio con este disparo
											if (pLinea->gid==222 && pvLinea->gid<400 && pvLinea->gid!=212 && pvLinea->gid!=223) { // y no es defensa ni sat ni mina
												capturada=1;
												pFlota->capturas[pvLinea->gid]++;
											}
											navesMuertas[1-bando]++;
											bMuerta=true;
										}
									}
								}
								if (!almacenar(pvLinea,vNave,iGrV,iVict,escudo,blinda,capturada)) return 0;
								if (bMuerta) {
									if (navesMuertas[1-bando]>=m_navBandos[1-bando]) {
										// Cortar iteraciones, ya no quedan enemigas
										 nGrupo=1; // Salir del bucle de naves atacantes agrupadas
										 break; // Salir de fuegos rápidos
									}
								}
								if (!fuegoRapido(pLinea->gid,pvLinea->gid)) break;
							}
						}
					}
				}
			}
		}
		for (iFl=0;iFl<m_nFlotas[1-bando];iFl++) {
			pFlota=&m_flotas[1-bando][iFl];
			for (iLin=0;iLin<pFlota->nLineas;iLin++) {
				pLinea=&pFlota->lineas[iLin];
				if (pLinea->nav2grupos) free(pLinea->nav2grupos);
				pLinea->nav2grupos=NULL;
				if (pLinea->indiceGrupos) free(pLinea->indiceGrupos);
				pLinea->indiceGrupos=NULL;
			}
		}
		fin=GetTickCount();
		TRACE(" %f secs\n",(fin-inicio)/1000.0);
	}
	return 1;
}
Mmmm ¿qué me queda?

Ah, sí, los fuegos rápidos. Se cargan una sola vez al inicio del programa, y son un array tal que m_pFuegoRapido[atacante-200][defensor-200]=fuegoRápido. El -200 es porque las naves están numeradas a partir del 200, y no es plan de gastar memoria para guardar fuegos rápidos de edificios.

Y por cierto, la parte de guardar en memoria la representación de las naves y su agrupación por daño sufrido durante la batalla... es un dolor. Me puse ciego a porros para hacerlo, así que si no lo entendéis ya sabéis el método xD Como pista, hay dos o tres formas de guardar la batalla en memoria según lo grande que sea, pues las formas más eficientes en velocidad gastan más memoria, y viceversa. Así que el programa estima y decide por una de ellas. Y la de batallas realmente grandes, es realmente complicada xD
Bueno, creo que está completo el código, así que debería funcionar sin problemas.

Hale, ya tenéis comida. Ahora respondo personales :)
Veo que nos has puesto todo el codigo (facil de traducir a otros lenguajes), pero no has dado ninguna descripción de las estructuras de datos que usa el motor de batallas. Con esa estructura, podría usar una traducción del codigo adaptada a los datos de un formulario de simulacion, creando un programa offline que simule combates.
asturcon3
Site Admin
Site Admin
Mensajes: 6211
Registrado: 12 Nov 2007 14:36
Alianza: aSACo, ofcourse

Re: Motor de batallas, código fuente (muy técnico me temo)

Mensaje por asturcon3 »

no has dado ninguna descripción de las estructuras de datos que usa el motor de batallas
La de veces que me lo has tenido que decir para que me enterara de lo que me pedías xD

Lo acabo de añadir al primer post, abajo del todo :)
Imagen
5aMu
Mensajes: 673
Registrado: 13 Mar 2009 16:58

Re: Motor de batallas, código fuente (muy técnico me temo)

Mensaje por 5aMu »

OGarena no es un xnova y se distingue con únicamente entrar 5 segundos al juego. Sólo con esto ya demuestras tus grandes conocimientos del lenguaje ;)
Imagen

Primer juego basado en el proyecto Xnova Francés equiparable con OGarena u OGame.
No te olvides de visitar nuestro nuevo Universo Zeus, el primero con un impresionante final...
adri93
Mensajes: 4
Registrado: 23 Ago 2009 01:01

Re: Motor de batallas, código fuente (muy técnico me temo)

Mensaje por adri93 »

Bueno, decir que me quede leyendo por la pagina 2 y creo que el tio ese pesado solo quiere robarle el codigo a asturcon :D

PD a asturcon:Esta bonito el codigo, xD Siempre tuve curiosidad por verlo ;)
Responder