static bool tryload(Settings *setfile)
{
   char setfilename_tmp[1024];
   RFILE *fp = NULL;

   retro_create_path_string(setfilename_tmp, sizeof(setfilename_tmp), g_dir, setfilename);

   fp = filestream_open(setfilename_tmp, RETRO_VFS_FILE_ACCESS_READ, 
         RETRO_VFS_FILE_ACCESS_HINT_NONE);
   if (!fp)
   {
      NX_ERR("Couldn't open file %s.\n", setfilename_tmp);
      return 1;
   }

   NX_LOG("Loading settings...\n");

   setfile->version = 0;
   filestream_read(fp, setfile, sizeof(Settings));

   if (setfile->version != SETTINGS_VERSION)
   {
      NX_ERR("Wrong settings version %04x.\n", setfile->version);
      return 1;
   }

   filestream_close(fp);
   return 0;
}
Exemple #2
0
static bool check_data_exists()
{
   char fname[1024];
	retro_create_subpath_string(fname, sizeof(fname), g_dir, data_dir, "npc.tbl");
	NX_LOG("check_data_exists: %s\n", fname);

	if (file_exists(fname))
      return 0;
	
   NX_ERR("Fatal Error\n");

   NX_ERR("Missing \"%s\" directory.\n", data_dir);
   NX_ERR("Please copy it over from a Doukutsu installation.\n");
	
	return 1;
}
bool settings_save(Settings *setfile)
{
   char setfilename_tmp[1024];
   RFILE *fp = NULL;

   if (!setfile)
      setfile = &normal_settings;

   retro_create_path_string(setfilename_tmp, sizeof(setfilename_tmp), g_dir, setfilename);

   fp = filestream_open(setfilename_tmp, RETRO_VFS_FILE_ACCESS_WRITE, 
         RETRO_VFS_FILE_ACCESS_HINT_NONE);
   if (!fp)
   {
      NX_ERR("Couldn't open file %s.\n", setfilename_tmp);
      return 1;
   }

   NX_LOG("Writing settings...\n");

   for(int i=0;i<INPUT_COUNT;i++)
      setfile->input_mappings[i] = input_get_mapping(i);

   setfile->version = SETTINGS_VERSION;
   filestream_write(fp, setfile, sizeof(Settings));
   filestream_close(fp);
   return 0;
}
Exemple #4
0
uint8_t read_U8(const uint8_t **data, const uint8_t *data_end)
{
	if (*data > data_end)
	{
		NX_ERR("read_U8: read past end of buffer: *data > data_end\n");
		return 0xfe;
	}
	
	return *(*data)++;
}
bool SIFLoader::LoadHeader(const char *filename)
{
CFILE *fp;
uint32_t magick;

	ClearIndex();
	
	if (fFP) cclose(fFP);
	fp = fFP = copen(filename, "rb");
	
	if (!fp)
	{
		NX_ERR("SIFLoader::LoadHeader: failed to open file '%s'\n", filename);
		return 1;
	}
	
	if ((magick = cgetl(fp)) != SIF_MAGICK)
	{
		NX_ERR("SIFLoader::LoadHeader: magick check failed--this isn't a SIF file or is wrong version?\n");
		NX_ERR(" (expected %08x, got %08x)\n", SIF_MAGICK, magick);
		return 1;
	}
	
	int nsections = cgetc(fp);
	NX_LOG("SIFLoader::LoadHeader: read index of %d sections\n", nsections);
	
	for(int i=0;i<nsections;i++)
	{
		SIFIndexEntry *entry = new SIFIndexEntry;
		
		entry->type = cgetc(fp);		// section type
		entry->foffset = cgetl(fp);		// absolute offset in file
		entry->length = cgetl(fp);		// length of section data
		entry->data = NULL;				// we won't load it until asked
		
		fIndex.AddItem(entry);
		//NX_LOG("  - Sect%02d @ %04x\n", entry->type, entry->foffset);
	}
	
	// ..leave file handle open, its ok
	return 0;
}
static Object *mbubble_find_target(void)
{
    Object *target = FindObjectByID2(1000);
    if (!target)
    {
        NX_ERR("ai_miserys_bubble: failed to find a target object with ID2=1000\n");
        return NULL;
    }

    return target;
}
Exemple #7
0
void write_Variable(DBuffer *out, const uint8_t *data, int len)
{
	if (len > 255)
	{
		NX_ERR("write_Variable: input length > 255\n");
		len = 255;
	}
	
	out->AppendChar(len);
	out->AppendData(data, len);
}
Exemple #8
0
void write_Variable16(DBuffer *out, DBuffer *in)
{
	int len = in->Length();
	if (len > 65535)
	{
		NX_ERR("write_Variable16: input length > 65535\n");
		len = 65535;
	}
	
	out->Append16(len);
	out->AppendData(in->Data(), len);
}
// add an item to the inventory list (generates an error msg if inventory is full)
void AddInventory(int item)
{
	if (player->ninventory+1 >= MAX_INVENTORY)
   {
      NX_ERR("<<<AddInventory: inventory is full>>\n");
      game.running = 0;
      return;
   }
	
	player->inventory[player->ninventory++] = item;
	sound(SND_GET_ITEM);
	RefreshInventoryScreen();
}
Exemple #10
0
uint32_t read_U32(const uint8_t **data, const uint8_t *data_end)
{
	const uint8_t *ptr = *data;
	
	if ((ptr + 3) > data_end)
	{
		NX_ERR("read_U32: read past end of buffer: *data + 3 > data_end\n");
		return 0xfefefefe;
	}
	
	*data = (ptr + 4);
	return (ptr[3] << 24) | (ptr[2] << 16) | (ptr[1] << 8) | ptr[0];
}
Exemple #11
0
void read_Variable16(DBuffer *out, const uint8_t **data, const uint8_t *data_end)
{
	uint16_t len = read_U16(data, data_end);
	const uint8_t *ptr = *data;
	
	if ((ptr + (len - 1)) > data_end)
	{
		NX_ERR("read_Variable16: read past end of buffer: *ptr+len > data_end\n");
		return;
	}
	
	out->SetTo(ptr, len);
	*data = (ptr + len);
}
Exemple #12
0
// return a random number between min and max inclusive
int random(int min, int max)
{
   int range, val;

   if (max < min)
   {
      NX_ERR("random(): warning: max < min [%d, %d]\n", min, max);
      min ^= max;
      max ^= min;
      min ^= max;
   }

   range = (max - min);

   if (range >= RAND_MAX)
   {
      NX_ERR("random(): range > RAND_MAX\n", min, max);
      return 0;
   }

   val = getrand() % (range + 1);
   return val + min;
}
Exemple #13
0
uint16_t read_U16(const uint8_t **data, const uint8_t *data_end)
{
	const uint8_t *ptr = *data;
	
	if ((ptr + 1) > data_end)
	{
		NX_ERR("read_U16: read past end of buffer: *data + 1 > data_end\n");
		return 0xfefe;
	}
	
	*data = (ptr + 2);
	// we should not just cast to a uint16_t, as some processors
	// e.g. ARM would have alignment issues then, plus endian issues on others.
	return (ptr[1] << 8) | ptr[0];
}
void SIFSpritesSect::LoadPointList(SIFPointList *lst, const uint8_t **data, const uint8_t *data_end)
{
	lst->count = read_U8(data, data_end);
	if (lst->count > SIF_MAX_BLOCK_POINTS)
	{
		NX_ERR("SIFSpritesSect::LoadPointList: too many block points (%d, max=%d)\n", lst->count, SIF_MAX_BLOCK_POINTS);
		return;
	}
	
	for(int i=0;i<lst->count;i++)
	{
		lst->point[i].x = (int16_t)read_U16(data, data_end);
		lst->point[i].y = (int16_t)read_U16(data, data_end);
	}
}
void FileBuffer::CheckFlush(int maxsize)
{
	if (fBuffer.Length() >= maxsize)
	{
		if (fFP)
		{
			//NX_LOG("CheckFlush wrote %d bytes", fBuffer.Length()\n);
			fwrite(fBuffer.Data(), fBuffer.Length(), 1, fFP);
			fBuffer.Clear();
		}
		else
		{
			NX_ERR("CheckFlush: no file\n");
		}
	}
}
Exemple #16
0
char read_nonblank_char(const char **data, const char *data_end)
{
char ch;

	for(;;)
	{
		if (*data > data_end)
		{
			NX_ERR("read_nonblank_char: read past end of buffer: *data > data_end\n");
			return 254;
		}
		
		ch = read_char(data, data_end);
		if (ch != ' ' && ch != '\t' && ch != '\n' && ch != '\r') break;
	}
	
	return ch;
}
// allocate for an empty surface of the given size
bool NXSurface::AllocNew(int wd, int ht, NXFormat *format)
{
	Free();
	
#ifdef FRONTEND_SUPPORTS_RGB565
	fSurface = SDL_CreateRGBSurface(SDL_SRCCOLORKEY, wd, ht, 16, 0x1f << 11, 0x3f << 5, 0x1f << 0, 0);
#else
	fSurface = SDL_CreateRGBSurface(SDL_SRCCOLORKEY, wd, ht, 15, 0x1f << 10, 0x1f << 5, 0x1f << 0, 0);
#endif
	
	if (!fSurface)
	{
		NX_ERR("NXSurface::AllocNew: failed to allocate RGB surface\n");
		return 1;
	}
	
	return fSurface;
}
// load the surface from a .pbm or bitmap file
bool NXSurface::LoadImage(const char *pbm_name, bool use_colorkey, int use_display_format)
{
	SDL_Surface *image;

	Free();
	char filename[1024];

	NX_LOG("filename: %s\n", pbm_name);
	
	image = SDL_LoadBMP(pbm_name);
	if (!image)
	{
		NX_ERR("NXSurface::LoadImage: load failed of '%s'!\n", filename);
		return 1;
	}
	
	fSurface = Scale(image, SCALE, use_colorkey, true, use_display_format);
	return (fSurface == NULL);
}
// load the surface from a .pbm or bitmap file
bool NXSurface::LoadImage(const char *pbm_name, bool use_colorkey)
{
	Free();

	fSurface = SDL_LoadBMP(pbm_name);
	if (!fSurface)
	{
		NX_ERR("NXSurface::LoadImage: load failed of '%s'!\n", pbm_name);
		return 1;
	}
	
	uint8_t color = SDL_MapRGB(fSurface->format, 0, 0, 0);

	// set colorkey to black if requested
	if (use_colorkey)
		SDL_SetColorKey(fSurface, SDL_SRCCOLORKEY, color);

	return (fSurface == NULL);
}
// load into memory and return a pointer to the section of type 'type',
// or NULL if the file doesn't have a section of that type.
uint8_t *SIFLoader::FindSection(int type, int *length_out)
{
	// try and find the section in the index
	for(int i=0;;i++)
	{
		SIFIndexEntry *entry = (SIFIndexEntry *)fIndex.ItemAt(i);
		if (!entry) break;
		
		if (entry->type == type)
		{	// got it!
			
			// haven't loaded it yet? need to fetch it from file?
			if (!entry->data)
			{
				if (!fFP)
				{
					NX_ERR("SIFLoader::FindSection: entry found and need to load it, but file handle closed\n");
					if (length_out) *length_out = 0;
					return NULL;
				}
				
				NX_LOG("Loading SIF section %d from address %04x\n", type, entry->foffset);
				
				entry->data = (uint8_t *)malloc(entry->length);
				cseek(fFP, entry->foffset, SEEK_SET);
				cread(entry->data, entry->length, 1, fFP);
			}
			
			if (length_out) *length_out = entry->length;
			return entry->data;
		}
	}
	
	if (length_out) *length_out = 0;
	return NULL;
}
Exemple #21
0
void ai_npc_sue(Object *o)
{
	switch(o->state)
	{
		case 0:		// stand and blink
			o->timer = 0;
			o->frame = 0;
			o->xinertia = 0;
			o->sue.carried_by = NULL;
			randblink(o, 1, 4);
		break;
		
		case 3:		// walking
		case 4:		// walking
		case 5:		// face away
			ai_generic_npc(o);
		break;
		
		// got punched by Igor
		case 6:
			o->state = 7;
			o->frame = 7;
			o->timer = 0;
			sound(SND_ENEMY_SQUEAK);
		case 7:
			if (++o->timer > 10)
				o->state = 0;
		break;
		
		// got punched extra hard by Igor
		// flys through air backwards and crashes
		case 8:
			o->state = 9;
			o->frame = 7;
			o->timer = 0;
			sound(SND_ENEMY_SQUEAK);
			
			o->yinertia = -0x200;
			XMOVE(-0x400);
		case 9:
			if (++o->timer > 3 && o->blockd)
			{
				o->state = 10;
				o->dir ^= 1;
			}
		break;
		case 10:
			o->xinertia = 0;
			o->frame = 8;
		break;
		
		// punching the air (when she tells Igor "I'm not afraid of you!")
		case 11:
			o->state = 12;
			o->timer = 0;
			o->animframe = 0;
			o->animtimer = 0;
		case 12:
		{
			const static int punchframes[] = { 10, 0 };
			o->animate_seq(8, punchframes, 2);
		}
		break;
		
		// picked up & carried away by Igor
		case 13:
			o->frame = 11;
			o->xinertia = 0;
			o->yinertia = 0;
			o->state = 14;
			
			// find Igor
			o->sue.carried_by = FindObjectByID2(501);
			if (!o->sue.carried_by)
				NX_ERR("-- Could not find entity carrying Sue (ID 501)\n");
		case 14:	// being carried--see aftermove routine
			o->frame = 9;
		break;
		
		// spawn red crystal and call it to us (Undead Core intro)
		case 15:
		{
			o->PushBehind(dr_create_red_crystal(o->x+(128<<CSF), o->y));
			
			o->state = 16;
			o->xinertia = 0;
			o->frame = 0;
		}
		case 16:
		{
			crystal_xmark = o->x - (18<<CSF);
			crystal_ymark = o->y - (8<<CSF);
		}
		break;
		case 17:	// look up (still followed by red crystal)
		{
			o->xinertia = 0;
			o->frame = 12;
			
			crystal_xmark = o->x;
			crystal_ymark = o->y - (8<<CSF);
		}
		break;
		
		// run away from DOCTOR_GHOST and hide behind player
		case 20:
		{
			o->state = 21;
			o->frame = 2;
			o->animtimer = 0;
		}
		case 21:
		{
			ANIMATE(2, 2, 5);
			XMOVE(0x400);
			
			if (o->x < player->x - (8<<CSF))
			{
				o->dir = RIGHT;
				o->state = 0;
			}
		}
		break;
		
		// run, during "we've got to get out of here" post-undead core cutscene.
		case 30:
		{
			o->state = 31;
			o->frame = 2;
			o->animtimer = 0;
		}
		case 31:
		{
			ANIMATE(2, 2, 5);
			XMOVE(0x400);
		}
		break;
		
		case 40:	// she jumps off the island
		{
			o->state = 41;
			o->frame = 9;
			o->yinertia = -0x400;
		}
		break;
		
		/*default:
			NX_ERR("-- Sue entered unhandled state %d (0x%02x)\n", o->state, o->state);
			exit(1);*/
	}
	
	o->yinertia += 0x40;
	LIMITX(0x400);
	LIMITY(0x5ff);
}
bool extract_pxt(FILE *fp)
{
struct
{
	union
	{
		int intvalue;
		double fpvalue;
	} values[50];
} chan[4];
int s, c, i;

char slash;
#ifdef _WIN32
slash = '\\';
#else
slash = '/';
#endif

	for(s=0;;s++)
	{
		if (!snd[s].id) break;
		
		char outfilename[MAXPATHLEN];
      char outpath[MAXPATHLEN];
		snprintf(outfilename, sizeof(outfilename), "%s%cpxt%cfx%02x.pxt", g_dir, slash, slash, snd[s].id);
		snprintf(outpath, sizeof(outpath), "%s%cpxt", g_dir, slash);
		NX_LOG("[ %s ]\n", outfilename);

#if defined(_WIN32)
		_mkdir(outpath);
#else
		mkdir(outpath, 0755);
#endif
		FILE *fpo = fopen(outfilename, "wb");
		if (!fpo)
		{
			NX_ERR("failed to open %s\n", outfilename);
			return 1;
		}
		
		fseek(fp, snd[s].offset, SEEK_SET);
		memset(chan, 0, sizeof(chan));
		
		// load data
		for(c=0;c<snd[s].nchanl;c++)
		{
			for(i=0;fields[i].name;i++)
			{
				if (fields[i].is_integer)
				{
					chan[c].values[i].intvalue = fgetl(fp);
				}
				else
				{
					chan[c].values[i].fpvalue = fgetfloat(fp);
				}
			}
			
			// skip padding between sections
			if (fgetl(fp) != 0)
			{
				NX_ERR("PXT out of sync\n");
				return 1;
			}
		}
		
		// write human-readable section
		for(c=0;c<4;c++)
		{
			for(i=0;fields[i].name;i++)
			{
				if (fields[i].is_integer)
					fprintf(fpo, "%s:%d\r\n", fields[i].name, chan[c].values[i].intvalue);
				else
					fprintf(fpo, "%s:%.2f\r\n", fields[i].name, chan[c].values[i].fpvalue);
			}
			
			fprintf(fpo, "\r\n");
		}
		
		// write machine-readable section
		for(c=0;c<4;c++)
		{
			fprintf(fpo, "{");
			
			for(i=0;fields[i].name;i++)
			{
				const char *suffix = (fields[i+1].name == NULL) ? "},\r\n" : ",";
				
				if (fields[i].is_integer)
					fprintf(fpo, "%d%s", chan[c].values[i].intvalue, suffix);
				else
					fprintf(fpo, "%.2f%s", chan[c].values[i].fpvalue, suffix);
			}
		}
		
		fclose(fpo);
	}
	
	return 0;
}
bool SIFSpritesSect::Decode(const uint8_t *data, int datalen, \
						  SIFSprite *sprites, int *nsprites_out, int maxsprites)
{
const uint8_t *data_end = data + (datalen - 1);
int i, f, nsprites;
	
	nsprites = read_U16(&data, data_end);
	if (nsprites_out) *nsprites_out = nsprites;
	
	if (nsprites >= maxsprites)
	{
		NX_ERR("SIFSpritesSect::Decode: too many sprites in file (nsprites=%d, maxsprites=%d)\n", nsprites, maxsprites);
		return 1;
	}
	
	NX_LOG("SIFSpritesSect: loading %d sprites\n", nsprites);
	for(i=0;i<nsprites;i++)
	{
		if (data > data_end)
		{
			NX_ERR("SIFSpritesSect::Decode: section corrupt: overran end of data\n");
			return 1;
		}
		
		// read sprite-level fields
		sprites[i].w = read_U8(&data, data_end);
		sprites[i].h = read_U8(&data, data_end);
		sprites[i].spritesheet = read_U8(&data, data_end);
		
		sprites[i].nframes = read_U8(&data, data_end);
		sprites[i].ndirs = read_U8(&data, data_end);
		
		if (sprites[i].ndirs > SIF_MAX_DIRS)
		{
			NX_ERR("SIFSpritesSect::Decode: SIF_MAX_DIRS exceeded on sprite %d (ndirs=%d)\n", i, sprites[i].ndirs);
			return 1;
		}
		
		LoadRect(&sprites[i].bbox, &data, data_end);
		LoadRect(&sprites[i].solidbox, &data, data_end);
		
		LoadPoint(&sprites[i].spawn_point, &data, data_end);
		
		LoadPointList(&sprites[i].block_l, &data, data_end);
		LoadPointList(&sprites[i].block_r, &data, data_end);
		LoadPointList(&sprites[i].block_u, &data, data_end);
		LoadPointList(&sprites[i].block_d, &data, data_end);
		
		// malloc enough space to hold the specified number
		// of apple fritters, i mean, frames.
		sprites[i].frame = (SIFFrame *)malloc(sizeof(SIFFrame) * sprites[i].nframes);
		
		// then load all frames
		for(f=0;f<sprites[i].nframes;f++)
		{
			if (LoadFrame(&sprites[i].frame[f], sprites[i].ndirs, &data, data_end))
				return 1;
		}
	}
	
	return 0;
}
// load savefile #num into the given Profile structure.
bool profile_load(const char *pfname, Profile *file)
{
   int i, curweaponslot;
   FILE *fp = fopen(pfname, "rb");

   memset(file, 0, sizeof(Profile));

   if (!fp)
      return 1;

   if (!fverifystring(fp, "Do041220"))
      goto error;

   file->stage = fgetl(fp);
   file->songno = fgetl(fp);

   file->px = fgetl(fp);
   file->py = fgetl(fp);
   file->pdir = CVTDir(fgetl(fp));

   file->maxhp = fgeti(fp);
   file->num_whimstars = fgeti(fp);
   file->hp = fgeti(fp);

   fgeti(fp);						// unknown value
   curweaponslot = fgetl(fp);		// current weapon (slot, not number, converted below)
   fgetl(fp);						// unknown value
   file->equipmask = fgetl(fp);	// equipped items

   // load weapons
   fseek(fp, PF_WEAPONS_OFFS, SEEK_SET);
   for(i=0;i<MAX_WPN_SLOTS;i++)
   {
      int level, xp, maxammo, ammo;
      int type = fgetl(fp);
      if (!type)
         break;

      level   = fgetl(fp);
      xp      = fgetl(fp);
      maxammo = fgetl(fp);
      ammo    = fgetl(fp);

      file->weapons[type].hasWeapon = true;
      file->weapons[type].level = (level - 1);
      file->weapons[type].xp = xp;
      file->weapons[type].ammo = ammo;
      file->weapons[type].maxammo = maxammo;

      if (i == curweaponslot)
         file->curWeapon = type;
   }

   /* load inventory */
   file->ninventory = 0;
   fseek(fp, PF_INVENTORY_OFFS, SEEK_SET);
   for(i=0;i<MAX_INVENTORY;i++)
   {
      int item = fgetl(fp);
      if (!item)
         break;

      file->inventory[file->ninventory++] = item;
   }

   /* load teleporter slots */
   file->num_teleslots = 0;
   fseek(fp, PF_TELEPORTER_OFFS, SEEK_SET);

   for(i=0;i<NUM_TELEPORTER_SLOTS;i++)
   {
      int slotno   = fgetl(fp);
      int scriptno = fgetl(fp);
      if (slotno == 0)
         break;

      file->teleslots[file->num_teleslots].slotno = slotno;
      file->teleslots[file->num_teleslots].scriptno = scriptno;
      file->num_teleslots++;
   }

   /* load flags */
   fseek(fp, PF_FLAGS_OFFS, SEEK_SET);
   if (!fverifystring(fp, "FLAG"))
   {
      NX_ERR("profile_load: missing 'FLAG' marker\n");
      goto error;
   }

   fresetboolean();
   for(i=0;i<NUM_GAMEFLAGS;i++)
      file->flags[i] = fbooleanread(fp);

   fclose(fp);
   return 0;

error:
   fclose(fp);
   return 1;
}
Exemple #25
0
static void fatal(const char *str)
{
	NX_ERR("Fatal error: '%s'\n", str);
}
Exemple #26
0
void pre_main(void)
{
#ifdef DEBUG_LOG
char debug_fname[1024];
retro_create_path_string(debug_fname, sizeof(debug_fname), g_dir, "debug.txt");
SetLogFilename(debug_fname);
#endif
	// start up inputs first thing because settings_load may remap them
	input_init();
	
	// load settings, or at least get the defaults,
	// so we know the initial screen resolution.
	settings_load();

   char filename[1024];
	FILE *fp;

	NX_LOG("= Extracting Files =\n");

	retro_create_path_string(filename, sizeof(filename), g_dir, "Doukutsu.exe");
	fp = fopen(filename, "rb");

   extract_files(fp);

	if (sound_init()) { fatal("Failed to initialize sound."); error = 1; return; }
   
	extract_stages(fp);

	fclose(fp);
	
   settings->files_extracted = true;
   settings_save();
	
	if (Graphics::init(settings->resolution)) { NX_ERR("Failed to initialize graphics.\n"); error = 1; return; }
	if (font_init()) { NX_ERR("Failed to load font.\n"); error = 1; return; }
	
	//return;
	
	if (check_data_exists())
	{
		error = 1;
		return;
	}
	
	//Graphics::ShowLoadingScreen();
	if (trig_init()) { fatal("Failed trig module init."); error = 1; return; }
	
	if (tsc_init()) { fatal("Failed to initialize script engine."); error = 1; return; }
	if (textbox.Init()) { fatal("Failed to initialize textboxes."); error = 1; return; }
	if (Carets::init()) { fatal("Failed to initialize carets."); error = 1; return; }
	
	if (game.init())
	{
		error = 1;
		return;
	}
	game.setmode(GM_NORMAL);
	// set null stage just to have something to do while we go to intro
	game.switchstage.mapno = 0;
	
	//#define REPLAY
	#ifdef REPLAY
		game.switchstage.mapno = START_REPLAY;
		//Replay::set_ffwd(6000);
		//Replay::set_stopat(3500);
		game.switchstage.param = 1;
	#else
		//game.switchstage.mapno = LOAD_GAME;
		//game.pause(GP_OPTIONS);
		
		if (settings->skip_intro && file_exists(GetProfileName(settings->last_save_slot)))
			game.switchstage.mapno = LOAD_GAME;
		else
			game.setmode(GM_INTRO);
	#endif
	
	// for debug
	if (game.paused) { game.switchstage.mapno = 0; game.switchstage.eventonentry = 0; }
	if (game.switchstage.mapno == LOAD_GAME) inhibit_loadfade = true;
	
	game.running = true;
	freshstart = true;
	
	NX_LOG("Entering main loop...\n");
	
	//return;
}
bool extract_files(FILE *exefp)
{
uint8_t *buffer;
uint8_t *file;
uint32_t length;
uint32_t crc;
bool check_crc = true;
bool first_crc_failure = true;

	buffer = (uint8_t *)malloc(MAX_FILE_SIZE);
	crc_init();
	
	for(int i=0;;i++)
	{
		if (!files[i].filename) break;
		char outfilename[1024];
		retro_create_path_string(outfilename, sizeof(outfilename), g_dir, files[i].filename);
		
		NX_LOG("[ %s ]\n", outfilename);
		
		// initialize header if any
		file = buffer;
		length = files[i].length;
		
		if (files[i].header)
		{
			memcpy(buffer, files[i].header, HEADER_LEN);
			file += HEADER_LEN;
			length += HEADER_LEN;
		}
		
		// read data from exe
		fseek(exefp, files[i].offset, SEEK_SET);
		fread(file, files[i].length, 1, exefp);
		
		if (check_crc)
		{
			crc = crc_calc(file, files[i].length);
			if (crc != files[i].crc)
			{
				NX_ERR("File '%s' failed CRC check.\n", outfilename);
				NX_ERR("\n");
				
					NX_ERR("[I]gnore\n");
					NX_ERR("Ignore [A]ll\n");
					NX_ERR("[S]top\n");
					#define IGNORE_BTN		SDLK_i
					#define IGNORE_ALL_BTN	SDLK_a
					#define STOP_BTN		SDLK_s
				
				first_crc_failure = false;
			}
		}
		
		// write out the file
		createdir(outfilename);
		
		FILE *fp = fopen(outfilename, "wb");
		if (!fp)
		{
			NX_ERR("Failed to open '%s' for writing.\n", outfilename);
			free(buffer);
			return 1;
		}
		
		fwrite(buffer, length, 1, fp);
		fclose(fp);
	}
	
	free(buffer);
	return 0;
}
// static function, and requires a reload of all surfaces
void NXSurface::SetScale(int factor)
{
	NX_ERR("NXSurface::SetScale: CONFIG_MUTABLE_SCALE not set\n");
}
bool extract_pxt(FILE *fp, int s, stPXSound *outsnd)
{
struct
{
	union
	{
		int intvalue;
		double fpvalue;
	} values[21];
} chan[4];
int c, i;
int found = 0;
char slash;
#ifdef _WIN32
slash = '\\';
#else
slash = '/';
#endif
   for (i = 0; i < sizeof(snd) / sizeof(snd[0]); i++)
   {
      if (snd[i].id == s)
      {
         found = 1;
         s = i;
         break;
      }
   }
   if (!found)
      return 1;

		fseek(fp, snd[s].offset, SEEK_SET);
		memset(chan, 0, sizeof(chan));
		
		// load data
		for(c=0;c<snd[s].nchanl;c++)
		{
			for(i=0;fields[i].name;i++)
			{
				if (fields[i].is_integer)
				{
					chan[c].values[i].intvalue = fgetl(fp);
				}
				else
				{
					chan[c].values[i].fpvalue = fgetfloat(fp);
				}
			}
			
			// skip padding between sections
			if (fgetl(fp) != 0)
			{
				NX_ERR("PXT out of sync\n");
				return 1;
			}
		}
   
      for (c = 0; c < 4; c++)
      {
         outsnd->chan[c].enabled = chan[c].values[0].intvalue;
         outsnd->chan[c].size_blocks = chan[c].values[1].intvalue;
         
         pxt_SetModel(&outsnd->chan[c].main, chan[c].values[2].intvalue);
         outsnd->chan[c].main.repeat = chan[c].values[3].fpvalue;
         outsnd->chan[c].main.volume = chan[c].values[4].intvalue;
         outsnd->chan[c].main.offset = chan[c].values[5].intvalue;
         
         pxt_SetModel(&outsnd->chan[c].pitch, chan[c].values[6].intvalue);
         outsnd->chan[c].pitch.repeat = chan[c].values[7].fpvalue;
         outsnd->chan[c].pitch.volume = chan[c].values[8].intvalue;
         outsnd->chan[c].pitch.offset = chan[c].values[9].intvalue;
         
         pxt_SetModel(&outsnd->chan[c].volume, chan[c].values[10].intvalue);
         outsnd->chan[c].volume.repeat = chan[c].values[11].fpvalue;
         outsnd->chan[c].volume.volume = chan[c].values[12].intvalue;
         outsnd->chan[c].volume.offset = chan[c].values[13].intvalue;
         
         outsnd->chan[c].envelope.initial = chan[c].values[14].intvalue;

         outsnd->chan[c].envelope.time[0] = chan[c].values[15].intvalue;
         outsnd->chan[c].envelope.val[0] = chan[c].values[16].intvalue;
         outsnd->chan[c].envelope.time[1] = chan[c].values[17].intvalue;
         outsnd->chan[c].envelope.val[1] = chan[c].values[18].intvalue;
         outsnd->chan[c].envelope.time[2] = chan[c].values[19].intvalue;
         outsnd->chan[c].envelope.val[2] = chan[c].values[20].intvalue;
      }
	
	return 0;
}