frame += frame_inc;
- if(frame > get_frames()) {
+ if(frame >= get_frames()) {
frame = fmodf(frame+get_frames(), get_frames());
animation_loops--;
+++ /dev/null
-// $Id$
-//
-// SuperTux - A Jump'n Run
-// Copyright (C) 2004 Matthias Braun <matze@braunis.de
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-#include <config.h>
-
-#include "background.h"
-#include "app/globals.h"
-#include "camera.h"
-#include "video/drawing_context.h"
-#include "utils/lispwriter.h"
-
-Background::Background()
- : type(INVALID), layer(LAYER_BACKGROUND0), image(0)
-{
-}
-
-Background::Background(LispReader& reader)
- : type(INVALID), layer(LAYER_BACKGROUND0), image(0)
-{
- reader.read_int("layer", layer);
- if(reader.read_string("image", imagefile)
- && reader.read_float("speed", speed)) {
- set_image(imagefile, speed);
- }
-
- std::vector <unsigned int> bkgd_top_color, bkgd_bottom_color;
- if(reader.read_int_vector("top_color", bkgd_top_color) &&
- reader.read_int_vector("bottom_color", bkgd_bottom_color))
- set_gradient(Color(bkgd_top_color), Color(bkgd_bottom_color));
-}
-
-Background::~Background()
-{
- printf("bgfree.\n");
- delete image;
-}
-
-void
-Background::write(LispWriter& writer)
-{
- if(type == INVALID)
- return;
-
- writer.start_list("background");
-
- if(type == IMAGE) {
- writer.write_string("image", imagefile);
- writer.write_float("speed", speed);
- } else if(type == GRADIENT) {
- std::vector <unsigned int> bkgd_top_color, bkgd_bottom_color;
- bkgd_top_color.push_back(gradient_top.red);
- bkgd_top_color.push_back(gradient_top.green);
- bkgd_top_color.push_back(gradient_top.blue);
- bkgd_bottom_color.push_back(gradient_top.red);
- bkgd_bottom_color.push_back(gradient_top.green);
- bkgd_bottom_color.push_back(gradient_top.blue);
- writer.write_int_vector("top_color", bkgd_top_color);
- writer.write_int_vector("bottom_color", bkgd_bottom_color);
- }
- writer.write_int("layer", layer);
-
- writer.end_list("background");
-}
-
-void
-Background::action(float)
-{
-}
-
-void
-Background::set_image(const std::string& name, float speed)
-{
- this->type = IMAGE;
- this->imagefile = name;
- this->speed = speed;
-
- printf("seti %p\n", this);
- delete image;
- image = new Surface(datadir + "/images/background/" + name, false);
-}
-
-void
-Background::set_gradient(Color top, Color bottom)
-{
- type = GRADIENT;
- gradient_top = top;
- gradient_bottom = bottom;
-
- delete image;
- image = new Surface(top, bottom, screen->w, screen->h);
-}
-
-void
-Background::draw(DrawingContext& context)
-{
- if(type == GRADIENT) {
- context.push_transform();
- context.set_translation(Vector(0, 0));
- context.draw_surface(image, Vector(0, 0), layer);
- context.pop_transform();
- } else if(type == IMAGE) {
- if(!image)
- return;
-
- int sx = int(-context.get_translation().x * speed) % image->w - image->w;
- int sy = int(-context.get_translation().y * speed) % image->h - image->h;
- context.push_transform();
- context.set_translation(Vector(0, 0));
- for(int x = sx; x < screen->w; x += image->w)
- for(int y = sy; y < screen->h; y += image->h)
- context.draw_surface(image, Vector(x, y), layer);
- context.pop_transform();
- }
-}
-
+++ /dev/null
-// $Id$
-//
-// SuperTux - A Jump'n Run
-// Copyright (C) 2004 Matthias Braun <matze@braunis.de
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-#ifndef SUPERTUX_BACKGROUND_H
-#define SUPERTUX_BACKGROUND_H
-
-#include "video/surface.h"
-#include "video/drawing_context.h"
-#include "special/game_object.h"
-#include "utils/lispreader.h"
-#include "serializable.h"
-
-class DisplayManager;
-
-class Background : public GameObject, public Serializable
-{
-public:
- Background();
- Background(LispReader& reader);
- virtual ~Background();
-
- virtual void write(LispWriter& writer);
-
- void set_image(const std::string& name, float bkgd_speed);
-
- void set_gradient(Color top, Color bottom);
-
- std::string get_image() const
- { return imagefile; }
- float get_speed() const
- { return speed; }
- Color get_gradient_top() const
- { return gradient_top; }
- Color get_gradient_bottom() const
- { return gradient_bottom; }
-
- virtual void action(float elapsed_time);
-
- virtual void draw(DrawingContext& context);
-
-private:
- enum Type {
- INVALID, GRADIENT, IMAGE
- };
-
- Type type;
- int layer;
- std::string imagefile;
- float speed;
- Surface* image;
- Color gradient_top, gradient_bottom;
-};
-
-#endif /*SUPERTUX_BACKGROUND_H*/
-
#include <config.h>
#include "badguy.h"
-#include "camera.h"
+#include "object/camera.h"
static const float SQUISH_TIME = 2;
static const float X_OFFSCREEN_DISTANCE = 1600;
#include "special/moving_object.h"
#include "special/sprite.h"
#include "math/physic.h"
-#include "player.h"
+#include "object/player.h"
#include "serializable.h"
#include "resources.h"
#include "sector.h"
+++ /dev/null
-// $Id$
-//
-// SuperTux - A Jump'n Run
-// Copyright (C) 2004 Matthias Braun <matze@braunis.de
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-#include <config.h>
-
-#include <stdexcept>
-#include <sstream>
-#include <cmath>
-
-#include "camera.h"
-#include "utils/lispreader.h"
-#include "utils/lispwriter.h"
-#include "player.h"
-#include "tilemap.h"
-#include "gameloop.h"
-#include "app/globals.h"
-#include "sector.h"
-
-using namespace SuperTux;
-
-Camera::Camera(Sector* newsector)
- : sector(newsector), do_backscrolling(true), scrollchange(NONE),
- auto_idx(0), auto_t(0)
-{
- mode = NORMAL;
-}
-
-Camera::~Camera()
-{
-}
-
-const Vector&
-Camera::get_translation() const
-{
- return translation;
-}
-
-void
-Camera::parse(LispReader& reader)
-{
- std::string modename;
-
- reader.read_string("mode", modename);
- if(modename == "normal") {
- mode = NORMAL;
-
- do_backscrolling = true;
- reader.read_bool("backscrolling", do_backscrolling);
- } else if(modename == "autoscroll") {
- mode = AUTOSCROLL;
-
- lisp_object_t* cur = 0;
- reader.read_lisp("path", cur);
- if(cur == 0) {
- throw std::runtime_error("No path specified in autoscroll camera.");
- }
- float speed = 50;
- while(!lisp_nil_p(cur)) {
- if(strcmp(lisp_symbol(lisp_car(lisp_car(cur))), "point") != 0) {
- std::cerr << "Warning: unknown token in camera path.\n";
- continue;
- }
-
- LispReader reader(lisp_cdr(lisp_car(cur)));
-
- ScrollPoint point;
- if(!reader.read_float("x", point.position.x) ||
- !reader.read_float("y", point.position.y)) {
- throw std::runtime_error("x and y missing in point of camerapath");
- }
- reader.read_float("speed", speed);
- point.speed = speed;
- scrollpoints.push_back(point);
-
- cur = lisp_cdr(cur);
- }
- } else if(modename == "manual") {
- mode = MANUAL;
- } else {
- std::stringstream str;
- str << "invalid camera mode '" << modename << "'found in worldfile.";
- throw std::runtime_error(str.str());
- }
-}
-
-void
-Camera::write(LispWriter& writer)
-{
- writer.start_list("camera");
-
- if(mode == NORMAL) {
- writer.write_string("mode", "normal");
- writer.write_bool("backscrolling", do_backscrolling);
- } else if(mode == AUTOSCROLL) {
- writer.write_string("mode", "autoscroll");
- writer.start_list("path");
- for(std::vector<ScrollPoint>::iterator i = scrollpoints.begin();
- i != scrollpoints.end(); ++i) {
- writer.start_list("point");
- writer.write_float("x", i->position.x);
- writer.write_float("y", i->position.y);
- writer.write_float("speed", i->speed);
- writer.end_list("point");
- }
-
- writer.end_list("path");
- } else if(mode == MANUAL) {
- writer.write_string("mode", "manual");
- }
-
- writer.end_list("camera");
-}
-
-void
-Camera::reset(const Vector& tuxpos)
-{
- translation.x = tuxpos.x - screen->w/3 * 2;
- translation.y = tuxpos.y - screen->h/2;
- keep_in_bounds();
-}
-
-static const float EPSILON = .00001;
-static const float max_speed_y = 140;
-
-void
-Camera::action(float elapsed_time)
-{
- if(mode == NORMAL)
- scroll_normal(elapsed_time);
- else if(mode == AUTOSCROLL)
- scroll_autoscroll(elapsed_time);
-}
-
-void
-Camera::keep_in_bounds()
-{
- float width = sector->solids->get_width() * 32;
- float height = sector->solids->get_height() * 32;
-
- // don't scroll before the start or after the level's end
- if(translation.y > height - screen->h)
- translation.y = height - screen->h;
- if(translation.y < 0)
- translation.y = 0;
- if(translation.x > width - screen->w)
- translation.x = width - screen->w;
- if(translation.x < 0)
- translation.x = 0;
-}
-
-void
-Camera::scroll_normal(float elapsed_time)
-{
- assert(sector != 0);
- Player* player = sector->player;
-
- // check that we don't have division by zero later
- if(elapsed_time < EPSILON)
- return;
-
- /****** Vertical Scrolling part ******/
- bool do_y_scrolling = true;
-
- if(player->dying || sector->solids->get_height() == 19)
- do_y_scrolling = false;
-
- if(do_y_scrolling) {
- // target_y is the high we target our scrolling at. This is not always the
- // high of the player, but if he is jumping upwards we should use the
- // position where he last touched the ground. (this probably needs
- // exceptions for trampolines and similar things in the future)
- float target_y;
- if(player->fall_mode == Player::JUMPING)
- target_y = player->last_ground_y + player->get_bbox().get_height();
- else
- target_y = player->get_bbox().p2.y;
-
- // delta_y is the distance we'd have to travel to directly reach target_y
- float delta_y = translation.y - (target_y - screen->h/2);
- // speed is the speed the camera would need to reach target_y in this frame
- float speed_y = delta_y / elapsed_time;
-
- // limit the camera speed when jumping upwards
- if(player->fall_mode != Player::FALLING
- && player->fall_mode != Player::TRAMPOLINE_JUMP) {
- if(speed_y > max_speed_y)
- speed_y = max_speed_y;
- else if(speed_y < -max_speed_y)
- speed_y = -max_speed_y;
- }
-
- // finally scroll with calculated speed
- translation.y -= speed_y * elapsed_time;
- }
-
- /****** Horizontal scrolling part *******/
-
- // our camera is either in leftscrolling, rightscrolling or nonscrollingmode.
-
- // when suddenly changing directions while scrolling into the other direction.
- // abort scrolling, since tux might be going left/right at a relatively small
- // part of the map (like when jumping upwards)
- if((player->dir == ::LEFT && scrollchange == RIGHT)
- || (player->dir == ::RIGHT && scrollchange == LEFT))
- scrollchange = NONE;
- // when in left 1/3rd of screen scroll left
- if(player->get_bbox().get_middle().x < translation.x + screen->w/3 - 16
- && do_backscrolling)
- scrollchange = LEFT;
- // scroll right when in right 1/3rd of screen
- else if(player->get_bbox().get_middle().x > translation.x + screen->w/3*2+16)
- scrollchange = RIGHT;
-
- // calculate our scroll target depending on scroll mode
- float target_x;
- if(scrollchange == LEFT)
- target_x = player->get_bbox().get_middle().x - screen->w/3*2;
- else if(scrollchange == RIGHT)
- target_x = player->get_bbox().get_middle().x - screen->w/3;
- else
- target_x = translation.x;
-
- // that's the distance we would have to travel to reach target_x
- float delta_x = translation.x - target_x;
- // the speed we'd need to travel to reach target_x in this frame
- float speed_x = delta_x / elapsed_time;
-
- // limit our speed
- float maxv = 130 + (fabsf(player->physic.get_velocity_x() * 1.3));
- if(speed_x > maxv)
- speed_x = maxv;
- else if(speed_x < -maxv)
- speed_x = -maxv;
-
- // apply scrolling
- translation.x -= speed_x * elapsed_time;
-
- keep_in_bounds();
-}
-
-void
-Camera::scroll_autoscroll(float elapsed_time)
-{
- Player* player = sector->player;
-
- if(player->dying)
- return;
-
- if(auto_t - elapsed_time >= 0) {
- translation += current_dir * elapsed_time;
- auto_t -= elapsed_time;
- } else {
- // do the rest of the old movement
- translation += current_dir * auto_t;
- elapsed_time -= auto_t;
- auto_t = 0;
-
- // construct path for next point
- if(auto_idx+1 >= scrollpoints.size()) {
- keep_in_bounds();
- return;
- }
- Vector distance = scrollpoints[auto_idx+1].position
- - scrollpoints[auto_idx].position;
- current_dir = distance.unit() * scrollpoints[auto_idx].speed;
- auto_t = distance.norm() / scrollpoints[auto_idx].speed;
-
- // do movement for the remaining time
- translation += current_dir * elapsed_time;
- auto_t -= elapsed_time;
- auto_idx++;
- }
-
- keep_in_bounds();
-}
+++ /dev/null
-// $Id$
-//
-// SuperTux - A Jump'n Run
-// Copyright (C) 2004 Matthias Braun <matze@braunis.de
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-#ifndef SUPERTUX_CAMERA_H
-#define SUPERTUX_CAMERA_H
-
-#include <vector>
-#include <cassert>
-
-#include "defines.h"
-#include "math/vector.h"
-#include "special/game_object.h"
-#include "video/drawing_context.h"
-#include "serializable.h"
-
-using namespace SuperTux;
-
-namespace SuperTux {
-class LispReader;
-}
-
-class Sector;
-
-class Camera : public GameObject, public Serializable
-{
-public:
- Camera(Sector* sector);
- virtual ~Camera();
-
- /// parse camera mode from lisp file
- void parse(LispReader& reader);
- /// write camera mode to a lisp file
- virtual void write(LispWriter& writer);
-
- /// reset camera postion
- virtual void reset(const Vector& tuxpos);
-
- /** @deprecated@ */
- const Vector& get_translation() const;
-
- virtual void action(float elapsed_time);
-
- virtual void draw(DrawingContext& )
- {
- }
-
- void set_scrolling(int scroll_x, int scroll_y)
- {
- translation.x = scroll_x;
- translation.y = scroll_y;
- }
-
- enum CameraMode
- {
- NORMAL, AUTOSCROLL, MANUAL
- };
- CameraMode mode;
-
-private:
- void scroll_normal(float elapsed_time);
- void scroll_autoscroll(float elapsed_time);
- void keep_in_bounds();
-
- enum LeftRightScrollChange
- {
- NONE, LEFT, RIGHT
- };
-
- Vector translation;
-
- Sector* sector;
-
- // normal mode
- bool do_backscrolling;
- LeftRightScrollChange scrollchange;
-
- // autoscroll mode
- class ScrollPoint {
- public:
- Vector position;
- float speed;
- };
- std::vector<ScrollPoint> scrollpoints;
- size_t auto_idx;
- float auto_t;
- Vector current_dir;
-};
-
-#endif /*SUPERTUX_CAMERA_H*/
-
#include "high_scores.h"
#include "gui/menu.h"
#include "sector.h"
-#include "player.h"
#include "level.h"
#include "scene.h"
#include "tile.h"
-#include "particlesystem.h"
+#include "object/particlesystem.h"
+#include "object/background.h"
+#include "object/tilemap.h"
+#include "object/camera.h"
+#include "object/player.h"
#include "resources.h"
-#include "background.h"
-#include "tilemap.h"
#include "app/gettext.h"
#include "worldmap.h"
#include "intro.h"
#include "misc.h"
-#include "camera.h"
#include "statistics.h"
#include "timer.h"
#include "object/fireworks.h"
+++ /dev/null
-// $Id$
-//
-// SuperTux
-// Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
-// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-// 02111-1307, USA.
-#include <config.h>
-
-#include <algorithm>
-#include <iostream>
-#include <cmath>
-
-#include "app/globals.h"
-#include "tile.h"
-#include "tile_manager.h"
-#include "gameloop.h"
-#include "gameobjs.h"
-#include "special/sprite_manager.h"
-#include "resources.h"
-#include "sector.h"
-#include "tilemap.h"
-#include "video/drawing_context.h"
-#include "camera.h"
-
-BouncyCoin::BouncyCoin(const Vector& pos)
- : position(pos)
-{
- timer.start(.3);
- sprite = sprite_manager->create("coin");
- sprite->set_action("still");
-}
-
-BouncyCoin::~BouncyCoin()
-{
- delete sprite;
-}
-
-void
-BouncyCoin::action(float elapsed_time)
-{
- position.y += -200 * elapsed_time;
-
- if(timer.check())
- remove_me();
-}
-
-void
-BouncyCoin::draw(DrawingContext& context)
-{
- sprite->draw(context, position, LAYER_OBJECTS);
-}
-
-//---------------------------------------------------------------------------
-
-BrokenBrick::BrokenBrick(Sprite* nsprite,
- const Vector& pos, const Vector& nmovement)
- : sprite(new Sprite(*nsprite)), position(pos), movement(nmovement)
-{
- timer.start(.2);
-}
-
-BrokenBrick::~BrokenBrick()
-{
- delete sprite;
-}
-
-void
-BrokenBrick::action(float elapsed_time)
-{
- position += movement * elapsed_time;
-
- if (timer.check())
- remove_me();
-}
-
-void
-BrokenBrick::draw(DrawingContext& context)
-{
- sprite->draw_part(context,
- Vector(rand() % 16, rand() % 16), Vector(16, 16),
- position, LAYER_OBJECTS + 1);
-}
-
-//---------------------------------------------------------------------------
-
-FloatingText::FloatingText(const Vector& pos, const std::string& text_)
- : position(pos), text(text_)
-{
- timer.start(.1);
- position.x -= text.size() * 8;
-}
-
-FloatingText::FloatingText(const Vector& pos, int score)
- : position(pos)
-{
- timer.start(.1);
-
- // turn int into a string
- char str[10];
- snprintf(str, 10, "%d", score);
- text = str;
-
- position.x -= text.size() * 8;
-}
-
-void
-FloatingText::action(float elapsed_time)
-{
- position.y -= 1.4 * elapsed_time;
-
- if(timer.check())
- remove_me();
-}
-
-#define FADING_TIME .350
-
-void
-FloatingText::draw(DrawingContext& context)
-{
- // make an alpha animation when disapearing
- int alpha;
- if(timer.get_timeleft() < FADING_TIME)
- alpha = int(timer.get_timeleft() * 255 / FADING_TIME);
- else
- alpha = 255;
-
- context.push_transform();
- context.set_alpha(alpha);
-
- context.draw_text(gold_text, text, position, LEFT_ALLIGN, LAYER_OBJECTS+1);
-
- context.pop_transform();
-}
-
-/* Trampoline */
-
-#if 0
-Sprite *img_trampoline;
-
-Trampoline::Trampoline(LispReader& reader)
-{
- reader.read_float("x", base.x);
- reader.read_float("y", base.y);
- base.width = 32;
- base.height = 32;
- power = 7.5;
- reader.read_float("power", power);
-
- frame = 0;
- mode = M_NORMAL;
- physic.reset();
-}
-
-Trampoline::Trampoline(float x, float y)
-{
- base.x = x;
- base.y = y;
- base.width = 32;
- base.height = 32;
- power = 7.5;
-
- frame = 0;
- mode = M_NORMAL;
- physic.reset();
-}
-
-void
-Trampoline::write(LispWriter& writer)
-{
- writer.start_list("trampoline");
-
- writer.write_float("x", base.x);
- writer.write_float("y", base.y);
- writer.write_float("power", power);
-
- writer.end_list("trampoline");
-}
-
-void
-Trampoline::draw(DrawingContext& context)
-{
- img_trampoline->set_frame(frame);
- img_trampoline->draw(context, base, LAYER_OBJECTS);
- frame = 0;
-}
-
-void
-Trampoline::action(float frame_ratio)
-{
- // TODO: Remove if we're too far off the screen
-
- // Falling
- if (mode != M_HELD)
- {
- if (issolid(base.x + base.width/2, base.y + base.height))
- {
- base.y = int((base.y + base.height)/32) * 32 - base.height;
-
- physic.enable_gravity(false);
- physic.set_velocity_y(0.0f);
-
- physic.set_velocity_x(0);
- }
- else
- {
- physic.enable_gravity(true);
- }
- }
- else // Player is carrying us around
- {
- /* FIXME: The trampoline object shouldn't know about pplayer objects. */
- /* If we're holding the iceblock */
- Player& tux = *Sector::current()->player;
- Direction dir = tux.dir;
-
- if(dir == RIGHT)
- {
- base.x = tux.base.x + 16;
- base.y = tux.base.y + tux.base.height/1.5 - base.height;
- }
- else /* facing left */
- {
- base.x = tux.base.x - 16;
- base.y = tux.base.y + tux.base.height/1.5 - base.height;
- }
-
- if(collision_object_map(base))
- {
- base.x = tux.base.x;
- base.y = tux.base.y + tux.base.height/1.5 - base.height;
- }
- }
-
- physic.apply(frame_ratio, base.x, base.y, Sector::current()->gravity);
- collision_swept_object_map(&old_base, &base);
-}
-
-void
-Trampoline::collision(const MovingObject&, int)
-{
- // comes later
-}
-
-void
-Trampoline::collision(void *p_c_object, int c_object, CollisionType type)
-{
- Player* pplayer_c = NULL;
- switch (c_object)
- {
- case CO_PLAYER:
- pplayer_c = (Player*) p_c_object;
-
- if (type == COLLISION_NORMAL)
- {
- // Pick up if HELD (done in Player)
- }
-
- else if (type == COLLISION_SQUISH)
- {
- int squish_amount = (32 - (int)pplayer_c->base.y % 32);
-
- if (squish_amount < 24)
- frame = 3;
- else if (squish_amount < 28)
- frame = 2;
- else if (squish_amount < 30)
- frame = 1;
- else
- frame = 0;
-
- if (squish_amount < 20) {
- pplayer_c->physic.set_velocity_y(power);
- pplayer_c->fall_mode = Player::TRAMPOLINE_JUMP;
- }
- else if (pplayer_c->physic.get_velocity_y() < 0)
- pplayer_c->physic.set_velocity_y(-squish_amount/32);
- }
-
- break;
-
- default:
- break;
-
- }
-}
-#endif
-
-/* Flying Platform */
-
-#if 0
-Sprite *img_flying_platform;
-
-FlyingPlatform::FlyingPlatform(LispReader& reader)
-{
- reader.read_int_vector("x", pos_x);
- reader.read_int_vector("y", pos_y);
-
- velocity = 2.0;
- reader.read_float("velocity", velocity);
-
- base.x = pos_x[0];
- base.y = pos_y[0];
- base.width = 96;
- base.height = 40;
-
- point = 0;
- move = false;
-
- float x = pos_x[point+1] - pos_x[point];
- float y = pos_y[point+1] - pos_y[point];
- vel_x = x*velocity / sqrt(x*x + y*y);
- vel_y = -(velocity - vel_x);
-
- frame = 0;
-}
-
-FlyingPlatform::FlyingPlatform(int x, int y)
-{
-base.x = x;
-base.y = y;
-point = 0;
-move = false;
-}
-
-void
-FlyingPlatform::write(LispWriter& writer)
-{
- writer.start_list("flying-trampoline");
-
- writer.write_int_vector("x", pos_x);
- writer.write_int_vector("y", pos_y);
- writer.write_float("velocity", velocity);
-
- writer.end_list("flying-trampoline");
-}
-
-void
-FlyingPlatform::draw(DrawingContext& context)
-{
- img_flying_platform->draw(context, base, LAYER_OBJECTS);
-}
-
-void
-FlyingPlatform::action(float frame_ratio)
-{
- // TODO: Remove if we're too far off the screen
-
-if(!move)
- return;
-
-if((unsigned)point+1 != pos_x.size())
- {
- if(((pos_x[point+1] > pos_x[point] && base.x >= pos_x[point+1]) ||
- (pos_x[point+1] < pos_x[point] && base.x <= pos_x[point+1]) ||
- pos_x[point] == pos_x[point+1]) &&
- ((pos_y[point+1] > pos_y[point] && base.y >= pos_y[point+1]) ||
- (pos_y[point+1] < pos_y[point] && base.y <= pos_y[point+1]) ||
- pos_y[point] == pos_y[point+1]))
- {
- point++;
-
- float x = pos_x[point+1] - pos_x[point];
- float y = pos_y[point+1] - pos_y[point];
- vel_x = x*velocity / sqrt(x*x + y*y);
- vel_y = -(velocity - vel_x);
- }
- }
-else // last point
- {
- // point = 0;
- // reverse vector
- return;
- }
-/*
-if(pos_x[point+1] > base.x)
- base.x += velocity * frame_ratio;
-else if(pos_x[point+1] < base.x)
- base.x -= velocity * frame_ratio;
-
-if(pos_y[point+1] > base.y)
- base.y += velocity * frame_ratio;
-else if(pos_y[point+1] < base.y)
- base.y -= velocity * frame_ratio;
-*/
-
-base.x += vel_x * frame_ratio;
-base.y += vel_y * frame_ratio;
-}
-
-void
-FlyingPlatform::collision(const MovingObject&, int)
-{
- // comes later
-}
-
-void
-FlyingPlatform::collision(void *p_c_object, int c_object, CollisionType type)
-{
-(void) p_c_object;
-(void) type;
-
-// Player* pplayer_c = NULL;
- switch (c_object)
- {
- case CO_PLAYER:
-// pplayer_c = (Player*) p_c_object;
- move = true;
-
- break;
-
- default:
- break;
-
- }
-}
-#endif
-
-Sprite *img_smoke_cloud = 0;
-
-SmokeCloud::SmokeCloud(const Vector& pos)
- : position(pos)
-{
- timer.start(.3);
-}
-
-void
-SmokeCloud::action(float elapsed_time)
-{
- position.y -= 120 * elapsed_time;
-
- if(timer.check())
- remove_me();
-}
-
-void
-SmokeCloud::draw(DrawingContext& context)
-{
- img_smoke_cloud->draw(context, position, LAYER_OBJECTS+1);
-}
-
-Particles::Particles(const Vector& epicenter, int min_angle, int max_angle,
- const Vector& initial_velocity, const Vector& acceleration, int number,
- Color color_, int size_, float life_time, int drawing_layer_)
- : accel(acceleration), color(color_), size(size_), drawing_layer(drawing_layer_)
-{
- if(life_time == 0) {
- live_forever = true;
- } else {
- live_forever = false;
- timer.start(life_time);
- }
-
- // create particles
- for(int p = 0; p < number; p++)
- {
- Particle* particle = new Particle;
- particle->pos = epicenter;
-
- float angle = ((rand() % (max_angle-min_angle))+min_angle)
- * (M_PI / 180); // convert to radius
- particle->vel.x = /*fabs*/(sin(angle)) * initial_velocity.x;
-// if(angle >= M_PI && angle < M_PI*2)
-// particle->vel.x *= -1; // work around to fix signal
- particle->vel.y = /*fabs*/(cos(angle)) * initial_velocity.y;
-// if(angle >= M_PI_2 && angle < 3*M_PI_2)
-// particle->vel.y *= -1;
-
- particles.push_back(particle);
- }
-}
-
-Particles::~Particles()
-{
- // free particles
- for(std::vector<Particle*>::iterator i = particles.begin();
- i < particles.end(); i++)
- delete (*i);
-}
-
-void
-Particles::action(float elapsed_time)
-{
- Vector camera = Sector::current()->camera->get_translation();
-
- // update particles
- for(std::vector<Particle*>::iterator i = particles.begin();
- i != particles.end(); ) {
- (*i)->pos.x += (*i)->vel.x * elapsed_time;
- (*i)->pos.y += (*i)->vel.y * elapsed_time;
-
- (*i)->vel.x += accel.x * elapsed_time;
- (*i)->vel.y += accel.y * elapsed_time;
-
- if((*i)->pos.x < camera.x || (*i)->pos.x > screen->w + camera.x ||
- (*i)->pos.y < camera.y || (*i)->pos.y > screen->h + camera.y) {
- delete (*i);
- i = particles.erase(i);
- } else {
- ++i;
- }
- }
-
- if((timer.check() && !live_forever) || particles.size() == 0)
- remove_me();
-}
-
-void
-Particles::draw(DrawingContext& context)
-{
- // draw particles
- for(std::vector<Particle*>::iterator i = particles.begin();
- i != particles.end(); i++) {
- context.draw_filled_rect((*i)->pos, Vector(size,size), color,drawing_layer);
- }
-}
-
-void load_object_gfx()
-{
-#if 0
- img_trampoline = sprite_manager->load("trampoline");
- img_trampoline->start_animation(0);
- img_flying_platform = sprite_manager->load("flying_platform");
-#endif
- img_smoke_cloud = sprite_manager->create("stomp");
-}
-
-void free_object_gfx()
-{
- delete img_smoke_cloud;
-}
-
+++ /dev/null
-// $Id$
-//
-// SuperTux
-// Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
-// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-// 02111-1307, USA.
-
-#ifndef SUPERTUX_GAMEOBJS_H
-#define SUPERTUX_GAMEOBJS_H
-
-#include "video/surface.h"
-#include "timer.h"
-#include "scene.h"
-#include "math/physic.h"
-#include "special/game_object.h"
-#include "special/moving_object.h"
-#include "serializable.h"
-#include "utils/lispwriter.h"
-
-/* Bounciness of distros: */
-#define NO_BOUNCE 0
-#define BOUNCE 1
-
-namespace SuperTux {
-class Sprite;
-}
-
-class BouncyCoin : public GameObject
-{
-public:
- BouncyCoin(const Vector& pos);
- ~BouncyCoin();
- virtual void action(float elapsed_time);
- virtual void draw(DrawingContext& context);
-
-private:
- Sprite* sprite;
- Vector position;
- Timer2 timer;
-};
-
-class BrokenBrick : public GameObject
-{
-public:
- BrokenBrick(Sprite* sprite, const Vector& pos, const Vector& movement);
- ~BrokenBrick();
-
- virtual void action(float elapsed_time);
- virtual void draw(DrawingContext& context);
-
-private:
- Timer2 timer;
- Sprite* sprite;
- Vector position;
- Vector movement;
-};
-
-class FloatingText : public GameObject
-{
-public:
- FloatingText(const Vector& pos, const std::string& text_);
- FloatingText(const Vector& pos, int s); // use this for score, for instance
-
- virtual void action(float elapsed_time);
- virtual void draw(DrawingContext& context);
-
-private:
- Vector position;
- std::string text;
- Timer2 timer;
-};
-
-#if 0
-extern Sprite *img_trampoline;
-
-class Trampoline : public MovingObject, public Serializable
-{
-public:
- Trampoline(LispReader& reader);
- Trampoline(float x, float y);
-
- virtual void write(LispWriter& writer);
- virtual void action(float frame_ratio);
- virtual void draw(DrawingContext& context);
-
- virtual void collision(const MovingObject& other, int);
- void collision(void *p_c_object, int c_object, CollisionType type);
-
- Physic physic;
- enum { M_NORMAL, M_HELD } mode;
-
- private:
- float power;
- unsigned int frame;
-};
-#endif
-
-extern Sprite *img_smoke_cloud;
-
-class SmokeCloud : public GameObject
-{
-public:
- SmokeCloud(const Vector& pos);
-
- virtual void action(float elapsed_time);
- virtual void draw(DrawingContext& context);
-
-private:
- Timer2 timer;
- Vector position;
-};
-
-class Particles : public GameObject
-{
-public:
- Particles(const Vector& epicenter, int min_angle, int max_angle,
- const Vector& initial_velocity, const Vector& acceleration,
- int number, Color color, int size, float life_time, int drawing_layer);
- ~Particles();
-
- virtual void action(float elapsed_time);
- virtual void draw(DrawingContext& context);
-
-private:
- Vector accel;
- Timer2 timer;
- bool live_forever;
-
- Color color;
- float size;
- int drawing_layer;
-
- struct Particle {
- Vector pos, vel;
-// float angle;
- };
- std::vector <Particle*> particles;
-};
-
-void load_object_gfx();
-void free_object_gfx();
-
-#endif
-
-/* Local Variables: */
-/* mode:c++ */
-/* End: */
#include "app/globals.h"
#include "app/setup.h"
-#include "camera.h"
#include "video/screen.h"
#include "level.h"
#include "math/physic.h"
#include "tile.h"
#include "utils/lispreader.h"
#include "resources.h"
-#include "gameobjs.h"
#include "utils/lispwriter.h"
-#include "tilemap.h"
+#include "object/gameobjs.h"
+#include "object/camera.h"
+#include "object/tilemap.h"
using namespace std;
}
void
-Level::create(const std::string& filename)
-{
- Level level;
- const size_t width = 25;
- const size_t height = 19;
- level.add_sector(Sector::create("main", width, height));
- level.save(filename);
-}
-
-void
Level::load(const std::string& filepath)
{
LispReader* level = LispReader::load(filepath, "supertux-level");
void
Level::do_vertical_flip()
{
+#if 0
for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i)
i->second->do_vertical_flip();
+#endif
}
void
int total_coins = 0;
for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i) {
TileMap* solids = i->second->solids;
- if(!solids) {
- std::cerr << "Sector '" << i->first << "' contains no solids!?!\n";
- continue;
- }
+ assert(solids != 0);
for(size_t x = 0; x < solids->get_width(); ++x)
for(size_t y = 0; y < solids->get_height(); ++y) {
const Tile* tile = solids->get_tile(x, y);
// loads a levelfile
void load(const std::string& filename);
void save(const std::string& filename);
- static void create(const std::string& filename);
EndSequenceType get_end_sequence_type() const
{ return end_sequence_type; }
#include "leveleditor.h"
#include "resources.h"
#include "tile.h"
-#include "tilemap.h"
#include "tile_manager.h"
#include "sector.h"
-#include "background.h"
#include "gameloop.h"
-#include "gameobjs.h"
-#include "camera.h"
+#include "object/gameobjs.h"
+#include "object/camera.h"
+#include "object/tilemap.h"
+#include "object/background.h"
LevelEditor::LevelEditor()
{
level_subset->description = create_subset_menu->get_item_by_id(MN_ID_DESCRIPTION_SUBSET).input;
//FIXME: generate better level filenames
level_subset->add_level(subset_name+'/'+"new_level.stl");
- Level::create(level_subset->get_level_filename(0));
+ Level* newlevel = new Level();
+ newlevel->add_sector(create_sector("main", 25, 19));
+ newlevel->save(level_subset->get_level_filename(0));
level_subset->save();
load_level(0);
if(confirm_dialog(NULL, str))
{
level_subset->add_level("new_level.stl");
- Level::create(level_subset->get_level_filename(level_nb + 1));
+ Level* newlevel = new Level();
+ newlevel->add_sector(create_sector("main", 25, 19));
+ newlevel->save(level_subset->get_level_filename(level_nb + 1));
level_subset->save();
load_level(level_nb + 1);
}
{
if(!confirm_dialog(NULL, _("No more sectors exist. Create another?")))
return;
- sector_ = Sector::create("new_sector",25,19);
+ sector_ = create_sector("new_sector",25,19);
level->add_sector(sector_);
}
show_grid = show_grid_t;
mouse_cursor->set_state(MC_NORMAL);
}
+
+Sector*
+LevelEditor::create_sector(const std::string& name, size_t width, size_t height)
+{
+ Sector* sector = new Sector;
+ sector->set_name(name);
+
+ sector->add_object(new TileMap(LAYER_BACKGROUNDTILES, false, width, height));
+ sector->add_object(new TileMap(LAYER_TILES, true, width, height));
+ sector->add_object(new TileMap(LAYER_FOREGROUNDTILES, false, width, height));
+ sector->add_object(new Camera(sector));
+ sector->update_game_objects();
+
+ return sector;
+}
+
Vector selection_ini, selection_end;
bool level_changed;
+
+private:
+ Sector* create_sector(const std::string& name, size_t width, size_t height);
};
#endif
#define SUPERTUX_MISC_H
#include "app/setup.h"
-#include "resources.h"
+#include "app/gettext.h"
#include "gui/menu.h"
#include "utils/configfile.h"
-#include "player.h"
#include "title.h"
+#include "resources.h"
#include "worldmap.h"
#include "gameloop.h"
-#include "app/gettext.h"
+#include "object/player.h"
class MyConfig : public Config
{
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <config.h>
+
+#include "background.h"
+#include "app/globals.h"
+#include "camera.h"
+#include "video/drawing_context.h"
+#include "utils/lispwriter.h"
+
+Background::Background()
+ : type(INVALID), layer(LAYER_BACKGROUND0), image(0)
+{
+}
+
+Background::Background(LispReader& reader)
+ : type(INVALID), layer(LAYER_BACKGROUND0), image(0)
+{
+ reader.read_int("layer", layer);
+ if(reader.read_string("image", imagefile)
+ && reader.read_float("speed", speed)) {
+ set_image(imagefile, speed);
+ }
+
+ std::vector <unsigned int> bkgd_top_color, bkgd_bottom_color;
+ if(reader.read_int_vector("top_color", bkgd_top_color) &&
+ reader.read_int_vector("bottom_color", bkgd_bottom_color))
+ set_gradient(Color(bkgd_top_color), Color(bkgd_bottom_color));
+}
+
+Background::~Background()
+{
+ delete image;
+}
+
+void
+Background::write(LispWriter& writer)
+{
+ if(type == INVALID)
+ return;
+
+ writer.start_list("background");
+
+ if(type == IMAGE) {
+ writer.write_string("image", imagefile);
+ writer.write_float("speed", speed);
+ } else if(type == GRADIENT) {
+ std::vector <unsigned int> bkgd_top_color, bkgd_bottom_color;
+ bkgd_top_color.push_back(gradient_top.red);
+ bkgd_top_color.push_back(gradient_top.green);
+ bkgd_top_color.push_back(gradient_top.blue);
+ bkgd_bottom_color.push_back(gradient_top.red);
+ bkgd_bottom_color.push_back(gradient_top.green);
+ bkgd_bottom_color.push_back(gradient_top.blue);
+ writer.write_int_vector("top_color", bkgd_top_color);
+ writer.write_int_vector("bottom_color", bkgd_bottom_color);
+ }
+ writer.write_int("layer", layer);
+
+ writer.end_list("background");
+}
+
+void
+Background::action(float)
+{
+}
+
+void
+Background::set_image(const std::string& name, float speed)
+{
+ this->type = IMAGE;
+ this->imagefile = name;
+ this->speed = speed;
+
+ delete image;
+ image = new Surface(datadir + "/images/background/" + name, false);
+}
+
+void
+Background::set_gradient(Color top, Color bottom)
+{
+ type = GRADIENT;
+ gradient_top = top;
+ gradient_bottom = bottom;
+
+ delete image;
+ image = new Surface(top, bottom, screen->w, screen->h);
+}
+
+void
+Background::draw(DrawingContext& context)
+{
+ if(type == GRADIENT) {
+ context.push_transform();
+ context.set_translation(Vector(0, 0));
+ context.draw_surface(image, Vector(0, 0), layer);
+ context.pop_transform();
+ } else if(type == IMAGE) {
+ if(!image)
+ return;
+
+ int sx = int(-context.get_translation().x * speed) % image->w - image->w;
+ int sy = int(-context.get_translation().y * speed) % image->h - image->h;
+ context.push_transform();
+ context.set_translation(Vector(0, 0));
+ for(int x = sx; x < screen->w; x += image->w)
+ for(int y = sy; y < screen->h; y += image->h)
+ context.draw_surface(image, Vector(x, y), layer);
+ context.pop_transform();
+ }
+}
+
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef SUPERTUX_BACKGROUND_H
+#define SUPERTUX_BACKGROUND_H
+
+#include "video/surface.h"
+#include "video/drawing_context.h"
+#include "special/game_object.h"
+#include "utils/lispreader.h"
+#include "serializable.h"
+
+class DisplayManager;
+
+class Background : public GameObject, public Serializable
+{
+public:
+ Background();
+ Background(LispReader& reader);
+ virtual ~Background();
+
+ virtual void write(LispWriter& writer);
+
+ void set_image(const std::string& name, float bkgd_speed);
+
+ void set_gradient(Color top, Color bottom);
+
+ std::string get_image() const
+ { return imagefile; }
+ float get_speed() const
+ { return speed; }
+ Color get_gradient_top() const
+ { return gradient_top; }
+ Color get_gradient_bottom() const
+ { return gradient_bottom; }
+
+ virtual void action(float elapsed_time);
+
+ virtual void draw(DrawingContext& context);
+
+private:
+ enum Type {
+ INVALID, GRADIENT, IMAGE
+ };
+
+ Type type;
+ int layer;
+ std::string imagefile;
+ float speed;
+ Surface* image;
+ Color gradient_top, gradient_bottom;
+};
+
+#endif /*SUPERTUX_BACKGROUND_H*/
+
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <config.h>
+
+#include <stdexcept>
+#include <sstream>
+#include <cmath>
+
+#include "camera.h"
+#include "utils/lispreader.h"
+#include "utils/lispwriter.h"
+#include "player.h"
+#include "tilemap.h"
+#include "gameloop.h"
+#include "app/globals.h"
+#include "sector.h"
+
+using namespace SuperTux;
+
+Camera::Camera(Sector* newsector)
+ : sector(newsector), do_backscrolling(true), scrollchange(NONE),
+ auto_idx(0), auto_t(0)
+{
+ mode = NORMAL;
+}
+
+Camera::~Camera()
+{
+}
+
+const Vector&
+Camera::get_translation() const
+{
+ return translation;
+}
+
+void
+Camera::parse(LispReader& reader)
+{
+ std::string modename;
+
+ reader.read_string("mode", modename);
+ if(modename == "normal") {
+ mode = NORMAL;
+
+ do_backscrolling = true;
+ reader.read_bool("backscrolling", do_backscrolling);
+ } else if(modename == "autoscroll") {
+ mode = AUTOSCROLL;
+
+ lisp_object_t* cur = 0;
+ reader.read_lisp("path", cur);
+ if(cur == 0) {
+ throw std::runtime_error("No path specified in autoscroll camera.");
+ }
+ float speed = 50;
+ while(!lisp_nil_p(cur)) {
+ if(strcmp(lisp_symbol(lisp_car(lisp_car(cur))), "point") != 0) {
+ std::cerr << "Warning: unknown token in camera path.\n";
+ continue;
+ }
+
+ LispReader reader(lisp_cdr(lisp_car(cur)));
+
+ ScrollPoint point;
+ if(!reader.read_float("x", point.position.x) ||
+ !reader.read_float("y", point.position.y)) {
+ throw std::runtime_error("x and y missing in point of camerapath");
+ }
+ reader.read_float("speed", speed);
+ point.speed = speed;
+ scrollpoints.push_back(point);
+
+ cur = lisp_cdr(cur);
+ }
+ } else if(modename == "manual") {
+ mode = MANUAL;
+ } else {
+ std::stringstream str;
+ str << "invalid camera mode '" << modename << "'found in worldfile.";
+ throw std::runtime_error(str.str());
+ }
+}
+
+void
+Camera::write(LispWriter& writer)
+{
+ writer.start_list("camera");
+
+ if(mode == NORMAL) {
+ writer.write_string("mode", "normal");
+ writer.write_bool("backscrolling", do_backscrolling);
+ } else if(mode == AUTOSCROLL) {
+ writer.write_string("mode", "autoscroll");
+ writer.start_list("path");
+ for(std::vector<ScrollPoint>::iterator i = scrollpoints.begin();
+ i != scrollpoints.end(); ++i) {
+ writer.start_list("point");
+ writer.write_float("x", i->position.x);
+ writer.write_float("y", i->position.y);
+ writer.write_float("speed", i->speed);
+ writer.end_list("point");
+ }
+
+ writer.end_list("path");
+ } else if(mode == MANUAL) {
+ writer.write_string("mode", "manual");
+ }
+
+ writer.end_list("camera");
+}
+
+void
+Camera::reset(const Vector& tuxpos)
+{
+ translation.x = tuxpos.x - screen->w/3 * 2;
+ translation.y = tuxpos.y - screen->h/2;
+ keep_in_bounds();
+}
+
+static const float EPSILON = .00001;
+static const float max_speed_y = 140;
+
+void
+Camera::action(float elapsed_time)
+{
+ if(mode == NORMAL)
+ scroll_normal(elapsed_time);
+ else if(mode == AUTOSCROLL)
+ scroll_autoscroll(elapsed_time);
+}
+
+void
+Camera::keep_in_bounds()
+{
+ float width = sector->solids->get_width() * 32;
+ float height = sector->solids->get_height() * 32;
+
+ // don't scroll before the start or after the level's end
+ if(translation.y > height - screen->h)
+ translation.y = height - screen->h;
+ if(translation.y < 0)
+ translation.y = 0;
+ if(translation.x > width - screen->w)
+ translation.x = width - screen->w;
+ if(translation.x < 0)
+ translation.x = 0;
+}
+
+void
+Camera::scroll_normal(float elapsed_time)
+{
+ assert(sector != 0);
+ Player* player = sector->player;
+
+ // check that we don't have division by zero later
+ if(elapsed_time < EPSILON)
+ return;
+
+ /****** Vertical Scrolling part ******/
+ bool do_y_scrolling = true;
+
+ if(player->dying || sector->solids->get_height() == 19)
+ do_y_scrolling = false;
+
+ if(do_y_scrolling) {
+ // target_y is the high we target our scrolling at. This is not always the
+ // high of the player, but if he is jumping upwards we should use the
+ // position where he last touched the ground. (this probably needs
+ // exceptions for trampolines and similar things in the future)
+ float target_y;
+ if(player->fall_mode == Player::JUMPING)
+ target_y = player->last_ground_y + player->get_bbox().get_height();
+ else
+ target_y = player->get_bbox().p2.y;
+
+ // delta_y is the distance we'd have to travel to directly reach target_y
+ float delta_y = translation.y - (target_y - screen->h/2);
+ // speed is the speed the camera would need to reach target_y in this frame
+ float speed_y = delta_y / elapsed_time;
+
+ // limit the camera speed when jumping upwards
+ if(player->fall_mode != Player::FALLING
+ && player->fall_mode != Player::TRAMPOLINE_JUMP) {
+ if(speed_y > max_speed_y)
+ speed_y = max_speed_y;
+ else if(speed_y < -max_speed_y)
+ speed_y = -max_speed_y;
+ }
+
+ // finally scroll with calculated speed
+ translation.y -= speed_y * elapsed_time;
+ }
+
+ /****** Horizontal scrolling part *******/
+
+ // our camera is either in leftscrolling, rightscrolling or nonscrollingmode.
+
+ // when suddenly changing directions while scrolling into the other direction.
+ // abort scrolling, since tux might be going left/right at a relatively small
+ // part of the map (like when jumping upwards)
+ if((player->dir == ::LEFT && scrollchange == RIGHT)
+ || (player->dir == ::RIGHT && scrollchange == LEFT))
+ scrollchange = NONE;
+ // when in left 1/3rd of screen scroll left
+ if(player->get_bbox().get_middle().x < translation.x + screen->w/3 - 16
+ && do_backscrolling)
+ scrollchange = LEFT;
+ // scroll right when in right 1/3rd of screen
+ else if(player->get_bbox().get_middle().x > translation.x + screen->w/3*2+16)
+ scrollchange = RIGHT;
+
+ // calculate our scroll target depending on scroll mode
+ float target_x;
+ if(scrollchange == LEFT)
+ target_x = player->get_bbox().get_middle().x - screen->w/3*2;
+ else if(scrollchange == RIGHT)
+ target_x = player->get_bbox().get_middle().x - screen->w/3;
+ else
+ target_x = translation.x;
+
+ // that's the distance we would have to travel to reach target_x
+ float delta_x = translation.x - target_x;
+ // the speed we'd need to travel to reach target_x in this frame
+ float speed_x = delta_x / elapsed_time;
+
+ // limit our speed
+ float maxv = 130 + (fabsf(player->physic.get_velocity_x() * 1.3));
+ if(speed_x > maxv)
+ speed_x = maxv;
+ else if(speed_x < -maxv)
+ speed_x = -maxv;
+
+ // apply scrolling
+ translation.x -= speed_x * elapsed_time;
+
+ keep_in_bounds();
+}
+
+void
+Camera::scroll_autoscroll(float elapsed_time)
+{
+ Player* player = sector->player;
+
+ if(player->dying)
+ return;
+
+ if(auto_t - elapsed_time >= 0) {
+ translation += current_dir * elapsed_time;
+ auto_t -= elapsed_time;
+ } else {
+ // do the rest of the old movement
+ translation += current_dir * auto_t;
+ elapsed_time -= auto_t;
+ auto_t = 0;
+
+ // construct path for next point
+ if(auto_idx+1 >= scrollpoints.size()) {
+ keep_in_bounds();
+ return;
+ }
+ Vector distance = scrollpoints[auto_idx+1].position
+ - scrollpoints[auto_idx].position;
+ current_dir = distance.unit() * scrollpoints[auto_idx].speed;
+ auto_t = distance.norm() / scrollpoints[auto_idx].speed;
+
+ // do movement for the remaining time
+ translation += current_dir * elapsed_time;
+ auto_t -= elapsed_time;
+ auto_idx++;
+ }
+
+ keep_in_bounds();
+}
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef SUPERTUX_CAMERA_H
+#define SUPERTUX_CAMERA_H
+
+#include <vector>
+#include <cassert>
+
+#include "defines.h"
+#include "math/vector.h"
+#include "special/game_object.h"
+#include "video/drawing_context.h"
+#include "serializable.h"
+
+using namespace SuperTux;
+
+namespace SuperTux {
+class LispReader;
+}
+
+class Sector;
+
+class Camera : public GameObject, public Serializable
+{
+public:
+ Camera(Sector* sector);
+ virtual ~Camera();
+
+ /// parse camera mode from lisp file
+ void parse(LispReader& reader);
+ /// write camera mode to a lisp file
+ virtual void write(LispWriter& writer);
+
+ /// reset camera postion
+ virtual void reset(const Vector& tuxpos);
+
+ /** @deprecated@ */
+ const Vector& get_translation() const;
+
+ virtual void action(float elapsed_time);
+
+ virtual void draw(DrawingContext& )
+ {
+ }
+
+ void set_scrolling(int scroll_x, int scroll_y)
+ {
+ translation.x = scroll_x;
+ translation.y = scroll_y;
+ }
+
+ enum CameraMode
+ {
+ NORMAL, AUTOSCROLL, MANUAL
+ };
+ CameraMode mode;
+
+private:
+ void scroll_normal(float elapsed_time);
+ void scroll_autoscroll(float elapsed_time);
+ void keep_in_bounds();
+
+ enum LeftRightScrollChange
+ {
+ NONE, LEFT, RIGHT
+ };
+
+ Vector translation;
+
+ Sector* sector;
+
+ // normal mode
+ bool do_backscrolling;
+ LeftRightScrollChange scrollchange;
+
+ // autoscroll mode
+ class ScrollPoint {
+ public:
+ Vector position;
+ float speed;
+ };
+ std::vector<ScrollPoint> scrollpoints;
+ size_t auto_idx;
+ float auto_t;
+ Vector current_dir;
+};
+
+#endif /*SUPERTUX_CAMERA_H*/
+
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
+// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+#include <config.h>
+
+#include <algorithm>
+#include <iostream>
+#include <cmath>
+
+#include "app/globals.h"
+#include "tile.h"
+#include "tile_manager.h"
+#include "gameloop.h"
+#include "gameobjs.h"
+#include "special/sprite_manager.h"
+#include "resources.h"
+#include "sector.h"
+#include "tilemap.h"
+#include "video/drawing_context.h"
+#include "camera.h"
+
+BouncyCoin::BouncyCoin(const Vector& pos)
+ : position(pos)
+{
+ timer.start(.3);
+ sprite = sprite_manager->create("coin");
+ sprite->set_action("still");
+}
+
+BouncyCoin::~BouncyCoin()
+{
+ delete sprite;
+}
+
+void
+BouncyCoin::action(float elapsed_time)
+{
+ position.y += -200 * elapsed_time;
+
+ if(timer.check())
+ remove_me();
+}
+
+void
+BouncyCoin::draw(DrawingContext& context)
+{
+ sprite->draw(context, position, LAYER_OBJECTS);
+}
+
+//---------------------------------------------------------------------------
+
+BrokenBrick::BrokenBrick(Sprite* nsprite,
+ const Vector& pos, const Vector& nmovement)
+ : sprite(new Sprite(*nsprite)), position(pos), movement(nmovement)
+{
+ timer.start(.2);
+}
+
+BrokenBrick::~BrokenBrick()
+{
+ delete sprite;
+}
+
+void
+BrokenBrick::action(float elapsed_time)
+{
+ position += movement * elapsed_time;
+
+ if (timer.check())
+ remove_me();
+}
+
+void
+BrokenBrick::draw(DrawingContext& context)
+{
+ sprite->draw_part(context,
+ Vector(rand() % 16, rand() % 16), Vector(16, 16),
+ position, LAYER_OBJECTS + 1);
+}
+
+//---------------------------------------------------------------------------
+
+FloatingText::FloatingText(const Vector& pos, const std::string& text_)
+ : position(pos), text(text_)
+{
+ timer.start(.1);
+ position.x -= text.size() * 8;
+}
+
+FloatingText::FloatingText(const Vector& pos, int score)
+ : position(pos)
+{
+ timer.start(.1);
+
+ // turn int into a string
+ char str[10];
+ snprintf(str, 10, "%d", score);
+ text = str;
+
+ position.x -= text.size() * 8;
+}
+
+void
+FloatingText::action(float elapsed_time)
+{
+ position.y -= 1.4 * elapsed_time;
+
+ if(timer.check())
+ remove_me();
+}
+
+#define FADING_TIME .350
+
+void
+FloatingText::draw(DrawingContext& context)
+{
+ // make an alpha animation when disapearing
+ int alpha;
+ if(timer.get_timeleft() < FADING_TIME)
+ alpha = int(timer.get_timeleft() * 255 / FADING_TIME);
+ else
+ alpha = 255;
+
+ context.push_transform();
+ context.set_alpha(alpha);
+
+ context.draw_text(gold_text, text, position, LEFT_ALLIGN, LAYER_OBJECTS+1);
+
+ context.pop_transform();
+}
+
+/* Trampoline */
+
+#if 0
+Sprite *img_trampoline;
+
+Trampoline::Trampoline(LispReader& reader)
+{
+ reader.read_float("x", base.x);
+ reader.read_float("y", base.y);
+ base.width = 32;
+ base.height = 32;
+ power = 7.5;
+ reader.read_float("power", power);
+
+ frame = 0;
+ mode = M_NORMAL;
+ physic.reset();
+}
+
+Trampoline::Trampoline(float x, float y)
+{
+ base.x = x;
+ base.y = y;
+ base.width = 32;
+ base.height = 32;
+ power = 7.5;
+
+ frame = 0;
+ mode = M_NORMAL;
+ physic.reset();
+}
+
+void
+Trampoline::write(LispWriter& writer)
+{
+ writer.start_list("trampoline");
+
+ writer.write_float("x", base.x);
+ writer.write_float("y", base.y);
+ writer.write_float("power", power);
+
+ writer.end_list("trampoline");
+}
+
+void
+Trampoline::draw(DrawingContext& context)
+{
+ img_trampoline->set_frame(frame);
+ img_trampoline->draw(context, base, LAYER_OBJECTS);
+ frame = 0;
+}
+
+void
+Trampoline::action(float frame_ratio)
+{
+ // TODO: Remove if we're too far off the screen
+
+ // Falling
+ if (mode != M_HELD)
+ {
+ if (issolid(base.x + base.width/2, base.y + base.height))
+ {
+ base.y = int((base.y + base.height)/32) * 32 - base.height;
+
+ physic.enable_gravity(false);
+ physic.set_velocity_y(0.0f);
+
+ physic.set_velocity_x(0);
+ }
+ else
+ {
+ physic.enable_gravity(true);
+ }
+ }
+ else // Player is carrying us around
+ {
+ /* FIXME: The trampoline object shouldn't know about pplayer objects. */
+ /* If we're holding the iceblock */
+ Player& tux = *Sector::current()->player;
+ Direction dir = tux.dir;
+
+ if(dir == RIGHT)
+ {
+ base.x = tux.base.x + 16;
+ base.y = tux.base.y + tux.base.height/1.5 - base.height;
+ }
+ else /* facing left */
+ {
+ base.x = tux.base.x - 16;
+ base.y = tux.base.y + tux.base.height/1.5 - base.height;
+ }
+
+ if(collision_object_map(base))
+ {
+ base.x = tux.base.x;
+ base.y = tux.base.y + tux.base.height/1.5 - base.height;
+ }
+ }
+
+ physic.apply(frame_ratio, base.x, base.y, Sector::current()->gravity);
+ collision_swept_object_map(&old_base, &base);
+}
+
+void
+Trampoline::collision(const MovingObject&, int)
+{
+ // comes later
+}
+
+void
+Trampoline::collision(void *p_c_object, int c_object, CollisionType type)
+{
+ Player* pplayer_c = NULL;
+ switch (c_object)
+ {
+ case CO_PLAYER:
+ pplayer_c = (Player*) p_c_object;
+
+ if (type == COLLISION_NORMAL)
+ {
+ // Pick up if HELD (done in Player)
+ }
+
+ else if (type == COLLISION_SQUISH)
+ {
+ int squish_amount = (32 - (int)pplayer_c->base.y % 32);
+
+ if (squish_amount < 24)
+ frame = 3;
+ else if (squish_amount < 28)
+ frame = 2;
+ else if (squish_amount < 30)
+ frame = 1;
+ else
+ frame = 0;
+
+ if (squish_amount < 20) {
+ pplayer_c->physic.set_velocity_y(power);
+ pplayer_c->fall_mode = Player::TRAMPOLINE_JUMP;
+ }
+ else if (pplayer_c->physic.get_velocity_y() < 0)
+ pplayer_c->physic.set_velocity_y(-squish_amount/32);
+ }
+
+ break;
+
+ default:
+ break;
+
+ }
+}
+#endif
+
+/* Flying Platform */
+
+#if 0
+Sprite *img_flying_platform;
+
+FlyingPlatform::FlyingPlatform(LispReader& reader)
+{
+ reader.read_int_vector("x", pos_x);
+ reader.read_int_vector("y", pos_y);
+
+ velocity = 2.0;
+ reader.read_float("velocity", velocity);
+
+ base.x = pos_x[0];
+ base.y = pos_y[0];
+ base.width = 96;
+ base.height = 40;
+
+ point = 0;
+ move = false;
+
+ float x = pos_x[point+1] - pos_x[point];
+ float y = pos_y[point+1] - pos_y[point];
+ vel_x = x*velocity / sqrt(x*x + y*y);
+ vel_y = -(velocity - vel_x);
+
+ frame = 0;
+}
+
+FlyingPlatform::FlyingPlatform(int x, int y)
+{
+base.x = x;
+base.y = y;
+point = 0;
+move = false;
+}
+
+void
+FlyingPlatform::write(LispWriter& writer)
+{
+ writer.start_list("flying-trampoline");
+
+ writer.write_int_vector("x", pos_x);
+ writer.write_int_vector("y", pos_y);
+ writer.write_float("velocity", velocity);
+
+ writer.end_list("flying-trampoline");
+}
+
+void
+FlyingPlatform::draw(DrawingContext& context)
+{
+ img_flying_platform->draw(context, base, LAYER_OBJECTS);
+}
+
+void
+FlyingPlatform::action(float frame_ratio)
+{
+ // TODO: Remove if we're too far off the screen
+
+if(!move)
+ return;
+
+if((unsigned)point+1 != pos_x.size())
+ {
+ if(((pos_x[point+1] > pos_x[point] && base.x >= pos_x[point+1]) ||
+ (pos_x[point+1] < pos_x[point] && base.x <= pos_x[point+1]) ||
+ pos_x[point] == pos_x[point+1]) &&
+ ((pos_y[point+1] > pos_y[point] && base.y >= pos_y[point+1]) ||
+ (pos_y[point+1] < pos_y[point] && base.y <= pos_y[point+1]) ||
+ pos_y[point] == pos_y[point+1]))
+ {
+ point++;
+
+ float x = pos_x[point+1] - pos_x[point];
+ float y = pos_y[point+1] - pos_y[point];
+ vel_x = x*velocity / sqrt(x*x + y*y);
+ vel_y = -(velocity - vel_x);
+ }
+ }
+else // last point
+ {
+ // point = 0;
+ // reverse vector
+ return;
+ }
+/*
+if(pos_x[point+1] > base.x)
+ base.x += velocity * frame_ratio;
+else if(pos_x[point+1] < base.x)
+ base.x -= velocity * frame_ratio;
+
+if(pos_y[point+1] > base.y)
+ base.y += velocity * frame_ratio;
+else if(pos_y[point+1] < base.y)
+ base.y -= velocity * frame_ratio;
+*/
+
+base.x += vel_x * frame_ratio;
+base.y += vel_y * frame_ratio;
+}
+
+void
+FlyingPlatform::collision(const MovingObject&, int)
+{
+ // comes later
+}
+
+void
+FlyingPlatform::collision(void *p_c_object, int c_object, CollisionType type)
+{
+(void) p_c_object;
+(void) type;
+
+// Player* pplayer_c = NULL;
+ switch (c_object)
+ {
+ case CO_PLAYER:
+// pplayer_c = (Player*) p_c_object;
+ move = true;
+
+ break;
+
+ default:
+ break;
+
+ }
+}
+#endif
+
+Sprite *img_smoke_cloud = 0;
+
+SmokeCloud::SmokeCloud(const Vector& pos)
+ : position(pos)
+{
+ timer.start(.3);
+}
+
+void
+SmokeCloud::action(float elapsed_time)
+{
+ position.y -= 120 * elapsed_time;
+
+ if(timer.check())
+ remove_me();
+}
+
+void
+SmokeCloud::draw(DrawingContext& context)
+{
+ img_smoke_cloud->draw(context, position, LAYER_OBJECTS+1);
+}
+
+Particles::Particles(const Vector& epicenter, int min_angle, int max_angle,
+ const Vector& initial_velocity, const Vector& acceleration, int number,
+ Color color_, int size_, float life_time, int drawing_layer_)
+ : accel(acceleration), color(color_), size(size_), drawing_layer(drawing_layer_)
+{
+ if(life_time == 0) {
+ live_forever = true;
+ } else {
+ live_forever = false;
+ timer.start(life_time);
+ }
+
+ // create particles
+ for(int p = 0; p < number; p++)
+ {
+ Particle* particle = new Particle;
+ particle->pos = epicenter;
+
+ float angle = ((rand() % (max_angle-min_angle))+min_angle)
+ * (M_PI / 180); // convert to radius
+ particle->vel.x = /*fabs*/(sin(angle)) * initial_velocity.x;
+// if(angle >= M_PI && angle < M_PI*2)
+// particle->vel.x *= -1; // work around to fix signal
+ particle->vel.y = /*fabs*/(cos(angle)) * initial_velocity.y;
+// if(angle >= M_PI_2 && angle < 3*M_PI_2)
+// particle->vel.y *= -1;
+
+ particles.push_back(particle);
+ }
+}
+
+Particles::~Particles()
+{
+ // free particles
+ for(std::vector<Particle*>::iterator i = particles.begin();
+ i < particles.end(); i++)
+ delete (*i);
+}
+
+void
+Particles::action(float elapsed_time)
+{
+ Vector camera = Sector::current()->camera->get_translation();
+
+ // update particles
+ for(std::vector<Particle*>::iterator i = particles.begin();
+ i != particles.end(); ) {
+ (*i)->pos.x += (*i)->vel.x * elapsed_time;
+ (*i)->pos.y += (*i)->vel.y * elapsed_time;
+
+ (*i)->vel.x += accel.x * elapsed_time;
+ (*i)->vel.y += accel.y * elapsed_time;
+
+ if((*i)->pos.x < camera.x || (*i)->pos.x > screen->w + camera.x ||
+ (*i)->pos.y < camera.y || (*i)->pos.y > screen->h + camera.y) {
+ delete (*i);
+ i = particles.erase(i);
+ } else {
+ ++i;
+ }
+ }
+
+ if((timer.check() && !live_forever) || particles.size() == 0)
+ remove_me();
+}
+
+void
+Particles::draw(DrawingContext& context)
+{
+ // draw particles
+ for(std::vector<Particle*>::iterator i = particles.begin();
+ i != particles.end(); i++) {
+ context.draw_filled_rect((*i)->pos, Vector(size,size), color,drawing_layer);
+ }
+}
+
+void load_object_gfx()
+{
+#if 0
+ img_trampoline = sprite_manager->load("trampoline");
+ img_trampoline->start_animation(0);
+ img_flying_platform = sprite_manager->load("flying_platform");
+#endif
+ img_smoke_cloud = sprite_manager->create("stomp");
+}
+
+void free_object_gfx()
+{
+ delete img_smoke_cloud;
+}
+
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
+// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#ifndef SUPERTUX_GAMEOBJS_H
+#define SUPERTUX_GAMEOBJS_H
+
+#include "video/surface.h"
+#include "timer.h"
+#include "scene.h"
+#include "math/physic.h"
+#include "special/game_object.h"
+#include "special/moving_object.h"
+#include "serializable.h"
+#include "utils/lispwriter.h"
+
+/* Bounciness of distros: */
+#define NO_BOUNCE 0
+#define BOUNCE 1
+
+namespace SuperTux {
+class Sprite;
+}
+
+class BouncyCoin : public GameObject
+{
+public:
+ BouncyCoin(const Vector& pos);
+ ~BouncyCoin();
+ virtual void action(float elapsed_time);
+ virtual void draw(DrawingContext& context);
+
+private:
+ Sprite* sprite;
+ Vector position;
+ Timer2 timer;
+};
+
+class BrokenBrick : public GameObject
+{
+public:
+ BrokenBrick(Sprite* sprite, const Vector& pos, const Vector& movement);
+ ~BrokenBrick();
+
+ virtual void action(float elapsed_time);
+ virtual void draw(DrawingContext& context);
+
+private:
+ Timer2 timer;
+ Sprite* sprite;
+ Vector position;
+ Vector movement;
+};
+
+class FloatingText : public GameObject
+{
+public:
+ FloatingText(const Vector& pos, const std::string& text_);
+ FloatingText(const Vector& pos, int s); // use this for score, for instance
+
+ virtual void action(float elapsed_time);
+ virtual void draw(DrawingContext& context);
+
+private:
+ Vector position;
+ std::string text;
+ Timer2 timer;
+};
+
+#if 0
+extern Sprite *img_trampoline;
+
+class Trampoline : public MovingObject, public Serializable
+{
+public:
+ Trampoline(LispReader& reader);
+ Trampoline(float x, float y);
+
+ virtual void write(LispWriter& writer);
+ virtual void action(float frame_ratio);
+ virtual void draw(DrawingContext& context);
+
+ virtual void collision(const MovingObject& other, int);
+ void collision(void *p_c_object, int c_object, CollisionType type);
+
+ Physic physic;
+ enum { M_NORMAL, M_HELD } mode;
+
+ private:
+ float power;
+ unsigned int frame;
+};
+#endif
+
+extern Sprite *img_smoke_cloud;
+
+class SmokeCloud : public GameObject
+{
+public:
+ SmokeCloud(const Vector& pos);
+
+ virtual void action(float elapsed_time);
+ virtual void draw(DrawingContext& context);
+
+private:
+ Timer2 timer;
+ Vector position;
+};
+
+class Particles : public GameObject
+{
+public:
+ Particles(const Vector& epicenter, int min_angle, int max_angle,
+ const Vector& initial_velocity, const Vector& acceleration,
+ int number, Color color, int size, float life_time, int drawing_layer);
+ ~Particles();
+
+ virtual void action(float elapsed_time);
+ virtual void draw(DrawingContext& context);
+
+private:
+ Vector accel;
+ Timer2 timer;
+ bool live_forever;
+
+ Color color;
+ float size;
+ int drawing_layer;
+
+ struct Particle {
+ Vector pos, vel;
+// float angle;
+ };
+ std::vector <Particle*> particles;
+};
+
+void load_object_gfx();
+void free_object_gfx();
+
+#endif
+
+/* Local Variables: */
+/* mode:c++ */
+/* End: */
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#include <config.h>
+
+#include <iostream>
+#include <cmath>
+
+#include "particlesystem.h"
+#include "app/globals.h"
+#include "utils/lispreader.h"
+#include "utils/lispwriter.h"
+#include "video/drawing_context.h"
+
+ParticleSystem::ParticleSystem()
+{
+ virtual_width = screen->w;
+ virtual_height = screen->h;
+ layer = LAYER_BACKGROUND1;
+}
+
+ParticleSystem::~ParticleSystem()
+{
+ std::vector<Particle*>::iterator i;
+ for(i = particles.begin(); i != particles.end(); ++i) {
+ delete *i;
+ }
+}
+
+void ParticleSystem::draw(DrawingContext& context)
+{
+ float scrollx = context.get_translation().x;
+ float scrolly = context.get_translation().y;
+
+ context.push_transform();
+ context.set_translation(Vector(0,0));
+
+ std::vector<Particle*>::iterator i;
+ for(i = particles.begin(); i != particles.end(); ++i) {
+ Particle* particle = *i;
+
+ // remap x,y coordinates onto screencoordinates
+ Vector pos;
+ pos.x = fmodf(particle->pos.x - scrollx, virtual_width);
+ if(pos.x < 0) pos.x += virtual_width;
+ pos.y = fmodf(particle->pos.y - scrolly, virtual_height);
+ if(pos.y < 0) pos.y += virtual_height;
+
+ if(pos.x > screen->w) pos.x -= virtual_width;
+ if(pos.y > screen->h) pos.y -= virtual_height;
+ context.draw_surface(particle->texture, pos, layer);
+ }
+
+ context.pop_transform();
+}
+
+SnowParticleSystem::SnowParticleSystem()
+{
+ snowimages[0] = new Surface(datadir+"/images/shared/snow0.png", true);
+ snowimages[1] = new Surface(datadir+"/images/shared/snow1.png", true);
+ snowimages[2] = new Surface(datadir+"/images/shared/snow2.png", true);
+
+ virtual_width = screen->w * 2;
+
+ // create some random snowflakes
+ size_t snowflakecount = size_t(virtual_width/10.0);
+ for(size_t i=0; i<snowflakecount; ++i) {
+ SnowParticle* particle = new SnowParticle;
+ particle->pos.x = rand() % int(virtual_width);
+ particle->pos.y = rand() % screen->h;
+ int snowsize = rand() % 3;
+ particle->texture = snowimages[snowsize];
+ do {
+ particle->speed = snowsize*.2 + (float(rand()%10)*.4);
+ } while(particle->speed < 1);
+ particle->speed *= 10; // gravity
+
+ particles.push_back(particle);
+ }
+}
+
+void
+SnowParticleSystem::parse(LispReader& reader)
+{
+ reader.read_int("layer", layer);
+}
+
+void
+SnowParticleSystem::write(LispWriter& writer)
+{
+ writer.start_list("particles-snow");
+ writer.write_int("layer", layer);
+ writer.end_list("particles-snow");
+}
+
+SnowParticleSystem::~SnowParticleSystem()
+{
+ for(int i=0;i<3;++i)
+ delete snowimages[i];
+}
+
+void SnowParticleSystem::action(float elapsed_time)
+{
+ std::vector<Particle*>::iterator i;
+ for(i = particles.begin(); i != particles.end(); ++i) {
+ SnowParticle* particle = (SnowParticle*) *i;
+ particle->pos.y += particle->speed * elapsed_time;
+ if(particle->pos.y > screen->h) {
+ particle->pos.y = fmodf(particle->pos.y , virtual_height);
+ particle->pos.x = rand() % int(virtual_width);
+ }
+ }
+}
+
+CloudParticleSystem::CloudParticleSystem()
+{
+ cloudimage = new Surface(datadir + "/images/shared/cloud.png", true);
+
+ virtual_width = 2000.0;
+
+ // create some random clouds
+ for(size_t i=0; i<15; ++i) {
+ CloudParticle* particle = new CloudParticle;
+ particle->pos.x = rand() % int(virtual_width);
+ particle->pos.y = rand() % int(virtual_height);
+ particle->texture = cloudimage;
+ particle->speed = -float(25 + rand() % 30);
+
+ particles.push_back(particle);
+ }
+}
+
+void
+CloudParticleSystem::parse(LispReader& reader)
+{
+ reader.read_int("layer", layer);
+}
+
+void
+CloudParticleSystem::write(LispWriter& writer)
+{
+ writer.start_list("particles-clouds");
+ writer.write_int("layer", layer);
+ writer.end_list("particles-clouds");
+}
+
+CloudParticleSystem::~CloudParticleSystem()
+{
+ delete cloudimage;
+}
+
+void CloudParticleSystem::action(float elapsed_time)
+{
+ std::vector<Particle*>::iterator i;
+ for(i = particles.begin(); i != particles.end(); ++i) {
+ CloudParticle* particle = (CloudParticle*) *i;
+ particle->pos.x += particle->speed * elapsed_time;
+ }
+}
--- /dev/null
+// $Id$
+//
+// SuperTux
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef SUPERTUX_PARTICLESYSTEM_H
+#define SUPERTUX_PARTICLESYSTEM_H
+
+#include <vector>
+
+#include "video/surface.h"
+#include "special/game_object.h"
+#include "serializable.h"
+
+using namespace SuperTux;
+
+namespace SuperTux {
+class LispReader;
+}
+
+class DisplayManager;
+
+/**
+ * This is the base class for particle systems. It is responsible for storing a
+ * set of particles with each having an x- and y-coordinate the number of the
+ * layer where it should be drawn and a texture.
+ * The coordinate system used here is a virtual one. It would be a bad idea to
+ * populate whole levels with particles. So we're using a virtual rectangle
+ * here that is tiled onto the level when drawing. This rectangle has the size
+ * (virtual_width, virtual_height). We're using modulo on the particle
+ * coordinates, so when a particle leaves left, it'll reenter at the right
+ * side.
+ *
+ * Classes that implement a particle system should subclass from this class,
+ * initialize particles in the constructor and move them in the simulate
+ * function.
+ */
+class ParticleSystem : public GameObject
+{
+public:
+ ParticleSystem();
+ virtual ~ParticleSystem();
+
+ virtual void draw(DrawingContext& context);
+
+protected:
+ int layer;
+
+ class Particle
+ {
+ public:
+ virtual ~Particle()
+ { }
+
+ Vector pos;
+ Surface* texture;
+ };
+
+ std::vector<Particle*> particles;
+ float virtual_width, virtual_height;
+};
+
+class SnowParticleSystem : public ParticleSystem, public Serializable
+{
+public:
+ SnowParticleSystem();
+ virtual ~SnowParticleSystem();
+
+ void parse(LispReader& reader);
+ void write(LispWriter& writer);
+
+ virtual void action(float elapsed_time);
+
+ std::string type() const
+ { return "SnowParticleSystem"; }
+
+private:
+ class SnowParticle : public Particle
+ {
+ public:
+ float speed;
+ };
+
+ Surface* snowimages[3];
+};
+
+class CloudParticleSystem : public ParticleSystem, public Serializable
+{
+public:
+ CloudParticleSystem();
+ virtual ~CloudParticleSystem();
+
+ void parse(LispReader& reader);
+ void write(LispWriter& writer);
+
+ virtual void action(float elapsed_time);
+
+ std::string type() const
+ { return "SnowParticleSystem"; }
+
+private:
+ class CloudParticle : public Particle
+ {
+ public:
+ float speed;
+ };
+
+ Surface* cloudimage;
+};
+
+#endif
+
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2003 Tobias Glaesser <tobi.web@gmx.de>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#include <config.h>
+
+#include <typeinfo>
+#include <cmath>
+#include <iostream>
+#include <cassert>
+
+#include "app/globals.h"
+#include "app/gettext.h"
+#include "player.h"
+#include "defines.h"
+#include "scene.h"
+#include "tile.h"
+#include "special/sprite.h"
+#include "sector.h"
+#include "resources.h"
+#include "video/screen.h"
+#include "statistics.h"
+#include "gameloop.h"
+#include "object/tilemap.h"
+#include "object/camera.h"
+#include "object/gameobjs.h"
+#include "trigger/trigger_base.h"
+
+static const int TILES_FOR_BUTTJUMP = 3;
+static const float SHOOTING_TIME = .150;
+/// time before idle animation starts
+static const float IDLE_TIME = 2.5;
+
+static const float WALK_ACCELERATION_X = 300;
+static const float RUN_ACCELERATION_X = 400;
+static const float SKID_XM = 200;
+static const float SKID_TIME = .3;
+static const float MAX_WALK_XM = 230;
+static const float MAX_RUN_XM = 320;
+static const float WALK_SPEED = 100;
+
+// growing animation
+Surface* growingtux_left[GROWING_FRAMES];
+Surface* growingtux_right[GROWING_FRAMES];
+
+Surface* tux_life = 0;
+
+Sprite* smalltux_gameover = 0;
+Sprite* smalltux_star = 0;
+Sprite* bigtux_star = 0;
+
+TuxBodyParts* small_tux = 0;
+TuxBodyParts* big_tux = 0;
+TuxBodyParts* fire_tux = 0;
+TuxBodyParts* ice_tux = 0;
+
+PlayerKeymap keymap;
+
+PlayerKeymap::PlayerKeymap()
+{
+ keymap.up = SDLK_UP;
+ keymap.down = SDLK_DOWN;
+ keymap.left = SDLK_LEFT;
+ keymap.right = SDLK_RIGHT;
+
+ keymap.power = SDLK_LCTRL;
+ keymap.jump = SDLK_SPACE;
+}
+
+void player_input_init(player_input_type* pplayer_input)
+{
+ pplayer_input->up = UP;
+ pplayer_input->old_up = UP;
+ pplayer_input->down = UP;
+ pplayer_input->fire = UP;
+ pplayer_input->left = UP;
+ pplayer_input->old_fire = UP;
+ pplayer_input->right = UP;
+ pplayer_input->jump = UP;
+ pplayer_input->old_jump = UP;
+ pplayer_input->activate = UP;
+}
+
+void
+TuxBodyParts::set_action(std::string action, int loops)
+{
+ if(head != NULL)
+ head->set_action(action, loops);
+ if(body != NULL)
+ body->set_action(action, loops);
+ if(arms != NULL)
+ arms->set_action(action, loops);
+ if(feet != NULL)
+ feet->set_action(action, loops);
+}
+
+void
+TuxBodyParts::draw(DrawingContext& context, const Vector& pos, int layer,
+ Uint32 drawing_effect)
+{
+ if(head != NULL)
+ head->draw(context, pos, layer-1, drawing_effect);
+ if(body != NULL)
+ body->draw(context, pos, layer-3, drawing_effect);
+ if(arms != NULL)
+ arms->draw(context, pos, layer, drawing_effect);
+ if(feet != NULL)
+ feet->draw(context, pos, layer-2, drawing_effect);
+}
+
+Player::Player()
+{
+ init();
+}
+
+Player::~Player()
+{
+}
+
+void
+Player::init()
+{
+ holding_something = false;
+
+ bbox.set_size(31.8, 31.8);
+
+ size = SMALL;
+ got_power = NONE_POWER;
+
+ dir = RIGHT;
+ old_dir = dir;
+ duck = false;
+ dead = false;
+
+ dying = DYING_NOT;
+ last_ground_y = 0;
+ fall_mode = ON_GROUND;
+ jumping = false;
+ flapping = false;
+ can_jump = true;
+ can_flap = false;
+ falling_from_flap = false;
+ enable_hover = false;
+ butt_jump = false;
+
+ flapping_velocity = 0;
+
+ // temporary to help player's choosing a flapping
+ flapping_mode = MAREK_FLAP;
+
+ // Ricardo's flapping
+ flaps_nb = 0;
+
+ on_ground_flag = false;
+
+ player_input_init(&input);
+
+ physic.reset();
+}
+
+int
+Player::key_event(SDLKey key, int state)
+{
+ idle_timer.start(IDLE_TIME, true);
+
+ if(key == keymap.right)
+ {
+ input.right = state;
+ return true;
+ }
+ else if(key == keymap.left)
+ {
+ input.left = state;
+ return true;
+ }
+ else if(key == keymap.up)
+ {
+ if(state == UP)
+ input.old_up = UP;
+ input.up = state;
+ /* Up key also opens activates stuff */
+ input.activate = state;
+ return true;
+ }
+ else if(key == keymap.down)
+ {
+ input.down = state;
+ return true;
+ }
+ else if(key == keymap.power)
+ {
+ if (state == UP)
+ input.old_fire = UP;
+ input.fire = state;
+
+ return true;
+ }
+ else if(key == keymap.jump)
+ {
+ if (state == UP)
+ input.old_jump = UP;
+ input.jump = state;
+ return true;
+ }
+ else
+ return false;
+}
+
+void
+Player::level_begin()
+{
+ move(Vector(100, 170));
+ duck = false;
+
+ dying = DYING_NOT;
+
+ player_input_init(&input);
+
+ on_ground_flag = false;
+
+ physic.reset();
+}
+
+PlayerStatus&
+Player::get_status()
+{
+ return player_status;
+}
+
+void
+Player::action(float elapsed_time)
+{
+ if(dying && dying_timer.check()) {
+ dead = true;
+ return;
+ }
+
+ if (input.fire == UP)
+ holding_something = false;
+
+ if(dying == DYING_NOT)
+ handle_input();
+
+ movement = physic.get_movement(elapsed_time);
+
+#if 0
+ // special exception for cases where we're stuck under tiles after
+ // being ducked. In this case we drift out
+ if(!duck && on_ground() && old_base.x == base.x && old_base.y == base.y
+ && collision_object_map(base))
+ {
+ base.x += elapsed_time * WALK_SPEED * (dir ? 1: -1);
+ previous_base = old_base = base;
+ }
+
+ /* Reset score multiplier (for multi-hits): */
+ if (!invincible_timer.started())
+ {
+ if(player_status.score_multiplier > player_status.max_score_multiplier)
+ {
+ player_status.max_score_multiplier = player_status.score_multiplier;
+
+ // show a message
+ char str[124];
+ sprintf(str, _("New max combo: %d"), player_status.max_score_multiplier-1);
+ Sector::current()->add_floating_text(base, str);
+ }
+ player_status.score_multiplier = 1;
+ }
+ }
+
+ }
+#endif
+
+ on_ground_flag = false;
+}
+
+bool
+Player::on_ground()
+{
+ return on_ground_flag;
+}
+
+void
+Player::handle_horizontal_input()
+{
+ float vx = physic.get_velocity_x();
+ float vy = physic.get_velocity_y();
+ float ax = physic.get_acceleration_x();
+ float ay = physic.get_acceleration_y();
+
+ float dirsign = 0;
+ if(input.left == DOWN && input.right == UP && (!duck || physic.get_velocity_y() != 0)) {
+ old_dir = dir;
+ dir = LEFT;
+ dirsign = -1;
+ } else if(input.left == UP && input.right == DOWN && (!duck || physic.get_velocity_y() != 0)) {
+ old_dir = dir;
+ dir = RIGHT;
+ dirsign = 1;
+ }
+
+ if (input.fire == UP) {
+ ax = dirsign * WALK_ACCELERATION_X;
+ // limit speed
+ if(vx >= MAX_WALK_XM && dirsign > 0) {
+ vx = MAX_WALK_XM;
+ ax = 0;
+ } else if(vx <= -MAX_WALK_XM && dirsign < 0) {
+ vx = -MAX_WALK_XM;
+ ax = 0;
+ }
+ } else {
+ ax = dirsign * RUN_ACCELERATION_X;
+ // limit speed
+ if(vx >= MAX_RUN_XM && dirsign > 0) {
+ vx = MAX_RUN_XM;
+ ax = 0;
+ } else if(vx <= -MAX_RUN_XM && dirsign < 0) {
+ vx = -MAX_RUN_XM;
+ ax = 0;
+ }
+ }
+
+ // we can reach WALK_SPEED without any acceleration
+ if(dirsign != 0 && fabs(vx) < WALK_SPEED) {
+ vx = dirsign * WALK_SPEED;
+ }
+
+ // changing directions?
+ if(on_ground() && ((vx < 0 && dirsign >0) || (vx>0 && dirsign<0)))
+ {
+ // let's skid!
+ if(fabs(vx)>SKID_XM && !skidding_timer.started())
+ {
+ skidding_timer.start(SKID_TIME);
+ SoundManager::get()->play_sound(IDToSound(SND_SKID));
+ // dust some partcles
+ Sector::current()->add_object(
+ new Particles(
+ Vector(bbox.p1.x + (dir == RIGHT ? bbox.get_width() : 0),
+ bbox.p2.y),
+ dir == RIGHT ? 270+20 : 90-40, dir == RIGHT ? 270+40 : 90-20,
+ Vector(280,-260), Vector(0,0.030), 3, Color(100,100,100), 3, .8,
+ LAYER_OBJECTS+1));
+
+ ax *= 2.5;
+ }
+ else
+ {
+ ax *= 2;
+ }
+ }
+
+ // we get slower when not pressing any keys
+ if(dirsign == 0) {
+ if(fabs(vx) < WALK_SPEED) {
+ vx = 0;
+ ax = 0;
+ } else if(vx < 0) {
+ ax = WALK_ACCELERATION_X * 1.5;
+ } else {
+ ax = WALK_ACCELERATION_X * -1.5;
+ }
+ }
+
+#if 0
+ // if we're on ice slow down acceleration or deceleration
+ if (isice(base.x, base.y + base.height))
+ {
+ /* the acceleration/deceleration rate on ice is inversely proportional to
+ * the current velocity.
+ */
+
+ // increasing 1 will increase acceleration/deceleration rate
+ // decreasing 1 will decrease acceleration/deceleration rate
+ // must stay above zero, though
+ if (ax != 0) ax *= 1 / fabs(vx);
+ }
+#endif
+
+ // extend/shrink tux collision rectangle so that we fall through/walk over 1
+ // tile holes
+ if(fabsf(vx) > MAX_WALK_XM) {
+ bbox.set_width(33);
+ } else {
+ bbox.set_width(31.8);
+ }
+
+ physic.set_velocity(vx, vy);
+ physic.set_acceleration(ax, ay);
+}
+
+void
+Player::handle_vertical_input()
+{
+ // set fall mode...
+ if(on_ground()) {
+ fall_mode = ON_GROUND;
+ last_ground_y = get_pos().y;
+ } else {
+ if(get_pos().y > last_ground_y)
+ fall_mode = FALLING;
+ else if(fall_mode == ON_GROUND)
+ fall_mode = JUMPING;
+ }
+
+ if(on_ground()) { /* Make sure jumping is off. */
+ jumping = false;
+ flapping = false;
+ falling_from_flap = false;
+ if (flapping_timer.started()) {
+ flapping_timer.start(0);
+ }
+
+ physic.set_acceleration_y(0); //for flapping
+ }
+
+ // Press jump key
+ if(input.jump == DOWN && can_jump && on_ground())
+ {
+ if(duck) { // only jump a little bit when in duck mode {
+ physic.set_velocity_y(300);
+ } else {
+ // jump higher if we are running
+ if (fabs(physic.get_velocity_x()) > MAX_WALK_XM)
+ physic.set_velocity_y(580);
+ else
+ physic.set_velocity_y(520);
+ }
+
+ //bbox.move(Vector(0, -1));
+ jumping = true;
+ flapping = false;
+ can_jump = false;
+ can_flap = false;
+ flaps_nb = 0; // Ricardo's flapping
+ if (size == SMALL)
+ SoundManager::get()->play_sound(IDToSound(SND_JUMP));
+ else
+ SoundManager::get()->play_sound(IDToSound(SND_BIGJUMP));
+ }
+ // Let go of jump key
+ else if(input.jump == UP)
+ {
+ if (!flapping && !duck && !falling_from_flap && !on_ground())
+ {
+ can_flap = true;
+ }
+ if (jumping && physic.get_velocity_y() > 0)
+ {
+ jumping = false;
+ physic.set_velocity_y(0);
+ }
+ }
+
+ // temporary to help player's choosing a flapping
+ if(flapping_mode == RICARDO_FLAP)
+ {
+ // Flapping, Ricardo's version
+ // similar to SM3 Fox
+ if(input.jump == DOWN && input.old_jump == UP && can_flap &&
+ flaps_nb < 3)
+ {
+ physic.set_velocity_y(350);
+ physic.set_velocity_x(physic.get_velocity_x() * 35);
+ flaps_nb++;
+ }
+ }
+ else if(flapping_mode == MAREK_FLAP)
+ {
+ // Flapping, Marek's version
+ if (input.jump == DOWN && can_flap)
+ {
+ if (!flapping_timer.started())
+ {
+ flapping_timer.start(TUX_FLAPPING_TIME);
+ flapping_velocity = physic.get_velocity_x();
+ }
+ if (flapping_timer.check())
+ {
+ can_flap = false;
+ falling_from_flap = true;
+ }
+ jumping = true;
+ flapping = true;
+ if (!flapping_timer.check()) {
+ float cv = flapping_velocity * sqrt(
+ TUX_FLAPPING_TIME - flapping_timer.get_timegone()
+ / TUX_FLAPPING_TIME);
+
+ //Handle change of direction while flapping
+ if (((dir == LEFT) && (cv > 0)) || (dir == RIGHT) && (cv < 0)) {
+ cv *= (-1);
+ }
+ physic.set_velocity_x(cv);
+ physic.set_velocity_y(
+ flapping_timer.get_timegone()/.850);
+ }
+ }
+ }
+ else if(flapping_mode == RYAN_FLAP)
+ {
+ // Flapping, Ryan's version
+ if (input.jump == DOWN && can_flap)
+ {
+ if (!flapping_timer.started())
+ {
+ flapping_timer.start(TUX_FLAPPING_TIME);
+ }
+ if (flapping_timer.check())
+ {
+ can_flap = false;
+ falling_from_flap = true;
+ }
+ jumping = true;
+ flapping = true;
+ if (flapping && flapping_timer.get_timegone() <= TUX_FLAPPING_TIME
+ && physic.get_velocity_y() < 0)
+ {
+ float gravity = Sector::current()->gravity;
+ (void)gravity;
+ float xr = (fabsf(physic.get_velocity_x()) / MAX_RUN_XM);
+
+ // XXX: magic numbers. should be a percent of gravity
+ // gravity is (by default) -0.1f
+ physic.set_acceleration_y(12 + 1*xr);
+
+#if 0
+ // To slow down x-vel when flapping (not working)
+ if (fabsf(physic.get_velocity_x()) > MAX_WALK_XM)
+ {
+ if (physic.get_velocity_x() < 0)
+ physic.set_acceleration_x(1.0f);
+ else if (physic.get_velocity_x() > 0)
+ physic.set_acceleration_x(-1.0f);
+ }
+#endif
+ }
+ }
+ else
+ {
+ physic.set_acceleration_y(0);
+ }
+ }
+
+ // Hover
+ //(disabled by default, use cheat code "hover" to toggle on/off)
+ //TODO: needs some tweaking, especially when used together with double jump and jumping off badguys
+ if (enable_hover && input.jump == DOWN && !jumping && !butt_jump && physic.get_velocity_y() <= 0)
+ {
+ physic.set_velocity_y(-100);
+ }
+
+#if 0
+ /* In case the player has pressed Down while in a certain range of air,
+ enable butt jump action */
+ if (input.down == DOWN && !butt_jump && !duck)
+ if(tiles_on_air(TILES_FOR_BUTTJUMP) && jumping)
+ butt_jump = true;
+#endif
+
+ /* When Down is not held anymore, disable butt jump */
+ if(butt_jump && input.down == UP)
+ butt_jump = false;
+
+ // Do butt jump
+ if (butt_jump && on_ground() && size == BIG)
+ {
+ // Add a smoke cloud
+ if (duck)
+ Sector::current()->add_smoke_cloud(Vector(get_pos().x - 32, get_pos().y));
+ else
+ Sector::current()->add_smoke_cloud(
+ Vector(get_pos().x - 32, get_pos().y + 32));
+
+ butt_jump = false;
+
+#if 0
+ // Break bricks beneath Tux
+ if(Sector::current()->trybreakbrick(
+ Vector(base.x + 1, base.y + base.height), false)
+ || Sector::current()->trybreakbrick(
+ Vector(base.x + base.width - 1, base.y + base.height), false))
+ {
+ physic.set_velocity_y(2);
+ butt_jump = true;
+ }
+#endif
+
+#if 0
+ // Kill nearby badguys
+ std::vector<GameObject*> gameobjects = Sector::current()->gameobjects;
+ for (std::vector<GameObject*>::iterator i = gameobjects.begin();
+ i != gameobjects.end();
+ i++)
+ {
+ BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
+ if(badguy)
+ {
+ // don't kill when badguys are already dying or in a certain mode
+ if(badguy->dying == DYING_NOT && badguy->mode != BadGuy::BOMB_TICKING &&
+ badguy->mode != BadGuy::BOMB_EXPLODE)
+ {
+ if (fabsf(base.x - badguy->base.x) < 96 &&
+ fabsf(base.y - badguy->base.y) < 64)
+ badguy->kill_me(25);
+ }
+ }
+ }
+#endif
+ }
+
+ /** jumping is only allowed if we're about to touch ground soon and if the
+ * button has been up in between the last jump
+ */
+ // FIXME
+#if 0
+ if ( (issolid(get_pos().x + bbox.get_width() / 2,
+ get_pos().y + bbox.get_height() + 64) ||
+ issolid(get_pos().x + 1, get_pos().y + bbox.get_height() + 64) ||
+ issolid(get_pos().x + bbox.get_width() - 1,
+ get_pos().y + bbox.get_height() + 64))
+ && jumping == false
+ && can_jump == false
+ && input.jump == DOWN
+ && input.old_jump == UP)
+ {
+ can_jump = true;
+ }
+#endif
+
+ input.old_jump = input.jump;
+}
+
+void
+Player::handle_input()
+{
+ /* Handle horizontal movement: */
+ handle_horizontal_input();
+
+ /* Jump/jumping? */
+ if (on_ground() && input.jump == UP)
+ can_jump = true;
+ handle_vertical_input();
+
+ /* Shoot! */
+ if (input.fire == DOWN && input.old_fire == UP && got_power != NONE_POWER) {
+ if(Sector::current()->add_bullet(
+ get_pos() + Vector(0, bbox.get_height()/2),
+ physic.get_velocity_x(), dir))
+ shooting_timer.start(SHOOTING_TIME);
+ input.old_fire = DOWN;
+ }
+
+ /* Duck! */
+ if (input.down == DOWN && size == BIG && !duck
+ && physic.get_velocity_y() == 0 && on_ground())
+ {
+ duck = true;
+ bbox.move(Vector(0, 32));
+ bbox.set_height(31.8);
+ }
+ else if(input.down == UP && size == BIG && duck)
+ {
+ // try if we can really unduck
+ bbox.move(Vector(0, -32));
+ bbox.set_height(63.8);
+ duck = false;
+ // FIXME
+#if 0
+ // when unducking in air we need some space to do so
+ if(on_ground() || !collision_object_map(bbox)) {
+ duck = false;
+ } else {
+ // undo the ducking changes
+ bbox.move(Vector(0, 32));
+ bbox.set_height(31.8);
+ }
+#endif
+ }
+}
+
+void
+Player::grow(bool animate)
+{
+ if(size == BIG)
+ return;
+
+ size = BIG;
+ bbox.set_height(63.8);
+ bbox.move(Vector(0, -32));
+
+ if(animate)
+ growing_timer.start(GROWING_TIME);
+}
+
+void
+Player::grabdistros()
+{
+}
+
+void
+Player::draw(DrawingContext& context)
+{
+ TuxBodyParts* tux_body;
+
+ if (size == SMALL)
+ tux_body = small_tux;
+ else if (got_power == FIRE_POWER)
+ tux_body = fire_tux;
+ else if (got_power == ICE_POWER)
+ tux_body = ice_tux;
+ else
+ tux_body = big_tux;
+
+ int layer = LAYER_OBJECTS + 10;
+
+ /* Set Tux sprite action */
+ if (duck && size == BIG)
+ {
+ if(dir == LEFT)
+ tux_body->set_action("duck-left");
+ else // dir == RIGHT
+ tux_body->set_action("duck-right");
+ }
+ else if (skidding_timer.started() && !skidding_timer.check())
+ {
+ if(dir == LEFT)
+ tux_body->set_action("skid-left");
+ else // dir == RIGHT
+ tux_body->set_action("skid-right");
+ }
+ else if (kick_timer.started() && !kick_timer.check())
+ {
+ if(dir == LEFT)
+ tux_body->set_action("kick-left");
+ else // dir == RIGHT
+ tux_body->set_action("kick-right");
+ }
+ else if (butt_jump && size == BIG)
+ {
+ if(dir == LEFT)
+ tux_body->set_action("buttjump-left");
+ else // dir == RIGHT
+ tux_body->set_action("buttjump-right");
+ }
+ else if (physic.get_velocity_y() != 0)
+ {
+ if(dir == LEFT)
+ tux_body->set_action("jump-left");
+ else // dir == RIGHT
+ tux_body->set_action("jump-right");
+ }
+ else
+ {
+ if (fabsf(physic.get_velocity_x()) < 1.0f) // standing
+ {
+ if(dir == LEFT)
+ tux_body->set_action("stand-left");
+ else // dir == RIGHT
+ tux_body->set_action("stand-right");
+ }
+ else // moving
+ {
+ if(dir == LEFT)
+ tux_body->set_action("walk-left");
+ else // dir == RIGHT
+ tux_body->set_action("walk-right");
+ }
+ }
+
+ if(idle_timer.check())
+ {
+ if(size == BIG)
+ {
+ if(dir == LEFT)
+ tux_body->head->set_action("idle-left", 1);
+ else // dir == RIGHT
+ tux_body->head->set_action("idle-right", 1);
+ }
+
+ }
+
+ // Tux is holding something
+ if ((holding_something && physic.get_velocity_y() == 0) ||
+ (shooting_timer.get_timeleft() > 0 && !shooting_timer.check()))
+ {
+ if (duck)
+ {
+ if(dir == LEFT)
+ tux_body->arms->set_action("duck+grab-left");
+ else // dir == RIGHT
+ tux_body->arms->set_action("duck+grab-right");
+ }
+ else
+ {
+ if(dir == LEFT)
+ tux_body->arms->set_action("grab-left");
+ else // dir == RIGHT
+ tux_body->arms->set_action("grab-right");
+ }
+ }
+
+ /* Draw Tux */
+ if (dying == DYING_SQUISHED) {
+ smalltux_gameover->draw(context, get_pos(), LAYER_FOREGROUNDTILES+1);
+ } else if(growing_timer.get_timeleft() > 0) {
+ if(size == SMALL)
+ {
+ if (dir == RIGHT)
+ context.draw_surface(growingtux_right[GROWING_FRAMES-1 -
+ int((growing_timer.get_timegone() *
+ GROWING_FRAMES) / GROWING_TIME)], get_pos(), layer);
+ else
+ context.draw_surface(growingtux_left[GROWING_FRAMES-1 -
+ int((growing_timer.get_timegone() *
+ GROWING_FRAMES) / GROWING_TIME)], get_pos(), layer);
+ }
+ else
+ {
+ if (dir == RIGHT)
+ context.draw_surface(growingtux_right[
+ int((growing_timer.get_timegone() *
+ GROWING_FRAMES) / GROWING_TIME)], get_pos(), layer);
+ else
+ context.draw_surface(growingtux_left[
+ int((growing_timer.get_timegone() *
+ GROWING_FRAMES) / GROWING_TIME)],
+ get_pos(), layer);
+ }
+ }
+ else if (safe_timer.started() && size_t(global_time*40)%2)
+ ; // don't draw Tux
+ else
+ tux_body->draw(context, get_pos(), layer);
+
+ // Draw blinking star overlay
+ if (invincible_timer.started() &&
+ (invincible_timer.get_timeleft() > TUX_INVINCIBLE_TIME_WARNING
+ || size_t(global_time*20)%2)
+ && !dying)
+ {
+ if (size == SMALL || duck)
+ smalltux_star->draw(context, get_pos(), layer + 5);
+ else
+ bigtux_star->draw(context, get_pos(), layer + 5);
+ }
+
+ if (debug_mode)
+ context.draw_filled_rect(get_pos(),
+ Vector(bbox.get_width(), bbox.get_height()),
+ Color(75,75,75, 150), LAYER_OBJECTS+20);
+}
+
+HitResponse
+Player::collision(GameObject& other, const CollisionHit& hit)
+{
+ if(other.get_flags() & FLAG_SOLID) {
+ if(hit.normal.y < 0) { // landed on floor?
+ if (physic.get_velocity_y() < 0)
+ physic.set_velocity_y(0);
+ on_ground_flag = true;
+ } else if(hit.normal.y > 0) { // bumped against the roof
+ physic.set_velocity_y(.1);
+ }
+
+ if(fabsf(hit.normal.x) > .9) { // hit on the side?
+ physic.set_velocity_x(0);
+ }
+
+ return CONTINUE;
+ }
+
+ TriggerBase* trigger = dynamic_cast<TriggerBase*> (&other);
+ if(trigger) {
+ if(input.up == DOWN && input.old_up == UP)
+ trigger->event(*this, TriggerBase::EVENT_ACTIVATE);
+ }
+
+ return FORCE_MOVE;
+}
+
+void
+Player::make_invincible()
+{
+ SoundManager::get()->play_sound(IDToSound(SND_HERRING));
+ invincible_timer.start(TUX_INVINCIBLE_TIME);
+ Sector::current()->play_music(HERRING_MUSIC);
+}
+
+/* Kill Player! */
+void
+Player::kill(HurtMode mode)
+{
+ if(dying)
+ return;
+
+ if(safe_timer.get_timeleft() > 0 || invincible_timer.get_timeleft() > 0)
+ return;
+
+ SoundManager::get()->play_sound(IDToSound(SND_HURT));
+
+ physic.set_velocity_x(0);
+
+ if (mode == SHRINK && size == BIG)
+ {
+ if (got_power != NONE_POWER)
+ {
+ safe_timer.start(TUX_SAFE_TIME);
+ got_power = NONE_POWER;
+ }
+ else
+ {
+ growing_timer.start(GROWING_TIME);
+ safe_timer.start(TUX_SAFE_TIME + GROWING_TIME);
+ size = SMALL;
+ bbox.set_height(31.8);
+ duck = false;
+ }
+ }
+ else
+ {
+ physic.enable_gravity(true);
+ physic.set_acceleration(0, 0);
+ physic.set_velocity(0, 700);
+ --player_status.lives;
+ dying = DYING_SQUISHED;
+ dying_timer.start(3.0);
+ flags |= FLAG_NO_COLLDET;
+ }
+}
+
+/* Remove Tux's power ups */
+void
+Player::remove_powerups()
+{
+ got_power = NONE_POWER;
+ size = SMALL;
+ bbox.set_height(31.8);
+}
+
+void
+Player::move(const Vector& vector)
+{
+ bbox.set_pos(vector);
+}
+
+void
+Player::check_bounds(Camera* camera)
+{
+ /* Keep tux in bounds: */
+ if (get_pos().x < 0)
+ { // Lock Tux to the size of the level, so that he doesn't fall of
+ // on the left side
+ bbox.set_pos(Vector(0, get_pos().y));
+ }
+
+ /* Keep in-bounds, vertically: */
+ if (get_pos().y > Sector::current()->solids->get_height() * 32)
+ {
+ kill(KILL);
+ return;
+ }
+
+ bool adjust = false;
+ // can happen if back scrolling is disabled
+ if(get_pos().x < camera->get_translation().x) {
+ bbox.set_pos(Vector(camera->get_translation().x, get_pos().y));
+ adjust = true;
+ }
+ if(get_pos().x >= camera->get_translation().x + screen->w - bbox.get_width())
+ {
+ bbox.set_pos(Vector(
+ camera->get_translation().x + screen->w - bbox.get_width(),
+ get_pos().y));
+ adjust = true;
+ }
+
+ if(adjust) {
+ // FIXME
+#if 0
+ // squished now?
+ if(collision_object_map(bbox)) {
+ kill(KILL);
+ return;
+ }
+#endif
+ }
+}
+
+void
+Player::bounce(BadGuy& )
+{
+ //Make sure we stopped flapping
+ flapping = false;
+ falling_from_flap = false;
+
+ if (input.jump)
+ physic.set_velocity_y(520);
+ else
+ physic.set_velocity_y(200);
+}
+
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2003 Tobias Glaesser <tobi.web@gmx.de>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#ifndef SUPERTUX_PLAYER_H
+#define SUPERTUX_PLAYER_H
+
+#include "SDL.h"
+
+#include "timer.h"
+#include "video/surface.h"
+#include "special/moving_object.h"
+#include "special/sprite.h"
+#include "math/physic.h"
+#include "defines.h"
+
+using namespace SuperTux;
+
+class BadGuy;
+
+/* Times: */
+
+#define TUX_SAFE_TIME 1.250
+#define TUX_INVINCIBLE_TIME 10.0
+#define TUX_INVINCIBLE_TIME_WARNING 2.0
+#define TUX_FLAPPING_TIME 1 /* How long Tux can flap his wings to gain additional jump height */
+#define TIME_WARNING 20 /* When to alert player they're low on time! */
+
+/* Scores: */
+
+#define SCORE_BRICK 5
+#define SCORE_DISTRO 20
+
+/* Sizes: */
+
+#define SMALL 0
+#define BIG 1
+
+#include <vector>
+
+struct PlayerKeymap
+{
+public:
+ int jump;
+ int up;
+ int down;
+ int left;
+ int right;
+ int power;
+
+ PlayerKeymap();
+};
+
+extern PlayerKeymap keymap;
+
+struct player_input_type
+{
+ int right;
+ int left;
+ int up;
+ int old_up;
+ int down;
+ int fire;
+ int old_fire;
+ int activate;
+ int jump;
+ int old_jump;
+};
+
+void player_input_init(player_input_type* pplayer_input);
+
+class Camera;
+class PlayerStatus;
+
+extern Surface* tux_life;
+
+extern Sprite* smalltux_gameover;
+extern Sprite* smalltux_star;
+extern Sprite* bigtux_star;
+
+#define GROWING_TIME 1.0
+#define GROWING_FRAMES 7
+extern Surface* growingtux_left[GROWING_FRAMES];
+extern Surface* growingtux_right[GROWING_FRAMES];
+
+class TuxBodyParts
+{
+public:
+ TuxBodyParts()
+ : head(0), body(0), arms(0), feet(0)
+ { }
+ ~TuxBodyParts() {
+ delete head;
+ delete body;
+ delete arms;
+ delete feet;
+ }
+
+ void set_action(std::string action, int loops = -1);
+ void one_time_animation();
+ void draw(DrawingContext& context, const Vector& pos, int layer,
+ Uint32 drawing_effect = NONE_EFFECT);
+
+ Sprite* head;
+ Sprite* body;
+ Sprite* arms;
+ Sprite* feet;
+};
+
+extern TuxBodyParts* small_tux;
+extern TuxBodyParts* big_tux;
+extern TuxBodyParts* fire_tux;
+extern TuxBodyParts* ice_tux;
+
+class Player : public MovingObject
+{
+public:
+ enum HurtMode { KILL, SHRINK };
+ enum Power { NONE_POWER, FIRE_POWER, ICE_POWER };
+ enum FallMode { ON_GROUND, JUMPING, TRAMPOLINE_JUMP, FALLING };
+
+ player_input_type input;
+ int got_power;
+ int size;
+ bool duck;
+ bool holding_something;
+ bool dead;
+ DyingType dying;
+
+ Direction dir;
+ Direction old_dir;
+
+ float last_ground_y;
+ FallMode fall_mode;
+
+ bool on_ground_flag;
+ bool jumping;
+ bool flapping;
+ bool can_jump;
+ bool can_flap;
+ bool falling_from_flap;
+ bool enable_hover;
+ bool butt_jump;
+
+ float flapping_velocity;
+
+ // Ricardo's flapping
+ int flaps_nb;
+
+ // temporary to help player's choosing a flapping
+ enum { MAREK_FLAP, RICARDO_FLAP, RYAN_FLAP, NONE_FLAP };
+ int flapping_mode;
+
+ Timer2 invincible_timer;
+ Timer2 skidding_timer;
+ Timer2 safe_timer;
+ Timer2 kick_timer;
+ Timer2 shooting_timer; // used to show the arm when Tux is shooting
+ Timer2 dying_timer;
+ Timer2 growing_timer;
+ Timer2 idle_timer;
+ Timer2 flapping_timer;
+ Physic physic;
+
+public:
+ Player();
+ virtual ~Player();
+
+ int key_event(SDLKey key, int state);
+ void level_begin();
+ void handle_input();
+ void grabdistros();
+
+ PlayerStatus& get_status();
+
+ virtual void action(float elapsed_time);
+ virtual void draw(DrawingContext& context);
+ virtual HitResponse collision(GameObject& other, const CollisionHit& hit);
+
+ void make_invincible();
+ bool is_invincible() const
+ {
+ return invincible_timer.started();
+ }
+ void kill(HurtMode mode);
+ void player_remove_powerups();
+ void check_bounds(Camera* camera);
+ bool on_ground();
+ bool under_solid();
+ void grow(bool animate = false);
+ void move(const Vector& vector);
+
+ void bounce(BadGuy& badguy);
+
+ bool is_dead() const
+ { return dead; }
+
+private:
+ void init();
+
+ void handle_horizontal_input();
+ void handle_vertical_input();
+ void remove_powerups();
+};
+
+#endif /*SUPERTUX_PLAYER_H*/
+
+/* Local Variables: */
+/* mode:c++ */
+/* End: */
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#include <config.h>
+
+#include <cassert>
+#include <algorithm>
+#include <iostream>
+#include <stdexcept>
+#include <cmath>
+
+#include "tilemap.h"
+#include "video/drawing_context.h"
+#include "level.h"
+#include "tile.h"
+#include "tile_manager.h"
+#include "app/globals.h"
+#include "utils/lispreader.h"
+#include "utils/lispwriter.h"
+
+TileMap::TileMap()
+ : solid(false), speed(1), width(0), height(0), layer(LAYER_TILES),
+ vertical_flip(false)
+{
+ tilemanager = TileManager::instance();
+
+ if(solid)
+ flags |= FLAG_SOLID;
+}
+
+TileMap::TileMap(LispReader& reader)
+ : solid(false), speed(1), width(0), height(0), layer(LAYER_TILES),
+ vertical_flip(false)
+{
+ tilemanager = TileManager::instance();
+
+ std::string layer_str;
+ if(reader.read_string("layer", layer_str)) {
+ if(layer_str == "background")
+ layer = LAYER_BACKGROUNDTILES;
+ else if(layer_str == "interactive")
+ layer = LAYER_TILES;
+ else if(layer_str == "foreground")
+ layer = LAYER_FOREGROUNDTILES;
+ else
+ std::cerr << "Unknown layer '" << layer_str << "' in tilemap.\n";
+ }
+
+ reader.read_bool("solid", solid);
+ reader.read_float("speed", speed);
+
+ if(solid && speed != 1) {
+ std::cout << "Speed of solid tilemap is not 1. fixing.\n";
+ speed = 1;
+ }
+ if(solid)
+ flags |= FLAG_SOLID;
+
+ if(!reader.read_int("width", width) ||
+ !reader.read_int("height", height))
+ throw std::runtime_error("No width or height specified in tilemap.");
+
+ if(!reader.read_int_vector("tiles", tiles))
+ throw std::runtime_error("No tiles in tilemap.");
+
+ if(int(tiles.size()) != width*height)
+ throw std::runtime_error("wrong number of tiles in tilemap.");
+}
+
+TileMap::TileMap(int layer_, bool solid_, size_t width_, size_t height_)
+ : solid(solid_), speed(1), width(0), height(0), layer(layer_),
+ vertical_flip(false)
+{
+ tilemanager = TileManager::instance();
+
+ resize(width_, height_);
+
+ if(solid)
+ flags |= FLAG_SOLID;
+}
+
+TileMap::~TileMap()
+{
+}
+
+void
+TileMap::write(LispWriter& writer)
+{
+ writer.start_list("tilemap");
+
+ if(layer == LAYER_BACKGROUNDTILES)
+ writer.write_string("layer", "background");
+ else if(layer == LAYER_TILES)
+ writer.write_string("layer", "interactive");
+ else if(layer == LAYER_FOREGROUNDTILES)
+ writer.write_string("layer", "foreground");
+ else {
+ writer.write_string("layer", "unknown");
+ std::cerr << "Warning unknown layer in tilemap.\n";
+ }
+
+ writer.write_bool("solid", solid);
+ writer.write_float("speed", speed);
+ writer.write_int("width", width);
+ writer.write_int("height", height);
+ writer.write_int_vector("tiles", tiles);
+
+ writer.end_list("tilemap");
+}
+
+void
+TileMap::action(float )
+{
+}
+
+void
+TileMap::draw(DrawingContext& context)
+{
+ context.push_transform();
+
+ if(vertical_flip)
+ context.set_drawing_effect(VERTICAL_FLIP);
+ float trans_x = roundf(context.get_translation().x);
+ float trans_y = roundf(context.get_translation().y);
+ context.set_translation(Vector(trans_x * speed, trans_y * speed));
+
+ /** if we don't round here, we'll have a 1 pixel gap on screen sometimes.
+ * I have no idea why */
+ float start_x = roundf(context.get_translation().x);
+ float start_y = roundf(context.get_translation().y);
+ float end_x = std::min(start_x + screen->w, float(width * 32));
+ float end_y = std::min(start_y + screen->h, float(height * 32));
+ start_x -= int(start_x) % 32;
+ start_y -= int(start_y) % 32;
+ int tsx = int(start_x / 32); // tilestartindex x
+ int tsy = int(start_y / 32); // tilestartindex y
+
+ Vector pos;
+ int tx, ty;
+ for(pos.x = start_x, tx = tsx; pos.x < end_x; pos.x += 32, ++tx) {
+ for(pos.y = start_y, ty = tsy; pos.y < end_y; pos.y += 32, ++ty) {
+ const Tile* tile = tilemanager->get(tiles[ty*width + tx]);
+ assert(tile != 0);
+ tile->draw(context, pos, layer);
+ }
+ }
+
+ if (debug_grid)
+ {
+ for (pos.x = start_x; pos.x < end_x; pos.x += 32)
+ {
+ context.draw_filled_rect(Vector (pos.x, start_y), Vector(1, fabsf(start_y - end_y)),
+ Color(225, 225, 225), LAYER_GUI-50);
+ }
+
+ for (pos.y = start_y; pos.y < end_y; pos.y += 32)
+ {
+ context.draw_filled_rect(Vector (start_x, pos.y), Vector(fabsf(start_x - end_x), 1),
+ Color(225, 225, 225), LAYER_GUI-50);
+ }
+ }
+
+ context.pop_transform();
+}
+
+void
+TileMap::set(int newwidth, int newheight, const std::vector<unsigned int>&newt,
+ int newlayer, bool newsolid)
+{
+ assert(int(newt.size()) == newwidth * newheight);
+
+ width = newwidth;
+ height = newheight;
+
+ tiles.resize(newt.size());
+ tiles = newt;
+
+ layer = newlayer;
+ solid = newsolid;
+ if(solid)
+ flags |= FLAG_SOLID;
+}
+
+void
+TileMap::resize(int new_width, int new_height)
+{
+ if(new_width < width) {
+ // remap tiles for new width
+ for(int y = 0; y < height && y < new_height; ++y) {
+ for(int x = 0; x < new_width; ++x) {
+ tiles[y * new_width + x] = tiles[y * width + x];
+ }
+ }
+ }
+
+ tiles.resize(new_width * new_height);
+
+ if(new_width > width) {
+ // remap tiles
+ for(int y = std::min(height, new_height)-1; y >= 0; --y) {
+ for(int x = new_width-1; x >= 0; --x) {
+ if(x >= width) {
+ tiles[y * new_width + x] = 0;
+ continue;
+ }
+
+ tiles[y * new_width + x] = tiles[y * width + x];
+ }
+ }
+ }
+
+ height = new_height;
+ width = new_width;
+}
+
+void
+TileMap::do_vertical_flip()
+{
+ // remap tiles vertically flipped
+ for(int y = 0; y < height / 2; ++y) {
+ for(int x = 0; x < width; ++x) {
+ std::swap(tiles[y*width + x], tiles[(((height-1)*width) - (y*width)) + x]);
+ }
+ }
+
+ vertical_flip = true;
+}
+
+const Tile*
+TileMap::get_tile(int x, int y) const
+{
+ if(x < 0 || x >= width || y < 0 || y >= height) {
+#ifdef DEBUG
+ //std::cout << "Warning: tile outside tilemap requested!\n";
+#endif
+ return tilemanager->get(0);
+ }
+
+ return tilemanager->get(tiles[y*width + x]);
+}
+
+const Tile*
+TileMap::get_tile_at(const Vector& pos) const
+{
+ return get_tile(int(pos.x)/32, int(pos.y)/32);
+}
+
+void
+TileMap::change(int x, int y, uint32_t newtile)
+{
+ assert(x >= 0 && x < width && y >= 0 && y < height);
+ tiles[y*width + x] = newtile;
+}
+
+void
+TileMap::change_at(const Vector& pos, uint32_t newtile)
+{
+ change(int(pos.x)/32, int(pos.y)/32, newtile);
+}
--- /dev/null
+// $Id$
+//
+// SuperTux - A Jump'n Run
+// Copyright (C) 2004 Matthias Braun <matze@braunis.de
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#ifndef SUPERTUX_TILEMAP_H
+#define SUPERTUX_TILEMAP_H
+
+#include <vector>
+#include <stdint.h>
+
+#include "special/game_object.h"
+#include "serializable.h"
+#include "math/vector.h"
+
+using namespace SuperTux;
+
+namespace SuperTux {
+class LispReader;
+}
+
+class Level;
+class TileManager;
+class Tile;
+
+/**
+ * This class is reponsible for drawing the level tiles
+ */
+class TileMap : public GameObject, public Serializable
+{
+public:
+ TileMap();
+ TileMap(LispReader& reader);
+ TileMap(int layer_, bool solid_, size_t width_, size_t height_);
+ virtual ~TileMap();
+
+ virtual void write(LispWriter& writer);
+
+ virtual void action(float elapsed_time);
+ virtual void draw(DrawingContext& context);
+
+ void set(int width, int height, const std::vector<unsigned int>& vec,
+ int layer, bool solid);
+
+ /** resizes the tilemap to a new width and height (tries to not destroy the
+ * existing map)
+ */
+ void resize(int newwidth, int newheight);
+
+ /** Flip the all tile map vertically. The purpose of this is to let
+ player to play the same level in a different way :) */
+ void do_vertical_flip();
+
+ size_t get_width() const
+ { return width; }
+
+ size_t get_height() const
+ { return height; }
+
+ int get_layer() const
+ { return layer; }
+
+ bool is_solid() const
+ { return solid; }
+
+ /// returns tile in row y and column y (of the tilemap)
+ const Tile* get_tile(int x, int y) const;
+ /// returns tile at position pos (in world coordinates)
+ const Tile* get_tile_at(const Vector& pos) const;
+
+ void change(int x, int y, uint32_t newtile);
+
+ void change_at(const Vector& pos, uint32_t newtile);
+
+private:
+ std::vector<uint32_t> tiles;
+
+private:
+ TileManager* tilemanager;
+ bool solid;
+ float speed;
+ int width, height;
+ int layer;
+
+ bool vertical_flip;
+};
+
+#endif /*SUPERTUX_TILEMAP_H*/
+
+++ /dev/null
-// $Id$
-//
-// SuperTux
-// Copyright (C) 2004 Matthias Braun <matze@braunis.de>
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-
-#include <config.h>
-
-#include <iostream>
-#include <cmath>
-
-#include "particlesystem.h"
-#include "app/globals.h"
-#include "utils/lispreader.h"
-#include "utils/lispwriter.h"
-#include "video/drawing_context.h"
-
-ParticleSystem::ParticleSystem()
-{
- virtual_width = screen->w;
- virtual_height = screen->h;
- layer = LAYER_BACKGROUND1;
-}
-
-ParticleSystem::~ParticleSystem()
-{
- std::vector<Particle*>::iterator i;
- for(i = particles.begin(); i != particles.end(); ++i) {
- delete *i;
- }
-}
-
-void ParticleSystem::draw(DrawingContext& context)
-{
- float scrollx = context.get_translation().x;
- float scrolly = context.get_translation().y;
-
- context.push_transform();
- context.set_translation(Vector(0,0));
-
- std::vector<Particle*>::iterator i;
- for(i = particles.begin(); i != particles.end(); ++i) {
- Particle* particle = *i;
-
- // remap x,y coordinates onto screencoordinates
- Vector pos;
- pos.x = fmodf(particle->pos.x - scrollx, virtual_width);
- if(pos.x < 0) pos.x += virtual_width;
- pos.y = fmodf(particle->pos.y - scrolly, virtual_height);
- if(pos.y < 0) pos.y += virtual_height;
-
- if(pos.x > screen->w) pos.x -= virtual_width;
- if(pos.y > screen->h) pos.y -= virtual_height;
- context.draw_surface(particle->texture, pos, layer);
- }
-
- context.pop_transform();
-}
-
-SnowParticleSystem::SnowParticleSystem()
-{
- snowimages[0] = new Surface(datadir+"/images/shared/snow0.png", true);
- snowimages[1] = new Surface(datadir+"/images/shared/snow1.png", true);
- snowimages[2] = new Surface(datadir+"/images/shared/snow2.png", true);
-
- virtual_width = screen->w * 2;
-
- // create some random snowflakes
- size_t snowflakecount = size_t(virtual_width/10.0);
- for(size_t i=0; i<snowflakecount; ++i) {
- SnowParticle* particle = new SnowParticle;
- particle->pos.x = rand() % int(virtual_width);
- particle->pos.y = rand() % screen->h;
- int snowsize = rand() % 3;
- particle->texture = snowimages[snowsize];
- do {
- particle->speed = snowsize*.2 + (float(rand()%10)*.4);
- } while(particle->speed < 1);
- particle->speed *= 10; // gravity
-
- particles.push_back(particle);
- }
-}
-
-void
-SnowParticleSystem::parse(LispReader& reader)
-{
- reader.read_int("layer", layer);
-}
-
-void
-SnowParticleSystem::write(LispWriter& writer)
-{
- writer.start_list("particles-snow");
- writer.write_int("layer", layer);
- writer.end_list("particles-snow");
-}
-
-SnowParticleSystem::~SnowParticleSystem()
-{
- for(int i=0;i<3;++i)
- delete snowimages[i];
-}
-
-void SnowParticleSystem::action(float elapsed_time)
-{
- std::vector<Particle*>::iterator i;
- for(i = particles.begin(); i != particles.end(); ++i) {
- SnowParticle* particle = (SnowParticle*) *i;
- particle->pos.y += particle->speed * elapsed_time;
- if(particle->pos.y > screen->h) {
- particle->pos.y = fmodf(particle->pos.y , virtual_height);
- particle->pos.x = rand() % int(virtual_width);
- }
- }
-}
-
-CloudParticleSystem::CloudParticleSystem()
-{
- cloudimage = new Surface(datadir + "/images/shared/cloud.png", true);
-
- virtual_width = 2000.0;
-
- // create some random clouds
- for(size_t i=0; i<15; ++i) {
- CloudParticle* particle = new CloudParticle;
- particle->pos.x = rand() % int(virtual_width);
- particle->pos.y = rand() % int(virtual_height);
- particle->texture = cloudimage;
- particle->speed = -float(25 + rand() % 30);
-
- particles.push_back(particle);
- }
-}
-
-void
-CloudParticleSystem::parse(LispReader& reader)
-{
- reader.read_int("layer", layer);
-}
-
-void
-CloudParticleSystem::write(LispWriter& writer)
-{
- writer.start_list("particles-clouds");
- writer.write_int("layer", layer);
- writer.end_list("particles-clouds");
-}
-
-CloudParticleSystem::~CloudParticleSystem()
-{
- delete cloudimage;
-}
-
-void CloudParticleSystem::action(float elapsed_time)
-{
- std::vector<Particle*>::iterator i;
- for(i = particles.begin(); i != particles.end(); ++i) {
- CloudParticle* particle = (CloudParticle*) *i;
- particle->pos.x += particle->speed * elapsed_time;
- }
-}
+++ /dev/null
-// $Id$
-//
-// SuperTux
-// Copyright (C) 2004 Matthias Braun <matze@braunis.de>
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-#ifndef SUPERTUX_PARTICLESYSTEM_H
-#define SUPERTUX_PARTICLESYSTEM_H
-
-#include <vector>
-
-#include "video/surface.h"
-#include "special/game_object.h"
-#include "serializable.h"
-
-using namespace SuperTux;
-
-namespace SuperTux {
-class LispReader;
-}
-
-class DisplayManager;
-
-/**
- * This is the base class for particle systems. It is responsible for storing a
- * set of particles with each having an x- and y-coordinate the number of the
- * layer where it should be drawn and a texture.
- * The coordinate system used here is a virtual one. It would be a bad idea to
- * populate whole levels with particles. So we're using a virtual rectangle
- * here that is tiled onto the level when drawing. This rectangle has the size
- * (virtual_width, virtual_height). We're using modulo on the particle
- * coordinates, so when a particle leaves left, it'll reenter at the right
- * side.
- *
- * Classes that implement a particle system should subclass from this class,
- * initialize particles in the constructor and move them in the simulate
- * function.
- */
-class ParticleSystem : public GameObject
-{
-public:
- ParticleSystem();
- virtual ~ParticleSystem();
-
- virtual void draw(DrawingContext& context);
-
-protected:
- int layer;
-
- class Particle
- {
- public:
- virtual ~Particle()
- { }
-
- Vector pos;
- Surface* texture;
- };
-
- std::vector<Particle*> particles;
- float virtual_width, virtual_height;
-};
-
-class SnowParticleSystem : public ParticleSystem, public Serializable
-{
-public:
- SnowParticleSystem();
- virtual ~SnowParticleSystem();
-
- void parse(LispReader& reader);
- void write(LispWriter& writer);
-
- virtual void action(float elapsed_time);
-
- std::string type() const
- { return "SnowParticleSystem"; }
-
-private:
- class SnowParticle : public Particle
- {
- public:
- float speed;
- };
-
- Surface* snowimages[3];
-};
-
-class CloudParticleSystem : public ParticleSystem, public Serializable
-{
-public:
- CloudParticleSystem();
- virtual ~CloudParticleSystem();
-
- void parse(LispReader& reader);
- void write(LispWriter& writer);
-
- virtual void action(float elapsed_time);
-
- std::string type() const
- { return "SnowParticleSystem"; }
-
-private:
- class CloudParticle : public Particle
- {
- public:
- float speed;
- };
-
- Surface* cloudimage;
-};
-
-#endif
-
+++ /dev/null
-// $Id$
-//
-// SuperTux - A Jump'n Run
-// Copyright (C) 2003 Tobias Glaesser <tobi.web@gmx.de>
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#include <config.h>
-
-#include <typeinfo>
-#include <cmath>
-#include <iostream>
-#include <cassert>
-
-#include "app/globals.h"
-#include "app/gettext.h"
-#include "player.h"
-#include "defines.h"
-#include "scene.h"
-#include "tile.h"
-#include "special/sprite.h"
-#include "sector.h"
-#include "tilemap.h"
-#include "camera.h"
-#include "gameobjs.h"
-#include "resources.h"
-#include "video/screen.h"
-#include "statistics.h"
-#include "gameloop.h"
-#include "trigger/trigger_base.h"
-
-static const int TILES_FOR_BUTTJUMP = 3;
-static const float SHOOTING_TIME = .150;
-/// time before idle animation starts
-static const float IDLE_TIME = 2.5;
-
-static const float WALK_ACCELERATION_X = 300;
-static const float RUN_ACCELERATION_X = 400;
-static const float SKID_XM = 200;
-static const float SKID_TIME = .3;
-static const float MAX_WALK_XM = 230;
-static const float MAX_RUN_XM = 320;
-static const float WALK_SPEED = 100;
-
-// growing animation
-Surface* growingtux_left[GROWING_FRAMES];
-Surface* growingtux_right[GROWING_FRAMES];
-
-Surface* tux_life = 0;
-
-Sprite* smalltux_gameover = 0;
-Sprite* smalltux_star = 0;
-Sprite* bigtux_star = 0;
-
-TuxBodyParts* small_tux = 0;
-TuxBodyParts* big_tux = 0;
-TuxBodyParts* fire_tux = 0;
-TuxBodyParts* ice_tux = 0;
-
-PlayerKeymap keymap;
-
-PlayerKeymap::PlayerKeymap()
-{
- keymap.up = SDLK_UP;
- keymap.down = SDLK_DOWN;
- keymap.left = SDLK_LEFT;
- keymap.right = SDLK_RIGHT;
-
- keymap.power = SDLK_LCTRL;
- keymap.jump = SDLK_SPACE;
-}
-
-void player_input_init(player_input_type* pplayer_input)
-{
- pplayer_input->up = UP;
- pplayer_input->old_up = UP;
- pplayer_input->down = UP;
- pplayer_input->fire = UP;
- pplayer_input->left = UP;
- pplayer_input->old_fire = UP;
- pplayer_input->right = UP;
- pplayer_input->jump = UP;
- pplayer_input->old_jump = UP;
- pplayer_input->activate = UP;
-}
-
-void
-TuxBodyParts::set_action(std::string action, int loops)
-{
- if(head != NULL)
- head->set_action(action, loops);
- if(body != NULL)
- body->set_action(action, loops);
- if(arms != NULL)
- arms->set_action(action, loops);
- if(feet != NULL)
- feet->set_action(action, loops);
-}
-
-void
-TuxBodyParts::draw(DrawingContext& context, const Vector& pos, int layer,
- Uint32 drawing_effect)
-{
- if(head != NULL)
- head->draw(context, pos, layer-1, drawing_effect);
- if(body != NULL)
- body->draw(context, pos, layer-3, drawing_effect);
- if(arms != NULL)
- arms->draw(context, pos, layer, drawing_effect);
- if(feet != NULL)
- feet->draw(context, pos, layer-2, drawing_effect);
-}
-
-Player::Player()
-{
- init();
-}
-
-Player::~Player()
-{
-}
-
-void
-Player::init()
-{
- holding_something = false;
-
- bbox.set_size(31.8, 31.8);
-
- size = SMALL;
- got_power = NONE_POWER;
-
- dir = RIGHT;
- old_dir = dir;
- duck = false;
- dead = false;
-
- dying = DYING_NOT;
- last_ground_y = 0;
- fall_mode = ON_GROUND;
- jumping = false;
- flapping = false;
- can_jump = true;
- can_flap = false;
- falling_from_flap = false;
- enable_hover = false;
- butt_jump = false;
-
- flapping_velocity = 0;
-
- // temporary to help player's choosing a flapping
- flapping_mode = MAREK_FLAP;
-
- // Ricardo's flapping
- flaps_nb = 0;
-
- on_ground_flag = false;
-
- player_input_init(&input);
-
- physic.reset();
-}
-
-int
-Player::key_event(SDLKey key, int state)
-{
- idle_timer.start(IDLE_TIME, true);
-
- if(key == keymap.right)
- {
- input.right = state;
- return true;
- }
- else if(key == keymap.left)
- {
- input.left = state;
- return true;
- }
- else if(key == keymap.up)
- {
- if(state == UP)
- input.old_up = UP;
- input.up = state;
- /* Up key also opens activates stuff */
- input.activate = state;
- return true;
- }
- else if(key == keymap.down)
- {
- input.down = state;
- return true;
- }
- else if(key == keymap.power)
- {
- if (state == UP)
- input.old_fire = UP;
- input.fire = state;
-
- return true;
- }
- else if(key == keymap.jump)
- {
- if (state == UP)
- input.old_jump = UP;
- input.jump = state;
- return true;
- }
- else
- return false;
-}
-
-void
-Player::level_begin()
-{
- move(Vector(100, 170));
- duck = false;
-
- dying = DYING_NOT;
-
- player_input_init(&input);
-
- on_ground_flag = false;
-
- physic.reset();
-}
-
-PlayerStatus&
-Player::get_status()
-{
- return player_status;
-}
-
-void
-Player::action(float elapsed_time)
-{
- if(dying && dying_timer.check()) {
- dead = true;
- return;
- }
-
- if (input.fire == UP)
- holding_something = false;
-
- if(dying == DYING_NOT)
- handle_input();
-
- movement = physic.get_movement(elapsed_time);
-
-#if 0
- // special exception for cases where we're stuck under tiles after
- // being ducked. In this case we drift out
- if(!duck && on_ground() && old_base.x == base.x && old_base.y == base.y
- && collision_object_map(base))
- {
- base.x += elapsed_time * WALK_SPEED * (dir ? 1: -1);
- previous_base = old_base = base;
- }
-
- /* Reset score multiplier (for multi-hits): */
- if (!invincible_timer.started())
- {
- if(player_status.score_multiplier > player_status.max_score_multiplier)
- {
- player_status.max_score_multiplier = player_status.score_multiplier;
-
- // show a message
- char str[124];
- sprintf(str, _("New max combo: %d"), player_status.max_score_multiplier-1);
- Sector::current()->add_floating_text(base, str);
- }
- player_status.score_multiplier = 1;
- }
- }
-
- }
-#endif
-
- on_ground_flag = false;
-}
-
-bool
-Player::on_ground()
-{
- return on_ground_flag;
-}
-
-void
-Player::handle_horizontal_input()
-{
- float vx = physic.get_velocity_x();
- float vy = physic.get_velocity_y();
- float ax = physic.get_acceleration_x();
- float ay = physic.get_acceleration_y();
-
- float dirsign = 0;
- if(input.left == DOWN && input.right == UP && (!duck || physic.get_velocity_y() != 0)) {
- old_dir = dir;
- dir = LEFT;
- dirsign = -1;
- } else if(input.left == UP && input.right == DOWN && (!duck || physic.get_velocity_y() != 0)) {
- old_dir = dir;
- dir = RIGHT;
- dirsign = 1;
- }
-
- if (input.fire == UP) {
- ax = dirsign * WALK_ACCELERATION_X;
- // limit speed
- if(vx >= MAX_WALK_XM && dirsign > 0) {
- vx = MAX_WALK_XM;
- ax = 0;
- } else if(vx <= -MAX_WALK_XM && dirsign < 0) {
- vx = -MAX_WALK_XM;
- ax = 0;
- }
- } else {
- ax = dirsign * RUN_ACCELERATION_X;
- // limit speed
- if(vx >= MAX_RUN_XM && dirsign > 0) {
- vx = MAX_RUN_XM;
- ax = 0;
- } else if(vx <= -MAX_RUN_XM && dirsign < 0) {
- vx = -MAX_RUN_XM;
- ax = 0;
- }
- }
-
- // we can reach WALK_SPEED without any acceleration
- if(dirsign != 0 && fabs(vx) < WALK_SPEED) {
- vx = dirsign * WALK_SPEED;
- }
-
- // changing directions?
- if(on_ground() && ((vx < 0 && dirsign >0) || (vx>0 && dirsign<0)))
- {
- // let's skid!
- if(fabs(vx)>SKID_XM && !skidding_timer.started())
- {
- skidding_timer.start(SKID_TIME);
- SoundManager::get()->play_sound(IDToSound(SND_SKID));
- // dust some partcles
- Sector::current()->add_object(
- new Particles(
- Vector(bbox.p1.x + (dir == RIGHT ? bbox.get_width() : 0),
- bbox.p2.y),
- dir == RIGHT ? 270+20 : 90-40, dir == RIGHT ? 270+40 : 90-20,
- Vector(280,-260), Vector(0,0.030), 3, Color(100,100,100), 3, .8,
- LAYER_OBJECTS+1));
-
- ax *= 2.5;
- }
- else
- {
- ax *= 2;
- }
- }
-
- // we get slower when not pressing any keys
- if(dirsign == 0) {
- if(fabs(vx) < WALK_SPEED) {
- vx = 0;
- ax = 0;
- } else if(vx < 0) {
- ax = WALK_ACCELERATION_X * 1.5;
- } else {
- ax = WALK_ACCELERATION_X * -1.5;
- }
- }
-
-#if 0
- // if we're on ice slow down acceleration or deceleration
- if (isice(base.x, base.y + base.height))
- {
- /* the acceleration/deceleration rate on ice is inversely proportional to
- * the current velocity.
- */
-
- // increasing 1 will increase acceleration/deceleration rate
- // decreasing 1 will decrease acceleration/deceleration rate
- // must stay above zero, though
- if (ax != 0) ax *= 1 / fabs(vx);
- }
-#endif
-
- // extend/shrink tux collision rectangle so that we fall through/walk over 1
- // tile holes
- if(fabsf(vx) > MAX_WALK_XM) {
- bbox.set_width(33);
- } else {
- bbox.set_width(31.8);
- }
-
- physic.set_velocity(vx, vy);
- physic.set_acceleration(ax, ay);
-}
-
-void
-Player::handle_vertical_input()
-{
- // set fall mode...
- if(on_ground()) {
- fall_mode = ON_GROUND;
- last_ground_y = get_pos().y;
- } else {
- if(get_pos().y > last_ground_y)
- fall_mode = FALLING;
- else if(fall_mode == ON_GROUND)
- fall_mode = JUMPING;
- }
-
- if(on_ground()) { /* Make sure jumping is off. */
- jumping = false;
- flapping = false;
- falling_from_flap = false;
- if (flapping_timer.started()) {
- flapping_timer.start(0);
- }
-
- physic.set_acceleration_y(0); //for flapping
- }
-
- // Press jump key
- if(input.jump == DOWN && can_jump && on_ground())
- {
- if(duck) { // only jump a little bit when in duck mode {
- physic.set_velocity_y(300);
- } else {
- // jump higher if we are running
- if (fabs(physic.get_velocity_x()) > MAX_WALK_XM)
- physic.set_velocity_y(580);
- else
- physic.set_velocity_y(520);
- }
-
- //bbox.move(Vector(0, -1));
- jumping = true;
- flapping = false;
- can_jump = false;
- can_flap = false;
- flaps_nb = 0; // Ricardo's flapping
- if (size == SMALL)
- SoundManager::get()->play_sound(IDToSound(SND_JUMP));
- else
- SoundManager::get()->play_sound(IDToSound(SND_BIGJUMP));
- }
- // Let go of jump key
- else if(input.jump == UP)
- {
- if (!flapping && !duck && !falling_from_flap && !on_ground())
- {
- can_flap = true;
- }
- if (jumping && physic.get_velocity_y() > 0)
- {
- jumping = false;
- physic.set_velocity_y(0);
- }
- }
-
- // temporary to help player's choosing a flapping
- if(flapping_mode == RICARDO_FLAP)
- {
- // Flapping, Ricardo's version
- // similar to SM3 Fox
- if(input.jump == DOWN && input.old_jump == UP && can_flap &&
- flaps_nb < 3)
- {
- physic.set_velocity_y(350);
- physic.set_velocity_x(physic.get_velocity_x() * 35);
- flaps_nb++;
- }
- }
- else if(flapping_mode == MAREK_FLAP)
- {
- // Flapping, Marek's version
- if (input.jump == DOWN && can_flap)
- {
- if (!flapping_timer.started())
- {
- flapping_timer.start(TUX_FLAPPING_TIME);
- flapping_velocity = physic.get_velocity_x();
- }
- if (flapping_timer.check())
- {
- can_flap = false;
- falling_from_flap = true;
- }
- jumping = true;
- flapping = true;
- if (!flapping_timer.check()) {
- float cv = flapping_velocity * sqrt(
- TUX_FLAPPING_TIME - flapping_timer.get_timegone()
- / TUX_FLAPPING_TIME);
-
- //Handle change of direction while flapping
- if (((dir == LEFT) && (cv > 0)) || (dir == RIGHT) && (cv < 0)) {
- cv *= (-1);
- }
- physic.set_velocity_x(cv);
- physic.set_velocity_y(
- flapping_timer.get_timegone()/.850);
- }
- }
- }
- else if(flapping_mode == RYAN_FLAP)
- {
- // Flapping, Ryan's version
- if (input.jump == DOWN && can_flap)
- {
- if (!flapping_timer.started())
- {
- flapping_timer.start(TUX_FLAPPING_TIME);
- }
- if (flapping_timer.check())
- {
- can_flap = false;
- falling_from_flap = true;
- }
- jumping = true;
- flapping = true;
- if (flapping && flapping_timer.get_timegone() <= TUX_FLAPPING_TIME
- && physic.get_velocity_y() < 0)
- {
- float gravity = Sector::current()->gravity;
- (void)gravity;
- float xr = (fabsf(physic.get_velocity_x()) / MAX_RUN_XM);
-
- // XXX: magic numbers. should be a percent of gravity
- // gravity is (by default) -0.1f
- physic.set_acceleration_y(12 + 1*xr);
-
-#if 0
- // To slow down x-vel when flapping (not working)
- if (fabsf(physic.get_velocity_x()) > MAX_WALK_XM)
- {
- if (physic.get_velocity_x() < 0)
- physic.set_acceleration_x(1.0f);
- else if (physic.get_velocity_x() > 0)
- physic.set_acceleration_x(-1.0f);
- }
-#endif
- }
- }
- else
- {
- physic.set_acceleration_y(0);
- }
- }
-
- // Hover
- //(disabled by default, use cheat code "hover" to toggle on/off)
- //TODO: needs some tweaking, especially when used together with double jump and jumping off badguys
- if (enable_hover && input.jump == DOWN && !jumping && !butt_jump && physic.get_velocity_y() <= 0)
- {
- physic.set_velocity_y(-100);
- }
-
-#if 0
- /* In case the player has pressed Down while in a certain range of air,
- enable butt jump action */
- if (input.down == DOWN && !butt_jump && !duck)
- if(tiles_on_air(TILES_FOR_BUTTJUMP) && jumping)
- butt_jump = true;
-#endif
-
- /* When Down is not held anymore, disable butt jump */
- if(butt_jump && input.down == UP)
- butt_jump = false;
-
- // Do butt jump
- if (butt_jump && on_ground() && size == BIG)
- {
- // Add a smoke cloud
- if (duck)
- Sector::current()->add_smoke_cloud(Vector(get_pos().x - 32, get_pos().y));
- else
- Sector::current()->add_smoke_cloud(
- Vector(get_pos().x - 32, get_pos().y + 32));
-
- butt_jump = false;
-
-#if 0
- // Break bricks beneath Tux
- if(Sector::current()->trybreakbrick(
- Vector(base.x + 1, base.y + base.height), false)
- || Sector::current()->trybreakbrick(
- Vector(base.x + base.width - 1, base.y + base.height), false))
- {
- physic.set_velocity_y(2);
- butt_jump = true;
- }
-#endif
-
-#if 0
- // Kill nearby badguys
- std::vector<GameObject*> gameobjects = Sector::current()->gameobjects;
- for (std::vector<GameObject*>::iterator i = gameobjects.begin();
- i != gameobjects.end();
- i++)
- {
- BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
- if(badguy)
- {
- // don't kill when badguys are already dying or in a certain mode
- if(badguy->dying == DYING_NOT && badguy->mode != BadGuy::BOMB_TICKING &&
- badguy->mode != BadGuy::BOMB_EXPLODE)
- {
- if (fabsf(base.x - badguy->base.x) < 96 &&
- fabsf(base.y - badguy->base.y) < 64)
- badguy->kill_me(25);
- }
- }
- }
-#endif
- }
-
- /** jumping is only allowed if we're about to touch ground soon and if the
- * button has been up in between the last jump
- */
- // FIXME
-#if 0
- if ( (issolid(get_pos().x + bbox.get_width() / 2,
- get_pos().y + bbox.get_height() + 64) ||
- issolid(get_pos().x + 1, get_pos().y + bbox.get_height() + 64) ||
- issolid(get_pos().x + bbox.get_width() - 1,
- get_pos().y + bbox.get_height() + 64))
- && jumping == false
- && can_jump == false
- && input.jump == DOWN
- && input.old_jump == UP)
- {
- can_jump = true;
- }
-#endif
-
- input.old_jump = input.jump;
-}
-
-void
-Player::handle_input()
-{
- /* Handle horizontal movement: */
- handle_horizontal_input();
-
- /* Jump/jumping? */
- if (on_ground() && input.jump == UP)
- can_jump = true;
- handle_vertical_input();
-
- /* Shoot! */
- if (input.fire == DOWN && input.old_fire == UP && got_power != NONE_POWER) {
- if(Sector::current()->add_bullet(
- get_pos() + Vector(0, bbox.get_height()/2),
- physic.get_velocity_x(), dir))
- shooting_timer.start(SHOOTING_TIME);
- input.old_fire = DOWN;
- }
-
- /* Duck! */
- if (input.down == DOWN && size == BIG && !duck
- && physic.get_velocity_y() == 0 && on_ground())
- {
- duck = true;
- bbox.move(Vector(0, 32));
- bbox.set_height(31.8);
- }
- else if(input.down == UP && size == BIG && duck)
- {
- // try if we can really unduck
- bbox.move(Vector(0, -32));
- bbox.set_height(63.8);
- duck = false;
- // FIXME
-#if 0
- // when unducking in air we need some space to do so
- if(on_ground() || !collision_object_map(bbox)) {
- duck = false;
- } else {
- // undo the ducking changes
- bbox.move(Vector(0, 32));
- bbox.set_height(31.8);
- }
-#endif
- }
-}
-
-void
-Player::grow(bool animate)
-{
- if(size == BIG)
- return;
-
- size = BIG;
- bbox.set_height(63.8);
- bbox.move(Vector(0, -32));
-
- if(animate)
- growing_timer.start(GROWING_TIME);
-}
-
-void
-Player::grabdistros()
-{
-}
-
-void
-Player::draw(DrawingContext& context)
-{
- TuxBodyParts* tux_body;
-
- if (size == SMALL)
- tux_body = small_tux;
- else if (got_power == FIRE_POWER)
- tux_body = fire_tux;
- else if (got_power == ICE_POWER)
- tux_body = ice_tux;
- else
- tux_body = big_tux;
-
- int layer = LAYER_OBJECTS + 10;
-
- /* Set Tux sprite action */
- if (duck && size == BIG)
- {
- if(dir == LEFT)
- tux_body->set_action("duck-left");
- else // dir == RIGHT
- tux_body->set_action("duck-right");
- }
- else if (skidding_timer.started() && !skidding_timer.check())
- {
- if(dir == LEFT)
- tux_body->set_action("skid-left");
- else // dir == RIGHT
- tux_body->set_action("skid-right");
- }
- else if (kick_timer.started() && !kick_timer.check())
- {
- if(dir == LEFT)
- tux_body->set_action("kick-left");
- else // dir == RIGHT
- tux_body->set_action("kick-right");
- }
- else if (butt_jump && size == BIG)
- {
- if(dir == LEFT)
- tux_body->set_action("buttjump-left");
- else // dir == RIGHT
- tux_body->set_action("buttjump-right");
- }
- else if (physic.get_velocity_y() != 0)
- {
- if(dir == LEFT)
- tux_body->set_action("jump-left");
- else // dir == RIGHT
- tux_body->set_action("jump-right");
- }
- else
- {
- if (fabsf(physic.get_velocity_x()) < 1.0f) // standing
- {
- if(dir == LEFT)
- tux_body->set_action("stand-left");
- else // dir == RIGHT
- tux_body->set_action("stand-right");
- }
- else // moving
- {
- if(dir == LEFT)
- tux_body->set_action("walk-left");
- else // dir == RIGHT
- tux_body->set_action("walk-right");
- }
- }
-
- if(idle_timer.check())
- {
- if(size == BIG)
- {
- if(dir == LEFT)
- tux_body->head->set_action("idle-left", 1);
- else // dir == RIGHT
- tux_body->head->set_action("idle-right", 1);
- }
-
- }
-
- // Tux is holding something
- if ((holding_something && physic.get_velocity_y() == 0) ||
- (shooting_timer.get_timeleft() > 0 && !shooting_timer.check()))
- {
- if (duck)
- {
- if(dir == LEFT)
- tux_body->arms->set_action("duck+grab-left");
- else // dir == RIGHT
- tux_body->arms->set_action("duck+grab-right");
- }
- else
- {
- if(dir == LEFT)
- tux_body->arms->set_action("grab-left");
- else // dir == RIGHT
- tux_body->arms->set_action("grab-right");
- }
- }
-
- /* Draw Tux */
- if (dying == DYING_SQUISHED) {
- smalltux_gameover->draw(context, get_pos(), LAYER_FOREGROUNDTILES+1);
- } else if(growing_timer.get_timeleft() > 0) {
- if(size == SMALL)
- {
- if (dir == RIGHT)
- context.draw_surface(growingtux_right[GROWING_FRAMES-1 -
- int((growing_timer.get_timegone() *
- GROWING_FRAMES) / GROWING_TIME)], get_pos(), layer);
- else
- context.draw_surface(growingtux_left[GROWING_FRAMES-1 -
- int((growing_timer.get_timegone() *
- GROWING_FRAMES) / GROWING_TIME)], get_pos(), layer);
- }
- else
- {
- if (dir == RIGHT)
- context.draw_surface(growingtux_right[
- int((growing_timer.get_timegone() *
- GROWING_FRAMES) / GROWING_TIME)], get_pos(), layer);
- else
- context.draw_surface(growingtux_left[
- int((growing_timer.get_timegone() *
- GROWING_FRAMES) / GROWING_TIME)],
- get_pos(), layer);
- }
- }
- else if (safe_timer.started() && size_t(global_time*40)%2)
- ; // don't draw Tux
- else
- tux_body->draw(context, get_pos(), layer);
-
- // Draw blinking star overlay
- if (invincible_timer.started() &&
- (invincible_timer.get_timeleft() > TUX_INVINCIBLE_TIME_WARNING
- || size_t(global_time*20)%2)
- && !dying)
- {
- if (size == SMALL || duck)
- smalltux_star->draw(context, get_pos(), layer + 5);
- else
- bigtux_star->draw(context, get_pos(), layer + 5);
- }
-
- if (debug_mode)
- context.draw_filled_rect(get_pos(),
- Vector(bbox.get_width(), bbox.get_height()),
- Color(75,75,75, 150), LAYER_OBJECTS+20);
-}
-
-HitResponse
-Player::collision(GameObject& other, const CollisionHit& hit)
-{
- if(other.get_flags() & FLAG_SOLID) {
- if(hit.normal.y < 0) { // landed on floor?
- if (physic.get_velocity_y() < 0)
- physic.set_velocity_y(0);
- on_ground_flag = true;
- } else if(hit.normal.y > 0) { // bumped against the roof
- physic.set_velocity_y(.1);
- }
-
- if(fabsf(hit.normal.x) > .9) { // hit on the side?
- physic.set_velocity_x(0);
- }
-
- return CONTINUE;
- }
-
- TriggerBase* trigger = dynamic_cast<TriggerBase*> (&other);
- if(trigger) {
- if(input.up == DOWN && input.old_up == UP)
- trigger->event(*this, TriggerBase::EVENT_ACTIVATE);
- }
-
- return FORCE_MOVE;
-}
-
-void
-Player::make_invincible()
-{
- SoundManager::get()->play_sound(IDToSound(SND_HERRING));
- invincible_timer.start(TUX_INVINCIBLE_TIME);
- Sector::current()->play_music(HERRING_MUSIC);
-}
-
-/* Kill Player! */
-void
-Player::kill(HurtMode mode)
-{
- if(dying)
- return;
-
- if(safe_timer.get_timeleft() > 0 || invincible_timer.get_timeleft() > 0)
- return;
-
- SoundManager::get()->play_sound(IDToSound(SND_HURT));
-
- physic.set_velocity_x(0);
-
- if (mode == SHRINK && size == BIG)
- {
- if (got_power != NONE_POWER)
- {
- safe_timer.start(TUX_SAFE_TIME);
- got_power = NONE_POWER;
- }
- else
- {
- growing_timer.start(GROWING_TIME);
- safe_timer.start(TUX_SAFE_TIME + GROWING_TIME);
- size = SMALL;
- bbox.set_height(31.8);
- duck = false;
- }
- }
- else
- {
- physic.enable_gravity(true);
- physic.set_acceleration(0, 0);
- physic.set_velocity(0, 700);
- --player_status.lives;
- dying = DYING_SQUISHED;
- dying_timer.start(3.0);
- flags |= FLAG_NO_COLLDET;
- }
-}
-
-/* Remove Tux's power ups */
-void
-Player::remove_powerups()
-{
- got_power = NONE_POWER;
- size = SMALL;
- bbox.set_height(31.8);
-}
-
-void
-Player::move(const Vector& vector)
-{
- bbox.set_pos(vector);
-}
-
-void
-Player::check_bounds(Camera* camera)
-{
- /* Keep tux in bounds: */
- if (get_pos().x < 0)
- { // Lock Tux to the size of the level, so that he doesn't fall of
- // on the left side
- bbox.set_pos(Vector(0, get_pos().y));
- }
-
- /* Keep in-bounds, vertically: */
- if (get_pos().y > Sector::current()->solids->get_height() * 32)
- {
- kill(KILL);
- return;
- }
-
- bool adjust = false;
- // can happen if back scrolling is disabled
- if(get_pos().x < camera->get_translation().x) {
- bbox.set_pos(Vector(camera->get_translation().x, get_pos().y));
- adjust = true;
- }
- if(get_pos().x >= camera->get_translation().x + screen->w - bbox.get_width())
- {
- bbox.set_pos(Vector(
- camera->get_translation().x + screen->w - bbox.get_width(),
- get_pos().y));
- adjust = true;
- }
-
- if(adjust) {
- // FIXME
-#if 0
- // squished now?
- if(collision_object_map(bbox)) {
- kill(KILL);
- return;
- }
-#endif
- }
-}
-
-void
-Player::bounce(BadGuy& )
-{
- //Make sure we stopped flapping
- flapping = false;
- falling_from_flap = false;
-
- if (input.jump)
- physic.set_velocity_y(520);
- else
- physic.set_velocity_y(200);
-}
-
+++ /dev/null
-// $Id$
-//
-// SuperTux - A Jump'n Run
-// Copyright (C) 2003 Tobias Glaesser <tobi.web@gmx.de>
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#ifndef SUPERTUX_PLAYER_H
-#define SUPERTUX_PLAYER_H
-
-#include "SDL.h"
-
-#include "timer.h"
-#include "video/surface.h"
-#include "special/moving_object.h"
-#include "special/sprite.h"
-#include "math/physic.h"
-#include "defines.h"
-
-using namespace SuperTux;
-
-class BadGuy;
-
-/* Times: */
-
-#define TUX_SAFE_TIME 1.250
-#define TUX_INVINCIBLE_TIME 10.0
-#define TUX_INVINCIBLE_TIME_WARNING 2.0
-#define TUX_FLAPPING_TIME 1 /* How long Tux can flap his wings to gain additional jump height */
-#define TIME_WARNING 20 /* When to alert player they're low on time! */
-
-/* Scores: */
-
-#define SCORE_BRICK 5
-#define SCORE_DISTRO 20
-
-/* Sizes: */
-
-#define SMALL 0
-#define BIG 1
-
-#include <vector>
-
-struct PlayerKeymap
-{
-public:
- int jump;
- int up;
- int down;
- int left;
- int right;
- int power;
-
- PlayerKeymap();
-};
-
-extern PlayerKeymap keymap;
-
-struct player_input_type
-{
- int right;
- int left;
- int up;
- int old_up;
- int down;
- int fire;
- int old_fire;
- int activate;
- int jump;
- int old_jump;
-};
-
-void player_input_init(player_input_type* pplayer_input);
-
-class Camera;
-class PlayerStatus;
-
-extern Surface* tux_life;
-
-extern Sprite* smalltux_gameover;
-extern Sprite* smalltux_star;
-extern Sprite* bigtux_star;
-
-#define GROWING_TIME 1.0
-#define GROWING_FRAMES 7
-extern Surface* growingtux_left[GROWING_FRAMES];
-extern Surface* growingtux_right[GROWING_FRAMES];
-
-class TuxBodyParts
-{
-public:
- TuxBodyParts()
- : head(0), body(0), arms(0), feet(0)
- { }
- ~TuxBodyParts() {
- delete head;
- delete body;
- delete arms;
- delete feet;
- }
-
- void set_action(std::string action, int loops = -1);
- void one_time_animation();
- void draw(DrawingContext& context, const Vector& pos, int layer,
- Uint32 drawing_effect = NONE_EFFECT);
-
- Sprite* head;
- Sprite* body;
- Sprite* arms;
- Sprite* feet;
-};
-
-extern TuxBodyParts* small_tux;
-extern TuxBodyParts* big_tux;
-extern TuxBodyParts* fire_tux;
-extern TuxBodyParts* ice_tux;
-
-class Player : public MovingObject
-{
-public:
- enum HurtMode { KILL, SHRINK };
- enum Power { NONE_POWER, FIRE_POWER, ICE_POWER };
- enum FallMode { ON_GROUND, JUMPING, TRAMPOLINE_JUMP, FALLING };
-
- player_input_type input;
- int got_power;
- int size;
- bool duck;
- bool holding_something;
- bool dead;
- DyingType dying;
-
- Direction dir;
- Direction old_dir;
-
- float last_ground_y;
- FallMode fall_mode;
-
- bool on_ground_flag;
- bool jumping;
- bool flapping;
- bool can_jump;
- bool can_flap;
- bool falling_from_flap;
- bool enable_hover;
- bool butt_jump;
-
- float flapping_velocity;
-
- // Ricardo's flapping
- int flaps_nb;
-
- // temporary to help player's choosing a flapping
- enum { MAREK_FLAP, RICARDO_FLAP, RYAN_FLAP, NONE_FLAP };
- int flapping_mode;
-
- Timer2 invincible_timer;
- Timer2 skidding_timer;
- Timer2 safe_timer;
- Timer2 kick_timer;
- Timer2 shooting_timer; // used to show the arm when Tux is shooting
- Timer2 dying_timer;
- Timer2 growing_timer;
- Timer2 idle_timer;
- Timer2 flapping_timer;
- Physic physic;
-
-public:
- Player();
- virtual ~Player();
-
- int key_event(SDLKey key, int state);
- void level_begin();
- void handle_input();
- void grabdistros();
-
- PlayerStatus& get_status();
-
- virtual void action(float elapsed_time);
- virtual void draw(DrawingContext& context);
- virtual HitResponse collision(GameObject& other, const CollisionHit& hit);
-
- void make_invincible();
- bool is_invincible() const
- {
- return invincible_timer.started();
- }
- void kill(HurtMode mode);
- void player_remove_powerups();
- void check_bounds(Camera* camera);
- bool on_ground();
- bool under_solid();
- void grow(bool animate = false);
- void move(const Vector& vector);
-
- void bounce(BadGuy& badguy);
-
- bool is_dead() const
- { return dead; }
-
-private:
- void init();
-
- void handle_horizontal_input();
- void handle_vertical_input();
- void remove_powerups();
-};
-
-#endif /*SUPERTUX_PLAYER_H*/
-
-/* Local Variables: */
-/* mode:c++ */
-/* End: */
#include "gui/menu.h"
#include "gui/button.h"
#include "scene.h"
-#include "player.h"
-#include "gameobjs.h"
#include "resources.h"
+#include "object/gameobjs.h"
+#include "object/player.h"
Surface* img_waves[3];
Surface* img_water;
#include "app/globals.h"
#include "sector.h"
#include "utils/lispreader.h"
-#include "gameobjs.h"
-#include "camera.h"
-#include "background.h"
-#include "particlesystem.h"
+#include "object/gameobjs.h"
+#include "object/camera.h"
+#include "object/background.h"
+#include "object/particlesystem.h"
+#include "object/tilemap.h"
#include "tile.h"
-#include "tilemap.h"
#include "audio/sound_manager.h"
#include "gameloop.h"
#include "resources.h"
song_title = "Mortimers_chipdisko.mod";
player = new Player();
add_object(player);
-
- printf("seccreated: %p.\n", this);
}
Sector::~Sector()
{
- printf("secdel: %p.\n", this);
+ update_game_objects();
+ assert(gameobjects_new.size() == 0);
+
for(GameObjects::iterator i = gameobjects.begin(); i != gameobjects.end();
++i) {
delete *i;
_current = 0;
}
-Sector *Sector::create(const std::string& name, size_t width, size_t height)
-{
- Sector *sector = new Sector;
- sector->name = name;
- TileMap *background = new TileMap(LAYER_BACKGROUNDTILES, false, width, height);
- TileMap *interactive = new TileMap(LAYER_TILES, true, width, height);
- TileMap *foreground = new TileMap(LAYER_FOREGROUNDTILES, false, width, height);
- sector->add_object(background);
- sector->add_object(interactive);
- sector->add_object(foreground);
- sector->solids = interactive;
- sector->camera = new Camera(sector);
- sector->add_object(sector->camera);
- sector->update_game_objects();
- return sector;
-}
-
GameObject*
Sector::parse_object(const std::string& name, LispReader& reader)
{
} else if(name == "nolok_01") {
return new Nolok_01(reader);
}
-#if 0
- else if(badguykind_from_string(name) != BAD_INVALID) {
- return new BadGuy(badguykind_from_string(name), reader);
- } else if(name == "trampoline") {
- return new Trampoline(reader);
- } else if(name == "flying-platform") {
- return new FlyingPlatform(reader);
-#endif
std::cerr << "Unknown object type '" << name << "'.\n";
return 0;
}
}
+ update_game_objects();
+ fix_old_tiles();
+ update_game_objects();
if(!camera) {
std::cerr << "sector '" << name << "' does not contain a camera.\n";
camera = new Camera(this);
bkgd_bottom.blue = b;
if(backgroundimage != "") {
- background = new Background;
+ Background* background = new Background;
background->set_image(backgroundimage, bgspeed);
add_object(background);
} else {
- background = new Background;
+ Background* background = new Background;
background->set_gradient(bkgd_top, bkgd_bottom);
add_object(background);
}
|| reader.read_int_vector("tilemap", tiles)) {
TileMap* tilemap = new TileMap();
tilemap->set(width, height, tiles, LAYER_TILES, true);
- solids = tilemap;
add_object(tilemap);
-
- fix_old_tiles();
}
if(reader.read_int_vector("background-tm", tiles)) {
}
// add a camera
- camera = new Camera(this);
+ Camera* camera = new Camera(this);
add_object(camera);
+
+ update_game_objects();
+ fix_old_tiles();
+ update_game_objects();
+ if(solids == 0)
+ throw std::runtime_error("sector does not contain a solid tile layer.");
}
void
}
void
-Sector::do_vertical_flip()
-{
- // remove or fix later
-#if 0
- for(GameObjects::iterator i = gameobjects_new.begin(); i != gameobjects_new.end(); ++i)
- {
- TileMap* tilemap = dynamic_cast<TileMap*> (*i);
- if(tilemap)
- {
- tilemap->do_vertical_flip();
- }
-
- BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
- if(badguy)
- badguy->start_position.y = solids->get_height()*32 - badguy->start_position.y - 32;
- Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
- if(trampoline)
- trampoline->base.y = solids->get_height()*32 - trampoline->base.y - 32;
- FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
- if(flying_platform)
- flying_platform->base.y = solids->get_height()*32 - flying_platform->base.y - 32;
- Door* door = dynamic_cast<Door*> (*i);
- if(door)
- door->set_area(door->get_area().x, solids->get_height()*32 - door->get_area().y - 32);
- }
-
- for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
- ++i) {
- SpawnPoint* spawn = *i;
- spawn->pos.y = solids->get_height()*32 - spawn->pos.y - 32;
- }
-#endif
-}
-
-void
Sector::add_object(GameObject* object)
{
// make sure the object isn't already in the list
}
/* Handle all possible collisions. */
- collision_handler();
-
+ collision_handler();
update_game_objects();
}
if(tilemap && tilemap->is_solid()) {
if(solids == 0) {
solids = tilemap;
- fix_old_tiles();
} else {
std::cerr << "Another solid tilemaps added. Ignoring.";
}
}
}
-void
-Sector::add_score(const Vector& pos, int s)
-{
- global_stats.add_points(SCORE_STAT, s);
-
- add_object(new FloatingText(pos, s));
-}
-
bool
Sector::add_bullet(const Vector& pos, float xm, Direction dir)
{
Sector();
~Sector();
- /// create new sector
- static Sector *create(const std::string& name, size_t width, size_t height);
/// read sector from lisp file
void parse(LispReader& reader);
void parse_old_format(LispReader& reader);
/// adds a gameobject
void add_object(GameObject* object);
+ void set_name(const std::string& name)
+ { this->name = name; }
const std::string& get_name() const
{ return name; }
case (or not). */
void collision_handler();
- void add_score(const Vector& pos, int s);
-
bool add_bullet(const Vector& pos, float xm, Direction dir);
bool add_smoke_cloud(const Vector& pos);
void add_floating_text(const Vector& pos, const std::string& text);
- /** Flip the all the sector vertically. The purpose of this is to let
- player to play the same level in a different way :) */
- void do_vertical_flip();
-
/** @evil@ but can#t always be avoided in current design... */
static Sector* current()
{ return _current; }
#include "video/surface.h"
#include "tile_manager.h"
#include "app/gettext.h"
-#include "player.h"
#include "misc.h"
#include "utils/configfile.h"
+++ /dev/null
-// $Id$
-//
-// SuperTux - A Jump'n Run
-// Copyright (C) 2004 Matthias Braun <matze@braunis.de
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#include <config.h>
-
-#include <cassert>
-#include <algorithm>
-#include <iostream>
-#include <stdexcept>
-#include <cmath>
-
-#include "tilemap.h"
-#include "video/drawing_context.h"
-#include "level.h"
-#include "tile.h"
-#include "tile_manager.h"
-#include "app/globals.h"
-#include "utils/lispreader.h"
-#include "utils/lispwriter.h"
-
-TileMap::TileMap()
- : solid(false), speed(1), width(0), height(0), layer(LAYER_TILES),
- vertical_flip(false)
-{
- tilemanager = TileManager::instance();
-
- if(solid)
- flags |= FLAG_SOLID;
-}
-
-TileMap::TileMap(LispReader& reader)
- : solid(false), speed(1), width(0), height(0), layer(LAYER_TILES),
- vertical_flip(false)
-{
- tilemanager = TileManager::instance();
-
- std::string layer_str;
- if(reader.read_string("layer", layer_str)) {
- if(layer_str == "background")
- layer = LAYER_BACKGROUNDTILES;
- else if(layer_str == "interactive")
- layer = LAYER_TILES;
- else if(layer_str == "foreground")
- layer = LAYER_FOREGROUNDTILES;
- else
- std::cerr << "Unknown layer '" << layer_str << "' in tilemap.\n";
- }
-
- reader.read_bool("solid", solid);
- reader.read_float("speed", speed);
-
- if(solid && speed != 1) {
- std::cout << "Speed of solid tilemap is not 1. fixing.\n";
- speed = 1;
- }
- if(solid)
- flags |= FLAG_SOLID;
-
- if(!reader.read_int("width", width) ||
- !reader.read_int("height", height))
- throw std::runtime_error("No width or height specified in tilemap.");
-
- if(!reader.read_int_vector("tiles", tiles))
- throw std::runtime_error("No tiles in tilemap.");
-
- if(int(tiles.size()) != width*height)
- throw std::runtime_error("wrong number of tiles in tilemap.");
-}
-
-TileMap::TileMap(int layer_, bool solid_, size_t width_, size_t height_)
- : solid(solid_), speed(1), width(0), height(0), layer(layer_),
- vertical_flip(false)
-{
- tilemanager = TileManager::instance();
-
- resize(width_, height_);
-
- if(solid)
- flags |= FLAG_SOLID;
-}
-
-TileMap::~TileMap()
-{
-}
-
-void
-TileMap::write(LispWriter& writer)
-{
- writer.start_list("tilemap");
-
- if(layer == LAYER_BACKGROUNDTILES)
- writer.write_string("layer", "background");
- else if(layer == LAYER_TILES)
- writer.write_string("layer", "interactive");
- else if(layer == LAYER_FOREGROUNDTILES)
- writer.write_string("layer", "foreground");
- else {
- writer.write_string("layer", "unknown");
- std::cerr << "Warning unknown layer in tilemap.\n";
- }
-
- writer.write_bool("solid", solid);
- writer.write_float("speed", speed);
- writer.write_int("width", width);
- writer.write_int("height", height);
- writer.write_int_vector("tiles", tiles);
-
- writer.end_list("tilemap");
-}
-
-void
-TileMap::action(float )
-{
-}
-
-void
-TileMap::draw(DrawingContext& context)
-{
- context.push_transform();
-
- if(vertical_flip)
- context.set_drawing_effect(VERTICAL_FLIP);
- float trans_x = roundf(context.get_translation().x);
- float trans_y = roundf(context.get_translation().y);
- context.set_translation(Vector(trans_x * speed, trans_y * speed));
-
- /** if we don't round here, we'll have a 1 pixel gap on screen sometimes.
- * I have no idea why */
- float start_x = roundf(context.get_translation().x);
- float start_y = roundf(context.get_translation().y);
- float end_x = std::min(start_x + screen->w, float(width * 32));
- float end_y = std::min(start_y + screen->h, float(height * 32));
- start_x -= int(start_x) % 32;
- start_y -= int(start_y) % 32;
- int tsx = int(start_x / 32); // tilestartindex x
- int tsy = int(start_y / 32); // tilestartindex y
-
- Vector pos;
- int tx, ty;
- for(pos.x = start_x, tx = tsx; pos.x < end_x; pos.x += 32, ++tx) {
- for(pos.y = start_y, ty = tsy; pos.y < end_y; pos.y += 32, ++ty) {
- const Tile* tile = tilemanager->get(tiles[ty*width + tx]);
- assert(tile != 0);
- tile->draw(context, pos, layer);
- }
- }
-
- if (debug_grid)
- {
- for (pos.x = start_x; pos.x < end_x; pos.x += 32)
- {
- context.draw_filled_rect(Vector (pos.x, start_y), Vector(1, fabsf(start_y - end_y)),
- Color(225, 225, 225), LAYER_GUI-50);
- }
-
- for (pos.y = start_y; pos.y < end_y; pos.y += 32)
- {
- context.draw_filled_rect(Vector (start_x, pos.y), Vector(fabsf(start_x - end_x), 1),
- Color(225, 225, 225), LAYER_GUI-50);
- }
- }
-
- context.pop_transform();
-}
-
-void
-TileMap::set(int newwidth, int newheight, const std::vector<unsigned int>&newt,
- int newlayer, bool newsolid)
-{
- assert(int(newt.size()) == newwidth * newheight);
-
- width = newwidth;
- height = newheight;
-
- tiles.resize(newt.size());
- tiles = newt;
-
- layer = newlayer;
- solid = newsolid;
- if(solid)
- flags |= FLAG_SOLID;
-}
-
-void
-TileMap::resize(int new_width, int new_height)
-{
- if(new_width < width) {
- // remap tiles for new width
- for(int y = 0; y < height && y < new_height; ++y) {
- for(int x = 0; x < new_width; ++x) {
- tiles[y * new_width + x] = tiles[y * width + x];
- }
- }
- }
-
- tiles.resize(new_width * new_height);
-
- if(new_width > width) {
- // remap tiles
- for(int y = std::min(height, new_height)-1; y >= 0; --y) {
- for(int x = new_width-1; x >= 0; --x) {
- if(x >= width) {
- tiles[y * new_width + x] = 0;
- continue;
- }
-
- tiles[y * new_width + x] = tiles[y * width + x];
- }
- }
- }
-
- height = new_height;
- width = new_width;
-}
-
-void
-TileMap::do_vertical_flip()
-{
- // remap tiles vertically flipped
- for(int y = 0; y < height / 2; ++y) {
- for(int x = 0; x < width; ++x) {
- std::swap(tiles[y*width + x], tiles[(((height-1)*width) - (y*width)) + x]);
- }
- }
-
- vertical_flip = true;
-}
-
-const Tile*
-TileMap::get_tile(int x, int y) const
-{
- if(x < 0 || x >= width || y < 0 || y >= height) {
-#ifdef DEBUG
- //std::cout << "Warning: tile outside tilemap requested!\n";
-#endif
- return tilemanager->get(0);
- }
-
- return tilemanager->get(tiles[y*width + x]);
-}
-
-const Tile*
-TileMap::get_tile_at(const Vector& pos) const
-{
- return get_tile(int(pos.x)/32, int(pos.y)/32);
-}
-
-void
-TileMap::change(int x, int y, uint32_t newtile)
-{
- assert(x >= 0 && x < width && y >= 0 && y < height);
- tiles[y*width + x] = newtile;
-}
-
-void
-TileMap::change_at(const Vector& pos, uint32_t newtile)
-{
- change(int(pos.x)/32, int(pos.y)/32, newtile);
-}
+++ /dev/null
-// $Id$
-//
-// SuperTux - A Jump'n Run
-// Copyright (C) 2004 Matthias Braun <matze@braunis.de
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License
-// as published by the Free Software Foundation; either version 2
-// of the License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
-#ifndef SUPERTUX_TILEMAP_H
-#define SUPERTUX_TILEMAP_H
-
-#include <vector>
-#include <stdint.h>
-
-#include "special/game_object.h"
-#include "serializable.h"
-#include "math/vector.h"
-
-using namespace SuperTux;
-
-namespace SuperTux {
-class LispReader;
-}
-
-class Level;
-class TileManager;
-class Tile;
-
-/**
- * This class is reponsible for drawing the level tiles
- */
-class TileMap : public GameObject, public Serializable
-{
-public:
- TileMap();
- TileMap(LispReader& reader);
- TileMap(int layer_, bool solid_, size_t width_, size_t height_);
- virtual ~TileMap();
-
- virtual void write(LispWriter& writer);
-
- virtual void action(float elapsed_time);
- virtual void draw(DrawingContext& context);
-
- void set(int width, int height, const std::vector<unsigned int>& vec,
- int layer, bool solid);
-
- /** resizes the tilemap to a new width and height (tries to not destroy the
- * existing map)
- */
- void resize(int newwidth, int newheight);
-
- /** Flip the all tile map vertically. The purpose of this is to let
- player to play the same level in a different way :) */
- void do_vertical_flip();
-
- size_t get_width() const
- { return width; }
-
- size_t get_height() const
- { return height; }
-
- int get_layer() const
- { return layer; }
-
- bool is_solid() const
- { return solid; }
-
- /// returns tile in row y and column y (of the tilemap)
- const Tile* get_tile(int x, int y) const;
- /// returns tile at position pos (in world coordinates)
- const Tile* get_tile_at(const Vector& pos) const;
-
- void change(int x, int y, uint32_t newtile);
-
- void change_at(const Vector& pos, uint32_t newtile);
-
-private:
- std::vector<uint32_t> tiles;
-
-private:
- TileManager* tilemanager;
- bool solid;
- float speed;
- int width, height;
- int layer;
-
- bool vertical_flip;
-};
-
-#endif /*SUPERTUX_TILEMAP_H*/
-
#include "worldmap.h"
#include "leveleditor.h"
#include "scene.h"
-#include "player.h"
#include "tile.h"
#include "sector.h"
-#include "tilemap.h"
+#include "object/tilemap.h"
+#include "object/camera.h"
+#include "object/player.h"
#include "resources.h"
#include "app/gettext.h"
#include "misc.h"
-#include "camera.h"
static Surface* bkg_title;
static Surface* logo;
#include <config.h>
#include "trigger_base.h"
-#include "player.h"
#include "video/drawing_context.h"
+#include "object/player.h"
TriggerBase::TriggerBase()
: sprite(0)