• Welcome to the Shining Force Mods Community Forum!

    We're a group of fans who are passionate about the Shining Force series, modding and, of course, video gaming.

    Register Log in

Shining Force Alternate

Shining Force Alternate V3.2C

Excited Season 2 GIF by The Office

Another awesome update! Cheers! :cool:
 
I can just say that Krin wouldn't want to let Bleu down. She's just deserving a chance to fight as his spirit lives on in her.
 
That helps.

Any chance you'll add Krin as a force member instead of being extra inventory space?
Not likely. I'm mostly finished with the project. Any further tweaks are to fix any issues that pop up.
 
For all ppl who only had a "shining_force1.smd" file (and not a required "shining_force1.bin") to apply the patch; these two programs might help to tackle this "issue":

Rename ur .smd file to
sforce1.smd

Create a ".c file" on ur Desktop (called "deinterleave.c"),
copy the "Code" into this file & safe it;
then Compile&Run the program (ask Microsoft Copilot, if ur not sure what to do):

Transform the SDM file to a BINARY [MAKE A BACKUP before doing so!] Cut the header & de-interleave:
/*
This is free and unencumbered software released into the public domain. Made my ArC.


gcc -o deinterleave deinterleave.c

./deinterleave game.smd

This tool converts an interleaved .SMD Sega Mega Drive ROM
into a normal linear .BIN ROM by reversing the SMD block format.

SMD FORMAT SUMMARY:

• First 0x200 bytes = SMD header
• Then the ROM is stored in 16 KB blocks
• Each 16 KB block is arranged like this:

[ 0x0000 – 0x1FFF ] = ODD bytes
[ 0x2000 – 0x3FFF ] = EVEN bytes

The Genesis expects bytes in this order:

EVEN0, ODD0, EVEN1, ODD1, EVEN2, ODD2, ...

So the SMD format is literally:

Block = [ODD half][EVEN half]

This program reconstructs the original byte order by
interleaving the two halves back together.
*/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

typedef struct {
uint8_t blocks;
uint8_t _3;
uint8_t type_flag;
uint8_t fill_0[5];
uint8_t _aa;
uint8_t _bb;
uint8_t _6;
uint8_t fill_1[0x1F5];
} smd_header_t;

int main(int argc, char *argv[])
{
if (argc < 2) {
fprintf(stderr, "Usage: %s file.smd\n", argv[0]);
return 1;
}

const char *infile = argv[1];
char outfile[1024];

// output name = input with .bin extension
const char *dot = strrchr(infile, '.');

if (dot) {
size_t len = dot - infile;
memcpy(outfile, infile, len);
outfile[len] = '\0';
strcat(outfile, ".bin");
} else {
snprintf(outfile, sizeof(outfile), "%s.bin", infile);
}

FILE *f_in = fopen(infile, "rb");
if (!f_in) {
perror("❌ Input open failed");
return 1;
}

FILE *f_out = fopen(outfile, "wb");
if (!f_out) {
perror("❌ Output open failed");
fclose(f_in);
return 1;
}

smd_header_t header;
if (fread(&header, sizeof(header), 1, f_in) != 1) {
fprintf(stderr, "☠️ Failed to read SMD header\n");
return 1;
}

uint32_t size = header.blocks << 14; // blocks * 16384
uint8_t *in = malloc(size);
uint8_t *out = malloc(size);

if (!in || !out) {
fprintf(stderr, "☠️ Memory allocation failed\n");
return 1;
}

fread(in, 1, size, f_in);

// Deinterleave each 16 KB block
for (uint32_t b = 0; b < header.blocks; b++) {
uint8_t *p_in = in + b * 0x4000;
uint8_t *p_out = out + b * 0x4000;

for (int n = 0; n < 0x2000; n++) {
p_out[n*2] = p_in[0x2000 + n];
p_out[n*2 + 1] = p_in[n];
}
}

fwrite(out, 1, size, f_out);

free(in);
free(out);
fclose(f_in);
fclose(f_out);

printf(" Wrote %s\n", outfile);
return 0;
}

Apply the IPS_Patch (the Mod file) to the "sforce1.bin" with this program:

Rename ur .ips file to
patch.ips

Create a ".c file" on ur Desktop (called "ips_patcher.c"),
copy the "Code" into this file & safe it; then compile&run.

// This is free and unencumbered software released into the public domain. Made my ArC.

// ips_patcher.c

// gcc -o ips_patcher ips_patcher.c

// ./ips_patcher sforce1.bin patch.ips sforce1_patched.bin

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#define IPS_HEADER "PATCH"
#define IPS_EOF "EOF"

static int verbose = 0;

void logmsg(const char *msg) {
if (verbose) {
printf("[DEBUG] %s\n", msg);
}
}

uint8_t *read_file(const char *filename, long *size_out) {
FILE *f = fopen(filename, "rb");
if (!f) return NULL;

fseek(f, 0, SEEK_END);
long size = ftell(f);
rewind(f);

uint8_t *data = malloc(size);
if (!data) {
fclose(f);
return NULL;
}

fread(data, 1, size, f);
fclose(f);

*size_out = size;
return data;
}

int write_file(const char *filename, uint8_t *data, long size) {
FILE *f = fopen(filename, "wb");
if (!f) return 0;

fwrite(data, 1, size, f);
fclose(f);
return 1;
}

int apply_ips_patch(const char *rom_path, const char *ips_path, const char *out_path) {
long rom_size, ips_size;

logmsg(" Reading ROM file...");
uint8_t *rom = read_file(rom_path, &rom_size);
if (!rom) {
printf("☠️ Error: Could not read ROM file.\n");
return 0;
}

logmsg("Reading IPS patch file...");
uint8_t *ips = read_file(ips_path, &ips_size);
if (!ips) {
printf("❌ Error: Could not read IPS file.\n");
free(rom);
return 0;
}

if (ips_size < 5 || memcmp(ips, IPS_HEADER, 5) != 0) {
printf("❌ Error: Invalid IPS header.\n");
free(rom);
free(ips);
return 0;
}

logmsg(" Valid IPS header found.");

long offset = 5;
int patch_count = 0;

while (offset < ips_size) {
if (offset + 3 <= ips_size && memcmp(&ips[offset], IPS_EOF, 3) == 0) {
logmsg(" Found EOF marker.");
break;
}

if (offset + 5 > ips_size) break;

// 3‑byte address (big endian)
uint32_t addr = (ips[offset] << 16) | (ips[offset+1] << 8) | ips[offset+2];
offset += 3;

// 2‑byte length (big endian)
uint16_t length = (ips[offset] << 8) | ips[offset+1];
offset += 2;

if (length == 0) {
// RLE record
if (offset + 3 > ips_size) break;

uint16_t rle_len = (ips[offset] << 8) | ips[offset+1];
uint8_t rle_byte = ips[offset+2];
offset += 3;

char dbg[128];
sprintf(dbg, " RLE patch at 0x%06X: %u bytes of 0x%02X", addr, rle_len, rle_byte);
logmsg(dbg);

// Extend ROM if needed
if (addr + rle_len > rom_size) {
long new_size = addr + rle_len;
rom = realloc(rom, new_size);
memset(rom + rom_size, 0, new_size - rom_size);
rom_size = new_size;
}

for (int i = 0; i < rle_len; i++) {
rom[addr + i] = rle_byte;
}

patch_count++;
} else {
// Normal patch
if (offset + length > ips_size) break;

char dbg[128];
sprintf(dbg, " Normal patch at 0x%06X: %u bytes", addr, length);
logmsg(dbg);

// Extend ROM if needed
if (addr + length > rom_size) {
long new_size = addr + length;
rom = realloc(rom, new_size);
memset(rom + rom_size, 0, new_size - rom_size);
rom_size = new_size;
}

memcpy(&rom[addr], &ips[offset], length);
offset += length;

patch_count++;
}
}

printf(" Applied %d patch segments.\n", patch_count);

logmsg(" Writing patched ROM...");
int ok = write_file(out_path, rom, rom_size);

free(rom);
free(ips);

return ok;
}

int main(int argc, char **argv) {
if (argc < 4) {
printf("Usage: %s [-v] rom.bin patch.ips output.bin\n", argv[0]);
return 1;
}

int argi = 1;
if (strcmp(argv[argi], "-v") == 0) {
verbose = 1;
argi++;
}

const char *rom = argv[argi++];
const char *ips = argv[argi++];
const char *out = argv[argi++];

printf("Applying IPS patch...\n");
printf("ROM: %s\n", rom);
printf("Patch: %s\n", ips);
printf("Out: %s\n", out);

if (apply_ips_patch(rom, ips, out)) {
printf(" Patch applied successfully.\n");
return 0;
} else {
printf("❌ Failed to apply patch.\n");
return 1;
}
}

Best regards,

ArC
 
Last edited:
Back
Top