Пример #1
0
        protected void FadeOut(int effect)
        {
            _mainVirtScreen.SetDirtyRange(0, 0);

            if (Game.Version < 7)
            {
                Camera.LastPosition.X = Camera.CurrentPosition.X;
            }

            if (Game.Version == 3 && _game.Platform == Platform.FMTowns)
            {
                Gdi.Fill(TextSurface,
                         new Rect(0, MainVirtScreen.TopLine * _textSurfaceMultiplier,
                                  _textSurface.Pitch, (MainVirtScreen.TopLine + MainVirtScreen.Height) * _textSurfaceMultiplier), 0);
            }

            if ((Game.Version == 7 || _screenEffectFlag) && effect != 0)
            {
                // Fill screen 0 with black
                var pixNav = new PixelNavigator(_mainVirtScreen.Surfaces[0]);
                pixNav.OffsetX(_mainVirtScreen.XStart);
                Gdi.Fill(pixNav, 0, _mainVirtScreen.Width, _mainVirtScreen.Height);

                // Fade to black with the specified effect, if any.
                switch (effect)
                {
                case 1:
                case 2:
                case 3:
                case 4:
                case 5:
                case 6:
                    DoTransitionEffect(effect - 1);
                    break;

                case 128:
                    UnkScreenEffect6();
                    break;

                case 129:
                    // Just blit screen 0 to the display (i.e. display will be black)
                    _mainVirtScreen.SetDirtyRange(0, _mainVirtScreen.Height);
                    UpdateDirtyScreen(_mainVirtScreen);
                    if (_townsScreen != null)
                    {
                        _townsScreen.Update();
                    }
                    break;

                default:
                    throw new NotImplementedException(string.Format("fadeOut: case {0}", effect));
                }
            }

            // Update the palette at the end (once we faded to black) to avoid
            // some nasty effects when the palette is changed
            UpdatePalette();

            _screenEffectFlag = false;
        }
Пример #2
0
        void OldRoomEffect()
        {
            _opCode = ReadByte();
            if ((_opCode & 0x1F) == 3)
            {
                var a = GetVarOrDirectWord(OpCodeParameter.Param1);

                if (Game.Platform == Platform.FMTowns && Game.Version == 3)
                {
                    if (a == 4)
                    {
                        Gdi.Fill(TextSurface, new Rect(0, 0, TextSurface.Width * TextSurfaceMultiplier, TextSurface.Height * TextSurfaceMultiplier), 0);
                        if (_townsScreen != null)
                        {
                            _townsScreen.ClearLayer(1);
                        }
                        return;
                    }
                }

                if (a != 0)
                {
                    _switchRoomEffect  = (byte)(a & 0xFF);
                    _switchRoomEffect2 = (byte)(a >> 8);
                }
                else
                {
                    FadeIn(_newEffect);
                }
            }
        }
Пример #3
0
        protected void RedefineBuiltinCursorFromChar(int index, int chr)
        {
            // Cursor image in both Loom versions are based on images from charset.
            // This function is *only* supported for Loom!
            if (_game.GameId != Scumm.IO.GameId.Loom)
            {
                throw new NotSupportedException("RedefineBuiltinCursorFromChar is *only* supported for Loom!");
            }
            if (index < 0 || index >= 4)
            {
                throw new ArgumentException("index");
            }

            //	const int oldID = _charset->getCurID();

            var ptr = _cursorImages[index];

            if (_game.Version == 3)
            {
                _charset.SetCurID(0);
            }
            else if (_game.Version >= 4)
            {
                _charset.SetCurID(1);
            }

            var s = new Surface(_charset.GetCharWidth(chr), _charset.GetFontHeight(), PixelFormat.Indexed8, false);
            var p = new PixelNavigator(s);

            Gdi.Fill(new PixelNavigator(s), 123, s.Width, s.Height);

            _charset.DrawChar(chr, s, 0, 0);

            Array.Clear(ptr, 0, ptr.Length);
            for (int h = 0; h < s.Height; h++)
            {
                for (int w = 0; w < s.Width; w++)
                {
                    p.GoTo(w, h);
                    if (p.Read() != 123)
                    {
                        ptr[h] |= (ushort)(1 << (15 - w));
                    }
                }
            }

            //	_charset->setCurID(oldID);
        }
Пример #4
0
        protected void InitScreens(int b, int h)
        {
            if (_townsScreen != null)
            {
                if (_townsClearLayerFlag == 0 && MainVirtScreen != null && ((h - b) != MainVirtScreen.Height))
                {
                    _townsScreen.ClearLayer(0);
                }

                if (Game.GameId != GameId.Monkey1)
                {
                    Gdi.Fill(TextSurface,
                             new Rect(0, 0, _textSurface.Width * _textSurfaceMultiplier, _textSurface.Height * _textSurfaceMultiplier), 0);
                    _townsScreen.ClearLayer(1);
                }
            }

            var format = Game.Features.HasFlag(GameFeatures.Is16BitColor) ? PixelFormat.Rgb16 : PixelFormat.Indexed8;

            _mainVirtScreen = new VirtScreen(b, ScreenWidth, h - b, format, 2, true);
            _textVirtScreen = new VirtScreen(0, ScreenWidth, b, format, 1);
            _verbVirtScreen = new VirtScreen(h, ScreenWidth, ScreenHeight - h, format, 1);

            // Since the size of screen 3 is fixed, there is no need to reallocate
            // it if its size changed.
            // Not sure what it is good for, though. I think it may have been used
            // in pre-V7 for the games messages (like 'Pause', Yes/No dialogs,
            // version display, etc.). I don't know about V7, maybe the same is the
            // case there. If so, we could probably just remove it completely.
            if (_game.Version >= 7)
            {
                _unkVirtScreen = new VirtScreen((ScreenHeight / 2) - 10, ScreenWidth, 13, format, 1);
            }
            else
            {
                _unkVirtScreen = new VirtScreen(80, ScreenWidth, 13, format, 1);
            }

            _screenB = b;
            _screenH = h;

            Gdi.Init();
        }
Пример #5
0
        protected void RestoreBackground(Rect rect, byte backColor = 0)
        {
            VirtScreen vs;

            if (rect.Top < 0)
            {
                rect.Top = 0;
            }
            if (rect.Left >= rect.Right || rect.Top >= rect.Bottom)
            {
                return;
            }

            if ((vs = FindVirtScreen(rect.Top)) == null)
            {
                return;
            }

            if (rect.Left > vs.Width)
            {
                return;
            }

            // Convert 'rect' to local (virtual screen) coordinates
            rect.Top    -= vs.TopLine;
            rect.Bottom -= vs.TopLine;

            rect.Clip(vs.Width, vs.Height);

            int height = rect.Height;
            int width  = rect.Width;

            if (_game.Platform == Platform.FMTowns && Game.GameId == GameId.Monkey1 && vs == VerbVirtScreen && rect.Bottom <= 154)
            {
                rect.Right = 319;
            }

            MarkRectAsDirty(vs, rect.Left, rect.Right, rect.Top, rect.Bottom, Gdi.UsageBitRestored);

            var screenBuf = new PixelNavigator(vs.Surfaces[0]);

            screenBuf.GoTo(vs.XStart + rect.Left, rect.Top);

            if (height == 0)
            {
                return;
            }

            if (vs.HasTwoBuffers && _currentRoom != 0 && IsLightOn())
            {
                var back = new PixelNavigator(vs.Surfaces[1]);
                back.GoTo(vs.XStart + rect.Left, rect.Top);
                Gdi.Blit(screenBuf, back, width, height);
                if (vs == MainVirtScreen && _charset.HasMask)
                {
                    if (_game.Platform == Platform.FMTowns)
                    {
                        var mask = new PixelNavigator(_textSurface);
                        mask.GoTo(rect.Left * _textSurfaceMultiplier, (rect.Top + vs.TopLine) * _textSurfaceMultiplier);
                        Gdi.Fill(mask, 0, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier);
                    }
                    else
                    {
                        var mask = new PixelNavigator(_textSurface);
                        mask.GoTo(rect.Left, rect.Top - ScreenTop);
                        Gdi.Fill(mask, CharsetMaskTransparency, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier);
                    }
                }
            }
            else
            {
                if (Game.Platform == Platform.FMTowns)
                {
                    backColor |= (byte)(backColor << 4);
                    var mask = new PixelNavigator(_textSurface);
                    mask.GoTo(rect.Left * _textSurfaceMultiplier, (rect.Top + vs.TopLine) * _textSurfaceMultiplier);
                    Gdi.Fill(mask, backColor, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier);
                }

                if (Game.Features.HasFlag(GameFeatures.Is16BitColor))
                {
                    Gdi.Fill(screenBuf, _16BitPalette[backColor], width, height);
                }
                else
                {
                    Gdi.Fill(screenBuf, backColor, width, height);
                }
            }
        }
Пример #6
0
        void DrawFlashlight()
        {
            int i, j, x, y;
            var vs = MainVirtScreen;

            // Remove the flash light first if it was previously drawn
            if (_flashlight.IsDrawn)
            {
                MarkRectAsDirty(MainVirtScreen, _flashlight.X, _flashlight.X + _flashlight.W,
                                _flashlight.Y, _flashlight.Y + _flashlight.H, Gdi.UsageBitDirty);

                if (_flashlight.PixelNavigator.HasValue)
                {
                    Gdi.Fill(_flashlight.PixelNavigator.Value, 0, _flashlight.W, _flashlight.H);
                }
                _flashlight.IsDrawn = false;
            }

            if (_flashlight.XStrips == 0 || _flashlight.YStrips == 0)
            {
                return;
            }

            // Calculate the area of the flashlight
            if (Game.GameId == GameId.Zak || Game.GameId == GameId.Maniac)
            {
                x = _mousePos.X + vs.XStart;
                y = _mousePos.Y - vs.TopLine;
            }
            else
            {
                var a = Actors[Variables[VariableEgo.Value]];
                x = a.Position.X;
                y = a.Position.Y;
            }
            _flashlight.W = _flashlight.XStrips * 8;
            _flashlight.H = _flashlight.YStrips * 8;
            _flashlight.X = x - _flashlight.W / 2 - _screenStartStrip * 8;
            _flashlight.Y = y - _flashlight.H / 2;

            if (Game.GameId == GameId.Loom)
            {
                _flashlight.Y -= 12;
            }

            // Clip the flashlight at the borders
            if (_flashlight.X < 0)
            {
                _flashlight.X = 0;
            }
            else if (_flashlight.X + _flashlight.W > Gdi.NumStrips * 8)
            {
                _flashlight.X = Gdi.NumStrips * 8 - _flashlight.W;
            }
            if (_flashlight.Y < 0)
            {
                _flashlight.Y = 0;
            }
            else if (_flashlight.Y + _flashlight.H > vs.Height)
            {
                _flashlight.Y = vs.Height - _flashlight.H;
            }

            // Redraw any actors "under" the flashlight
            for (i = _flashlight.X / 8; i < (_flashlight.X + _flashlight.W) / 8; i++)
            {
                Debug.Assert(0 <= i && i < Gdi.NumStrips);
                Gdi.SetGfxUsageBit(_screenStartStrip + i, Gdi.UsageBitDirty);
                vs.TDirty[i] = 0;
                vs.BDirty[i] = vs.Height;
            }

            var pn = new PixelNavigator(vs.Surfaces[0]);

            pn.GoTo(_flashlight.X + vs.XStart, _flashlight.Y);
            pn = new PixelNavigator(pn);
            _flashlight.PixelNavigator = pn;
            var bgbak = new PixelNavigator(vs.Surfaces[1]);

            bgbak.GoTo(_flashlight.X + vs.XStart, _flashlight.Y);

            Gdi.Blit(pn, bgbak, _flashlight.W, _flashlight.H);

            // Round the corners. To do so, we simply hard-code a set of nicely
            // rounded corners.
            var corner_data = new [] { 8, 6, 4, 3, 2, 2, 1, 1 };
            int minrow      = 0;
            int maxcol      = (_flashlight.W - 1);
            int maxrow      = (_flashlight.H - 1);

            for (i = 0; i < 8; i++, minrow++, maxrow--)
            {
                int d = corner_data[i];

                for (j = 0; j < d; j++)
                {
                    if (vs.BytesPerPixel == 2)
                    {
                        pn.GoTo(j, minrow);
                        pn.WriteUInt16(0);
                        pn.GoTo(maxcol - j, minrow);
                        pn.WriteUInt16(0);
                        pn.GoTo(j, maxrow);
                        pn.WriteUInt16(0);
                        pn.GoTo(maxcol - j, maxrow);
                        pn.WriteUInt16(0);
                    }
                    else
                    {
                        pn.GoTo(j, minrow);
                        pn.Write(0);
                        pn.GoTo(maxcol - j, minrow);
                        pn.Write(0);
                        pn.GoTo(j, maxrow);
                        pn.Write(0);
                        pn.GoTo(maxcol - j, maxrow);
                        pn.Write(0);
                    }
                }
            }

            _flashlight.IsDrawn = true;
        }
Пример #7
0
        void RoomOps()
        {
            bool paramsBeforeOpcode = (Game.Version == 3);
            int  a = 0;
            int  b = 0;

            if (paramsBeforeOpcode)
            {
                a = GetVarOrDirectWord(OpCodeParameter.Param1);
                b = GetVarOrDirectWord(OpCodeParameter.Param2);
            }

            _opCode = ReadByte();
            switch (_opCode & 0x1F)
            {
            case 1:         // SO_ROOM_SCROLL
            {
                if (!paramsBeforeOpcode)
                {
                    a = GetVarOrDirectWord(OpCodeParameter.Param1);
                    b = GetVarOrDirectWord(OpCodeParameter.Param2);
                }
                if (a < (ScreenWidth / 2))
                {
                    a = (ScreenWidth / 2);
                }
                if (b < (ScreenWidth / 2))
                {
                    b = (ScreenWidth / 2);
                }
                if (a > roomData.Header.Width - (ScreenWidth / 2))
                {
                    a = roomData.Header.Width - (ScreenWidth / 2);
                }
                if (b > roomData.Header.Width - (ScreenWidth / 2))
                {
                    b = roomData.Header.Width - (ScreenWidth / 2);
                }
                Variables[VariableCameraMinX.Value] = a;
                Variables[VariableCameraMaxX.Value] = b;
            }
            break;

            case 2:         // SO_ROOM_COLOR
            {
                if (Game.Version < 5)
                {
                    if (!paramsBeforeOpcode)
                    {
                        a = GetVarOrDirectWord(OpCodeParameter.Param1);
                        b = GetVarOrDirectWord(OpCodeParameter.Param2);
                    }
                    ScummHelper.AssertRange(0, a, 256, "RoomOps: 2: room color slot");
                    Gdi.RoomPalette[b] = (byte)a;
                    _fullRedraw        = true;
                }
                else
                {
                    throw new NotSupportedException("room-color is no longer a valid command");
                }
            }
            break;

            case 3:         // SO_ROOM_SCREEN
            {
                if (!paramsBeforeOpcode)
                {
                    a = GetVarOrDirectWord(OpCodeParameter.Param1);
                    b = GetVarOrDirectWord(OpCodeParameter.Param2);
                }
                InitScreens(a, b);
            }
            break;

            case 4:         // SO_ROOM_PALETTE
            {
                if (Game.Version < 5)
                {
                    if (!paramsBeforeOpcode)
                    {
                        a = GetVarOrDirectWord(OpCodeParameter.Param1);
                        b = GetVarOrDirectWord(OpCodeParameter.Param2);
                    }
                    ScummHelper.AssertRange(0, a, 256, "RoomOps: 4: room color slot");
                    _shadowPalette[b] = (byte)a;
                    SetDirtyColors(b, b);
                }
                else
                {
                    a = GetVarOrDirectWord(OpCodeParameter.Param1);
                    b = GetVarOrDirectWord(OpCodeParameter.Param2);
                    var c = GetVarOrDirectWord(OpCodeParameter.Param3);
                    _opCode = ReadByte();
                    var d = GetVarOrDirectByte(OpCodeParameter.Param1);
                    SetPalColor(d, a, b, c);                /* index, r, g, b */
                }
            }
            break;

            case 5:         // SO_ROOM_SHAKE_ON
                SetShake(true);
                break;

            case 6:         // SO_ROOM_SHAKE_OFF
                SetShake(false);
                break;

            case 7:         // SO_ROOM_SCALE
            {
                a       = GetVarOrDirectByte(OpCodeParameter.Param1);
                b       = GetVarOrDirectByte(OpCodeParameter.Param2);
                _opCode = ReadByte();
                var c = GetVarOrDirectByte(OpCodeParameter.Param1);
                var d = GetVarOrDirectByte(OpCodeParameter.Param2);
                _opCode = ReadByte();
                var e = GetVarOrDirectByte(OpCodeParameter.Param2);
                SetScaleSlot(e - 1, 0, b, a, 0, d, c);
            }
            break;

            case 8:         // SO_ROOM_INTENSITY
            {
                a = GetVarOrDirectByte(OpCodeParameter.Param1);
                b = GetVarOrDirectByte(OpCodeParameter.Param2);
                var c = GetVarOrDirectByte(OpCodeParameter.Param3);
                DarkenPalette(a, a, a, b, c);
            }
            break;

            case 9:             // SO_ROOM_SAVEGAME
            {
                _saveLoadFlag       = GetVarOrDirectByte(OpCodeParameter.Param1);
                _saveLoadSlot       = GetVarOrDirectByte(OpCodeParameter.Param2);
                _saveLoadSlot       = 99;                                       /* use this slot */
                _saveTemporaryState = true;
            }
            break;

            case 10:        // SO_ROOM_FADE
            {
                a = GetVarOrDirectWord(OpCodeParameter.Param1);
                if (a != 0)
                {
                    if (Game.Platform == Platform.FMTowns)
                    {
                        switch (a)
                        {
                        case 8:
                            TownsDrawStripToScreen(MainVirtScreen, 0, MainVirtScreen.TopLine, 0, 0, MainVirtScreen.Width, MainVirtScreen.TopLine + MainVirtScreen.Height);
                            _townsScreen.Update();
                            return;

                        case 9:
                            _townsActiveLayerFlags = 2;
                            _townsScreen.ToggleLayers(_townsActiveLayerFlags);
                            return;

                        case 10:
                            _townsActiveLayerFlags = 3;
                            _townsScreen.ToggleLayers(_townsActiveLayerFlags);
                            return;

                        case 11:
                            _townsScreen.ClearLayer(1);
                            return;

                        case 12:
                            _townsActiveLayerFlags = 0;
                            _townsScreen.ToggleLayers(_townsActiveLayerFlags);
                            return;

                        case 13:
                            _townsActiveLayerFlags = 1;
                            _townsScreen.ToggleLayers(_townsActiveLayerFlags);
                            return;

                        case 16:             // enable clearing of layer 2 buffer in drawBitmap()
                            TownsPaletteFlags |= 2;
                            return;

                        case 17:             // disable clearing of layer 2 buffer in drawBitmap()
                            TownsPaletteFlags &= ~2;
                            return;

                        case 18:             // clear kMainVirtScreen layer 2 buffer
                            Gdi.Fill(TextSurface,
                                     new Rect(0, MainVirtScreen.TopLine * TextSurfaceMultiplier,
                                              TextSurface.Pitch, (MainVirtScreen.TopLine + MainVirtScreen.Height) * TextSurfaceMultiplier), 0);
                            TownsPaletteFlags |= 1;
                            return;

                        case 19:             // enable palette operations (palManipulate(), cyclePalette() etc.)
                            TownsPaletteFlags |= 1;
                            return;

                        case 20:             // disable palette operations
                            TownsPaletteFlags &= ~1;
                            return;

                        case 21:             // disable clearing of layer 0 in initScreens()
                            _townsClearLayerFlag = 1;
                            return;

                        case 22:             // enable clearing of layer 0 in initScreens()
                            _townsClearLayerFlag = 0;
                            return;

                        case 30:
                            TownsOverrideShadowColor = 3;
                            return;
                        }
                    }
                    _switchRoomEffect  = (byte)(a & 0xFF);
                    _switchRoomEffect2 = (byte)(a >> 8);
                }
                else
                {
                    FadeIn(_newEffect);
                }
            }
            break;

            case 11:        // SO_RGB_ROOM_INTENSITY
            {
                a = GetVarOrDirectWord(OpCodeParameter.Param1);
                b = GetVarOrDirectWord(OpCodeParameter.Param2);
                var c = GetVarOrDirectWord(OpCodeParameter.Param3);
                _opCode = ReadByte();
                var d = GetVarOrDirectByte(OpCodeParameter.Param1);
                var e = GetVarOrDirectByte(OpCodeParameter.Param2);
                DarkenPalette(a, b, c, d, e);
            }
            break;

            case 12:            // SO_ROOM_SHADOW
            {
                a = GetVarOrDirectWord(OpCodeParameter.Param1);
                b = GetVarOrDirectWord(OpCodeParameter.Param2);
                var c = GetVarOrDirectWord(OpCodeParameter.Param3);
                _opCode = ReadByte();
                var d = GetVarOrDirectByte(OpCodeParameter.Param1);
                var e = GetVarOrDirectByte(OpCodeParameter.Param2);
                SetShadowPalette(a, b, c, d, e, 0, 256);
            }
            break;

            case 13:        // SO_SAVE_STRING
            {
                // This subopcode is used in Indy 4 to save the IQ points
                // data. No other LucasArts game uses it. We use this fact
                // to substitute a filename based on the targetname
                // ("TARGET.iq").
                //
                // This way, the iq data of each Indy 4 variant stays
                // separate. Moreover, the filename now clearly reflects to
                // which target it belongs (as it should).
                //
                // In addition, the Monkey Island fan patch (which adds
                // speech support and more things to MI 1 and 2) uses
                // this opcode to generate a "monkey.cfg" file containing.
                // some user controllable settings.
                // Once more we use a custom filename ("TARGET.cfg").
                var index    = GetVarOrDirectByte(OpCodeParameter.Param1);
                var filename = System.Text.Encoding.UTF8.GetString(ReadCharacters());
                filename = GetIqFilename(filename);

                using (var file = ServiceLocator.FileStorage.OpenFileWrite(filename))
                {
                    var str = _strings[index];
                    file.Write(str, 0, str.Length);
                    Variables[VariableSoundResult.Value] = 0;
                }
                break;
            }

            case 14:        // SO_LOAD_STRING
            {
                // This subopcode is used in Indy 4 to load the IQ points data.
                // See SO_SAVE_STRING for details
                var index    = GetVarOrDirectByte(OpCodeParameter.Param1);
                var filename = System.Text.Encoding.UTF8.GetString(ReadCharacters());
                filename = GetIqFilename(filename);
                if (ServiceLocator.FileStorage.FileExists(filename))
                {
                    _strings[index] = ServiceLocator.FileStorage.ReadAllBytes(filename);
                }
            }
            break;

            case 15:            // SO_ROOM_TRANSFORM
            {
                a       = GetVarOrDirectByte(OpCodeParameter.Param1);
                _opCode = ReadByte();
                b       = GetVarOrDirectByte(OpCodeParameter.Param1);
                var c = GetVarOrDirectByte(OpCodeParameter.Param2);
                _opCode = ReadByte();
                var d = GetVarOrDirectByte(OpCodeParameter.Param1);
                PalManipulateInit(a, b, c, d);
            }
            break;

            case 16:            // SO_CYCLE_SPEED
            {
                a = GetVarOrDirectByte(OpCodeParameter.Param1);
                b = GetVarOrDirectByte(OpCodeParameter.Param2);
                ScummHelper.AssertRange(1, a, 16, "o5_roomOps: 16: color cycle");
                _colorCycle[a - 1].Delay = (ushort)((b != 0) ? 0x4000 / (b * 0x4C) : 0);
            }
            break;

            default:
                throw new NotImplementedException();
            }
        }