private void InitCowSystem() { if (SystemVars.CurrentCd == 0) return; if (_cowFile == null) { var cowName = $"SPEECH{SystemVars.CurrentCd}.CLF"; _cowFile = TryToOpen(cowName); //if (_cowFile.isOpen()) //{ // debug(1, "Using FLAC compressed Speech Cluster"); //} _cowMode = CowMode.CowFLAC; } if (_cowFile == null) { var cowName = $"SPEECH{SystemVars.CurrentCd}.CLU"; _cowFile = TryToOpen(cowName); //if (!_cowFile.isOpen()) //{ // _cowFile.open("speech.clu"); //} // TODO: debug(1, "Using uncompressed Speech Cluster"); _cowMode = CowMode.CowWave; } if (SystemVars.Platform == Platform.PSX) { // There's only one file on the PSX, so set it to the current disc. _currentCowFile = (byte)SystemVars.CurrentCd; if (_cowFile == null) { _cowFile = TryToOpen("speech.dat"); _cowMode = CowMode.CowPSX; } } if (_cowFile == null) _cowFile = TryToOpen("speech.clu"); if (_cowFile == null) { _cowFile = TryToOpen("cows.mad"); _cowMode = CowMode.CowDemo; } if (_cowFile != null) { if (SystemVars.Platform == Platform.PSX) { // Get data from the external table file using (var tableFile = TryToOpen("speech.tab")) { _cowHeaderSize = (uint)tableFile.BaseStream.Length; _cowHeader = new UIntAccess(new byte[_cowHeaderSize], 0); if ((_cowHeaderSize & 3) != 0) throw new InvalidOperationException($"Unexpected cow header size {_cowHeaderSize}"); for (var cnt = 0; cnt < _cowHeaderSize / 4; cnt++) _cowHeader[cnt] = tableFile.ReadUInt32(); } } else { _cowHeaderSize = _cowFile.ReadUInt32(); _cowHeader = new UIntAccess(new byte[_cowHeaderSize], 0); if ((_cowHeaderSize & 3) != 0) throw new InvalidOperationException("Unexpected cow header size {_cowHeaderSize}"); for (var cnt = 0; cnt < (_cowHeaderSize / 4) - 1; cnt++) _cowHeader[cnt] = _cowFile.ReadUInt32(); _currentCowFile = (byte)SystemVars.CurrentCd; } } else { // TODO: warning($"Sound::initCowSystem: Can't open SPEECH{SystemVars.CurrentCd}.CLU"); } }
public uint FnCheckForTextLine(uint textId) { byte retVal = 0; if (_textList[textId / ITM_PER_SEC, 0] == 0) return 0; // section does not exist byte lang = (byte)SystemVars.Language; var textData = new UIntAccess(_resMan.OpenFetchRes(_textList[textId / ITM_PER_SEC, lang]), Header.Size); if ((textId & ITM_ID) < _resMan.ReadUInt32(textData[0])) { textData.Offset += 4; if (textData[(int)(textId & ITM_ID)] != 0) retVal = 1; } _resMan.ResClose(_textList[textId / ITM_PER_SEC, lang]); return retVal; }
private void OpenScriptResourceLittleEndian(uint id) { bool needByteSwap = false; if (_isBigEndian) { // Cluster files are in big endian fomat. // If the resource are not in memory anymore, and therefore will be read // from disk, they will need to be byte swaped. MemHandle memHandle = ResHandle(id); if (memHandle != null) needByteSwap = (memHandle.cond == MemMan.MEM_FREED); } ResOpen(id); if (needByteSwap) { MemHandle handle = ResHandle(id); if (handle == null) return; // uint32 totSize = handle.size; Header head = new Header(handle.data); head.comp_length = ScummHelper.SwapBytes(head.comp_length); head.decomp_length = ScummHelper.SwapBytes(head.decomp_length); head.version = ScummHelper.SwapBytes(head.version); UIntAccess data = new UIntAccess(handle.data, Header.Size); uint size = handle.size - Header.Size; if ((size & 3) != 0) throw new InvalidOperationException($"Odd size during script endian conversion. Resource ID ={id}, size = {size}"); size >>= 2; for (uint cnt = 0; cnt < size; cnt++) { data[0] = ScummHelper.SwapBytes(data[0]); data.Offset += 4; } } }
public void CloseCowSystem() { _cowFile.Dispose(); _cowFile = null; _cowHeader = null; _currentCowFile = 0; }
private void RenderParallax(byte[] data) { ushort paraScrlX, paraScrlY; ushort scrnScrlX, scrnScrlY; ushort scrnWidth, scrnHeight; ushort paraSizeX, paraSizeY; ParallaxHeader header = null; UIntAccess lineIndexes = null; if (SystemVars.Platform == Platform.PSX) //Parallax headers are different in PSX version FetchPsxParallaxSize(data, out paraSizeX, out paraSizeY); else { header = new ParallaxHeader(data); lineIndexes = new UIntAccess(data, ParallaxHeader.Size); paraSizeX = _resMan.ReadUInt16(header.sizeX); paraSizeY = _resMan.ReadUInt16(header.sizeY); } Debug.Assert((paraSizeX >= SCREEN_WIDTH) && (paraSizeY >= SCREEN_DEPTH)); // we have to render more than the visible screen part for displaying scroll frames scrnScrlX = (ushort)Math.Min((uint)_oldScrollX, Logic.ScriptVars[(int)ScriptVariableNames.SCROLL_OFFSET_X]); scrnWidth = (ushort)(SCREEN_WIDTH + Math.Abs((int)_oldScrollX - (int)Logic.ScriptVars[(int)ScriptVariableNames.SCROLL_OFFSET_X])); scrnScrlY = (ushort)Math.Min((uint)_oldScrollY, Logic.ScriptVars[(int)ScriptVariableNames.SCROLL_OFFSET_Y]); scrnHeight = (ushort)(SCREEN_DEPTH + Math.Abs((int)_oldScrollY - (int)Logic.ScriptVars[(int)ScriptVariableNames.SCROLL_OFFSET_Y])); if (_scrnSizeX != SCREEN_WIDTH) { double scrlfx = (paraSizeX - SCREEN_WIDTH) / ((double)(_scrnSizeX - SCREEN_WIDTH)); paraScrlX = (ushort)(scrnScrlX * scrlfx); } else paraScrlX = 0; if (_scrnSizeY != SCREEN_DEPTH) { double scrlfy = (paraSizeY - SCREEN_DEPTH) / ((double)(_scrnSizeY - SCREEN_DEPTH)); paraScrlY = (ushort)(scrnScrlY * scrlfy); } else paraScrlY = 0; if (SystemVars.Platform == Platform.PSX) { DrawPsxParallax(data, paraScrlX, scrnScrlX, scrnWidth); } else { for (ushort cnty = 0; cnty < scrnHeight; cnty++) { var src = _resMan.ReadUInt32(lineIndexes[cnty + paraScrlY]); var dest = scrnScrlX + (cnty + scrnScrlY) * _scrnSizeX; ushort remain = paraScrlX; ushort xPos = 0; while (remain != 0) { // skip past the first part of the parallax to get to the right scrolling position byte doSkip = data[src++]; if (doSkip <= remain) remain -= doSkip; else { xPos = (ushort)(doSkip - remain); dest += xPos; remain = 0; } byte doCopy = data[src++]; if (doCopy <= remain) { remain -= doCopy; src += doCopy; } else { ushort remCopy = (ushort)(doCopy - remain); Array.Copy(data, (int)(src + remain), _screenBuf, dest, remCopy); dest += remCopy; src += doCopy; xPos = remCopy; remain = 0; } } while (xPos < scrnWidth) { byte skip; if ((skip = data[src++]) != 0) { dest += skip; xPos += skip; } if (xPos < scrnWidth) { byte doCopy; if ((doCopy = data[src++]) != 0) { if (xPos + doCopy > scrnWidth) doCopy = (byte)(scrnWidth - xPos); Array.Copy(data, (int)src, _screenBuf, dest, doCopy); dest += doCopy; xPos += doCopy; src += doCopy; } } } } } }
void SaveThumbnail(BinaryWriter output, Surface thumb) { var bpp = Surface.GetBytesPerPixel(thumb.PixelFormat); if (bpp != 2 && bpp != 4) { // TODO: warning("trying to save thumbnail with bpp %u", bpp); return; } ThumbnailHeader header = new ThumbnailHeader(); header.Type = ScummHelper.MakeTag('T', 'H', 'M', 'B'); header.Size = (uint)(ThumbnailHeaderSize + thumb.Width * thumb.Height * bpp); header.Version = THMB_VERSION; header.Width = (ushort)thumb.Width; header.Height = (ushort)thumb.Height; output.WriteUInt32BigEndian(header.Type); output.WriteUInt32BigEndian(header.Size); output.WriteByte(header.Version); output.WriteUInt16BigEndian(header.Width); output.WriteUInt16BigEndian(header.Height); // Serialize the PixelFormat output.WriteByte(bpp); output.WriteByte(3); output.WriteByte(2); output.WriteByte(3); output.WriteByte(8); output.WriteByte(11); output.WriteByte(5); output.WriteByte(0); output.WriteByte(0); // Serialize the pixel data for (uint y = 0; y < thumb.Height; ++y) { switch (bpp) { case 2: { var pixels = new UShortAccess(thumb.Pixels, (int)(y * thumb.Width * 2)); for (uint x = 0; x < thumb.Width; ++x) { output.WriteUInt16BigEndian(pixels[0]); pixels.Offset += 2; } } break; case 4: { var pixels = new UIntAccess(thumb.Pixels, (int)(y * thumb.Width * 4)); for (var x = 0; x < thumb.Width; ++x) { output.WriteUInt32BigEndian(pixels[0]); pixels.Offset += 4; } } break; default: throw new NotSupportedException(); } } }
public bool RestoreGameFromFile(byte slot) { ushort cnt; var fName = $"sword1.{slot:D3}"; using (var inf = new BinaryReader(_saveFileMan.OpenForLoading(fName))) { // TODO: //if (inf==null) //{ // // Display an error message, and do nothing // // TODO: DisplayMessage(0, "Can't open file '%s'. (%s)", fName, _saveFileMan.popErrorDesc().c_str()); // return false; //} uint saveHeader = inf.ReadUInt32(); if (saveHeader != SAVEGAME_HEADER) { // Display an error message, and do nothing // TODO: DisplayMessage(0, "Save game '%s' is corrupt", fName); return false; } inf.BaseStream.Seek(40, SeekOrigin.Current); // skip description byte saveVersion = inf.ReadByte(); if (saveVersion > SAVEGAME_VERSION) { // TODO: warning("Different save game version"); return false; } if (saveVersion < 2) // These older version of the savegames used a flag to signal presence of thumbnail inf.BaseStream.Seek(1, SeekOrigin.Current); SkipThumbnail(inf); inf.ReadUInt32BigEndian(); // save date inf.ReadUInt16BigEndian(); // save time if (saveVersion < 2) { // Before version 2 we didn't had play time feature // TODO: g_engine.setTotalPlayTime(0); } else { var time = inf.ReadUInt32BigEndian(); // TODO: g_engine.setTotalPlayTime(time * 1000); } _restoreBuf = new byte[ ObjectMan.TOTAL_SECTIONS * 2 + Logic.NUM_SCRIPT_VARS * 4 + (SwordObject.Size - 12000)]; var liveBuf = new UShortAccess(_restoreBuf); var scriptBuf = new UIntAccess(_restoreBuf, 2 * ObjectMan.TOTAL_SECTIONS); var playerBuf = new UIntAccess(_restoreBuf, 2 * ObjectMan.TOTAL_SECTIONS + 4 * Logic.NUM_SCRIPT_VARS); for (cnt = 0; cnt < ObjectMan.TOTAL_SECTIONS; cnt++) liveBuf[cnt] = inf.ReadUInt16(); for (cnt = 0; cnt < Logic.NUM_SCRIPT_VARS; cnt++) scriptBuf[cnt] = inf.ReadUInt32(); uint playerSize = (SwordObject.Size - 12000) / 4; for (var cnt2 = 0; cnt2 < playerSize; cnt2++) playerBuf[cnt2] = inf.ReadUInt32(); // TODO: error //if (inf.err() || inf.eos()) //{ // displayMessage(0, "Can't read from file '%s'. (%s)", fName, _saveFileMan.popErrorDesc().c_str()); // delete inf; // free(_restoreBuf); // _restoreBuf = NULL; // return false; //} } return true; }
public void DoRestore() { var bufPos = new ByteAccess(_restoreBuf); _objMan.LoadLiveList(new UShortAccess(_restoreBuf)); bufPos.Offset += ObjectMan.TOTAL_SECTIONS * 2; for (var cnt = 0; cnt < Logic.NUM_SCRIPT_VARS; cnt++) { Logic.ScriptVars[cnt] = bufPos.Data.ToUInt32(bufPos.Offset); bufPos.Offset += 4; } uint playerSize = (SwordObject.Size - 12000) / 4; var cpt = _objMan.FetchObject(Logic.PLAYER); var playerRaw = new UIntAccess(cpt.Data, cpt.Offset); for (var cnt2 = 0; cnt2 < playerSize; cnt2++) { playerRaw[0] = bufPos.Data.ToUInt32(bufPos.Offset); playerRaw.Offset += 4; bufPos.Offset += 4; } Logic.ScriptVars[(int)ScriptVariableNames.CHANGE_DIR] = (uint)cpt.dir; Logic.ScriptVars[(int)ScriptVariableNames.CHANGE_X] = (uint)cpt.xcoord; Logic.ScriptVars[(int)ScriptVariableNames.CHANGE_Y] = (uint)cpt.ycoord; Logic.ScriptVars[(int)ScriptVariableNames.CHANGE_STANCE] = StaticRes.STAND; Logic.ScriptVars[(int)ScriptVariableNames.CHANGE_PLACE] = (uint)cpt.place; SystemVars.JustRestoredGame = 1; if (SystemVars.IsDemo) Logic.ScriptVars[(int)ScriptVariableNames.PLAYINGDEMO] = 1; }
private void SaveGameToFile(byte slot) { ushort cnt; var fName = $"sword1.{slot:D3}"; ushort[] liveBuf = new ushort[ObjectMan.TOTAL_SECTIONS]; using (var stream = _saveFileMan.OpenForSaving(fName)) using (var outf = new BinaryWriter(stream)) { //if (!outf) //{ // // Display an error message and do nothing // displayMessage(0, "Unable to create file '%s'. (%s)", fName, _saveFileMan.popErrorDesc().c_str()); // return; //} outf.WriteUInt32((uint)SAVEGAME_HEADER); outf.Write(StrToBytes(_saveNames[slot], 40)); outf.WriteByte(SAVEGAME_VERSION); if (!IsPanelShown()) // Generate a thumbnail only if we are outside of game menu SaveThumbnail(outf); // Date / time DateTime curTime = DateTime.Now; uint saveDate = (uint) ((curTime.Day & 0xFF) << 24 | ((curTime.Month + 1) & 0xFF) << 16 | ((curTime.Year + 1900) & 0xFFFF)); ushort saveTime = (ushort)((curTime.Hour & 0xFF) << 8 | ((curTime.Minute) & 0xFF)); outf.WriteUInt32BigEndian(saveDate); outf.WriteUInt16BigEndian(saveTime); // TODO: outf.WriteUInt32BigEndian(g_engine.getTotalPlayTime() / 1000); replaced by 0 outf.WriteUInt32BigEndian(0); _objMan.SaveLiveList(liveBuf); for (cnt = 0; cnt < ObjectMan.TOTAL_SECTIONS; cnt++) outf.WriteUInt16(liveBuf[cnt]); var cpt = _objMan.FetchObject(Logic.PLAYER); Logic.ScriptVars[(int)ScriptVariableNames.CHANGE_DIR] = (uint)cpt.dir; Logic.ScriptVars[(int)ScriptVariableNames.CHANGE_X] = (uint)cpt.xcoord; Logic.ScriptVars[(int)ScriptVariableNames.CHANGE_Y] = (uint)cpt.ycoord; Logic.ScriptVars[(int)ScriptVariableNames.CHANGE_STANCE] = StaticRes.STAND; Logic.ScriptVars[(int)ScriptVariableNames.CHANGE_PLACE] = (uint)cpt.place; for (cnt = 0; cnt < Logic.NUM_SCRIPT_VARS; cnt++) outf.WriteUInt32(Sword1.Logic.ScriptVars[cnt]); uint playerSize = (SwordObject.Size - 12000) / 4; var playerRaw = new UIntAccess(cpt.Data, cpt.Offset); for (var cnt2 = 0; cnt2 < playerSize; cnt2++) outf.WriteUInt32(playerRaw[cnt2]); } // TODO: error //if (outf.err()) // displayMessage(0, "Couldn't write to file '%s'. Device full? (%s)", fName, _saveFileMan.popErrorDesc().c_str()); //delete outf; }