src/worldmap/tux.cpp

Go to the documentation of this file.
00001 //  SuperTux -  A Jump'n Run
00002 //  Copyright (C) 2004 Ingo Ruhnke <grumbel@gmx.de>
00003 //  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
00004 //
00005 //  This program is free software: you can redistribute it and/or modify
00006 //  it under the terms of the GNU General Public License as published by
00007 //  the Free Software Foundation, either version 3 of the License, or
00008 //  (at your option) any later version.
00009 //
00010 //  This program is distributed in the hope that it will be useful,
00011 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 //  GNU General Public License for more details.
00014 //
00015 //  You should have received a copy of the GNU General Public License
00016 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017 
00018 #include "control/joystickkeyboardcontroller.hpp"
00019 #include "scripting/squirrel_util.hpp"
00020 #include "sprite/sprite.hpp"
00021 #include "sprite/sprite_manager.hpp"
00022 #include "supertux/globals.hpp"
00023 #include "supertux/player_status.hpp"
00024 #include "supertux/tile.hpp"
00025 #include "worldmap/level.hpp"
00026 #include "worldmap/tux.hpp"
00027 
00028 namespace worldmap {
00029 
00030 static const float TUXSPEED = 200;
00031 static const float map_message_TIME = 2.8f;
00032 
00033 Tux::Tux(WorldMap* worldmap_) :
00034   back_direction(),
00035   worldmap(worldmap_),
00036   sprite(),
00037   controller(),
00038   input_direction(),
00039   direction(),
00040   tile_pos(),
00041   offset(),
00042   moving(),
00043   ghost_mode()
00044 {
00045   sprite = sprite_manager->create("images/worldmap/common/tux.sprite");
00046 
00047   offset = 0;
00048   moving = false;
00049   direction = D_NONE;
00050   input_direction = D_NONE;
00051 
00052   ghost_mode = false;
00053 }
00054 
00055 Tux::~Tux()
00056 {
00057 }
00058 
00059 void
00060 Tux::draw(DrawingContext& context)
00061 {
00062   switch (worldmap->get_player_status()->bonus) {
00063     case GROWUP_BONUS:
00064       sprite->set_action(moving ? "large-walking" : "large-stop");
00065       break;
00066     case FIRE_BONUS:
00067       sprite->set_action(moving ? "fire-walking" : "fire-stop");
00068       break;
00069     case NO_BONUS:
00070       sprite->set_action(moving ? "small-walking" : "small-stop");
00071       break;
00072     default:
00073       log_debug << "Bonus type not handled in worldmap." << std::endl;
00074       sprite->set_action("large-stop");
00075       break;
00076   }
00077 
00078   sprite->draw(context, get_pos(), LAYER_OBJECTS);
00079 }
00080 
00081 Vector
00082 Tux::get_pos()
00083 {
00084   float x = tile_pos.x * 32;
00085   float y = tile_pos.y * 32;
00086 
00087   switch(direction)
00088   {
00089     case D_WEST:
00090       x -= offset - 32;
00091       break;
00092     case D_EAST:
00093       x += offset - 32;
00094       break;
00095     case D_NORTH:
00096       y -= offset - 32;
00097       break;
00098     case D_SOUTH:
00099       y += offset - 32;
00100       break;
00101     case D_NONE:
00102       break;
00103   }
00104 
00105   return Vector(x, y);
00106 }
00107 
00108 void
00109 Tux::stop()
00110 {
00111   offset = 0;
00112   direction = D_NONE;
00113   input_direction = D_NONE;
00114   moving = false;
00115 }
00116 
00117 void
00118 Tux::set_direction(Direction dir)
00119 {
00120   input_direction = dir;
00121 }
00122 
00123 void
00124 Tux::set_ghost_mode(bool enabled)
00125 {
00126   ghost_mode = enabled;
00127 }
00128 
00129 bool
00130 Tux::get_ghost_mode()
00131 {
00132   return ghost_mode;
00133 }
00134 
00135 void
00136 Tux::tryStartWalking()
00137 {
00138   if (moving)
00139     return;
00140   if (input_direction == D_NONE)
00141     return;
00142 
00143   LevelTile* level = worldmap->at_level();
00144 
00145   // We got a new direction, so lets start walking when possible
00146   Vector next_tile;
00147   if ((!level || level->solved)
00148       && worldmap->path_ok(input_direction, tile_pos, &next_tile)) {
00149     tile_pos = next_tile;
00150     moving = true;
00151     direction = input_direction;
00152     back_direction = reverse_dir(direction);
00153   } else if (ghost_mode || (input_direction == back_direction)) {
00154     moving = true;
00155     direction = input_direction;
00156     tile_pos = worldmap->get_next_tile(tile_pos, direction);
00157     back_direction = reverse_dir(direction);
00158   }
00159 }
00160 
00161 bool
00162 Tux::canWalk(int tile_data, Direction dir)
00163 {
00164   return ghost_mode || 
00165     ((tile_data & Tile::WORLDMAP_NORTH && dir == D_NORTH) ||
00166      (tile_data & Tile::WORLDMAP_SOUTH && dir == D_SOUTH) ||
00167      (tile_data & Tile::WORLDMAP_EAST  && dir == D_EAST) ||
00168      (tile_data & Tile::WORLDMAP_WEST  && dir == D_WEST));
00169 }
00170 
00171 void
00172 Tux::tryContinueWalking(float elapsed_time)
00173 {
00174   if (!moving)
00175     return;
00176 
00177   // Let tux walk
00178   offset += TUXSPEED * elapsed_time;
00179 
00180   // Do nothing if we have not yet reached the next tile
00181   if (offset <= 32)
00182     return;
00183 
00184   offset -= 32;
00185 
00186   SpriteChange* sprite_change = worldmap->at_sprite_change(tile_pos);
00187   if(sprite_change != NULL) {
00188     sprite = sprite_change->sprite->clone();
00189     sprite_change->clear_stay_action();
00190   }
00191 
00192   // if this is a special_tile with passive_message, display it
00193   SpecialTile* special_tile = worldmap->at_special_tile();
00194   if(special_tile)
00195   {
00196     // direction and the apply_action_ are opposites, since they "see"
00197     // directions in a different way
00198     if((direction == D_NORTH && special_tile->apply_action_south) ||
00199        (direction == D_SOUTH && special_tile->apply_action_north) ||
00200        (direction == D_WEST && special_tile->apply_action_east) ||
00201        (direction == D_EAST && special_tile->apply_action_west))
00202     {
00203       if(special_tile->passive_message) {
00204         worldmap->passive_message = special_tile->map_message;
00205         worldmap->passive_message_timer.start(map_message_TIME);
00206       } else if(special_tile->script != "") {
00207         try {
00208           std::istringstream in(special_tile->script);
00209           worldmap->run_script(in, "specialtile");
00210         } catch(std::exception& e) {
00211           log_warning << "Couldn't execute special tile script: " << e.what()
00212                       << std::endl;
00213         }
00214       }
00215     }
00216   }
00217 
00218   // check if we are at a Teleporter
00219   Teleporter* teleporter = worldmap->at_teleporter(tile_pos);
00220 
00221   // stop if we reached a level, a WORLDMAP_STOP tile, a teleporter or a special tile without a passive_message
00222   if ((worldmap->at_level())
00223       || (worldmap->tile_data_at(tile_pos) & Tile::WORLDMAP_STOP)
00224       || (special_tile && !special_tile->passive_message
00225           && special_tile->script == "")
00226       || (teleporter) || ghost_mode) {
00227     if(special_tile && !special_tile->map_message.empty()
00228        && !special_tile->passive_message)
00229       worldmap->passive_message_timer.start(0);
00230     stop();
00231     return;
00232   }
00233 
00234   // if user wants to change direction, try changing, else guess the direction in which to walk next
00235   const int tile_data = worldmap->tile_data_at(tile_pos);
00236   if ((direction != input_direction) && canWalk(tile_data, input_direction)) {
00237     direction = input_direction;
00238     back_direction = reverse_dir(direction);
00239   } else {
00240     Direction dir = D_NONE;
00241     if (tile_data & Tile::WORLDMAP_NORTH && back_direction != D_NORTH)
00242       dir = D_NORTH;
00243     else if (tile_data & Tile::WORLDMAP_SOUTH && back_direction != D_SOUTH)
00244       dir = D_SOUTH;
00245     else if (tile_data & Tile::WORLDMAP_EAST && back_direction != D_EAST)
00246       dir = D_EAST;
00247     else if (tile_data & Tile::WORLDMAP_WEST && back_direction != D_WEST)
00248       dir = D_WEST;
00249 
00250     if (dir == D_NONE) {
00251       // Should never be reached if tiledata is good
00252       log_warning << "Could not determine where to walk next" << std::endl;
00253       stop();
00254       return;
00255     }
00256 
00257     direction = dir;
00258     input_direction = direction;
00259     back_direction = reverse_dir(direction);
00260   }
00261 
00262   // Walk automatically to the next tile
00263   if(direction == D_NONE)
00264     return;
00265 
00266   Vector next_tile;
00267   if (!ghost_mode && !worldmap->path_ok(direction, tile_pos, &next_tile)) {
00268     log_debug << "Tilemap data is buggy" << std::endl;
00269     stop();
00270     return;
00271   }
00272 
00273   SpriteChange* next_sprite = worldmap->at_sprite_change(next_tile);
00274   if(next_sprite != NULL && next_sprite->change_on_touch) {
00275     sprite = next_sprite->sprite->clone();
00276     next_sprite->clear_stay_action();
00277   }
00278   SpriteChange* last_sprite = worldmap->at_sprite_change(tile_pos);
00279   if(last_sprite != NULL && next_sprite != NULL) {
00280     log_debug << "Old: " << tile_pos << " New: " << next_tile << std::endl;
00281     last_sprite->set_stay_action();
00282   }
00283 
00284   tile_pos = next_tile;
00285 }
00286 
00287 void
00288 Tux::updateInputDirection()
00289 {
00290   Controller *controller = g_jk_controller->get_main_controller();
00291   if(controller->hold(Controller::UP))
00292     input_direction = D_NORTH;
00293   else if(controller->hold(Controller::DOWN))
00294     input_direction = D_SOUTH;
00295   else if(controller->hold(Controller::LEFT))
00296     input_direction = D_WEST;
00297   else if(controller->hold(Controller::RIGHT))
00298     input_direction = D_EAST;
00299 }
00300 
00301 void
00302 Tux::update(float elapsed_time)
00303 {
00304   updateInputDirection();
00305   if (moving)
00306     tryContinueWalking(elapsed_time);
00307   else
00308     tryStartWalking();
00309 }
00310 
00311 void
00312 Tux::setup()
00313 {
00314   // check if we already touch a SpriteChange object
00315   SpriteChange* sprite_change = worldmap->at_sprite_change(tile_pos);
00316   if(sprite_change != NULL) {
00317     sprite = sprite_change->sprite->clone();
00318     sprite_change->clear_stay_action();
00319   }
00320 }
00321 
00322 } // namespace WorldmapNS
00323 
00324 /* EOF */

Generated on Mon Apr 21 03:38:19 2014 for SuperTux by  doxygen 1.5.1