Back to index

kdeartwork  4.3.2
aasaver.cpp
Go to the documentation of this file.
00001 /*
00002  * Asciiquarium - Native KDE Screensaver based on the Asciiquarium program
00003  *    (c) Kirk Baucom <kbaucom@schizoid.com>, which you can find at
00004  *    http://www.robobunny.com/projects/asciiquarium/
00005  *
00006  * Ported to KDE by Maksim Orlovich <maksim@kde.org> and
00007  * Michael Pyne <michael.pyne@kdemail.net>.
00008  *
00009  * Copyright (c) 2003 Kirk Baucom     <kbaucom@schizoid.com>
00010  * Copyright (c) 2005 Maksim Orlovich <maksim@kde.org>
00011  * Copyright (c) 2005, 2008 Michael Pyne <michael.pyne@kdemail.net>
00012  *
00013  * ASCII Art was mostly created by Joan Stark:
00014  *    http://www.geocities.com/SoHo/7373/
00015  *
00016  * the rest was crafted by Kirk Baucom, and all of it was edited by
00017  * Maksim Orlovich and Michael Pyne to adopt to C++ formatting.
00018  *
00019  * Ported to KDE 4 by Michael Pyne.
00020  *
00021  * This program is free software; you can redistribute it and/or
00022  * modify it under the terms of the GNU General Public License
00023  * as published by the Free Software Foundation; either version 2
00024  * of the License, or (at your option) any later version.
00025  *
00026  * This program is distributed in the hope that it will be useful,
00027  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00028  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00029  * GNU General Public License for more details.
00030  *
00031  * You should have received a copy of the GNU General Public License along with
00032  * this program; if not, write to the Free Software Foundation, Inc., 51
00033  * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
00034  */
00035 
00036 #include "aasaver.h"
00037 
00038 #include <QtGui/QDesktopWidget>
00039 #include <QtGui/QApplication>
00040 #include <QtGui/QPainter>
00041 #include <QtGui/QBrush>
00042 #include <QtGui/QPaintEvent>
00043 #include <QtCore/QList>
00044 
00045 #include <kdebug.h>
00046 #include <klocale.h>
00047 #include <kconfigdialog.h>
00048 
00049 #include <cstdlib>
00050 
00051 #include "screen.h"
00052 #include "frame.h"
00053 #include "sprite.h"
00054 
00055 #include "AASaverConfig.h"
00056 #include "ui_settingswidget.h"
00057 
00058 #define ARRAY_SIZE(arr) sizeof(arr)/sizeof(arr[0])
00059 
00060 AASaver *AASaver::m_instance = 0;
00061 
00062 AASaver::AASaver(WId id): KScreenSaver(id)
00063 {
00064     if(m_instance)
00065         std::abort();
00066 
00067     m_instance = this;
00068 
00069     screen = new Screen(this);
00070 
00071     addEnvironment();
00072     addCastle();
00073     addAllSeaweed();
00074     addAllFish();
00075     addRandom(screen);
00076 
00077     setAttribute(Qt::WA_OpaquePaintEvent);
00078     setAttribute(Qt::WA_NoSystemBackground);
00079     setAttribute(Qt::WA_PaintOnScreen);
00080     update(rect());
00081 }
00082 
00083 AASaver *AASaver::instance()
00084 {
00085     if(!m_instance)
00086         std::abort();
00087 
00088     return m_instance;
00089 }
00090 
00091 QString AASaver::randColor(QString color_mask)
00092 {
00093     char colors[] = {'c','C','r','R','y','Y','b','B','g','G','m','M'};
00094     for (int i = 1; i <= 9; ++i)
00095     {
00096         char color = colors[m_randomSequence.getLong(ARRAY_SIZE(colors))];
00097         color_mask.replace('0' + i, color);
00098     }
00099     return color_mask;
00100 }
00101 
00102 double AASaver::doubleRand(int max)
00103 {
00104     return m_randomSequence.getDouble() * max;
00105 }
00106 
00107 void AASaver::addCastle()
00108 {
00109     QString castle_image =
00110             "               T~~\n"
00111             "               |\n"
00112             "              /^\\\n"
00113             "             /   \\\n"
00114             " _   _   _  /     \\  _   _   _\n"
00115             "[ ]_[ ]_[ ]/ _   _ \\[ ]_[ ]_[ ]\n"
00116             "|_=__-_ =_|_[ ]_[ ]_|_=-___-__|\n"
00117             " | _- =  | =_ = _    |= _=   |\n"
00118             " |= -[]  |- = _ =    |_-=_[] |\n"
00119             " | =_    |= - ___    | =_ =  |\n"
00120             " |=  []- |-  /| |\\   |=_ =[] |\n"
00121             " |- =_   | =| | | |  |- = -  |\n"
00122             " |_______|__|_|_|_|__|_______|\n";
00123 
00124 
00125     QString castle_mask =
00126         "                RR\n"
00127         "\n"
00128         "              yyy\n"
00129         "             y   y\n"
00130         "            y     y\n"
00131         "           y       y\n"
00132         "\n"
00133         "\n"
00134         "\n"
00135         "              yyy\n"
00136         "             yy yy\n"
00137         "            y y y y\n"
00138         "            yyyyyyy\n";
00139 
00140     Frame f(castle_image, castle_mask, 0x686868/* XXX: why grey? */ );
00141 
00142     Sprite* castle = new Sprite(screen,
00143         screen->width() - 32, screen->height() - 13, 22);
00144     castle->addFrame(f);
00145     screen->addSprite(castle);
00146 }
00147 
00148 void AASaver::addEnvironment()
00149 {
00150     QString water_line_segment[] = {
00151         "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~",
00152         "^^^^ ^^^  ^^^   ^^^    ^^^^      ",
00153         "^^^^      ^^^^     ^^^    ^^     ",
00154         "^^      ^^^^      ^^^    ^^^^^^  "
00155     };
00156 
00157     // tile the segments so they stretch across the screen
00158     int segment_size   = water_line_segment[0].length();
00159     int segment_repeat = int(screen->width()/segment_size) + 1;
00160 
00161     for (unsigned i = 0; i < ARRAY_SIZE(water_line_segment); ++i) {
00162         //do the tiling
00163         QString out;
00164         for (int r = 0; r < segment_repeat; ++r)
00165             out += water_line_segment[i];
00166 
00167         //create a sprite.
00168         Sprite* s = new Sprite(screen, 0, i + 5, 22);
00169         s->addFrame(Frame(out, QString(), 0x149494));
00170         screen->addSprite(s);
00171     }
00172 }
00173 
00174 void AASaver::addAllSeaweed()
00175 {
00176     // figure out how many seaweed to add by the width of the screen
00177     int seaweed_count = int(screen->width() / 15.0);
00178     for (int i = 1; i <= seaweed_count; ++i)
00179         addSeaweed(screen);
00180 }
00181 
00186 class Seaweed: public Sprite
00187 {
00188     int m_ticks; 
00189     int m_lifeTimeMS; 
00190     static QList<int> m_positions;
00191 
00192 public:
00202     Seaweed(Screen* s, int x, int y, int life): Sprite(s, x, y, 21),
00203         m_ticks(0), m_lifeTimeMS(life)
00204     {
00205         m_positions.append(x);
00206     }
00207 
00208     ~Seaweed()
00209     {
00210         m_positions.removeAll(m_x);
00211     }
00212 
00213     static bool isTooClose(int newX)
00214     {
00215         foreach(int i, m_positions) {
00216             if(qAbs(i - newX) < 3)
00217                 return true;
00218         }
00219 
00220         return false;
00221     }
00222 
00227     virtual bool tickUpdate()
00228     {
00229         ++m_ticks;
00230         if (m_ticks * m_screen->msPerTick() > m_lifeTimeMS)
00231         {
00232             erase();
00233             kill();
00234             AASaver::instance()->addSeaweed(m_screen);
00235         }
00236 
00237         return Sprite::tickUpdate();
00238     }
00239 };
00240 
00241 QList<int> Seaweed::m_positions;
00242 
00243 void AASaver::addSeaweed(Screen* screen)
00244 {
00245     QString seaweed_image[] = {"", ""};
00246     int height = m_randomSequence.getLong(5) + 3;
00247     for (int i = 1; i <= height; ++i)
00248     {
00249         int left_side  = i % 2;
00250         int right_side = !left_side;
00251         seaweed_image[left_side]  += "(\n";
00252         seaweed_image[right_side] += " )\n";
00253     }
00254 
00255     int x = m_randomSequence.getLong(screen->width() - 2) + 1;
00256     int y = screen->height() - height;
00257 
00258     // Keep guessing random numbers until the seaweed isn't too
00259     // bunched up.
00260     while(Seaweed::isTooClose(x))
00261         x = m_randomSequence.getLong(screen->width() - 2) + 1;
00262 
00263     Seaweed* s = new Seaweed(screen, x, y,
00264         m_randomSequence.getLong(4*60000) + (8*60000)); // seaweed lives for 8 to 12 minutes
00265     s->addFrame(Frame(seaweed_image[0], QString(), 0x18AF18));
00266     s->addFrame(Frame(seaweed_image[1], QString(), 0x18AF18));
00267     s->setFrameDelay(m_randomSequence.getLong(50) + 250);
00268     screen->addSprite(s);
00269 }
00270 
00275 class AirBubble : public Sprite
00276 {
00277     const int m_startY; 
00278 
00279 public:
00289     AirBubble(Screen *screen, int x, int y, int z) :
00290         Sprite(screen, x, y, z), m_startY(y)
00291     {
00292         addFrame(Frame(".", QString(), 0x18B2B2));
00293         addFrame(Frame("o", QString(), 0x18B2B2));
00294         addFrame(Frame("O", QString(), 0x18B2B2));
00295 
00296         setFrameDelay(100);
00297     }
00298 
00303     virtual bool tickUpdate()
00304     {
00305         if (!timerTick())
00306             return false;
00307 
00308         erase();
00309 
00310         m_currentFrame = 0;
00311         if(m_startY - m_y > 5)
00312             m_currentFrame = 1;
00313         if(m_startY - m_y > 11)
00314             m_currentFrame = 2;
00315 
00316         m_y--;
00317         if(m_y < 9)
00318             kill();
00319 
00320         return true;
00321     }
00322 };
00323 
00327 class MovingSprite: public Sprite
00328 {
00329 protected:
00330     int m_direct; 
00331     double m_speed; 
00332     double m_realX; 
00333     int m_ticksSinceLastChange; 
00334     int m_frameTime;            
00335 
00336 public:
00352     MovingSprite(Screen* screen, int direct, double speed, int x, int y, int z):
00353         Sprite(screen, x, y, z), m_direct(direct), m_speed(speed), m_realX(x),
00354         m_ticksSinceLastChange(0), m_frameTime(250)
00355     {
00356     }
00357 
00364     void setFrameTime(int milliseconds)
00365     {
00366         m_frameTime = milliseconds;
00367     }
00368 
00370     int frameTime() const { return m_frameTime; }
00371 
00373     int direction() const
00374     {
00375         return m_direct;
00376     }
00377 
00379     double realSpeed() const
00380     {
00381         return m_speed;
00382     }
00383 
00385     double realX() const
00386     {
00387         return m_realX;
00388     }
00389 
00395     virtual bool tickUpdate()
00396     {
00397         if (!timerTick())
00398             return false;
00399 
00400         erase();
00401         m_realX += (m_direct * m_speed);
00402         m_x = (int) m_realX;
00403 
00404         ++m_ticksSinceLastChange;
00405         if(m_ticksSinceLastChange * m_screen->msPerTick() > m_frameTime)
00406         {
00407             m_ticksSinceLastChange = 0;
00408 
00409             ++m_currentFrame;
00410             if(m_currentFrame == m_frames.size())
00411                 m_currentFrame = 0;
00412         }
00413 
00414         if((m_x + m_frames[m_currentFrame].width() < 0) || (m_x > m_screen->width()))
00415             kill();
00416 
00417         return true;
00418     }
00419 };
00420 
00425 class RandomMovingSprite : public MovingSprite
00426 {
00427 public:
00428     RandomMovingSprite(Screen *screen, int direct, double speed, int x, int y, int z):
00429         MovingSprite(screen, direct, speed, x, y, z)
00430     {
00431     }
00432 
00434     virtual void kill()
00435     {
00436         MovingSprite::kill();
00437         AASaver::instance()->addRandom(m_screen);
00438     }
00439 };
00440 
00445 class FishSprite : public MovingSprite
00446 {
00447     double m_spacesPerBubble;   
00448     double m_lastBubbleRelease; 
00449 
00450 public:
00451     FishSprite(Screen* screen, int direct, double speed, int x, int y, int z):
00452         MovingSprite(screen, direct, speed, x, y, z), m_lastBubbleRelease(x)
00453     {
00454         m_spacesPerBubble = AASaver::instance()->doubleRand(screen->width()) + 12.0;
00455     }
00456 
00458     virtual void kill()
00459     {
00460         MovingSprite::kill();
00461         AASaver::instance()->addFish(m_screen);
00462     }
00463 
00468     virtual bool tickUpdate()
00469     {
00470         if(!MovingSprite::tickUpdate())
00471             return false;
00472 
00473         if(isKilled())
00474             return true;
00475 
00476         if(qAbs(realX() - m_lastBubbleRelease) >= m_spacesPerBubble)
00477         {
00478             m_lastBubbleRelease = realX();
00479 
00480             int bubbleX = m_x;
00481             QRect geometry = geom();
00482 
00483             if(m_direct > 0) // Moving right
00484                 bubbleX += geometry.width();
00485 
00486             AASaver::instance()->addBubble(m_screen, bubbleX,
00487                 m_y + geometry.height() / 2 - 1, m_z - 1);
00488         }
00489 
00490         return true;
00491     }
00492 };
00493 
00494 void AASaver::addAllFish()
00495 {
00496     // Determine how many logical pixels we are dealing with, and find out how
00497     // many we'd be dealing with in full screen, and then scale the user's
00498     // number down to adjust so that we look about the same in a window as we
00499     // do fullscreen. TODO: Xinerama issues?
00500     QRect fullScreenGeometry(QApplication::desktop()->screenGeometry());
00501 
00502     int full_width = fullScreenGeometry.width() / screen->cellWidth();
00503     int full_height = fullScreenGeometry.height() / screen->cellHeight() - 9;
00504     int full_size = full_width * full_height;
00505     int screen_size = (screen->height() - 9) * screen->width();
00506 
00507     int fish_count = AASaverConfig::fishCount() * screen_size / full_size;
00508     if(fish_count < 5)
00509         fish_count = 5;
00510 
00511     for (int i = 1; i <= fish_count; ++ i)
00512         addFish(screen);
00513 }
00514 
00515 Sprite *AASaver::newFish(Screen *screen)
00516 {
00517     QString fish_image[] = {
00518 "       \\\n"
00519 "     ...\\..,\n"
00520 "\\" "{}" "/'       \\\n" // trigraphs suck
00521 " >=     (  ' >\n"
00522 "/{}\\      / /\n"
00523 "    `\"'\"'/''\n",
00524 
00525 "       2\n"
00526 "     1112111\n"
00527 "6  11       1\n"
00528 " 66     7  4 5\n"
00529 "6  1      3 1\n"
00530 "    11111311\n",
00531 
00533 "      /\n"
00534 "  ,../...\n"
00535 " /       '\\" "{}" "/\n" // trigraphs suck
00536 "< '  )     =<\n"
00537 " \\ \\      /{}\\\n"
00538 "  `'\\'\"'\"'\n",
00539 
00540 "      2\n"
00541 "  1112111\n"
00542 " 1       11  6\n"
00543 "5 4  7     66\n"
00544 " 1 3      1  6\n"
00545 "  11311111\n",
00547 "    \\\n"
00548 "\\?/--\\\n"
00549 ">=  (o>\n"
00550 "/?\\__/\n"
00551 "    /\n",
00552 
00553 "    2\n"
00554 "6 1111\n"
00555 "66  745\n"
00556 "6 1111\n"
00557 "    3\n",
00558 
00560 "  /\n"
00561 " /--\\?/\n"
00562 "<o)  =<\n"
00563 " \\__/?\\\n"
00564 "  \\\n",
00565 
00566 "  2\n"
00567 " 1111 6\n"
00568 "547  66\n"
00569 " 1111 6\n"
00570 "  3\n",
00571 
00573 "       \\:.\n"
00574 "\\;,{}?,;\\\\\\\\\\,,\n"
00575 "  \\\\\\\\\\;;:::::o\n"
00576 "  ///;;::::::::<\n"
00577 " /;`?``/////``\n",
00578 
00579 "       222\n"
00580 "666   1122211\n"
00581 "  6661111111114\n"
00582 "  66611111111115\n"
00583 " 666 113333311\n",
00584 
00586 "      .:/\n"
00587 "   ,,///;,{}?,;/\n"
00588 " o:::::::;;///\n"
00589 ">::::::::;;\\\\\\\n"
00590 "  ''\\\\\\\\\\''?';\\\n",
00591 
00592 "      222\n"
00593 "   1122211   666\n"
00594 " 4111111111666\n"
00595 "51111111111666\n"
00596 "  113333311 666\n",
00597 
00599 "  __\n"
00600 "><_'>\n"
00601 "   '\n",
00602 
00603 "  11\n"
00604 "61145\n"
00605 "   3\n",
00606 
00608 " __\n"
00609 "<'_><\n"
00610 " `\n",
00611 
00612 " 11\n"
00613 "54116\n"
00614 " 3\n",
00615 
00617 "   ..\\,\n"
00618 ">='   ('>\n"
00619 "  '''/''\n",
00620 
00621 "   1121\n"
00622 "661   745\n"
00623 "  111311\n",
00624 
00626 "  ,/..\n"
00627 "<')   `=<\n"
00628 " ``\\```\n",
00629 
00630 "  1211\n"
00631 "547   166\n"
00632 " 113111\n",
00633 
00635 "   \\\n"
00636 "  / \\\n"
00637 ">=_('>\n"
00638 "  \\_/\n"
00639 "   /\n",
00640 
00641 "   2\n"
00642 "  1 1\n"
00643 "661745\n"
00644 "  111\n"
00645 "   3\n",
00646 
00648 "  /\n"
00649 " / \\\n"
00650 "<')_=<\n"
00651 " \\_/\n"
00652 "  \\\n",
00653 
00654 "  2\n"
00655 " 1 1\n"
00656 "547166\n"
00657 " 111\n"
00658 "  3\n",
00659 
00661 "  ,\\\n"
00662 ">=('>\n"
00663 "  '/\n",
00664 
00665 "  12\n"
00666 "66745\n"
00667 "  13\n",
00668 
00670 " /,\n"
00671 "<')=<\n"
00672 " \\`\n",
00673 
00674 " 21\n"
00675 "54766\n"
00676 " 31\n",
00677 
00679 "  __\n"
00680 "\\/ o\\\n"
00681 "/\\__/\n",
00682 
00683 "  11\n"
00684 "61 41\n"
00685 "61111\n",
00686 
00688 " __\n"
00689 "/o \\/\n"
00690 "\\__/\\\n",
00691 
00692 " 11\n"
00693 "14 16\n"
00694 "11116\n"
00695 };
00696 
00697     // # 1: body
00698     // # 2: dorsal fin
00699     // # 3: flippers
00700     // # 4: eye
00701     // # 5: mouth
00702     // # 6: tailfin
00703     // # 7: gills*
00704     int fish_num   = m_randomSequence.getLong(ARRAY_SIZE(fish_image)/2);
00705     int fish_index = fish_num * 2;
00706 
00707     double speed = doubleRand(2) + 0.25;
00708     int depth = 3 + m_randomSequence.getLong(18);
00709 
00710     QString color_mask = fish_image[fish_index+1];
00711     color_mask.replace('4', 'W');
00712 
00713     color_mask = randColor(color_mask);
00714 
00715     Frame fishFrame(fish_image[fish_index], color_mask, 0);
00716     int max_height = 9;
00717     int min_height = screen->height() - fishFrame.height();
00718 
00719     int x, y, dir;
00720     y = max_height + m_randomSequence.getLong(min_height - max_height);
00721     if (fish_num % 2)
00722     {
00723         x   = screen->width() - 2;
00724         dir = -1;
00725     }
00726     else
00727     {
00728         x   = 1 - fishFrame.width();
00729         dir = 1;
00730     }
00731 
00732     Sprite* fish = new FishSprite(screen, dir, speed, x, y, depth);
00733     fish->addFrame(fishFrame);
00734 
00735     return fish;
00736 }
00737 
00738 void AASaver::addFish(Screen* screen)
00739 {
00740     screen->addSprite(newFish(screen));
00741 }
00742 
00746 class Splat : public Sprite
00747 {
00748 public:
00756     Splat(Screen *screen, QPoint center, int depth) :
00757         Sprite(screen, 0, 0, depth, 450 /* frame Delay */)
00758     {
00759         QString splats[] = {
00760 "\n"
00761 "   .\n"
00762 "  ***\n"
00763 "   '\n"
00764 ""
00765 ,
00766 
00767 "\n"
00768 " \",*;`\n"
00769 " \"*,**\n"
00770 " *\"'~'\n"
00771 ""
00772 ,
00773 "  , ,\n"
00774 " \" \",\"'\n"
00775 " *\" *'\"\n"
00776 "  \" ; .\n"
00777 ""
00778 ,
00779 "* ' , ' `\n"
00780 "' ` * . '\n"
00781 " ' `' \",'\n"
00782 "* ' \" * .\n"
00783 "\" * ', '"
00784         };
00785 
00786         for(unsigned i = 0; i < ARRAY_SIZE(splats); ++i)
00787             addFrame(Frame(splats[i], QString(), 0xB21818, ' '));
00788 
00789         QRect r(center, QSize(9, 5));
00790         r.moveCenter(center);
00791         m_x = r.x();
00792         m_y = r.y();
00793 
00794         setDieAfterLastFrame(true);
00795     }
00796 };
00797 
00802 class TeethSprite : public MovingSprite
00803 {
00804 public:
00810     TeethSprite(MovingSprite *shark) : MovingSprite(shark->screen(), shark->direction(),
00811             shark->realSpeed(), 2 + shark->geom().left(), shark->geom().top(), shark->depth())
00812     {
00813         m_y += 7;
00814         m_z -= 1;
00815         m_realX = 2 + shark->realX();
00816 
00817         if(m_direct > 0) // Moving to right.
00818             m_realX = -10;
00819 
00820         addFrame(Frame("{}{}{}{}", QString(), 0));
00821     }
00822 
00824     bool canCollide() const { return true; }
00825 
00833     void collision(Sprite *sprite)
00834     {
00835         if(dynamic_cast<FishSprite *>(sprite)) {
00836             sprite->erase();
00837             sprite->kill();
00838 
00839             screen()->addSprite(new Splat(screen(), sprite->geom().center(), depth() - 1));
00840         }
00841     }
00842 };
00843 
00844 void AASaver::addShark(Screen* screen)
00845 {
00846     QString shark_image[] = {
00847 "                              __\n"
00848 "                             ( `\\\n"
00849 "  ,{}{}{}{}{}{}{}{}{}{}{}{}{}" ")   `\\\n" // trigraphs suck
00850 ";' `.{}{}{}{}{}{}{}{}{}{}{}{}" "(     `\\__\n" // trigraphs suck
00851 " ;   `.{}{}{}{}{}{}?__..---''          `~~~~-._\n"
00852 "  `.   `.____...--''                       (b  `--._\n"
00853 "    >                     _.-'      .((      ._     )\n"
00854 "  .`.-`--...__         .-'     -.___.....-(|/|/|/|/'\n"
00855 " ;.'{}{}{}{}?`. ...----`.___.',,,_______......---'\n"
00856 " '{}{}{}{}{}?" "'-'\n", // trigraphs suck
00857 
00858 "                                                     \n"
00859 "                                                     \n"
00860 "                                                     \n"
00861 "                                                     \n"
00862 "                                                     \n"
00863 "                                           cR        \n"
00864 "                                                     \n"
00865 "                                          cWWWWWWWW  \n"
00866 "                                                     \n"
00867 "                                                     \n",
00868 
00869 "                     __\n"
00870 "                    /' )\n"
00871 "                  /'   ({}{}{}{}{}{}{}{}{}{}{}{}{},\n"
00872 "              __/'     ){}{}{}{}{}{}{}{}{}{}{}{}.' `;\n"
00873 "      _.-~~~~'          ``---..__{}{}{}{}{}{}?.'   ;\n"
00874 " _.--'  b)                       ``--...____.'   .'\n"
00875 "(     _.      )).      `-._                     <\n"
00876 " `\\|\\|\\|\\|)-.....___.-     `-.         __...--'-.'.\n"
00877 "   `---......_______,,,`.___.'----... .'{}{}{}{}?`.;\n"
00878 "                                     `-`{}{}{}{}{}?`\n",
00879 
00880 "                                                     \n"
00881 "                                                     \n"
00882 "                                                     \n"
00883 "                                                     \n"
00884 "                                                     \n"
00885 "        Rc                                           \n"
00886 "                                                     \n"
00887 "  WWWWWWWWc                                          \n"
00888 "                                                     \n"
00889 "                                                     \n"
00890     };
00891 
00892     int shark_num   = m_randomSequence.getLong(ARRAY_SIZE(shark_image)/2);
00893     int shark_index = shark_num * 2;
00894     QString color_mask = randColor(shark_image[shark_index+1]);
00895     Frame sharkFrame(shark_image[shark_index], color_mask, 0x18B2B2);
00896 
00897     int x = -53;
00898     int y = 9 + m_randomSequence.getLong(screen->height() - (10 + 9));
00899     int dir = (shark_num % 2) ? -1 : 1;
00900 
00901     if(dir < 0)
00902         x = screen->width() - 2;
00903 
00904     RandomMovingSprite* shark = new RandomMovingSprite(screen, dir, 2, x, y, 2 /* Always at 2 */);
00905     shark->addFrame(sharkFrame);
00906     screen->addSprite(shark);
00907 
00908     TeethSprite *teeth = new TeethSprite(shark);
00909     screen->addSprite(teeth);
00910 }
00911 
00912 void AASaver::addBubble(Screen *screen, int x, int y, int z)
00913 {
00914     screen->addSprite(new AirBubble(screen, x, y, z));
00915 }
00916 
00917 void AASaver::addShip(Screen* screen)
00918 {
00919     QString ship_image[] = {
00920 "     |    |    |\n"
00921 "    )_)  )_)  )_)\n"
00922 "   )___))___))___)\\\n"
00923 "  )____)____)_____)\\\\\n"
00924 "_____|____|____|____\\\\\\__\n"
00925 "\\                   /",
00926 
00927 "     y    y    y\n"
00928 "                 \n"
00929 "                  w\n"
00930 "                   ww\n"
00931 "yyyyyyyyyyyyyyyyyyyywwwyy\n"
00932 "y                   y",
00933 
00934 "         |    |    |\n"
00935 "        (_(  (_(  (_(\n"
00936 "      /(___((___((___(\n"
00937 "    //(_____(____(____(\n"
00938 "__///____|____|____|_____\n"
00939 "    \\                   /",
00940 
00941 "         y    y    y\n"
00942 "                 \n"
00943 "      w            \n"
00944 "    ww               \n"
00945 "yywwwyyyyyyyyyyyyyyyyyyyy\n"
00946 "    y                   y"
00947     };
00948 
00949     int ship_num = m_randomSequence.getLong(17) % 2; // right == 0, left == 1
00950     int x = -24, dir = 1;
00951 
00952     if(ship_num == 1) {
00953         x = screen->width() - 2;
00954         dir = -1;
00955     }
00956 
00957     RandomMovingSprite *ship = new RandomMovingSprite(screen, dir, 1.0, x, 0, 2);
00958     ship->addFrame(Frame(ship_image[2 * ship_num], ship_image[2 * ship_num + 1], 0xFFFFFF));
00959     screen->addSprite(ship);
00960 }
00961 
00962 void AASaver::addWhale(Screen* screen)
00963 {
00964     QString whale_image[] = {
00965 "        .-----:\n"
00966 "      .'       `.\n"
00967 ",{}{}/       (o) \\\n"
00968 "\\`._/          ,__)",
00969 
00970 "             C C\n"
00971 "           CCCCCCC\n"
00972 "           C  C  C\n"
00973 "        BBBBBBB\n"
00974 "      BB       BB\n"
00975 "B    B       BWB B\n"
00976 "BBBBB          BBBB",
00977 
00978 "    :-----.\n"
00979 "  .'       `.\n"
00980 " / (o)       \\{}{},\n"
00981 "(__,          \\_.'/",
00982 
00983 "   C C\n"
00984 " CCCCCCC\n"
00985 " C  C  C\n"
00986 "    BBBBBBB\n"
00987 "  BB       BB\n"
00988 " B BWB       B    B\n"
00989 "BBBB          BBBBB"
00990     };
00991 
00992     QString spouty[] = {
00993 "\n"
00994 "\n"
00995 "   :",
00996 
00997 "\n"
00998 "   :\n"
00999 "   :",
01000 
01001 "  . .\n"
01002 "  -:-\n"
01003 "   :",
01004 
01005 "  . .\n"
01006 " .-:-.\n"
01007 "   :",
01008 
01009 "  . .\n"
01010 "'.-:-.`\n"
01011 "'  :  '",
01012 
01013 "\n"
01014 " .- -.\n"
01015 ";  :  ;",
01016 
01017 "\n"
01018 "\n"
01019 ";     ;"
01020     };
01021 
01022     int whale_num = m_randomSequence.getLong(2); // 0 = right, 1 = left
01023     int x = -18, spout_align = 11, dir = 1;
01024 
01025     if (whale_num == 1)
01026     {
01027         x = screen->width() - 2;
01028         spout_align = 1; // Waterspout closer to left side now.
01029         dir = -1;
01030     }
01031 
01032     QString mask = whale_image[2 * whale_num + 1];
01033 
01034     RandomMovingSprite *whale = new RandomMovingSprite(screen, dir, 1.0, x, 0, 2);
01035     whale->setFrameDelay(80);
01036     whale->setFrameTime(40);
01037 
01038     // We have to add some frames now.  The first five will have no water spout.
01039     QString blankWhaleFrame = QString("\n\n\n") + whale_image[2 * whale_num];
01040 
01041     for(unsigned i = 0; i < 5; ++i)
01042         whale->addFrame(Frame(blankWhaleFrame, mask, 0xFFFFFF));
01043 
01044     // Now add frames for the animated water spout.
01045     QString whaleFrame = whale_image[2 * whale_num];
01046     for (unsigned i = 0; i < ARRAY_SIZE(spouty); ++i)
01047     {
01048         QStringList spoutLines = spouty[i].split('\n');
01049         QString spout;
01050         QString padding;
01051 
01052         padding.fill(' ', spout_align);
01053 
01054         // Move spout over an appropriate distance to line up right.
01055         foreach(const QString &spoutLine, spoutLines) {
01056             spout += padding;
01057             spout += spoutLine;
01058             spout += '\n';
01059         }
01060 
01061         // Add spout to whale frame.
01062         whale->addFrame(Frame(spout + whaleFrame, mask, 0xFFFFFF));
01063     }
01064 
01065     screen->addSprite(whale);
01066 }
01067 
01068 void AASaver::addBigFish(Screen* screen)
01069 {
01070     QString big_fish_image[] = {
01071 " ______\n"
01072 "`\"\"-.  `````-----.....__\n"
01073 "     `.  .      .       `-.\n"
01074 "       :     .     .       `.\n"
01075 " ,{}{}?:   .    .          _ :\n"
01076 ": `.{}?:                  (@) `._\n"
01077 " `. `..'     .     =`-.       .__)\n"
01078 "   ;     .        =  ~  :     .-\"\n"
01079 " .' .'`.   .    .  =.-'  `._ .'\n"
01080 ": .'{}?:               .   .'\n"
01081 " '{}?.'  .    .     .   .-'\n"
01082 "   .'____....----''.'=.'\n"
01083 "   \"\"{}{}{}{}{}{}?.'.'\n"
01084 "               ''\"'`",
01085 
01086 " 111111\n"
01087 "11111  11111111111111111\n"
01088 "     11  2      2       111\n"
01089 "       1     2     2       11\n"
01090 " 1     1   2    2          1 1\n"
01091 "1 11   1                  1W1 111\n"
01092 " 11 1111     2     1111       1111\n"
01093 "   1     2        1  1  1     111\n"
01094 " 11 1111   2    2  1111  111 11\n"
01095 "1 11   1               2   11\n"
01096 " 1   11  2    2     2   111\n"
01097 "   111111111111111111111\n"
01098 "   11             1111\n"
01099 "               11111",
01100 
01101 "                           ______\n"
01102 "          __.....-----'''''  .-\"\"'\n"
01103 "       .-'       .      .  .'\n"
01104 "     .'       .     .     :\n"
01105 "    : _          .    .   :{}{}?,\n"
01106 " _.' (@)                  :{}?.' :\n"
01107 "(__.       .-'=     .     `..' .'\n"
01108 " \"-.     :  ~  =        .     ;\n"
01109 "   `. _.'  `-.=  .    .   .'`. `.\n"
01110 "     `.   .               :{}?`. :\n"
01111 "       `-.   .     .    .  `.{}?`\n"
01112 "          `.=`.``----....____`.\n"
01113 "            `.`.{}{}{}{}{}{}?\"\"\n"
01114 "              '`\"``",
01115 
01116 "                           111111\n"
01117 "          11111111111111111  11111\n"
01118 "       111       2      2  11\n"
01119 "     11       2     2     1\n"
01120 "    1 1          2    2   1     1\n"
01121 " 111 1W1                  1   11 1\n"
01122 "1111       1111     2     1111 11\n"
01123 " 111     1  1  1        2     1\n"
01124 "   11 111  1111  2    2   1111 11\n"
01125 "     11   2               1   11 1\n"
01126 "       111   2     2    2  11   1\n"
01127 "          111111111111111111111\n"
01128 "            1111             11\n"
01129 "              11111"
01130     };
01131 
01132     int big_fish_num = m_randomSequence.getLong(2); // right = 0, left = 1
01133 
01134     int maxHeight = 9, minHeight = screen->height() - 15;
01135     int y = m_randomSequence.getLong(minHeight - maxHeight) + maxHeight;
01136     int x = -34, dir = 1;
01137 
01138     if(big_fish_num == 1)
01139     {
01140         x = screen->width() - 1;
01141         dir = -1;
01142     }
01143 
01144     QString colors = randColor(big_fish_image[2 * big_fish_num + 1]);
01145     RandomMovingSprite *bigFish = new RandomMovingSprite(screen, dir, 3.0, x, y, 2);
01146     bigFish->addFrame(Frame(big_fish_image[2 * big_fish_num], colors, 0xFFFF54));
01147 
01148     screen->addSprite(bigFish);
01149 }
01150 
01151 void AASaver::addNessie(Screen* screen)
01152 {
01153     QString nessie_image[] = {
01154 "                                                          ____\n"
01155 "            __{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}/   o  \\\n"
01156 "          /    \\{}{}{}{}_{}{}{}{}{}{}{}{}{}{}?_{}{}{}?/     ____ >\n"
01157 "  _{}{}{}|  __  |{}{}?/   \\{}{}{}{}_{}{}{}{}/   \\{}{}|     |\n"
01158 " | \\{}{}?|  ||  |{}{}|     |{}{}?/   \\{}{}?|     |{}?|     |",
01159 
01160 "                                                          ____\n"
01161 "                                             __{}{}{}{}?/   o  \\\n"
01162 "             _{}{}{}{}{}{}{}{}{}{}?_{}{}{}?/    \\{}{}?/     ____ >\n"
01163 "   _{}{}{}?/   \\{}{}{}{}_{}{}{}{}/   \\{}{}|  __  |{}?|     |\n"
01164 "  | \\{}{}?|     |{}{}?/   \\{}{}?|     |{}?|  ||  |{}?|     |\n",
01165 
01166 "                                                          ____\n"
01167 "                                  __{}{}{}{}{}{}{}{}{}{}/   o  \\\n"
01168 " _{}{}{}{}{}{}{}{}{}{}{}_{}{}{}?/    \\{}{}{}{}_{}{}{}?/     ____ >\n"
01169 "| \\{}{}{}{}{}_{}{}{}{}/   \\{}{}|  __  |{}{}?/   \\{}{}|     |\n"
01170 " \\ \\{}{}{}?/   \\{}{}?|     |{}?|  ||  |{}{}|     |{}?|     |",
01171 
01172 "                                                          ____\n"
01173 "                       __{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}?/   o  \\\n"
01174 "  _{}{}{}{}{}_{}{}{}?/    \\{}{}{}{}_{}{}{}{}{}{}{}{}{}/     ____ >\n"
01175 " | \\{}{}{}?/   \\{}{}|  __  |{}{}?/   \\{}{}{}{}_{}{}{}|     |\n"
01176 "  \\ \\{}{}?|     |{}?|  ||  |{}{}|     |{}{}?/   \\{}{}|     |",
01177 
01178 "    ____\n"
01179 "  /  o   \\{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}__\n"
01180 "< ____     \\{}{}{}?_{}{}{}{}{}{}{}{}{}{}?_{}{}{}{}/    \\\n"
01181 "      |     |{}{}/   \\{}{}{}{}_{}{}{}{}/   \\{}{}?|  __  |{}{}{}_\n"
01182 "      |     |{}?|     |{}{}?/   \\{}{}?|     |{}{}|  ||  |{}{}?/ |",
01183 
01184 "    ____\n"
01185 "  /  o   \\{}{}{}{}?__\n"
01186 "< ____     \\{}{}?/    \\{}{}{}?_{}{}{}{}{}{}{}{}{}{}?_\n"
01187 "      |     |{}?|  __  |{}{}/   \\{}{}{}{}_{}{}{}{}/   \\{}{}{}?_\n"
01188 "      |     |{}?|  ||  |{}?|     |{}{}?/   \\{}{}?|     |{}{}?/ |",
01189 
01190 "    ____\n"
01191 "  /  o   \\{}{}{}{}{}{}{}{}{}{}__\n"
01192 "< ____     \\{}{}{}?_{}{}{}{}/    \\{}{}{}?_{}{}{}{}{}{}{}{}{}{}{}_\n"
01193 "      |     |{}{}/   \\{}{}?|  __  |{}{}/   \\{}{}{}{}_{}{}{}{}{}/ |\n"
01194 "      |     |{}?|     |{}{}|  ||  |{}?|     |{}{}?/   \\{}{}{}?/ /",
01195 
01196 "    ____\n"
01197 "  /  o   \\{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}?__\n"
01198 "< ____     \\{}{}{}{}{}{}{}{}{}_{}{}{}{}/    \\{}{}{}?_{}{}{}{}{}_\n"
01199 "      |     |{}{}{}_{}{}{}{}/   \\{}{}?|  __  |{}{}/   \\{}{}{}?/ |\n"
01200 "      |     |{}{}/   \\{}{}?|     |{}{}|  ||  |{}?|     |{}{}?/ /"
01201     };
01202 
01203     QString nessie_mask[] = {
01204 "\n"
01205 "                                                            W\n"
01206 "\n"
01207 "\n"
01208 "\n"
01209 "",
01210 
01211 "\n"
01212 "     W\n"
01213 "\n"
01214 "\n"
01215 "\n"
01216 ""
01217     };
01218 
01219     int nessie_num = m_randomSequence.getLong(2); // 0 = right, 1 = left.
01220     int x = -64, dir = 1;
01221 
01222     if(nessie_num == 1) {
01223         x = screen->width() - 2;
01224         dir = -1;
01225     }
01226 
01227     RandomMovingSprite *nessie = new RandomMovingSprite(screen, dir, 1.4, x, 2, 2);
01228     nessie->setFrameDelay(75);
01229     nessie->setFrameTime(400);
01230 
01231     for(unsigned i = 0; i < 4; ++i)
01232         nessie->addFrame(Frame(nessie_image[nessie_num * 4 + i], nessie_mask[nessie_num], 0x18B218));
01233 
01234     screen->addSprite(nessie);
01235 }
01236 
01237 void AASaver::addRandom(Screen* screen)
01238 {
01239     int choice = m_randomSequence.getLong(5);
01240 
01241     switch(choice)
01242     {
01243         case 0:
01244             addShark(screen);
01245             break;
01246         case 1:
01247             addShip(screen);
01248             break;
01249         case 2:
01250             addBigFish(screen);
01251             break;
01252         case 3:
01253             addNessie(screen);
01254             break;
01255         case 4:
01256             addWhale(screen);
01257             break;
01258     }
01259 }
01260 
01261 void AASaver::paintEvent(QPaintEvent* pe)
01262 {
01263     // Dirty region is passed instead of the entire viewport for efficiency.
01264     screen->paint(pe);
01265 }
01266 
01267 //
01268 // Implementation of the AASaverInterface
01269 //
01270 
01271 AASaverInterface::~AASaverInterface()
01272 {
01273 }
01274 
01275 KAboutData *AASaverInterface::aboutData()
01276 {
01277     return new KAboutData("kdeasciiquarium.kss", "kdeasciiquarium", ki18n("KDE Asciiquarium"), "0.4.1",
01278         ki18n("KDE Asciiquarium"));
01279 }
01280 
01281 KScreenSaver *AASaverInterface::create(WId id)
01282 {
01283     return new AASaver(id);
01284 }
01285 
01286 QDialog *AASaverInterface::setup()
01287 {
01288     KConfigDialog *dialog = KConfigDialog::exists("settings");
01289     if(dialog)
01290         return dialog;
01291 
01292     dialog = new KConfigDialog(0, "settings", AASaverConfig::self());
01293     KGlobal::locale()->insertCatalog("kdeasciiquarium");
01294     QWidget *settings = new QWidget(dialog);
01295     Ui::SettingsWidget ui;
01296     ui.setupUi(settings);
01297 
01298     dialog->addPage(settings, i18n("Asciiquarium Settings"), "preferences-desktop-screensaver");
01299 
01300     // Not much for help needed really...
01301     dialog->enableButton(KDialog::Help, false);
01302 
01303     return dialog;
01304 }
01305 
01306 int main(int argc, char **argv)
01307 {
01308     AASaverInterface kss;
01309     return kScreenSaverMain(argc, argv, kss);
01310 }
01311 
01312 // vim: set et ts=8 sw=4: