initial add
authorecalot <ecalot>
Sun, 20 Jun 2004 20:28:30 +0000 (20:28 +0000)
committerecalot <ecalot>
Sun, 20 Jun 2004 20:28:30 +0000 (20:28 +0000)
FP/src/res/maps.c [new file with mode: 0644]

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