(music "theme.mod")
(background "arctis.jpg")
(particle_system "")
- (bkgd_speed "2")
+ (bkgd_speed 0.5)
(bkgd_red_top 0)
(bkgd_green_top 0)
(bkgd_blue_top 0)
(music "forest.mod")
(background "cave2.jpg")
(particle_system "")
- (bkgd_speed 50)
+ (bkgd_speed 0.5)
(bkgd_red_top 150)
(bkgd_green_top 200)
(bkgd_blue_top 255)
--- /dev/null
+(supertux-level
+ (version 2)
+ (name "Sector Test")
+ (author "Matthias Braun")
+ (time 500)
+ (sector
+ (name "main")
+ (gravity 10)
+ (camera
+ (mode "normal")
+ )
+ (playerspawn
+ (name "main")
+ (x 100)
+ (y 170)
+ )
+ (tilemap
+ (layer "interactive")
+ (solid #t)
+ (speed 1.)
+ (width 50)
+ (height 15)
+ (tiles
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 48 0 0 0 0 0 0 0 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 27 28 28 28 28 28 28 28 29 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 0 0 48 0 0 48 0 0 0 0 0 0 48 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 48 48 48 48 48 48 48 48 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 48 0 0 0 0 0 0 0 48 0 0 0 48 0 0 0 0 0 0 48 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 7 8 8 8 8 8 48 0 0 0 0 7 8 8 48 76 76 76 48 8 8 8 8 8 8 48 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8
+ 28 28 28 28 28 28 28 28 28 28 28 28 28 28 48 75 75 75 48 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14 14
+ 10 11 11 11 11 11 11 11 11 11 11 11 11 11 48 48 48 48 48 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11
+ 10 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11 11
+ )
+ )
+ (background
+ (image "arctis.jpg")
+ (speed 0.5)
+ )
+ (fish (x 509) (y 181))
+ (flyingsnowball (x 941) (y 222))
+ (spiky (x 656) (y 306))
+ (snowball (x 259) (y 303))
+ (stalactite (x 1159) (y 288))
+ (stalactite (x 1235) (y 288))
+ (laptop (x 1198) (y 186))
+ (mriceblock (x 323) (y 74))
+ )
+)
(music "Mortimers_chipdisko.mod")
(background "")
(particle_system "")
- (bkgd_speed 50)
+ (bkgd_speed 0.5)
(bkgd_red_top 0)
(bkgd_green_top 0)
(bkgd_blue_top 255)
(music "Mortimers_chipdisko.mod")
(background "")
(particle_system "")
- (bkgd_speed 50)
- (bkgd_red_top 150)
+ (bkgd_speed 0.5)
+ (bkgd_red_top 50)
(bkgd_green_top 150)
(bkgd_blue_top 150)
(bkgd_red_bottom 150)
(music "Mortimers_chipdisko.mod")
(background "")
(particle_system "")
- (bkgd_speed 50)
+ (bkgd_speed 0.5)
(bkgd_red_top 150)
(bkgd_green_top 150)
(bkgd_blue_top 150)
(point (x 7889) (y 327))
)
(objects
- (mriceblock (x 613) (y 367))
+ (mriceblock
+ (x 613)
+ (y 367)
+ )
(mrbomb (x 5833) (y 353))
(mrbomb (x 6091) (y 334))
(money (x 6640) (y 288))
title.h \
type.cpp \
type.h \
-world.cpp \
-world.h \
worldmap.cpp \
worldmap.h \
tile.h \
moving_object.cpp \
serializable.h \
vector.cpp \
-vector.h
+vector.h \
+sector.cpp \
+sector.h
# EOF #
#include "globals.h"
#include "camera.h"
#include "screen/drawing_context.h"
+#include "lispwriter.h"
Background::Background()
: type(INVALID), image(0)
{
}
+Background::Background(LispReader& reader)
+ : type(INVALID), image(0)
+{
+ if(reader.read_string("image", imagefile)
+ && reader.read_float("speed", speed)) {
+ set_image(imagefile, speed);
+ }
+
+ int tr, tg, tb, br, bg, bb;
+ if(reader.read_int("top_red", tr) && reader.read_int("top_green", tg)
+ && reader.read_int("top_blue", tb) && reader.read_int("bottom_red", br)
+ && reader.read_int("bottom_green", br)
+ && reader.read_int("bottom_blue", bb)) {
+ set_gradient(Color(tr, tg, tb), Color(br, bg, bb));
+ }
+}
+
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) {
+ writer.write_int("top_red", gradient_top.red);
+ writer.write_int("top_green", gradient_top.green);
+ writer.write_int("top_blue", gradient_top.blue);
+ writer.write_int("bottom_red", gradient_bottom.red);
+ writer.write_int("bottom_green", gradient_bottom.green);
+ writer.write_int("bottom_blue", gradient_bottom.blue);
+ }
+
+ writer.end_list("background");
+}
+
+void
Background::action(float)
{
}
void
Background::set_image(const std::string& name, float speed)
{
- type = IMAGE;
+ this->type = IMAGE;
+ this->imagefile = name;
this->speed = speed;
delete image;
if(type == GRADIENT) {
context.draw_gradient(gradient_top, gradient_bottom, LAYER_BACKGROUND0);
} else if(type == IMAGE) {
- int sx = int(-context.get_translation().x * float(speed/100.))
+ int sx = int(-context.get_translation().x * speed)
% image->w - image->w;
- int sy = int(-context.get_translation().y * float(speed/100.))
+ int sy = int(-context.get_translation().y * speed)
% image->h - image->h;
context.push_transform();
context.set_translation(Vector(0, 0));
#include "screen/texture.h"
#include "screen/drawing_context.h"
#include "game_object.h"
+#include "lispreader.h"
+#include "serializable.h"
class DisplayManager;
-class Background : public GameObject
+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);
};
Type type;
+ std::string imagefile;
float speed;
Surface* image;
Color gradient_top, gradient_bottom;
#include "tile.h"
#include "resources.h"
#include "sprite_manager.h"
-#include "world.h"
#include "camera.h"
#include "lispwriter.h"
#include "level.h"
+#include "sector.h"
+#include "tilemap.h"
Sprite* img_mriceblock_flat_left;
Sprite* img_mriceblock_flat_right;
return BAD_WALKINGTREE;
else
{
- printf("Couldn't convert badguy: '%s'\n", str.c_str());
- return BAD_SNOWBALL;
+ return BAD_INVALID;
}
}
BadGuy::BadGuy(BadGuyKind kind_, LispReader& lispreader)
: removable(false), squishcount(0)
{
- lispreader.read_float("x", &start_position.x);
- lispreader.read_float("y", &start_position.y);
+ lispreader.read_float("x", start_position.x);
+ lispreader.read_float("y", start_position.y);
kind = kind_;
stay_on_platform = false;
- lispreader.read_bool("stay-on-platform", &stay_on_platform);
+ lispreader.read_bool("stay-on-platform", stay_on_platform);
init();
}
--base.y;
}
- if(World::current()->camera) {
- Vector scroll = World::current()->camera->get_translation();
+ if(Sector::current() && Sector::current()->camera) {
+ Vector scroll = Sector::current()->camera->get_translation();
if(start_position.x > scroll.x - X_OFFSCREEN_DISTANCE &&
start_position.x < scroll.x + screen->w + X_OFFSCREEN_DISTANCE &&
start_position.y < scroll.y + screen->h + Y_OFFSCREEN_DISTANCE) {
activate(LEFT);
}
+ } else {
+ if(start_position.x > 0 && start_position.x <= screen->w
+ && start_position.y > 0 && start_position.y <= screen->h)
+ activate(LEFT);
}
}
void
BadGuy::action_mriceblock(double elapsed_time)
{
- Player& tux = *World::current()->get_tux();
+ Player& tux = *Sector::current()->player;
if(mode != HELD)
fall();
check_horizontal_bump();
if(mode == KICK && changed != dir)
{
- float scroll_x = World::current()->camera->get_translation().x;
+ float scroll_x = Sector::current()->camera->get_translation().x;
/* handle stereo sound (number 10 should be tweaked...)*/
if (base.x < scroll_x + screen->w/2 - 10)
if (dir == LEFT && issolid( base.x, (int) base.y + halfheight))
{
if (kind == BAD_MRICEBLOCK && mode == KICK)
- World::current()->trybreakbrick(base.x, (int) base.y + halfheight, false);
+ Sector::current()->trybreakbrick(Vector(base.x, base.y + halfheight), false);
dir = RIGHT;
physic.set_velocity(-physic.get_velocity_x(), physic.get_velocity_y());
if (dir == RIGHT && issolid( base.x + base.width, (int)base.y + halfheight))
{
if (kind == BAD_MRICEBLOCK && mode == KICK)
- World::current()->trybreakbrick(base.x + base.width, (int) base.y + halfheight, false);
+ Sector::current()->trybreakbrick(
+ Vector(base.x + base.width, (int) base.y + halfheight), false);
dir = LEFT;
physic.set_velocity(-physic.get_velocity_x(), physic.get_velocity_y());
else
set_sprite(img_jumpy_left_up, img_jumpy_left_up);
- Player& tux = *World::current()->get_tux();
+ Player& tux = *Sector::current()->player;
static const float JUMPV = 6;
dying = DYING_NOT; // now the bomb hurts
timer.start(EXPLODETIME);
- float scroll_x = World::current()->camera->get_translation().x;
+ float scroll_x = Sector::current()->camera->get_translation().x;
/* play explosion sound */ // FIXME: is the stereo all right? maybe we should use player cordinates...
if (base.x < scroll_x + screen->w/2 - 10)
void
BadGuy::action_stalactite(double elapsed_time)
{
- Player& tux = *World::current()->get_tux();
+ Player& tux = *Sector::current()->player;
static const int SHAKETIME = 800;
static const int RANGE = 40;
physic.enable_gravity(true);
else
{
- Player& tux = *World::current()->get_tux();
+ Player& tux = *Sector::current()->player;
int dirsign = physic.get_velocity_x() < 0 ? -1 : 1;
if (fabsf(tux.base.x - base.x) < 150 && base.y < tux.base.y && tux.dying == DYING_NOT)
void
BadGuy::action_walkingtree(double elapsed_time)
{
- Player& tux = *World::current()->get_tux();
+ Player& tux = *Sector::current()->player;
Direction v_dir = physic.get_velocity_x() < 0 ? LEFT : RIGHT;
if (dying == DYING_NOT)
void
BadGuy::action(float elapsed_time)
{
- float scroll_x = World::current()->camera->get_translation().x;
- float scroll_y = World::current()->camera->get_translation().y;
+ float scroll_x = Sector::current()->camera->get_translation().x;
+ float scroll_y = Sector::current()->camera->get_translation().y;
// BadGuy fall below the ground
- if (base.y > World::current()->get_level()->height * 32) {
+ if (base.y > Sector::current()->solids->get_height() * 32) {
remove_me();
return;
}
{
make_player_jump(player);
- World::current()->add_score(Vector(base.x, base.y),
+ Sector::current()->add_score(Vector(base.x, base.y),
50 * player_status.score_multiplier);
play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER);
player_status.score_multiplier++;
explode(false);
make_player_jump(player);
- World::current()->add_score(Vector(base.x, base.y),
+ Sector::current()->add_score(Vector(base.x, base.y),
50 * player_status.score_multiplier);
play_sound(sounds[SND_SQUISH], SOUND_CENTER_SPEAKER);
player_status.score_multiplier++;
make_player_jump(player);
- World::current()->add_score(Vector(base.x, base.y),
+ Sector::current()->add_score(Vector(base.x, base.y),
25 * player_status.score_multiplier);
player_status.score_multiplier++;
make_player_jump(player);
base.y += 66 - base.height;
- World::current()->add_score(Vector(base.x, base.y),
+ Sector::current()->add_score(Vector(base.x, base.y),
25 * player_status.score_multiplier);
player_status.score_multiplier++;
set_sprite(img_mriceblock_falling_left, img_mriceblock_falling_right);
if(mode == HELD) {
mode = NORMAL;
- Player& tux = *World::current()->get_tux();
+ Player& tux = *Sector::current()->player;
tux.holding_something = false;
}
}
/* Gain some points: */
if (score != 0)
- World::current()->add_score(Vector(base.x, base.y),
+ Sector::current()->add_score(Vector(base.x, base.y),
score * player_status.score_multiplier);
/* Play death sound: */
void
BadGuy::explode(bool right_way)
{
- BadGuy *badguy = World::current()->add_bad_guy(base.x, base.y, BAD_BOMB);
+ BadGuy *badguy = Sector::current()->add_bad_guy(base.x, base.y, BAD_BOMB);
if(right_way)
{
badguy->timer.start(0);
#include "screen/texture.h"
#include "physic.h"
#include "sprite.h"
+#include "defines.h"
#include "moving_object.h"
#include "collision.h"
#include "serializable.h"
BAD_SNOWBALL,
BAD_WINGLING,
BAD_WALKINGTREE,
- NUM_BadGuyKinds
+ NUM_BadGuyKinds,
+
+ BAD_INVALID
};
BadGuyKind badguykind_from_string(const std::string& str);
#include <math.h>
#include "lispwriter.h"
#include "player.h"
-#include "level.h"
+#include "tilemap.h"
+#include "gameloop.h"
#include "globals.h"
-#include "world.h"
+#include "sector.h"
-Camera::Camera(Player* newplayer, Level* newlevel)
- : player(newplayer), level(newlevel), do_backscrolling(true),
- scrollchange(NONE), auto_idx(0), auto_t(0)
+Camera::Camera(Sector* newsector)
+ : sector(newsector), do_backscrolling(true), scrollchange(NONE),
+ auto_idx(0), auto_t(0)
{
- if(!player || !level)
- mode = MANUAL;
- else
- mode = NORMAL;
+ mode = NORMAL;
}
Camera::~Camera()
const Vector&
Camera::get_translation() const
{
- return World::current()->context.get_translation();
+ return translation;
}
void
{
std::string modename;
- reader.read_string("mode", &modename);
+ reader.read_string("mode", modename);
if(modename == "normal") {
mode = NORMAL;
do_backscrolling = true;
- reader.read_bool("backscrolling", &do_backscrolling);
+ reader.read_bool("backscrolling", do_backscrolling);
} else if(modename == "autoscroll") {
mode = AUTOSCROLL;
lisp_object_t* cur = 0;
- reader.read_lisp("path", &cur);
+ reader.read_lisp("path", cur);
if(cur == 0) {
throw std::runtime_error("No path specified in autoscroll camera.");
}
LispReader reader(lisp_cdr(lisp_car(cur)));
ScrollPoint point;
- if(!reader.read_float("x", &point.position.x) ||
- !reader.read_float("y", &point.position.y)) {
+ 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);
+ reader.read_float("speed", speed);
point.speed = speed;
scrollpoints.push_back(point);
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 = 1.4;
void
Camera::action(float elapsed_time)
{
- translation = World::current()->context.get_translation();
if(mode == NORMAL)
scroll_normal(elapsed_time);
else if(mode == AUTOSCROLL)
scroll_autoscroll(elapsed_time);
- World::current()->context.set_translation(translation);
}
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 > level->height * 32 - screen->h)
- translation.y = level->height * 32 - screen->h;
+ if(translation.y > height - screen->h)
+ translation.y = height - screen->h;
if(translation.y < 0)
translation.y = 0;
- if(translation.x > level->width * 32 - screen->w)
- translation.x = level->width * 32 - screen->w;
+ 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(level != 0 && player != 0);
+ assert(sector != 0);
+ Player* player = sector->player;
// check that we don't have division by zero later
if(elapsed_time < EPSILON)
/****** Vertical Scrolling part ******/
bool do_y_scrolling = true;
- if(player->dying || level->height == 19)
+ if(player->dying || sector->solids->get_height() == 19)
do_y_scrolling = false;
if(do_y_scrolling) {
void
Camera::scroll_autoscroll(float elapsed_time)
{
+ Player* player = sector->player;
+
if(player->dying)
return;
#include <cassert>
class LispReader;
-class Player;
-class Level;
+class Sector;
class Camera : public GameObject, public Serializable
{
public:
- Camera(Player* player = 0, Level* level = 0);
+ Camera(Sector* sector);
virtual ~Camera();
/// parse camera mode from lisp file
/// 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;
Vector translation;
- Player* player;
- Level* level;
+ Sector* sector;
// normal mode
bool do_backscrolling;
#include "collision.h"
#include "bitmask.h"
#include "scene.h"
-#include "world.h"
-#include "level.h"
+#include "sector.h"
+#include "tilemap.h"
#include "tile.h"
bool rectcollision(const base_type& one, const base_type& two)
bool collision_object_map(const base_type& base)
{
- if(!World::current())
- return false;
-
- const Level& level = *World::current()->get_level();
- TileManager& tilemanager = *TileManager::instance();
+ const TileMap& tilemap = *Sector::current()->solids;
// we make the collision rectangle 1 pixel smaller
int starttilex = int(base.x+1) / 32;
for(int x = starttilex; x*32 < max_x; ++x) {
for(int y = starttiley; y*32 < max_y; ++y) {
- Tile* tile = tilemanager.get(level.get_tile_at(x, y));
- if(tile && (tile->attributes & Tile::SOLID))
+ Tile* tile = tilemap.get_tile(x, y);
+ if(tile->attributes & Tile::SOLID)
return true;
}
}
void* collision_func(const base_type& base, tiletestfunction function)
{
- const Level& level = *World::current()->get_level();
- TileManager& tilemanager = *TileManager::instance();
+ const TileMap& tilemap = *Sector::current()->solids;
int starttilex = int(base.x) / 32;
int starttiley = int(base.y) / 32;
for(int x = starttilex; x*32 < max_x; ++x) {
for(int y = starttiley; y*32 < max_y; ++y) {
- Tile* tile = tilemanager.get(level.get_tile_at(x, y));
+ Tile* tile = tilemap.get_tile(x, y);
void* result = function(tile);
if(result != 0)
return result;
Tile* gettile(float x, float y)
{
- return TileManager::instance()->get(World::current()->get_level()->gettileid(x, y));
+ const TileMap& tilemap = *Sector::current()->solids;
+ return tilemap.get_tile_at(Vector(x, y));
}
bool issolid(float x, float y)
#include "type.h"
class Tile;
-class World;
/* Collision objects */
enum
LispReader reader(lisp_cdr(root_obj));
- reader.read_bool("fullscreen", &use_fullscreen);
- reader.read_bool("sound", &use_sound);
- reader.read_bool("music", &use_music);
- reader.read_bool("show_fps", &show_fps);
+ reader.read_bool("fullscreen", use_fullscreen);
+ reader.read_bool("sound", use_sound);
+ reader.read_bool("music", use_music);
+ reader.read_bool("show_fps", show_fps);
std::string video;
- reader.read_string ("video", &video);
+ reader.read_string ("video", video);
if (video == "opengl")
use_gl = true;
else
use_gl = false;
- reader.read_int ("joystick", &joystick_num);
+ reader.read_int ("joystick", joystick_num);
if (!(joystick_num >= 0))
use_joystick = false;
else
use_joystick = true;
- reader.read_int ("joystick-x", &joystick_keymap.x_axis);
- reader.read_int ("joystick-y", &joystick_keymap.y_axis);
- reader.read_int ("joystick-a", &joystick_keymap.a_button);
- reader.read_int ("joystick-b", &joystick_keymap.b_button);
- reader.read_int ("joystick-start", &joystick_keymap.start_button);
- reader.read_int ("joystick-deadzone", &joystick_keymap.dead_zone);
+ reader.read_int ("joystick-x", joystick_keymap.x_axis);
+ reader.read_int ("joystick-y", joystick_keymap.y_axis);
+ reader.read_int ("joystick-a", joystick_keymap.a_button);
+ reader.read_int ("joystick-b", joystick_keymap.b_button);
+ reader.read_int ("joystick-start", joystick_keymap.start_button);
+ reader.read_int ("joystick-deadzone", joystick_keymap.dead_zone);
- reader.read_int ("keyboard-jump", &keymap.jump);
- reader.read_int ("keyboard-duck", &keymap.duck);
- reader.read_int ("keyboard-left", &keymap.left);
- reader.read_int ("keyboard-right", &keymap.right);
- reader.read_int ("keyboard-fire", &keymap.fire);
+ reader.read_int ("keyboard-jump", keymap.jump);
+ reader.read_int ("keyboard-duck", keymap.duck);
+ reader.read_int ("keyboard-left", keymap.left);
+ reader.read_int ("keyboard-right", keymap.right);
+ reader.read_int ("keyboard-fire", keymap.fire);
lisp_free(root_obj);
}
void saveconfig (void)
{
/* write settings to config file */
-
FILE * config = opendata(config_filename, "w");
if(config)
#include "high_scores.h"
#include "menu.h"
#include "badguy.h"
-#include "world.h"
+#include "sector.h"
#include "special.h"
#include "player.h"
#include "level.h"
#include "particlesystem.h"
#include "resources.h"
#include "background.h"
+#include "tilemap.h"
#include "music_manager.h"
GameSession* GameSession::current_ = 0;
-GameSession::GameSession(const std::string& subset_, int levelnb_, int mode)
- : world(0), st_gl_mode(mode), levelnb(levelnb_), end_sequence(NO_ENDSEQUENCE),
- subset(subset_)
+GameSession::GameSession(const std::string& levelname_, int mode)
+ : level(0), currentsector(0), st_gl_mode(mode),
+ end_sequence(NO_ENDSEQUENCE), levelname(levelname_)
{
current_ = this;
fps_timer.init(true);
frame_timer.init(true);
+ context = new DrawingContext();
+
restart_level();
}
fps_timer.init(true);
frame_timer.init(true);
+#if 0
float old_x_pos = -1;
-
if (world)
{ // Tux has lost a life, so we try to respawn him at the nearest reset point
old_x_pos = world->get_tux()->base.x;
}
+#endif
- delete world;
+ delete level;
+ currentsector = 0;
- if (st_gl_mode == ST_GL_LOAD_LEVEL_FILE)
- {
- world = new World(subset);
- }
- else if (st_gl_mode == ST_GL_DEMO_GAME)
- {
- world = new World(subset);
- }
- else
- {
- world = new World(subset, levelnb);
- }
+ level = new Level;
+ level->load(levelname);
+ currentsector = level->get_sector("main");
+ if(!currentsector)
+ st_abort("Level has no main sector.", "");
+ currentsector->activate("main");
+#if 0 // TODO
// Set Tux to the nearest reset point
if (old_x_pos != -1)
{
world->get_tux()->base.y = best_reset_point.y;
}
}
+#endif
if (st_gl_mode != ST_GL_DEMO_GAME)
{
time_left.init(true);
start_timers();
- world->play_music(LEVEL_MUSIC);
+ currentsector->play_music(LEVEL_MUSIC);
}
GameSession::~GameSession()
{
- delete world;
+ delete level;
+ delete context;
}
void
char str[60];
DrawingContext context;
- world->background->draw(context);
+ currentsector->background->draw(context);
- sprintf(str, "%s", world->get_level()->name.c_str());
- context.draw_text_center(gold_text, str, Vector(0, 220), 0);
+ context.draw_text_center(gold_text, level->get_name(), Vector(0, 220),
+ LAYER_FOREGROUND1);
sprintf(str, "TUX x %d", player_status.lives);
- context.draw_text_center(white_text, str, Vector(0, 240), 0);
+ context.draw_text_center(white_text, str, Vector(0, 240),
+ LAYER_FOREGROUND1);
- sprintf(str, "by %s", world->get_level()->author.c_str());
- context.draw_text_center(white_small_text, str, Vector(0, 400), 0);
+ context.draw_text_center(white_small_text,
+ std::string("by ") + level->get_author(),
+ Vector(0, 400), LAYER_FOREGROUND1);
context.do_drawing();
void
GameSession::start_timers()
{
- time_left.start(world->get_level()->time_left*1000);
+ time_left.start(level->time_left*1000);
st_pause_ticks_init();
update_time = st_get_ticks();
}
void
GameSession::on_escape_press()
{
- if(world->get_tux()->dying || end_sequence != NO_ENDSEQUENCE)
+ if(currentsector->player->dying || end_sequence != NO_ENDSEQUENCE)
return; // don't let the player open the menu, when he is dying
+
if(game_pause)
return;
/* Tell Tux that the keys are all down, otherwise
it could have nasty bugs, like going allways to the right
or whatever that key does */
- Player& tux = *world->get_tux();
+ Player& tux = *(currentsector->player);
tux.key_event((SDLKey)keymap.jump, UP);
tux.key_event((SDLKey)keymap.duck, UP);
tux.key_event((SDLKey)keymap.left, UP);
{
if (end_sequence != NO_ENDSEQUENCE)
{
- Player& tux = *world->get_tux();
+ Player& tux = *currentsector->player;
tux.input.fire = UP;
tux.input.left = UP;
}
else
{
- Player& tux = *world->get_tux();
+ Player& tux = *currentsector->player;
switch(event.type)
{
void
GameSession::check_end_conditions()
{
- Player* tux = world->get_tux();
+ Player* tux = currentsector->player;
/* End of level? */
- int endpos = (World::current()->get_level()->width-5) * 32;
+ int endpos = (currentsector->solids->get_width() - 5) * 32;
Tile* endtile = collision_goal(tux->base);
// fallback in case the other endpositions don't trigger
void
GameSession::action(double frame_ratio)
{
- if (exit_status == ES_NONE && !world->get_tux()->growing_timer.check())
+ if (exit_status == ES_NONE && !currentsector->player->growing_timer.check())
{
// Update Tux and the World
- world->action(frame_ratio);
+ currentsector->action(frame_ratio);
}
}
void
GameSession::draw()
{
- DrawingContext& context = world->context;
-
- world->draw();
- drawstatus(context);
+ currentsector->draw(*context);
+ drawstatus(*context);
if(game_pause)
{
- context.push_transform();
- context.set_translation(Vector(0, 0));
-
int x = screen->h / 20;
for(int i = 0; i < x; ++i)
{
- context.draw_filled_rect(
+ context->draw_filled_rect(
Vector(i % 2 ? (pause_menu_frame * i)%screen->w :
-((pause_menu_frame * i)%screen->w)
,(i*20+pause_menu_frame)%screen->h),
Vector(screen->w,10),
Color(20,20,20, rand() % 20 + 1), LAYER_FOREGROUND1+1);
}
- context.draw_filled_rect(
+ context->draw_filled_rect(
Vector(0,0), Vector(screen->w, screen->h),
Color(rand() % 50, rand() % 50, rand() % 50, 128), LAYER_FOREGROUND1);
- world->context.draw_text_center(blue_text, "PAUSE - Press 'P' To Play",
+ context->draw_text_center(blue_text, "PAUSE - Press 'P' To Play",
Vector(0, 230), LAYER_FOREGROUND1+2);
-
- context.pop_transform();
}
if(Menu::current())
{
- Menu::current()->draw(context);
- mouse_cursor->draw(context);
+ Menu::current()->draw(*context);
+ mouse_cursor->draw(*context);
}
- context.do_drawing();
+ context->do_drawing();
}
void
}
/* Handle events: */
- world->get_tux()->input.old_fire = world->get_tux()->input.fire;
+ currentsector->player->input.old_fire
+ = currentsector->player->input.fire;
process_events();
process_menu();
}
/* Handle time: */
- if (!time_left.check() && world->get_tux()->dying == DYING_NOT
+ if (!time_left.check() && currentsector->player->dying == DYING_NOT
&& !end_sequence)
- world->get_tux()->kill(Player::KILL);
+ currentsector->player->kill(Player::KILL);
/* Handle music: */
- if(world->get_tux()->invincible_timer.check() && !end_sequence)
+ if(currentsector->player->invincible_timer.check() && !end_sequence)
{
- world->play_music(HERRING_MUSIC);
+ currentsector->play_music(HERRING_MUSIC);
}
/* are we low on time ? */
else if (time_left.get_left() < TIME_WARNING && !end_sequence)
{
- world->play_music(HURRYUP_MUSIC);
+ currentsector->play_music(HURRYUP_MUSIC);
}
/* or just normal music? */
- else if(world->get_music_type() != LEVEL_MUSIC && !end_sequence)
+ else if(currentsector->get_music_type() != LEVEL_MUSIC && !end_sequence)
{
- world->play_music(LEVEL_MUSIC);
+ currentsector->play_music(LEVEL_MUSIC);
}
/* Calculate frames per second */
/* Bounce a brick: */
void bumpbrick(float x, float y)
{
- World::current()->add_bouncy_brick(Vector(((int)(x + 1) / 32) * 32,
+ Sector::current()->add_bouncy_brick(Vector(((int)(x + 1) / 32) * 32,
(int)(y / 32) * 32));
play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
void
GameSession::drawstatus(DrawingContext& context)
{
- context.push_transform();
- context.set_translation(Vector(0, 0));
-
char str[60];
snprintf(str, 60, "%d", player_status.score);
context.draw_text(gold_text, str,
Vector(screen->w-4*16, 40), LAYER_FOREGROUND1);
}
-
- context.pop_transform();
}
void
char str[80];
DrawingContext context;
- world->background->draw(context);
+ currentsector->background->draw(context);
context.draw_text_center(blue_text, "Result:", Vector(0, 200),
LAYER_FOREGROUND1);
if (savegame)
{
LispReader reader(lisp_cdr(savegame));
- reader.read_string("title", &title);
+ reader.read_string("title", title);
lisp_free(savegame);
}
#include "sound.h"
#include "type.h"
-#include "level.h"
-#include "world.h"
/* GameLoop modes */
extern int game_started;
-class World;
+class Level;
+class Sector;
+class DrawingContext;
/** The GameSession class controlls the controll flow of a World, ie.
present the menu on specifc keypresses, render and update it while
keeping the speed and framerate sane, etc. */
class GameSession
{
- private:
+private:
Timer fps_timer;
Timer frame_timer;
Timer endsequence_timer;
- World* world;
+ Level* level;
+ Sector* currentsector;
+
int st_gl_mode;
int levelnb;
float fps_fps;
bool game_pause;
- // FIXME: Hack for restarting the level
- std::string subset;
-
- public:
+ std::string levelname;
+public:
enum ExitStatus { ES_NONE, ES_LEVEL_FINISHED, ES_GAME_OVER, ES_LEVEL_ABORT };
- private:
+private:
ExitStatus exit_status;
- public:
-
+public:
+ DrawingContext* context;
Timer time_left;
- GameSession(const std::string& subset, int levelnb, int mode);
+ GameSession(const std::string& level, int mode);
~GameSession();
/** Enter the busy loop */
void draw();
void action(double frame_ratio);
- Level* get_level() { return world->get_level(); }
- World* get_world() { return world; }
-
+ void set_current()
+ { current_ = this; }
static GameSession* current() { return current_; }
- private:
+
+ Sector* get_current_sector()
+ { return currentsector; }
+
+private:
static GameSession* current_;
void restart_level();
void drawendscreen();
void drawresultscreen(void);
- private:
+private:
void on_escape_press();
void process_menu();
};
#include <algorithm>
#include <iostream>
#include <math.h>
-#include "world.h"
#include "tile.h"
#include "gameloop.h"
#include "gameobjs.h"
#include "sprite_manager.h"
#include "resources.h"
-#include "level.h"
+#include "sector.h"
+#include "tilemap.h"
BouncyDistro::BouncyDistro(const Vector& pos)
: position(pos)
BouncyBrick::BouncyBrick(const Vector& pos)
: position(pos), offset(0), offset_m(-BOUNCY_BRICK_SPEED)
{
- shape = World::current()->get_level()->gettileid(pos.x, pos.y);
+ shape = Sector::current()->solids->get_tile_id_at(pos);
}
void
Trampoline::Trampoline(LispReader& reader)
{
- reader.read_float("x", &base.x);
- reader.read_float("y", &base.y);
+ 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);
+ reader.read_float("power", power);
frame = 0;
mode = M_NORMAL;
{
/* FIXME: The trampoline object shouldn't know about pplayer objects. */
/* If we're holding the iceblock */
- Player& tux = *World::current()->get_tux();
+ Player& tux = *Sector::current()->player;
Direction dir = tux.dir;
if(dir == RIGHT)
FlyingPlatform::FlyingPlatform(LispReader& reader)
{
- reader.read_int_vector("x", &pos_x);
- reader.read_int_vector("y", &pos_y);
+ reader.read_int_vector("x", pos_x);
+ reader.read_int_vector("y", pos_y);
velocity = 2.0;
- reader.read_float("velocity", &velocity);
+ reader.read_float("velocity", velocity);
base.x = pos_x[0];
base.y = pos_y[0];
#include "collision.h"
#include "game_object.h"
#include "moving_object.h"
+#include "serializable.h"
#include "lispwriter.h"
/* Bounciness of distros: */
if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-highscore") == 0)
{
LispReader reader(lisp_cdr(root_obj));
- reader.read_int("score", &hs_score);
- reader.read_string("name", &hs_name);
+ reader.read_int("score", hs_score);
+ reader.read_string("name", hs_name);
}
fclose(fi);
#include <string.h>
#include <iostream>
#include <fstream>
+#include <stdexcept>
#include "globals.h"
#include "setup.h"
#include "camera.h"
#include "level.h"
#include "physic.h"
#include "scene.h"
+#include "sector.h"
#include "tile.h"
#include "lispreader.h"
#include "resources.h"
#include "music_manager.h"
#include "gameobjs.h"
-#include "world.h"
-#include "background.h"
#include "lispwriter.h"
using namespace std;
new_subset.title = "Unknown Title";
new_subset.description = "No description so far.";
new_subset.save();
- new_lev.init_defaults();
- new_lev.save(subset_name, 1, 0);
+ //new_lev.save(subset_name, 1, 0);
}
void LevelSubset::parse (lisp_object_t* cursor)
}
}
-void LevelSubset::load(char *subset)
+void LevelSubset::load(const char* subset)
{
FILE* fi;
char filename[1024];
levels = --i;
}
-void LevelSubset::save()
+void
+LevelSubset::save()
{
FILE* fi;
string filename;
fprintf( fi,")");
fclose(fi);
-
}
}
-Level::Level()
- : img_bkgd(0)
-{
- init_defaults();
-}
-
-Level::~Level()
-{
- delete img_bkgd;
-}
-
-void
-Level::init_defaults()
-{
- name = "UnNamed";
- author = "UnNamed";
- song_title = "Mortimers_chipdisko.mod";
- width = 0;
- height = 0;
- start_pos.x = 100;
- start_pos.y = 170;
- time_left = 100;
- gravity = 10.;
-
- resize(21, 19);
-}
-
-int
-Level::load(const std::string& subset, int level, World* world)
+std::string
+LevelSubset::get_level_filename(unsigned int num)
{
char filename[1024];
-
+
// Load data file:
- snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir, subset.c_str(), level);
+ snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir,
+ name.c_str(), num);
if(!faccessible(filename))
- snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(), subset.c_str(), level);
-
- return load(filename, world);
-}
+ snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(),
+ name.c_str(), num);
-int
-Level::load(const std::string& filename, World* world)
-{
- lisp_object_t* root_obj = lisp_read_from_file(filename);
- if (!root_obj)
- {
- std::cout << "Level: Couldn't load file: " << filename << std::endl;
- return -1;
- }
-
- if (root_obj->type == LISP_TYPE_EOF || root_obj->type == LISP_TYPE_PARSE_ERROR)
- {
- lisp_free(root_obj);
- std::cout << "World: Parse Error in file '" << filename
- << "'.\n";
- return -1;
- }
-
- int version = 0;
- if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-level") == 0)
- {
- LispReader reader(lisp_cdr(root_obj));
- version = 0;
- reader.read_int("version", &version);
- if(!reader.read_int("width", &width))
- st_abort("No width specified for level.", "");
- if (!reader.read_float("start_pos_x", &start_pos.x)) start_pos.x = 100;
- if (!reader.read_float("start_pos_y", &start_pos.y)) start_pos.y = 170;
- time_left = 500;
- if(!reader.read_int("time", &time_left)) {
- printf("Warning: no time specified for level.\n");
- }
-
- height = 15;
- if(!reader.read_int("height", &height)) {
- printf("Warning: no height specified for level.\n");
- }
-
-
- // read old background stuff
- int bkgd_speed = 50;
- reader.read_int("bkgd_speed", &bkgd_speed);
-
- Color bkgd_top, bkgd_bottom;
- int r, g, b;
- reader.read_int("bkgd_red_top", &r);
- reader.read_int("bkgd_green_top", &g);
- reader.read_int("bkgd_blue_top", &b);
- bkgd_top.red = r;
- bkgd_top.green = g;
- bkgd_top.blue = b;
-
- reader.read_int("bkgd_red_bottom", &r);
- reader.read_int("bkgd_green_bottom", &g);
- reader.read_int("bkgd_blue_bottom", &b);
- bkgd_bottom.red = r;
- bkgd_bottom.green = g;
- bkgd_bottom.blue = b;
-
- std::string bkgd_image;
- reader.read_string("background", &bkgd_image);
-
- if(world) {
- Background* background = new Background();
- if(bkgd_image != "")
- background->set_image(bkgd_image, bkgd_speed);
- else
- background->set_gradient(bkgd_top, bkgd_bottom);
-
- world->add_object(background);
- }
-
- gravity = 10;
- reader.read_float("gravity", &gravity);
- name = "Noname";
- reader.read_string("name", &name);
- author = "unknown author";
- reader.read_string("author", &author);
- song_title = "";
- reader.read_string("music", &song_title);
- particle_system = "";
- reader.read_string("particle_system", &particle_system);
-
- reader.read_int_vector("background-tm", &bg_tiles);
- if(int(bg_tiles.size()) != width * height)
- st_abort("Wrong size of backgroundtilemap", "");
-
- if (!reader.read_int_vector("interactive-tm", &ia_tiles))
- reader.read_int_vector("tilemap", &ia_tiles);
- if(int(ia_tiles.size()) != width * height)
- st_abort("Wrong size of interactivetilemap", "");
-
- reader.read_int_vector("foreground-tm", &fg_tiles);
- if(int(fg_tiles.size()) != width * height)
- st_abort("Wrong size of foregroundtilemap", "");
-
- { // Read ResetPoints
- lisp_object_t* cur = 0;
- if (reader.read_lisp("reset-points", &cur))
- {
- while (!lisp_nil_p(cur))
- {
- lisp_object_t* data = lisp_car(cur);
-
- ResetPoint pos;
-
- LispReader reader(lisp_cdr(data));
- if (reader.read_int("x", &pos.x)
- && reader.read_int("y", &pos.y))
- {
- reset_points.push_back(pos);
- }
-
- cur = lisp_cdr(cur);
- }
- }
- }
-
- { // Read Objects
- lisp_object_t* cur = 0;
- if (reader.read_lisp("objects", &cur))
- {
- if(world)
- world->parse_objects(cur);
- }
- }
-
- { // Read Camera
- lisp_object_t* cur = 0;
- if (reader.read_lisp("camera", &cur))
- {
- LispReader reader(cur);
- if(world) {
- world->camera->read(reader);
- }
- }
- }
- }
-
- lisp_free(root_obj);
- return 0;
+ return std::string(filename);
}
-/* Save data for level: */
+//---------------------------------------------------------------------------
-void
-Level::save(const std::string& subset, int level, World* world)
+Level::Level()
+ : name("noname"), author("mr. x"), time_left(500)
{
- char filename[1024];
- char str[80];
-
- /* Save data file: */
- snprintf(str, sizeof(str), "/levels/%s/", subset.c_str());
- fcreatedir(str);
- snprintf(filename, sizeof(filename),
- "%s/levels/%s/level%d.stl", st_dir, subset.c_str(), level);
- if(!fwriteable(filename))
- snprintf(filename, sizeof(filename), "%s/levels/%s/level%d.stl",
- datadir.c_str(), subset.c_str(), level);
-
- std::ofstream out(filename);
- if(!out.good()) {
- st_abort("Couldn't write file.", filename);
- }
- LispWriter writer(out);
-
- /* Write header: */
- writer.write_comment("SuperTux level made using the built-in leveleditor");
- writer.start_list("supertux-level");
-
- writer.write_int("version", 1);
- writer.write_string("name", name);
- writer.write_string("author", author);
- writer.write_string("music", song_title);
- writer.write_string("background", bkgd_image);
- writer.write_string("particle_system", particle_system);
- writer.write_int("time", time_left);
- writer.write_int("width", width);
- writer.write_int("height", height);
- writer.write_float("gravity", gravity);
-
- writer.write_int_vector("background-tm", bg_tiles);
- writer.write_int_vector("interactive-tm", ia_tiles);
- writer.write_int_vector("foreground-tm", fg_tiles);
-
- writer.start_list("reset-points");
- for(std::vector<ResetPoint>::iterator i = reset_points.begin();
- i != reset_points.end(); ++i) {
- writer.start_list("point");
- writer.write_int("x", i->x);
- writer.write_int("y", i->y);
- writer.end_list("point");
- }
- writer.end_list("reset-points");
-
- // write objects
- writer.start_list("objects");
- // pick all objects that can be written into a levelfile
- for(std::vector<GameObject*>::iterator it = world->gameobjects.begin();
- it != world->gameobjects.end(); ++it) {
- Serializable* serializable = dynamic_cast<Serializable*> (*it);
- if(serializable)
- serializable->write(writer);
- }
- writer.end_list("objects");
-
- writer.end_list("supertux-level");
- out.close();
}
-/* Unload data for this level: */
void
-Level::cleanup()
+Level::load(const std::string& filename)
{
- bg_tiles.clear();
- ia_tiles.clear();
- fg_tiles.clear();
-
- reset_points.clear();
- name = "";
- author = "";
- song_title = "";
-}
-
-/* Load a level-specific graphic... */
-void Level::load_image(Surface** ptexture, string theme,const char * file, int use_alpha)
-{
- char fname[1024];
-
- snprintf(fname, 1024, "%s/themes/%s/%s", st_dir, theme.c_str(), file);
- if(!faccessible(fname))
- snprintf(fname, 1024, "%s/images/themes/%s/%s", datadir.c_str(), theme.c_str(), file);
-
- *ptexture = new Surface(fname, use_alpha);
-}
+ LispReader* level = LispReader::load(filename, "supertux-level");
-/* Change the size of a level */
-void
-Level::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) {
- ia_tiles[y * new_width + x] = ia_tiles[y * width + x];
- bg_tiles[y * new_width + x] = bg_tiles[y * width + x];
- fg_tiles[y * new_width + x] = fg_tiles[y * width + x];
- }
- }
+ int version = 1;
+ level->read_int("version", version);
+ if(version == 1) {
+ load_old_format(*level);
+ return;
}
- ia_tiles.resize(new_width * new_height);
- bg_tiles.resize(new_width * new_height);
- fg_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) {
- ia_tiles[y * new_width + x] = 0;
- bg_tiles[y * new_width + x] = 0;
- fg_tiles[y * new_width + x] = 0;
- } else {
- ia_tiles[y * new_width + x] = ia_tiles[y * width + x];
- bg_tiles[y * new_width + x] = bg_tiles[y * width + x];
- fg_tiles[y * new_width + x] = fg_tiles[y * width + x];
- }
- }
+ for(lisp_object_t* cur = level->get_lisp(); !lisp_nil_p(cur);
+ cur = lisp_cdr(cur)) {
+ std::string token = lisp_symbol(lisp_car(lisp_car(cur)));
+ lisp_object_t* data = lisp_car(lisp_cdr(lisp_car(cur)));
+ LispReader reader(lisp_cdr(lisp_car(cur)));
+
+ if(token == "name") {
+ name = lisp_string(data);
+ } else if(token == "author") {
+ author = lisp_string(data);
+ } else if(token == "time") {
+ time_left = lisp_integer(data);
+ } else if(token == "sector") {
+ Sector* sector = new Sector;
+ sector->parse(reader);
+ add_sector(sector);
+ } else {
+ std::cerr << "Unknown token '" << token << "' in level file.\n";
+ continue;
}
}
-
- height = new_height;
- width = new_width;
-}
-
-void
-Level::change(float x, float y, int tm, unsigned int c)
-{
- int yy = ((int)y / 32);
- int xx = ((int)x / 32);
-
- if (yy >= 0 && yy < height && xx >= 0 && xx <= width)
- {
- switch(tm)
- {
- case TM_BG:
- bg_tiles[yy * width + xx] = c;
- break;
- case TM_IA:
- ia_tiles[yy * width + xx] = c;
- break;
- case TM_FG:
- fg_tiles[yy * width + xx] = c;
- break;
- }
- }
+
+ delete level;
}
void
-Level::load_song()
+Level::load_old_format(LispReader& reader)
{
- char* song_path;
- char* song_subtitle;
-
- level_song = music_manager->load_music(datadir + "/music/" + song_title);
-
- song_path = (char *) malloc(sizeof(char) * datadir.length() +
- strlen(song_title.c_str()) + 8 + 5);
- song_subtitle = strdup(song_title.c_str());
- strcpy(strstr(song_subtitle, "."), "\0");
- sprintf(song_path, "%s/music/%s-fast%s", datadir.c_str(),
- song_subtitle, strstr(song_title.c_str(), "."));
- if(!music_manager->exists_music(song_path)) {
- level_song_fast = level_song;
- } else {
- level_song_fast = music_manager->load_music(song_path);
- }
- free(song_subtitle);
- free(song_path);
-}
+ reader.read_string("name", name);
+ reader.read_string("author", author);
+ reader.read_int("time", time_left);
-MusicRef
-Level::get_level_music()
-{
- return level_song;
+ Sector* sector = new Sector;
+ sector->parse_old_format(reader);
+ add_sector(sector);
}
-MusicRef
-Level::get_level_music_fast()
+Level::~Level()
{
- return level_song_fast;
+ for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i)
+ delete i->second;
}
-unsigned int
-Level::gettileid(float x, float y) const
+void
+Level::add_sector(Sector* sector)
{
- int xx, yy;
- unsigned int c;
-
- yy = ((int)y / 32);
- xx = ((int)x / 32);
-
- if (yy >= 0 && yy < height && xx >= 0 && xx <= width)
- c = ia_tiles[yy * width + xx];
- else
- c = 0;
-
- return c;
+ sectors.insert(std::make_pair(sector->get_name(), sector));
}
-unsigned int
-Level::get_tile_at(int x, int y) const
+Sector*
+Level::get_sector(const std::string& name)
{
- if(x < 0 || x >= width || y < 0 || y >= height)
+ Sectors::iterator i = sectors.find(name);
+ if(i == sectors.end())
return 0;
-
- return ia_tiles[y * width + x];
+
+ return i->second;
}
-/* EOF */
#ifndef SUPERTUX_LEVEL_H
#define SUPERTUX_LEVEL_H
+#include <map>
#include <string>
#include "screen/texture.h"
#include "lispreader.h"
#include "musicref.h"
class Tile;
-class World;
/** This type holds meta-information about a level-subset.
It could be extended to handle manipulation of subsets. */
~LevelSubset();
static void create(const std::string& subset_name);
- void load(char *subset);
+ void load(const char* subset);
void save();
+ std::string get_level_filename(unsigned int i);
+
std::string name;
std::string title;
std::string description;
void parse(lisp_object_t* cursor);
};
-#define LEVEL_NAME_MAX 20
-
-enum TileMapType {
- TM_BG,
- TM_IA,
- TM_FG
-};
-
-struct ResetPoint
-{
- int x;
- int y;
-};
+class Sector;
-class Level
+class Level
{
public:
- Surface* img_bkgd;
- MusicRef level_song;
- MusicRef level_song_fast;
-
std::string name;
std::string author;
- std::string song_title;
- std::string bkgd_image;
- std::string particle_system;
- std::vector<unsigned int> bg_tiles; /* Tiles in the background */
- std::vector<unsigned int> ia_tiles; /* solid Tiles in the game */
- std::vector<unsigned int> fg_tiles; /* Tiles in the foreground */
int time_left;
- int width;
- int height;
- Vector start_pos;
- float gravity;
-
- /** A collection of points to which Tux can be reset after a lost live */
- std::vector<ResetPoint> reset_points;
- public:
+ typedef std::map<std::string, Sector*> Sectors;
+ Sectors sectors;
+
+public:
Level();
- Level(const std::string& subset, int level, World* world);
- Level(const std::string& filename, World* world);
~Level();
- /** Will the Level structure with default values */
- void init_defaults();
-
- /** Cleanup the level struct from allocated tile data and such */
- void cleanup();
-
- /** Load data for this level:
- Returns -1, if the loading of the level failed.
- XXX the world parameter is a temporary hack
- */
- int load(const std::string& subset, int level, World* world);
-
- /** Load data for this level:
- Returns -1, if the loading of the level failed.
- XXX the world parameter is a temporary hack
- */
- int load(const std::string& filename, World* world);
-
- void load_song();
- void free_song();
- MusicRef get_level_music();
- MusicRef get_level_music_fast();
-
- // XXX the world parameter is a temporary hack
- void save(const std::string& subset, int level, World* world);
-
- /** Edit a piece of the map! */
- void change(float x, float y, int tm, unsigned int c);
-
- /** Resize the level to a new width/height */
- void resize(int new_width, int new_height);
-
- /** Return the id of the tile at position x/y */
- unsigned int gettileid(float x, float y) const;
- /** returns the id of the tile at position x,y
- * (these are logical and not pixel coordinates)
- */
- unsigned int get_tile_at(int x, int y) const;
-
- void load_image(Surface** ptexture, std::string theme, const char * file, int use_alpha);
+ void load(const std::string& filename);
+ void save(const std::string& filename);
+
+ const std::string& get_name() const
+ { return name; }
+
+ const std::string& get_author() const
+ { return author; }
+
+ void add_sector(Sector* sector);
+
+ Sector* get_sector(const std::string& name);
+
+private:
+ void load_old_format(LispReader& reader);
};
#endif /*SUPERTUX_LEVEL_H*/
using namespace std;
LispReader::LispReader (lisp_object_t* l)
- : lst (l)
+ : owner(0), lst (l)
{
- //std::cout << "LispReader: " << std::flush;
- //lisp_dump(lst, stdout);
- //std::cout << std::endl;
+}
+
+LispReader::~LispReader()
+{
+ if(owner)
+ lisp_free(owner);
+}
+
+LispReader*
+LispReader::load(const std::string& filename, const std::string& toplevellist)
+{
+ lisp_object_t* obj = lisp_read_from_file(filename);
+
+ if(obj->type == LISP_TYPE_EOF || obj->type == LISP_TYPE_PARSE_ERROR) {
+ lisp_free(obj);
+ throw LispReaderException("LispReader::load", __FILE__, __LINE__);
+ }
+
+ if(toplevellist != lisp_symbol(lisp_car(obj))) {
+ lisp_car(obj);
+ throw LispReaderException("LispReader::load wrong toplevel symbol",
+ __FILE__, __LINE__);
+ }
+
+ LispReader* reader = new LispReader(lisp_cdr(obj));
+ reader->owner = obj;
+
+ return reader;
}
lisp_object_t*
}
bool
-LispReader::read_int (const char* name, int* i)
+LispReader::read_int (const char* name, int& i)
{
lisp_object_t* obj = search_for (name);
- if (obj)
- {
- if (!lisp_integer_p(lisp_car(obj)))
- {
- //st_abort("LispReader expected type integer at token: ", name); /* Instead of giving up, we return with false now. */
- return false;
- }
- *i = lisp_integer(lisp_car(obj));
- return true;
- }
- return false;
+ if(!obj)
+ return false;
+
+ if (!lisp_integer_p(lisp_car(obj)))
+ return false;
+
+ i = lisp_integer(lisp_car(obj));
+ return true;
}
bool
-LispReader::read_lisp(const char* name, lisp_object_t** b)
+LispReader::read_lisp(const char* name, lisp_object_t*& b)
{
lisp_object_t* obj = search_for (name);
- if (obj)
- {
- *b = obj;
- return true;
- }
- else
+ if (!obj)
return false;
+
+ b = obj;
+ return true;
+}
+
+LispReader*
+LispReader::read_lisp(const char* name)
+{
+ lisp_object_t* obj = search_for(name);
+ if(!obj)
+ return 0;
+
+ return new LispReader(obj);
}
bool
-LispReader::read_float (const char* name, float* f)
+LispReader::read_float (const char* name, float& f)
{
lisp_object_t* obj = search_for (name);
- if (obj)
- {
- if (!lisp_real_p(lisp_car(obj)) && !lisp_integer_p(lisp_car(obj)))
- st_abort("LispReader expected type real at token: ", name);
- *f = lisp_real(lisp_car(obj));
- return true;
- }
- return false;
+ if (!obj)
+ return false;
+
+ if (!lisp_real_p(lisp_car(obj)) && !lisp_integer_p(lisp_car(obj)))
+ st_abort("LispReader expected type real at token: ", name);
+
+ f = lisp_real(lisp_car(obj));
+ return true;
}
bool
-LispReader::read_string_vector (const char* name, std::vector<std::string>* vec)
+LispReader::read_string_vector (const char* name, std::vector<std::string>& vec)
{
lisp_object_t* obj = search_for (name);
- if (obj)
- {
- while(!lisp_nil_p(obj))
- {
- if (!lisp_string_p(lisp_car(obj)))
- st_abort("LispReader expected type string at token: ", name);
- vec->push_back(lisp_string(lisp_car(obj)));
- obj = lisp_cdr(obj);
- }
- return true;
- }
- return false;
+ if (!obj)
+ return false;
+
+ vec.clear();
+ while(!lisp_nil_p(obj))
+ {
+ if (!lisp_string_p(lisp_car(obj)))
+ st_abort("LispReader expected type string at token: ", name);
+ vec.push_back(lisp_string(lisp_car(obj)));
+ obj = lisp_cdr(obj);
+ }
+ return true;
}
bool
-LispReader::read_int_vector (const char* name, std::vector<int>* vec)
+LispReader::read_int_vector (const char* name, std::vector<int>& vec)
{
- vec->clear();
lisp_object_t* obj = search_for (name);
- if (obj)
- {
- while(!lisp_nil_p(obj))
- {
- if (!lisp_integer_p(lisp_car(obj)))
- st_abort("LispReader expected type integer at token: ", name);
- vec->push_back(lisp_integer(lisp_car(obj)));
- obj = lisp_cdr(obj);
- }
- return true;
- }
- return false;
+ if (!obj)
+ return false;
+
+ vec.clear();
+ while(!lisp_nil_p(obj))
+ {
+ if (!lisp_integer_p(lisp_car(obj)))
+ st_abort("LispReader expected type integer at token: ", name);
+ vec.push_back(lisp_integer(lisp_car(obj)));
+ obj = lisp_cdr(obj);
+ }
+ return true;
}
bool
-LispReader::read_int_vector (const char* name, std::vector<unsigned int>* vec)
+LispReader::read_int_vector (const char* name, std::vector<unsigned int>& vec)
{
- vec->clear();
lisp_object_t* obj = search_for (name);
- if (obj)
- {
- while(!lisp_nil_p(obj))
- {
- if (!lisp_integer_p(lisp_car(obj)))
- st_abort("LispReader expected type integer at token: ", name);
- vec->push_back(lisp_integer(lisp_car(obj)));
- obj = lisp_cdr(obj);
- }
- return true;
- }
- return false;
+ if (!obj)
+ return false;
+
+ vec.clear();
+ while(!lisp_nil_p(obj))
+ {
+ if (!lisp_integer_p(lisp_car(obj)))
+ st_abort("LispReader expected type integer at token: ", name);
+ vec.push_back(lisp_integer(lisp_car(obj)));
+ obj = lisp_cdr(obj);
+ }
+ return true;
}
bool
-LispReader::read_char_vector (const char* name, std::vector<char>* vec)
+LispReader::read_char_vector (const char* name, std::vector<char>& vec)
{
lisp_object_t* obj = search_for (name);
- if (obj)
- {
- while(!lisp_nil_p(obj))
- {
- vec->push_back(*lisp_string(lisp_car(obj)));
- obj = lisp_cdr(obj);
- }
- return true;
- }
- return false;
+ if (!obj)
+ return false;
+
+ vec.clear();
+ while(!lisp_nil_p(obj))
+ {
+ vec.push_back(*lisp_string(lisp_car(obj)));
+ obj = lisp_cdr(obj);
+ }
+ return true;
}
bool
-LispReader::read_string (const char* name, std::string* str)
+LispReader::read_string (const char* name, std::string& str)
{
lisp_object_t* obj = search_for (name);
- if (obj)
- {
- if (!lisp_string_p(lisp_car(obj)))
- st_abort("LispReader expected type string at token: ", name);
- *str = lisp_string(lisp_car(obj));
- return true;
- }
- return false;
+ if (!obj)
+ return false;
+
+ if (!lisp_string_p(lisp_car(obj)))
+ st_abort("LispReader expected type string at token: ", name);
+ str = lisp_string(lisp_car(obj));
+ return true;
}
bool
-LispReader::read_bool (const char* name, bool* b)
+LispReader::read_bool (const char* name, bool& b)
{
lisp_object_t* obj = search_for (name);
- if (obj)
- {
- if (!lisp_boolean_p(lisp_car(obj)))
- st_abort("LispReader expected type bool at token: ", name);
- *b = lisp_boolean(lisp_car(obj));
- return true;
- }
- return false;
+ if (!obj)
+ return false;
+
+ if (!lisp_boolean_p(lisp_car(obj)))
+ st_abort("LispReader expected type bool at token: ", name);
+ b = lisp_boolean(lisp_car(obj));
+ return true;
}
lisp_object_t*
return lst;
}
-lisp_object_t* lisp_read_from_gzfile(const char* filename)
-{
- bool done = false;
- lisp_object_t* root_obj = 0;
- int chunk_size = 128 * 1024;
- int buf_pos = 0;
- int try_number = 1;
- char* buf = static_cast<char*>(malloc(chunk_size));
- if (!buf)
- throw LispReaderException("lisp_read_from_gzfile()", __FILE__, __LINE__);
-
- gzFile in = gzopen(filename, "r");
-
- while (!done)
- {
- int ret = gzread(in, buf + buf_pos, chunk_size);
- if (ret == -1)
- {
- free (buf);
- throw LispReaderException("Error while reading from file", __FILE__, __LINE__);
- }
- else if (ret == chunk_size) // buffer got full, eof not yet there so resize
- {
- buf_pos = chunk_size * try_number;
- try_number += 1;
- buf = static_cast<char*>(realloc(buf, chunk_size * try_number));
-
- if (!buf)
- throw LispReaderException("lisp_read_from_gzfile()", __FILE__, __LINE__);
- }
- else
- {
- // everything fine, encountered EOF
- done = true;
- }
- }
-
- lisp_stream_t stream;
- lisp_stream_init_string (&stream, buf);
- root_obj = lisp_read (&stream);
-
- free(buf);
- gzclose(in);
-
- return root_obj;
-}
-
-bool has_suffix(const char* data, const char* suffix)
-{
- int suffix_len = strlen(suffix);
- int data_len = strlen(data);
-
- const char* data_suffix = (data + data_len - suffix_len);
-
- if (data_suffix >= data)
- {
- return (strcmp(data_suffix, suffix) == 0);
- }
- else
- {
- return false;
- }
-}
-
lisp_object_t* lisp_read_from_file(const std::string& filename)
{
- lisp_stream_t stream;
+ FILE* in = fopen(filename.c_str(), "r");
- if (has_suffix(filename.c_str(), ".gz"))
- {
- return lisp_read_from_gzfile(filename.c_str());
- }
- else
- {
- lisp_object_t* obj = 0;
- FILE* in = fopen(filename.c_str(), "r");
+ if(!in)
+ return 0;
- if (in)
- {
- lisp_stream_init_file(&stream, in);
- obj = lisp_read(&stream);
- fclose(in);
- }
+ lisp_stream_t stream;
+ lisp_stream_init_file(&stream, in);
+ lisp_object_t* obj = lisp_read(&stream);
+ fclose(in);
- return obj;
- }
+ return obj;
}
// EOF //
} v;
};
-lisp_stream_t* lisp_stream_init_gzfile (lisp_stream_t *stream, gzFile file);
lisp_stream_t* lisp_stream_init_file (lisp_stream_t *stream, FILE *file);
lisp_stream_t* lisp_stream_init_string (lisp_stream_t *stream, char *buf);
lisp_stream_t* lisp_stream_init_any (lisp_stream_t *stream, void *data,
class LispReader
{
private:
+ lisp_object_t* owner;
lisp_object_t* lst;
lisp_object_t* search_for(const char* name);
+
public:
/** cur == ((pos 1 2 3) (id 12 3 4)...) */
- LispReader (lisp_object_t* l);
-
- bool read_int_vector (const char* name, std::vector<int>* vec);
- bool read_int_vector (const char* name, std::vector<unsigned int>* vec);
- bool read_char_vector (const char* name, std::vector<char>* vec);
- bool read_string_vector (const char* name, std::vector<std::string>* vec);
- bool read_string (const char* name, std::string* str);
- bool read_int (const char* name, int* i);
- bool read_float (const char* name, float* f);
- bool read_bool (const char* name, bool* b);
- bool read_lisp (const char* name, lisp_object_t** b);
+ LispReader(lisp_object_t* l);
+ ~LispReader();
+
+ bool read_int_vector(const char* name, std::vector<int>& vec);
+ bool read_int_vector(const char* name, std::vector<unsigned int>& vec);
+ bool read_char_vector(const char* name, std::vector<char>& vec);
+ bool read_string_vector(const char* name, std::vector<std::string>& vec);
+ bool read_string(const char* name, std::string& str);
+ bool read_int(const char* name, int& i);
+ bool read_float(const char* name, float& f);
+ bool read_bool(const char* name, bool& b);
+ bool read_lisp(const char* name, lisp_object_t*& b);
+ LispReader* read_lisp(const char* name);
+
+ static LispReader* load(const std::string& filename,
+ const std::string& toplevellist);
lisp_object_t* get_lisp();
};
int menu_height = get_height();
int menu_width = get_width();
- context.push_transform();
- context.set_translation(Vector(0, 0));
-
/* Draw a transparent background */
context.draw_filled_rect(
Vector(pos_x - menu_width/2, pos_y - 24*item.size()/2 - 10),
{
draw_item(context, i, menu_width, menu_height);
}
- context.pop_transform();
}
MenuItem&
timer.start(MC_FRAME_PERIOD);
}
- context.push_transform();
- context.set_translation(Vector(0, 0));
context.draw_surface_part(cursor, Vector(w*cur_frame, h*cur_state), Vector(w,
h), Vector(x-mid_x, y-mid_y), LAYER_FOREGROUND1+100);
- context.pop_transform();
}
#include <iostream>
#include <math.h>
#include "globals.h"
-#include "world.h"
-#include "level.h"
-#include "scene.h"
-#include "camera.h"
+#include "lispreader.h"
+#include "lispwriter.h"
+#include "screen/drawing_context.h"
ParticleSystem::ParticleSystem()
{
virtual_width = screen->w;
virtual_height = screen->h;
+ layer = LAYER_BACKGROUND1;
}
ParticleSystem::~ParticleSystem()
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_BACKGROUND1);
+ context.draw_surface(particle->texture, pos, layer);
}
context.pop_transform();
do {
particle->speed = snowsize/60.0 + (float(rand()%10)/300.0);
} while(particle->speed < 0.01);
- particle->speed *= World::current()->get_level()->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)
}
}
+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;
#include <vector>
#include "screen/texture.h"
#include "game_object.h"
+#include "serializable.h"
+class LispReader;
class DisplayManager;
/**
virtual void draw(DrawingContext& context);
protected:
+ int layer;
+
class Particle
{
public:
float virtual_width, virtual_height;
};
-class SnowParticleSystem : public ParticleSystem
+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
Surface* snowimages[3];
};
-class CloudParticleSystem : public ParticleSystem
+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
#include "defines.h"
#include "physic.h"
#include "timer.h"
-#include "world.h"
+#include "sector.h"
#include "level.h"
Physic::Physic()
void
Physic::apply(float frame_ratio, float &x, float &y)
{
- float gravity = World::current()->get_level()->gravity;
+ float gravity = Sector::current()->gravity;
float grav;
if(gravity_enabled)
grav = gravity / 100.0;
#include "scene.h"
#include "tile.h"
#include "sprite.h"
+#include "sector.h"
+#include "tilemap.h"
+#include "camera.h"
#include "gameobjs.h"
#include "screen/screen.h"
if (isbrick(base.x, base.y) ||
isfullbox(base.x, base.y))
{
- World::current()->trygrabdistro(base.x, base.y - 32, BOUNCE);
- World::current()->trybumpbadguy(base.x, base.y - 64);
+ Sector::current()->trygrabdistro(
+ Vector(base.x, base.y - 32), BOUNCE);
+ Sector::current()->trybumpbadguy(Vector(base.x, base.y - 64));
- World::current()->trybreakbrick(base.x, base.y, size == SMALL);
+ Sector::current()->trybreakbrick(
+ Vector(base.x, base.y), size == SMALL);
bumpbrick(base.x, base.y);
- World::current()->tryemptybox(base.x, base.y, RIGHT);
+ Sector::current()->tryemptybox(Vector(base.x, base.y), RIGHT);
}
if (isbrick(base.x+ 31, base.y) ||
isfullbox(base.x+ 31, base.y))
{
- World::current()->trygrabdistro(base.x+ 31, base.y - 32,BOUNCE);
- World::current()->trybumpbadguy(base.x+ 31, base.y - 64);
+ Sector::current()->trygrabdistro(
+ Vector(base.x+ 31, base.y - 32), BOUNCE);
+ Sector::current()->trybumpbadguy(Vector(base.x+ 31, base.y - 64));
if(size == BIG)
- World::current()->trybreakbrick(base.x+ 31, base.y, size == SMALL);
+ Sector::current()->trybreakbrick(
+ Vector(base.x+ 31, base.y), size == SMALL);
bumpbrick(base.x+ 31, base.y);
- World::current()->tryemptybox(base.x+ 31, base.y, LEFT);
+ Sector::current()->tryemptybox(Vector(base.x+ 31, base.y), LEFT);
}
}
butt_jump = false;
// Break bricks beneath Tux
- if(World::current()->trybreakbrick(base.x + 1, base.y + base.height, false)
- || World::current()->trybreakbrick(
- base.x + base.width - 1, base.y + base.height, false))
+ 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;
}
// Kill nearby badguys
- std::vector<GameObject*> gameobjects = World::current()->gameobjects;
+ std::vector<GameObject*> gameobjects = Sector::current()->gameobjects;
for (std::vector<GameObject*>::iterator i = gameobjects.begin();
i != gameobjects.end();
i++)
/* Shoot! */
if (input.fire == DOWN && input.old_fire == UP && got_power != NONE_POWER)
{
- if(World::current()->add_bullet(Vector(base.x, base.y + (base.height/2)),
+ if(Sector::current()->add_bullet(Vector(base.x, base.y + (base.height/2)),
physic.get_velocity_x(), dir))
shooting_timer.start(SHOOTING_TIME);
input.old_fire = DOWN;
/* Grab distros: */
if (!dying)
{
- World::current()->trygrabdistro(base.x, base.y, NO_BOUNCE);
- World::current()->trygrabdistro(base.x+ 31, base.y, NO_BOUNCE);
+ Sector::current()->trygrabdistro(Vector(base.x, base.y), NO_BOUNCE);
+ Sector::current()->trygrabdistro(Vector(base.x+ 31, base.y), NO_BOUNCE);
- World::current()->trygrabdistro(base.x, base.y + base.height, NO_BOUNCE);
- World::current()->trygrabdistro(base.x+ 31, base.y + base.height, NO_BOUNCE);
+ Sector::current()->trygrabdistro(
+ Vector(base.x, base.y + base.height), NO_BOUNCE);
+ Sector::current()->trygrabdistro(
+ Vector(base.x+ 31, base.y + base.height), NO_BOUNCE);
if(size == BIG)
{
- World::current()->trygrabdistro(base.x, base.y + base.height / 2, NO_BOUNCE);
- World::current()->trygrabdistro(base.x+ 31, base.y + base.height / 2, NO_BOUNCE);
+ Sector::current()->trygrabdistro(
+ Vector(base.x, base.y + base.height / 2), NO_BOUNCE);
+ Sector::current()->trygrabdistro(
+ Vector(base.x+ 31, base.y + base.height / 2), NO_BOUNCE);
}
}
}
void
-Player::check_bounds(DrawingContext& viewport)
+Player::check_bounds(Camera* camera)
{
/* Keep tux in bounds: */
if (base.x < 0)
}
/* Keep in-bounds, vertically: */
- if (base.y > World::current()->get_level()->height * /*TILE_HEIGHT*/ 32)
+ if (base.y > Sector::current()->solids->get_height() * 32)
{
kill(KILL);
return;
bool adjust = false;
// can happen if back scrolling is disabled
- if(base.x < viewport.get_translation().x) {
- base.x = viewport.get_translation().x;
+ if(base.x < camera->get_translation().x) {
+ base.x = camera->get_translation().x;
adjust = true;
}
- if(base.x >= viewport.get_translation().x + screen->w - base.width) {
- base.x = viewport.get_translation().x + screen->w - base.width;
+ if(base.x >= camera->get_translation().x + screen->w - base.width) {
+ base.x = camera->get_translation().x + screen->w - base.width;
adjust = true;
}
}
}
-// EOF //
-
void player_input_init(player_input_type* pplayer_input);
class Sprite;
+class Camera;
extern Surface* tux_life;
void collision(void* p_c_object, int c_object);
void kill(HurtMode mode);
void player_remove_powerups();
- void check_bounds(DrawingContext& context);
+ void check_bounds(Camera* camera);
bool on_ground();
bool under_solid();
bool tiles_on_air(int tiles);
Surface* img_poletop;
Surface* img_flag[2];
Surface* img_cloud[2][4];
+Surface* img_distro[4];
MusicRef herring_song;
MusicRef level_end_song;
--- /dev/null
+#include "sector.h"
+
+#include <memory>
+#include <stdexcept>
+#include <iostream>
+#include <fstream>
+#include <stdexcept>
+#include "lispreader.h"
+
+#include "badguy.h"
+#include "special.h"
+#include "gameobjs.h"
+#include "camera.h"
+#include "background.h"
+#include "particlesystem.h"
+#include "tile.h"
+#include "tilemap.h"
+#include "music_manager.h"
+#include "gameloop.h"
+#include "resources.h"
+
+Sector* Sector::_current = 0;
+
+Sector::Sector()
+ : gravity(10), player(0), solids(0), background(0), camera(0),
+ currentmusic(LEVEL_MUSIC)
+{
+ song_title = "Mortimers_chipdisko.mod";
+ player = new Player();
+ add_object(player);
+}
+
+Sector::~Sector()
+{
+ for(GameObjects::iterator i = gameobjects.begin(); i != gameobjects.end();
+ ++i)
+ delete *i;
+
+ for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
+ ++i)
+ delete *i;
+
+ if(_current == this)
+ _current = 0;
+}
+
+void
+Sector::parse(LispReader& lispreader)
+{
+ _current = this;
+
+ for(lisp_object_t* cur = lispreader.get_lisp(); !lisp_nil_p(cur);
+ cur = lisp_cdr(cur)) {
+ std::string token = lisp_symbol(lisp_car(lisp_car(cur)));
+ lisp_object_t* data = lisp_car(lisp_cdr(lisp_car(cur)));
+ LispReader reader(lisp_cdr(lisp_car(cur)));
+
+ if(token == "name") {
+ name = lisp_string(data);
+ } else if(token == "gravity") {
+ gravity = lisp_integer(data);
+ } else if(token == "music") {
+ song_title = lisp_string(data);
+ load_music();
+ } else if(token == "camera") {
+ if(camera) {
+ std::cerr << "Warning: More than 1 camera defined in sector.\n";
+ continue;
+ }
+ camera = new Camera(this);
+ camera->read(reader);
+ add_object(camera);
+ } else if(token == "background") {
+ background = new Background(reader);
+ add_object(background);
+ } else if(token == "playerspawn") {
+ SpawnPoint* sp = new SpawnPoint;
+ reader.read_string("name", sp->name);
+ reader.read_float("x", sp->pos.x);
+ reader.read_float("y", sp->pos.y);
+ } else if(token == "tilemap") {
+ TileMap* tilemap = new TileMap(reader);
+ add_object(tilemap);
+
+ if(tilemap->is_solid()) {
+ if(solids) {
+ std::cerr << "Warning multiple solid tilemaps in sector.\n";
+ continue;
+ }
+ solids = tilemap;
+ }
+ } else if(badguykind_from_string(token) != BAD_INVALID) {
+ add_object(new BadGuy(badguykind_from_string(token), reader));
+ } else if(token == "trampoline") {
+ add_object(new Trampoline(reader));
+ } else if(token == "flying-platform") {
+ add_object(new FlyingPlatform(reader));
+ } else if(token == "particles-snow") {
+ SnowParticleSystem* partsys = new SnowParticleSystem();
+ partsys->parse(reader);
+ add_object(partsys);
+ } else if(token == "particles-clouds") {
+ CloudParticleSystem* partsys = new CloudParticleSystem();
+ partsys->parse(reader);
+ add_object(partsys);
+ }
+ }
+
+ if(!camera) {
+ std::cerr << "sector does not contain a camera.\n";
+ camera = new Camera(this);
+ }
+ if(!solids)
+ throw std::runtime_error("sector does not contain a solid tile layer.");
+}
+
+void
+Sector::parse_old_format(LispReader& reader)
+{
+ _current = this;
+
+ name = "main";
+ reader.read_float("gravity", gravity);
+
+ std::string backgroundimage;
+ reader.read_string("background", backgroundimage);
+ float bgspeed = .5;
+ reader.read_float("bkgd_speed", bgspeed);
+
+ Color bkgd_top, bkgd_bottom;
+ int r = 0, g = 0, b = 128;
+ reader.read_int("bkgd_red_top", r);
+ reader.read_int("bkgd_green_top", g);
+ reader.read_int("bkgd_blue_top", b);
+ bkgd_top.red = r;
+ bkgd_top.green = g;
+ bkgd_top.blue = b;
+
+ reader.read_int("bkgd_red_bottom", r);
+ reader.read_int("bkgd_green_bottom", g);
+ reader.read_int("bkgd_blue_bottom", b);
+ bkgd_bottom.red = r;
+ bkgd_bottom.green = g;
+ bkgd_bottom.blue = b;
+
+ if(backgroundimage != "") {
+ background = new Background;
+ background->set_image(backgroundimage, bgspeed);
+ add_object(background);
+ } else {
+ background = new Background;
+ background->set_gradient(bkgd_top, bkgd_bottom);
+ add_object(background);
+ }
+
+ std::string particlesystem;
+ reader.read_string("particle_system", particlesystem);
+ if(particlesystem == "clouds")
+ add_object(new CloudParticleSystem());
+ else if(particlesystem == "snow")
+ add_object(new SnowParticleSystem());
+
+ Vector startpos(100, 170);
+ reader.read_float("start_pos_x", startpos.x);
+ reader.read_float("start_pos_y", startpos.y);
+
+ SpawnPoint* spawn = new SpawnPoint;
+ spawn->pos = startpos;
+ spawn->name = "main";
+ spawnpoints.push_back(spawn);
+
+ song_title = "Mortimers_chipdisko.mod";
+ reader.read_string("music", song_title);
+ load_music();
+
+ int width, height = 15;
+ reader.read_int("width", width);
+ reader.read_int("height", height);
+
+ std::vector<unsigned int> tiles;
+ if(reader.read_int_vector("interactive-tm", tiles)
+ || reader.read_int_vector("tilemap", tiles)) {
+ TileMap* tilemap = new TileMap();
+ tilemap->set(width, height, tiles, LAYER_TILES, true);
+ solids = tilemap;
+ add_object(tilemap);
+ }
+
+ if(reader.read_int_vector("background-tm", tiles)) {
+ TileMap* tilemap = new TileMap();
+ tilemap->set(width, height, tiles, LAYER_BACKGROUNDTILES, false);
+ add_object(tilemap);
+ }
+
+ if(reader.read_int_vector("foreground-tm", tiles)) {
+ TileMap* tilemap = new TileMap();
+ tilemap->set(width, height, tiles, LAYER_FOREGROUNDTILES, false);
+ add_object(tilemap);
+ }
+
+ // TODO read resetpoints
+
+ // read objects
+ {
+ lisp_object_t* cur = 0;
+ if(reader.read_lisp("objects", cur)) {
+ while(!lisp_nil_p(cur)) {
+ lisp_object_t* data = lisp_car(cur);
+ std::string object_type = lisp_symbol(lisp_car(data));
+
+ LispReader reader(lisp_cdr(data));
+
+ if(object_type == "trampoline") {
+ add_object(new Trampoline(reader));
+ }
+ else if(object_type == "flying-platform") {
+ add_object(new FlyingPlatform(reader));
+ }
+ else {
+ BadGuyKind kind = badguykind_from_string(object_type);
+ add_object(new BadGuy(kind, reader));
+ }
+
+ cur = lisp_cdr(cur);
+ }
+ }
+ }
+
+ // add a camera
+ camera = new Camera(this);
+ add_object(camera);
+}
+
+void
+Sector::write(LispWriter& writer)
+{
+ writer.write_string("name", name);
+ writer.write_float("gravity", gravity);
+
+ for(GameObjects::iterator i = gameobjects.begin();
+ i != gameobjects.end(); ++i) {
+ Serializable* serializable = dynamic_cast<Serializable*> (*i);
+ if(serializable)
+ serializable->write(writer);
+ }
+}
+
+void
+Sector::add_object(GameObject* object)
+{
+ // XXX a bit hackish, at least try to keep the number of these things down...
+ BadGuy* badguy = dynamic_cast<BadGuy*> (object);
+ if(badguy)
+ badguys.push_back(badguy);
+ Bullet* bullet = dynamic_cast<Bullet*> (object);
+ if(bullet)
+ bullets.push_back(bullet);
+ Upgrade* upgrade = dynamic_cast<Upgrade*> (object);
+ if(upgrade)
+ upgrades.push_back(upgrade);
+ Trampoline* trampoline = dynamic_cast<Trampoline*> (object);
+ if(trampoline)
+ trampolines.push_back(trampoline);
+ FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (object);
+ if(flying_platform)
+ flying_platforms.push_back(flying_platform);
+ Background* background = dynamic_cast<Background*> (object);
+ if(background)
+ this->background = background;
+
+ gameobjects.push_back(object);
+}
+
+void
+Sector::activate(const std::string& spawnpoint)
+{
+ _current = this;
+
+ // Apply bonuses from former levels
+ switch (player_status.bonus)
+ {
+ case PlayerStatus::NO_BONUS:
+ break;
+
+ case PlayerStatus::FLOWER_BONUS:
+ player->got_power = Player::FIRE_POWER; // FIXME: add ice power to here
+ // fall through
+
+ case PlayerStatus::GROWUP_BONUS:
+ player->grow(false);
+ break;
+ }
+
+ SpawnPoint* sp = 0;
+ for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
+ ++i) {
+ if((*i)->name == spawnpoint) {
+ sp = *i;
+ break;
+ }
+ }
+ if(!sp) {
+ std::cerr << "Spawnpoint '" << spawnpoint << "' not found.\n";
+ } else {
+ player->move(sp->pos);
+ }
+
+ camera->reset(Vector(player->base.x, player->base.y));
+}
+
+void
+Sector::action(float elapsed_time)
+{
+ player->check_bounds(camera);
+
+ /* update objects (don't use iterators here, because the list might change
+ * during the iteration)
+ */
+ for(size_t i = 0; i < gameobjects.size(); ++i)
+ if(gameobjects[i]->is_valid())
+ gameobjects[i]->action(elapsed_time);
+
+ /* Handle all possible collisions. */
+ collision_handler();
+
+ /** cleanup marked objects */
+ for(std::vector<GameObject*>::iterator i = gameobjects.begin();
+ i != gameobjects.end(); /* nothing */) {
+ if((*i)->is_valid() == false) {
+ BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
+ if(badguy) {
+ badguys.erase(std::remove(badguys.begin(), badguys.end(), badguy),
+ badguys.end());
+ }
+ Bullet* bullet = dynamic_cast<Bullet*> (*i);
+ if(bullet) {
+ bullets.erase(
+ std::remove(bullets.begin(), bullets.end(), bullet),
+ bullets.end());
+ }
+ Upgrade* upgrade = dynamic_cast<Upgrade*> (*i);
+ if(upgrade) {
+ upgrades.erase(
+ std::remove(upgrades.begin(), upgrades.end(), upgrade),
+ upgrades.end());
+ }
+ Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
+ if(trampoline) {
+ trampolines.erase(
+ std::remove(trampolines.begin(), trampolines.end(), trampoline),
+ trampolines.end());
+ }
+ FlyingPlatform* flying_platform= dynamic_cast<FlyingPlatform*> (*i);
+ if(flying_platform) {
+ flying_platforms.erase(
+ std::remove(flying_platforms.begin(), flying_platforms.end(), flying_platform),
+ flying_platforms.end());
+ }
+
+ delete *i;
+ i = gameobjects.erase(i);
+ } else {
+ ++i;
+ }
+ }
+}
+
+void
+Sector::draw(DrawingContext& context)
+{
+ context.push_transform();
+ context.set_translation(camera->get_translation());
+
+ for(GameObjects::iterator i = gameobjects.begin();
+ i != gameobjects.end(); ++i) {
+ if( (*i)->is_valid() )
+ (*i)->draw(context);
+ }
+
+ context.pop_transform();
+}
+
+void
+Sector::collision_handler()
+{
+ // CO_BULLET & CO_BADGUY check
+ for(unsigned int i = 0; i < bullets.size(); ++i)
+ {
+ for (BadGuys::iterator j = badguys.begin(); j != badguys.end(); ++j)
+ {
+ if((*j)->dying != DYING_NOT)
+ continue;
+
+ if(rectcollision(bullets[i]->base, (*j)->base))
+ {
+ // We have detected a collision and now call the
+ // collision functions of the collided objects.
+ (*j)->collision(bullets[i], CO_BULLET, COLLISION_NORMAL);
+ bullets[i]->collision(CO_BADGUY);
+ break; // bullet is invalid now, so break
+ }
+ }
+ }
+
+ /* CO_BADGUY & CO_BADGUY check */
+ for (BadGuys::iterator i = badguys.begin(); i != badguys.end(); ++i)
+ {
+ if((*i)->dying != DYING_NOT)
+ continue;
+
+ BadGuys::iterator j = i;
+ ++j;
+ for (; j != badguys.end(); ++j)
+ {
+ if(j == i || (*j)->dying != DYING_NOT)
+ continue;
+
+ if(rectcollision((*i)->base, (*j)->base))
+ {
+ // We have detected a collision and now call the
+ // collision functions of the collided objects.
+ (*j)->collision(*i, CO_BADGUY);
+ (*i)->collision(*j, CO_BADGUY);
+ }
+ }
+ }
+ if(player->dying != DYING_NOT) return;
+
+ // CO_BADGUY & CO_PLAYER check
+ for (BadGuys::iterator i = badguys.begin(); i != badguys.end(); ++i)
+ {
+ if((*i)->dying != DYING_NOT)
+ continue;
+
+ if(rectcollision_offset((*i)->base, player->base, 0, 0))
+ {
+ // We have detected a collision and now call the collision
+ // functions of the collided objects.
+ if (player->previous_base.y < player->base.y &&
+ player->previous_base.y + player->previous_base.height
+ < (*i)->base.y + (*i)->base.height/2
+ && !player->invincible_timer.started())
+ {
+ (*i)->collision(player, CO_PLAYER, COLLISION_SQUISH);
+ }
+ else
+ {
+ player->collision(*i, CO_BADGUY);
+ (*i)->collision(player, CO_PLAYER, COLLISION_NORMAL);
+ }
+ }
+ }
+
+ // CO_UPGRADE & CO_PLAYER check
+ for(unsigned int i = 0; i < upgrades.size(); ++i)
+ {
+ if(rectcollision(upgrades[i]->base, player->base))
+ {
+ // We have detected a collision and now call the collision
+ // functions of the collided objects.
+ upgrades[i]->collision(player, CO_PLAYER, COLLISION_NORMAL);
+ }
+ }
+
+ // CO_TRAMPOLINE & (CO_PLAYER or CO_BADGUY)
+ for (Trampolines::iterator i = trampolines.begin(); i != trampolines.end(); ++i)
+ {
+ if (rectcollision((*i)->base, player->base))
+ {
+ if (player->previous_base.y < player->base.y &&
+ player->previous_base.y + player->previous_base.height
+ < (*i)->base.y + (*i)->base.height/2)
+ {
+ (*i)->collision(player, CO_PLAYER, COLLISION_SQUISH);
+ }
+ else if (player->previous_base.y <= player->base.y)
+ {
+ player->collision(*i, CO_TRAMPOLINE);
+ (*i)->collision(player, CO_PLAYER, COLLISION_NORMAL);
+ }
+ }
+ }
+
+ // CO_FLYING_PLATFORM & (CO_PLAYER or CO_BADGUY)
+ for (FlyingPlatforms::iterator i = flying_platforms.begin(); i != flying_platforms.end(); ++i)
+ {
+ if (rectcollision((*i)->base, player->base))
+ {
+ if (player->previous_base.y < player->base.y &&
+ player->previous_base.y + player->previous_base.height
+ < (*i)->base.y + (*i)->base.height/2)
+ {
+ (*i)->collision(player, CO_PLAYER, COLLISION_SQUISH);
+ player->collision(*i, CO_FLYING_PLATFORM);
+ }
+/* else if (player->previous_base.y <= player->base.y)
+ {
+ }*/
+ }
+ }
+}
+
+void
+Sector::add_score(const Vector& pos, int s)
+{
+ player_status.score += s;
+
+ add_object(new FloatingScore(pos, s));
+}
+
+void
+Sector::add_bouncy_distro(const Vector& pos)
+{
+ add_object(new BouncyDistro(pos));
+}
+
+void
+Sector::add_broken_brick(const Vector& pos, Tile* tile)
+{
+ add_broken_brick_piece(pos, Vector(-1, -4), tile);
+ add_broken_brick_piece(pos + Vector(0, 16), Vector(-1.5, -3), tile);
+
+ add_broken_brick_piece(pos + Vector(16, 0), Vector(1, -4), tile);
+ add_broken_brick_piece(pos + Vector(16, 16), Vector(1.5, -3), tile);
+}
+
+void
+Sector::add_broken_brick_piece(const Vector& pos, const Vector& movement,
+ Tile* tile)
+{
+ add_object(new BrokenBrick(tile, pos, movement));
+}
+
+void
+Sector::add_bouncy_brick(const Vector& pos)
+{
+ add_object(new BouncyBrick(pos));
+}
+
+BadGuy*
+Sector::add_bad_guy(float x, float y, BadGuyKind kind)
+{
+ BadGuy* badguy = new BadGuy(kind, x, y);
+ add_object(badguy);
+ return badguy;
+}
+
+void
+Sector::add_upgrade(const Vector& pos, Direction dir, UpgradeKind kind)
+{
+ add_object(new Upgrade(pos, dir, kind));
+}
+
+bool
+Sector::add_bullet(const Vector& pos, float xm, Direction dir)
+{
+ if(player->got_power == Player::FIRE_POWER)
+ {
+ if(bullets.size() > MAX_FIRE_BULLETS-1)
+ return false;
+ }
+ else if(player->got_power == Player::ICE_POWER)
+ {
+ if(bullets.size() > MAX_ICE_BULLETS-1)
+ return false;
+ }
+
+ Bullet* new_bullet = 0;
+ if(player->got_power == Player::FIRE_POWER)
+ new_bullet = new Bullet(pos, xm, dir, FIRE_BULLET);
+ else if(player->got_power == Player::ICE_POWER)
+ new_bullet = new Bullet(pos, xm, dir, ICE_BULLET);
+ else
+ throw std::runtime_error("wrong bullet type.");
+ add_object(new_bullet);
+
+ play_sound(sounds[SND_SHOOT], SOUND_CENTER_SPEAKER);
+
+ return true;
+}
+
+/* Break a brick: */
+bool
+Sector::trybreakbrick(const Vector& pos, bool small)
+{
+ Tile* tile = solids->get_tile_at(pos);
+ if (tile->attributes & Tile::BRICK)
+ {
+ if (tile->data > 0)
+ {
+ /* Get a distro from it: */
+ add_bouncy_distro(
+ Vector(((int)(pos.x + 1) / 32) * 32, (int)(pos.y / 32) * 32));
+
+ // TODO: don't handle this in a global way but per-tile...
+ if (!counting_distros)
+ {
+ counting_distros = true;
+ distro_counter = 5;
+ }
+ else
+ {
+ distro_counter--;
+ }
+
+ if (distro_counter <= 0)
+ {
+ counting_distros = false;
+ solids->change_at(pos, tile->next_tile);
+ }
+
+ play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
+ player_status.score = player_status.score + SCORE_DISTRO;
+ player_status.distros++;
+ return true;
+ }
+ else if (!small)
+ {
+ /* Get rid of it: */
+ solids->change_at(pos, tile->next_tile);
+
+ /* Replace it with broken bits: */
+ add_broken_brick(Vector(
+ ((int)(pos.x + 1) / 32) * 32,
+ (int)(pos.y / 32) * 32), tile);
+
+ /* Get some score: */
+ play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
+ player_status.score = player_status.score + SCORE_BRICK;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Empty a box: */
+void
+Sector::tryemptybox(const Vector& pos, Direction col_side)
+{
+ Tile* tile = solids->get_tile_at(pos);
+ if (!(tile->attributes & Tile::FULLBOX))
+ return;
+
+ // according to the collision side, set the upgrade direction
+ if(col_side == LEFT)
+ col_side = RIGHT;
+ else
+ col_side = LEFT;
+
+ int posx = ((int)(pos.x+1) / 32) * 32;
+ int posy = (int)(pos.y/32) * 32 - 32;
+ switch(tile->data)
+ {
+ case 1: // Box with a distro!
+ add_bouncy_distro(Vector(posx, posy));
+ play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
+ player_status.score = player_status.score + SCORE_DISTRO;
+ player_status.distros++;
+ break;
+
+ case 2: // Add a fire flower upgrade!
+ if (player->size == SMALL) /* Tux is small, add mints! */
+ add_upgrade(Vector(posx, posy), col_side, UPGRADE_GROWUP);
+ else /* Tux is big, add a fireflower: */
+ add_upgrade(Vector(posx, posy), col_side, UPGRADE_FIREFLOWER);
+ play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
+ break;
+
+ case 5: // Add an ice flower upgrade!
+ if (player->size == SMALL) /* Tux is small, add mints! */
+ add_upgrade(Vector(posx, posy), col_side, UPGRADE_GROWUP);
+ else /* Tux is big, add an iceflower: */
+ add_upgrade(Vector(posx, posy), col_side, UPGRADE_ICEFLOWER);
+ play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
+ break;
+
+ case 3: // Add a golden herring
+ add_upgrade(Vector(posx, posy), col_side, UPGRADE_HERRING);
+ break;
+
+ case 4: // Add a 1up extra
+ add_upgrade(Vector(posx, posy), col_side, UPGRADE_1UP);
+ break;
+ default:
+ break;
+ }
+
+ /* Empty the box: */
+ solids->change_at(pos, tile->next_tile);
+}
+
+/* Try to grab a distro: */
+void
+Sector::trygrabdistro(const Vector& pos, int bounciness)
+{
+ Tile* tile = solids->get_tile_at(pos);
+ if (!(tile->attributes & Tile::COIN))
+ return;
+
+ solids->change_at(pos, tile->next_tile);
+ play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
+
+ if (bounciness == BOUNCE)
+ {
+ add_bouncy_distro(Vector(((int)(pos.x + 1) / 32) * 32,
+ (int)(pos.y / 32) * 32));
+ }
+
+ player_status.score = player_status.score + SCORE_DISTRO;
+ player_status.distros++;
+}
+
+/* Try to bump a bad guy from below: */
+void
+Sector::trybumpbadguy(const Vector& pos)
+{
+ // Bad guys:
+ for (BadGuys::iterator i = badguys.begin(); i != badguys.end(); ++i)
+ {
+ if ((*i)->base.x >= pos.x - 32 && (*i)->base.x <= pos.x + 32 &&
+ (*i)->base.y >= pos.y - 16 && (*i)->base.y <= pos.y + 16)
+ {
+ (*i)->collision(player, CO_PLAYER, COLLISION_BUMP);
+ }
+ }
+
+ // Upgrades:
+ for (unsigned int i = 0; i < upgrades.size(); i++)
+ {
+ if (upgrades[i]->base.height == 32 &&
+ upgrades[i]->base.x >= pos.x - 32 && upgrades[i]->base.x <= pos.x + 32 &&
+ upgrades[i]->base.y >= pos.y - 16 && upgrades[i]->base.y <= pos.y + 16)
+ {
+ upgrades[i]->collision(player, CO_PLAYER, COLLISION_BUMP);
+ }
+ }
+}
+
+void
+Sector::load_music()
+{
+ char* song_path;
+ char* song_subtitle;
+
+ level_song = music_manager->load_music(datadir + "/music/" + song_title);
+
+ song_path = (char *) malloc(sizeof(char) * datadir.length() +
+ strlen(song_title.c_str()) + 8 + 5);
+ song_subtitle = strdup(song_title.c_str());
+ strcpy(strstr(song_subtitle, "."), "\0");
+ sprintf(song_path, "%s/music/%s-fast%s", datadir.c_str(),
+ song_subtitle, strstr(song_title.c_str(), "."));
+ if(!music_manager->exists_music(song_path)) {
+ level_song_fast = level_song;
+ } else {
+ level_song_fast = music_manager->load_music(song_path);
+ }
+ free(song_subtitle);
+ free(song_path);
+}
+
+void
+Sector::play_music(int type)
+{
+ currentmusic = type;
+ switch(currentmusic) {
+ case HURRYUP_MUSIC:
+ music_manager->play_music(level_song_fast);
+ break;
+ case LEVEL_MUSIC:
+ music_manager->play_music(level_song);
+ break;
+ case HERRING_MUSIC:
+ music_manager->play_music(herring_song);
+ break;
+ default:
+ music_manager->halt_music();
+ break;
+ }
+}
+
+int
+Sector::get_music_type()
+{
+ return currentmusic;
+}
--- /dev/null
+#ifndef __SECTOR_H__
+#define __SECTOR_H__
+
+#include <string>
+#include <vector>
+#include "vector.h"
+#include "badguy.h"
+#include "special.h"
+#include "musicref.h"
+#include "screen/drawing_context.h"
+
+class GameObject;
+class Background;
+class Player;
+class Camera;
+class Trampoline;
+class FlyingPlatform;
+class TileMap;
+class Upgrade;
+class Bullet;
+class BadGuy;
+class Vector;
+class LispReader;
+class Tile;
+
+struct SpawnPoint
+{
+ std::string name;
+ Vector pos;
+};
+
+/** This class holds a sector (a part of a level) and all the game objects
+ * (badguys, player, background, tilemap, ...)
+ */
+class Sector
+{
+public:
+ Sector();
+ ~Sector();
+
+ /// read sector from lisp file
+ void parse(LispReader& reader);
+ void parse_old_format(LispReader& reader);
+ /// write sector to lisp file
+ void write(LispWriter& writer);
+
+ /// activates this sector (change music, intialize player class, ...)
+ void activate(const std::string& spawnpoint = "main");
+
+ void action(float elapsed_time);
+ void draw(DrawingContext& context);
+
+ /// adds a gameobject
+ void add_object(GameObject* object);
+
+ const std::string& get_name() const
+ { return name; }
+
+ void play_music(int musictype);
+ int get_music_type();
+
+ /** Checks for all possible collisions. And calls the
+ collision_handlers, which the collision_objects provide for this
+ case (or not). */
+ void collision_handler();
+
+ void add_score(const Vector& pos, int s);
+ void add_bouncy_distro(const Vector& pos);
+ void add_broken_brick(const Vector& pos, Tile* tile);
+ void add_broken_brick_piece(const Vector& pos,
+ const Vector& movement, Tile* tile);
+ void add_bouncy_brick(const Vector& pos);
+
+ BadGuy* add_bad_guy(float x, float y, BadGuyKind kind);
+
+ void add_upgrade(const Vector& pos, Direction dir, UpgradeKind kind);
+ bool add_bullet(const Vector& pos, float xm, Direction dir);
+
+ /** Try to grab the coin at the given coordinates */
+ void trygrabdistro(const Vector& pos, int bounciness);
+
+ /** Try to break the brick at the given coordinates */
+ bool trybreakbrick(const Vector& pos, bool small);
+
+ /** Try to get the content out of a bonus box, thus emptying it */
+ void tryemptybox(const Vector& pos, Direction col_side);
+
+ /** Try to bumb a badguy that might we walking above Tux, thus shaking
+ the tile which the badguy is walking on an killing him this way */
+ void trybumpbadguy(const Vector& pos);
+
+ /** @evil@ */
+ static Sector* current()
+ { return _current; }
+
+private:
+ void load_music();
+
+ static Sector* _current;
+
+ std::string name;
+
+ std::string song_title;
+ MusicRef level_song;
+ MusicRef level_song_fast;
+
+public:
+ float gravity;
+
+ // some special objects, where we need direct access
+ Player* player;
+ TileMap* solids;
+ Background* background;
+ Camera* camera;
+
+private:
+ typedef std::vector<BadGuy*> BadGuys;
+ BadGuys badguys;
+ typedef std::vector<Trampoline*> Trampolines;
+ Trampolines trampolines;
+ typedef std::vector<FlyingPlatform*> FlyingPlatforms;
+ FlyingPlatforms flying_platforms;
+
+ std::vector<Upgrade*> upgrades;
+ std::vector<Bullet*> bullets;
+
+public: // ugly
+ typedef std::vector<GameObject*> GameObjects;
+ GameObjects gameobjects;
+
+private:
+ typedef std::vector<SpawnPoint*> SpawnPoints;
+ SpawnPoints spawnpoints;
+
+ int distro_counter;
+ bool counting_distros;
+ int currentmusic;
+};
+
+#endif
+
#include "scene.h"
#include "globals.h"
#include "player.h"
+#include "sector.h"
#include "sprite_manager.h"
#include "resources.h"
physic.set_velocity_y(-9);
float scroll_x =
- World::current()->camera->get_translation().x;
+ Sector::current()->camera->get_translation().x;
float scroll_y =
- World::current()->camera->get_translation().y;
+ Sector::current()->camera->get_translation().y;
if (base.x < scroll_x ||
base.x > scroll_x + screen->w ||
base.y < scroll_y ||
/* Away from the screen? Kill it! */
float scroll_x =
- World::current()->camera->get_translation().x;
+ Sector::current()->camera->get_translation().x;
float scroll_y =
- World::current()->camera->get_translation().y;
+ Sector::current()->camera->get_translation().y;
if(base.x < scroll_x - X_OFFSCREEN_DISTANCE ||
base.x > scroll_x + screen->w + X_OFFSCREEN_DISTANCE ||
{
play_sound(sounds[SND_HERRING], SOUND_CENTER_SPEAKER);
pplayer->invincible_timer.start(TUX_INVINCIBLE_TIME);
- World::current()->play_music(HERRING_MUSIC);
+ Sector::current()->play_music(HERRING_MUSIC);
}
else if (kind == UPGRADE_1UP)
{
LispReader reader(cur);
- if(!reader.read_string("name", &name))
+ if(!reader.read_string("name", name))
st_abort("Sprite wihtout name", "");
- reader.read_int("x-hotspot", &x_hotspot);
- reader.read_int("y-hotspot", &y_hotspot);
- reader.read_float("fps", &fps);
+ reader.read_int("x-hotspot", x_hotspot);
+ reader.read_int("y-hotspot", y_hotspot);
+ reader.read_float("fps", fps);
std::vector<std::string> images;
- if(!reader.read_string_vector("images", &images))
+ if(!reader.read_string_vector("images", images))
st_abort("Sprite contains no images: ", name.c_str());
for(std::vector<std::string>::size_type i = 0; i < images.size(); ++i)
int main(int argc, char * argv[])
{
+#ifndef DEBUG
try {
+#endif
st_directory_setup();
parseargs(argc, argv);
}
else if (level_startup_file)
{
- GameSession session(level_startup_file, 1, ST_GL_LOAD_LEVEL_FILE);
+ GameSession session(level_startup_file, ST_GL_LOAD_LEVEL_FILE);
session.run();
}
else
Surface::debug_check();
#endif
st_shutdown();
+#ifndef DEBUG // we want to see the backtrace in gdb when in debug mode
}
catch (SuperTuxException &e)
{
{
std:: cerr << "Unhandled exception: " << e.what() << std::endl;
}
+#endif
return 0;
}
int
Tile::read(LispReader& reader)
{
- if(!reader.read_int("id", &id)) {
+ if(!reader.read_int("id", id)) {
std::cerr << "Missing tile-id.\n";
return -1;
}
bool value;
- if(reader.read_bool("solid", &value) && value)
+ if(reader.read_bool("solid", value) && value)
attributes |= SOLID;
- if(reader.read_bool("unisolid", &value) && value)
+ if(reader.read_bool("unisolid", value) && value)
attributes |= GOAL;
- if(reader.read_bool("brick", &value) && value)
+ if(reader.read_bool("brick", value) && value)
attributes |= BRICK;
- if(reader.read_bool("ice", &value) && value)
+ if(reader.read_bool("ice", value) && value)
attributes |= ICE;
- if(reader.read_bool("water", &value) && value)
+ if(reader.read_bool("water", value) && value)
attributes |= WATER;
- if(reader.read_bool("spike", &value) && value)
+ if(reader.read_bool("spike", value) && value)
attributes |= SPIKE;
- if(reader.read_bool("fullbox", &value) && value)
+ if(reader.read_bool("fullbox", value) && value)
attributes |= FULLBOX;
- if(reader.read_bool("distro", &value) && value)
+ if(reader.read_bool("distro", value) && value)
attributes |= COIN;
- if(reader.read_bool("coin", &value) && value)
+ if(reader.read_bool("coin", value) && value)
attributes |= COIN;
- if(reader.read_bool("goal", &value) && value)
+ if(reader.read_bool("goal", value) && value)
attributes |= GOAL;
- reader.read_int("data", &data);
- reader.read_int("anim-speed", &anim_speed);
- reader.read_int("next-tile", &next_tile);
+ reader.read_int("data", data);
+ reader.read_int("anim-speed", anim_speed);
+ reader.read_int("next-tile", next_tile);
std::vector<std::string> filenames;
- reader.read_string_vector("images", &filenames);
+ reader.read_string_vector("images", filenames);
std::vector<std::string> editor_filenames;
- reader.read_string_vector("editor-images", &editor_filenames);
+ reader.read_string_vector("editor-images", editor_filenames);
// read images
for(std::vector<std::string>::iterator i = filenames.begin();
{
LispReader reader(lisp_cdr(element));
std::string filename;
- reader.read_string("file", &filename);
+ reader.read_string("file", filename);
filename = datadir + "/images/tilesets/" + filename;
load_tileset(filename);
}
{
TileGroup new_;
LispReader reader(lisp_cdr(element));
- reader.read_string("name", &new_.name);
- reader.read_int_vector("tiles", &new_.tiles);
+ reader.read_string("name", new_.name);
+ reader.read_int_vector("tiles", new_.tiles);
if(!tilegroups_)
tilegroups_ = new std::set<TileGroup>;
tilegroups_->insert(new_).first;
else if (strcmp(lisp_symbol(lisp_car(element)), "properties") == 0)
{
LispReader reader(lisp_cdr(element));
- reader.read_int("id", &tileset_id);
+ reader.read_int("id", tileset_id);
tileset_id *= 1000;
}
else
#include <assert.h>
#include <algorithm>
+#include <iostream>
+#include <stdexcept>
#include <math.h>
#include "screen/drawing_context.h"
#include "level.h"
#include "tile.h"
#include "globals.h"
+#include "lispreader.h"
+#include "lispwriter.h"
-TileMap::TileMap(Level* newlevel)
- : level(newlevel)
+TileMap::TileMap()
+ : solid(false), speed(1), width(0), height(0), layer(LAYER_TILES)
{
tilemanager = TileManager::instance();
}
+TileMap::TileMap(LispReader& reader)
+ : solid(false), speed(1), width(0), height(0), layer(LAYER_TILES)
+{
+ tilemanager = TileManager::instance();
+
+ std::string layer;
+ if(reader.read_string("layer", layer)) {
+ if(layer == "background")
+ layer = LAYER_BACKGROUNDTILES;
+ else if(layer == "interactive")
+ layer = LAYER_TILES;
+ else if(layer == "foreground")
+ layer = LAYER_FOREGROUNDTILES;
+ else
+ std::cout << "Unknown layer '" << layer << "' 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(!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()
{
}
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 {
+ std::cout << "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(const std::vector<unsigned int>& tiles, DrawingContext& context,
- int layer)
+TileMap::draw(DrawingContext& context)
{
/** 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(level->width * 32));
- float end_y = std::min(start_y + screen->h, float(level->height * 32));
+ float start_x = roundf(context.get_translation().x * speed);
+ float start_y = roundf(context.get_translation().y * speed);
+ 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 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) {
- tilemanager->draw_tile(context, tiles[ty*level->width + tx], pos, layer);
+ tilemanager->draw_tile(context, tiles[ty*width + tx], pos, layer);
}
}
}
void
-TileMap::draw(DrawingContext& context)
+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 = newt;
+ layer = newlayer;
+ solid = newsolid;
+}
+
+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;
+ } else {
+ tiles[y * new_width + x] = tiles[y * width + x];
+ }
+ }
+ }
+ }
+
+ height = new_height;
+ width = new_width;
+}
+
+Tile*
+TileMap::get_tile(int x, int y) const
+{
+ if(x < 0 || x >= width || y < 0 || y >= height)
+ return tilemanager->get(0);
+
+ return tilemanager->get(tiles[y*width + x]);
+}
+
+Tile*
+TileMap::get_tile_at(const Vector& pos) const
+{
+ return get_tile(int(pos.x)/32, int(pos.y)/32);
+}
+
+unsigned int
+TileMap::get_tile_id_at(const Vector& pos) const
+{
+ int x = int(pos.x)/32;
+ int y = int(pos.y)/32;
+ return tiles[y*width + x];
+}
+
+void
+TileMap::change(int x, int y, unsigned int newtile)
+{
+ assert(x >= 0 && x < width && y >= 0 && y < height);
+ tiles[y*width + x] = newtile;
+}
+
+void
+TileMap::change_at(const Vector& pos, unsigned int newtile)
{
- draw(level->bg_tiles, context, LAYER_BACKGROUNDTILES);
- draw(level->ia_tiles, context, LAYER_TILES);
- draw(level->fg_tiles, context, LAYER_FOREGROUNDTILES);
+ change(int(pos.x)/32, int(pos.y)/32, newtile);
}
#include <vector>
#include "game_object.h"
#include "serializable.h"
+#include "vector.h"
class Level;
class TileManager;
+class LispReader;
+class Tile;
/**
* This class is reponsible for drawing the level tiles
*/
-class TileMap : public GameObject
+class TileMap : public GameObject, public Serializable
{
public:
- TileMap(Level* level);
+ TileMap();
+ TileMap(LispReader& reader);
virtual ~TileMap();
+ virtual void write(LispWriter& writer);
+
virtual void action(float elapsed_time);
- virtual void draw(const std::vector<unsigned int>& tiles,
- DrawingContext& context, int layer);
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);
+
+ size_t get_width() const
+ { return width; }
+
+ size_t get_height() const
+ { return height; }
+
+ bool is_solid() const
+ { return solid; }
+
+ unsigned int get_tile_id_at(const Vector& pos) const;
+
+ /// returns tile in row y and column y (of the tilemap)
+ Tile* get_tile(int x, int y) const;
+ /// returns tile at position pos (in world coordinates)
+ Tile* get_tile_at(const Vector& pos) const;
+
+ void change(int x, int y, unsigned int newtile);
+
+ void change_at(const Vector& pos, unsigned int newtile);
+
+public:
+ std::vector<unsigned int> tiles;
private:
TileManager* tilemanager;
- Level* level;
+ bool solid;
+ float speed;
+ int width, height;
+ int layer;
};
#endif
#include "player.h"
#include "math.h"
#include "tile.h"
+#include "sector.h"
+#include "tilemap.h"
#include "resources.h"
static Surface* bkg_title;
static unsigned int last_update_time;
static unsigned int update_time;
-std::vector<LevelSubset*> contrib_subsets;
-std::string current_contrib_subset;
+static GameSession* titlesession;
+
+static std::vector<LevelSubset*> contrib_subsets;
+static LevelSubset* current_contrib_subset = 0;
void free_contrib_menu()
{
// FIXME: This shouln't be busy looping
LevelSubset& subset = * (contrib_subsets[index]);
- current_contrib_subset = subset.name;
+ current_contrib_subset = ⊂
contrib_subset_menu->clear();
contrib_subset_menu->additem(MN_LABEL, subset.title, 0,0);
contrib_subset_menu->additem(MN_HL,"",0,0);
+
for (int i = 1; i <= subset.levels; ++i)
{
- Level level;
- level.load(subset.name, i, 0);
- contrib_subset_menu->additem(MN_ACTION, level.name, 0, 0, i);
+ Level* level = new Level;
+ level->load(subset.get_level_filename(i));
+ contrib_subset_menu->additem(MN_ACTION, level->get_name(), 0, 0, i);
+ delete level;
}
+
contrib_subset_menu->additem(MN_HL,"",0,0);
contrib_subset_menu->additem(MN_BACK, "Back", 0, 0);
+
+ titlesession->get_current_sector()->activate();
+ titlesession->set_current();
}
}
else
if (contrib_subset_menu->get_item_by_id(index).kind == MN_ACTION)
{
std::cout << "Starting level: " << index << std::endl;
- GameSession session(current_contrib_subset, index, ST_GL_PLAY);
+
+ GameSession session(
+ current_contrib_subset->get_level_filename(index), ST_GL_PLAY);
session.run();
player_status.reset();
Menu::set_current(main_menu);
+ titlesession->get_current_sector()->activate();
+ titlesession->set_current();
}
}
}
-void draw_demo(GameSession* session, double frame_ratio)
+void draw_demo(double frame_ratio)
{
- World* world = session->get_world();
- World::set_current(world);
- Level* plevel = session->get_level();
- Player* tux = world->get_tux();
+ Sector* world = titlesession->get_current_sector();
+ Player* tux = world->player;
world->play_music(LEVEL_MUSIC);
}
// Wrap around at the end of the level back to the beginnig
- if(plevel->width * 32 - 320 < tux->base.x)
+ if(world->solids->get_width() * 32 - 320 < tux->base.x)
{
tux->level_begin();
}
walking = false;
}
- world->draw();
+ world->draw(*titlesession->context);
}
/* --- TITLE SCREEN --- */
st_pause_ticks_init();
- GameSession session(datadir + "/levels/misc/menu.stl", 0, ST_GL_DEMO_GAME);
+ titlesession = new GameSession(datadir + "/levels/misc/menu.stl", ST_GL_DEMO_GAME);
/* Load images: */
bkg_title = new Surface(datadir + "/images/background/arctis.jpg", IGNORE_ALPHA);
random_timer.start(rand() % 2000 + 2000);
Menu::set_current(main_menu);
- DrawingContext& context = World::current()->context;
+ DrawingContext& context = *titlesession->context;
while (Menu::current())
{
// if we spent to much time on a menu entry
}
/* Draw the background: */
- draw_demo(&session, frame_ratio);
+ draw_demo(frame_ratio);
- context.push_transform();
- context.set_translation(Vector(0, 0));
if (Menu::current() == main_menu)
context.draw_surface(logo, Vector(screen->w/2 - logo->w/2, 30),
LAYER_FOREGROUND1+1);
"This game comes with ABSOLUTELY NO WARRANTY. This is free software, and you\n"
"are welcome to redistribute it under certain conditions; see the file COPYING\n"
"for details.\n", Vector(0, screen->h - 70), LAYER_FOREGROUND1);
- context.pop_transform();
/* Don't draw menu, if quit is true */
Menu* menu = Menu::current();
else if (process_load_game_menu())
{
// FIXME: shouldn't be needed if GameSession doesn't relay on global variables
+ titlesession->get_current_sector()->activate();
+ titlesession->set_current();
//titletux.level_begin();
update_time = st_get_ticks();
}
/* Free surfaces: */
free_contrib_menu();
+ delete titlesession;
delete bkg_title;
delete logo;
delete img_choose_subset;
+++ /dev/null
-// $Id$
-//
-// SuperTux
-// Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
-// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
-// Copyright (C) 2004 Ingo Ruhnke <grumbel@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 <iostream>
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-#include "globals.h"
-#include "scene.h"
-#include "screen/screen.h"
-#include "defines.h"
-#include "world.h"
-#include "level.h"
-#include "tile.h"
-#include "resources.h"
-#include "gameobjs.h"
-#include "camera.h"
-#include "background.h"
-#include "tilemap.h"
-
-Surface* img_distro[4];
-
-World* World::current_ = 0;
-
-World::World(const std::string& filename, int level_nr)
- : level(0), tux(0), background(0), camera(0)
-{
- // FIXME: Move this to action and draw and everywhere else where the
- // world calls child functions
- current_ = this;
-
- tux = new Player;
- add_object(tux);
-
- level = new Level;
- camera = new Camera(tux, level);
- add_object(camera);
-
- if(level_nr >= 0) {
- level->load(filename, level_nr, this);
- } else {
- level->load(filename, this);
- }
- tux->move(level->start_pos);
-
- set_defaults();
-
- // add background
- activate_particle_systems();
-
- // add tilemap
- add_object(new TileMap(level));
- level->load_song();
-
- apply_bonuses();
-}
-
-void
-World::apply_bonuses()
-{
- // Apply bonuses from former levels
- switch (player_status.bonus)
- {
- case PlayerStatus::NO_BONUS:
- break;
-
- case PlayerStatus::FLOWER_BONUS:
- tux->got_power = Player::FIRE_POWER; // FIXME: add ice power to here
- // fall through
-
- case PlayerStatus::GROWUP_BONUS:
- tux->grow(false);
- break;
- }
-}
-
-World::~World()
-{
- for (std::vector<GameObject*>::iterator i = gameobjects.begin();
- i != gameobjects.end(); ++i) {
- delete *i;
- }
-
- delete level;
-
- current_ = 0;
-}
-
-void
-World::set_defaults()
-{
- player_status.score_multiplier = 1;
-
- counting_distros = false;
- distro_counter = 0;
-
- /* set current song/music */
- currentmusic = LEVEL_MUSIC;
-}
-
-void
-World::add_object(GameObject* object)
-{
- // XXX hack for now until new collision code is ready
- BadGuy* badguy = dynamic_cast<BadGuy*> (object);
- if(badguy)
- bad_guys.push_back(badguy);
- Bullet* bullet = dynamic_cast<Bullet*> (object);
- if(bullet)
- bullets.push_back(bullet);
- Upgrade* upgrade = dynamic_cast<Upgrade*> (object);
- if(upgrade)
- upgrades.push_back(upgrade);
- Trampoline* trampoline = dynamic_cast<Trampoline*> (object);
- if(trampoline)
- trampolines.push_back(trampoline);
- FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (object);
- if(flying_platform)
- flying_platforms.push_back(flying_platform);
- Background* background = dynamic_cast<Background*> (object);
- if(background)
- this->background = background;
-
- gameobjects.push_back(object);
-}
-
-void
-World::parse_objects(lisp_object_t* cur)
-{
- while(!lisp_nil_p(cur)) {
- lisp_object_t* data = lisp_car(cur);
- std::string object_type = lisp_symbol(lisp_car(data));
-
- LispReader reader(lisp_cdr(data));
-
- if(object_type == "trampoline") {
- add_object(new Trampoline(reader));
- }
- else if(object_type == "flying-platform") {
- add_object(new FlyingPlatform(reader));
- }
- else {
- BadGuyKind kind = badguykind_from_string(object_type);
- add_object(new BadGuy(kind, reader));
- }
-
- cur = lisp_cdr(cur);
- }
-}
-
-void
-World::activate_particle_systems()
-{
- if (level->particle_system == "clouds")
- {
- add_object(new CloudParticleSystem);
- }
- else if (level->particle_system == "snow")
- {
- add_object(new SnowParticleSystem);
- }
- else if (level->particle_system != "")
- {
- st_abort("unknown particle system specified in level", "");
- }
-}
-
-void
-World::draw()
-{
- /* Draw objects */
- for(std::vector<GameObject*>::iterator i = gameobjects.begin();
- i != gameobjects.end(); ++i)
- if((*i)->is_valid())
- (*i)->draw(context);
-}
-
-void
-World::action(float elapsed_time)
-{
- tux->check_bounds(context);
-
- /* update objects (don't use iterators here, because the list might change
- * during the iteration)
- */
- for(size_t i = 0; i < gameobjects.size(); ++i)
- if(gameobjects[i]->is_valid())
- gameobjects[i]->action(elapsed_time);
-
- /* Handle all possible collisions. */
- collision_handler();
-
- /** cleanup marked objects */
- for(std::vector<GameObject*>::iterator i = gameobjects.begin();
- i != gameobjects.end(); /* nothing */) {
- if((*i)->is_valid() == false) {
- BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
- if(badguy) {
- bad_guys.erase(std::remove(bad_guys.begin(), bad_guys.end(), badguy),
- bad_guys.end());
- }
- Bullet* bullet = dynamic_cast<Bullet*> (*i);
- if(bullet) {
- bullets.erase(
- std::remove(bullets.begin(), bullets.end(), bullet),
- bullets.end());
- }
- Upgrade* upgrade = dynamic_cast<Upgrade*> (*i);
- if(upgrade) {
- upgrades.erase(
- std::remove(upgrades.begin(), upgrades.end(), upgrade),
- upgrades.end());
- }
- Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
- if(trampoline) {
- trampolines.erase(
- std::remove(trampolines.begin(), trampolines.end(), trampoline),
- trampolines.end());
- }
- FlyingPlatform* flying_platform= dynamic_cast<FlyingPlatform*> (*i);
- if(flying_platform) {
- flying_platforms.erase(
- std::remove(flying_platforms.begin(), flying_platforms.end(), flying_platform),
- flying_platforms.end());
- }
-
- delete *i;
- i = gameobjects.erase(i);
- } else {
- ++i;
- }
- }
-}
-
-void
-World::collision_handler()
-{
- // CO_BULLET & CO_BADGUY check
- for(unsigned int i = 0; i < bullets.size(); ++i)
- {
- for (BadGuys::iterator j = bad_guys.begin(); j != bad_guys.end(); ++j)
- {
- if((*j)->dying != DYING_NOT)
- continue;
-
- if(rectcollision(bullets[i]->base, (*j)->base))
- {
- // We have detected a collision and now call the
- // collision functions of the collided objects.
- (*j)->collision(bullets[i], CO_BULLET, COLLISION_NORMAL);
- bullets[i]->collision(CO_BADGUY);
- break; // bullet is invalid now, so break
- }
- }
- }
-
- /* CO_BADGUY & CO_BADGUY check */
- for (BadGuys::iterator i = bad_guys.begin(); i != bad_guys.end(); ++i)
- {
- if((*i)->dying != DYING_NOT)
- continue;
-
- BadGuys::iterator j = i;
- ++j;
- for (; j != bad_guys.end(); ++j)
- {
- if(j == i || (*j)->dying != DYING_NOT)
- continue;
-
- if(rectcollision((*i)->base, (*j)->base))
- {
- // We have detected a collision and now call the
- // collision functions of the collided objects.
- (*j)->collision(*i, CO_BADGUY);
- (*i)->collision(*j, CO_BADGUY);
- }
- }
- }
-
- if(tux->dying != DYING_NOT) return;
-
- // CO_BADGUY & CO_PLAYER check
- for (BadGuys::iterator i = bad_guys.begin(); i != bad_guys.end(); ++i)
- {
- if((*i)->dying != DYING_NOT)
- continue;
-
- if(rectcollision_offset((*i)->base, tux->base, 0, 0))
- {
- // We have detected a collision and now call the collision
- // functions of the collided objects.
- if (tux->previous_base.y < tux->base.y &&
- tux->previous_base.y + tux->previous_base.height
- < (*i)->base.y + (*i)->base.height/2
- && !tux->invincible_timer.started())
- {
- (*i)->collision(tux, CO_PLAYER, COLLISION_SQUISH);
- }
- else
- {
- tux->collision(*i, CO_BADGUY);
- (*i)->collision(tux, CO_PLAYER, COLLISION_NORMAL);
- }
- }
- }
-
- // CO_UPGRADE & CO_PLAYER check
- for(unsigned int i = 0; i < upgrades.size(); ++i)
- {
- if(rectcollision(upgrades[i]->base, tux->base))
- {
- // We have detected a collision and now call the collision
- // functions of the collided objects.
- upgrades[i]->collision(tux, CO_PLAYER, COLLISION_NORMAL);
- }
- }
-
- // CO_TRAMPOLINE & (CO_PLAYER or CO_BADGUY)
- for (Trampolines::iterator i = trampolines.begin(); i != trampolines.end(); ++i)
- {
- if (rectcollision((*i)->base, tux->base))
- {
- if (tux->previous_base.y < tux->base.y &&
- tux->previous_base.y + tux->previous_base.height
- < (*i)->base.y + (*i)->base.height/2)
- {
- (*i)->collision(tux, CO_PLAYER, COLLISION_SQUISH);
- }
- else if (tux->previous_base.y <= tux->base.y)
- {
- tux->collision(*i, CO_TRAMPOLINE);
- (*i)->collision(tux, CO_PLAYER, COLLISION_NORMAL);
- }
- }
- }
-
- // CO_FLYING_PLATFORM & (CO_PLAYER or CO_BADGUY)
- for (FlyingPlatforms::iterator i = flying_platforms.begin(); i != flying_platforms.end(); ++i)
- {
- if (rectcollision((*i)->base, tux->base))
- {
- if (tux->previous_base.y < tux->base.y &&
- tux->previous_base.y + tux->previous_base.height
- < (*i)->base.y + (*i)->base.height/2)
- {
- (*i)->collision(tux, CO_PLAYER, COLLISION_SQUISH);
- tux->collision(*i, CO_FLYING_PLATFORM);
- }
-/* else if (tux->previous_base.y <= tux->base.y)
- {
- }*/
- }
- }
-}
-
-void
-World::add_score(const Vector& pos, int s)
-{
- player_status.score += s;
-
- add_object(new FloatingScore(pos, s));
-}
-
-void
-World::add_bouncy_distro(const Vector& pos)
-{
- add_object(new BouncyDistro(pos));
-}
-
-void
-World::add_broken_brick(const Vector& pos, Tile* tile)
-{
- add_broken_brick_piece(pos, Vector(-1, -4), tile);
- add_broken_brick_piece(pos + Vector(0, 16), Vector(-1.5, -3), tile);
-
- add_broken_brick_piece(pos + Vector(16, 0), Vector(1, -4), tile);
- add_broken_brick_piece(pos + Vector(16, 16), Vector(1.5, -3), tile);
-}
-
-void
-World::add_broken_brick_piece(const Vector& pos, const Vector& movement,
- Tile* tile)
-{
- add_object(new BrokenBrick(tile, pos, movement));
-}
-
-void
-World::add_bouncy_brick(const Vector& pos)
-{
- add_object(new BouncyBrick(pos));
-}
-
-BadGuy*
-World::add_bad_guy(float x, float y, BadGuyKind kind)
-{
- BadGuy* badguy = new BadGuy(kind, x, y);
- add_object(badguy);
- return badguy;
-}
-
-void
-World::add_upgrade(const Vector& pos, Direction dir, UpgradeKind kind)
-{
- add_object(new Upgrade(pos, dir, kind));
-}
-
-bool
-World::add_bullet(const Vector& pos, float xm, Direction dir)
-{
- if(tux->got_power == Player::FIRE_POWER)
- {
- if(bullets.size() > MAX_FIRE_BULLETS-1)
- return false;
- }
- else if(tux->got_power == Player::ICE_POWER)
- {
- if(bullets.size() > MAX_ICE_BULLETS-1)
- return false;
- }
-
- Bullet* new_bullet = 0;
- if(tux->got_power == Player::FIRE_POWER)
- new_bullet = new Bullet(pos, xm, dir, FIRE_BULLET);
- else if(tux->got_power == Player::ICE_POWER)
- new_bullet = new Bullet(pos, xm, dir, ICE_BULLET);
- else
- st_abort("wrong bullet type.", "");
- add_object(new_bullet);
-
- play_sound(sounds[SND_SHOOT], SOUND_CENTER_SPEAKER);
-
- return true;
-}
-
-void
-World::play_music(int musictype)
-{
- currentmusic = musictype;
- switch(currentmusic) {
- case HURRYUP_MUSIC:
- music_manager->play_music(get_level()->get_level_music_fast());
- break;
- case LEVEL_MUSIC:
- music_manager->play_music(get_level()->get_level_music());
- break;
- case HERRING_MUSIC:
- music_manager->play_music(herring_song);
- break;
- default:
- music_manager->halt_music();
- break;
- }
-}
-
-int
-World::get_music_type()
-{
- return currentmusic;
-}
-
-/* Break a brick: */
-bool
-World::trybreakbrick(float x, float y, bool small)
-{
- Level* plevel = get_level();
-
- Tile* tile = gettile(x, y);
- if (tile->attributes & Tile::BRICK)
- {
- if (tile->data > 0)
- {
- /* Get a distro from it: */
- add_bouncy_distro(
- Vector(((int)(x + 1) / 32) * 32, (int)(y / 32) * 32));
-
- // TODO: don't handle this in a global way but per-tile...
- if (!counting_distros)
- {
- counting_distros = true;
- distro_counter = 5;
- }
- else
- {
- distro_counter--;
- }
-
- if (distro_counter <= 0)
- {
- counting_distros = false;
- plevel->change(x, y, TM_IA, tile->next_tile);
- }
-
- play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
- player_status.score = player_status.score + SCORE_DISTRO;
- player_status.distros++;
- return true;
- }
- else if (!small)
- {
- /* Get rid of it: */
- plevel->change(x, y, TM_IA, tile->next_tile);
-
- /* Replace it with broken bits: */
- add_broken_brick(Vector(
- ((int)(x + 1) / 32) * 32,
- (int)(y / 32) * 32), tile);
-
- /* Get some score: */
- play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER);
- player_status.score = player_status.score + SCORE_BRICK;
-
- return true;
- }
- }
-
- return false;
-}
-
-/* Empty a box: */
-void
-World::tryemptybox(float x, float y, Direction col_side)
-{
- Tile* tile = gettile(x,y);
- if (!(tile->attributes & Tile::FULLBOX))
- return;
-
- // according to the collision side, set the upgrade direction
- if(col_side == LEFT)
- col_side = RIGHT;
- else
- col_side = LEFT;
-
- int posx = ((int)(x+1) / 32) * 32;
- int posy = (int)(y/32) * 32 - 32;
- switch(tile->data)
- {
- case 1: // Box with a distro!
- add_bouncy_distro(Vector(posx, posy));
- play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
- player_status.score = player_status.score + SCORE_DISTRO;
- player_status.distros++;
- break;
-
- case 2: // Add a fire flower upgrade!
- if (tux->size == SMALL) /* Tux is small, add mints! */
- add_upgrade(Vector(posx, posy), col_side, UPGRADE_GROWUP);
- else /* Tux is big, add a fireflower: */
- add_upgrade(Vector(posx, posy), col_side, UPGRADE_FIREFLOWER);
- play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
- break;
-
- case 5: // Add an ice flower upgrade!
- if (tux->size == SMALL) /* Tux is small, add mints! */
- add_upgrade(Vector(posx, posy), col_side, UPGRADE_GROWUP);
- else /* Tux is big, add an iceflower: */
- add_upgrade(Vector(posx, posy), col_side, UPGRADE_ICEFLOWER);
- play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER);
- break;
-
- case 3: // Add a golden herring
- add_upgrade(Vector(posx, posy), col_side, UPGRADE_HERRING);
- break;
-
- case 4: // Add a 1up extra
- add_upgrade(Vector(posx, posy), col_side, UPGRADE_1UP);
- break;
- default:
- break;
- }
-
- /* Empty the box: */
- level->change(x, y, TM_IA, tile->next_tile);
-}
-
-/* Try to grab a distro: */
-void
-World::trygrabdistro(float x, float y, int bounciness)
-{
- Tile* tile = gettile(x, y);
- if (tile && (tile->attributes & Tile::COIN))
- {
- level->change(x, y, TM_IA, tile->next_tile);
- play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER);
-
- if (bounciness == BOUNCE)
- {
- add_bouncy_distro(Vector(((int)(x + 1) / 32) * 32,
- (int)(y / 32) * 32));
- }
-
- player_status.score = player_status.score + SCORE_DISTRO;
- player_status.distros++;
- }
-}
-
-/* Try to bump a bad guy from below: */
-void
-World::trybumpbadguy(float x, float y)
-{
- // Bad guys:
- for (BadGuys::iterator i = bad_guys.begin(); i != bad_guys.end(); ++i)
- {
- if ((*i)->base.x >= x - 32 && (*i)->base.x <= x + 32 &&
- (*i)->base.y >= y - 16 && (*i)->base.y <= y + 16)
- {
- (*i)->collision(tux, CO_PLAYER, COLLISION_BUMP);
- }
- }
-
- // Upgrades:
- for (unsigned int i = 0; i < upgrades.size(); i++)
- {
- if (upgrades[i]->base.height == 32 &&
- upgrades[i]->base.x >= x - 32 && upgrades[i]->base.x <= x + 32 &&
- upgrades[i]->base.y >= y - 16 && upgrades[i]->base.y <= y + 16)
- {
- upgrades[i]->collision(tux, CO_PLAYER, COLLISION_BUMP);
- }
- }
-}
-
-/* EOF */
-
+++ /dev/null
-// $Id$
-//
-// SuperTux
-// Copyright (C) 2000 Bill Kendrick <bill@newbreedsoftware.com>
-// Copyright (C) 2004 Tobias Glaesser <tobi.web@gmx.de>
-// Copyright (C) 2004 Ingo Ruhnke <grumbel@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_WORLD_H
-#define SUPERTUX_WORLD_H
-
-#include <vector>
-#include <SDL.h>
-#include "type.h"
-#include "scene.h"
-#include "special.h"
-#include "badguy.h"
-#include "particlesystem.h"
-#include "screen/drawing_context.h"
-
-class Camera;
-class Level;
-class Background;
-class Trampoline;
-class FlyingPlatform;
-
-/** The World class holds a level and all the game objects (badguys,
- bouncy distros, etc) that are needed to run a game. */
-class World
-{
-private:
- typedef std::list<BadGuy*> BadGuys;
- BadGuys bad_guys_to_add;
- typedef std::list<Trampoline*> Trampolines;
- Trampolines trampolines;
- typedef std::list<FlyingPlatform*> FlyingPlatforms;
- FlyingPlatforms flying_platforms;
- Level* level;
- Player* tux;
-
- int distro_counter;
- bool counting_distros;
- int currentmusic;
-
- static World* current_;
-public:
- Background* background;
- BadGuys bad_guys;
-
- std::vector<Upgrade*> upgrades;
- std::vector<Bullet*> bullets;
- std::vector<GameObject*> gameobjects;
-
- Camera* camera;
- DrawingContext context;
-
-public:
- static World* current()
- { return current_; }
- static void set_current(World* w)
- { current_ = w; }
-
- World(const std::string& filename, int level_nr = -1);
- ~World();
-
- Level* get_level()
- { return level; }
- Player* get_tux()
- { return tux; }
-
- void add_object(GameObject* object);
-
- void set_defaults();
-
- void draw();
- void action(float elapsed_time);
-
- void play_music(int musictype);
- int get_music_type();
-
- /** Checks for all possible collisions. And calls the
- collision_handlers, which the collision_objects provide for this
- case (or not). */
- void collision_handler();
-
- void parse_objects(lisp_object_t* cur);
-
- void activate_particle_systems();
-
- void add_score(const Vector& pos, int s);
- void add_bouncy_distro(const Vector& pos);
- void add_broken_brick(const Vector& pos, Tile* tile);
- void add_broken_brick_piece(const Vector& pos,
- const Vector& movement, Tile* tile);
- void add_bouncy_brick(const Vector& pos);
-
- BadGuy* add_bad_guy(float x, float y, BadGuyKind kind);
-
- void add_upgrade(const Vector& pos, Direction dir, UpgradeKind kind);
- bool add_bullet(const Vector& pos, float xm, Direction dir);
-
- /** Try to grab the coin at the given coordinates */
- void trygrabdistro(float x, float y, int bounciness);
-
- /** Try to break the brick at the given coordinates */
- bool trybreakbrick(float x, float y, bool small);
-
- /** Try to get the content out of a bonus box, thus emptying it */
- void tryemptybox(float x, float y, Direction col_side);
-
- /** Try to bumb a badguy that might we walking above Tux, thus shaking
- the tile which the badguy is walking on an killing him this way */
- void trybumpbadguy(float x, float y);
-
- /** Apply bonuses active in the player status, used to reactivate
- bonuses from former levels */
- void apply_bonuses();
-};
-
-/** FIMXE: Workaround for the leveleditor mainly */
-extern World global_world;
-
-#endif /*SUPERTUX_WORLD_H*/
-
-/* Local Variables: */
-/* mode:c++ */
-/* End: */
-
#include "lispreader.h"
#include "gameloop.h"
#include "setup.h"
+#include "sector.h"
#include "worldmap.h"
#include "resources.h"
tile->auto_walk = false;
LispReader reader(lisp_cdr(element));
- reader.read_int("id", &id);
- reader.read_bool("north", &tile->north);
- reader.read_bool("south", &tile->south);
- reader.read_bool("west", &tile->west);
- reader.read_bool("east", &tile->east);
- reader.read_bool("stop", &tile->stop);
- reader.read_bool("auto-walk", &tile->auto_walk);
- reader.read_string("image", &filename);
+ reader.read_int("id", id);
+ reader.read_bool("north", tile->north);
+ reader.read_bool("south", tile->south);
+ reader.read_bool("west", tile->west);
+ reader.read_bool("east", tile->east);
+ reader.read_bool("stop", tile->stop);
+ reader.read_bool("auto-walk", tile->auto_walk);
+ reader.read_string("image", filename);
tile->sprite = new Surface(
datadir + "/images/worldmap/" + filename,
if (strcmp(lisp_symbol(lisp_car(element)), "tilemap") == 0)
{
LispReader reader(lisp_cdr(element));
- reader.read_int("width", &width);
- reader.read_int("height", &height);
- reader.read_int_vector("data", &tilemap);
+ reader.read_int("width", width);
+ reader.read_int("height", height);
+ reader.read_int_vector("data", tilemap);
}
else if (strcmp(lisp_symbol(lisp_car(element)), "properties") == 0)
{
LispReader reader(lisp_cdr(element));
- reader.read_string("name", &name);
- reader.read_string("music", &music);
+ reader.read_string("name", name);
+ reader.read_string("music", music);
}
else if (strcmp(lisp_symbol(lisp_car(element)), "levels") == 0)
{
level.south = true;
level.west = true;
- reader.read_string("extro-filename", &level.extro_filename);
- reader.read_string("name", &level.name);
- reader.read_int("x", &level.x);
- reader.read_int("y", &level.y);
+ reader.read_string("extro-filename", level.extro_filename);
+ reader.read_string("name", level.name);
+ reader.read_int("x", level.x);
+ reader.read_int("y", level.y);
levels.push_back(level);
}
if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-level") == 0)
{
LispReader reader(lisp_cdr(root_obj));
- reader.read_string("name", &level.title);
+ reader.read_string("name", level.title);
}
lisp_free(root_obj);
shrink_fade(Vector((level->x*32 + 16 + offset.x),(level->y*32 + 16
+ offset.y)), 500);
GameSession session(datadir + "/levels/" + level->name,
- 1, ST_GL_LOAD_LEVEL_FILE);
+ ST_GL_LOAD_LEVEL_FILE);
switch (session.run())
{
bool old_level_state = level->solved;
level->solved = true;
- if (session.get_world()->get_tux()->got_power !=
- session.get_world()->get_tux()->NONE_POWER)
+ if (session.get_current_sector()->player->got_power !=
+ session.get_current_sector()->player->NONE_POWER)
player_status.bonus = PlayerStatus::FLOWER_BONUS;
- else if (session.get_world()->get_tux()->size == BIG)
+ else if (session.get_current_sector()->player->size == BIG)
player_status.bonus = PlayerStatus::GROWUP_BONUS;
else
player_status.bonus = PlayerStatus::NO_BONUS;
void
WorldMap::draw_status(DrawingContext& context)
{
- context.push_transform();
- context.set_translation(Vector(0, 0));
-
char str[80];
sprintf(str, "%d", player_status.score);
cur = lisp_cdr(cur);
LispReader reader(cur);
- reader.read_int("lives", &player_status.lives);
- reader.read_int("score", &player_status.score);
- reader.read_int("distros", &player_status.distros);
+ reader.read_int("lives", player_status.lives);
+ reader.read_int("score", player_status.score);
+ reader.read_int("distros", player_status.distros);
if (player_status.lives < 0)
player_status.lives = START_LIVES;
lisp_object_t* tux_cur = 0;
- if (reader.read_lisp("tux", &tux_cur))
+ if (reader.read_lisp("tux", tux_cur))
{
Vector p;
std::string back_str = "none";
std::string bonus_str = "none";
LispReader tux_reader(tux_cur);
- tux_reader.read_float("x", &p.x);
- tux_reader.read_float("y", &p.y);
- tux_reader.read_string("back", &back_str);
- tux_reader.read_string("bonus", &bonus_str);
+ tux_reader.read_float("x", p.x);
+ tux_reader.read_float("y", p.y);
+ tux_reader.read_string("back", back_str);
+ tux_reader.read_string("bonus", bonus_str);
player_status.bonus = string_to_bonus(bonus_str);
tux->back_direction = string_to_direction(back_str);
}
lisp_object_t* level_cur = 0;
- if (reader.read_lisp("levels", &level_cur))
+ if (reader.read_lisp("levels", level_cur))
{
while(level_cur)
{
bool solved = false;
LispReader level_reader(data);
- level_reader.read_string("name", &name);
- level_reader.read_bool("solved", &solved);
+ level_reader.read_string("name", name);
+ level_reader.read_bool("solved", solved);
for(Levels::iterator i = levels.begin(); i != levels.end(); ++i)
{