示例#1
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);
        }
示例#2
0
        static byte[] Capture(VirtScreen screen, int x, int y, int w, int h)
        {
            var pixels = new byte[w * h];
            var nav    = new PixelNavigator(screen.Surfaces[0]);

            nav.GoTo(x, y);
            for (int height = 0; height < h; height++)
            {
                for (int width = 0; width < w; width++)
                {
                    pixels[height * w + width] = nav.Read();
                    nav.OffsetX(1);
                }
                nav.Offset(-w, 1);
            }
            return(pixels);
        }
示例#3
0
        protected void GetPixel(int x, int y)
        {
            var vs = FindVirtScreen(y);

            if (vs == null || x > ScreenWidth - 1 || x < 0)
            {
                Push(-1);
                return;
            }

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

            nav.GoTo(x, y - vs.TopLine);
            var pixel = nav.Read();

            Push(pixel);
        }
示例#4
0
 static void DumpZPlanes(Room room, string name)
 {
     if (room.Image != null)
     {
         for (int i = 0; i < room.Image.ZPlanes.Count; i++)
         {
             var zplane  = room.Image.ZPlanes[i];
             var nStrips = zplane.StripOffsets.Count;
             var pixels  = new byte[nStrips * room.Header.Height];
             var pn      = new PixelNavigator(pixels, nStrips, 1);
             using (var ms = new MemoryStream(zplane.Data))
             {
                 for (int nStrip = 0; nStrip < nStrips; nStrip++)
                 {
                     var offset = zplane.StripOffsets[nStrip];
                     if (offset.HasValue)
                     {
                         ms.Seek(offset.Value, SeekOrigin.Begin);
                         pn.GoTo(nStrip, 0);
                         DecompressMaskImg(pn, ms, room.Header.Height);
                     }
                 }
             }
             using (var bmpZ = new System.Drawing.Bitmap(nStrips * 8, room.Header.Height))
             {
                 for (int j = 0; j < room.Header.Height; j++)
                 {
                     for (int x = 0; x < nStrips; x++)
                     {
                         for (int b = 0; b < 8; b++)
                         {
                             bmpZ.SetPixel(x * 8 + b, j, (pixels[x + j * nStrips] & (0x80 >> b)) != 0 ? System.Drawing.Color.White : System.Drawing.Color.Black);
                         }
                     }
                 }
                 bmpZ.Save(name + "_z" + i + ".png");
             }
         }
     }
 }
示例#5
0
        protected void TownsDrawStripToScreen(VirtScreen vs, int dstX, int dstY, int srcX, int srcY, int width, int height)
        {
            if (width <= 0 || height <= 0)
            {
                return;
            }

            int m = _textSurfaceMultiplier;

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

            src1.GoTo(vs.XStart + srcX, srcY);
            var src2 = new PixelNavigator(_textSurface);

            src2.GoTo(srcX * m, (srcY + vs.TopLine - ScreenTop) * m);
            var dst1 = new PixelNavigator(_townsScreen.GetLayerPixels(0, dstX, dstY).Value);
            var dst2 = new PixelNavigator(_townsScreen.GetLayerPixels(1, dstX * m, dstY * m).Value);

            int dp1 = _townsScreen.GetLayerPitch(0) - width * _townsScreen.GetLayerBpp(0);
            int dp2 = _townsScreen.GetLayerPitch(1) - width * m * _townsScreen.GetLayerBpp(1);
            int sp1 = vs.Pitch - (width * Surface.GetBytesPerPixel(vs.PixelFormat));
            int sp2 = _textSurface.Pitch - width * m;

            if (vs == MainVirtScreen || Game.GameId == GameId.Indy3 || Game.GameId == GameId.Zak)
            {
                for (int h = 0; h < height; ++h)
                {
                    if (Surface.GetBytesPerPixel(_gfxManager.PixelFormat) == 2)
                    {
                        for (int w = 0; w < width; ++w)
                        {
                            dst1.WriteUInt16(_16BitPalette[src1.Read()]);
                            src1.OffsetX(1);
                            dst1.OffsetX(1);
                        }

                        src1.OffsetX(sp1 / src1.BytesByPixel);
                        dst1.OffsetX(dp1 / dst1.BytesByPixel);
                    }
                    else
                    {
                        for (int i = 0; i < width; i++)
                        {
                            dst1.Write(src1.Read());
                            dst1.OffsetX(1);
                            src1.OffsetX(1);
                        }
                    }

                    for (int sH = 0; sH < m; ++sH)
                    {
                        for (int i = 0; i < width * m; i++)
                        {
                            dst2.Write(src2.Read());
                            src2.OffsetX(1);
                            dst2.OffsetX(1);
                        }
                        src2.OffsetX(_textSurface.Width - (width * m));
                        dst2.OffsetX(dst2.Width - (width * m));
                    }
                }
            }
            else
            {
                dst1 = new PixelNavigator(dst2);
                for (int h = 0; h < height; ++h)
                {
                    for (int w = 0; w < width; ++w)
                    {
                        var t = (src1.Read()) & 0x0f;
                        src1.OffsetX(1);
                        for (int i = 0; i < m; i++)
                        {
                            dst1.Write((byte)((t << 4) | t));
                            dst1.OffsetX(1);
                        }
                    }

                    dst1 = new PixelNavigator(dst2);
                    var src3 = new PixelNavigator(src2);

                    if (m == 2)
                    {
                        dst2.OffsetY(1);
                        src3.OffsetY(1);
                    }

                    for (int w = 0; w < width * m; ++w)
                    {
                        dst2.Write((byte)(src3.Read() | dst1.Read() & _townsLayer2Mask[src3.Read()]));
                        dst2.OffsetX(1);
                        dst1.Write((byte)(src2.Read() | dst1.Read() & _townsLayer2Mask[src2.Read()]));
                        src2.OffsetX(1);
                        src3.OffsetX(1);
                        dst1.OffsetX(1);
                    }

                    src1.OffsetX(sp1 / src1.BytesByPixel);
                    src2 = new PixelNavigator(src3);
                    src2.OffsetX(sp2 / src2.BytesByPixel);
                    dst1 = new PixelNavigator(dst2);
                    dst1.OffsetX(dp2 / dst1.BytesByPixel);
                    dst2.OffsetX(dp2 / dst2.BytesByPixel);
                }
            }

            _townsScreen.AddDirtyRect(dstX * m, dstY * m, width * m, height * m);
        }
示例#6
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);
                }
            }
        }
示例#7
0
        /// <summary>
        /// Blit the specified rectangle from the given virtual screen to the display.
        /// Note: t and b are in *virtual screen* coordinates, while x is relative to
        /// the *real screen*. This is due to the way tdirty/vdirty work: they are
        /// arrays which map 'strips' (sections of the real screen) to dirty areas as
        /// specified by top/bottom coordinate in the virtual screen.
        /// </summary>
        /// <param name="vs"></param>
        /// <param name="x"></param>
        /// <param name="width"></param>
        /// <param name="top"></param>
        /// <param name="bottom"></param>
        void DrawStripToScreen(VirtScreen vs, int x, int width, int top, int bottom)
        {
            // Short-circuit if nothing has to be drawn
            if (bottom <= top || top >= vs.Height)
            {
                return;
            }

            // Perform some clipping
            if (width > vs.Width - x)
            {
                width = vs.Width - x;
            }
            if (top < ScreenTop)
            {
                top = ScreenTop;
            }
            if (bottom > ScreenTop + ScreenHeight)
            {
                bottom = ScreenTop + ScreenHeight;
            }

            // Convert the vertical coordinates to real screen coords
            int y      = vs.TopLine + top - ScreenTop;
            int height = bottom - top;

            if (width <= 0 || height <= 0)
            {
                return;
            }

            byte[] src;
            if (Game.Version < 7)
            {
                if (Game.Platform == Platform.FMTowns)
                {
                    TownsDrawStripToScreen(vs, x, y, x, top, width, height);
                    return;
                }

                var srcNav = new PixelNavigator(vs.Surfaces[0]);
                srcNav.GoTo(vs.XStart + x, top);

                var compNav = new PixelNavigator(_composite);
                var txtNav  = new PixelNavigator(_textSurface);
                int m       = _textSurfaceMultiplier;
                txtNav.GoTo(x * m, y * m);

                var vsPitch   = vs.Pitch - width * vs.BytesPerPixel;
                var textPitch = _textSurface.Pitch - width * m;

                for (int h = height * m; h > 0; --h)
                {
                    for (int w = width * m; w > 0; w--)
                    {
                        var temp = txtNav.Read();
                        int mask = temp ^ CharsetMaskTransparency;
                        mask = (((mask & 0x7f) + 0x7f) | mask) & 0x80;
                        mask = ((mask >> 7) + 0x7f) ^ 0x80;

                        var dst = ((temp ^ srcNav.Read()) & mask) ^ temp;
                        compNav.Write((byte)dst);

                        srcNav.OffsetX(1);
                        txtNav.OffsetX(1);
                        compNav.OffsetX(1);
                    }

                    srcNav.OffsetX(vsPitch);
                    txtNav.OffsetX(textPitch);
                }

                src = _composite.Pixels;
            }
            else
            {
                src = new byte[width * height * vs.BytesPerPixel];
                var srcNav = new PixelNavigator(vs.Surfaces[0]);
                srcNav.GoTo(vs.XStart + x, top);
                for (int h = 0; h < height; h++)
                {
                    for (int w = 0; w < width; w++)
                    {
                        src[h * width + w] = srcNav.Read();
                        srcNav.OffsetX(1);
                    }
                    srcNav.Offset(-width, 1);
                }
            }

            // Finally blit the whole thing to the screen
            _gfxManager.CopyRectToScreen(src, width * vs.BytesPerPixel, x, y, width, height);
        }
示例#8
0
        protected void DrawBoxCore(int x, int y, int x2, int y2, int color)
        {
            VirtScreen vs;

            if ((vs = FindVirtScreen(y)) == null)
            {
                return;
            }

            if (x > x2)
            {
                ScummHelper.Swap(ref x, ref x2);
            }

            if (y > y2)
            {
                ScummHelper.Swap(ref y, ref y2);
            }

            x2++;
            y2++;

            // Adjust for the topline of the VirtScreen
            y  -= vs.TopLine;
            y2 -= vs.TopLine;

            // Clip the coordinates
            if (x < 0)
            {
                x = 0;
            }
            else if (x >= vs.Width)
            {
                return;
            }

            if (x2 < 0)
            {
                return;
            }
            if (x2 > vs.Width)
            {
                x2 = vs.Width;
            }

            if (y < 0)
            {
                y = 0;
            }
            else if (y > vs.Height)
            {
                return;
            }

            if (y2 < 0)
            {
                return;
            }

            if (y2 > vs.Height)
            {
                y2 = vs.Height;
            }

            int width  = x2 - x;
            int height = y2 - y;

            // This will happen in the Sam & Max intro - see bug #1039162 - where
            // it would trigger an assertion in blit().

            if (width <= 0 || height <= 0)
            {
                return;
            }

            MarkRectAsDirty(vs, x, x2, y, y2);

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

            backbuff.GoTo(vs.XStart + x, y);

            // A check for -1 might be wrong in all cases since o5_drawBox() in its current form
            // is definitely not capable of passing a parameter of -1 (color range is 0 - 255).
            // Just to make sure I don't break anything I restrict the code change to FM-Towns
            // version 5 games where this change is necessary to fix certain long standing bugs.
            if (color == -1 || (color >= 254 && Game.Platform == Platform.FMTowns && (Game.GameId == GameId.Monkey2 || Game.GameId == GameId.Indy4)))
            {
                if (_game.Platform == Platform.FMTowns)
                {
                    if (color == 254)
                    {
                        TownsSetupPalCycleField(x, y, x2, y2);
                    }
                }
                else
                {
                    if (vs != MainVirtScreen)
                    {
                        Debug.WriteLine("can only copy bg to main window");
                    }

                    var bgbuff = new PixelNavigator(vs.Surfaces[1]);
                    bgbuff.GoTo(vs.XStart + x, y);

                    Gdi.Blit(backbuff, bgbuff, width, height);
                    if (_charset.HasMask)
                    {
                        var mask = new PixelNavigator(_textSurface);
                        mask.GoToIgnoreBytesByPixel(x * _textSurfaceMultiplier, (y - ScreenTop) * _textSurfaceMultiplier);
                        Gdi.Fill(mask, CharsetMaskTransparency, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier);
                    }
                }
            }
            else
            {
                if (_game.Features.HasFlag(GameFeatures.Is16BitColor))
                {
                    Gdi.Fill(backbuff, _16BitPalette[color], width, height);
                }
                else
                {
                    if (_game.Platform == Platform.FMTowns)
                    {
                        color = ((color & 0x0f) << 4) | (color & 0x0f);
                        var mask = new PixelNavigator(_textSurface);
                        mask.GoTo(x * _textSurfaceMultiplier, (y - ScreenTop + vs.TopLine) * _textSurfaceMultiplier);
                        Gdi.Fill(mask, (byte)color, width * _textSurfaceMultiplier, height * _textSurfaceMultiplier);

                        if (Game.GameId == GameId.Monkey2 || Game.GameId == GameId.Indy4 || ((Game.GameId == GameId.Indy3 || Game.GameId == GameId.Zak) &&
                                                                                             vs != TextVirtScreen) || (_game.GameId == GameId.Loom && vs == MainVirtScreen))
                        {
                            return;
                        }
                    }

                    Gdi.Fill(backbuff, (byte)color, width, height);
                }
            }
        }
示例#9
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;
        }
示例#10
0
        protected virtual void KernelGetFunctions()
        {
            var vs = MainVirtScreen;

            var args = GetStackList(30);

            switch (args[0])
            {
            case 113:
                // WORKAROUND for bug #899249: The scripts used for screen savers
                // in Sam & Max use hard coded values for the maximum height and width.
                // This causes problems in rooms (ie. Credits) where their values are
                // lower, so we set result to zero if out of bounds.
                if (args[1] >= 0 && args[1] <= vs.Width && args[2] >= 0 && args[2] <= vs.Height)
                {
                    var nav = new PixelNavigator(vs.Surfaces[0]);
                    nav.GoTo(args[1], args[2]);
                    var pixel = nav.Read();
                    Push(pixel);
                }
                else
                {
                    Push(0);
                }
                break;

            case 115:
                Push(GetSpecialBox(new Point((short)args[1], (short)args[2])));
                break;

            case 116:
                Push(CheckXYInBoxBounds(args[3], new Point((short)args[1], (short)args[2])));
                break;

            case 206:
                Push(RemapPaletteColor(args[1], args[2], args[3], -1));
                break;

            case 207:
            {
                var i = GetObjectIndex(args[1]);
                Debug.Assert(i != 0);
                Push(_objs[i].Position.X);
            }
            break;

            case 208:
            {
                var i = GetObjectIndex(args[1]);
                Debug.Assert(i != 0);
                Push(_objs[i].Position.Y);
            }
            break;

            case 209:
            {
                var i = GetObjectIndex(args[1]);
                Debug.Assert(i != 0);
                Push(_objs[i].Width);
            }
            break;

            case 210:
            {
                var i = GetObjectIndex(args[1]);
                Debug.Assert(i != 0);
                Push(_objs[i].Height);
            }
            break;

            case 211:
                /*
                 * 13 = thrust
                 * 336 = thrust
                 * 328 = thrust
                 * 27 = abort
                 * 97 = left
                 * 331 = left
                 * 115 = right
                 * 333 = right
                 */

                Push(GetKeyState(args[1]));
                break;

            case 212:
            {
                var a = Actors[args[1]];
                // This is used by walk scripts
                Push(a.Frame);
            }
            break;

            case 213:
            {
                var slot = GetVerbSlot(args[1], 0);
                Push(Verbs[slot].CurRect.Left);
            }
            break;

            case 214:
            {
                var slot = GetVerbSlot(args[1], 0);
                Push(Verbs[slot].CurRect.Top);
            }
            break;

            case 215:
                if ((_extraBoxFlags[args[1]] & 0x00FF) == 0x00C0)
                {
                    Push(_extraBoxFlags[args[1]]);
                }
                else
                {
                    Push((int)GetBoxFlags((byte)args[1]));
                }
                break;

            default:
                throw new NotSupportedException(string.Format("KernelGetFunctions: default case {0}", args[0]));
            }
        }