/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "engines/metaengine.h" #include "base/plugins.h" #include "base/version.h" #include "common/events.h" #include "common/system.h" #include "common/translation.h" #include "common/util.h" #include "graphics/managed_surface.h" #include "gui/about.h" #include "gui/gui-manager.h" #include "gui/ThemeEval.h" namespace GUI { class EE; class EEHandler { public: EEHandler(); ~EEHandler(); bool handleKeyDown(Common::KeyState &state); private: EE *_ee; }; enum { kScrollStartDelay = 1500, kScrollMillisPerPixel = 60 }; // Every Line should start with a letter followed by a digit. Currently those can be // (all subject to change) // Letter: // C, L, R -- set center/left/right alignment // A -- ASCII text to replace the next (latin1) line // Digit: // 0 - 2 -- set a custom color: // 0 normal text // 1 highlighted text // 2 disabled text // TODO: Maybe add a tab/indent feature; that is, make it possible to specify // an amount by which that line shall be indented (the indent of course would have // to be considered while performing any word wrapping, too). // // TODO: Add different font sizes (for bigger headlines) // TODO: Allow color change in the middle of a line... static const char *copyright_text[] = { "", "C0""Copyright (C) 2001-2019 The ScummVM Team", "C0""https://www.scummvm.org", "", "C0""ScummVM is the legal property of its developers, whose names are too numerous to list here. Please refer to the COPYRIGHT file distributed with this binary.", "", }; static const char *gpl_text[] = { "", "C0""This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.", "C0""", "C0""This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.", "", "C0""You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.", "", }; #include "gui/credits.h" AboutDialog::AboutDialog() : Dialog(10, 20, 300, 174), _scrollPos(0), _scrollTime(0), _willClose(false) { reflowLayout(); int i; for (i = 0; i < 1; i++) _lines.push_back(""); Common::String version("C0""ScummVM "); version += gScummVMVersion; _lines.push_back(version); Common::String date = Common::String::format(_("(built on %s)"), gScummVMBuildDate); _lines.push_back("C2" + date); for (i = 0; i < ARRAYSIZE(copyright_text); i++) addLine(copyright_text[i]); Common::String features("C1"); features += _("Features compiled in:"); addLine(features.c_str()); Common::String featureList("C0"); featureList += gScummVMFeatures; addLine(featureList.c_str()); _lines.push_back(""); Common::String engines("C1"); engines += _("Available engines:"); addLine(engines.c_str()); const PluginList &plugins = EngineMan.getPlugins(); PluginList::const_iterator iter = plugins.begin(); for (; iter != plugins.end(); ++iter) { Common::String str; str = "C0"; str += (*iter)->getName(); addLine(str.c_str()); str = "C2"; str += (*iter)->get().getOriginalCopyright(); addLine(str.c_str()); //addLine(""); } for (i = 0; i < ARRAYSIZE(gpl_text); i++) addLine(gpl_text[i]); _lines.push_back(""); for (i = 0; i < ARRAYSIZE(credits); i++) addLine(credits[i]); _eeHandler = new EEHandler; } void AboutDialog::addLine(const char *str) { if (*str == 0) { _lines.push_back(""); } else { Common::String format(str, 2); str += 2; static Common::String asciiStr; if (format[0] == 'A') { bool useAscii = false; #ifdef USE_TRANSLATION // We could use TransMan.getCurrentCharset() but rather than compare strings // it is easier to use TransMan.getCharsetMapping() (non null in case of non // ISO-8859-1 mapping) useAscii = (TransMan.getCharsetMapping() != NULL); #endif if (useAscii) asciiStr = str; return; } StringArray wrappedLines; if (!asciiStr.empty()) { g_gui.getFont().wordWrapText(asciiStr, _w - 2 * _xOff, wrappedLines); asciiStr.clear(); } else g_gui.getFont().wordWrapText(str, _w - 2 * _xOff, wrappedLines); for (StringArray::const_iterator i = wrappedLines.begin(); i != wrappedLines.end(); ++i) { _lines.push_back(format + *i); } } } void AboutDialog::open() { _scrollTime = g_system->getMillis() + kScrollStartDelay; _scrollPos = 0; _willClose = false; Dialog::open(); } void AboutDialog::close() { Dialog::close(); } void AboutDialog::drawDialog(DrawLayer layerToDraw) { Dialog::drawDialog(layerToDraw); setTextDrawableArea(Common::Rect(_x, _y, _x + _w, _y + _h)); // Draw text // TODO: Add a "fade" effect for the top/bottom text lines // TODO: Maybe prerender all of the text into another surface, // and then simply compose that over the screen surface // in the right way. Should be even faster... const int firstLine = _scrollPos / _lineHeight; const int lastLine = MIN((_scrollPos + _h) / _lineHeight + 1, (uint32)_lines.size()); int y = _y + _yOff - (_scrollPos % _lineHeight); for (int line = firstLine; line < lastLine; line++) { const char *str = _lines[line].c_str(); Graphics::TextAlign align = Graphics::kTextAlignCenter; ThemeEngine::WidgetStateInfo state = ThemeEngine::kStateEnabled; if (*str) { switch (str[0]) { case 'C': align = Graphics::kTextAlignCenter; break; case 'L': align = Graphics::kTextAlignLeft; break; case 'R': align = Graphics::kTextAlignRight; break; default: error("Unknown scroller opcode '%c'", str[0]); break; } switch (str[1]) { case '0': state = ThemeEngine::kStateEnabled; break; case '1': state = ThemeEngine::kStateHighlight; break; case '2': state = ThemeEngine::kStateDisabled; break; case '3': warning("Need state for color 3"); // color = g_gui._shadowcolor; break; case '4': warning("Need state for color 4"); // color = g_gui._bgcolor; break; default: error("Unknown color type '%c'", str[1]); } str += 2; } // Trim leading whitespaces if center mode is on if (align == Graphics::kTextAlignCenter) while (*str && *str == ' ') str++; if (*str) g_gui.theme()->drawText(Common::Rect(_x + _xOff, y, _x + _w - _xOff, y + g_gui.theme()->getFontHeight()), str, state, align, ThemeEngine::kTextInversionNone, 0, false, ThemeEngine::kFontStyleBold, ThemeEngine::kFontColorNormal, true, _textDrawableArea); y += _lineHeight; } } void AboutDialog::handleTickle() { const uint32 t = g_system->getMillis(); int scrollOffset = ((int)t - (int)_scrollTime) / kScrollMillisPerPixel; if (scrollOffset > 0) { int modifiers = g_system->getEventManager()->getModifierState(); // Scroll faster when shift is pressed if (modifiers & Common::KBD_SHIFT) scrollOffset *= 4; // Reverse scrolling when alt is pressed if (modifiers & Common::KBD_ALT) scrollOffset *= -1; _scrollPos += scrollOffset; _scrollTime = t; if (_scrollPos < 0) { _scrollPos = 0; } else if ((uint32)_scrollPos > _lines.size() * _lineHeight) { _scrollPos = 0; _scrollTime += kScrollStartDelay; } drawDialog(kDrawLayerForeground); } } void AboutDialog::handleMouseUp(int x, int y, int button, int clickCount) { // Close upon any mouse click close(); } void AboutDialog::handleKeyDown(Common::KeyState state) { if (_eeHandler->handleKeyDown(state)) { reflowLayout(); return; } if (state.ascii) _willClose = true; } void AboutDialog::handleKeyUp(Common::KeyState state) { if (state.ascii && _willClose) close(); } void AboutDialog::reflowLayout() { Dialog::reflowLayout(); int i; const int screenW = g_system->getOverlayWidth(); const int screenH = g_system->getOverlayHeight(); _xOff = g_gui.xmlEval()->getVar("Globals.About.XOffset", 5); _yOff = g_gui.xmlEval()->getVar("Globals.About.YOffset", 5); int outerBorder = g_gui.xmlEval()->getVar("Globals.About.OuterBorder"); _w = screenW - 2 * outerBorder; _h = screenH - 2 * outerBorder; _lineHeight = g_gui.getFontHeight() + 3; // Heuristic to compute 'optimal' dialog width int maxW = _w - 2*_xOff; _w = 0; for (i = 0; i < ARRAYSIZE(credits); i++) { int tmp = g_gui.getStringWidth(credits[i]) + 5; if (_w < tmp && tmp <= maxW) { _w = tmp; } } _w += 2*_xOff; // Center the dialog _x = (screenW - _w) / 2; _y = (screenH - _h) / 2; } //////////////////////////////// //// Here we go //////////////////////////////// enum { kDirUp, kDirLeft, kDirRight }; enum { kModeMenu, kModePlay, kModePause }; enum { kPlComp, kPlHuman }; enum { kSndPoint, kSndHit, kSndLoss }; class EE { public: EE(); ~EE(); void run(); private: Graphics::ManagedSurface _back; int _hits; bool _rmode; // animation after loosing int _score[2]; bool _soundEnabled; bool _shouldQuit; int _rcnt; //last 20 cycles of round int _winner; //who wins the point or serving int _tvelx, _tvely; int _x[2], _y[2], _px[2]; int _frame[2], _frameindex[2]; int _rebound[2]; int _bx, _by, _pbx, _pby, _tbx, _tby, _bvelx, _bvely; int _serve, _server, _servevel, _compserve; int _hitter, _starter, _sstage; int _bytop; int _rnd; int _olx, _oly, _orx, _ory, _obx, _oby; bool _air; bool _oCoords; int _mode; int _keymove[2][3]; int _opts; int _opt; Graphics::Surface _sp[10]; Graphics::PixelFormat _format; int _windowX, _windowY; uint32 _colorBlue, _colorOrange; void cls(bool update = true); void loadSounds(); void processKeyUp(Common::Event &e); void processKeyDown(Common::Event &e); void getPos(); void setwinner(); void resetpt(); void calcscore(); int destination(int pl, int destx, int tol); bool moveball(); void docollisions(); void computer0(); void computer1(); void init(); void draw(int sn, int x, int y); void doMenu(Common::Event &e); void putshapes(); void game(); void playSound(int d); void genSprites(); void drawStatus(Common::String str, int x, uint32 color, int y = 0, int color2 = 0, int w = 16); }; EEHandler::EEHandler() { _ee = new EE; } EEHandler::~EEHandler() { delete _ee; } bool EEHandler::handleKeyDown(Common::KeyState &state) { if (state.ascii == 'v') { _ee->run(); g_gui.redrawFull(); return true; } return false; } EE::EE() { _windowX = (g_system->getOverlayWidth() > 320) ? (g_system->getOverlayWidth() - 320) / 2 : 0; _windowY = (g_system->getOverlayHeight() > 200) ? (g_system->getOverlayHeight() - 200) / 2 : 0; _format = g_system->getOverlayFormat(); _back.create(MIN(g_system->getOverlayWidth(), 320), MIN(g_system->getOverlayHeight(), 200), _format); _colorBlue = _format.RGBToColor(5 * 16, 7 * 16, 8 * 16); _colorOrange = _format.RGBToColor(15 * 16, 7 * 16, 8 * 16); init(); } EE::~EE() { } void EE::cls(bool update) { _back.fillRect(Common::Rect(0, 0, MIN(g_system->getOverlayWidth(), 320), MIN(g_system->getOverlayHeight(), 200)), 0); if (update) g_system->copyRectToOverlay(_back.getPixels(), _back.pitch, _windowX, _windowY, MIN(g_system->getOverlayWidth(), 320), MIN(g_system->getOverlayHeight(), 200)); } void EE::run() { _shouldQuit = false; genSprites(); init(); while (!_shouldQuit) { Common::Event event; while (g_system->getEventManager()->pollEvent(event)) { switch (event.type) { case Common::EVENT_QUIT: case Common::EVENT_RTL: _shouldQuit = true; break; case Common::EVENT_LBUTTONDOWN: break; case Common::EVENT_KEYDOWN: processKeyDown(event); break; case Common::EVENT_KEYUP: processKeyUp(event); break; default: break; } } game(); putshapes(); g_system->updateScreen(); g_system->delayMillis(10); } } enum { kSpL1, kSpL2, kSpL3, kSpR1, kSpR2, kSpR3, kSpB1, kSpB2, kSpB3, kSpB4, kSp0, kSp1, kSp2, kSp3, kSp4, kSp5, kSp6, kSp7, kSp8, kSp9, kSpSt }; const int polecol[] = {0, 1, 2, 3, 3, 4, 6, 7, 9, 14}; const int jump[] = {-4, -4, -3, -3, -3, -3, -2, -2, -2, -2, -2, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4}; void EE::loadSounds() { #if 0 if ($.isEmptyObject(sounds)) { for (i = 0; i < snNames.length; i++) { s = snNames[i]; sounds[s] = new Audio(); sounds[s].src = 'sounds/' + s + '.wav'; } } #endif } void EE::processKeyUp(Common::Event &e) { switch (e.kbd.keycode) { case Common::KEYCODE_LEFT: // left _keymove[1][kDirLeft] = 0; break; case Common::KEYCODE_RIGHT: // right _keymove[1][kDirRight] = 0; break; case Common::KEYCODE_UP: // top _keymove[1][kDirUp] = 0; break; case Common::KEYCODE_a: //a _keymove[0][kDirLeft] = 0; break; case Common::KEYCODE_d: // d _keymove[0][kDirRight] = 0; break; case Common::KEYCODE_w: // w _keymove[0][kDirUp] = 0; break; default: break; } } void EE::processKeyDown(Common::Event &e) { if (_mode == kModeMenu) { doMenu(e); return; } switch (e.kbd.keycode) { case Common::KEYCODE_LEFT: // left _keymove[1][kDirLeft] = -2; break; case Common::KEYCODE_RIGHT: // right _keymove[1][kDirRight] = 2; break; case Common::KEYCODE_UP: // top _keymove[1][kDirUp]= 1; break; case Common::KEYCODE_a: //a _keymove[0][kDirLeft] = -2; break; case Common::KEYCODE_d: // d _keymove[0][kDirRight] = 2; break; case Common::KEYCODE_w: // w _keymove[0][kDirUp] = 1; break; case Common::KEYCODE_ESCAPE: _mode = kModeMenu; break; case Common::KEYCODE_p: // p _keymove[0][kDirRight] = _keymove[0][kDirLeft] = _keymove[0][kDirUp] = 0; _mode = (_mode == kModePlay) ? kModePause : kModePlay; break; case Common::KEYCODE_r: // r if (_mode == kModePlay) init(); break; case Common::KEYCODE_s: // s if (!_soundEnabled) loadSounds(); _soundEnabled = !_soundEnabled; break; default: break; } } void EE::getPos() { int tx, velx, bnd; for (int i = 0; i < 2; i++) { if (_keymove[i][kDirUp] && _frameindex[i] == -1) _frameindex[i] = 0; tx = _x[i] + (velx = _keymove[i][kDirLeft] + _keymove[i][kDirRight]); bnd = 3 + i * 155; if (velx > 0) { if (tx < bnd + 119) _x[i] = tx; else _x[i] = bnd + 119; } else if (tx > bnd) { _x[i] = tx; } else { _x[i] = bnd; } if (_frameindex[i] == -2) { _y[i] = 173; _frame[i] = 0; _frameindex[i] = -1; } if (_frameindex[i] == -1) { if (velx != 0) { if (abs(_px[i] - _x[i]) > 4) { _frame[i] ^= 1; _px[i] = _x[i]; } } else { _frame[i] = 0; } } else { _frame[i] = 2 + (_frameindex[i] > 18); if (_frameindex[i] == 19) _y[i] -= 4; _y[i] += jump[_frameindex[i]++]; if (_frameindex[i] > 37) _frameindex[i] = -2; } } } void EE::setwinner() { if (_hits > 2) { _winner = 1 - _hitter; } else { _winner = _tbx < 150 ? 1 : 0; } _tvely = abs(_bvely) >> 3; _tvelx = abs(_bvelx) >> 3; } void EE::resetpt() { _keymove[0][kDirUp] = 0; _keymove[1][kDirUp] = 0; getPos(); if (abs(_bvelx) > _tvelx) { if (_bvelx < 0) _bvelx = -_tvelx; else _bvelx = _tvelx; } if (abs(_bvely) > _tvely) { if (_bvely < 0) _bvely = -_tvely; else _bvely = _tvely; } docollisions(); moveball(); putshapes(); } void EE::calcscore() { if (_winner == _server) { if (_soundEnabled && _mode != kModeMenu) { playSound(kSndPoint); } _score[_winner]++; if (_score[_winner] > 14 && _score[_winner] - _score[1 - _winner] > 1) { init(); return; } } else { if (_soundEnabled && _mode != kModeMenu) { playSound(kSndLoss); } _server = _winner; } _bx = (_tbx = _pbx = (64 + _winner * 165)) << 6; _by = (_tby = _pby = 135) << 6; _bvelx = _bvely = _hits = _rebound[0] = _rebound[1] = 0; _serve = _servevel = 1; _hitter = 2; _compserve = abs(_rnd) % 5; if (_score[_server] == 14) _compserve = 5; _sstage = 0; } int EE::destination(int pl, int destx, int tol) { int xp; xp = _x[pl]; if (abs(xp - destx) < tol) { _keymove[pl][kDirLeft] = 0; _keymove[pl][kDirRight] = 0; return 1; } if (xp < destx) { _keymove[pl][kDirLeft] = 0; _keymove[pl][kDirRight] = 2; } else { _keymove[pl][kDirLeft] = -2; _keymove[pl][kDirRight] = 0; } return 0; } int reset = false; bool EE::moveball() { int rbvelx, rbvely; bool hitfloor; if (!reset) { _bx = 4096; _by = 8640; _bvelx = 125; _bvely = -259; reset = true; } rbvelx = _bvelx; rbvely = _bvely; if (rbvelx > 319) rbvelx = 319; if (rbvelx < -319) rbvelx = -319; if (rbvely > 319) rbvely = 319; if (rbvely < -319) rbvely = -319; _pbx = _tbx; _pby = _tby; _bx += rbvelx; _by += rbvely; if (_bx < 320) { _bx = 320; rbvelx = -rbvelx; rbvelx -= rbvelx >> 4; rbvely -= rbvely >> 4; if (_hitter == 1) { _hitter = 2; _hits = 0; } } if (_bx > 18112) { _bx = 18112; rbvelx = -rbvelx; rbvelx -= rbvelx >> 4; rbvely -= rbvely >> 4; if (_hitter == 0) { _hitter = 2; _hits = 0; } } if (_by < 832) { _by = 832; rbvely = -rbvely; rbvelx -= rbvelx >> 4; rbvely -= rbvely >> 4; } if (_by > 11392) { _by = 11392; rbvely = -rbvely; hitfloor = false; } else { hitfloor = true; } if (rbvely > 0) rbvely += 1; else rbvely += 1; _tbx = _bx >> 6; _tby = _by >> 6; _bvelx = rbvelx; _bvely = rbvely; return hitfloor; } void EE::docollisions() { int dx, dy, dist, rndoff; for (int i = 0; i < 2; i++) { dx = _tbx - _x[i] - i * 7; dy = (_tby - _y[i]) >> 1; dist = (dx >> 2) * dx + dy * dy; if (dist < 110) { rndoff = 8 - (_rnd & 15); if (_frameindex[i] > -1) _bvely = -abs(_bvely) + (jump[_frameindex[i]] << (3 << _servevel)); else _bvely = -abs(_bvely); _bvely += rndoff; _bvelx += dx * abs(dx) + ((_keymove[i][kDirRight] + _keymove[i][kDirLeft]) << (4 + _servevel)) + rndoff; if (!_rebound[i]) { if (_mode != kModeMenu) { if (_soundEnabled && _mode != kModeMenu) { playSound(kSndHit); } } _bytop = 200; _serve = 0; _rebound[i] = 1; if (_hitter != i) { _hitter = i; _hits = 0; } else { _hits++; } } } else if (_rebound[i]) { _rebound[i] = _servevel = 0; } } int i = 1; if (_tby > 91) { if (_pbx < 128 && _tbx > 127) { _bvelx = -abs(_bvelx) >> 1; _bx = 127 * 64; i = 0; } else if (_pbx > 159 && _tbx < 160) { _bvelx = abs(_bvelx) >> 1; _bx = 160 * 64; i = 0; } } if (i && _tby > 81 && _tbx > 127 && _tbx < 160) { if (_tby > 91) { if (_tbx < 148) _bvelx = -abs(_bvelx); else _bvelx = abs(_bvelx); } else if ((_tbx > 147 && 161 - _tbx >= polecol[91 - _tby]) || (_tbx < 148 && _tbx - 133 >= polecol[91 - _tby])) { if (_bvely > 0) { dx = _tbx - 145; if (dx < -5) _bvelx = -abs(_bvelx); if (dx > 5) _bvelx = abs(_bvelx); _bvely = -abs(_bvely); } if (abs(_bvelx) > 32) _bvelx = _bvelx >> 1; if (abs(_bvely) > 32) _bvely = _bvely >> 1; } } } void EE::computer0() { int ystep, destx, dx, rndoff, dest = 0; _keymove[0][kDirUp] = 0; if (_tby < _bytop) _bytop = _tby; rndoff = 5 - _rnd % 10; if (_serve && ((_server & 1) == 0)) { switch (_compserve) { case 0: dest = destination(0, 55, 2); break; case 1: dest = destination(0, 84, 2); break; case 2: dest = destination(0, 80, 2); break; case 3: if (_sstage == 0) { if ((dest = destination(0, 44, 2))) _sstage = 1; } else { destination(0, 58, 2); dest = 1; } break; case 4: if (_sstage == 0) { if ((dest = destination(0, 90, 2))) _sstage = 1; } else { destination(0, 58, 2); dest = 1; } break; case 5: if (_sstage == 0) { if (destination(0, 3, 2)) _sstage = 1; dest = 0; } else { destination(0, 8 + _sstage++, 1); dest = 1; } break; default: break; } _keymove[0][kDirUp] = dest; } else if (_bvely > 0 && _tbx < 140) { if (_bvely >> 6 == 0) ystep = 0; else ystep = (140 - _tby) / (_bvely >> 6); if (ystep < 1 || (_bvelx >> 6) == 0) destx = _tbx; else destx = _tbx + (_bvelx >> 6) * ystep - 4; dx = _x[0] - _tbx; if (abs(_bvelx) < 128 && _bytop < 75) { if ((_tby < 158) ^ (_bvelx < 0)) destination(0, _tbx - 15, 3); else destination(0, _tbx + 15, 3); } else { if (_tby > 130) { if (abs(dx) > 6 && abs(_bvelx) < 1024) { destination(0, _tbx - ((_x[0] - 60) >> 3), 3); } else { destination(0, _tbx + rndoff + ((_x[0] - 60) >> 3), 10); _keymove[0][kDirUp] = _x[0] < 105 && (_hitter != 0 || _hits < 2); } } else { if (destx < 3) destx = 6 - destx; if (destx > 123) destx = 246 - destx; destination(0, destx + rndoff, 3); } } } else destination(0, 56, 8); } void EE::computer1() { int ystep, destx, dx, rndoff, dest = 0; _keymove[1][kDirUp] = 0; if (_tby < _bytop) _bytop = _tby; rndoff = 5 - _rnd % 10; if (_serve && ((_server & 1) == 1)) { switch (_compserve) { case 0: dest = destination(1, 232, 2); break; case 1: dest = destination(1, 202, 2); break; case 2: dest = destination(1, 208, 2); break; case 3: if (_sstage == 0) { if ((dest = destination(1, 250, 2))) _sstage = 1; } else { destination(1, 220, 2); dest = 1; } break; case 4: if (_sstage == 0) { if ((dest = destination(1, 190, 2))) _sstage = 1; } else { destination(1, 230, 2); dest = 1; } break; case 5: if (_sstage == 0) { if (destination(1, 277, 2)) _sstage = 1; dest = 0; } else { destination(1, 272 - _sstage++, 1); dest = 1; } break; default: break; } _keymove[1][kDirUp] = dest; } else if (_bvely > 0 && _tbx > 125) { if (_bvely >> 6 == 0) ystep = 0; else ystep = (140 - _tby) / (_bvely >> 6); if (ystep < 1 || (_bvelx >> 6) == 0) destx = _tbx; else destx = _tbx + (_bvelx >> 6) * ystep - 4; dx = _x[1] - _tbx; if (abs(_bvelx) < 128 && _bytop < 75) { if ((_tby < 158) ^ (_bvelx < 0)) destination(1, _tbx + 15, 3); else destination(1, _tbx - 15, 3); } else { if (_tby > 130) { if (abs(dx) > 6 && abs(_bvelx) < 1024) destination(1, _tbx + ((_x[1] - 218) >> 3), 3); else { destination(1, _tbx - rndoff - ((_x[1] - 218) >> 3), 10); _keymove[1][kDirUp] = _x[1] > 175 && (_hitter != 1 || _hits < 2); } } else { if (destx < 158) destx = 316 - destx; if (destx > 277) destx = 554 - destx; destination(1, destx - rndoff, 3); } } } else destination(1, 211, 8); } void EE::init() { cls(); _rnd = 0; _starter = _winner = _hits = 0; _bvelx = _bvely = 0; _tbx = 200; _tby = 20; _bytop = 200; _x[0] = 64; _x[1] = 226; _air = false; _rcnt = 0; _tvelx = _tvely = 0; for (int i = 0; i < 2; i++) { _px[i] = _x[i]; _y[i] = 173; _frameindex[i] = -1; _rebound[i] = 0; _score[i] = 0; _keymove[i][kDirRight] = _keymove[i][kDirLeft] = _keymove[i][kDirUp] = 0; _frame[i] = 0; } _oCoords = false; _opts = 3; _opt = 0; _mode = kModeMenu; _soundEnabled = false; _olx = _oly = _orx = _ory = _obx = _oby = 0; _compserve = 0; _sstage = 0; _tbx = 64 + _starter * 165; _pbx = _tbx; _bx = _tbx << 6; _tby = 135; _pby = 135; _by = _tby << 6; _server = 2 + _starter; _hitter = 2; _serve = _servevel = 1; _rmode = false; } void EE::drawStatus(Common::String str, int x, uint32 color, int y, int color2, int w) { if (color2) _back.fillRect(Common::Rect(x, y, x + w, y + 10), color2); g_gui.theme()->getFont(ThemeEngine::kFontStyleConsole)->drawString(&_back, str, x, y, 160, color); } void EE::draw(int sn, int x, int y) { _back.transBlitFrom(_sp[sn], Common::Point(x, y), 0); g_system->copyRectToOverlay(_back.getBasePtr(x, y), _back.pitch, MIN(_windowX + x, g_system->getOverlayWidth()), MIN(_windowY + y, g_system->getOverlayHeight()), MIN(_sp[sn].w, g_system->getOverlayWidth() - MIN(_windowX + x, g_system->getOverlayWidth())), MIN(_sp[sn].h, g_system->getOverlayHeight() - MIN(_windowY + y, g_system->getOverlayHeight()) )); } const char *codes = "Dvhgkm#Ztrsm|ffrs(#$%&'#$%&O}pes&}{1$M{tiq$%&'#$M{tiq${y5(Fsrv||hv%&'#$" "Hutxxxjx'~v2%N|udr%&'#Gtsw}wiw&}{1$Hutxxxjx'#$%&'(#$%W|qw$%&'(#$%&'"; void EE::putshapes() { int sprite; cls(false); if (_oCoords) { g_system->copyRectToOverlay(_back.getBasePtr(_obx, _oby), _back.pitch, MIN(_windowX + _obx, g_system->getOverlayWidth()), MIN(_windowY + _oby, g_system->getOverlayHeight()), MIN(_sp[kSpB1].w, g_system->getOverlayWidth() - MIN(_windowX + _obx, g_system->getOverlayWidth())), MIN(_sp[kSpB1].h, g_system->getOverlayHeight() - MIN(_windowY + _oby, g_system->getOverlayHeight()) )); g_system->copyRectToOverlay(_back.getBasePtr(_olx, _oly), _back.pitch, MIN(_windowX + _olx, g_system->getOverlayWidth()), MIN(_windowY + _oly, g_system->getOverlayHeight()), MIN(_sp[kSpL1].w, g_system->getOverlayWidth() - MIN(_windowX + _olx, g_system->getOverlayWidth())), MIN(_sp[kSpL1].h, g_system->getOverlayHeight() - MIN(_windowY + _oly, g_system->getOverlayHeight()) )); g_system->copyRectToOverlay(_back.getBasePtr(_orx, _ory), _back.pitch, MIN(_windowX + _orx, g_system->getOverlayWidth()), MIN(_windowY + _ory, g_system->getOverlayHeight()), MIN(_sp[kSpR1].w, g_system->getOverlayWidth() - MIN(_windowX + _orx, g_system->getOverlayWidth())), MIN(_sp[kSpR1].h, g_system->getOverlayHeight() - MIN(_windowY + _ory, g_system->getOverlayHeight()) )); } sprite = kSpB1 + (_tbx / 16) % 4; draw(sprite, _tbx, _tby); _obx = _tbx; _oby = _tby; if (_y[0] < 173) { sprite = kSpL3; } else { if ((_x[0] / 8) % 2) sprite = kSpL1; else sprite = kSpL2; } draw(sprite, _x[0], _y[0]); _olx = _x[0]; _oly = _y[0]; if (_y[1] < 173) { sprite = kSpR3; } else { if ((_x[1] / 8) % 2) sprite = kSpR1; else sprite = kSpR2; } draw(sprite, _x[1], _y[1]); _orx = _x[1]; _ory = _y[1]; _oCoords = true; const int frames[] = { 153, 106, 160, 200, 4, 13, 6, 200, 310, 13, 312, 200, 4, 13, 312, 14, 4, 199, 312, 200, 154, 107, 159, 199 }; uint32 color1 = _back.format.RGBToColor(5 * 16, 7 * 16, 8 * 16); uint32 color2 = _back.format.RGBToColor(6 * 16, 8 * 16, 12 * 16); const int *ptr = frames; for (int i = 0; i < 6; i++, ptr += 4) { Common::Rect r(ptr[0], ptr[1], ptr[2], ptr[3]); _back.fillRect(r, (i < 5 ? color1 : color2)); g_system->copyRectToOverlay(_back.getBasePtr(ptr[0], ptr[1]), _back.pitch, MIN(_windowX + ptr[0], g_system->getOverlayWidth()), MIN(_windowY + ptr[1], g_system->getOverlayHeight()), MIN(r.width(), g_system->getOverlayWidth() - MIN(_windowX + ptr[0], g_system->getOverlayWidth())), MIN(r.height(), g_system->getOverlayHeight() - MIN(_windowY + ptr[1], g_system->getOverlayHeight()) )); } int startx = 32; Common::String str = Common::String::format("%02d", _score[0]); drawStatus(str, startx, _colorOrange); startx += 16; drawStatus((_server == 0) ? "*" : " ", startx, _colorBlue); startx = 264; str = Common::String::format("%02d", _score[1]); drawStatus(str, startx, _colorOrange); startx += 16; drawStatus((_server == 1) ? "*" : " ", startx, _colorBlue); for (int i = 0; i < 6; i++) { char buf[100]; int c; for (c = 0; c < 23; c++) buf[c] = codes[c + 23 * i] - 3 - c % 6; buf[c] = 0; int sx = i == 0 ? 110 : 92; int sy = i == 0 ? 0 : 20; int c1 = i == 0 ? _colorOrange : (i - 1 == _opt) ? 0 : _colorBlue; int c2 = i - 1 == _opt ? _colorBlue : 0; drawStatus(buf, sx, c1, sy + i * 10, c2, 135); if (_mode != kModeMenu) break; } g_system->copyRectToOverlay(_back.getPixels(), _back.pitch, MIN(_windowX, g_system->getOverlayWidth()), MIN(_windowY, g_system->getOverlayHeight()), MIN(320, g_system->getOverlayWidth() - MIN(_windowX, g_system->getOverlayWidth())), MIN(10, g_system->getOverlayHeight() - MIN(_windowY, g_system->getOverlayHeight()) )); if (_mode == kModeMenu) { g_system->copyRectToOverlay(_back.getBasePtr(92, 30), _back.pitch, MIN(_windowX + 92, g_system->getOverlayWidth()), MIN(_windowY + 30, g_system->getOverlayHeight()), MIN(135, g_system->getOverlayWidth() - MIN(_windowX + 92, g_system->getOverlayWidth())), MIN(5 * 10, g_system->getOverlayHeight() - MIN(_windowY + 30, g_system->getOverlayHeight()) )); } } void EE::doMenu(Common::Event &e) { switch (e.kbd.keycode) { case Common::KEYCODE_UP: _opt--; if (_opt < 0) _opt = 4; break; case Common::KEYCODE_DOWN: _opt = (_opt + 1) % 5; break; case Common::KEYCODE_RETURN: if (_opt < 4) { _opts = _opt; _mode = kModePlay; cls(); } else { _shouldQuit = true; } break; case Common::KEYCODE_ESCAPE: _shouldQuit = true; break; default: break; } } void EE::game() { if (_mode == kModePlay || _mode == kModeMenu) { _rnd = (_rnd * 5 + 1) % 32767; if (_opts & 1) computer0(); if (_opts & 2) computer1(); if (_rmode) { if (_rcnt-- > 0 || _frameindex[0] != -1 || _frameindex[1] != -1) { resetpt(); } else { _rmode = false; calcscore(); } return; } getPos(); if (_serve) { docollisions(); _air = true; } else { if (_air) { docollisions(); _air = moveball(); } } if (!_air || _hits > 2) { setwinner(); _rmode = true; _rcnt = 20; } } } void EE::playSound(int sound) { // FIXME } static const uint32 ball[21] = { 0x0000fd00, 0x00074ac0, 0x000afde0, 0x001703e8, 0x0038f7d8, 0x0056f73c, 0x00aef6fc, 0x00cf79fb, 0x01afbbf7, 0x01b7bdcd, 0x0077dd3a, 0x013beef3, 0x01bbef6a, 0x015df78b, 0x00defbea, 0x00ef7dd8, 0x00779eb4, 0x0029ef68, 0x001ef4a0, 0x000673c0, 0x0000ae00 }; static const uint32 head[38] = { 0xbb400000, 0x0000000f, 0xea650000, 0x000003af, 0xfaaa6000, 0x00000e7f, 0xfea5a400, 0x03ff2af0, 0x3eaa6900, 0x3ea969c0, 0x3ea99940, 0xeaaa69c8, 0x3a669540, 0xea995540, 0x5a555550, 0xa9aa999a, 0x65a65550, 0x2aa69a5a, 0x59555650, 0x02aaaa55, 0x6aa66550, 0x000aa950, 0x6a569950, 0x000a9500, 0xa9595580, 0x00015001, 0xa9a55540, 0x00000015, 0xa9a9a500, 0x0000015a, 0x59695800, 0x00001659, 0x65659000, 0x00000a96, 0xa65a8000, 0x000002aa, 0xa6500000, 0x0000002a }; static const uint32 legs[42] = { 0xa0000000, 0x00000000, 0x80000000, 0x00000002, 0x80000000, 0x00000002,0xa0000000, 0x00000000, 0x50000000, 0x00000000, 0xf0000000, 0x00000003, 0xfc000000, 0x000003ff, 0xa0000000, 0x00000002, 0x0a000000, 0x0000000a, 0x02400000, 0x00000028, 0x00700000, 0x00000028, 0x00fc0000, 0x00000014, 0x03c00000, 0x000000fc, 0x0f000000, 0x0000ffff, 0xa0000000, 0x00000000, 0x80000000, 0x00000002, 0xa8000000, 0x00000002, 0x29c00000, 0x00000000, 0x01f00000, 0x00000000, 0x0fc00000, 0x00000000, 0xfc000000, 0x00000000 }; static const int spcolors[10 * 3] = { 0, 0, 0, 8, 15, 8, 6, 12, 6, 12, 13, 12, 0, 0, 0, 15, 8, 8, 12, 6, 6, 13, 12, 12, 0, 0, 0, 12, 12, 12 }; void EE::genSprites() { uint32 palette[12]; for (int i = 0; i < 10 * 3; i += 3) palette[i / 3] = _back.format.RGBToColor(spcolors[i] * 16, spcolors[i + 1] * 16, spcolors[i + 2] * 16); for (int s = 0; s < 4; s++) { _sp[kSpB1 + s].create(25, 21, g_system->getOverlayFormat()); int posy = 0, dy = 1; if (s & 2) { posy = 20; dy = -1; } for (int y = 0; y < 21; y++, posy += dy) { uint32 pixels = ball[y]; int posx = 0, dx = 1; if (s & 1) { posx = 24; dx = -1; } for (int x = 0; x < 25; x++, posx += dx) { int color = pixels & 1; pixels >>= 1; if (_back.format.bytesPerPixel == 2) *((uint16 *)_sp[kSpB1 + s].getBasePtr(posx, posy)) = (uint16)palette[color + 8]; else if (_back.format.bytesPerPixel == 4) *((uint32 *)_sp[kSpB1 + s].getBasePtr(posx, posy)) = palette[color + 8]; } } } for (int s = 0; s < 6; s++) { _sp[kSpL1 + s].create(32, 26, g_system->getOverlayFormat()); for (int y = 0; y < 26; y++) { const uint32 *ptr = (y < 19) ? &head[y * 2] : &legs[(y - 19 + (s % 3) * 7) * 2]; uint32 pixels = *ptr++; int posx = 0, dx = 1; if (s > 2) { posx = 31; dx = -1; } for (int x = 0; x < 32; x++, posx += dx) { int color = pixels & 3; pixels >>= 2; if (x == 15) pixels = *ptr; if (_back.format.bytesPerPixel == 2) *((uint16 *)_sp[kSpL1 + s].getBasePtr(posx, y)) = (uint16)palette[color + 4 * (s / 3)]; else if (_back.format.bytesPerPixel == 4) *((uint32 *)_sp[kSpL1 + s].getBasePtr(posx, y)) = palette[color + 4 * (s / 3)]; } } } } } // End of namespace GUI