git » fp-git.git » commit 9cc719e

initial add

author ecalot
2004-06-20 20:28:30 UTC
committer ecalot
2004-06-20 20:28:30 UTC
parent b45fb54eedef73640e78cfc6f55980ef51f009aa

initial add

FP/src/res/maps.c +870 -0

diff --git a/FP/src/res/maps.c b/FP/src/res/maps.c
new file mode 100644
index 0000000..8e62ddd
--- /dev/null
+++ b/FP/src/res/maps.c
@@ -0,0 +1,870 @@
+/***************************************************************\
+|                           Prototipos                          |
+\***************************************************************/
+
+	//File management procedures
+	char mLoadPED(char* vFile,tLevel* lev);
+	char mLoadDAT(char* vFile,tLevel* lev,char levelNumber); //Tested 5
+	char mSavePED(char* vFile,tLevel* lev); //Tested 8
+	char mSaveDAT(char* vFile,tLevel* lev); //Tested 3
+
+	//char mChangeLevel(tLevel* lev,char newLevel); //0 si no hay cambios; si hay cambios en paredes devuelve la camtidad de paredes cambiadas
+	//char mAllowedOn(char levelnumber,char wall); //1 si wall es permitido en levelnumber; 0 si no
+
+	//Information methods
+	void mSetText (tLevel* lev,char* text);
+	void mGetText (tLevel* lev,char* text);
+
+	//tLevel Set methods
+	void mSetWall (tLevel* lev,char pantalla,char p,char b,char valor);
+	void mSetLink (tLevel* lev,char pantalla,char tipo,char valor);
+	void mSetGuard(tLevel* lev,char pantalla,char p,char b,char vidas,char color,char sentido,char erase);
+	void mSetBack (tLevel* lev,char pantalla,char p,char b,char valor);
+	//tLevel Get Methods
+	char mGetWall (tLevel* lev,char pantalla,char p,char b);
+	char mGetLink (tLevel* lev,char pantalla,char tipo);
+	void mGetGuard(tLevel* lev,char pantalla,char* p,char* b,char* vidas,char* color,char* sentido,char* erase);
+	char mGetBack (tLevel* lev,char pantalla,char p,char b);
+
+	//Gate handling Methods
+	/*
+	Public:
+	mCreateEventList
+	mAddToEventList
+	mGetEventList
+	mRemFromEventList
+	mRemoveEventList
+
+	Private:
+
+	mSaveEventList
+	mLoadEventList
+	*/
+
+
+	//Screen Links Handling Methods
+	char mGetScreen    (tLevel* lev, char i,char j, char* error);
+	void mGetMainScreen(tLevel* lev, char* i,char* j);
+	void mRemScreen    (tLevel* lev, char i,char j, char* error);
+	void mAddScreen    (tLevel* lev, char i,char j, char* error);
+	void mGetSize      (tLevel* lev, char* i,char* j);
+	char mGetScrCount  (tLevel* lev);
+		//Nota: si mGetScrCount(lev) es 24, entonces el nivel esta lleno
+	void mCpyScreen    (tLevel* lev, char fromi,char fromj,char toi,char toj, char* error);
+
+	//Start position handling
+	void mGetStartPosition(tLevel* lev,char* pantalla, char* p, char *b,char *sentido,char *sentido2);
+	void mSetStartPosition(tLevel* lev,char pantalla, char p, char b,char sentido,char sentido2);
+	void mGetDebugPosition(tLevel* lev,char* pantalla, char* p, char *b,char *sentido);
+	void mSetDebugPosition(tLevel* lev,char pantalla, char p, char b,char sentido);
+		//Nota: DebugPosition puede no existir en lev, en ese caso la convension es no existe si pantalla igual a 0, de lo contrario existe y la pantalla inicial es pantalla
+
+/***************************************************************\
+|                  I M P L E M E N T A T I O N                  |
+\***************************************************************/
+
+/*
+	Se utilizan partes del archivo como validadores, texto aparte,
+	etc. Aparentemente es texto desperdiciado, no se detectaron
+	cambios en el comportamiento de los niveles.
+*/
+
+/***************************************************************\
+|                Private memory stream handling                 |
+\***************************************************************/
+
+void mSetArray(tLevel* lev, char *pos,int from,unsigned int length,int validator) {
+	char validate=0;
+	while (length--) {
+		validate+=((*lev).levelArray[from]-pos[length]);
+		(*lev).levelArray[from++]=pos[length];
+	}
+	(*lev).levelArray[validator]+=validate;
+}
+
+void mGetArray(tLevel* lev, char *pos,int from,int length) {
+	while (length--) pos[length]=(*lev).levelArray[from++];
+}
+
+/***************************************************************\
+|                         Gate handling                         |
+\***************************************************************/
+
+//Privados
+void getRawEvent(tLevel* lev,char id,tGateEvent* event) { //private
+	unsigned char x1,x2,valor;
+	(*event).pos[0]  =(*lev).levelArray[MAPS_BLOCK_OFFSET_GATE_1+id];
+	(*event).pos[1]  =(*lev).levelArray[MAPS_BLOCK_OFFSET_GATE_2+id];
+}
+
+void setRawEvent(tLevel* lev,char id,tGateEvent* event) { //private
+	unsigned char x1,x2,validate;
+	x1=(*event).pos[0];
+	x2=(*event).pos[1];
+	validate  =((*lev).levelArray[MAPS_BLOCK_OFFSET_GATE_1+id]-x1)+((*lev).levelArray[MAPS_BLOCK_OFFSET_GATE_2+id]-x2);
+
+	(*lev).levelArray[MAPS_BLOCK_OFFSET_GATE_1+id]=x1;
+	(*lev).levelArray[MAPS_BLOCK_OFFSET_GATE_2+id]=x2;
+	(*lev).levelArray[MAPS_BLOCK_OFFSET_VALIDATOR_WALL]+=validate;
+}
+
+//Privado, pero publico dentro de maps.c
+void mLoadEventList(tLevel* lev) {
+	//Esta funcion carga el TDA con los datos que lee del rigido
+	char a=0;
+	char b=0;
+
+	//Cargar gateList con las asociaciones del mapa
+	int j=0;
+	for (int i=0;i<MAPS_BLOCK_SIZEOF_WALL;i++) {
+		switch ((*lev).levelArray[MAPS_BLOCK_OFFSET_WALL+i]) {
+			case MAPS_OBJ_BAL_D:
+			case MAPS_OBJ_BAL_U:
+				(*lev).gateList.item[j].door=i;
+				(*lev).gateList.item[j++].id=(*lev).levelArray[MAPS_BLOCK_OFFSET_BACK+i];
+		}
+	}
+	(*lev).gateList.size=j;
+
+	//Cargar gateTDA con datos de la tabla
+	j=0;
+	for (tGateEvent evento;j<MAPS_BLOCK_SIZEOF_GATE;j++) {
+		getRawEvent(lev,j,&evento);
+		if (evento.pos[0]>=(0x80)) {
+			(*lev).gateTDA.row[a].size=b;
+			b=0;
+			a++;
+		} else {
+			b++;
+		}
+		(*lev).gateTDA.row[a].event[b]=evento;
+	}
+	(*lev).gateTDA.size=a;
+}
+
+//mSevEventList private functions
+
+void anularEvento(tGateEvent *e) {
+	(*e).pos[0]=0;
+	(*e).pos[1]=0;
+}
+
+char obtenerFila(tGateRow *fila,unsigned char c,int k,tLevel* lev) {
+	char aux=((*lev).gateTDA.row[k].size==c);
+	if (aux) {
+		*fila=(*lev).gateTDA.row[k];
+	}
+	return aux;
+}
+
+char sameEvent(tGateEvent event1,tGateEvent event2) {
+	return ((event1.pos[1]==event2.pos[1]) && ((event1.pos[0]%0x80)==(event1.pos[0]%0x80)));
+}
+
+tGateEvent setFlag(tGateEvent evento,char flag) {
+	evento.pos[0]=(evento.pos[0]%0x80)+(0x80*flag);
+	return evento;
+}
+
+#define MAPS_GATE_DIFFERS 0
+#define MAPS_GATE_EQUALS  1
+#define MAPS_GATE_BELONGS 2
+
+char belongsToDiskList(tLevel* lev, tGateRow *fila,int i) {
+	tGateEvent evento;
+
+	char total=0;
+	char pertenece;
+	//recorrer la lista de eventos
+	for (int k=i;((*lev).gateEvents.event[k].pos[0]<(0x80));k++) {
+		total++;
+		pertenece=0;
+		for (char j=0;(j<(*fila).size) && (!pertenece);j++) {
+			pertenece=(sameEvent((*fila).event[j],(*lev).gateEvents.event[k]));
+		}
+		if (!pertenece) {
+			return MAPS_GATE_DIFFERS;
+		}
+	}
+	if (total==(*fila).size) {
+		return MAPS_GATE_EQUALS;
+	} else {
+		return MAPS_GATE_BELONGS;
+	}
+}
+
+void apuntar(tLevel* lev,unsigned char i) {
+	(*lev).gateList.item[(*lev).gateList.size].id=i;
+	(*lev).gateList.size++;
+}
+
+#define MAPS_GATE_SINGLE_EVENT    0
+#define MAPS_GATE_MULTIPLE_EVENT  1
+char intertLeft(tLevel* lev,tGateRow fila,int inicioFila,int numeroFila,char mode) {
+	//Esta funcion inserta en gateEvents el o los eventos de fila que no estan insertados
+	//Por cada insersion deben ser modificados los ids correspondientes en la gateList
+	//devuelve 1 si entro
+	//devuelve 0 en caso de superarse lso 256 bytes
+
+	/*
+	 1) En caso de MULTIPLE EVENT los elementos de la fila
+	    que ya estan enliastados en gateEvents deben ser
+	    eliminados de la fila. Se coloca el evento nulo en
+	    reemplazo de estos.
+	*/
+
+	char j,pertenece;
+	if (mode==MAPS_GATE_MULTIPLE_EVENT) {
+		for (int k=inicioFila;((*lev).gateEvents.event[k].pos[0]<(0x80));k++) {
+			pertenece=0;
+			for (j=0;(j<fila.size) && (!pertenece);j++) {
+				pertenece=(sameEvent(fila.event[j],(*lev).gateEvents.event[k]));
+			}
+			if (pertenece) {
+				anularEvento(&(fila.event[j]));
+			}
+		}
+	}
+
+	/*
+	 2) En caso de MAPS_GATE_SINGLE_EVENT el ultimo debe
+	    marcar fin de la lista. A tal fin, cambiaremos ese
+	    flag del evento. Como la inserion se hara de adelante
+	    hacia atras, simplemente debemos setear el flag al
+	    principio
+	*/
+
+	int c=(mode==MAPS_GATE_SINGLE_EVENT);
+
+	/*
+	 3) Se debera iterar para toda la fila e insertar
+	    evento por evento en la gateEvents en la posicion inicioFila.
+			Cada insersion implica un corrimiento de ids en la gateList
+	*/
+
+	for (j=0;(j<fila.size);j++) {
+		if (fila.event[j].pos[0]) { //Para cada evento nonulo de la fila
+			//Adelantar todos los eventos posteriores a inicioFila
+			for (int k=(*lev).gateEvents.size;k>inicioFila;k--) {
+				(*lev).gateEvents.event[k+1]=(*lev).gateEvents.event[k];
+			}
+
+			//Insertar (*fila).event[j] en la gateEvents en la posicion generada en inicioFila.
+			//Se tendra en cuenta el flag de de fin de lista
+			(*lev).gateEvents.event[inicioFila]=setFlag(fila.event[j],c);
+
+			//El flag del fin de lista se cancela
+			c=0;
+
+			//Incrementar la cantidad de eventos de la gateEvent, en caso de no poder abortar
+			if ((*lev).gateEvents.size==255) {
+				return 0;
+			} else {
+				(*lev).gateEvents.size++;
+			}
+
+			//Finalmente se debe recorrer la gate list e incrementar el contenido que supere a inicioFila
+			for (int k=0;k<(*lev).gateList.size;k++) {
+				if ((*lev).gateList.item[k].id>=inicioFila)
+					((*lev).gateList.item[k].id)++;
+			}
+		}
+	}
+	return 1;
+}
+
+//Main function
+char mSaveEventList(tLevel* lev) {
+	//Lee el TDA, optimiza el espacio que ocupan los datos y lo guardaen disco
+	//devuelve 1 en caso de que entre en disco
+	//devuelve 0 en caso de que no hayan entrado los datos en disco
+
+	//Inicializar variables
+	unsigned char n=(*lev).gateTDA.size;
+	unsigned char c=1;
+	char x;
+	tGateRow fila;
+	(*lev).gateEvents.size=0;
+	(*lev).gateList.size=0;
+
+	//Generar a partir de gateTDA la lista de eventos gateEventList y de asociaciones gateList
+	while (n) { //Para todos los elementos
+		for (int k=0;k<(*lev).gateTDA.size;k++) { //Recorrer filas de gateTDA
+			if (obtenerFila(&fila,c,k,lev)) {  //mietras haya elementos con tamagno=c sin procesar fila=(*lev).gateTDA.row[n] where fila=(*lev).gateTDA.row[n].size=c;
+				//entra con fila seteada en la fila k con c elementos adentro.
+				n--;
+				x=0;
+				for (int i=0;((i<(*lev).gateEvents.size) && (!x));i++) { //recorrer lo ya creado de gateEvents
+					x=belongsToDiskList(lev,&fila,i);
+					switch (x) {
+						case MAPS_GATE_BELONGS:
+							/*
+							  Pertenece, pero puede que este no sea el principio de la lista
+							  en ese caso no puedo insertar porque corromperia la puerta
+							  anterior, por eso voy a verificar que sea el primero de la lista
+							  o bien que el anterior tenga el flag c.
+							*/
+							if ((i=0) || ((*lev).gateEvents.event[i-1].pos[0]>0x80)) {
+								if (!intertLeft(lev,fila,i,k,MAPS_GATE_MULTIPLE_EVENT)) {
+									return 0;
+								}
+								apuntar(lev,i);
+							}
+							break;
+						case MAPS_GATE_EQUALS:
+							apuntar(lev,i);
+					}
+				}
+				if (!x) {
+					if (!intertLeft(lev,fila,(*lev).gateEvents.size,k,MAPS_GATE_SINGLE_EVENT)) {
+						return 0;
+					}
+				}
+			}
+		}
+		c++;
+	}
+
+	//Guardar gateEvents y gateList en el formato.
+	//gateList
+	for (int i=0;i<(*lev).gateEvents.size;i++) {
+		setRawEvent(lev,i,&((*lev).gateEvents.event[i]));
+	}
+	int location;
+	unsigned char validate=0;
+	for (int i=0;i<(*lev).gateList.size;i++) {
+		location=MAPS_BLOCK_OFFSET_BACK+(*lev).gateList.item[i].door;
+		validate+=(*lev).levelArray[location]-(*lev).gateList.item[i].id;
+		(*lev).levelArray[location]=(*lev).gateList.item[i].id;
+	}
+	(*lev).levelArray[MAPS_BLOCK_OFFSET_VALIDATOR_WALL]+=validate;
+
+	return 1;
+}
+
+void getGateAsociation(tLevel* lev,char id,char* scr,char* p,char* b, char *termino) {
+	unsigned char x1,x2,valor;
+	x1        =(*lev).levelArray[MAPS_BLOCK_OFFSET_GATE_1+id];
+	x2        =(*lev).levelArray[MAPS_BLOCK_OFFSET_GATE_2+id];
+
+	*scr      =(x2/8)+(x1%(0x80))/(0x20);
+	valor     =(x1%(0x20));
+	*b        =(valor%10);
+	*p        =(valor/10);
+	*termino  =(x1/(0x80)); //c=(Se pasa a la siguiente)?0:1
+}
+
+void setGateAsociation(tLevel* lev,char id,char scr,char p,char b, char termino) {
+	unsigned char x1,x2,validate;
+
+	x1        =((scr%4)*0x20)+(p*10+b)+(termino?0x80:0);
+	x2        =((scr/4)*0x20);
+	validate  =((*lev).levelArray[MAPS_BLOCK_OFFSET_GATE_1+id]-x1)+((*lev).levelArray[MAPS_BLOCK_OFFSET_GATE_2+id]-x2);
+
+	(*lev).levelArray[MAPS_BLOCK_OFFSET_GATE_1+id]=x1;
+	(*lev).levelArray[MAPS_BLOCK_OFFSET_GATE_2+id]=x2;
+	(*lev).levelArray[MAPS_BLOCK_OFFSET_VALIDATOR_WALL]+=validate;
+}
+
+void shiftEventId(tLevel* lev,char from,char delta) { //private
+	char validate=0;
+	char aux;
+	for (int i=0;i<MAPS_BLOCK_SIZEOF_WALL;i++) {
+		switch ((*lev).levelArray[MAPS_BLOCK_OFFSET_WALL+i]) {
+			case MAPS_OBJ_BAL_D:
+			case MAPS_OBJ_BAL_U:
+				if ((*lev).levelArray[MAPS_BLOCK_OFFSET_BACK+i]>from) {
+					(*lev).levelArray[MAPS_BLOCK_OFFSET_BACK+i]+=delta;
+					validate-=delta;
+				}
+		}
+	}
+	(*lev).levelArray[MAPS_BLOCK_OFFSET_VALIDATOR_WALL]+=validate;
+}
+
+void insertEvent(tLevel* lev,char id,char scr,char p,char b) {
+	char x1,x2,x3,x4;
+
+	shiftEventId(lev,id,+1);
+	for (int i=20;i>id;i--) {
+		getGateAsociation(lev,i-1,&x1,&x2,&x3,&x4);
+		setGateAsociation(lev,i,x1,x2,x3,x4);
+	}
+	setGateAsociation(lev,id,scr,p,b,0);
+}
+
+/***************************************************************\
+|                         Text handling                         |
+\***************************************************************/
+
+#define MAPS_BLOCK_OFFSET_START_POSITION_SIZE3 3
+//Actualmente guarda 1+MAPS_BLOCK_SIZEOF_UNKNOWN_1+MAPS_BLOCK_SIZEOF_UNKNOWN_2+MAPS_BLOCK_SIZEOF_UNKNOWN_4+unk_5+unk_6+unk_7 = 564 caracteres. *text debe medir 565 incluyendo el caracter nulo.
+void mSetText (tLevel* lev,char* text) {
+	mSetArray(lev,text,MAPS_BLOCK_OFFSET_START_POSITION+MAPS_BLOCK_OFFSET_START_POSITION_SIZE3,1,MAPS_BLOCK_OFFSET_VALIDATOR_LINK);
+	mSetArray(lev,&(text[1]),MAPS_BLOCK_OFFSET_UNKNOWN_1,MAPS_BLOCK_SIZEOF_UNKNOWN_1,MAPS_BLOCK_OFFSET_VALIDATOR_WALL);
+	mSetArray(lev,&(text[MAPS_BLOCK_SIZEOF_UNKNOWN_1+1]),MAPS_BLOCK_OFFSET_UNKNOWN_2,MAPS_BLOCK_SIZEOF_UNKNOWN_2,MAPS_BLOCK_OFFSET_VALIDATOR_WALL);
+	mSetArray(lev,&(text[MAPS_BLOCK_SIZEOF_UNKNOWN_2+MAPS_BLOCK_SIZEOF_UNKNOWN_1+1]),MAPS_BLOCK_OFFSET_UNKNOWN_4,MAPS_BLOCK_SIZEOF_UNKNOWN_4,MAPS_BLOCK_OFFSET_VALIDATOR_LINK);
+	mSetArray(lev,&(text[MAPS_BLOCK_SIZEOF_UNKNOWN_4+MAPS_BLOCK_SIZEOF_UNKNOWN_2+MAPS_BLOCK_SIZEOF_UNKNOWN_1+1]),MAPS_BLOCK_OFFSET_UNKNOWN_5,MAPS_BLOCK_SIZEOF_UNKNOWN_5,MAPS_BLOCK_OFFSET_VALIDATOR_LINK);
+	mSetArray(lev,&(text[MAPS_BLOCK_SIZEOF_UNKNOWN_5+MAPS_BLOCK_SIZEOF_UNKNOWN_4+MAPS_BLOCK_SIZEOF_UNKNOWN_2+MAPS_BLOCK_SIZEOF_UNKNOWN_1+1]),MAPS_BLOCK_OFFSET_UNKNOWN_6,MAPS_BLOCK_SIZEOF_UNKNOWN_6,MAPS_BLOCK_OFFSET_VALIDATOR_LINK);
+	mSetArray(lev,&(text[MAPS_BLOCK_SIZEOF_UNKNOWN_6+MAPS_BLOCK_SIZEOF_UNKNOWN_5+MAPS_BLOCK_SIZEOF_UNKNOWN_4+MAPS_BLOCK_SIZEOF_UNKNOWN_2+MAPS_BLOCK_SIZEOF_UNKNOWN_1+1]),MAPS_BLOCK_OFFSET_UNKNOWN_7,MAPS_BLOCK_SIZEOF_UNKNOWN_7,MAPS_BLOCK_OFFSET_VALIDATOR_LINK);
+}
+
+void mGetText (tLevel* lev,char* text) {
+	mGetArray(lev,text,MAPS_BLOCK_OFFSET_START_POSITION+MAPS_BLOCK_OFFSET_START_POSITION_SIZE3,1);
+	mGetArray(lev,&(text[1]),MAPS_BLOCK_OFFSET_UNKNOWN_1,MAPS_BLOCK_SIZEOF_UNKNOWN_1);
+	mGetArray(lev,&(text[MAPS_BLOCK_SIZEOF_UNKNOWN_1+1]),MAPS_BLOCK_OFFSET_UNKNOWN_2,MAPS_BLOCK_SIZEOF_UNKNOWN_2);
+	mGetArray(lev,&(text[MAPS_BLOCK_SIZEOF_UNKNOWN_2+MAPS_BLOCK_SIZEOF_UNKNOWN_1+1]),MAPS_BLOCK_OFFSET_UNKNOWN_4,MAPS_BLOCK_SIZEOF_UNKNOWN_4);
+	mGetArray(lev,&(text[MAPS_BLOCK_SIZEOF_UNKNOWN_4+MAPS_BLOCK_SIZEOF_UNKNOWN_2+MAPS_BLOCK_SIZEOF_UNKNOWN_1+1]),MAPS_BLOCK_OFFSET_UNKNOWN_5,MAPS_BLOCK_SIZEOF_UNKNOWN_5);
+	mGetArray(lev,&(text[MAPS_BLOCK_SIZEOF_UNKNOWN_5+MAPS_BLOCK_SIZEOF_UNKNOWN_4+MAPS_BLOCK_SIZEOF_UNKNOWN_2+MAPS_BLOCK_SIZEOF_UNKNOWN_1+1]),MAPS_BLOCK_OFFSET_UNKNOWN_6,MAPS_BLOCK_SIZEOF_UNKNOWN_6);
+	mGetArray(lev,&(text[MAPS_BLOCK_SIZEOF_UNKNOWN_6+MAPS_BLOCK_SIZEOF_UNKNOWN_5+MAPS_BLOCK_SIZEOF_UNKNOWN_4+MAPS_BLOCK_SIZEOF_UNKNOWN_2+MAPS_BLOCK_SIZEOF_UNKNOWN_1+1]),MAPS_BLOCK_OFFSET_UNKNOWN_7,MAPS_BLOCK_SIZEOF_UNKNOWN_7);
+	text[MAPS_BLOCK_SIZEOF_UNKNOWN_7+MAPS_BLOCK_SIZEOF_UNKNOWN_6+MAPS_BLOCK_SIZEOF_UNKNOWN_5+MAPS_BLOCK_SIZEOF_UNKNOWN_4+MAPS_BLOCK_SIZEOF_UNKNOWN_2+MAPS_BLOCK_SIZEOF_UNKNOWN_1+1]=0;
+}
+
+/***************************************************************\
+|                     Start Position handling                   |
+\***************************************************************/
+
+void mGetDebugPosition(tLevel* lev,char* pantalla, char* p, char *b,char *sentido) {
+	unsigned char dp[2];
+	unsigned char valor;
+	mGetArray(lev,dp,MAPS_BLOCK_OFFSET_START_POSITION+4,2);
+	*pantalla =(dp[0]);
+	*sentido  =(dp[1]%2);
+	valor     =(dp[1]/2);
+	*b        =(valor%10);
+	*p        =(valor/10);
+}
+
+void mSetDebugPosition(tLevel* lev,char pantalla, char p, char b,char sentido) {
+	unsigned char dp[2];
+	dp[0]     =pantalla;
+	dp[1]     =pantalla?(((p*10+b)*2)+(sentido?1:0)):0;
+	mSetArray(lev,dp,MAPS_BLOCK_OFFSET_START_POSITION+4,2,MAPS_BLOCK_OFFSET_VALIDATOR_LINK);
+}
+
+void mGetStartPosition(tLevel* lev,char* pantalla, char* p, char *b,char *sentido,char *sentido2) {
+	*pantalla =(*lev).levelArray[MAPS_BLOCK_OFFSET_START_POSITION];
+	char valor=(*lev).levelArray[MAPS_BLOCK_OFFSET_START_POSITION+1];
+	*b        =(valor%10);
+	*p        =(valor/10);
+	*sentido  =((*lev).levelArray[MAPS_BLOCK_OFFSET_START_POSITION+2])?1:0;
+	*sentido2 =((*lev).levelArray[MAPS_BLOCK_OFFSET_START_POSITION+6])?1:0;
+}
+
+void mSetStartPosition(tLevel* lev,char pantalla, char p, char b,char sentido,char sentido2) {
+	unsigned char valor=pantalla;
+	int location=MAPS_BLOCK_OFFSET_START_POSITION;
+	unsigned char offsetval=0;
+
+	//pantalla
+	offsetval+=(256-valor)+(*lev).levelArray[location];
+	(*lev).levelArray[location++]=valor;
+
+	//Posicion
+	valor     =p*10+b;
+	offsetval+=(256-valor)+(*lev).levelArray[location];
+	(*lev).levelArray[location++]=valor;
+
+	//sentidos
+	valor     =sentido?MAPS_DIRECTION_RIGHT:MAPS_DIRECTION_LEFT;
+	offsetval+=(256-valor)+(*lev).levelArray[location];
+	(*lev).levelArray[location]=valor;
+
+	location +=4;
+	valor     =sentido2?MAPS_DIRECTION_RIGHT:MAPS_DIRECTION_LEFT;
+	offsetval+=(256-valor)+(*lev).levelArray[location];
+	(*lev).levelArray[location]=valor;
+
+	//Validacion
+	(*lev).levelArray[MAPS_BLOCK_OFFSET_VALIDATOR_LINK]+=offsetval;
+}
+
+/***************************************************************\
+|                      S E T S  &  G E T S                      |
+\***************************************************************/
+
+
+void mSetWall  (tLevel* lev,char pantalla,char p,char b,char valor) {
+	int location=MAPS_BLOCK_OFFSET_WALL+30*(pantalla-1)+10*p+b;
+
+	(*lev).levelArray[MAPS_BLOCK_OFFSET_VALIDATOR_WALL]+=(*lev).levelArray[location]-valor;
+	(*lev).levelArray[location]=valor;
+}
+
+char mGetWall (tLevel* lev,char pantalla,char p,char b) {
+	return (*lev).levelArray[MAPS_BLOCK_OFFSET_WALL+30*(pantalla-1)+10*p+b];
+}
+
+void mSetBack (tLevel* lev,char pantalla,char p,char b,char valor) {
+	int location=MAPS_BLOCK_OFFSET_BACK+30*(pantalla-1)+10*p+b;
+
+	(*lev).levelArray[MAPS_BLOCK_OFFSET_VALIDATOR_WALL]+=(*lev).levelArray[location]-valor;
+	(*lev).levelArray[location]=valor;
+}
+
+char mGetBack (tLevel* lev,char pantalla,char p,char b) {
+	return (*lev).levelArray[MAPS_BLOCK_OFFSET_BACK+30*(pantalla-1)+10*p+b];
+}
+
+void mSetLink (tLevel* lev,char pantalla,char tipo,char valor) {
+	if ((pantalla<25) && (pantalla) && (valor<25)) {
+		int location=(MAPS_BLOCK_OFFSET_LINK+((pantalla-1)*4)+tipo);
+		(*lev).levelArray[MAPS_BLOCK_OFFSET_VALIDATOR_LINK]+=(*lev).levelArray[location]-valor;
+		(*lev).levelArray[location]=valor;
+	}
+}
+
+char mGetLink (tLevel* lev,char pantalla,char tipo) {
+	return (*lev).levelArray[MAPS_BLOCK_OFFSET_LINK+((pantalla-1)*4)+tipo];
+}
+
+/***************************************************************\
+|                   Abstract Guard Handling                     |
+\***************************************************************/
+
+void mSetGuard(tLevel* lev,char pantalla,char p,char b,char vidas,char color,char sentido,char erase) {
+
+	//Posicion
+	unsigned char valor=erase?30:p*10+b;
+	int location=MAPS_BLOCK_OFFSET_GUARD_POSITION-1+pantalla;
+	unsigned char offsetval=((*lev).levelArray[MAPS_BLOCK_OFFSET_VALIDATOR_LINK]+(256-valor)+(*lev).levelArray[location]);
+	(*lev).levelArray[location]=valor;
+	//sentido
+	valor     =sentido?MAPS_DIRECTION_RIGHT:MAPS_DIRECTION_LEFT;
+	location  =MAPS_BLOCK_OFFSET_GUARD_DIRECTION-1+pantalla;
+	offsetval+=(256-valor)+(*lev).levelArray[location];
+	(*lev).levelArray[location]=valor;
+	//skill
+	valor     =erase?1:vidas;
+	location  =MAPS_BLOCK_OFFSET_GUARD_SKILL-1+pantalla;
+	offsetval+=(256-valor)+(*lev).levelArray[location];
+	(*lev).levelArray[location]=valor;
+	//Color
+	valor     =erase?0:color;
+	location  =MAPS_BLOCK_OFFSET_GUARD_COLOR-1+pantalla;
+	offsetval+=(256-valor)+(*lev).levelArray[location];
+	(*lev).levelArray[location]=valor;
+
+	//Validar
+	(*lev).levelArray[MAPS_BLOCK_OFFSET_VALIDATOR_LINK]=offsetval/*+(256-valor)+(*lev).levelArray[location]*/;
+}
+
+void mGetGuard(tLevel* lev,char pantalla,char* p,char* b,char* vidas,char* color,char* sentido,char* exists) {
+	//Posicion
+	unsigned char valor=((*lev).levelArray[(MAPS_BLOCK_OFFSET_GUARD_POSITION-1+pantalla)]);
+	*exists = (valor<30);
+	*b      = (valor%10);
+	*p      = (valor/10);
+	//sentido
+	*sentido=!(*lev).levelArray[MAPS_BLOCK_OFFSET_GUARD_DIRECTION-1+pantalla];
+	//skill
+	*vidas  =(*lev).levelArray[MAPS_BLOCK_OFFSET_GUARD_SKILL-1+pantalla];
+	//Color
+	*color  =(*lev).levelArray[MAPS_BLOCK_OFFSET_GUARD_COLOR-1+pantalla];
+}
+
+/***************************************************************\
+|                     Screen Link Handling                      |
+\***************************************************************/
+
+//Recursive mapping sub procedures
+void mRecLink(char i, char j, tLevel* lev); //prototype
+void mRecIndirect(char i, char j, tLevel* lev, char scr, char pos) {
+	char aux;
+	char auxb;
+	if ((*lev).handledLinks.linkMap[i][j]==255) {
+		aux=mGetLink (lev,scr,pos);
+		if (!(auxb=(!aux))) auxb=(!(*lev).handledLinks.linkList[aux]);
+		if (auxb) {
+			(*lev).handledLinks.linkMap[i][j]=aux;
+			if (aux) {
+				(*lev).handledLinks.linkList[aux]=1;
+				mRecLink(i,j,lev);
+			}
+		} else {
+			(*lev).handledLinks.linkMap[i][j]=0;
+		}
+	}
+}
+
+void mRecLink(char i, char j, tLevel* lev) {
+	char scr=(*lev).handledLinks.linkMap[i][j];
+
+	mRecIndirect(i,j-1,lev,scr,MAPS_sLeft);
+	mRecIndirect(i,j+1,lev,scr,MAPS_sRight);
+	mRecIndirect(i-1,j,lev,scr,MAPS_sUp);
+	mRecIndirect(i+1,j,lev,scr,MAPS_sDown);
+}
+
+void mCalcularLimUp (tLevel* lev) {
+	char i=0;
+	char j=0;
+	while (((*lev).handledLinks.linkMap[i][j]==255) && (j<MAPS_MAX_LENGTH)) {
+		if (++i==MAPS_MAX_LENGTH) {
+			j++;
+			i=0;
+		}
+	}
+	(*lev).handledLinks.limUp=j;
+}
+
+void mCalcularLimLeft (tLevel* lev) {
+	char i=0;
+	char j=0;
+	while (((*lev).handledLinks.linkMap[j][i]==255) && (j<MAPS_MAX_LENGTH)) {
+		if (++i==MAPS_MAX_LENGTH) {
+			j++;
+			i=0;
+		}
+	}
+	(*lev).handledLinks.limLeft=j;
+}
+
+void mCalcularLimDown (tLevel* lev) {
+	char i=0;
+	char j=MAPS_MAX_LENGTH-1;
+	while (((*lev).handledLinks.linkMap[i][j]==255) && j) {
+		if (++i==MAPS_MAX_LENGTH) {
+			j--;
+			i=0;
+		}
+	}
+	(*lev).handledLinks.limDown=j;
+}
+
+void mCalcularLimRight (tLevel* lev) {
+	char i=0;
+	char j=MAPS_MAX_LENGTH-1;
+	while (((*lev).handledLinks.linkMap[j][i]==255) && j) {
+		if (++i==MAPS_MAX_LENGTH) {
+			j--;
+			i=0;
+		}
+	}
+	(*lev).handledLinks.limRight=j;
+}
+
+
+//	Main mCreateLinkMap
+void mCreateLinkMap(tLevel* lev) { //private
+	char	i,j,start;
+
+	//Initialize arrays
+	for (j=0;j<MAPS_MAX_LENGTH;j++)
+		for (i=0;i<MAPS_MAX_LENGTH;(*lev).handledLinks.linkMap[i++][j]=255);
+	for (j=1;j<=MAPS_MAX_SCREENS;(*lev).handledLinks.linkList[j++]=0);
+
+	//Inicializar start en la pantalla de inicio
+	mGetStartPosition(lev,&start,&i,&i,&i,&i);
+	(*lev).handledLinks.linkMap[MAPS_LINKMAP_CENTER][MAPS_LINKMAP_CENTER]=start;
+	(*lev).handledLinks.linkList[start]=1;
+
+	//Start Recursive Mapper
+	mRecLink(MAPS_LINKMAP_CENTER,MAPS_LINKMAP_CENTER,lev);
+
+	//Buscar limites del nivel
+	mCalcularLimUp   (lev);
+	mCalcularLimDown (lev);
+	mCalcularLimLeft (lev);
+	mCalcularLimRight(lev);
+
+}
+
+void mGetSize      (tLevel* lev, char* i,char* j) {
+	*i=(*lev).handledLinks.limRight - (*lev).handledLinks.limLeft;
+	*j=(*lev).handledLinks.limDown  - (*lev).handledLinks.limUp;
+}
+
+char mGetScrCount  (tLevel* lev) {
+	char l,aux;
+
+	aux=0;
+	for (l=1;l<=MAPS_MAX_SCREENS;aux+=((*lev).handledLinks.linkList[l++]?1:0));
+	return aux;
+}
+
+char mGetScreen    (tLevel* lev, char i,char j, char* error) {
+	char aux;
+
+	aux=(*lev).handledLinks.linkMap[(*lev).handledLinks.limLeft+i][(*lev).handledLinks.limUp+j];
+	*error=(aux==255);
+	return aux;
+}
+
+void mGetMainScreen(tLevel* lev, char* i,char* j) {
+	*i=(MAPS_LINKMAP_CENTER) - (*lev).handledLinks.limLeft;
+	*j=(MAPS_LINKMAP_CENTER) - (*lev).handledLinks.limUp;
+}
+
+void mAddScreen    (tLevel* lev, char i,char j, char* error) {
+	char scr=mGetScreen(lev,i,j,error);
+	*error=(*error || scr);
+	if (!*error) {
+		int l=1;
+		while ((*lev).handledLinks.linkList[l] && (l++<MAPS_MAX_SCREENS));
+		if ((*lev).handledLinks.linkList[l]) {
+			*error=1;
+		} else {
+			//Pedir pantalla
+			(*lev).handledLinks.linkList[l]=1;
+
+			i+=(*lev).handledLinks.limLeft;
+			j+=(*lev).handledLinks.limUp;
+
+			//En caso de agregar una pantalla en alguno de los bordes, estos se amplian
+			if ((*lev).handledLinks.limLeft=i) (*lev).handledLinks.limLeft--;
+			if ((*lev).handledLinks.limUp=j) (*lev).handledLinks.limUp--;
+			if ((*lev).handledLinks.limRight=i) (*lev).handledLinks.limRight++;
+			if ((*lev).handledLinks.limDown=j) (*lev).handledLinks.limDown++;
+
+
+			//Poner 0 alrededor de l
+			(*lev).handledLinks.linkMap[i][j-1]%=255;
+			(*lev).handledLinks.linkMap[i][j+1]%=255;
+			(*lev).handledLinks.linkMap[i+1][j]%=255;
+			(*lev).handledLinks.linkMap[i-1][j]%=255;
+
+			//Poner l en l
+			(*lev).handledLinks.linkMap[i][j]=l;
+
+			//Setear links desde l a las 4 pantallas adyacentes
+			mSetLink (lev,l,MAPS_sUp,(*lev).handledLinks.linkMap[i][j-1]);
+			mSetLink (lev,l,MAPS_sDown,(*lev).handledLinks.linkMap[i][j+1]);
+			mSetLink (lev,l,MAPS_sRight,(*lev).handledLinks.linkMap[i+1][j]);
+			mSetLink (lev,l,MAPS_sLeft,(*lev).handledLinks.linkMap[i-1][j]);
+
+			//Setear links desde las 4 pantallas adyacentes a l
+			mSetLink (lev,(*lev).handledLinks.linkMap[i][j+1],MAPS_sUp,l);
+			mSetLink (lev,(*lev).handledLinks.linkMap[i][j-1],MAPS_sDown,l);
+			mSetLink (lev,(*lev).handledLinks.linkMap[i-1][j],MAPS_sRight,l);
+			mSetLink (lev,(*lev).handledLinks.linkMap[i+1][j],MAPS_sLeft,l);
+
+			//Limpiar contenido de la pantalla l
+			for (i=0;i<3;i++) {
+				for (j=0;j<10;j++) {
+					mSetWall(lev,l,i,j,0);
+					mSetBack(lev,l,i,j,0);
+				}
+			}
+			mSetGuard(lev,l,1,1,1,1,1,1);
+			//Listo, ya cree la pantalla y la linkie
+		}
+	}
+}
+
+void mRemScreen    (tLevel* lev, char i,char j, char* error) {
+	/*{Q&D:
+		1) Si parten a la mitad un nivel se pierde una de las mitades
+		2) no se refresca la LinkMap en ese caso
+		3) tampoco une las pantallas que estaban a los costados}*/
+	unsigned char l=mGetScreen(lev,i,j,error);
+	*error=*error || (!l);
+	if (!*error) {
+		//Liberar pantalla
+		(*lev).handledLinks.linkList[l]=0;
+
+		//Seteo posiciones absolutas
+		i+=(*lev).handledLinks.limLeft;
+		j+=(*lev).handledLinks.limUp;
+
+		//Poner 0 en l
+		(*lev).handledLinks.linkMap[i][j]=0;
+
+		//En caso de remover una pantalla en alguno de los bordes, estos se recalculan
+		if ((*lev).handledLinks.limLeft=i) 	mCalcularLimLeft(lev);
+		if ((*lev).handledLinks.limUp=j)    mCalcularLimUp(lev);
+		if ((*lev).handledLinks.limRight=i) mCalcularLimRight(lev);
+		if ((*lev).handledLinks.limDown=j)  mCalcularLimDown(lev);
+
+		//Borrar links desds las 4 pantallas adyacentes a l
+		mSetLink (lev,(*lev).handledLinks.linkMap[i][j+1],MAPS_sLeft,0);
+		mSetLink (lev,(*lev).handledLinks.linkMap[i][j-1],MAPS_sRight,0);
+		mSetLink (lev,(*lev).handledLinks.linkMap[i-1][j],MAPS_sDown,0);
+		mSetLink (lev,(*lev).handledLinks.linkMap[i+1][j],MAPS_sUp,0);
+	}
+}
+
+void mCpyScreen    (tLevel* lev, char fromi,char fromj,char toi,char toj, char* error) {
+	char fromscr,toscr,i,j,k,l;
+	char sentido,existe;
+
+	//Verificar que la pantalla source y la pantalla target existan
+	fromscr=mGetScreen(lev,fromi,fromj,error); //Verifico que existe la pantalla from
+	*error=(*error || fromscr);
+	if (!*error) { //Verifico que existe la pantalla to
+		toscr=mGetScreen(lev,toi,toj,error);
+		*error=(*error || toscr);
+	}
+	if (!*error) { //Si existen ambas pantallas
+		//Copiar contenido de la pantalla from a la pantalla to:
+
+		//Copiar wall y back
+		char contenido[30];
+		mGetArray(lev,contenido,MAPS_BLOCK_OFFSET_WALL-30+fromscr*30,30);
+		mSetArray(lev,contenido,MAPS_BLOCK_OFFSET_WALL-30+toscr*30,30,MAPS_BLOCK_OFFSET_VALIDATOR_WALL);
+		mGetArray(lev,contenido,MAPS_BLOCK_OFFSET_BACK-30+fromscr*30,30);
+		mSetArray(lev,contenido,MAPS_BLOCK_OFFSET_BACK-30+toscr*30,30,MAPS_BLOCK_OFFSET_VALIDATOR_WALL);
+
+		//Copiar Guards
+		mGetGuard(lev,fromscr,&i,&j,&k,&l,&sentido,&existe);
+		mSetGuard(lev,toscr,i,j,k,l,sentido,existe);
+		//Listo, ya se copio el contenido y el guardia
+	}
+}
+
+/***************************************************************\
+|                         File handling                         |
+\***************************************************************/
+
+char mLoadPED(char* vFile,tLevel* lev) {
+	FILE *fp;
+	char aux;
+
+	if ((fp=fopen(vFile,"rb"))==NULL) {
+		return 0;
+	} else {
+		aux=fread (lev,sizeof(*lev),1,fp);
+		fclose(fp);
+		return aux;
+	}
+}
+
+char mLoadDAT(char* vFile,tLevel* lev,char levelNumber) {
+	FILE *fp;
+	char aux;
+
+	if ((fp=fopen(vFile,"rb"))==NULL) {
+		return 0;
+	} else {
+		(*lev).level=levelNumber;
+		fpos_t position=levelNumber*MAPS_BLOCK_SIZEOF_LEVEL+MAPS_BLOCK_OFFSET_LEVELS;
+		fsetpos (fp, &position);
+		aux=fread (&(*lev).levelArray,MAPS_BLOCK_SIZEOF_LEVEL,1,fp);
+		mCreateLinkMap(lev);
+		fclose(fp);
+		return aux;
+	}
+}
+
+char mSavePED(char* vFile,tLevel* lev) {
+  FILE * pFile;
+  if ((pFile = fopen (vFile , "wb"))==NULL) {
+		return 0;
+	}
+  fwrite (lev, 1, sizeof(*lev), pFile);
+  fclose (pFile);
+  return 1;
+}
+
+char mSaveDAT(char* vFile,tLevel* lev) {
+  FILE * pFile;
+  if ((pFile = fopen (vFile , "r+b"))==NULL) {
+		return 0;
+	}
+	fpos_t position=(*lev).level*MAPS_BLOCK_SIZEOF_LEVEL+MAPS_BLOCK_OFFSET_LEVELS;
+  fsetpos (pFile, &position);
+  fwrite ((*lev).levelArray, 1, MAPS_BLOCK_SIZEOF_LEVEL, pFile);
+  fclose (pFile);
+  return 1;
+}
+