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; }
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; }
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; }
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); }
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(); }
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]; }
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); }
// 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; }
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"); } } }
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; }
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; }
static void fatal(const char *str) { NX_ERR("Fatal error: '%s'\n", str); }
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; }