src/badguy/dispenser.cpp

Go to the documentation of this file.
00001 //  SuperTux
00002 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
00003 //
00004 //  This program is free software: you can redistribute it and/or modify
00005 //  it under the terms of the GNU General Public License as published by
00006 //  the Free Software Foundation, either version 3 of the License, or
00007 //  (at your option) any later version.
00008 //
00009 //  This program is distributed in the hope that it will be useful,
00010 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 //  GNU General Public License for more details.
00013 //
00014 //  You should have received a copy of the GNU General Public License
00015 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 
00017 #include "badguy/dispenser.hpp"
00018 
00019 #include "audio/sound_manager.hpp"
00020 #include "math/random_generator.hpp"
00021 #include "object/bullet.hpp"
00022 #include "object/player.hpp"
00023 #include "supertux/object_factory.hpp"
00024 #include "supertux/sector.hpp"
00025 #include "util/reader.hpp"
00026 
00027 #include <stdexcept>
00028 
00029 Dispenser::Dispenser(const Reader& reader) :
00030   BadGuy(reader, "images/creatures/dispenser/dispenser.sprite"),
00031   cycle(),
00032   badguys(),
00033   next_badguy(),
00034   dispense_timer(),
00035   autotarget(),
00036   swivel(),
00037   broken(),
00038   random(),
00039   type()
00040 {
00041   set_colgroup_active(COLGROUP_MOVING_STATIC);
00042   sound_manager->preload("sounds/squish.wav");
00043   reader.get("cycle", cycle);
00044   reader.get("badguy", badguys);
00045   random = false; // default
00046   reader.get("random", random);
00047   type = "dropper"; //default
00048   reader.get("type", type);
00049   next_badguy = 0;
00050   autotarget = false;
00051   swivel = false;
00052   broken = false;
00053 
00054   if (badguys.size() <= 0)
00055     throw std::runtime_error("No badguys in dispenser.");
00056 
00057   if (type == "rocketlauncher") {
00058     sprite->set_action(dir == LEFT ? "working-left" : "working-right");
00059     set_colgroup_active(COLGROUP_MOVING); //if this were COLGROUP_MOVING_STATIC MrRocket would explode on launch.
00060 
00061     if (start_dir == AUTO) {
00062       autotarget = true;
00063     }
00064   } else if (type == "cannon") {
00065     sprite->set_action("working");
00066   } else {
00067     sprite->set_action("dropper");
00068   }
00069 
00070   bbox.set_size(sprite->get_current_hitbox_width(), sprite->get_current_hitbox_height());
00071   countMe = false;
00072 }
00073 
00074 void
00075 Dispenser::activate()
00076 {
00077   if( broken ){
00078     return;
00079   }
00080   if( autotarget && !swivel ){ // auto cannon sprite might be wrong
00081     Player* player = this->get_nearest_player();
00082     if( player ){
00083       dir = (player->get_pos().x > get_pos().x) ? RIGHT : LEFT;
00084       sprite->set_action(dir == LEFT ? "working-left" : "working-right");
00085     }
00086   }
00087   dispense_timer.start(cycle, true);
00088   launch_badguy();
00089 }
00090 
00091 void
00092 Dispenser::deactivate()
00093 {
00094   dispense_timer.stop();
00095 }
00096 
00097 //TODO: Add launching velocity to certain badguys
00098 bool
00099 Dispenser::collision_squished(GameObject& object)
00100 {
00101   //Cannon launching MrRocket can be broken by jumping on it
00102   //other dispensers are not that fragile.
00103   if (broken || type != "rocketlauncher") {
00104     return false;
00105   }
00106 
00107   sprite->set_action(dir == LEFT ? "broken-left" : "broken-right");
00108   dispense_timer.start(0);
00109   set_colgroup_active(COLGROUP_MOVING_STATIC); // Tux can stand on broken cannon.
00110   Player* player = dynamic_cast<Player*>(&object);
00111   if (player){
00112     player->bounce(*this);
00113   }
00114   sound_manager->play("sounds/squish.wav", get_pos());
00115   broken = true;
00116   return true;
00117 }
00118 
00119 HitResponse
00120 Dispenser::collision(GameObject& other, const CollisionHit& hit)
00121 {
00122   Player* player = dynamic_cast<Player*> (&other);
00123   if(player) {
00124     // hit from above?
00125     if (player->get_bbox().p2.y < (bbox.p1.y + 16)) {
00126       collision_squished(*player);
00127       return FORCE_MOVE;
00128     }
00129     if(frozen){
00130       unfreeze();
00131     }
00132     return FORCE_MOVE;
00133   }
00134 
00135   Bullet* bullet = dynamic_cast<Bullet*> (&other);
00136   if(bullet){
00137     return collision_bullet(*bullet, hit);
00138   }
00139 
00140   return FORCE_MOVE;
00141 }
00142 
00143 void
00144 Dispenser::active_update(float )
00145 {
00146   if (dispense_timer.check()) {
00147     // auto always shoots in Tux's direction
00148     if( autotarget ){ 
00149       if( sprite->animation_done()) {
00150         sprite->set_action(dir == LEFT ? "working-left" : "working-right");
00151         swivel = false;
00152       }
00153 
00154       Player* player = this->get_nearest_player();
00155       if( player && !swivel ){
00156         Direction targetdir = (player->get_pos().x > get_pos().x) ? RIGHT : LEFT;
00157         if( dir != targetdir ){ // no target: swivel cannon 
00158           swivel = true;
00159           dir = targetdir;
00160           sprite->set_action(dir == LEFT ? "swivel-left" : "swivel-right", 1);
00161         } else { // tux in sight: shoot
00162           launch_badguy();
00163         }
00164       }
00165     } else {
00166       launch_badguy();
00167     }
00168   }
00169 }
00170 
00171 void
00172 Dispenser::launch_badguy()
00173 {
00174   //FIXME: Does is_offscreen() work right here?
00175   if (!is_offscreen()) {
00176     Direction launchdir = dir;
00177     if( !autotarget && start_dir == AUTO ){
00178       Player* player = this->get_nearest_player();
00179       if( player ){
00180         launchdir = (player->get_pos().x > get_pos().x) ? RIGHT : LEFT;
00181       } 
00182     } 
00183 
00184     if (badguys.size() > 1) {
00185       if (random) {
00186         next_badguy = gameRandom.rand(badguys.size());
00187       }
00188       else {
00189         next_badguy++;
00190 
00191         if (next_badguy >= badguys.size())
00192           next_badguy = 0;
00193       }
00194     }
00195 
00196     std::string badguy = badguys[next_badguy];
00197 
00198     if(badguy == "random") {
00199       log_warning << "random is outdated; use a list of badguys to select from." << std::endl;
00200       return;
00201     }
00202 
00203     try {
00204       GameObject *game_object;
00205       MovingObject *moving_object;
00206       Vector spawnpoint;
00207       Rectf object_bbox;
00208 
00209       /* Need to allocate the badguy first to figure out its bounding box. */
00210       game_object = ObjectFactory::instance().create(badguy, get_pos(), launchdir);
00211       if (game_object == NULL)
00212         throw std::runtime_error("Creating " + badguy + " object failed.");
00213 
00214       moving_object = dynamic_cast<MovingObject *> (game_object);
00215       if (moving_object == NULL)
00216         throw std::runtime_error(badguy + " is not a moving object.");
00217 
00218       object_bbox = moving_object->get_bbox ();
00219 
00220       if (type == "dropper") {
00221         spawnpoint = get_anchor_pos (get_bbox (), ANCHOR_BOTTOM);
00222         spawnpoint.x -= 0.5 * object_bbox.get_width ();
00223       }
00224       else if ((type == "cannon") || (type == "rocketlauncher")) {
00225         spawnpoint = get_pos (); /* top-left corner of the cannon */
00226         if (launchdir == LEFT)
00227           spawnpoint.x -= object_bbox.get_width () + 1;
00228         else
00229           spawnpoint.x += get_bbox ().get_width () + 1;
00230       }
00231 
00232       /* Now we set the real spawn position */
00233       moving_object->set_pos (spawnpoint);
00234 
00235       Sector::current()->add_object(moving_object);
00236     } catch(std::exception& e) {
00237       log_warning << "Error dispensing badguy: " << e.what() << std::endl;
00238       return;
00239     }
00240   }
00241 }
00242 
00243 void
00244 Dispenser::freeze()
00245 {
00246   BadGuy::freeze();
00247   dispense_timer.stop();
00248 }
00249 
00250 void
00251 Dispenser::unfreeze()
00252 {
00253   BadGuy::unfreeze();
00254   activate();
00255 }
00256 
00257 bool
00258 Dispenser::is_freezable() const
00259 {
00260   return true;
00261 }
00262 
00263 /* EOF */

Generated on Mon Jun 9 03:38:17 2014 for SuperTux by  doxygen 1.5.1