00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
00178 offset += TUXSPEED * elapsed_time;
00179
00180
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
00193 SpecialTile* special_tile = worldmap->at_special_tile();
00194 if(special_tile)
00195 {
00196
00197
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
00219 Teleporter* teleporter = worldmap->at_teleporter(tile_pos);
00220
00221
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
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
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
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
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 }
00323
00324