Merge pull request #51 from ilag11111/cheatSupport
authorTwinaphex <libretro@gmail.com>
Thu, 23 Mar 2017 19:18:00 +0000 (20:18 +0100)
committerGitHub <noreply@github.com>
Thu, 23 Mar 2017 19:18:00 +0000 (20:18 +0100)
Add cheat support for Genesis/MegaDrive, CD, and 32X games

pico/patch.c
platform/libretro/libretro.c

index b961e80..558658c 100644 (file)
@@ -142,7 +142,7 @@ static void hex_decode(const char *code, struct patch *result)
 /* THIS is the function you call from the MegaDrive or whatever. This figures
  * out whether it's a genie or hex code, depunctuates it, and calls the proper
  * decoder. */
-static void decode(const char* code, struct patch* result)
+void decode(const char* code, struct patch* result)
 {
   int len = strlen(code), i, j;
   char code_to_pass[16], *x;
@@ -211,7 +211,8 @@ bad_code:
 
 unsigned int PicoRead16(unsigned int a);
 void PicoWrite16(unsigned int a, unsigned short d);
-
+extern unsigned short m68k_read16(unsigned int a);
+extern void m68k_write16(int a, unsigned short d);
 
 void PicoPatchUnload(void)
 {
@@ -299,6 +300,8 @@ void PicoPatchPrepare(void)
                PicoPatches[i].addr &= ~1;
                if (PicoPatches[i].addr < Pico.romsize)
                        PicoPatches[i].data_old = *(unsigned short *)(Pico.rom + PicoPatches[i].addr);
+               else
+                       PicoPatches[i].data_old = (unsigned short) m68k_read16(PicoPatches[i].addr);
                if (strstr(PicoPatches[i].name, "AUTO"))
                        PicoPatches[i].active = 1;
        }
@@ -328,7 +331,15 @@ void PicoPatchApply(void)
                }
                else
                {
-                       /* TODO? */
+                       if (PicoPatches[i].active)
+                               m68k_write16(PicoPatches[i].addr,PicoPatches[i].data);
+                       else {
+                               // if current addr is not patched by older patch, write back original val
+                               for (u = 0; u < i; u++)
+                                       if (PicoPatches[u].addr == addr) break;
+                               if (u == i)
+                                       m68k_write16(PicoPatches[i].addr,PicoPatches[i].data_old);
+                       }
                }
        }
 }
index 332cf65..f11b5da 100644 (file)
@@ -53,6 +53,7 @@ int _newlib_vm_size_user = 1 << TARGET_SIZE_2;
 
 #include <pico/pico_int.h>
 #include <pico/state.h>
+#include <pico/patch.h>
 #include "../common/input_pico.h"
 #include "../common/version.h"
 #include "libretro.h"
@@ -691,13 +692,90 @@ bool retro_unserialize(const void *data, size_t size)
    return ret == 0;
 }
 
-/* cheats - TODO */
+typedef struct patch
+{
+       unsigned int addr;
+       unsigned short data;
+} patch;
+
+extern void decode(char *buff, patch *dest);
+extern uint16_t m68k_read16(uint32_t a);
+extern void m68k_write16(uint32_t a, uint16_t d);
+
 void retro_cheat_reset(void)
 {
+       int i=0;
+       unsigned int addr;
+
+       for (i = 0; i < PicoPatchCount; i++)
+       {
+               addr = PicoPatches[i].addr;
+               if (addr < Pico.romsize) {
+                       if (PicoPatches[i].active)
+                               *(unsigned short *)(Pico.rom + addr) = PicoPatches[i].data_old;
+               } else {
+                       if (PicoPatches[i].active)
+                               m68k_write16(PicoPatches[i].addr,PicoPatches[i].data_old);
+               }
+       }
+
+       PicoPatchUnload();
 }
 
 void retro_cheat_set(unsigned index, bool enabled, const char *code)
 {
+       patch pt;
+       int array_len = PicoPatchCount;
+       char codeCopy[256];
+       char *buff;
+       bool multiline=0;
+
+       strcpy(codeCopy,code);
+       
+       if (strstr(code,"+")){
+               multiline=1;
+               buff = strtok(codeCopy,"+");
+       } else {
+               buff=codeCopy;
+       }
+
+       while (buff != NULL)
+       {
+               decode(buff, &pt);
+               if (pt.addr == (uint32_t) -1 || pt.data == (uint16_t) -1)
+               {
+                       log_cb(RETRO_LOG_ERROR,"CHEATS: Invalid code: %s\n",buff);
+                       return;
+               }
+
+               /* code was good, add it */
+               if (array_len < PicoPatchCount + 1)
+               {
+                       void *ptr;
+                       array_len *= 2;
+                       array_len++;
+                       ptr = realloc(PicoPatches, array_len * sizeof(PicoPatches[0]));
+                       if (ptr == NULL) {
+                               log_cb(RETRO_LOG_ERROR,"CHEATS: Failed to allocate memory for: %s\n",buff);
+                               return;
+                       }
+                       PicoPatches = ptr;
+               }
+               strcpy(PicoPatches[PicoPatchCount].code, buff);
+
+               PicoPatches[PicoPatchCount].active = enabled;
+               PicoPatches[PicoPatchCount].addr = pt.addr;
+               PicoPatches[PicoPatchCount].data = pt.data;
+               if (PicoPatches[PicoPatchCount].addr < Pico.romsize)
+                       PicoPatches[PicoPatchCount].data_old = *(uint16_t *)(Pico.rom + PicoPatches[PicoPatchCount].addr);
+               else
+                       PicoPatches[PicoPatchCount].data_old = (uint16_t) m68k_read16(PicoPatches[PicoPatchCount].addr);
+               PicoPatchCount++;
+
+               if (!multiline)
+                       break;
+               buff = strtok(NULL,"+");
+       }
 }
 
 /* multidisk support */
@@ -1270,6 +1348,7 @@ void retro_run(void)
          if (input_state_cb(pad, RETRO_DEVICE_JOYPAD, 0, i))
             PicoPad[pad] |= retro_pico_map[i];
 
+   PicoPatchApply();
    PicoFrame();
 
    video_cb((short *)vout_buf + vout_offset,