xgalaga++-0.8.4/0000755000175000017500000000000012227337317011712 5ustar marcmarcxgalaga++-0.8.4/player.xpm0000644000175000017500000000076010034600350013717 0ustar marcmarc/* XPM */ const char *const player_xpm[] = { "13 17 10 1", " c None", ". c #930700", "+ c #BB3707", "@ c #0001A2", "# c #D7D7E7", "$ c #838383", "% c #474747", "& c #AFB3D3", "* c #838FBB", "= c #0100FF", " .+. ", " .+++. ", " ++@++ ", " .+.+.+. ", " .#. ", " $ $#$ $ ", "%#% $#$ %#%", "$#$ $#$ $#$", "$#$$ $#$ $$#$", "$#$&&&#&&&$#$", "$#&$$$#$$$&#$", "$#$$%$#$%$$#$", "$#$ $#$ $#$", "%*% %#% %*%", "@=@ $ @=@", "@=@ @=@", "@=@ @=@"}; xgalaga++-0.8.4/sprites.h0000644000175000017500000000615111014750563013552 0ustar marcmarc#ifndef SPRITES_H #define SPRITES_H #include "gfxinterface.h" #include "pix.h" #include // A sprite is defined by a Pix and a position. class Sprite { const Pix * pix_; Coord pos_; public: Sprite(const Pix * pix, Coord pos); virtual ~Sprite() {} Coord Position() const { return pos_; } int Width() const { return pix_->Width(); } int Height() const { return pix_->Height(); } Coord Dim() const { return pix_->Dim(); } void Mask() const { pix_->Mask(pos_); } void Draw() const { pix_->Draw(pos_); } bool Collide(const Sprite & other) const; protected: void MoveTo(Coord to); }; // Projectile is the base class for constant speed moving objects. class Projectile : public Sprite { const Coord speed_; public: Projectile(const Pix * pix, Coord pos, Coord speed) : Sprite(pix, pos), speed_(speed) {} void Move() { MoveTo(Position() + speed_); } bool Out() const; }; // They are several bonus types, all dropping the same way. class Bonus : public Projectile { public: // To be synchronized with bonus to pix table in .cc file. enum bonus_t { none=0, extra_speed=1, extra_fire=2, extra_shield=3, extra_multi=4 }; private: const bonus_t type_; public: Bonus(Coord pos, bonus_t type); bonus_t Type() const { return type_; } }; // One trajectory is given to each Alien. The trajectory computes // Aliens positions. The position may be X-mirrored (for split convoys). // The Trajectory can build an attack. // A trajectory has 4 stages: // - an arriving stage consisting of passing through given RCoord's; // - a joining stage to join the cruising position; // - a cruising stage at position given by a changing base and a fixed delta; // - an attacking stage consisting of passing through random RCoord's. class Trajectory { public: enum stage_t { arriving, joining, cruising, attacking }; private: stage_t stage_; // current trajectory stage const RCoord * arrival_; // table of RCoord's, RCEnd terminated const bool mirrored_; // Use X-mirrored RCoord's? const Coord & base_cruise_; // Ref to var updated with cruise position const Coord delta_cruise_; // delta from base cruise postion std::vector attack_; // keep built attack trajectory std::vector::const_iterator attack_it_; // current attack pos public: Trajectory(const RCoord * arrival, bool mirrored, const Coord & base_cruise, Coord delta_cruise); stage_t Stage() const { return stage_; } Coord NextPosition(Coord from, int velocity); Coord InitPosition() const { return mirrored_ ? arrival_[0].XMirror() : arrival_[0]; } void BuildAttack(Coord from); }; // An alien vessel is displayed by a pix at a position given by its trajectory. // It can fire bullets (dropping bombs). It can collide with player bullets. class Alien : public Sprite { Trajectory trajectory_; const int speed_; public: Alien(const Pix * pix, const Trajectory & trajectory, int speed); void Move(); Coord CannonPosition() const; Trajectory::stage_t Stage() const { return trajectory_.Stage(); } void BuildAttack() { trajectory_.BuildAttack(Position()); } }; #endif xgalaga++-0.8.4/highscore.cc0000644000175000017500000000542211257750617014203 0ustar marcmarc#include "highscore.h" #include "instance.h" #include #include #include #include #include #include #include using std::string; /* * HighScores */ HighScores * HighScores::singleton_ (0); HighScores & HighScores::Instance() { if (!singleton_) { singleton_ = new HighScores; InstancesManager::Instance().Push(DestroyInstance); } return *singleton_; } void HighScores::Update() { const std::string score_file_name (Config::Instance().GetScoreFileName()); PosixBuf filebuf (score_file_name, O_RDWR | O_CREAT, 0660); if (filebuf.FD() < 0) throw std::runtime_error ("Cannot open high scores file '"+score_file_name+"'!"); if (filebuf.Lock(last_score_ != -1 ? F_WRLCK : F_RDLCK) == -1) throw std::runtime_error ("Cannot lock high scores file '"+score_file_name+"'!"); std::iostream file (&filebuf); Load(file); file.clear(); if (last_score_ != -1) { high_scores_[last_size_].insert(HighScore(last_score_)); last_score_ = -1; if (filebuf.Truncate() != 0) throw std::runtime_error ("Cannot update high scores file '"+score_file_name+"'!"); file.seekg(0); Save(file); } } const std::multiset * HighScores::Get(Coord window_size) const { const Ctn::const_iterator it (high_scores_.find(window_size)); return it == high_scores_.end() ? 0 : &(it->second); } void HighScores::Load(std::istream & scores_file) { high_scores_.clear(); int score; Coord window_size; string name; std::time_t score_date = 0; while (scores_file.peek() != EOF) { if (scores_file.peek() == 'T') { scores_file.ignore(); if (!(scores_file >> score_date >> score >> window_size.x >> window_size.y && std::getline(scores_file, name))) { break; } } else { if (!(scores_file >> score >> window_size.x >> window_size.y && std::getline(scores_file, name))) { break; } } if (!name.empty()) { name.erase(0, 1); } high_scores_[window_size].insert(HighScore(score, name, score_date)); } if (!scores_file.eof()) throw std::runtime_error ("Error while reading high scores file '"+Config::Instance().GetScoreFileName()+"'!"); } void HighScores::Save(std::ostream & scores_file) const { for (Ctn::const_iterator mapit (high_scores_.begin()); mapit != high_scores_.end(); ++mapit) { for (std::multiset::const_iterator setit (mapit->second.begin()); setit != mapit->second.end(); ++setit) { scores_file << 'T' << setit->Date() << ' ' << setit->Value() << ' ' << mapit->first.x << ' ' << mapit->first.y << ' ' << setit->Name() << '\n'; if (!scores_file.good()) { throw std::runtime_error ("Error while saving high scores file '"+Config::Instance().GetScoreFileName()+"'!"); } } } } xgalaga++-0.8.4/vectordeque.t.h0000644000175000017500000000333110013205110014623 0ustar marcmarc#ifndef VECTORDEQUE_T_H #define VECTORDEQUE_T_H #include #include // Implement a deque in a vector, so that it can be accessed // as one or two (when circular) old-style arrays. template class VectorDeque { public: typedef typename std::vector::size_type size_type; private: std::vector vec_; size_type first_, size_; public: VectorDeque() : first_(0), size_(0) {} explicit VectorDeque(size_type capacity) : vec_(capacity), first_(0), size_(0) {} size_type Capacity() const { return vec_.size(); } size_type Size() const { return size_; } T & operator[](size_type i) { return vec_[(first_ + i) % Capacity()]; } const T & operator[](size_type i) const { return vec_[(first_ + i) % Capacity()]; } T * Vector1() { return &vec_[first_]; } const T * Vector1() const { return &vec_[first_]; } size_type Vector1Size() const { return std::min(Capacity() - first_, size_); } T * Vector2() { return &vec_[0]; } const T * Vector2() const { return &vec_[0]; } size_type Vector2Size() const { return size_ - Vector1Size(); } void Push(T); void Pop(); private: void Grow(size_type add_capacity); }; template void VectorDeque::Push(T t) { if (size_ == Capacity()) Grow(Capacity() / 4 + 1); vec_[(first_ + size_) % Capacity()] = t; ++size_; } template inline void VectorDeque::Pop() { first_ = (first_ + 1) % Capacity(); --size_; } template void VectorDeque::Grow(size_type add_capacity) { vec_.resize(vec_.size() + add_capacity); if (first_ + size_ > vec_.size() - add_capacity) { std::copy(vec_.rbegin() + add_capacity, vec_.rbegin() + (vec_.size() - first_), vec_.rbegin()); first_ += add_capacity; } } #endif xgalaga++-0.8.4/alien3.xpm0000644000175000017500000000103310016155535013602 0ustar marcmarc/* XPM */ const char *const alien3_xpm[] = { "17 18 7 1", " c None", ". c #900000", "+ c #C00000", "@ c #F00000", "# c #005000", "$ c #009000", "% c #00D000", " . +@@@+ . ", " ## @+...+@ ## ", " ##$$$$%%%$$$$## ", " #$$%%%$$$%%%$$# ", "##$%$$#%%%#$$%$##", "#$$%$# #$%$$#", "#$$%$$$###$$$%$$#", "#$$%%%$$$$$%%%$$#", "#$$%$#$%%%$#$%$$#", "#$$%$##$%$##$%$$#", "#$$%$ #$%$# $%$$#", "##$%$ #$%$# $%$##", " #$%$ #$%$# $%$# ", " ##%$#$$%$$#$%## ", " #%$ $ $ $%# ", " ##$ #$%$# $## ", " #$ $# ", " # # "}; xgalaga++-0.8.4/alien14.xpm0000644000175000017500000000070110016155510013656 0ustar marcmarc/* XPM */ const char *const alien14_xpm[] = { "12 17 8 1", " c None", ". c #0000AF", "+ c #0000FF", "@ c #99953E", "# c #010000", "$ c #CFC954", "% c #FFFF00", "& c #FF0000", " .+. .+. ", ".++++@@++++.", "+++++##+++++", ".++++$$++++.", " .+++##+++. ", " .+++%%+++. ", " +++##+++ ", " +++%%+++ ", " .++@##@++. ", " .++$%%$++. ", ".+++%##%+++.", "++++$%%$++++", ".+++@##@+++.", " .+.@%%@.+. ", " @%@@%@ ", " %@&&@% ", " %&&&&% "}; xgalaga++-0.8.4/stars.cc0000644000175000017500000000442711015046501013346 0ustar marcmarc#include "stars.h" #include "config.h" #include "instance.h" #include #include #include /* * StarsFields::StarsField */ StarsFields::StarsField::StarsField(int speed) : speed_(speed) { if (speed < 1) throw std::range_error ("Illegal star speed"); // slow stars are farther => dimmer color_.red = color_.green = color_.blue = std::min(65535u, 20000u + (speed_ * speed_) * 5000); X11::Inst().AllocColorAlways(&color_); } void StarsFields::StarsField::Scroll() { static unsigned count = 0; // Scroll existing stars, destroying out of window ones. X11::Inst().SetClipMask(None); X11::Inst().SetForeground(X11::Inst().GetBlack()); DrawAll(); for (FieldCtn::size_type v = 0; v < field_.Size(); ++v) { field_[v].y += speed_; } while (field_.Size() > 0 && field_[0].YOut()) { field_.Pop(); } X11::Inst().SetForeground(color_.pixel); DrawAll(); // Create one star in an (empty) top line on pair 'count'. if (count++ & 1) { const Coord star (std::rand() % X11::Inst().WindowWidth(), std::rand() % speed_); field_.Push(star); X11::Inst().DrawPoint(star); } } void StarsFields::StarsField::DrawAll() const { if (field_.Vector1Size() > 0) { X11::Inst().DrawPoints(field_.Vector1(), field_.Vector1Size()); if (field_.Vector2Size() > 0) { X11::Inst().DrawPoints(field_.Vector2(), field_.Vector2Size()); } } } /* * StarsFields */ StarsFields * StarsFields::singleton_ (0); const int StarsFields::max_star_speed_; StarsFields & StarsFields::Instance() { if (!singleton_) { singleton_ = new StarsFields; InstancesManager::Instance().Push(DestroyInstance); } return *singleton_; } void StarsFields::DestroyInstance() { delete singleton_; singleton_ = 0; } StarsFields::StarsFields() { for (int speed (1); speed <= max_star_speed_; ++speed) { stars_fields_.push_back(new StarsField(speed)); } } StarsFields::~StarsFields() { for (Ctn::iterator it (stars_fields_.begin()); it != stars_fields_.end(); ++it) { delete *it; } } void StarsFields::Scroll() { int nb (Config::Instance().ScaleDetails(max_star_speed_)); for (Ctn::iterator it (stars_fields_.begin()); it != stars_fields_.end() && nb > 0; ++it, --nb) { (*it)->Scroll(); } } xgalaga++-0.8.4/alien6.xpm0000644000175000017500000000071510016155565013616 0ustar marcmarc/* XPM */ const char *const alien6_xpm[] = { "16 15 7 1", " c None", ". c #99953E", "+ c #FFFF00", "@ c #BCBCBC", "# c #FFFFFF", "$ c #A80000", "% c #FF0000", " .. .. ", " .++. .++. ", ".++++. .++++.", ".++++. .++++.", " .+++@ @+++. ", " ..@#@ @#@.. ", " @#@@#@ ", " @##@ ", " @@ ", " $$ ", " $%%$ ", " $%%%%$ ", " $%%%%$ ", " $%%$ ", " $$ "}; xgalaga++-0.8.4/alien5.xpm0000644000175000017500000000074210016155545013613 0ustar marcmarc/* XPM */ const char *const alien5_xpm[] = { "16 13 11 1", " c None", ". c #C1C1C1", "+ c #B0B0B0", "@ c #00FF00", "# c #909090", "$ c #A1A1A1", "% c #C15F5F", "& c #E16F6F", "* c #7F503F", "= c #A19050", "- c #FF0000", ". .", ". ++ .", "@ #$..$# @", "@% #++&&++# %@", "@*&#$++**++$#&*@", "@+=%&+*==*+&%=+@", "@+*=%*=&&=*%=*+@", ". $*=%%==%%=*$ .", "+ #*==&&==*# +", "# $+*%%*+$ #", " #*%--%*# ", " =* *= ", " % % "}; xgalaga++-0.8.4/stars.h0000644000175000017500000000162210022670315013205 0ustar marcmarc#ifndef STARS_H #define STARS_H #include "gfxinterface.h" #include "vectordeque.t.h" #include class StarsFields { // A stars field contains stars scrolling together at a given speed, // all the same color (computed from speed). class StarsField { typedef VectorDeque FieldCtn; FieldCtn field_; int speed_; XColor color_; StarsField(const StarsField&); // no copy StarsField & operator=(const StarsField&); // no copy public: StarsField(int speed); void Scroll(); private: void DrawAll() const; }; static StarsFields * singleton_; static const int max_star_speed_ = 3; typedef std::list Ctn; Ctn stars_fields_; StarsFields(); ~StarsFields(); StarsFields(const StarsFields&); // no copy StarsFields & operator=(const StarsFields&); // no copy public: static StarsFields & Instance(); static void DestroyInstance(); void Scroll(); }; #endif xgalaga++-0.8.4/score.h0000644000175000017500000000156310022671426013174 0ustar marcmarc#ifndef SCORE_H #define SCORE_H #include "gfxinterface.h" #include class Score { static Score * singleton_; int score_; int shield_; int level_; Coord pos_; XFontStruct * font_; XColor color_; std::string old_text_; Score(); ~Score(); public: static Score & Instance(); static void DestroyInstance(); int Value() const { return score_; } void Add(int i) { score_ += i; } void IncLevel() { ++level_; } void SetShield(int i) { shield_ = i; } void ReInit() { score_ = 0; level_ = 1; } void Refresh() { Mask(); Draw(); } int Level() const { return level_; } void ShowLevel() const { DrawLevel(color_.pixel); } void EraseLevel() const { DrawLevel(X11::Inst().GetBlack()); } int Height() const { return font_->descent + font_->ascent; } private: void Draw(); void DrawLevel(X11::Color) const; void Mask() const; int PosY() const; }; #endif xgalaga++-0.8.4/bomb.xpm0000644000175000017500000000023510016155630013345 0ustar marcmarc/* XPM */ const char *const bomb_xpm[] = { "5 5 4 1", " c None", ". c #955500", "+ c #FFC800", "@ c #FFD4B5", " . ", " .+..", ".+@+.", "..+. ", " . "}; xgalaga++-0.8.4/xpms.h0000644000175000017500000000156110034604203013036 0ustar marcmarc#ifndef XPMS_H #define XPMS_H extern const char *const player_xpm[]; extern const char *const bullet_xpm[]; extern const char *const bomb_xpm[]; extern const char *const bonus_fire_xpm[]; extern const char *const bonus_shield_xpm[]; extern const char *const bonus_speed_xpm[]; extern const char *const bonus_multi_xpm[]; extern const char *const alien1_xpm[]; extern const char *const alien2_xpm[]; extern const char *const alien3_xpm[]; extern const char *const alien4_xpm[]; extern const char *const alien5_xpm[]; extern const char *const alien6_xpm[]; extern const char *const alien7_xpm[]; extern const char *const alien8_xpm[]; extern const char *const alien9_xpm[]; extern const char *const alien10_xpm[]; extern const char *const alien11_xpm[]; extern const char *const alien12_xpm[]; extern const char *const alien13_xpm[]; extern const char *const alien14_xpm[]; #endif xgalaga++-0.8.4/instance.cc0000644000175000017500000000075610022707467014033 0ustar marcmarc#include "instance.h" InstancesManager * InstancesManager::singleton_ (0); InstancesManager & InstancesManager::Instance() { if (!singleton_) singleton_ = new InstancesManager; return *singleton_; } void InstancesManager::DestroyInstance() { delete singleton_; singleton_ = 0; } InstancesManager::~InstancesManager() { while (!destroy_funcs_.empty()) { destroy_funcs_.top()(); destroy_funcs_.pop(); } } void InstancesManager::Push(void(*pf)()) { destroy_funcs_.push(pf); } xgalaga++-0.8.4/alien8.xpm0000644000175000017500000000074010016155605013611 0ustar marcmarc/* XPM */ const char *const alien8_xpm[] = { "15 16 8 1", " c None", ". c #C00000", "+ c #900000", "@ c #606000", "# c #F00000", "$ c #A0A000", "% c #F0F000", "& c #0000F0", " . +@+ . ", ".#. +.$.+ .#.", ".#.++.#%#.++.#.", "+$%$.##%##.$%$+", " $%$. .$%$ ", " $%$$ $$%$ ", " $%$%$%$ ", " $%%%$ ", " $%$ ", " $%$ ", " $%$ ", " $%$ ", " $%$ ", " &$& ", " &&&&& ", " &&& "}; xgalaga++-0.8.4/managers.h0000644000175000017500000000662010034604703013652 0ustar marcmarc#ifndef MANAGERS_H #define MANAGERS_H #include "constants.h" #include "explosion.h" #include "sprites.h" #include #include #include #include // An aliens convoy is defined by the vessel, the number of // vessels and the formation (that can be X-mirrored) struct ConvoyData { const int wait; const char *const *const alien_xpm; const int convoy_size_pc; const RCoord *const arrival; const bool x_mirror; const bool split; int ConvoySize() const; }; class BulletsManager { typedef std::list BulletsCtn; BulletsCtn bullets_; public: ~BulletsManager(); void Move(); void Add(const Pix * pix, Coord pos, Coord speed); int DoCollisions(const Sprite & other, int max); int Nb() const { return bullets_.size(); } }; class BonusManager { typedef std::list BonusCtn; BonusCtn bonuses_; public: ~BonusManager(); void Move(); void Add(Coord pos, Bonus::bonus_t type); Bonus::bonus_t GetBonusCollision(const Sprite & other); }; class ExplosionsManager { typedef std::list ExplosionsCtn; ExplosionsCtn explosions_; public: ~ExplosionsManager(); void Move(); void Add(Coord pos, Coord speed, XColor color, int duration = 24); }; // Aliens arrive in convoys. The AlienManager creates aliens according // to convoys data and then move and destroy them if collision. class AliensManager { static int bonus_wait_; BulletsManager *const bombs_manager_; BulletsManager *const bullets_manager_; BonusManager *const bonus_manager_; ExplosionsManager *const explosions_manager_; const int level_number_; const ConvoyData *const convoys_; const int nconvoys_; const int max_convoy_size_; int convoy_idx_; int convoy_alien_idx_; const int speed_; Coord base_cruise_; int base_cruise_speed_; enum creation_t { new_convoy, new_alien, new_attack }; creation_t next_creation_; int next_creation_wait_; typedef std::list AliensCtn; AliensCtn aliens_; public: AliensManager(BulletsManager * bombs_manager, BulletsManager * bullets_manager, BonusManager*, ExplosionsManager*, int level_number, const ConvoyData * convoysdata, int max_level); ~AliensManager(); void Move(); void Fire() const; int DoBulletsCollisions(); bool Finished() const { return next_creation_ == new_attack && aliens_.empty(); } private: int GetMaxConvoySize() const; void Creation(); void CreateBonusMaybe(Coord); }; // The player ship is displayed by a pix and moves on the bottom of the window. // It can fire bullets. It can collide with alien bullets (bombs) and bonuses. // The shield is decremented by each collision. class Player : public Sprite { Player(const Player &); // no copy Player & operator=(const Player &); // no copy BulletsManager *const bullets_manager_; BulletsManager *const bombs_manager_; BonusManager *const bonus_manager_; ExplosionsManager *const explosions_manager_; const int below_y_; int shield_; int speed_; int fire_wait_, fire_interval_; int multi_fire_; public: Player(BulletsManager * bullets_manager, BulletsManager * bombs_manager, BonusManager*, ExplosionsManager*, int below_y); void Move(int direction); void Fire(); void DoBombsCollisions(); void DoBonusCollisions(); int Shield() const { return shield_; } void ExtraFire(); void ExtraMulti(); void ExtraShield() { ++shield_; } void ExtraSpeed() { ++speed_; } private: int PosY() const; }; #endif xgalaga++-0.8.4/input.cc0000644000175000017500000000502210017223126013342 0ustar marcmarc#include "input.h" #include "gfxinterface.h" #include Input::Input() : quit_ (false) , move_ (0) , left_ (false), right_ (false), last_is_left_(false) , up_ (false), down_ (false), last_is_up_(false) , fire_ (false), firing_(false) , start_ (false) , pause_ (false) , cheat_ (false) , details_ (0) , window_size_(0) {} void Input::Update() { fire_ = false; move_ = 0; vmove_ = 0; start_ = false; cheat_ = false; highscores_ = false; details_ = 0; window_size_ = 0; while (X11::Inst().Pending()) { XEvent e; X11::Inst().NextEvent(&e); switch (e.type) { case KeyPress: switch (XLookupKeysym(&e.xkey, 0)) { case XK_Left: left_ = true; last_is_left_ = true; break; case XK_Right: right_ = true; last_is_left_ = false; break; case XK_Up: up_ = true; last_is_up_ = true; break; case XK_Down: down_ = true; last_is_up_ = false; break; case XK_space: fire_ = firing_ = true; break; default: { char c (0); XLookupString(&e.xkey, &c, 1, 0, 0); switch (c) { case '+': details_ = 1; break; case '-': details_ = -1; break; case '1': window_size_ = 1; break; case '2': window_size_ = 2; break; case '3': window_size_ = 3; break; case '4': window_size_ = 4; break; case '5': window_size_ = 5; break; case 'h': highscores_ = true; break; case 'p': pause_ = !pause_; break; case 'q': quit_ = true; return; case 's': start_ = true; return; case 'C': cheat_ = true; return; } } } break; case KeyRelease: switch (XLookupKeysym(&e.xkey, 0)) { case XK_Left: left_ = false; break; case XK_Right: right_ = false; break; case XK_Up: up_ = false; break; case XK_Down: down_ = false; break; case XK_space: firing_ = false; break; } break; } } fire_ |= firing_; if (!left_ && !right_) move_ = 0; else if ( left_ && !right_) move_ = -1; else if (!left_ && right_) move_ = 1; else if (last_is_left_) move_ = -1; else move_ = 1; if (!up_ && !down_) vmove_ = 0; else if ( up_ && !down_) vmove_ = -1; else if (!up_ && down_) vmove_ = 1; else if (last_is_up_) vmove_ = -1; else vmove_ = 1; } xgalaga++-0.8.4/highscore.h0000644000175000017500000000242411014756751014040 0ustar marcmarc#ifndef HIGH_SCORE_H #define HIGH_SCORE_H #include "config.h" #include "gfxinterface.h" #include "posix_stream.h" #include #include #include #include #include class HighScore { int score_; std::string name_; std::time_t date_; friend class HighScores; HighScore(int score, const std::string & name = Config::Instance().GetPlayerName(), std::time_t date = std::time(0)) : score_(score), name_(name), date_(date) {} public: int Value() const { return score_; } std::string Name() const { return name_; } std::time_t Date() const { return date_; } }; inline bool operator<(const HighScore & lhs, const HighScore & rhs) { return lhs.Value() < rhs.Value(); } class HighScores { static HighScores * singleton_; typedef std::map > Ctn; Ctn high_scores_; int last_score_; Coord last_size_; HighScores() : last_score_(-1) {} public: static HighScores & Instance(); static void DestroyInstance() { delete singleton_; singleton_ = 0; } void Add(int score, Coord window_size) { last_score_ = score; last_size_ = window_size; } void Update(); const std::multiset * Get(Coord window_size) const; private: void Load(std::istream &); void Save(std::ostream &) const; }; #endif xgalaga++-0.8.4/pix.cc0000644000175000017500000000351310022700164013004 0ustar marcmarc#include "pix.h" #include "instance.h" #include #include /* * Pix */ Pix::Pix(const char *const * xpm) { XpmAttributes attrs; attrs.valuemask = XpmSize | XpmExactColors | XpmCloseness; attrs.exactColors = False; attrs.closeness = 65535; const int err_code (X11::Inst().CreatePixmapFromData(xpm, &pixmap_, &shapemask_, &attrs)); if (err_code != XpmSuccess) { const std::string msg ("Pixmap creation failed: "); throw std::runtime_error (msg + XpmGetErrorString(err_code)); } dim_ = Coord(attrs.width, attrs.height); } Pix::~Pix() { X11::Inst().FreePixmap(pixmap_); X11::Inst().FreePixmap(shapemask_); } void Pix::Draw(Coord pos) const { pos -= Dim() / 2; X11::Inst().SetClipOrigin(pos); X11::Inst().SetClipMask(shapemask_); X11::Inst().CopyAreaToWindow(pixmap_, Coord(0,0), Dim(), pos); } void Pix::Mask(Coord pos) const { pos -= Dim() / 2; X11::Inst().SetClipOrigin(pos); X11::Inst().SetClipMask(shapemask_); X11::Inst().SetForeground(X11::Inst().GetBlack()); X11::Inst().FillRectangle(pos, Dim()); } void Pix::Move(Coord from, Coord to) const { if (from != to) Mask(from); Draw(to); } /* * PixKeeper */ PixKeeper * PixKeeper::singleton_ (0); PixKeeper::~PixKeeper() { for (PixCtn::const_iterator it (pixes_.begin()); it != pixes_.end(); ++it) { delete it->second; } } PixKeeper & PixKeeper::Instance() { if (!singleton_) { singleton_ = new PixKeeper; InstancesManager::Instance().Push(DestroyInstance); } return *singleton_; } void PixKeeper::DestroyInstance() { delete singleton_; singleton_ = 0; } const Pix * PixKeeper::Get(const char *const * pix_data) { const PixCtn::const_iterator it (pixes_.find(pix_data)); if (it != pixes_.end()) return it->second; const Pix *const pix (new Pix(pix_data)); pixes_.insert(PixCtn::value_type(pix_data, pix)); return pix; } xgalaga++-0.8.4/bullet.xpm0000644000175000017500000000030310016155670013715 0ustar marcmarc/* XPM */ const char *const bullet_xpm[] = { "5 7 4 1", " c None", ". c #797979797979", "X c #BCBCBCBCBCBC", "o c #FFFFFFFFFFFF", " .X. ", ".XoX.", ".XoX.", ".XoX.", " .X. ", " . ", ".XoX."}; xgalaga++-0.8.4/bonus_multi.xpm0000644000175000017500000000051110034604134014761 0ustar marcmarc/* XPM */ const char *const bonus_multi_xpm[] = { "15 10 4 1", " c None", ". c #00000000AFAF", "X c #00000000FFFF", "o c #FFFFFFFFFFFF", " ..XXX XXX.. ", " ..XXX o XXXX. ", ". XXX o XXX .", ". o XX o XX o X", ".. o X o X o XX", "... o o o XXX", ".... o o o XXXX", "..... ooo XXXX.", " ..... XXXX. ", " ........... "}; xgalaga++-0.8.4/gfxinterface.cc0000644000175000017500000001042211256504650014662 0ustar marcmarc#include "gfxinterface.h" #include "instance.h" #include #include #include #include /* * Coord */ // Implementations of conversions from pixels distances to relative distances. inline int Rel(int dist, int scale) { return (dist * RCoord::max + scale / 2) / scale; } inline int UnRel(int r, int scale) { return (r * scale + RCoord::max / 2) / RCoord::max; } Coord::Coord(RCoord rc) { x = UnRel(rc.x, X11::Inst().WindowWidth()); y = UnRel(rc.y, X11::Inst().WindowHeight()); } RCoord Coord::ToRCoord() const { return RCoord(Rel(x, X11::Inst().WindowWidth()), Rel(y, X11::Inst().WindowHeight())); } double Coord::Length() const { return std::sqrt(static_cast(x * x + y * y)); } Coord & Coord::operator*=(double rhs) { x = static_cast(std::floor(x * rhs + 0.5)); y = static_cast(std::floor(y * rhs + 0.5)); return *this; } Coord & Coord::operator/=(double rhs) { x = static_cast(std::floor(x / rhs + 0.5)); y = static_cast(std::floor(y / rhs + 0.5)); return *this; } /* * X11 */ X11 * X11::singleton_ (0); unsigned X11::default_window_width_ (640); unsigned X11::default_window_height_ (480); void X11::CreateInstance() { if (!singleton_) { singleton_ = new X11; InstancesManager::Instance().Push(DestroyInstance); } } X11::X11() : window_width_ (default_window_width_) , window_height_(default_window_height_) { display_ = XOpenDisplay(0); if (!display_) throw std::runtime_error ("Cannot open display"); screen_ = DefaultScreen(display_); visual_ = DefaultVisual(display_, screen_); colormap_ = DefaultColormap(display_, screen_); gc_ = DefaultGC(display_, screen_); const Color black (BlackPixel(display_, screen_)); window_ = XCreateSimpleWindow(display_, DefaultRootWindow(display_), 0, 0, window_width_, window_height_, 0, black, black); XSelectInput(display_, window_, StructureNotifyMask); XMapWindow(display_, window_); XEvent e; do XNextEvent(display_, &e); while (e.type != MapNotify); XSelectInput(display_, window_, KeyPressMask | KeyReleaseMask); } X11::~X11() { XDestroyWindow(display_, window_); XCloseDisplay(display_); } void X11::SetWindowTitle(const std::string & title) const { const char *const list_ptr (title.c_str()); XTextProperty property; if (XStringListToTextProperty(const_cast(&list_ptr), 1, &property)) { XSetWMName(display_, window_, &property); XFree(property.value); } // Do nothing if out of memory. } Status X11::GetWindowAttributes(XWindowAttributes * attrs) { XWindowAttributes attrs2; if (!attrs) attrs = &attrs2; const Status s (XGetWindowAttributes(display_, window_, attrs)); if (s != 0) { window_width_ = attrs->width; window_height_ = attrs->height; } return s; } void X11::ResizeWindow(unsigned width, unsigned height) { GetWindowAttributes(); if (width != window_width_ || height != window_height_) { XEvent e; XSelectInput(display_, window_, StructureNotifyMask); XResizeWindow(display_, window_, width, height); do XNextEvent(display_, &e); while (e.type != ConfigureNotify); XSelectInput(display_, window_, KeyPressMask | KeyReleaseMask); window_width_ = width; window_height_ = height; } } inline unsigned ColorDistance(const XColor & c1, const XColor & c2) { return std::abs(c1.red - c2.red ) + std::abs(c1.green - c2.green) + std::abs(c1.blue - c2.blue ); } void X11::AllocColorAlways(XColor * color) const { if (AllocColor(color)) return; std::vector colors (visual_->map_entries); for (std::vector::size_type i (0); i < colors.size(); ++i) { colors[i].pixel = i; } XQueryColors(display_, colormap_, &colors[0], colors.size()); unsigned min_dist (3*65535 + 1); std::vector::size_type best_index (0); for (std::vector::size_type i (0); i < colors.size(); ++i) { const unsigned dist (ColorDistance(colors[i], *color)); if (dist < min_dist) { min_dist = dist; best_index = i; } } // This allocation may fail because the colormap is not locked (and // X Window color management is crap). // But it looks like it is 1) rare enough 2) quite benign 3) hard to // work around, so let it silently fail. *color = colors[best_index]; AllocColor(color); } xgalaga++-0.8.4/main.cc0000644000175000017500000003267511015033355013147 0ustar marcmarc#include "config.h" #include "constants.h" #include "gfxinterface.h" #include "highscore.h" #include "input.h" #include "instance.h" #include "managers.h" #include "menu.h" #include "score.h" #include "stars.h" #include "time_util.h" #include "xpms.h" #include #include #include #include #include namespace Data { // The following arrays are arrival trajectories defined with relative // coordinates. // RCEnd is the end marker. const RCoord hang[] = { RCoord(512,-20), RCoord(512,612), RCoord(496,662), RCoord(454,704), RCoord(414,716), RCoord(368,704), RCoord(330,662), RCoord(318,612), RCoord(330,556), RCoord(512,260), RCEnd }; const RCoord infinity[] = { RCoord(-20,800), RCoord(460+300,544-200), RCoord(512+300,530-200), RCoord(560+300,544-200), RCoord(592+300,588-200), RCoord(598+300,618-200), RCoord(592+300,648-200), RCoord(560+300,690-200), RCoord(512+300,702-200), RCoord(512-300,702-200), RCoord(462-300,690-200), RCoord(430-300,648-200), RCoord(422-300,618-200), RCoord(428-300,588-200), RCoord(460-300,544-200), RCEnd }; const RCoord v[] = { RCoord(-20,312), RCoord(350,550), RCoord(700,550), RCoord(800,500), RCEnd }; const RCoord u[] = { RCoord(256,-20), RCoord(256,600), RCoord(768,600), RCoord(768,200), RCEnd }; const RCoord loop[] = { RCoord(-20,430), RCoord(512,430), RCoord(560,444), RCoord(592,488), RCoord(598,518), RCoord(592,548), RCoord(560,590), RCoord(512,602), RCoord(462,590), RCoord(430,548), RCoord(422,518), RCoord(428,488), RCoord(460,444), RCoord(512,430), RCoord(560,444), RCoord(592,488), RCoord(598,518), RCoord(592,548), RCoord(560,590), RCoord(512,602), RCoord(462,590), RCoord(430,548), RCoord(422,518), RCoord(428,488), RCoord(460,444), RCEnd }; const RCoord left[] = { RCoord(-20,512), RCoord(512,512), RCEnd }; const RCoord sine[] = { RCoord(-20,586), RCoord(0,566), RCoord(20,540), RCoord(66,524), RCoord(124,548), RCoord(152,588), RCoord(158,634), RCoord(182,676), RCoord(244,700), RCoord(302,676), RCoord(328,634), RCoord(338,588), RCoord(364,548), RCoord(422,524), RCoord(482,548), RCoord(506,588), RCEnd }; const RCoord t_diag[] = { RCoord(-20,-20), RCoord(512,700), RCEnd }; const RCoord b_diag[] = { RCoord(-20,1024+20), RCoord(512,316), RCEnd }; const RCoord b_zz[] = { RCoord(-20,1000), RCoord(100,1000), RCoord(0,900), RCoord(100,900), RCoord(0,800), RCoord(100,800), RCoord(0,700), RCoord(100,700), RCoord(0,600), RCoord(100,600), RCoord(0,500), RCoord(100,500), RCoord(0,400), RCoord(100,400), RCEnd }; const RCoord t_zz[] = { RCoord(-20,100), RCoord(100,100), RCoord(0,200), RCoord(100,200), RCoord(0,300), RCoord(100,300), RCoord(0,400), RCoord(100,400), RCoord(0,500), RCoord(100,500), RCoord(0,600), RCoord(100,600), RCoord(0,700), RCoord(100,700), RCEnd }; const RCoord t_circ[] = { RCoord(20,-20), RCoord(20,194), RCoord(22,240), RCoord(30,280), RCoord(38,320), RCoord(52,360), RCoord(66,402), RCoord(88,446), RCoord(112,490), RCoord(144,532), RCoord(172,566), RCoord(212,604), RCoord(246,630), RCoord(292,660), RCoord(334,680), RCoord(394,700), RCoord(436,710), RCoord(512,716), RCoord(1024-436,710), RCoord(1024-394,700), RCoord(1024-334,680), RCoord(1024-292,660), RCoord(1024-246,630), RCoord(1024-212,604), RCoord(1024-172,566), RCoord(1024-144,532), RCoord(1024-112,490), RCoord(1024-88,446), RCoord(1024-66,402), RCoord(1024-52,360), RCoord(1024-38,320), RCoord(1024-30,280), RCoord(1024-22,240), RCoord(1024-20,194), RCEnd }; const RCoord boing[] = { RCoord(24,1024+20), RCoord(24,796), RCoord(30,716), RCoord(40,644), RCoord(50,608), RCoord(60,576), RCoord(70,538), RCoord(80,516), RCoord(90,496), RCoord(100,476), RCoord(110,464), RCoord(120,446), RCoord(130,426), RCoord(140,420), RCoord(150,406), RCoord(160,390), RCoord(170,386), RCoord(180,376), RCoord(190,366), RCoord(200,362), RCoord(210,356), RCoord(220,350), RCoord(230,346), RCoord(240,344), RCoord(250,340), RCoord(260,339), RCoord(278,338), RCoord(2*278-260,339), RCoord(2*278-250,340), RCoord(2*278-240,344), RCoord(2*278-230,346), RCoord(2*278-220,350), RCoord(2*278-210,356), RCoord(2*278-200,362), RCoord(2*278-190,366), RCoord(2*278-180,376), RCoord(2*278-170,386), RCoord(2*278-160,390), RCoord(2*278-150,406), RCoord(2*278-140,420), RCoord(2*278-130,426), RCoord(2*278-120,446), RCoord(2*278-110,464), RCoord(2*278-100,476), RCoord(2*278-90,496), RCoord(2*278-80,516), RCoord(2*278-70,538), RCoord(2*278-60,576), RCoord(2*278-50,608), RCoord(2*278-40,644), RCoord(2*278-30,716), RCoord(2*278-24, 796), RCEnd }; const RCoord drop128[] = { RCoord(128,-20), RCoord(128,700), RCEnd }; const RCoord drop256[] = { RCoord(256,-20), RCoord(256,700), RCEnd }; const RCoord drop384[] = { RCoord(384,-20), RCoord(384,700), RCEnd }; const RCoord drop512[] = { RCoord(512,-20), RCoord(512,700), RCEnd }; const RCoord drop640[] = { RCoord(640,-20), RCoord(640,700), RCEnd }; const RCoord drop768[] = { RCoord(768,-20), RCoord(768,700), RCEnd }; const RCoord drop896[] = { RCoord(896,-20), RCoord(896,700), RCEnd }; // The following arrays fully define the game levels with the // following parameters: // - delay in frames before aliens convoy creation // - XPM data to draw the alien // - percentage of window width taken by the aliens convoy // - aliens convoy trajectory // - boolean, true iff the convoy is mirrored // - boolean, true iff the convoy is made of two mirrored half-convoys const ConvoyData cd1[] = { { 0, alien1_xpm, 50, hang, false, true }, {100, alien1_xpm, 50, hang, false, true }, {100, alien1_xpm, 50, hang, false, true }, {100, alien1_xpm, 50, hang, false, true }, {100, alien1_xpm, 30, hang, false, true }, { 10, alien13_xpm, 15, hang, false, true }, {0,0,0,0,false,false} }; const ConvoyData cd2[] = { {200, alien2_xpm, 50, v, false, false }, {150, alien2_xpm, 50, v, true, false }, {150, alien2_xpm, 50, v, false, false }, {100, alien2_xpm, 50, v, true, false }, {100, alien2_xpm, 30, hang, false, true }, { 10, alien13_xpm, 15, hang, false, true }, {0,0,0,0,false,false} }; const ConvoyData cd3[] = { {200, alien3_xpm, 50, t_diag, false, false }, {200, alien3_xpm, 50, t_diag, true, false }, {200, alien3_xpm, 50, t_diag, false, true }, {10, alien3_xpm, 50, t_diag, true, true }, {0,0,0,0,false,false} }; const ConvoyData cd4[] = { {200, alien4_xpm, 50, u, false, true }, {170, alien4_xpm, 50, u, false, true }, {170, alien4_xpm, 50, u, false, true }, {170, alien4_xpm, 50, u, false, true }, {150, alien4_xpm, 30, v, false, false }, { 10, alien13_xpm, 15, v, false, false }, {0,0,0,0,false,false} }; const ConvoyData cd5[] = { {200, alien5_xpm, 50, loop, false, false }, { 25, alien5_xpm, 50, loop, true, false }, {150, alien5_xpm, 50, b_diag, false, false }, {150, alien5_xpm, 50, b_diag, true, false }, {150, alien5_xpm, 50, loop, false, false }, {0,0,0,0,false,false} }; const ConvoyData cd6[] = { {200, alien6_xpm, 50, hang, false, true }, {150, alien6_xpm, 50, infinity, false, true }, {150, alien6_xpm, 50, infinity, true, false }, {100, alien6_xpm, 30, infinity, false, false }, {100, alien6_xpm, 50, infinity, true, false }, {150, alien13_xpm, 15, b_diag, true, false }, {0,0,0,0,false,false} }; const ConvoyData cd7[] = { {200, alien7_xpm, 50, b_zz, false, true }, {150, alien7_xpm, 50, t_zz, false, true }, {100, alien7_xpm, 50, b_zz, false, true }, { 50, alien7_xpm, 50, t_zz, false, true }, { 10, alien7_xpm, 50, t_zz, false, true }, {0,0,0,0,false,false} }; const ConvoyData cd8[] = { {200, alien8_xpm, 50, sine, false, false }, { 0, alien8_xpm, 50, sine, true, true }, { 50, alien8_xpm, 25, drop128, false, true }, { 5, alien8_xpm, 25, drop256, false, true }, { 5, alien8_xpm, 25, drop384, false, true }, { 5, alien8_xpm, 25, drop512, false, true }, { 5, alien8_xpm, 25, drop640, false, true }, { 5, alien8_xpm, 25, drop768, false, true }, {0,0,0,0,false,false} }; const ConvoyData cd9[] = { {200, alien9_xpm, 10, t_circ, false, false }, { 50, alien9_xpm, 20, t_circ, true, false }, { 50, alien9_xpm, 30, t_circ, false, false }, { 50, alien9_xpm, 40, t_circ, true, false }, { 50, alien9_xpm, 50, t_circ, false, true }, { 50, alien9_xpm, 50, t_circ, true, true }, { 50, alien9_xpm, 40, t_circ, false, false }, { 50, alien9_xpm, 30, t_circ, true, false }, { 50, alien9_xpm, 20, t_circ, false, false }, { 50, alien9_xpm, 10, t_circ, true, false }, {0,0,0,0,false,false} }; const ConvoyData cd10[] = { {200, alien10_xpm, 50, boing, false, false }, {50, alien10_xpm, 50, boing, true, false }, {10, alien10_xpm, 50, boing, false, true }, {10, alien10_xpm, 50, boing, false, true }, {10, alien10_xpm, 50, boing, false, true }, {10, alien10_xpm, 50, boing, false, true }, {10, alien10_xpm, 50, boing, false, true }, {10, alien10_xpm, 50, boing, false, true }, {0,0,0,0,false,false} }; const ConvoyData cd11[] = { {200, alien11_xpm, 50, sine, false, true }, {25, alien11_xpm, 50, sine, false, true }, {25, alien11_xpm, 50, sine, false, true }, {25, alien11_xpm, 50, sine, false, true }, {0,0,0,0,false,false} }; const ConvoyData cd12[] = { {200, alien12_xpm, 13, drop128, false, false }, {0, alien12_xpm, 13, drop896, false, false }, {0, alien12_xpm, 13, drop256, false, false }, {0, alien12_xpm, 13, drop768, false, false }, {0, alien12_xpm, 13, drop384, false, false }, {0, alien12_xpm, 13, drop640, false, false }, {0, alien13_xpm, 25, drop512, false, false }, {0,0,0,0,false,false} }; const ConvoyData cd13[] = { {100, alien14_xpm, 50, v, false, true }, {0, alien1_xpm, 50, v, false, true }, {0, alien2_xpm, 50, v, false, true }, {0, alien3_xpm, 50, v, false, true }, {0, alien4_xpm, 50, v, false, true }, {0, alien5_xpm, 50, v, false, true }, {0, alien6_xpm, 50, v, false, true }, {0, alien7_xpm, 50, v, false, true }, {0, alien8_xpm, 50, v, false, true }, {0, alien9_xpm, 50, v, false, true }, {0,0,0,0,false,false} }; // Game levels const ConvoyData *const levels[] = { cd1, cd2, cd3, cd4, cd5, cd6, cd7, cd8, cd9, cd10, cd11, cd12, cd13 }; } // namespace Data /* * Main functions */ AliensManager * NewLevel(BulletsManager * bombs_manager, BulletsManager * bullets_manager, BonusManager * bonus_manager, ExplosionsManager * explosions_manager) { const size_t nb_levels (sizeof Data::levels / sizeof Data::levels[0]); const size_t data_number ((Score::Instance().Level() - 1) % nb_levels); return new AliensManager (bombs_manager, bullets_manager, bonus_manager, explosions_manager, Score::Instance().Level(), Data::levels[data_number], nb_levels); } void Play() { X11::Inst().ClearWindow(); Score::Instance().ReInit(); Input input; BulletsManager bullets, bombs; BonusManager bonuses; ExplosionsManager explosions; std::auto_ptr aliens (NewLevel(&bombs, &bullets, &bonuses, &explosions)); Player player (&bullets, &bombs, &bonuses, &explosions, Score::Instance().Height() + 1); Score::Instance().SetShield(player.Shield()); int fast_star_scrolling_time (0); bool cheated (false); bool window_resized (false); Coord last_window_size (X11::Inst().WindowWidth(), X11::Inst().WindowHeight()); double frame_time (0); for (;;) { input.Update(); if (input.Quit()) break; if (!input.Pause()) { Config::Instance().AddDetailsLevel(input.Details()); SetStandardWindowSize(input.WindowSize()); X11::Inst().GetWindowAttributes(); if (last_window_size != Coord(X11::Inst().WindowWidth(), X11::Inst().WindowHeight())) { last_window_size = Coord(X11::Inst().WindowWidth(), X11::Inst().WindowHeight()); window_resized = true; } const int old_score (Score::Instance().Value()); Score::Instance().Add(aliens->DoBulletsCollisions()); if (old_score % 1000 > Score::Instance().Value() % 1000) { player.ExtraShield(); } player.DoBombsCollisions(); player.DoBonusCollisions(); if (input.Cheat()) { cheated = true; player.ExtraFire(); player.ExtraShield(); } Score::Instance().SetShield(player.Shield()); if (player.Shield() < 0) { if (!cheated && !window_resized) { HighScores::Instance().Add(Score::Instance().Value(), last_window_size); } break; } if (aliens->Finished()) { Score::Instance().IncLevel(); std::auto_ptr n (NewLevel(&bombs, &bullets, &bonuses, &explosions)); aliens = n; fast_star_scrolling_time = 100; } StarsFields::Instance().Scroll(); if (fast_star_scrolling_time > 0) { --fast_star_scrolling_time; if (fast_star_scrolling_time == 0) Score::Instance().EraseLevel(); StarsFields::Instance().Scroll(); StarsFields::Instance().Scroll(); if (fast_star_scrolling_time > 0) Score::Instance().ShowLevel(); } aliens->Move(); bonuses.Move(); player.Move(input.Move()); bullets.Move(); bombs.Move(); aliens->Fire(); if (input.Fire()) player.Fire(); explosions.Move(); Score::Instance().Refresh(); } X11::Inst().Sync(False); frame_time = SleepTimeInterval(frame_time, 1.0 / vfreq); } } void MainLoop() { X11::CreateInstance(); X11::Inst().SetWindowTitle("XGalaga++"); while (StartMenu::Instance().Display()) { Play(); } } int main() { int code (0); try { MainLoop(); } catch (const std::exception & e) { std::cerr << e.what() << std::endl; code = 1; } catch (...) { std::cerr << "Unknown exception." << std::endl; code = 1; } InstancesManager::DestroyInstance(); return code; } xgalaga++-0.8.4/xpms.cc0000644000175000017500000000077010034604252013201 0ustar marcmarc#include "xpms.h" #include "player.xpm" #include "bullet.xpm" #include "bomb.xpm" #include "bonus_fire.xpm" #include "bonus_shield.xpm" #include "bonus_speed.xpm" #include "bonus_multi.xpm" #include "alien1.xpm" #include "alien2.xpm" #include "alien3.xpm" #include "alien4.xpm" #include "alien5.xpm" #include "alien6.xpm" #include "alien7.xpm" #include "alien8.xpm" #include "alien9.xpm" #include "alien10.xpm" #include "alien11.xpm" #include "alien12.xpm" #include "alien13.xpm" #include "alien14.xpm" xgalaga++-0.8.4/instance.h0000644000175000017500000000112510035072604013654 0ustar marcmarc#ifndef INSTANCE_H #define INSTANCE_H #include // This singleton registers functions and calls them in reverse order of // registration when it is destroyed. it is used to destroy other singletons. class InstancesManager { static InstancesManager * singleton_; std::stack destroy_funcs_; InstancesManager() {} ~InstancesManager(); InstancesManager(const InstancesManager&); // no copy InstancesManager & operator=(const InstancesManager&); // no copy public: static InstancesManager & Instance(); static void DestroyInstance(); void Push(void(*pf)()); }; #endif xgalaga++-0.8.4/README0000644000175000017500000000660312227330433012567 0ustar marcmarc XGALAGA++ XGalaga++ is a classic vertical scrolling shoot'em up. It requires no X Window extension and its window is freely resizable. It is inspired by XGalaga, but rewritten from scratch, except for the graphics. Home page: http://marc.mongenet.ch/OSS/XGalaga/ COPYRIGHT İ 2003, 2004, 2008, 2009, 2010, 2013 Marc Mongenet Xgalaga++ is free software, available under the terms of the GNU General Public License. Note: Graphic art copied from XGalaga 2.0.34, İ 1995, 1998, Joe Rumsey. REQUIREMENTS - POSIX system - X11R6 + for development: - GNU Make - Standard C++ compiler - X11R6 XLibs dev libs (including Xpm v4 dev libs) INSTALL make all make install You may need to edit installation pathes in the Makefile. Note: The Makefile is a "Generic Makefiles" from http://marc.mongenet.ch/OSS/GenericMakefiles/. VERSIONS (2013-10-15) v0.8.4: Fix missing include (thanks to nemysis) (2012-04-20) v0.8.3: Fix to compile on BSD (thanks to nemysis) (2010-12-09) v0.8.2: Fix to compile on 64-bit systems (thanks to Zbigniew Baniewski) (2009-09-23) v0.8.1: Fixed includes to compile with GCC 4.3. (2008-05-21) v0.8: -Os build option Update email & website Completed manual Less randomness in bonus distribution Save high scores date Draw less scrolling stars (2004-04-08) v0.7: Added multi-fire bonus Added three levels (2004-03-09) v0.6.1: Corrected a bug in high score display (2004-03-08) v0.6: Added XGAL_PSEUDO environment variable Player name always displayed in start menu & high scores Scrollable high scores (2004-01-19) v0.5: Added high scores Standardized the build/install make targets Created a Debian source package (2003-10-15) v0.4: More precise (shaped) sprite erasure Nicer start menu Many code cleanups & optimizations Created a binary (i386) Debian package Added a man page (2003-10-10) v0.3: Better difficulty progression, less dependent on window size Upgraded all levels, now they are 10 levels New default window size and choice of standard sizes Added a cheat key Corrected huge memory leak (2003-09-30) v0.2: Pseudo color visuals supported More precise sprites positioning Blueish player explosions (2003-09-27) v0.1: First release TODO Before 1.0 - Add fire power bonus - Add solidity to aliens Sometime - Invisible cursor - High precision collision detection - Sound - Mouse/Joystisk/Joypad control - Multiplayer BUGS Know bugs - Sprite are erased before being drawn at a new position and erasure also affects the background. Could be corrected with dual-buffering, but it takes much more CPU time. - The scrolling is not _really_ smooth (I miss the Amiga :-)) However, it is not worse than other X11 games. Please send bug reports and suggestions to marc@mongenet.ch. AUTHOR Marc Mongenet marc@mongenet.ch http://marc.mongenet.ch/ I created this game because I was annoyed by bugs in XGalaga 2.0.34 and the source files were too difficult to modify. So I learned X11 (XLib) programming from Web tutorials and wrote this game. Of course, xgalaga++ is probably as buggy as the original XGalaga. xgalaga++-0.8.4/sprites.cc0000644000175000017500000000673011014750545013713 0ustar marcmarc#include "sprites.h" #include "config.h" #include "constants.h" #include "xpms.h" #include #include /* * Sprite */ Sprite::Sprite(const Pix * pix, Coord pos) : pix_(pix) , pos_(pos) { if (!pix) throw std::invalid_argument ("Null pixmap for sprite"); Draw(); } bool Sprite::Collide(const Sprite & other) const { // Collision if the horizontal/vertical distance is smaller than the addition // of half Widths/Heights. return std::abs(pos_.x - other.pos_.x) * 2 < Width() + other.Width() && std::abs(pos_.y - other.pos_.y) * 2 < Height() + other.Height(); } void Sprite::MoveTo(Coord to) { pix_->Move(pos_, to); pos_ = to; } /* * Projectile */ bool Projectile::Out() const { return Position().y - Height() / 2 + Height() < 0 || Position().y - Height() / 2 >= X11::Inst().WindowHeight(); } /* * Bonus */ // To be synchronized with bonus types enum in .h file. static const char *const * bonus2pix[] = { 0, bonus_speed_xpm, bonus_fire_xpm, bonus_shield_xpm, bonus_multi_xpm }; Bonus::Bonus(Coord pos, bonus_t type) : Projectile(PixKeeper::Instance().Get(bonus2pix[type]), pos, Coord(0, 1)) , type_(type) {} /* * Trajectory */ Trajectory::Trajectory(const RCoord * arrival, bool mirrored, const Coord & base_cruise, Coord delta_cruise) : stage_ (arriving) , arrival_ (arrival) , mirrored_ (mirrored) , base_cruise_ (base_cruise) , delta_cruise_(delta_cruise) { if (!arrival || *arrival == RCEnd) { throw std::invalid_argument ("Empty arrival trajectory"); } } Coord Trajectory::NextPosition(Coord from, int velocity) { if (velocity == 0) return from; switch (stage_) { case arriving: { const Coord goal (mirrored_ ? arrival_->XMirror() : *arrival_); const Coord delta (goal - from); const double scale (delta.Length() / velocity); if (scale < 1.0) { if (*(++arrival_) == RCEnd) stage_ = joining; return NextPosition(from, velocity); } return from + delta / scale; } case joining: { const Coord cruise_pos (base_cruise_ + delta_cruise_); const Coord delta (cruise_pos - from); const double scale (delta.Length() / velocity); if (scale <= 1.0) { stage_ = cruising; return cruise_pos; } return from + delta / scale; } case cruising: return base_cruise_ + delta_cruise_; case attacking: default: { const Coord delta (*attack_it_ - from); const double scale (delta.Length() / (velocity - 1)); if (scale < 1.0) { if (++attack_it_ == attack_.end()) { attack_.clear(); stage_ = joining; from.y = -g_alien_height; return from; } return NextPosition(from, velocity); } return from + delta / scale; } } // switch } void Trajectory::BuildAttack(Coord from) { const int min_delta_y (RCoord::max / 64); attack_.reserve(RCoord::max / min_delta_y); RCoord next (from.ToRCoord()); do { next += RCoord(std::rand() % (RCoord::max/3) - RCoord::max/3/2, std::rand() % (RCoord::max/4) + min_delta_y); attack_.push_back(next); } while (!next.YOut()); attack_it_ = attack_.begin(); stage_ = attacking; } /* * Alien */ Alien::Alien(const Pix * pix, const Trajectory & trajectory, int speed) : Sprite (pix, trajectory.InitPosition()) , trajectory_(trajectory) , speed_ (speed) { } void Alien::Move() { MoveTo(trajectory_.NextPosition(Position(), speed_)); } Coord Alien::CannonPosition() const { Coord pos (Position()); pos.y += Height() - (Height() / 2); return pos; } xgalaga++-0.8.4/alien2.xpm0000644000175000017500000000065110016155522013602 0ustar marcmarc/* XPM */ const char *const alien2_xpm[] = { "17 14 5 1", " c None", ". c #0000FF", "+ c #99953E", "@ c #CFC954", "# c #FFF968", " . ", " ++++++...++++++ ", "+@@@@@+...+@@@@@+", " +@@###+.+###@@+ ", " ++@###+###@++ ", " +@#######@+ ", " +@#######@+ ", " +@##+##@+ ", " +@+ +@+ ", " +@+ +@+ ", " +@#+#@+ ", " +@#@+ ", " +@+ ", " + "}; xgalaga++-0.8.4/time_util.cc0000644000175000017500000000103511015035525014201 0ustar marcmarc#include "time_util.h" #include #include double CurrentMicroSecond() { timeval now; gettimeofday(&now, 0); return now.tv_sec + now.tv_usec / 1000000.0; } double SleepTimeInterval(double interval_start_time, double interval) { const double remaining (interval_start_time + interval - CurrentMicroSecond()); if (remaining > 0) { timeval timeout; timeout.tv_sec = remaining; timeout.tv_usec = (remaining - timeout.tv_sec) * 1000000; select(0, 0, 0, 0, &timeout); } return CurrentMicroSecond(); } xgalaga++-0.8.4/posix_stream.cc0000644000175000017500000000411511744116773014743 0ustar marcmarc#include "posix_stream.h" #include #include #include #include #include #include const ptrdiff_t PosixBuf::in_back_; PosixBuf::PosixBuf(const std::string & file_name, int open_flags, int mode) : fd_ (open(file_name.c_str(), open_flags, mode)) { // The last table character is used to save the overflow character. setp(outbuffer_, outbuffer_ + sizeof outbuffer_ - 1); setg(inbuffer_ + in_back_, inbuffer_ + in_back_, inbuffer_ + in_back_); } PosixBuf::~PosixBuf() { if (fd_ >= 0) { sync(); close(fd_); } } int PosixBuf::Lock(short type) const { struct flock lk; lk.l_type = type; lk.l_whence = SEEK_SET; lk.l_start = 0; lk.l_len = 0; return fcntl(fd_, F_SETLKW, &lk); } int PosixBuf::Truncate(off_t len) const { return ftruncate(fd_, len); } PosixBuf::int_type PosixBuf::FlushBuffer() { const int total (pptr() - pbase()); int flushed (0); do { ssize_t ret; while ((ret = write(fd_, outbuffer_ + flushed, total - flushed)) == -1 && errno == EINTR); if (ret == -1) return EOF; flushed += ret; } while (flushed < total); pbump(-total); return total; } // Virtual method called when the output buffer overflows. PosixBuf::int_type PosixBuf::overflow(int_type c) { if (c != EOF) { *pptr() = c; pbump(1); } return FlushBuffer(); } PosixBuf::int_type PosixBuf::underflow() { if (gptr() < egptr()) return static_cast(*gptr()); const ptrdiff_t n_back (std::min(in_back_, gptr() - eback())); std::copy(gptr() - n_back, gptr(), inbuffer_ + in_back_ - n_back); int ret; while ((ret = read(fd_, inbuffer_ + in_back_, sizeof inbuffer_ - in_back_)) == -1 && errno == EINTR); if (ret <= 0) return EOF; setg(inbuffer_ + in_back_ - n_back, inbuffer_ + in_back_, inbuffer_ + in_back_ + ret); return static_cast(*gptr()); } // Synchronize stream with file => flush buffer int PosixBuf::sync() { return FlushBuffer() == EOF ? -1 : 0; } PosixBuf::pos_type PosixBuf::seekpos(pos_type pos, std::ios_base::openmode) { if (FlushBuffer() == EOF) return -1; return lseek(fd_, pos, SEEK_SET); } xgalaga++-0.8.4/constants.h0000644000175000017500000000035610022521730014064 0ustar marcmarc#ifndef CONSTANTS_H #define CONSTANTS_H // Aliens dimension enum { g_alien_width = 19, g_aliens_hspacing = 22, g_alien_height = 20, g_aliens_vspacing = 24 }; // Vertical refresh rate const int vfreq (50); #endif xgalaga++-0.8.4/time_util.h0000644000175000017500000000053011015033631014036 0ustar marcmarc#ifndef TIME_UTIL_H #define TIME_UTIL_H double CurrentMicroSecond(); // Sleep until 'interval_start_time' + 'interval' is CurrentMicroSecond(). // Return CurrentMicroSecond(). Do not sleep at all if // 'interval_start_time' + 'interval' >= CurrentMicroSecond(). double SleepTimeInterval(double interval_start_time, double interval); #endif xgalaga++-0.8.4/alien13.xpm0000644000175000017500000000070310016155476013672 0ustar marcmarc/* XPM */ const char *const alien13_xpm[] = { "13 17 7 1", " c None", ". c #606000", "+ c #A0A000", "@ c #F0F000", "# c #F00000", "$ c #C00000", "% c #900000", ". .", "+. .+", ".@. ### .@.", ".+. $$.$$ .+.", " +@.+$+$+.@+ ", " . @+%@%+@ . ", " .+.@@@.+. ", " + +@+ + ", " +@+ ", " .@. ", " .@. ", " .+. ", " .+. ", " .@. ", " .@+@. ", " .+. .+. ", " .+. "}; xgalaga++-0.8.4/bonus_speed.xpm0000644000175000017500000000051110016155657014742 0ustar marcmarc/* XPM */ const char *const bonus_speed_xpm[] = { "15 10 4 1", " c None", ". c #999995953E3E", "X c #FFFFFFFF0000", "o c #FFFF00000000", " ..XX X.. ", " ..XX oooo XX. ", "...X o XXXX.", "..XX o XXXXXX", "...XX ooo XXXXX", "....XX o XXXX", "..... o XXXX", ".... oooo XXXX.", " .... XXXX. ", " ........... "}; xgalaga++-0.8.4/posix_stream.h0000644000175000017500000000163011500253763014573 0ustar marcmarc#ifndef POSIX_STREAM_H #define POSIX_STREAM_H #include #include #include #include #include #include #include // Customized implementation of Josuttis p673-681. // It is too brittle to be reusable as is. class PosixBuf : public std::streambuf { const int fd_; char outbuffer_[4096]; static const ptrdiff_t in_back_ = 4; char inbuffer_[4096 + in_back_]; public: // see open() parameters for constructor PosixBuf(const std::string & file_name, int open_flags, int mode = 0); virtual ~PosixBuf(); int FD() const { return fd_; } int Lock(short type) const; // type: see fcntl() struct flock l_type int Truncate(off_t len = 0) const; private: int_type FlushBuffer(); virtual int_type overflow(int_type c); virtual int_type underflow(); virtual int sync(); virtual pos_type seekpos(pos_type, std::ios_base::openmode); }; #endif xgalaga++-0.8.4/score.cc0000644000175000017500000000351210022706531013322 0ustar marcmarc#include "score.h" #include "instance.h" #include #include #include Score * Score::singleton_ (0); Score & Score::Instance() { if (!singleton_) { singleton_ = new Score; InstancesManager::Instance().Push(DestroyInstance); } return *singleton_; } void Score::DestroyInstance() { delete singleton_; singleton_ = 0; } Score::Score() : score_ (0) , shield_(-1) , level_ (0) , font_ (X11::Inst().LoadQueryFont("*-helvetica-*-r-*-*-12-*")) { if (!font_) { font_ = X11::Inst().LoadQueryFont("fixed"); if (!font_) throw std::runtime_error ("X font error"); } pos_ = Coord(2, PosY()); color_.red = color_.green = 48 * 1024; color_.blue = 65535; X11::Inst().AllocColorAlways(&color_); Draw(); } Score::~Score() { X11::Inst().FreeFont(font_); } void Score::Draw() { X11::Inst().SetClipMask(None); X11::Inst().SetForeground(color_.pixel); std::ostringstream ost; ost << "level: " << std::setw(2) << std::setfill(' ') << level_ << " score: " << std::setw(4) << std::setfill('0') << score_; if (shield_ >= 0) ost << " shield: " << std::string(shield_, 'ğ'); old_text_ = ost.str(); pos_.y = PosY(); X11::Inst().SetFont(font_->fid); X11::Inst().DrawString(pos_, old_text_); } void Score::Mask() const { X11::Inst().SetClipMask(None); X11::Inst().SetForeground(X11::Inst().GetBlack()); X11::Inst().SetFont(font_->fid); X11::Inst().DrawString(pos_, old_text_); } void Score::DrawLevel(X11::Color color) const { X11::Inst().SetClipMask(None); X11::Inst().SetForeground(color); X11::Inst().SetFont(font_->fid); Coord pos (RCoord(512, 512)); std::ostringstream ost; ost << "LEVEL " << level_; pos.x -= XTextWidth(font_, ost.str().c_str(), ost.str().size()) / 2; X11::Inst().DrawString(pos, ost.str()); } int Score::PosY() const { return X11::Inst().WindowHeight() - font_->descent; } xgalaga++-0.8.4/config.cc0000644000175000017500000000363311256504420013463 0ustar marcmarc#include "config.h" #include "gfxinterface.h" #include "instance.h" #include #include #include #include namespace { std::string GetUserFullName() { const passwd *const pwd (getpwuid(getuid())); const char * gecos (pwd->pw_gecos); if (!gecos || !gecos[0]) return pwd->pw_name; while (*gecos && *gecos != ',') ++gecos; return std::string(pwd->pw_gecos, gecos - pwd->pw_gecos); } std::string PlayerName() { const char *const env_name (std::getenv("XGAL_PSEUDO")); return env_name ? env_name : GetUserFullName(); } #define TO_STRING(s) #s #define MAKE_STRING(s) TO_STRING(s) #ifndef HIGH_SCORES_FILE #define HIGH_SCORES_FILE .xgalaga++.scores #endif // If absolute path, return as-is, else prefix with home dir. std::string ScoreFileName() { static const char scores_file_name[] = MAKE_STRING(HIGH_SCORES_FILE); if (scores_file_name[0] != '/') { const passwd *const pwd (getpwuid(getuid())); if (pwd->pw_dir) return std::string(pwd->pw_dir) + '/' + scores_file_name; } return scores_file_name; } } /* * Config */ Config * Config::singleton_ (0); Config & Config::Instance() { if (!singleton_) { singleton_ = new Config; InstancesManager::Instance().Push(DestroyInstance); } return *singleton_; } Config::Config() : details_level_ (max_details) , player_name_ (PlayerName()) , score_file_name_(ScoreFileName()) { } void Config::AddDetailsLevel(int i) { if (details_level_ + i >= min_details && details_level_ + i <= max_details) { details_level_ = details_level_ + i; } } /* * */ void SetStandardWindowSize(unsigned win_size) { static const unsigned widths[] = { 640, 800, 1024, 1280, 1600 }; static const unsigned heights[] = { 480, 600, 768, 1024, 1200 }; if (win_size > 0 && win_size <= sizeof widths / sizeof widths[0]) { --win_size; X11::Inst().ResizeWindow(widths[win_size], heights[win_size]); X11::Inst().ClearWindow(); } } xgalaga++-0.8.4/bonus_fire.xpm0000644000175000017500000000051010016155640014556 0ustar marcmarc/* XPM */ const char *const bonus_fire_xpm[] = { "15 10 4 1", " c None", ". c #00000000AFAF", "X c #00000000FFFF", "o c #FFFFFFFFFFFF", " ..XX XXX.. ", " ..XX oo XXXX. ", "...XX oo XXXXX.", "..XXX oo XXXXXX", "...XXX XXXXXXX", "...XXX XXXXXXX", "....X oo XXXXXX", "..... oo XXXXX.", " .... oo XXXX. ", " .... ..... "}; xgalaga++-0.8.4/xgalaga++.6x0000644000175000017500000000175011015127250013711 0ustar marcmarc.TH XGALAGA++ 6 "21-MAY-2008" .SH NAME XGalaga++ \- X11 classic vertical scrolling shoot'em up .SH SYNOPSIS .B xgalaga++ .SH DESCRIPTION .LP XGalaga++ is a classic vertical scrolling shoot'em up: fire at aliens, collect bonuses and survive as long as you can. .SH KEYBOARD COMMANDS .TP .BI 1,2,3,4,5 Resize the window to 640x480, 800x600, 1024x768, 1280x1024, or 1600x1200. .TP .BI h Toggle high scores and menu. .TP .BI p Pause. .TP .BI q End game, or quit XGalaga++ (from menu). .TP .BI s Start game .TP .BI space Fire. .TP .BI left/right\ arrow Move vessel left/right. .TP .BI up/down\ arrow Scroll high scores up/down. .TP .BI -/+ Decrease/increase details (use a bit less CPU and memory). .SH ENVIRONMENT VARIABLES XGAL_PSEUDO - Player pseudonym, used for high scores. .SH "SEE ALSO" .BR xgalaga (6) .SH AUTHORS Marc Mongenet, <\fImarc@mongenet.ch\fP> .LP Joe Rumsey, <\fIjoe@rumsey.org\fP> (Original xgalaga author) .LP Vincent Renardias <\fIvincent@waw.com\fP> (Original xgalaga man page) .LP xgalaga++-0.8.4/menu.cc0000644000175000017500000001763012227331642013167 0ustar marcmarc#include "menu.h" #include "config.h" #include "constants.h" #include "gfxinterface.h" #include "highscore.h" #include "input.h" #include "instance.h" #include "pix.h" #include "score.h" #include "stars.h" #include "time_util.h" #include "xpms.h" #include #include #include #include StartMenu * StartMenu::singleton_ (0); StartMenu & StartMenu::Instance() { if (!singleton_) { singleton_ = new StartMenu; InstancesManager::Instance().Push(DestroyInstance); } return *singleton_; } const char *const menu_lines[] = { "XGalaga++ v0.8.4 (2013-10-15)", "İ2003-2013 Marc Mongenet, graphics from XGalaga 2.0.34", "This game is free software, covered by the GPL.", "", "Welcome player %p!", "", "Key Action", "ŻŻŻ ŻŻŻŻŻŻ", "s start game", "q quit", "h toggle high scores / menu", "p pause", "1,2,3,4,5 set window size", "+ increase details", "- decrease details", " fire", " move left/right", " scroll high scores up/down", "", "Bonus", "ŻŻŻŻŻ", "extra shield every 1000 points" }; StartMenu::StartMenu() : font_(X11::Inst().LoadQueryFont("*-fixed-bold-r-*-*-14-*-*-*-*-*-iso8859-1")) , text_width_ (0) , wait_scores_ (5000) , print_scores_ (false) , scroll_scores_ (0) , can_scroll_ (true) , last_window_size_(0, 0) , rGb_ (0) , rGb_add_ (1024) { if (!font_) { font_ = X11::Inst().LoadQueryFont("*-fixed-*"); if (!font_) throw std::runtime_error ("X font error"); } for (size_t i (0); i < sizeof menu_lines / sizeof menu_lines[0]; ++i) { text_width_ = std::max(text_width_, XTextWidth(font_, menu_lines[i], std::strlen(menu_lines[i]))); } } StartMenu::~StartMenu() { X11::Inst().FreeFont(font_); } bool StartMenu::Display() { Input input; bool updated (false); double frame_time (0); for (;;) { input.Update(); if (input.Quit()) return false; if (input.Start()) { print_scores_ = true; wait_scores_ = 5000; return true; } Config::Instance().AddDetailsLevel(input.Details()); SetStandardWindowSize(input.WindowSize()); X11::Inst().GetWindowAttributes(); if (--wait_scores_ < 0 || input.HighScores()) { print_scores_ = !print_scores_; wait_scores_ = 1000; X11::Inst().ClearWindow(); } StarsFields::Instance().Scroll(); Score::Instance().Refresh(); if (last_window_size_ != Coord(X11::Inst().WindowWidth(), X11::Inst().WindowHeight())) { last_window_size_ = Coord(X11::Inst().WindowWidth(), X11::Inst().WindowHeight()); scroll_scores_ = 0; } if (print_scores_) { try { if (!updated) { HighScores::Instance().Update(); updated = true; } if (input.VMove()) { if (can_scroll_ || input.VMove() < 0) scroll_scores_ += input.VMove(); if (scroll_scores_ < 0) scroll_scores_ = 0; wait_scores_ = 1000; } PrintScores(NextColor()); } catch (const std::exception & e) { X11::Inst().SetForeground(X11::Inst().GetWhite()); X11::Inst().SetClipMask(None); X11::Inst().SetFont(font_->fid); X11::Inst().DrawString(Coord(1, last_window_size_.y / 2), e.what()); } } else PrintHelp(NextColor()); X11::Inst().Sync(False); frame_time = SleepTimeInterval(frame_time, 1.0 / vfreq); } } XColor StartMenu::NextColor() { XColor color; color.red = 48*1024; color.blue = 65535; rGb_ += rGb_add_; if (rGb_ == 0) { rGb_add_ = -rGb_add_; rGb_ += rGb_add_; } color.green = rGb_; return color; } void StartMenu::SetFontContext(XColor & color) const { X11::Inst().AllocColorAlways(&color); X11::Inst().SetForeground(color.pixel); X11::Inst().SetClipMask(None); X11::Inst().SetFont(font_->fid); } void StartMenu::PrintHelp(XColor color) { Coord pos (std::max(0, (last_window_size_.x - text_width_) / 2), 20); SetFontContext(color); // Draw help text for (size_t i (0); i < sizeof menu_lines / sizeof menu_lines[0]; ++i) { std::string line (menu_lines[i]); while (line.find("%p") != std::string::npos) { line.replace(line.find("%p"), 2, Config::Instance().GetPlayerName()); } X11::Inst().DrawString(pos, line); pos.y += LineHeight(); if (line.empty()) { color.red -= 8192; X11::Inst().AllocColorAlways(&color); X11::Inst().SetForeground(color.pixel); } } // Draw bonus pixs with help text static const char *const *const bonuses[] = { bonus_speed_xpm, bonus_fire_xpm, bonus_shield_xpm, bonus_multi_xpm }; static const char *const bonus_text[] = { "extra speed", "extra fire", "extra shield", "multi fire" }; for (size_t i (0); i < sizeof bonuses / sizeof bonuses[0]; ++i) { const Pix *const bonus (PixKeeper::Instance().Get(bonuses[i])); bonus->Draw(pos + Coord(bonus->Width() / 2, -bonus->Height() / 2)); X11::Inst().SetClipMask(None); X11::Inst().DrawString(pos + Coord(2 * bonus->Width(), 0), bonus_text[i]); pos.y += std::max(bonus->Height(), LineHeight()); } } void StartMenu::PrintScores(XColor color) { Coord pos (std::max(0, (last_window_size_.x - text_width_) / 2), 20); SetFontContext(color); // Draw high scores title std::ostringstream ost; ost <<"High scores for "< *const high_scores (HighScores::Instance().Get(last_window_size_)); if (!high_scores) { score_lines_.clear(); ost.str("None."); X11::Inst().DrawString(pos, ost.str().c_str()); return; } // Display high scores // The first line is always displayed // The best player is always displayed (on last line if necessary). int rank (0); size_t line (0); int last_score (-1); const std::string player_name (Config::Instance().GetPlayerName()); bool look_for_player (false); bool player_displayed (false); for (std::multiset::const_reverse_iterator it (high_scores->rbegin()); (can_scroll_ = it != high_scores->rend()) && (look_for_player || pos.y < last_window_size_.y - LineHeight()); ++it) { ++rank; if ((rank > scroll_scores_ && !look_for_player) || (look_for_player && it->Name() == player_name)) { // Construct this line ost.str(""); if (it->Value() != last_score) { last_score = it->Value(); ost << std::setfill(' ') << std::setw(2) << rank << ". "; } else { ost << " "; } char score_date[20]; const time_t score_date_tm = it->Date(); strftime(score_date, sizeof score_date, "%x", localtime(&score_date_tm)); // Null score date means no date recorded -> deplace date by spaces. if (it->Date() == 0) { for (int i = 0; score_date[i] != '\0'; ++i) { score_date[i] = ' '; } } ost << std::setfill(' ') << std::setw(6) << last_score << " " << score_date << ' ' << it->Name(); // Undraw old line if is different const std::string score_line (ost.str()); if (line == score_lines_.size()) score_lines_.push_back(score_line); else if (score_lines_[line] != score_line) { X11::Inst().SetForeground(X11::Inst().GetBlack()); X11::Inst().DrawString(pos, score_lines_[line].c_str()); score_lines_[line] = score_line; } // text color with special color for current player if (it->Name() == player_name) { player_displayed = true; if (color.green) color.green += (65535 - color.green) / 2; } if (color.red >= 1024) color.red -= 1024; X11::Inst().AllocColorAlways(&color); X11::Inst().SetForeground(color.pixel); if (it->Name() == player_name) { if (color.green) color.green -= 65535 - color.green; } X11::Inst().DrawString(pos, score_line.c_str()); ++line; pos.y += LineHeight(); look_for_player = !player_displayed && pos.y >= last_window_size_.y - 2 * LineHeight(); } } } xgalaga++-0.8.4/alien7.xpm0000644000175000017500000000101110016155575013606 0ustar marcmarc/* XPM */ const char *const alien7_xpm[] = { "16 18 7 1", " c None", ". c #CFC954", "+ c #FFF968", "@ c #A80000", "# c #FF0000", "$ c #6E0000", "% c #010000", " ...... ", " ++++++++++ ", " @##########@ ", " @##########@ ", " @########@ ", " @@@@@@@@@@ ", " $$$$$$$$$$ ", " @@@@@@@@@@ ", " @@@@@@@@@@@@@@ ", "@##############@", " @############@ ", " @###%%%%###@ ", " @###%%###@ ", " @##%%##@ ", " @######@ ", " @######@ ", " @####@ ", " @@@@ "}; xgalaga++-0.8.4/explosion.cc0000644000175000017500000000314611256504463014244 0ustar marcmarc#include "explosion.h" #include "config.h" #include /* * Explosion */ Explosion::Explosion(Coord pos, Coord speed, XColor color, int duration) : color_ (color) , moves_ (0) , duration_(duration) { const int nb_dots (Config::Instance().ScaleDetails(16 * duration)); dots_.reserve(nb_dots); dots_speed_.reserve(nb_dots); for (int i (0); i < nb_dots; ++i) { using std::rand; const Coord particle (rand() % 16 + rand() % 16 - 16, rand() % 16 + rand() % 16 - 16); dots_.push_back(particle + pos); Coord particle_speed (particle / 4 + speed); particle_speed += Coord(rand() % 5 - 2, rand() % 5 - 2); dots_speed_.push_back(particle_speed); } XColor close_color = color_; X11::Inst().AllocColorAlways(&close_color); DrawAll(close_color.pixel); } void Explosion::Move() { if (moves_ < duration_) { ++moves_; DrawAll(X11::Inst().GetBlack()); if (moves_ < duration_) { for (dotsCtn::size_type i (0); i < dots_.size(); ++i) { dots_[i] += dots_speed_[i]; } color_.red = color_.red * 98 / 100; color_.green = color_.green * 96 / 100; color_.blue = color_.blue * 96 / 100; if (color_.red < 48*1024 && color_.red > 36*1024) { color_.red = color_.red * 96 / 100; color_.green = color_.green * 92 / 100; color_.blue = color_.blue * 92 / 100; } XColor close_color = color_; X11::Inst().AllocColorAlways(&close_color); DrawAll(close_color.pixel); } } } void Explosion::DrawAll(X11::Color color) const { X11::Inst().SetForeground(color); X11::Inst().SetClipMask(None); X11::Inst().DrawPoints(&dots_[0], dots_.size()); } xgalaga++-0.8.4/gfxinterface.h0000644000175000017500000001731310023254402014516 0ustar marcmarc#ifndef X11_H #define X11_H #include #include #include #include #include // Relative coordinates between (0; 0) for top-left and (max-1; max-1) // for bottom-right. struct RCoord { enum { max = 1024 }; int x, y; RCoord() {} RCoord(int _x, int _y) : x(_x), y(_y) {} bool XOut() const { return x < 0 || x >= max; } bool YOut() const { return y < 0 || y >= max; } bool Out() const { return XOut() || YOut(); } RCoord XMirror() const { return RCoord(max - x, y); } RCoord & operator+=(RCoord rhs) { x += rhs.x; y += rhs.y; return *this; } RCoord & operator-=(RCoord rhs) { x -= rhs.x; y -= rhs.y; return *this; } }; inline RCoord operator+(RCoord lhs, RCoord rhs) { return lhs += rhs; } inline RCoord operator-(RCoord lhs, RCoord rhs) { return lhs -= rhs; } inline bool operator==(RCoord lhs, RCoord rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } const RCoord RCEnd (std::numeric_limits::max(), std::numeric_limits::max()); // Absolute coordinates, directly useful with X Window functions. struct Coord : public XPoint { Coord() {} Coord(short _x, short _y) { x = _x; y = _y; } Coord(RCoord); RCoord ToRCoord() const; bool XOut() const; bool YOut() const; bool Out() const { return XOut() || YOut(); } double Length() const; Coord & operator+=(Coord rhs) { x += rhs.x; y += rhs.y; return *this; } Coord & operator-=(Coord rhs) { x -= rhs.x; y -= rhs.y; return *this; } Coord & operator*=(double rhs); Coord & operator/=(double rhs); Coord & operator*=(int rhs) { x = static_cast(x * rhs); y = static_cast(y * rhs); return *this; } Coord & operator/=(int rhs) { x = static_cast(x / rhs); y = static_cast(y / rhs); return *this; } }; inline Coord operator+(Coord lhs, Coord rhs) { return lhs += rhs; } inline Coord operator-(Coord lhs, Coord rhs) { return lhs -= rhs; } template inline Coord operator*(T lhs, Coord rhs) { return rhs *= lhs; } template inline Coord operator/(Coord lhs, T rhs) { return lhs /= rhs; } inline bool operator==(Coord lhs, Coord rhs) { return lhs.x == rhs.x && lhs.y == rhs.y; } inline bool operator!=(Coord lhs, Coord rhs) { return !(lhs == rhs); } inline bool operator<(Coord lhs, Coord rhs) { return (lhs.x << 16 | lhs.y) < (rhs.x << 16 | rhs.y); } // The GUI is a single X window. This class is not an abstraction, it only // keeps useful data like the X display, screen, visual, colormap... class X11 { static X11 * singleton_; static unsigned default_window_width_; static unsigned default_window_height_; X11(); ~X11(); Display * display_; int screen_; Visual * visual_; Colormap colormap_; GC gc_; Window window_; unsigned window_width_, window_height_; // cached values public: typedef unsigned long Color; static X11 & Inst(); static void CreateInstance(); static void DestroyInstance(); static void SetDefaultWindowWidth(unsigned); static void SetDefaultWindowHeight(unsigned); void SetWindowTitle(const std::string & title) const; Status GetWindowAttributes(XWindowAttributes * = 0); void ResizeWindow(unsigned width, unsigned height); int WindowWidth() const; int WindowHeight() const; Color GetBlack() const; Color GetWhite() const; void SetForeground(Color color) const; Status AllocColor(XColor *) const; void AllocColorAlways(XColor *) const; void FreeColor(Color) const; void DrawPoint(int x, int y) const; void DrawPoint(Coord) const; void DrawPoints(const XPoint * points, int npoints) const; void SetClipOrigin(int x, int y) const; void SetClipOrigin(Coord) const; void SetClipMask(Pixmap) const; void ClearWindow() const; void CopyAreaToWindow(Drawable src, int src_x, int src_y, unsigned width, unsigned height, int dest_x, int dest_y) const; void CopyAreaToWindow(Drawable src, Coord src_c, Coord dim, Coord dest_c) const; void FillRectangle(Coord c, Coord dim) const; void NextEvent(XEvent *) const; int Pending() const; void Sync(Bool discard) const; int CreatePixmapFromData(const char *const * xpm, Pixmap * pixmap, Pixmap * pixmask, XpmAttributes *) const; void FreePixmap(Pixmap) const; XFontStruct * LoadQueryFont(const std::string & font_name) const; void FreeFont(XFontStruct * font) const; void SetFont(Font font) const; void DrawString(Coord c, const std::string & str) const; }; inline X11 & X11::Inst() { return *singleton_; } inline void X11::DestroyInstance() { delete singleton_; singleton_ = 0; } inline void X11::SetDefaultWindowWidth(unsigned width) { default_window_width_ = width; } inline void X11::SetDefaultWindowHeight(unsigned height) { default_window_height_ = height; } inline int X11::WindowWidth() const { return window_width_; } inline int X11::WindowHeight() const { return window_height_; } inline X11::Color X11::GetBlack() const { return BlackPixel(display_, screen_); } inline X11::Color X11::GetWhite() const { return WhitePixel(display_, screen_); } inline void X11::SetForeground(Color color) const { XSetForeground(display_, gc_, color); } inline Status X11::AllocColor(XColor * color) const { return XAllocColor(display_, colormap_, color); } //inline void X11::FreeColor(Color color) const // { XFreeColors(display_, colormap_, &color, 1, 0); } inline void X11::DrawPoint(int x, int y) const { XDrawPoint(display_, window_, gc_, x, y); } inline void X11::DrawPoint(Coord c) const { DrawPoint(c.x, c.y); } inline void X11::DrawPoints(const XPoint * points, int npoints) const { XDrawPoints(display_, window_, gc_, const_cast(points), npoints, CoordModeOrigin); } inline void X11::SetClipOrigin(int x, int y) const { XSetClipOrigin(display_, gc_, x, y); } inline void X11::SetClipOrigin(Coord c) const { SetClipOrigin(c.x, c.y); } inline void X11::SetClipMask(Pixmap pixmap) const { XSetClipMask(display_, gc_, pixmap); } inline void X11::ClearWindow() const { XClearWindow(display_, window_); } inline void X11::CopyAreaToWindow(Drawable src, int src_x, int src_y, unsigned width, unsigned height, int dest_x, int dest_y) const { XCopyArea(display_, src, window_, gc_, src_x, src_y, width, height, dest_x, dest_y); } inline void X11::CopyAreaToWindow(Drawable src, Coord src_c, Coord dim, Coord dest_c) const { CopyAreaToWindow(src, src_c.x, src_c.y, dim.x, dim.y, dest_c.x, dest_c.y); } inline void X11::FillRectangle(Coord c, Coord dim) const { XFillRectangle(display_, window_, gc_, c.x, c.y, dim.x, dim.y); } inline void X11::NextEvent(XEvent * evt) const { XNextEvent(display_, evt); } inline int X11::Pending() const { return XPending(display_); } inline void X11::Sync(Bool discard) const { XSync(display_, discard); } inline int X11::CreatePixmapFromData(const char *const * xpm, Pixmap * pixmap, Pixmap * pixmask, XpmAttributes * attrs) const { return XpmCreatePixmapFromData(display_, window_, const_cast(xpm), pixmap, pixmask, attrs); } inline void X11::FreePixmap(Pixmap pixmap) const { XFreePixmap(display_, pixmap); } inline XFontStruct * X11::LoadQueryFont(const std::string & font_name) const { return XLoadQueryFont(display_, font_name.c_str()); } inline void X11::FreeFont(XFontStruct * font) const { XFreeFont(display_, font); } inline void X11::SetFont(Font font) const { XSetFont(display_, gc_, font); } inline void X11::DrawString(Coord c, const std::string & str) const { XDrawString(display_, window_, gc_, c.x, c.y, str.c_str(), str.size()); } inline bool Coord::XOut() const { return x < 0 || x >= X11::Inst().WindowWidth(); } inline bool Coord::YOut() const { return y < 0 || y >= X11::Inst().WindowHeight(); } #endif xgalaga++-0.8.4/alien11.xpm0000644000175000017500000000101610016155436013662 0ustar marcmarc/* XPM */ const char *const alien11_xpm[] = { "14 16 12 1", " c None", ". c #C1C1C1", "+ c #909090", "@ c #A1A1A1", "# c #B0B0B0", "$ c #E16F6F", "% c #7F503F", "& c #600000", "* c #00FF00", "= c #A19050", "- c #C15F5F", "; c #FF0000", ". +@@+ .", "+ +####+ +", "+ +##$$##+ +", "+ $%&.%%.&%$ +", "* $==&==&==$ *", "*@#$-=$$=-$#@*", "*@##$----$##@*", "*@+ -%%- +@*", "+ == +", "+ + @--@ + +", " +@$..$@+ ", " *@#..#@* ", " * ;; * ", " * * ", " + + ", " + + "}; xgalaga++-0.8.4/alien9.xpm0000644000175000017500000000106410016155617013615 0ustar marcmarc/* XPM */ const char *const alien9_xpm[] = { "15 18 11 1", " c None", ". c #909090", "+ c #B0B0B0", "@ c #FF0000", "# c #A1A1A1", "$ c #C1C1C1", "% c #E16F6F", "& c #C15F5F", "* c #7F503F", "= c #A19050", "- c #00FF00", " . . ", " +@+ ", " #$# ", " %$% ", " #&# ", " #&*&# ", ". ##*%=%*## .", ".##&&=*%*=&&##.", "-#%=#+=%=+#=%#-", "- & -", "- % -", ". # .", " # ", " # ", " #+# ", " +$+ ", " .+. ", " . "}; xgalaga++-0.8.4/alien12.xpm0000644000175000017500000000072410016155466013673 0ustar marcmarc/* XPM */ const char *const alien12_xpm[] = { "13 18 7 1", " c None", ". c #BF6A41", "+ c #FF8E57", "@ c #008100", "# c #00B000", "$ c #00E500", "% c #010000", " ..+.. ", " +++++ ", " @@@@@@@ ", " @###$###@ ", " @###$###@ ", " @##$##@ ", " @##$##@ ", " @#$#@ ", " @#$#@ ", " @$@ ", " @@@@#$#@@@@ ", "@#####$#####@", " @####$####@ ", " @##%%%##@ ", " @#%%%#@ ", " @#%#@ ", " @$@ ", " @ "}; xgalaga++-0.8.4/input.h0000644000175000017500000000140210022523170013200 0ustar marcmarc#ifndef INPUT_H #define INPUT_H class Input { bool quit_; int move_; bool left_, right_, last_is_left_; int vmove_; bool up_, down_, last_is_up_; bool fire_, firing_; bool start_; bool pause_; bool cheat_; bool highscores_; int details_; int window_size_; public: Input(); void Update(); bool Quit() const { return quit_; } int Move() const { return move_; } int VMove() const { return vmove_; } bool Fire() const { return fire_; } bool Start() const { return start_; } bool Pause() const { return pause_; } bool Cheat() const { return cheat_; } bool HighScores() const { return highscores_; } int Details() const { return details_; } int WindowSize() const { return window_size_; } }; #endif xgalaga++-0.8.4/alien4.xpm0000644000175000017500000000076710016155555013622 0ustar marcmarc/* XPM */ const char *const alien4_xpm[] = { "17 17 6 1", " c None", ". c #006000", "+ c #00A000", "@ c #00F000", "# c #A05020", "$ c #F0F0F0", " ..++@.+.. ", " +++++@..+++ ", " +++++@...++ ", " ..+++@..... ", " +++++ ", " ++@++ ", " +@@@+ ", " #+@ @+# ", " # . . # ", " @@@@@@@@@@@@@@@ ", "@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@@@@@@", " @@@@@@@@@@@@@@@ ", " .+++. ", " +@@@+ ", " ", " $$$$$ "}; xgalaga++-0.8.4/alien1.xpm0000644000175000017500000000102710016154510013573 0ustar marcmarc/* XPM */ const char *const alien1_xpm[] = { "18 17 7 1", " c None", ". c #603000", "+ c #F0F000", "@ c #A05000", "# c #C0C000", "$ c #909000", "% c #F08000", " ..++++.. ", " @@+#$$#+@@ ", " @@.@. .@.@@ ", " @@@..%..%..@@@ ", " .@@%%.@%%@.%%@@. ", ".@%%@@@@ @@@@%%@.", "@.@@ .@@. @@.@", "@%. @%%@ %@", "@. @..@ .@", "%@. .%%. .@%", "@. @..@ .@", ". .@%%@. .", " @%@@%@ ", " @% %@ ", " .% %. ", " @ @ ", " @ @ "}; xgalaga++-0.8.4/alien10.xpm0000644000175000017500000000067210016155426013667 0ustar marcmarc/* XPM */ const char *const alien10_xpm[] = { "14 13 10 1", " c None", ". c #FFFFFF", "+ c #797979", "@ c #BCBCBC", "# c #010000", "$ c #FF0000", "% c #A80000", "& c #0000AF", "* c #0000FF", "= c #00FFFF", " .. ", " +..+ ", " @ @..@ @ ", " @ @..@ @ ", "@ @##@ @", "@...+@##@+...@", "...++####++...", "$$%%%@..@%%%$$", "@ @..@ @", "@ +..+ @", " @ &*==*& @ ", " @ &**& @ ", " && "}; xgalaga++-0.8.4/Makefile0000644000175000017500000001771411744117327013364 0ustar marcmarc# Makefile for single executable C++ project with auto-dependencies and # multiple build options # Copyright (C) 2000-2003 Marc Mongenet ############################################################################### # PROJECT SPECIFIC DEFINITIONS ############################################################################### # name of file to build EXE = xgalaga++ # name of manual (leave empty if none) MANUAL = xgalaga++.6x # source files suffix (all source files must have the same suffix) SOURCE_SUFFIX = cc # C++ compiler CXX = g++ # source files directory srcdir = . # build directory builddir = . # installation directories installprefix = /usr bindir = $(installprefix)/games mandir = $(installprefix)/share/man/man6 # preprocessor options to find all included files INC_PATH = -I$(srcdir) -I/usr/local/include # libraries link options ('-lm' is common to link with the math library) LNK_LIBS = -lm -lX11 -lXpm -L/usr/local/lib/ # other compilation options # The high scores file is only writable by the executable and shared # by all players. HIGH_SCORES_FILE=/var/games/xgalaga++.scores #HIGH_SCORES_FILE=.xgalaga++.scores # This group is used for the executable and high scores file. # The executable is setgid. EXE_GROUP=games COMPILE_OPTS = -DHIGH_SCORES_FILE=$(HIGH_SCORES_FILE) # basic compiler warning options (for GOAL_EXE) BWARN_OPTS = -Wall -ansi # extented compiler warning options (for GOAL_DEBUG) EWARN_OPTS = $(BWARN_OPTS) -pedantic -W\ -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align\ -Wwrite-strings -Woverloaded-virtual -Winline ############################################################################### # INTERNAL DEFINITIONS # The following definitions are designed to be project neutral. ############################################################################### # You may freely change the following goal names if you dislike them. GOAL_DEBUG = debug GOAL_PROF = prof GOAL_EXE = all # build options for GOAL_DEBUG (executable for debugging) goal ifeq "$(MAKECMDGOALS)" "$(GOAL_DEBUG)" # specific options for debugging GOAL_OPTS = -g # compilation verification options WARN_OPTS = $(EWARN_OPTS) # optimization options OPTIMISE_OPTS = # dependencies must be up to date CHECK_DEPS = yes else # build options for GOAL_PROF (executable for profiling) goal ifeq "$(MAKECMDGOALS)" "$(GOAL_PROF)" # specific options for profiling GOAL_OPTS = -pg # compilation verification options WARN_OPTS = $(BWARN_OPTS) # optimization options OPTIMISE_OPTS = -O # dependencies must be up to date CHECK_DEPS = yes else # build options for GOAL_EXE (optimized executable) goal ifeq "$(MAKECMDGOALS)" "$(GOAL_EXE)" # specific options for optimized executable GOAL_OPTS = -s # compilation verification options WARN_OPTS = $(BWARN_OPTS) # optimization options OPTIMISE_OPTS = -Os -fomit-frame-pointer # dependencies must be up to date CHECK_DEPS = yes else # Other goals do not require up to date dependencies. CHECK_DEPS = no endif endif endif # preprocessor options CPPOPTS = $(INC_PATH) # compiler options CXXOPTS = $(GOAL_OPTS) $(COMPILE_OPTS) $(WARN_OPTS) $(OPTIMISE_OPTS) # linker options LDOPTS = $(GOAL_OPTS) $(LNK_LIBS) # source files in this project sources := $(wildcard $(srcdir)/*.$(SOURCE_SUFFIX)) # object files in this project objs := $(notdir $(sources)) objs := $(addprefix $(builddir)/, $(objs)) objs := $(objs:.$(SOURCE_SUFFIX)=.o) # executable with full path exe = $(builddir)/$(EXE) # This makefile creates and includes makefiles containing actual dependencies. # For every source file a dependencies makefile is created and included. # The deps variable contains the list of all dependencies makefiles. deps_suffix = d deps := $(objs:.o=.$(deps_suffix)) # To detect goal changes (for instance from GOAL_DEBUG to GOAL_EXE) # between invocations, this makefile creates an empty file (the goal flag # file) which suffix is the goal name. goal_flag_file_prefix = $(builddir)/Last_make_goal_was_ goal_flag_file = $(goal_flag_file_prefix)$(MAKECMDGOALS) ############################################################################### # TARGETS ############################################################################### # Delete the target file of a rule if the command used to update it failed. # Do that because the newly generated target file may be corrupted but appear # up to date. .DELETE_ON_ERROR: # Clear default suffix list to disable all implicit rules. .SUFFIXES: # usage message for this makefile .PHONY: usage usage: @echo "GOAL EFFECT" @echo "---- ------" @echo "usage print this message" @echo "list list the source files" @echo "$(GOAL_EXE) build the executable" @echo "$(GOAL_DEBUG) build the executable with debug options" @echo "$(GOAL_PROF) build the executable with profiling options" @echo "clean remove all built files" @echo "install remove all built files" @echo "uninstall remove all built files" # If source files exist then build the EXE file. .PHONY: $(GOAL_EXE) ifneq "$(strip $(sources))" "" $(GOAL_EXE): $(exe) else $(GOAL_EXE): @echo "No source file found." endif # GOAL_DEBUG and GOAL_PROF targets use the same rules than GOAL_EXE. .PHONY: $(GOAL_DEBUG) $(GOAL_DEBUG): $(GOAL_EXE) .PHONY: $(GOAL_PROF) $(GOAL_PROF): $(GOAL_EXE) ############################################################################### # BUILDING # Note: CPPFLAGS, CXXFLAGS or LDFLAGS are not used but may be specified by the # user at make invocation. ############################################################################### # linking $(exe): $(objs) $(CXX) $^ -o $@ $(LDOPTS) $(LDFLAGS) # explicit definition of the implicit rule used to compile source files $(builddir)/%.o: $(srcdir)/%.$(SOURCE_SUFFIX) $(CXX) -c $< $(CPPOPTS) $(CXXOPTS) $(CPPFLAGS) $(CXXFLAGS) -o $@ # Rule to build our included dependencies makefiles. # This rule is used by GNU Make because it automatically tries to (re)build # obsolete or non-existent included makefiles. # These files are created with one line of the form: # 1.o 1.d: $(goal_flag_file) 1.cc 1.h 2.h 3.h g.h # The implicit rule previously defined will be used for compilation. # Note that the dependencies can be goal specific. # The goal_flag_file is determined at run time because it must be the current # goal and not the goal in use when the dependencies makefile was created. $(builddir)/%.$(deps_suffix): $(srcdir)/%.$(SOURCE_SUFFIX) $(goal_flag_file) $(SHELL) -ec '$(CXX) -MM $(CPPOPTS) $(CPPFLAGS) $< |\ sed '\''s@\($*\)\.o[ :]*@$(builddir)/\1.o $@: $$(goal_flag_file) @g'\'' > $@;\ [ -s $@ ] || rm -f $@' # If dependencies have to be up to date then include dependencies makefiles. ifeq "$(CHECK_DEPS)" "yes" ifneq "$(strip $(sources))" "" include $(deps) endif endif # Rule to produce the goal flag file. # If the goal has changed then we must rebuild on a clean state because # pre-processor DEFINE's may have changed. $(goal_flag_file): rm -f $(exe) $(goal_flag_file_prefix)* $(objs) $(deps) touch $@ ############################################################################### # NON-BUILD TARGETS ############################################################################### # List the source files .PHONY: list list: @echo $(sources) | tr [:space:] \\n # Remove all files that are normally created by building the program. .PHONY: clean clean: rm -f $(exe) $(goal_flag_file_prefix)* $(objs) $(deps) ############################################################################### # INSTALLATION TARGETS ############################################################################### # Installation procedure # Customized for XGalaga++ install: cp $(EXE) $(bindir) if [ -n "$(MANUAL)" ]; then cp $(MANUAL) $(mandir); fi if [ -n "$(EXE_GROUP)" ]; then chgrp $(EXE_GROUP) $(bindir)/$(EXE); fi chmod g+s $(bindir)/$(EXE) touch $(HIGH_SCORES_FILE) if [ -n "$(EXE_GROUP)" ]; then chgrp $(EXE_GROUP) $(HIGH_SCORES_FILE); fi chmod 664 $(HIGH_SCORES_FILE) .PHONY: uninstall uninstall: rm $(bindir)/$(EXE) rm $(mandir)/$(MANUAL) xgalaga++-0.8.4/menu.h0000644000175000017500000000165410022760304013020 0ustar marcmarc#ifndef MENU_H #define MENU_H #include "gfxinterface.h" #include #include class StartMenu { static StartMenu * singleton_; XFontStruct * font_; int text_width_; int wait_scores_; // time to wait before score/help auto-switch bool print_scores_; // Is scores or help menu displayed? int scroll_scores_; // Scroll down scores this many lines bool can_scroll_; // Can scroll down? Coord last_window_size_; std::vector score_lines_; unsigned short rGb_; // for color cycling short rGb_add_; // for color cycling StartMenu(); ~StartMenu(); XColor NextColor(); int LineHeight() const { return font_->ascent + font_->descent + 1; } void PrintHelp(XColor color); void PrintScores(XColor color); public: static StartMenu & Instance(); static void DestroyInstance() { delete singleton_; singleton_ = 0; } bool Display(); private: void SetFontContext(XColor &) const; }; #endif xgalaga++-0.8.4/managers.cc0000644000175000017500000002454112227331571014020 0ustar marcmarc#include "managers.h" #include "xpms.h" #include #include #include template inline void Delete(typename Ctn::value_type ptr) { delete ptr; } /* * ConvoyData */ int ConvoyData::ConvoySize() const { return X11::Inst().WindowWidth() * convoy_size_pc / g_aliens_hspacing / 100; } /* * BulletsManager */ BulletsManager::~BulletsManager() { std::for_each(bullets_.begin(), bullets_.end(), Delete); } void BulletsManager::Move() { BulletsCtn::iterator it (bullets_.begin()); while (it != bullets_.end()) { (*it)->Move(); if ((*it)->Out()) { delete *it; it = bullets_.erase(it); } else { ++it; } } } void BulletsManager::Add(const Pix * pix, Coord pos, Coord speed) { bullets_.push_back(new Projectile (pix, pos, speed)); } int BulletsManager::DoCollisions(const Sprite & other, int max) { int res (0); BulletsCtn::iterator it (bullets_.begin()); while (res < max && it != bullets_.end()) { if ((*it)->Collide(other)) { ++res; (*it)->Mask(); delete *it; it = bullets_.erase(it); } else { ++it; } } return res; } /* * BonusManager */ BonusManager::~BonusManager() { std::for_each(bonuses_.begin(), bonuses_.end(), Delete); } void BonusManager::Move() { BonusCtn::iterator it (bonuses_.begin()); while (it != bonuses_.end()) { (*it)->Move(); if ((*it)->Out()) { delete *it; it = bonuses_.erase(it); } else { ++it; } } } void BonusManager::Add(Coord pos, Bonus::bonus_t type) { bonuses_.push_back(new Bonus (pos, type)); } Bonus::bonus_t BonusManager::GetBonusCollision(const Sprite & other) { BonusCtn::iterator it (bonuses_.begin()); while (it != bonuses_.end()) { if ((*it)->Collide(other)) { const Bonus::bonus_t res ((*it)->Type()); (*it)->Mask(); delete *it; bonuses_.erase(it); return res; } ++it; } return Bonus::none; } /* * ExplosionsManager */ ExplosionsManager::~ExplosionsManager() { std::for_each(explosions_.begin(), explosions_.end(), Delete); } void ExplosionsManager::Move() { ExplosionsCtn::iterator it (explosions_.begin()); while (it != explosions_.end()) { (*it)->Move(); if ((*it)->Finished()) { delete *it; it = explosions_.erase(it); } else { ++it; } } } void ExplosionsManager::Add(Coord pos, Coord speed, XColor color, int duration) { explosions_.push_back(new Explosion (pos, speed, color, duration)); } /* * AliensManager */ static int GetNbConvoys(const ConvoyData * convoys) { const ConvoyData * p (convoys); while (p->alien_xpm) ++p; return p - convoys; } int AliensManager::bonus_wait_; AliensManager::AliensManager(BulletsManager * bombs_manager, BulletsManager * bullets_manager, BonusManager * bonus_manager, ExplosionsManager * explosions_manager, int level_number, const ConvoyData * convoys_data, int max_level) : bombs_manager_ (bombs_manager) , bullets_manager_ (bullets_manager) , bonus_manager_ (bonus_manager) , explosions_manager_(explosions_manager) , level_number_ (level_number) , convoys_ (convoys_data) , nconvoys_ (GetNbConvoys(convoys_data)) , max_convoy_size_ (GetMaxConvoySize()) , convoy_idx_ (0) , speed_ (level_number / (max_level + 1) + 3) , base_cruise_ (0, g_alien_height) , base_cruise_speed_ (1) , next_creation_ (new_convoy) { if (level_number_ < 1 || !convoys_ || !convoys_[0].alien_xpm) { throw std::invalid_argument ("AliensManager data error"); } next_creation_wait_ = convoys_[0].wait; if (level_number_ == 1) bonus_wait_ = 20; } int AliensManager::GetMaxConvoySize() const { int res (0); for (int i (0); i < nconvoys_; ++i) { const int convoy_size (convoys_[i].ConvoySize()); if (convoy_size > res) res = convoy_size; } return res; } AliensManager::~AliensManager() { std::for_each(aliens_.begin(), aliens_.end(), Delete); } void AliensManager::Move() { base_cruise_.x += base_cruise_speed_; if ((base_cruise_speed_ < 0 && base_cruise_.x <= g_alien_width / 2) || (base_cruise_speed_ > 0 && base_cruise_.x >= X11::Inst().WindowWidth() - g_alien_width / 2 - (max_convoy_size_ - 1) * g_aliens_hspacing)) { base_cruise_speed_ *= -1; } for (std::list::iterator it (aliens_.begin()); it != aliens_.end(); ++it) { (*it)->Move(); } if (next_creation_wait_ == 0) { Creation(); } else { --next_creation_wait_; } } void AliensManager::Creation() { switch (next_creation_) { case new_convoy: convoy_alien_idx_ = 0; next_creation_ = new_alien; // continue with new_alien case new_alien: { const ConvoyData *const convoy (convoys_ + convoy_idx_); const Coord delta_cruise ((convoy_alien_idx_ + (max_convoy_size_ - convoy->ConvoySize()) / 2) * g_aliens_hspacing, (nconvoys_ - convoy_idx_ - 1) * g_aliens_vspacing); const bool mirrored (convoy->x_mirror ^ (convoy->split && convoy_alien_idx_ % 2 == 0)); aliens_.push_back(new Alien (PixKeeper::Instance().Get(convoy->alien_xpm), Trajectory (convoy->arrival, mirrored, base_cruise_, delta_cruise), speed_)); if (++convoy_alien_idx_ < convoy->ConvoySize()) { next_creation_wait_ = 30 / speed_; } else { ++convoy_idx_; if (convoy_idx_ < nconvoys_) { next_creation_ = new_convoy; next_creation_wait_ = convoys_[convoy_idx_].wait; } else { next_creation_ = new_attack; next_creation_wait_ = std::max(50, 750 - level_number_ * 33); } } break; } case new_attack: { int nb_attacking (0); for (AliensCtn::const_iterator it (aliens_.begin()); it != aliens_.end(); ++it) { if ((*it)->Stage() == Trajectory::attacking) ++nb_attacking; } for (AliensCtn::iterator it (aliens_.begin()); it != aliens_.end() && nb_attacking < level_number_ * 3; ++it) { if ((*it)->Stage() == Trajectory::cruising) { (*it)->BuildAttack(); ++nb_attacking; } } next_creation_wait_ = 5; } } // switch } void AliensManager::Fire() const { for (AliensCtn::const_iterator it (aliens_.begin()); it != aliens_.end() && bombs_manager_->Nb() < 3 * level_number_ * max_convoy_size_ / 12; ++it) { if ((*it)->Stage() != Trajectory::cruising && (*it)->Stage() != Trajectory::joining && std::rand() % 50 < speed_) { const int bomb_speed_x (std::rand() % 3 + std::rand() % 3 - 2); const Coord bomb_speed (bomb_speed_x, speed_ * 3 / 2 - std::abs(bomb_speed_x)); bombs_manager_->Add(PixKeeper::Instance().Get(bomb_xpm), (*it)->CannonPosition(), bomb_speed); } } } int AliensManager::DoBulletsCollisions() { int nb (0); AliensCtn::iterator it (aliens_.begin()); while (it != aliens_.end()) { if (bullets_manager_->DoCollisions(**it, 1)) { // alien explosion and bonus creation (maybe) (*it)->Mask(); XColor color; color.red = color.green = 65535; color.blue = 54*1024; explosions_manager_->Add((*it)->Position(), Coord(0,-4), color); CreateBonusMaybe((*it)->Position()); ++nb; delete *it; it = aliens_.erase(it); } else { ++it; } } return nb; } void AliensManager::CreateBonusMaybe(Coord pos) { static Bonus::bonus_t bonuses[] = { Bonus::extra_speed, Bonus::extra_speed, Bonus::extra_speed, Bonus::extra_speed, Bonus::extra_fire, Bonus::extra_fire, Bonus::extra_fire, Bonus::extra_fire, Bonus::extra_fire, Bonus::extra_multi, Bonus::extra_multi, Bonus::extra_shield, Bonus::extra_shield, }; static size_t created = 0; if (--bonus_wait_ > 0) return; if (created % (sizeof bonuses / sizeof bonuses[0]) == 0) { created = 0; std::random_shuffle(&bonuses[0], &bonuses[sizeof bonuses / sizeof bonuses[0]]); } bonus_wait_ = max_convoy_size_ * 5; bonus_manager_->Add(pos, bonuses[created++]); } /* * Player */ Player::Player(BulletsManager * bullets_manager, BulletsManager * bombs_manager, BonusManager * bonus_manager, ExplosionsManager * explosions_manager, int below_y) : Sprite (PixKeeper::Instance().Get(player_xpm), Coord(X11::Inst().WindowWidth() / 2, -50)) , bullets_manager_ (bullets_manager) , bombs_manager_ (bombs_manager) , bonus_manager_ (bonus_manager) , explosions_manager_(explosions_manager) , below_y_ (below_y) , shield_ (3) , speed_ (2) , fire_wait_ (0) , fire_interval_ (24) , multi_fire_ (1) { } void Player::Move(int direction) { if (fire_wait_ > 0) --fire_wait_; Coord pos (Position()); pos.x += direction * speed_; if (pos.x < Width() / 2) pos.x = Width() / 2; else { const int max_right (X11::Inst().WindowWidth() - Width() / 2 - 1); if (pos.x > max_right) pos.x = max_right; } pos.y = PosY(); MoveTo(pos); } void Player::Fire() { if (fire_wait_ > 0) return; fire_wait_ = fire_interval_; for (int i (0); i < multi_fire_; ++i) { Coord speed (i - multi_fire_ / 2, -10); if (multi_fire_ % 2 == 0 && i >= multi_fire_ / 2) ++speed.x; Coord fire_pos (Position()); fire_pos.y -= Height() / 2; bullets_manager_->Add(PixKeeper::Instance().Get(bullet_xpm), fire_pos, speed); } } void Player::DoBombsCollisions() { for (int n (bombs_manager_->DoCollisions(*this, shield_ + 1)); n; --n) { --shield_; XColor color; color.blue = 65535; color.red = color.green = 54*1024; explosions_manager_->Add(Position(), Coord(0,0), color, 50); } } void Player::DoBonusCollisions() { Bonus::bonus_t res; while ((res = bonus_manager_->GetBonusCollision(*this)) != Bonus::none) { switch (res) { case Bonus::extra_speed: ExtraSpeed(); break; case Bonus::extra_fire: ExtraFire(); break; case Bonus::extra_multi: ExtraMulti(); break; case Bonus::extra_shield: ExtraShield(); break; default: break; } } } int Player::PosY() const { return X11::Inst().WindowHeight() - below_y_ - Height() / 2; } void Player::ExtraFire() { if (fire_interval_ > 5) { fire_interval_ = fire_interval_ * 3 / 4; fire_wait_ = fire_wait_ * 3 / 4; } } void Player::ExtraMulti() { if (multi_fire_ < 9) { fire_interval_ = fire_interval_ * (multi_fire_ + 1) / multi_fire_; fire_wait_ = fire_wait_ * (multi_fire_ + 1) / multi_fire_; ++multi_fire_; } } xgalaga++-0.8.4/bonus_shield.xpm0000644000175000017500000000053710016155647015121 0ustar marcmarc/* XPM */ const char *const bonus_shield_xpm[] = { "15 10 5 1", " c None", ". c #000081810000", "X c #0000B0B00000", "o c #0000E5E50000", "O c #0000FFFFFFFF", " .Xooo ooo.. ", " .Xooo O oooo. ", ".XXo OOO ooo.", "XXo O OOO O ooo", "XXX O OOO O ooo", "XXX O OOO O ooo", "XXX OOOOOOO ooo", ".XX O OOO O oo.", " .X O O O o. ", " .X XX XX X. "}; xgalaga++-0.8.4/pix.h0000644000175000017500000000213210016321436012646 0ustar marcmarc#ifndef PIX_H #define PIX_H #include "gfxinterface.h" #include // Picture defined by two pixmaps: one for colors; one for tranparency (shape). // The constructors loads it in the X server and it can then be displayed an // arbitrary number of times. class Pix { Pixmap pixmap_, shapemask_; Coord dim_; Pix(const Pix &); // no copy Pix & operator=(const Pix &); // no assign friend class PixKeeper; Pix(const char *const * xpm); ~Pix(); public: int Width() const { return dim_.x; } int Height() const { return dim_.y; } Coord Dim() const { return dim_; } void Draw(Coord pos) const; void Mask(Coord pos) const; void Move(Coord from, Coord to) const; }; // Singleton that initializes and keep Pix's. class PixKeeper { static PixKeeper * singleton_; PixKeeper() {} ~PixKeeper(); PixKeeper(const PixKeeper &); // no copy PixKeeper & operator=(const PixKeeper &); // no copy typedef std::map PixCtn; PixCtn pixes_; public: static PixKeeper & Instance(); static void DestroyInstance(); const Pix * Get(const char *const * pix_data); }; #endif xgalaga++-0.8.4/config.h0000644000175000017500000000155110022777526013333 0ustar marcmarc#ifndef CONFIG_H #define CONFIG_H #include // Store configuration class Config { static Config * singleton_; enum { min_details = 0, max_details = 4 }; int details_level_; const std::string player_name_; const std::string score_file_name_; Config(); Config(const Config&); // no copy Config & operator=(const Config&); // no copy public: static Config & Instance(); static void DestroyInstance() { delete singleton_; singleton_ = 0; } void AddDetailsLevel(int); int ScaleDetails(int val) const { return val * details_level_ / max_details; } int MaxDetails() const { return max_details; } const std::string & GetPlayerName() const { return player_name_; } const std::string & GetScoreFileName() const { return score_file_name_; } }; // Resize window to standard size, 0 has no effect. void SetStandardWindowSize(unsigned win_size); #endif xgalaga++-0.8.4/explosion.h0000644000175000017500000000074510013273470014077 0ustar marcmarc#ifndef EXPLOSION_H #define EXPLOSION_H #include "gfxinterface.h" #include // An explosion is made of moving, color changing, dots. class Explosion { XColor color_; int moves_; const int duration_; typedef std::vector dotsCtn; dotsCtn dots_, dots_speed_; public: Explosion(Coord pos, Coord speed, XColor color, int duration = 24); void Move(); bool Finished() const { return moves_ >= duration_; } private: void DrawAll(X11::Color color) const; }; #endif