00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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;
00046 reader.get("random", random);
00047 type = "dropper";
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);
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 ){
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
00098 bool
00099 Dispenser::collision_squished(GameObject& object)
00100 {
00101
00102
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);
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
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
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 ){
00158 swivel = true;
00159 dir = targetdir;
00160 sprite->set_action(dir == LEFT ? "swivel-left" : "swivel-right", 1);
00161 } else {
00162 launch_badguy();
00163 }
00164 }
00165 } else {
00166 launch_badguy();
00167 }
00168 }
00169 }
00170
00171 void
00172 Dispenser::launch_badguy()
00173 {
00174
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
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 ();
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
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