Exemple #1
0
        protected override bool HandleSubTags(ref int offset)
        {
            if (_tbufferSize - offset >= 8)
            {
                var type           = System.Text.Encoding.UTF8.GetString(_tbuffer, offset, 4);
                var size           = ScummHelper.SwapBytes(BitConverter.ToUInt32(_tbuffer, offset + 4));
                var available_size = _tbufferSize - offset;
                switch (type)
                {
                case "MAP ":
                    _inData = false;
                    if (available_size >= (size + 8))
                    {
                        var tmp = new byte[_tbuffer.Length - offset];
                        Array.Copy(_tbuffer, offset, tmp, 0, tmp.Length);
                        HandleMap(tmp);
                    }
                    break;

                case "DATA":
                    _inData   = true;
                    _dataSize = (int)size;
                    offset   += 8;
                    {
                        int reqsize = 1;
                        if (_channels == 2)
                        {
                            reqsize *= 2;
                        }
                        if (_bitsize == 16)
                        {
                            reqsize *= 2;
                        }
                        else if (_bitsize == 12)
                        {
                            if (reqsize > 1)
                            {
                                reqsize = reqsize * 3 / 2;
                            }
                            else
                            {
                                reqsize = 3;
                            }
                        }
                        if ((size % reqsize) != 0)
                        {
                            Debug.WriteLine("Invalid iMUS sound data size : ({0} %% {1}) != 0, correcting...", size, reqsize);
                            size += (uint)(3 - (size % reqsize));
                        }
                    }
                    return(false);
//                    default:
//                        Console.Error.WriteLine("unknown Chunk in iMUS track : {0} ", type);
//                        break;
                }
                offset += (int)(size + 8);
                return(true);
            }
            return(false);
        }
Exemple #2
0
        protected virtual ColorCycle[] ReadCYCL()
        {
            var colorCycle = new ColorCycle[16];

            for (int i = 0; i < 16; i++)
            {
                var delay = ScummHelper.SwapBytes(_reader.ReadUInt16());
                var start = _reader.ReadByte();
                var end   = _reader.ReadByte();

                colorCycle[i] = new ColorCycle();

                if (delay == 0 || delay == 0x0aaa || start >= end)
                {
                    continue;
                }

                colorCycle[i].Counter = 0;
                colorCycle[i].Delay   = (ushort)(16384 / delay);
                colorCycle[i].Flags   = 2;
                colorCycle[i].Start   = start;
                colorCycle[i].End     = end;
            }

            return(colorCycle);
        }
Exemple #3
0
        bool HandleMap(byte[] data)
        {
            // Read the chunk size & skip over the chunk header
            var size = ScummHelper.SwapBytes(BitConverter.ToUInt32(data, 4));
            var i    = 8;

            while (size > 0)
            {
                var subType = System.Text.Encoding.UTF8.GetString(data, i, 4);
                var subSize = ScummHelper.SwapBytes(BitConverter.ToUInt32(data, i + 4));
                i    += 8;
                size -= 8;

                switch (subType)
                {
                case "FRMT":
//                        if (subSize != 20)
//                            Console.Error.WriteLine("invalid size for FRMT Chunk");
                    //uint32 imuse_start = READ_BE_UINT32(data);
                    //uint32 unk = READ_BE_UINT32(data+4);
                    _bitsize  = (int)ScummHelper.SwapBytes(BitConverter.ToUInt32(data, i + 8));
                    _rate     = (int)ScummHelper.SwapBytes(BitConverter.ToUInt32(data, i + 12));
                    _channels = (int)ScummHelper.SwapBytes(BitConverter.ToUInt32(data, i + 16));
                    Debug.Assert(_channels == 1 || _channels == 2);
                    break;

                case "TEXT":
                    // Ignore this
                    break;

                case "REGN":
//                        if (subSize != 8)
//                            Console.Error.WriteLine("invalid size for REGN Chunk");
                    break;

                case "STOP":
//                        if (subSize != 4)
//                            Console.Error.WriteLine("invalid size for STOP Chunk");
                    break;
//                    default:
//                        Console.Error.WriteLine("Unknown iMUS subChunk found : {0}, {1}", subType, subSize);
//                        break;
                }

                i    += (int)subSize;
                size -= subSize;
            }
            return(true);
        }
Exemple #4
0
        short ReadEndianSample(byte[] ptr, int offset)
        {
            ushort value;

            if (_is16Bit)
            {
                value = _isLE ? BitConverter.ToUInt16(ptr, offset) : ScummHelper.SwapBytes(BitConverter.ToUInt16(ptr, offset));
            }
            else
            {
                value = (ushort)(ptr[offset] << 8);
            }

            if (_isUnsigned)
            {
                value ^= 0x8000;
            }

            return((short)value);
        }
Exemple #5
0
        public static int Decode12BitsSample(byte[] src, out byte[] dst, int size)
        {
            int loop_size = size / 3;
            int s_size    = loop_size * 4;

            dst = new byte[s_size];
            var i   = 0;
            var ptr = 0;
            int tmp;

            while ((loop_size--) != 0)
            {
                byte v1 = src[i++];
                byte v2 = src[i++];
                byte v3 = src[i++];
                tmp = ((((v2 & 0x0f) << 8) | v1) << 4) - 0x8000;
                Array.Copy(BitConverter.GetBytes(ScummHelper.SwapBytes((ushort)tmp)), 0, dst, ptr, 2);
                ptr += 2;
                tmp  = ((((v2 & 0xf0) << 4) | v3) << 4) - 0x8000;
                Array.Copy(BitConverter.GetBytes(ScummHelper.SwapBytes((ushort)tmp)), 0, dst, ptr, 2);
                ptr += 2;
            }
            return(s_size);
        }
Exemple #6
0
        byte DrawLimb(Actor a, int limb)
        {
            var  cost   = a.Cost;
            byte result = 0;

            var lastDx = 0;
            var lastDy = 0;

            if (SkipLimbs)
            {
                return(0);
            }

            if (cost.Active[limb] == 0 || ((cost.Stopped & (1 << limb)) != 0))
            {
                return(0);
            }

            var p = cost.Curpos[limb];

            AkosOpcode code = (AkosOpcode)aksq[p];

            if (((ushort)code & 0x80) != 0)
            {
                code = (AkosOpcode)ScummHelper.SwapBytes(BitConverter.ToUInt16(aksq, p));
            }


            if (code == AkosOpcode.C021 || code == AkosOpcode.C022)
            {
                ushort s     = (ushort)(cost.Curpos[limb] + 4);
                var    extra = aksq[p + 3];
                byte   n     = extra;
                p   += (ushort)(extra + 2);
                code = (code == AkosOpcode.C021) ? AkosOpcode.ComplexChan : AkosOpcode.ComplexChan2;
            }

            if (code == AkosOpcode.Return || code == AkosOpcode.EndSeq)
            {
                return(0);
            }

            if (code != AkosOpcode.ComplexChan && code != AkosOpcode.ComplexChan2)
            {
                var off = ResourceFile7.ToStructure <AkosOffset>(akos, (int)(akof + 6 * ((ushort)code & 0xFFF)));

                Debug.Assert(((ushort)code & 0xFFF) * 6 < ScummHelper.SwapBytes(BitConverter.ToUInt32(akos, (int)(akof - 4))) - 8);
                Debug.Assert(((ushort)code & 0x7000) == 0);

                _srcptr = (int)off.akcd;
                Debug.Assert(_srcptr < akcd.Length);
                var costumeInfo = ResourceFile7.ToStructure <CostumeInfo>(akos, (int)(akci + off.akci));

                _width  = costumeInfo.width;
                _height = costumeInfo.height;
                var xmoveCur = _xmove + costumeInfo.rel_x;
                var ymoveCur = _ymove + costumeInfo.rel_y;
                _xmove += costumeInfo.move_x;
                _ymove -= costumeInfo.move_y;

                switch (_codec)
                {
                case 1:
                    result |= Codec1(xmoveCur, ymoveCur);
                    break;

                case 5:
                    result |= Codec5(xmoveCur, ymoveCur);
                    break;

                case 16:
                    result |= Codec16(xmoveCur, ymoveCur);
                    break;

                default:
                    throw new InvalidOperationException(string.Format("akos_drawLimb: invalid _codec {0}", _codec));
                }
            }
            else
            {
                if (code == AkosOpcode.ComplexChan2)
                {
                    lastDx = BitConverter.ToInt16(aksq, p + 2);
                    lastDy = BitConverter.ToInt16(aksq, p + 4);
                    p     += 4;
                }

                var extra = aksq[p + 2];
                p += 3;

                for (var i = 0; i != extra; i++)
                {
                    code = (AkosOpcode)aksq[p + 4];
                    if (((ushort)code & 0x80) != 0)
                    {
                        code = (AkosOpcode)ScummHelper.SwapBytes(BitConverter.ToUInt16(aksq, p + 4));
                    }
                    var off = ResourceFile7.ToStructure <AkosOffset>(akos, (int)(akof + 6 * ((ushort)code & 0xFFF)));

                    _srcptr = (int)off.akcd;
                    var costumeInfo = ResourceFile7.ToStructure <CostumeInfo>(akos, (int)(akci + off.akci));

                    _width  = costumeInfo.width;
                    _height = costumeInfo.height;

                    var xmoveCur = _xmove + BitConverter.ToInt16(aksq, p + 0);
                    var ymoveCur = _ymove + BitConverter.ToInt16(aksq, p + 2);

                    if (i == extra - 1)
                    {
                        _xmove += lastDx;
                        _ymove -= lastDy;
                    }

                    p += ((aksq[p + 4] & 0x80) != 0) ? (ushort)6 : (ushort)5;

                    switch (_codec)
                    {
                    case 1:
                        result |= Codec1(xmoveCur, ymoveCur);
                        break;

                    case 5:
                        result |= Codec5(xmoveCur, ymoveCur);
                        break;

                    case 16:
                        result |= Codec16(xmoveCur, ymoveCur);
                        break;

                    case 32:
                        result |= Codec32(xmoveCur, ymoveCur);
                        break;

                    default:
                        throw new InvalidOperationException(string.Format("akos_drawLimb: invalid _codec {0}", _codec));
                    }
                }
            }

            return(result);
        }
Exemple #7
0
        protected override bool HandleSubTags(ref int offset)
        {
            if (_tbufferSize - offset >= 8)
            {
                var type           = System.Text.Encoding.UTF8.GetString(_tbuffer, offset, 4);
                var size           = ScummHelper.SwapBytes(BitConverter.ToUInt32(_tbuffer, offset + 4));
                var available_size = _tbufferSize - offset;

                switch (type)
                {
                case "STRK":
                    _inData = false;
                    if (available_size >= (size + 8))
                    {
                        var subSize = ScummHelper.SwapBytes(BitConverter.ToUInt32(_tbuffer, offset + 4));
                        if (subSize != 14 && subSize != 10)
                        {
                            throw new NotSupportedException(string.Format("STRK has an invalid size : {0}", subSize));
                        }
                    }
                    else
                    {
                        return(false);
                    }
                    break;

                case "SMRK":
                    _inData = false;
                    if (available_size >= (size + 8))
                    {
                        _markReached = true;
                    }
                    else
                    {
                        return(false);
                    }
                    break;

                case "SHDR":
                    _inData = false;
                    if (available_size >= (size + 8))
                    {
                        var subSize = ScummHelper.SwapBytes(BitConverter.ToUInt32(_tbuffer, offset + 4));
                        if (subSize != 4)
                        {
                            throw new NotSupportedException(string.Format("SHDR has an invalid size : {0}", subSize));
                        }
                    }
                    else
                    {
                        return(false);
                    }
                    break;

                case "SDAT":
                    _inData   = true;
                    _dataSize = (int)size;
                    offset   += 8;
                    return(false);

                default:
                    throw new NotSupportedException(string.Format("unknown Chunk in SAUD track : {0}", type));
                }
                offset += (int)(size + 8);
                return(true);
            }
            return(false);
        }
Exemple #8
0
        void LoadFont(string filename)
        {
            byte[] dataSrc;
            using (var file = ServiceLocator.FileStorage.OpenFileRead(filename))
            {
                var reader = new BinaryReader(file);
                var tag    = System.Text.Encoding.UTF8.GetString(reader.ReadBytes(4));
                if (tag != "ANIM")
                {
                    throw new InvalidOperationException("NutRenderer.LoadFont() there is no ANIM chunk in font header");
                }

                var length = (int)reader.ReadUInt32BigEndian();
                dataSrc = reader.ReadBytes(length);
            }

            if (System.Text.Encoding.UTF8.GetString(dataSrc, 0, 4) != "AHDR")
            {
                throw new InvalidOperationException("NutRenderer::loadFont() there is no AHDR chunk in font header");
            }

            // We pre-decode the font, which may seem wasteful at first. Actually,
            // the memory needed for just the decoded glyphs is smaller than the
            // whole of the undecoded font file.


            _numChars = BitConverter.ToUInt16(dataSrc, 10);
            Debug.Assert(_numChars <= _chars.Length);

            _paletteMap = new byte[256];

            var offset        = 0;
            var decodedLength = 0;

            for (var l = 0; l < _numChars; l++)
            {
                offset += (int)ScummHelper.SwapBytes(BitConverter.ToUInt32(dataSrc, offset + 4)) + 16;
                int width  = BitConverter.ToUInt16(dataSrc, offset + 14);
                int height = BitConverter.ToUInt16(dataSrc, offset + 16);
                int size   = width * height;
                decodedLength += size;
                if (size > _maxCharSize)
                {
                    _maxCharSize = size;
                }
            }

            Debug.WriteLine("NutRenderer::loadFont('{0}') - decodedLength = {1}", filename, decodedLength);

            _decodedData = new byte[decodedLength];
            var decodedPos = 0;

            offset = 0;
            for (var l = 0; l < _numChars; l++)
            {
                offset += (int)ScummHelper.SwapBytes(BitConverter.ToUInt32(dataSrc, offset + 4)) + 8;
                if (System.Text.Encoding.UTF8.GetString(dataSrc, offset, 4) != "FRME")
                {
                    throw new InvalidOperationException(string.Format("NutRenderer::loadFont({0}) there is no FRME chunk {1} (offset {2:X})", filename, l, offset));
                }
                offset += 8;
                if (System.Text.Encoding.UTF8.GetString(dataSrc, offset, 4) != "FOBJ")
                {
                    throw new InvalidOperationException(string.Format("NutRenderer::loadFont({0}) there is no FOBJ chunk in FRME chunk {1} (offset {2:X})", filename, l, offset));
                }
                int codec = BitConverter.ToUInt16(dataSrc, offset + 8);
                // _chars[l].xoffs = READ_LE_UINT16(dataSrc + offset + 10);
                // _chars[l].yoffs = READ_LE_UINT16(dataSrc + offset + 12);
                _chars[l].Width     = BitConverter.ToUInt16(dataSrc, offset + 14);
                _chars[l].Height    = BitConverter.ToUInt16(dataSrc, offset + 16);
                _chars[l].Src       = _decodedData;
                _chars[l].SrcOffset = decodedPos;

                decodedPos += (_chars[l].Width * _chars[l].Height);

                // If characters have transparency, then bytes just get skipped and
                // so there may appear some garbage. That's why we have to fill it
                // with a default color first.
                if (codec == 44)
                {
                    for (int i = 0; i < _chars[l].Width * _chars[l].Height; i++)
                    {
                        _chars[l].Src[_chars[l].SrcOffset + i] = Smush44TransparentColor;
                    }
                    _paletteMap[Smush44TransparentColor] = 1;
                    _chars[l].Transparency = Smush44TransparentColor;
                }
                else
                {
                    for (int i = 0; i < _chars[l].Width * _chars[l].Height; i++)
                    {
                        _chars[l].Src[_chars[l].SrcOffset + i] = DefaultTransparentColor;
                    }
                    _paletteMap[DefaultTransparentColor] = 1;
                    _chars[l].Transparency = DefaultTransparentColor;
                }

                switch (codec)
                {
                case 1:
                    Codec1(_chars[l].Src, _chars[l].SrcOffset, dataSrc, offset + 22, _chars[l].Width, _chars[l].Height, _chars[l].Width);
                    break;

                case 21:
                case 44:
                    Codec21(_chars[l].Src, _chars[l].SrcOffset, dataSrc, offset + 22, _chars[l].Width, _chars[l].Height, _chars[l].Width);
                    break;

                default:
                    throw new InvalidOperationException(string.Format("NutRenderer::loadFont: unknown codec: {0}", codec));
                }
            }

            // We have decoded the font. Now let's see if we can re-compress it to
            // a more compact format. Start by counting the number of colors.

            int numColors = 0;

            for (var l = 0; l < 256; l++)
            {
                if (_paletteMap[l] != 0)
                {
                    if (numColors < _palette.Length)
                    {
                        _paletteMap[l]      = (byte)numColors;
                        _palette[numColors] = (byte)l;
                    }
                    numColors++;
                }
            }

            // Now _palette contains all the used colors, and _paletteMap maps the
            // real color to the palette index.

            if (numColors <= 2)
            {
                _bpp = 1;
            }
            else if (numColors <= 4)
            {
                _bpp = 2;
            }
            else if (numColors <= 16)
            {
                _bpp = 4;
            }
            else
            {
                _bpp = 8;
            }

            if (_bpp < 8)
            {
                int compressedLength = 0;
                for (var l = 0; l < 256; l++)
                {
                    compressedLength += (((_bpp * _chars[l].Width + 7) / 8) * _chars[l].Height);
                }

                Debug.WriteLine("NutRenderer::loadFont('{0}') - compressedLength = {1} ({2} bpp)", filename, compressedLength, _bpp);

                var compressedData = new byte[compressedLength];

                offset = 0;

                for (var l = 0; l < 256; l++)
                {
                    var src      = _chars[l].Src;
                    var srcPos   = _chars[l].SrcOffset;
                    var dstPos   = offset;
                    int srcPitch = _chars[l].Width;
                    int dstPitch = (_bpp * _chars[l].Width + 7) / 8;

                    for (var h = 0; h < _chars[l].Height; h++)
                    {
                        byte bit     = 0x80;
                        var  nextDst = dstPos + dstPitch;
                        for (int w = 0; w < srcPitch; w++)
                        {
                            byte color = _paletteMap[src[srcPos + w]];
                            for (int i = 0; i < _bpp; i++)
                            {
                                if ((color & (1 << i)) != 0)
                                {
                                    compressedData[dstPos] |= bit;
                                }
                                bit >>= 1;
                            }
                            if (bit == 0)
                            {
                                bit = 0x80;
                                dstPos++;
                            }
                        }
                        srcPos += srcPitch;
                        dstPos  = nextDst;
                    }
                    _chars[l].Src       = compressedData;
                    _chars[l].SrcOffset = offset;
                    offset += (dstPitch * _chars[l].Height);
                }

                _decodedData = compressedData;

                _charBuffer = new byte[_maxCharSize];
            }

            _paletteMap = null;
        }
Exemple #9
0
 static uint GetResSnd()
 {
     return(ScummHelper.SwapBytes(BitConverter.ToUInt32(
                                      System.Text.Encoding.UTF8.GetBytes("snd "), 0)));
 }
Exemple #10
0
        public void QueueCompressedBuffer(byte[] buffer, int bufferSize, int unpackedSize)
        {
            using (var ms = new MemoryStream(buffer, 0, bufferSize))
            {
                var audioBS = BitStream.Create8Lsb(ms);

                bool dataPresent = audioBS.GetBit() != 0;

                if (!dataPresent)
                {
                    return;
                }

                bool isStereo = audioBS.GetBit() != 0;
                Debug.Assert(isStereo == _audioInfo.isStereo);
                bool is16Bits = audioBS.GetBit() != 0;
                Debug.Assert(is16Bits == _audioInfo.is16Bits);

                int numBytes = 1 * (isStereo ? 2 : 1) * (is16Bits ? 2 : 1);

                byte[] unpackedBuffer = new byte[unpackedSize];
                var    curPointer     = 0;
                var    curPos         = 0;

                SmallHuffmanTree[] audioTrees = new SmallHuffmanTree[4];
                for (int k = 0; k < numBytes; k++)
                {
                    audioTrees[k] = new SmallHuffmanTree(audioBS);
                }

                // Base values, stored as big endian

                int[] bases = new int[2];

                if (isStereo)
                {
                    if (is16Bits)
                    {
                        bases[1] = ScummHelper.SwapBytes((ushort)audioBS.GetBits(16));
                    }
                    else
                    {
                        bases[1] = (int)audioBS.GetBits(8);
                    }
                }

                if (is16Bits)
                {
                    bases[0] = ScummHelper.SwapBytes((ushort)audioBS.GetBits(16));
                }
                else
                {
                    bases[0] = (int)audioBS.GetBits(8);
                }

                // The bases are the first samples, too
                for (int i = 0;
                     i < (isStereo ? 2 : 1);
                     i++, curPointer += (is16Bits ? 2 : 1), curPos += (is16Bits ? 2 : 1))
                {
                    if (is16Bits)
                    {
                        unpackedBuffer.WriteUInt16BigEndian(curPointer, (ushort)bases[i]);
                    }
                    else
                    {
                        unpackedBuffer[curPointer] = (byte)((bases[i] & 0xFF) ^ 0x80);
                    }
                }

                // Next follow the deltas, which are added to the corresponding base values and
                // are stored as little endian
                // We store the unpacked bytes in big endian format

                while (curPos < unpackedSize)
                {
                    // If the sample is stereo, the data is stored for the left and right channel, respectively
                    // (the exact opposite to the base values)
                    if (!is16Bits)
                    {
                        for (int k = 0; k < (isStereo ? 2 : 1); k++)
                        {
                            sbyte delta = (sbyte)((short)audioTrees[k].GetCode(audioBS));
                            bases[k] = (bases[k] + delta) & 0xFF;
                            unpackedBuffer[curPointer++] = (byte)(bases[k] ^ 0x80);
                            curPos++;
                        }
                    }
                    else
                    {
                        for (int k = 0; k < (isStereo ? 2 : 1); k++)
                        {
                            byte lo = (byte)audioTrees[k * 2].GetCode(audioBS);
                            byte hi = (byte)audioTrees[k * 2 + 1].GetCode(audioBS);
                            bases[k] += (short)(lo | (hi << 8));

                            unpackedBuffer.WriteUInt16BigEndian(curPointer, (ushort)bases[k]);
                            curPointer += 2;
                            curPos     += 2;
                        }
                    }
                }

                QueuePCM(unpackedBuffer, unpackedSize);
            }
        }
Exemple #11
0
 public uint ReadUInt32(uint value)
 {
     return(_isBigEndian ? ScummHelper.SwapBytes(value) : value);
 }
Exemple #12
0
 public short ReadInt16(short value)
 {
     return(_isBigEndian ? ScummHelper.SwapBytes(value) : value);
 }
Exemple #13
0
        public static bool IncreaseAnim(Actor a, int chan, byte[] aksq, byte[] akfo, int numakfo, ScummEngine vm)
        {
            byte active;
            int  old_curpos, end;
            int  curpos;
            bool flag_value, needRedraw;
            int  tmp, tmp2;

            active     = a.Cost.Active[chan];
            end        = a.Cost.End[chan];
            old_curpos = curpos = a.Cost.Curpos[chan];
            flag_value = false;
            needRedraw = false;

            do
            {
                var code = (AkosOpcode)aksq[curpos];
                if (((ushort)code & 0x80) != 0)
                {
                    code = (AkosOpcode)ScummHelper.SwapBytes(BitConverter.ToUInt16(aksq, curpos));
                }

                switch (active)
                {
                case 6:
                case 8:
                    switch (code)
                    {
                    case AkosOpcode.JumpIfSet:
                    case AkosOpcode.AddVar:
                    case AkosOpcode.SetVar:
                    case AkosOpcode.SkipGE:
                    case AkosOpcode.SkipG:
                    case AkosOpcode.SkipLE:
                    case AkosOpcode.SkipL:

                    case AkosOpcode.SkipNE:
                    case AkosOpcode.SkipE:
                    case AkosOpcode.C016:
                    case AkosOpcode.C017:
                    case AkosOpcode.C018:
                    case AkosOpcode.C019:
                        curpos += 5;
                        break;

                    case AkosOpcode.JumpTable:
                    case AkosOpcode.SetActorClip:
                    case AkosOpcode.Ignore3:
                    case AkosOpcode.Ignore2:
                    case AkosOpcode.Ignore:
                    case AkosOpcode.StartAnim:
                    case AkosOpcode.StartVarAnim:
                    case AkosOpcode.CmdQue3:
                    case AkosOpcode.C042:
                    case AkosOpcode.C044:
                    case AkosOpcode.C0A3:
                        curpos += 3;
                        break;

                    case AkosOpcode.SoundStuff:
//                                if (Game.Heversion >= 61)
//                                    curpos += 6;
//                                else
                        curpos += 8;
                        break;

                    case AkosOpcode.Cmd3:
                    case AkosOpcode.SetVarInActor:
                    case AkosOpcode.SetDrawOffs:
                        curpos += 6;
                        break;

                    case AkosOpcode.ClearFlag:
                    case AkosOpcode.HideActor:
                    case AkosOpcode.IncVar:
                    case AkosOpcode.CmdQue3Quick:
                    case AkosOpcode.Return:
                    case AkosOpcode.EndSeq:
                        curpos += 2;
                        break;

                    case AkosOpcode.JumpGE:
                    case AkosOpcode.JumpG:
                    case AkosOpcode.JumpLE:
                    case AkosOpcode.JumpL:
                    case AkosOpcode.JumpNE:
                    case AkosOpcode.JumpE:
                    case AkosOpcode.Random:
                        curpos += 7;
                        break;

                    case AkosOpcode.Flip:
                    case AkosOpcode.Jump:
                    case AkosOpcode.StartAnimInActor:
                    case AkosOpcode.C0A0:
                    case AkosOpcode.C0A1:
                    case AkosOpcode.C0A2:
                        curpos += 4;
                        break;

                    case AkosOpcode.ComplexChan2:
                        curpos += 4;
                        curpos += 3;
                        tmp     = aksq[curpos - 1];
                        while (--tmp >= 0)
                        {
                            curpos += 4;
                            curpos += ((aksq[curpos] & 0x80) != 0) ? 2 : 1;
                        }
                        break;

                    // Fall through
                    case AkosOpcode.ComplexChan:
                        curpos += 3;
                        tmp     = aksq[curpos - 1];
                        while (--tmp >= 0)
                        {
                            curpos += 4;
                            curpos += ((aksq[curpos] & 0x80) != 0) ? 2 : 1;
                        }
                        break;

                    case AkosOpcode.C021:
                    case AkosOpcode.C022:
                    case AkosOpcode.C045:
                    case AkosOpcode.C046:
                    case AkosOpcode.C047:
                    case AkosOpcode.C048:
                        needRedraw = true;
                        curpos    += aksq[curpos + 2];
                        break;

                    case AkosOpcode.C08E:
                        akos_queCommand(7, a, GW(aksq, curpos, 2), 0, vm);
                        curpos += 4;
                        break;

                    default:
                        curpos += (((short)code & 0x8000) != 0) ? 2 : 1;
                        break;
                    }
                    break;

                case 2:
                    curpos += (((short)code & 0x8000) != 0) ? 2 : 1;
                    if (curpos > end)
                    {
                        curpos = a.Cost.Start[chan];
                    }
                    break;

                case 3:
                    if (curpos != end)
                    {
                        curpos += (((short)code & 0x8000) != 0) ? 2 : 1;
                    }
                    break;
                }

                code = (AkosOpcode)aksq[curpos];
                if (((short)code & 0x80) != 0)
                {
                    code = (AkosOpcode)ScummHelper.SwapBytes(BitConverter.ToUInt16(aksq, curpos));
                }

                if (flag_value && code != AkosOpcode.ClearFlag)
                {
                    continue;
                }

                switch (code)
                {
                case AkosOpcode.StartAnimInActor:
                    akos_queCommand(4, vm.Actors[a.GetAnimVar(GB(aksq, curpos, 2))], a.GetAnimVar(GB(aksq, curpos, 3)), 0, vm);
                    continue;

                case AkosOpcode.Random:
                    a.SetAnimVar(GB(aksq, curpos, 6), new Random().Next(GW(aksq, curpos, 2), GW(aksq, curpos, 4)));
                    continue;

                case AkosOpcode.JumpGE:
                case AkosOpcode.JumpG:
                case AkosOpcode.JumpLE:
                case AkosOpcode.JumpL:
                case AkosOpcode.JumpNE:
                case AkosOpcode.JumpE:
                    if (akos_compare(a.GetAnimVar(GB(aksq, curpos, 4)), GW(aksq, curpos, 5), (byte)(code - AkosOpcode.JumpStart)))
                    {
                        curpos = GUW(aksq, curpos, 2);
                        break;
                    }
                    continue;

                case AkosOpcode.IncVar:
                    a.SetAnimVar(0, a.GetAnimVar(0) + 1);
                    continue;

                case AkosOpcode.SetVar:
                    a.SetAnimVar(GB(aksq, curpos, 4), GW(aksq, curpos, 2));
                    continue;

                case AkosOpcode.AddVar:
                    a.SetAnimVar(GB(aksq, curpos, 4), a.GetAnimVar(GB(aksq, curpos, 4)) + GW(aksq, curpos, 2));
                    continue;

                case AkosOpcode.Flip:
                    a.Flip = GW(aksq, curpos, 2) != 0;
                    continue;

                case AkosOpcode.CmdQue3:
//                        if (Game.Heversion >= 61)
                    //                            tmp = GB(aksq, curpos,2);
//                        else
                    tmp = GB(aksq, curpos, 2) - 1;
                    if ((uint)tmp < 24)
                    {
                        akos_queCommand(3, a, a.Sounds[tmp], 0, vm);
                    }
                    continue;

                case AkosOpcode.CmdQue3Quick:
                    akos_queCommand(3, a, a.Sounds[0], 0, vm);
                    continue;

                case AkosOpcode.StartAnim:
                    akos_queCommand(4, a, GB(aksq, curpos, 2), 0, vm);
                    continue;

                case AkosOpcode.StartVarAnim:
                    akos_queCommand(4, a, a.GetAnimVar(GB(aksq, curpos, 2)), 0, vm);
                    continue;

                case AkosOpcode.SetVarInActor:
                    vm.Actors[a.GetAnimVar(GB(aksq, curpos, 2))].SetAnimVar(GB(aksq, curpos, 3), GW(aksq, curpos, 4));
                    continue;

                case AkosOpcode.HideActor:
                    akos_queCommand(1, a, 0, 0, vm);
                    continue;

                case AkosOpcode.SetActorClip:
                    akos_queCommand(5, a, GB(aksq, curpos, 2), 0, vm);
                    continue;

                case AkosOpcode.SoundStuff:
//                        if (_game.heversion >= 61)
//                            continue;
                    tmp = GB(aksq, curpos, 2) - 1;
                    if (tmp >= 8)
                    {
                        continue;
                    }
                    tmp2 = GB(aksq, curpos, 4);
                    if (tmp2 < 1 || tmp2 > 3)
                    {
                        throw new InvalidOperationException(string.Format("akos_increaseAnim:8 invalid code {0}", tmp2));
                    }
                    akos_queCommand((byte)(tmp2 + 6), a, a.Sounds[tmp], GB(aksq, curpos, 6), vm);
                    continue;

                case AkosOpcode.SetDrawOffs:
                    akos_queCommand(6, a, GW(aksq, curpos, 2), GW(aksq, curpos, 4), vm);
                    continue;

                case AkosOpcode.JumpTable:
                    if (akfo == null)
                    {
                        throw new InvalidOperationException("akos_increaseAnim: no AKFO table");
                    }
                    tmp = a.GetAnimVar(GB(aksq, curpos, 2)) - 1;
//                        if (_game.heversion >= 80)
//                        {
//                            if (tmp < 0 || tmp > a.Cost.heJumpCountTable[chan] - 1)
//                                error("akos_increaseAnim: invalid jump value %d", tmp);
//                            curpos = READ_LE_UINT16(akfo + a.Cost.heJumpOffsetTable[chan] + tmp * 2);
//                        }
//                        else
                    {
                        if (tmp < 0 || tmp > numakfo - 1)
                        {
                            throw new InvalidOperationException(string.Format("akos_increaseAnim: invalid jump value {0}", tmp));
                        }
                        curpos = BitConverter.ToUInt16(akfo, tmp);
                    }
                    break;

                case AkosOpcode.JumpIfSet:
                    if (a.GetAnimVar(GB(aksq, curpos, 4)) == 0)
                    {
                        continue;
                    }
                    a.SetAnimVar(GB(aksq, curpos, 4), 0);
                    curpos = GUW(aksq, curpos, 2);
                    break;

                case AkosOpcode.ClearFlag:
                    flag_value = false;
                    continue;

                case AkosOpcode.Jump:
                    curpos = GUW(aksq, curpos, 2);
                    break;

                case AkosOpcode.Return:
                case AkosOpcode.EndSeq:
                case AkosOpcode.ComplexChan:
                case AkosOpcode.C08E:
                case AkosOpcode.ComplexChan2:
                    break;

                case AkosOpcode.C021:
                case AkosOpcode.C022:
                    needRedraw = true;
                    break;

                case AkosOpcode.Cmd3:
                case AkosOpcode.Ignore:
                case AkosOpcode.Ignore3:
                    continue;

                case AkosOpcode.Ignore2:
//                        if (_game.heversion >= 71)
                    //                            akos_queCommand(3, a, a._sound[a.GetAnimVar(GB(aksq, curpos,2))], 0);
                    continue;

                case AkosOpcode.SkipE:
                case AkosOpcode.SkipNE:
                case AkosOpcode.SkipL:
                case AkosOpcode.SkipLE:
                case AkosOpcode.SkipG:
                case AkosOpcode.SkipGE:
                    if (!akos_compare(a.GetAnimVar(GB(aksq, curpos, 4)), GW(aksq, curpos, 2), (byte)(code - AkosOpcode.SkipStart)))
                    {
                        flag_value = true;
                    }
                    continue;

                case AkosOpcode.C016:
                    if (vm.Sound.IsSoundRunning(a.Sounds[a.GetAnimVar(GB(aksq, curpos, 4))]))
                    {
                        curpos = GUW(aksq, curpos, 2);
                        break;
                    }
                    continue;

                case AkosOpcode.C017:
                    if (!vm.Sound.IsSoundRunning(a.Sounds[a.GetAnimVar(GB(aksq, curpos, 4))]))
                    {
                        curpos = GUW(aksq, curpos, 2);
                        break;
                    }
                    continue;

                case AkosOpcode.C018:
                    if (vm.Sound.IsSoundRunning(a.Sounds[GB(aksq, curpos, 4)]))
                    {
                        curpos = GUW(aksq, curpos, 2);
                        break;
                    }
                    continue;

                case AkosOpcode.C019:
                    if (!vm.Sound.IsSoundRunning(a.Sounds[GB(aksq, curpos, 4)]))
                    {
                        curpos = GUW(aksq, curpos, 2);
                        break;
                    }
                    continue;

                case AkosOpcode.C042:
                    akos_queCommand(9, a, a.Sounds[GB(aksq, curpos, 2)], 0, vm);
                    continue;

                case AkosOpcode.C044:
                    akos_queCommand(9, a, a.Sounds[a.GetAnimVar(GB(aksq, curpos, 2))], 0, vm);
                    continue;

//                    case AkosOpcode.C045:
//                        ((ActorHE*)a).SetUserCondition(GB(aksq, curpos, 3), a.GetAnimVar(GB(aksq, curpos, 4)));
//                        continue;
//                    case AkosOpcode.C046:
//                        a.SetAnimVar(GB(aksq, curpos, 4), ((ActorHE*)a).isUserConditionSet(GB(aksq, curpos, 3)));
//                        continue;
//                    case AkosOpcode.C047:
//                        ((ActorHE*)a).setTalkCondition(GB(aksq, curpos, 3));
//                        continue;
//                    case AkosOpcode.C048:
//                        a.setAnimVar(GB(aksq, curpos, 4), ((ActorHE*)a).isTalkConditionSet(GB(aksq, curpos, 3)));
//                        continue;
                case AkosOpcode.C0A0:
                    akos_queCommand(8, a, GB(aksq, curpos, 2), 0, vm);
                    continue;

//                    case AkosOpcode.C0A1:
//                        if (((ActorHE*)a)._heTalking != 0)
//                        {
//                            curpos = GUW(aksq, curpos, 2);
//                            break;
//                        }
//                        continue;
//                    case AkosOpcode.C0A2:
//                        if (((ActorHE*)a)._heTalking == 0)
//                        {
//                            curpos = GUW(aksq, curpos, 2);
//                            break;
//                        }
//                        continue;
                case AkosOpcode.C0A3:
                    akos_queCommand(8, a, a.GetAnimVar(GB(aksq, curpos, 2)), 0, vm);
                    continue;

                case AkosOpcode.C0A4:
                    if (vm.Variables[vm.VariableTalkActor.Value] != 0)
                    {
                        curpos = GUW(aksq, curpos, 2);
                        break;
                    }
                    continue;

                case AkosOpcode.C0A5:
                    if (vm.Variables[vm.VariableTalkActor.Value] == 0)
                    {
                        curpos = GUW(aksq, curpos, 2);
                        break;
                    }
                    continue;

                default:
                    if (((short)code & 0xC000) == 0xC000)
                    {
                        throw new InvalidOperationException(string.Format("Undefined uSweat token {0:X}", code));
                    }
                    break;
                }
                break;
            } while (true);

            int code2 = aksq[curpos];

            if ((code2 & 0x80) != 0)
            {
                code2 = ScummHelper.SwapBytes(BitConverter.ToUInt16(aksq, curpos));
            }

            if (((code2 & 0xC000) == 0xC000) && code2 != (int)AkosOpcode.ComplexChan &&
                code2 != (int)AkosOpcode.Return && code2 != (int)AkosOpcode.EndSeq &&
                code2 != (int)AkosOpcode.C08E && code2 != (int)AkosOpcode.ComplexChan2 &&
                code2 != (int)AkosOpcode.C021 && code2 != (int)AkosOpcode.C022)
            {
                throw new InvalidOperationException(string.Format("Ending with undefined uSweat token {0:X}", code2));
            }

            a.Cost.Curpos[chan] = (ushort)curpos;

            if (needRedraw)
            {
                return(true);
            }
            else
            {
                return(curpos != old_curpos);
            }
        }
Exemple #14
0
        private UShortAccess UncompressSpeech(uint index, uint cSize, out uint size)
        {
            _cowFile.BaseStream.Seek(index, SeekOrigin.Begin);
            var  fBuf      = _cowFile.ReadBytes((int)cSize);
            uint headerPos = 0;

            while ((fBuf.ToUInt32BigEndian((int)headerPos) != ScummHelper.MakeTag('d', 'a', 't', 'a')) && (headerPos < 100))
            {
                headerPos++;
            }

            UShortAccess srcData;

            if (headerPos < 100)
            {
                int   resSize;
                uint  srcPos;
                short length;
                cSize     /= 2;
                headerPos += 4; // skip 'data' tag
                if (_cowMode != CowMode.CowDemo)
                {
                    resSize    = (int)(fBuf.ToUInt32((int)headerPos) >> 1);
                    headerPos += 4;
                }
                else
                {
                    // the demo speech files have the uncompressed size
                    // embedded in the compressed stream *sigh*
                    //
                    // But not always, apparently. See bug #2182450. Is
                    // there any way to figure out the size other than
                    // decoding the sound in that case?

                    if (fBuf[headerPos + 1] == 0)
                    {
                        if (fBuf.ToInt16((int)headerPos) == 1)
                        {
                            resSize  = fBuf.ToInt16((int)(headerPos + 2));
                            resSize |= fBuf.ToInt16((int)(headerPos + 6)) << 16;
                        }
                        else
                        {
                            resSize = fBuf.ToInt32((int)(headerPos + 2));
                        }
                        resSize >>= 1;
                    }
                    else
                    {
                        resSize = 0;
                        srcData = new UShortAccess(fBuf);
                        srcPos  = headerPos >> 1;
                        while (srcPos < cSize)
                        {
                            length = (short)srcData[(int)srcPos];
                            srcPos++;
                            if (length < 0)
                            {
                                resSize -= length;
                                srcPos++;
                            }
                            else
                            {
                                resSize += length;
                                srcPos   = (uint)(srcPos + length);
                            }
                        }
                    }
                }
                Debug.Assert((headerPos & 1) == 0);
                srcData = new UShortAccess(fBuf);
                srcPos  = headerPos >> 1;
                uint dstPos      = 0;
                var  dstData     = new UShortAccess(new byte[resSize * 2]);
                int  samplesLeft = resSize;
                while (srcPos < cSize && samplesLeft > 0)
                {
                    length = (short)(_bigEndianSpeech ? ScummHelper.SwapBytes(srcData[(int)srcPos]) : srcData[(int)srcPos]);
                    srcPos++;
                    if (length < 0)
                    {
                        length = (short)-length;
                        if (length > samplesLeft)
                        {
                            length = (short)samplesLeft;
                        }
                        short value;
                        if (_bigEndianSpeech)
                        {
                            value = (short)ScummHelper.SwapBytes(srcData[(int)srcPos]);
                        }
                        else
                        {
                            value = (short)srcData[(int)srcPos];
                        }
                        for (ushort cnt = 0; cnt < (ushort)length; cnt++)
                        {
                            dstData[(int)dstPos++] = (ushort)value;
                        }
                        srcPos++;
                    }
                    else
                    {
                        if (length > samplesLeft)
                        {
                            length = (short)samplesLeft;
                        }
                        if (_bigEndianSpeech)
                        {
                            for (ushort cnt = 0; cnt < length; cnt++)
                            {
                                dstData[(int)dstPos++] = ScummHelper.SwapBytes(srcData[(int)srcPos++]);
                            }
                        }
                        else
                        {
                            Array.Copy(srcData.Data, (int)(srcData.Offset + srcPos * 2), dstData.Data, (int)(dstData.Offset + dstPos * 2), length * 2);
                            dstPos = (uint)(dstPos + length);
                            srcPos = (uint)(srcPos + length);
                        }
                    }
                    samplesLeft -= length;
                }
                if (samplesLeft > 0)
                {
                    dstData.Data.Set((int)(dstData.Offset + dstPos), 0, samplesLeft * 2);
                }
                if (_cowMode == CowMode.CowDemo) // demo has wave output size embedded in the compressed data
                {
                    dstData.Data.WriteUInt32(dstData.Offset, 0);
                }
                size = (uint)(resSize * 2);
                CalcWaveVolume(dstData, resSize);
                return(dstData);
            }
            else
            {
                // TODO: warning("Sound::uncompressSpeech(): DATA tag not found in wave header");
                size = 0;
                return(null);
            }
        }
Exemple #15
0
        public void PlaySound(ushort sound, ushort volume, byte channel)
        {
            if (channel == 0)
            {
                _mixer.StopID(SoundChannel0);
            }
            else
            {
                _mixer.StopID(SoundChannel1);
            }

            if (_soundData == null)
            {
                // TODO: warning
                //warning("Sound::playSound(%04X, %04X) called with a section having been loaded", sound, volume);
                return;
            }

            if (sound > _soundsTotal)
            {
                // TODO: debug
                //debug(5, "Sound::playSound %d ignored, only %d sfx in file", sound, _soundsTotal);
                return;
            }

            volume = (ushort)((volume & 0x7F) << 1);
            sound &= 0xFF;

            // Note: All those tables are big endian. Don't ask me why. *sigh*

            // Use the sample rate from game data, see bug #1507757.
            var sampleRate = _sampleRates.Data.ToUInt16BigEndian(_sampleRates.Offset + (sound << 2));

            if (sampleRate > 11025)
            {
                sampleRate = 11025;
            }
            var dataOfs  = ScummHelper.SwapBytes(_sfxInfo[((sound << 3) + 0) / 2]) << 4;
            int dataSize = ScummHelper.SwapBytes(_sfxInfo[((sound << 3) + 2) / 2]);
            int dataLoop = ScummHelper.SwapBytes(_sfxInfo[((sound << 3) + 6) / 2]);

            dataOfs += _sfxBaseOfs;

            var stream = new RawStream(AudioFlags.Unsigned, sampleRate, false,
                                       new MemoryStream(_soundData, dataOfs, dataSize));

            IAudioStream output;

            if (dataLoop != 0)
            {
                var loopSta = dataSize - dataLoop;
                var loopEnd = dataSize;

                output = new SubLoopingAudioStream(stream, 0, new Timestamp(0, loopSta, sampleRate),
                                                   new Timestamp(0, loopEnd, sampleRate), true);
            }
            else
            {
                output = stream;
            }

            if (channel == 0)
            {
                _ingameSound0 = _mixer.PlayStream(SoundType.SFX, output, SoundChannel0, volume, 0);
            }
            else
            {
                _ingameSound1 = _mixer.PlayStream(SoundType.SFX, output, SoundChannel1, volume, 0);
            }
        }