How to edit Icewind Dale EE savegame

I have spent countless hours playing role-playing video games. Recently, I bought Icewind Dale: Enhanced Edition for Linux. It is still great experience, but I have to admit that I have gone to the dark side and modified save file. Just think of it as a programming exercise.

Icewind Dale: Enhanced Edition
Icewind Dale: Enhanced Edition

Source code

There is nothing fancy about this program. It should be extended to wait for confirmation before applying changes, so it may be updated in the future.

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <string.h>

#define FILE_TYPE    "GAMEV2.0"
#define MAX_PATH_LEN 1024
#define MAX_GOLD     10000000   // you can even set more then 1 000 000 000

int verify_file_type(FILE *fp);

int main(int argc, char *argv[]) {
  // file
  FILE *fp;
  char *filename = "BALDUR.gam";
  
  // options
  int opt;
  extern int opterr;
  opterr= 0; // make getopt silent

  // flags
  int pflag = 0, aflag = 0, dflag = 0;

  // initial values
  char     *path   = "";  
  unsigned long int  amount = 0;

  // full file path
  char path_buffer[MAX_PATH_LEN] = "";

  // gold amount stored inside save file
  unsigned int current_gold;
  
  // temporary variables;
  char *str_end;
  
  // parse options
  while((opt = getopt(argc, argv, "p:a:d")) != -1) {
    switch(opt) {
    case 'p':
      path = optarg;
      
      // check path
      snprintf(path_buffer, sizeof(path_buffer), "%s%s", path, filename);
      fp=fopen(path_buffer,"r");
      if(fp == NULL){
       	fprintf (stderr, "Cannot open file: %s\n", path_buffer); 
       	exit(EXIT_FAILURE); 
      }
      fclose(fp);      
      pflag=1; // path is set
      break;
    case 'a':
      amount = strtol(optarg, &str_end, 0);

      // check for additional characters
      if(*str_end != '\0') {
	fprintf(stderr,"Amount contains additional characters: %s\n", str_end);
	exit(EXIT_FAILURE);
      }

      // check for max value
      if(amount > MAX_GOLD){
	fprintf(stderr, "Too much gold.\n");
	exit(EXIT_FAILURE);	
      }
      aflag=1; // amount is set
      break;
    case 'd':
      dflag = 1; // debug is set
      break;
    case '?':
      if(optopt == 'p')
	fprintf (stderr, "Option -%c requires an path argument.\n", optopt);
      else if(optopt == 'a')
	fprintf (stderr, "Option -%c requires an amount argument.\n", optopt);
      else if (isprint (optopt))
	fprintf (stderr, "Unknown option `-%c'.\n", optopt);
      else
	fprintf (stderr, "Unknown option `\\x%x'.\n", optopt);
      exit(EXIT_FAILURE);
      break;
    }
  }

  // require correct path and amount
  if(aflag == 0 || pflag == 0) {
      fprintf (stderr, "Parameters: -p directory-path -a gold-amount [-d]\n");
      fprintf (stderr, "Example: -a 200000 -p \"/home/milosz/.local/share/Icewind Dale - Enhanced Edition/save/000000008-2/\"\n");
      exit(EXIT_FAILURE);
  }
  
  // print debug information
  if(dflag == 1) {
    printf("Defined file path   = %s\n", path);
    printf("Defined gold amount = %ld\n", amount);
  }

  // open save file
  fp=fopen(path_buffer,"r+");
  if(fp != NULL){
    if(verify_file_type(fp) == 0) {
      // read gold amount 
      fseek(fp, 24, SEEK_SET);
      fread(&current_gold,1,4,fp);

      // print debug information
      if(dflag == 1)
	printf("Old gold amount     = %i\n", current_gold);

      // write new walue
      fseek(fp, 24, SEEK_SET);
      fwrite(&amount, 1, sizeof(unsigned int), fp);
    }
    fclose(fp);  
  }
  exit(EXIT_SUCCESS);  
}


// verify Icewind Dale: EE save game
int verify_file_type(FILE *fp) {
  char buffer[8];

  // store current file position
  long int position = ftell(fp);

  // rewind file to the beginning
  rewind(fp);

  // read 8 characters
  fread(&buffer,1,8,fp);

  // restore file position  
  fseek(fp, position, SEEK_SET);

  if(strcmp(buffer, FILE_TYPE) == 0)
    return 0;
  else
    return 1;
}

Usage

Specify gold amount and save file location to automatically apply changes.

$ ./alchemist -a 9968543  -p "/home/milosz/.local/share/Icewind Dale - Enhanced Edition/save/000000008-2/" -d
    
Defined file path   = /home/milosz/.local/share/Icewind Dale - Enhanced Edition/save/000000008-2/
Defined gold amount = 9968543
Old gold amount     = 540

References

Source code is available in Icewind Dale: EE repository.

Milosz Galazka's Picture

About Milosz Galazka

Milosz is a Linux Foundation Certified Engineer working for a successful Polish company as a system administrator and a long time supporter of Free Software Foundation and Debian operating system.

Gdansk, Poland https://sleeplessbeastie.eu