X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fgameobjs.cpp;h=39d4eb699751fb897d1a060ad5e7639211fd1bae;hb=76d092bebada7aca0db7435a2810ce749816a056;hp=f16630579fde5c1d9d62195a06900065e26c6e74;hpb=168c326b585555e4ea6d444ad96a83d880d5c7e3;p=supertux.git diff --git a/src/gameobjs.cpp b/src/gameobjs.cpp index f16630579..39d4eb699 100644 --- a/src/gameobjs.cpp +++ b/src/gameobjs.cpp @@ -1,158 +1,497 @@ -#include "world.h" +// $Id$ +// +// SuperTux +// Copyright (C) 2000 Bill Kendrick +// Copyright (C) 2004 Tobias Glaesser +// +// 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 +#include +#include + +#include "app/globals.h" #include "tile.h" +#include "tile_manager.h" #include "gameloop.h" #include "gameobjs.h" +#include "special/sprite_manager.h" +#include "resources.h" +#include "sector.h" +#include "tilemap.h" +#include "video/drawing_context.h" -void bouncy_distro_init(bouncy_distro_type* pbouncy_distro, float x, float y) +BouncyDistro::BouncyDistro(const Vector& pos) + : position(pos) { - pbouncy_distro->base.x = x; - pbouncy_distro->base.y = y; - pbouncy_distro->base.ym = -2; + ym = -2; } -void bouncy_distro_action(bouncy_distro_type* pbouncy_distro) +void +BouncyDistro::action(float elapsed_time) { - pbouncy_distro->base.y = pbouncy_distro->base.y + pbouncy_distro->base.ym * frame_ratio; + position.y += ym * elapsed_time; - pbouncy_distro->base.ym += 0.1 * frame_ratio; + ym += 0.1 * elapsed_time; // not framerate independent... but who really cares + if(ym >= 0) + remove_me(); +} - if (pbouncy_distro->base.ym >= 0) - world.bouncy_distros.erase(static_cast::iterator>(pbouncy_distro)); +void +BouncyDistro::draw(DrawingContext& context) +{ + context.draw_surface(img_distro[0], position, LAYER_OBJECTS); } -void bouncy_distro_draw(bouncy_distro_type* pbouncy_distro) + +BrokenBrick::BrokenBrick(Tile* ntile,const Vector& pos, const Vector& nmovement) + : tile(ntile), position(pos), movement(nmovement) { - texture_draw(&img_distro[0], - pbouncy_distro->base.x - scroll_x, - pbouncy_distro->base.y); + timer.start(200); } -void broken_brick_init(broken_brick_type* pbroken_brick, Tile* tile, - float x, float y, float xm, float ym) +void +BrokenBrick::action(float elapsed_time) { - pbroken_brick->tile = tile; - pbroken_brick->base.x = x; - pbroken_brick->base.y = y; - pbroken_brick->base.xm = xm; - pbroken_brick->base.ym = ym; + position += movement * elapsed_time; - timer_init(&pbroken_brick->timer, true); - timer_start(&pbroken_brick->timer,200); + if (!timer.check()) + remove_me(); } -void broken_brick_action(broken_brick_type* pbroken_brick) +void +BrokenBrick::draw(DrawingContext& context) { - pbroken_brick->base.x = pbroken_brick->base.x + pbroken_brick->base.xm * frame_ratio; - pbroken_brick->base.y = pbroken_brick->base.y + pbroken_brick->base.ym * frame_ratio; + if (tile->images.size() > 0) + context.draw_surface_part(tile->images[0], + Vector(rand() % 16, rand() % 16), + Vector(16, 16), + position, LAYER_OBJECTS + 1); +} - if (!timer_check(&pbroken_brick->timer)) - world.broken_bricks.erase(static_cast::iterator>(pbroken_brick)); +BouncyBrick::BouncyBrick(const Vector& pos) + : position(pos), offset(0), offset_m(-BOUNCY_BRICK_SPEED), + shape(Sector::current()->solids->get_tile_id_at(pos)) +{ + shape.hidden = true; } -void broken_brick_draw(broken_brick_type* pbroken_brick) +void +BouncyBrick::action(float elapsed_time) { - SDL_Rect src, dest; - src.x = rand() % 16; - src.y = rand() % 16; - src.w = 16; - src.h = 16; + offset += offset_m * elapsed_time; + + /* Go back down? */ + if (offset < -BOUNCY_BRICK_MAX_OFFSET) + offset_m = BOUNCY_BRICK_SPEED; - dest.x = (int)(pbroken_brick->base.x - scroll_x); - dest.y = (int)pbroken_brick->base.y; - dest.w = 16; - dest.h = 16; - - if (pbroken_brick->tile->images.size() > 0) - texture_draw_part(&pbroken_brick->tile->images[0], - src.x,src.y,dest.x,dest.y,dest.w,dest.h); + /* Stop bouncing? */ + if (offset >= 0) + { + shape.hidden = false; + remove_me(); + } } -void bouncy_brick_init(bouncy_brick_type* pbouncy_brick, float x, float y) +void +BouncyBrick::draw(DrawingContext& context) { - pbouncy_brick->base.x = x; - pbouncy_brick->base.y = y; - pbouncy_brick->offset = 0; - pbouncy_brick->offset_m = -BOUNCY_BRICK_SPEED; - pbouncy_brick->shape = GameSession::current()->get_level()->gettileid(x, y); + TileManager::instance()-> + draw_tile(context, shape.id, position + Vector(0, offset), LAYER_TILES+1); } -void bouncy_brick_action(bouncy_brick_type* pbouncy_brick) +FloatingScore::FloatingScore(const Vector& pos, int score) + : position(pos) { + timer.start(1000); + snprintf(str, 10, "%d", score); + position.x -= strlen(str) * 8; +} - pbouncy_brick->offset = (pbouncy_brick->offset + - pbouncy_brick->offset_m * frame_ratio); +void +FloatingScore::action(float elapsed_time) +{ + position.y -= 2 * elapsed_time; - /* Go back down? */ + if(!timer.check()) + remove_me(); +} - if (pbouncy_brick->offset < -BOUNCY_BRICK_MAX_OFFSET) - pbouncy_brick->offset_m = BOUNCY_BRICK_SPEED; +void +FloatingScore::draw(DrawingContext& context) +{ + context.draw_text(gold_text, str, position, LAYER_OBJECTS); +} +/* Trampoline */ - /* Stop bouncing? */ +Sprite *img_trampoline; + +Trampoline::Trampoline(LispReader& reader) +{ + reader.read_float("x", base.x); + reader.read_float("y", base.y); + base.width = 32; + base.height = 32; + power = 7.5; + reader.read_float("power", power); + + frame = 0; + mode = M_NORMAL; + physic.reset(); +} + +Trampoline::Trampoline(float x, float y) +{ + base.x = x; + base.y = y; + base.width = 32; + base.height = 32; + power = 7.5; - if (pbouncy_brick->offset >= 0) - world.bouncy_bricks.erase(static_cast::iterator>(pbouncy_brick)); + frame = 0; + mode = M_NORMAL; + physic.reset(); } -void bouncy_brick_draw(bouncy_brick_type* pbouncy_brick) +void +Trampoline::write(LispWriter& writer) { - int s; - SDL_Rect dest; - - if (pbouncy_brick->base.x >= scroll_x - 32 && - pbouncy_brick->base.x <= scroll_x + screen->w) + writer.start_list("trampoline"); + + writer.write_float("x", base.x); + writer.write_float("y", base.y); + writer.write_float("power", power); + + writer.end_list("trampoline"); +} + +void +Trampoline::draw(DrawingContext& context) +{ + img_trampoline->set_frame(frame); + img_trampoline->draw(context, base, LAYER_OBJECTS); + frame = 0; +} + +void +Trampoline::action(float frame_ratio) +{ + // TODO: Remove if we're too far off the screen + + // Falling + if (mode != M_HELD) + { + if (issolid(base.x + base.width/2, base.y + base.height)) { - dest.x = (int)(pbouncy_brick->base.x - scroll_x); - dest.y = (int)pbouncy_brick->base.y; - dest.w = 32; - dest.h = 32; - - Level* plevel = GameSession::current()->get_level(); - - // FIXME: overdrawing hack to clean the tile from the screen to - // paint it later at on offseted position - if(plevel->bkgd_image[0] == '\0') - { - fillrect(pbouncy_brick->base.x - scroll_x, pbouncy_brick->base.y, - 32,32, - plevel->bkgd_red, plevel->bkgd_green, plevel->bkgd_blue, 0); - } - else - { - s = (int)scroll_x / 30; - texture_draw_part(&plevel->img_bkgd, dest.x + s, dest.y, - dest.x, dest.y,dest.w,dest.h); + base.y = int((base.y + base.height)/32) * 32 - base.height; + + physic.enable_gravity(false); + physic.set_velocity_y(0.0f); + + physic.set_velocity_x(0); + } + else + { + physic.enable_gravity(true); + } + } + else // Player is carrying us around + { + /* FIXME: The trampoline object shouldn't know about pplayer objects. */ + /* If we're holding the iceblock */ + Player& tux = *Sector::current()->player; + Direction dir = tux.dir; + + if(dir == RIGHT) + { + base.x = tux.base.x + 16; + base.y = tux.base.y + tux.base.height/1.5 - base.height; + } + else /* facing left */ + { + base.x = tux.base.x - 16; + base.y = tux.base.y + tux.base.height/1.5 - base.height; + } + + if(collision_object_map(base)) + { + base.x = tux.base.x; + base.y = tux.base.y + tux.base.height/1.5 - base.height; + } + } + + physic.apply(frame_ratio, base.x, base.y, Sector::current()->gravity); + collision_swept_object_map(&old_base, &base); +} + +void +Trampoline::collision(const MovingObject&, int) +{ + // comes later +} + +void +Trampoline::collision(void *p_c_object, int c_object, CollisionType type) +{ + Player* pplayer_c = NULL; + switch (c_object) + { + case CO_PLAYER: + pplayer_c = (Player*) p_c_object; + + if (type == COLLISION_NORMAL) + { + // Pick up if HELD (done in Player) + } + + else if (type == COLLISION_SQUISH) + { + int squish_amount = (32 - (int)pplayer_c->base.y % 32); + + if (squish_amount < 24) + frame = 3; + else if (squish_amount < 28) + frame = 2; + else if (squish_amount < 30) + frame = 1; + else + frame = 0; + + if (squish_amount < 20) { + pplayer_c->physic.set_velocity_y(power); + pplayer_c->fall_mode = Player::TRAMPOLINE_JUMP; } + else if (pplayer_c->physic.get_velocity_y() < 0) + pplayer_c->physic.set_velocity_y(-squish_amount/32); + } + + break; + + default: + break; + + } +} - Tile::draw(pbouncy_brick->base.x - scroll_x, - pbouncy_brick->base.y + pbouncy_brick->offset, - pbouncy_brick->shape); +/* Flying Platform */ + +Sprite *img_flying_platform; + +FlyingPlatform::FlyingPlatform(LispReader& reader) +{ + reader.read_int_vector("x", pos_x); + reader.read_int_vector("y", pos_y); + + velocity = 2.0; + reader.read_float("velocity", velocity); + + base.x = pos_x[0]; + base.y = pos_y[0]; + base.width = 96; + base.height = 40; + + point = 0; + move = false; + + float x = pos_x[point+1] - pos_x[point]; + float y = pos_y[point+1] - pos_y[point]; + vel_x = x*velocity / sqrt(x*x + y*y); + vel_y = -(velocity - vel_x); + + frame = 0; +} + +FlyingPlatform::FlyingPlatform(int x, int y) +{ +base.x = x; +base.y = y; +point = 0; +move = false; +} + +void +FlyingPlatform::write(LispWriter& writer) +{ + writer.start_list("flying-trampoline"); + + writer.write_int_vector("x", pos_x); + writer.write_int_vector("y", pos_y); + writer.write_float("velocity", velocity); + + writer.end_list("flying-trampoline"); +} + +void +FlyingPlatform::draw(DrawingContext& context) +{ + img_flying_platform->draw(context, base, LAYER_OBJECTS); +} + +void +FlyingPlatform::action(float frame_ratio) +{ + // TODO: Remove if we're too far off the screen + +if(!move) + return; + +if((unsigned)point+1 != pos_x.size()) + { + if(((pos_x[point+1] > pos_x[point] && base.x >= pos_x[point+1]) || + (pos_x[point+1] < pos_x[point] && base.x <= pos_x[point+1]) || + pos_x[point] == pos_x[point+1]) && + ((pos_y[point+1] > pos_y[point] && base.y >= pos_y[point+1]) || + (pos_y[point+1] < pos_y[point] && base.y <= pos_y[point+1]) || + pos_y[point] == pos_y[point+1])) + { + point++; + + float x = pos_x[point+1] - pos_x[point]; + float y = pos_y[point+1] - pos_y[point]; + vel_x = x*velocity / sqrt(x*x + y*y); + vel_y = -(velocity - vel_x); } + } +else // last point + { + // point = 0; + // reverse vector + return; + } +/* +if(pos_x[point+1] > base.x) + base.x += velocity * frame_ratio; +else if(pos_x[point+1] < base.x) + base.x -= velocity * frame_ratio; + +if(pos_y[point+1] > base.y) + base.y += velocity * frame_ratio; +else if(pos_y[point+1] < base.y) + base.y -= velocity * frame_ratio; +*/ + +base.x += vel_x * frame_ratio; +base.y += vel_y * frame_ratio; } -void floating_score_init(floating_score_type* pfloating_score, float x, float y, int s) +void +FlyingPlatform::collision(const MovingObject&, int) { - pfloating_score->base.x = x; - pfloating_score->base.y = y - 16; - timer_init(&pfloating_score->timer,true); - timer_start(&pfloating_score->timer,1000); - pfloating_score->value = s; + // comes later } -void floating_score_action(floating_score_type* pfloating_score) +void +FlyingPlatform::collision(void *p_c_object, int c_object, CollisionType type) { - pfloating_score->base.y = pfloating_score->base.y - 2 * frame_ratio; +(void) p_c_object; +(void) type; - if(!timer_check(&pfloating_score->timer)) - world.floating_scores.erase(static_cast::iterator>(pfloating_score)); +// Player* pplayer_c = NULL; + switch (c_object) + { + case CO_PLAYER: +// pplayer_c = (Player*) p_c_object; + move = true; + + break; + + default: + break; + + } } -void floating_score_draw(floating_score_type* pfloating_score) +Sprite *img_smoke_cloud; + +SmokeCloud::SmokeCloud(const Vector& pos) + : position(pos) { - char str[10]; - sprintf(str, "%d", pfloating_score->value); - text_draw(&gold_text, str, (int)pfloating_score->base.x + 16 - strlen(str) * 8, (int)pfloating_score->base.y, 1); + timer.start(300); } -/* EOF */ +void +SmokeCloud::action(float elapsed_time) +{ + position.y -= 1.2 * elapsed_time; + + if(!timer.check()) + remove_me(); +} + +void +SmokeCloud::draw(DrawingContext& context) +{ + img_smoke_cloud->draw(context, position, LAYER_OBJECTS+1); +} + +Particles::Particles(const Vector& epicenter, const Vector& velocity, const Vector& acceleration, int number, Color color_, int size_, int life_time) + : color(color_), size(size_), vel(velocity), accel(acceleration) +{ + timer.start(life_time); + + // create particles + for(int p = 0; p < number; p++) + { + Particle* particle = new Particle; + particle->pos = epicenter; + particle->angle = (rand() % 360) * (M_PI / 180); // in radius + + particles.push_back(particle); + } +} + +Particles::~Particles() +{ + // free particles + for(std::vector::iterator i = particles.begin(); i < particles.end(); i++) + delete (*i); +} + +void +Particles::action(float elapsed_time) +{ + vel.x += accel.x * elapsed_time; + vel.y += accel.y * elapsed_time; + + // update particles + for(int p = 0; p < particles.size(); p++) + { + particles[p]->pos.x += sin(particles[p]->angle) * vel.x * elapsed_time; + particles[p]->pos.y += cos(particles[p]->angle) * vel.y * elapsed_time; + } + + if(!timer.check()) + remove_me(); +} +void +Particles::draw(DrawingContext& context) +{ + // draw particles + for(int p = 0; p < particles.size(); p++) + { + context.draw_filled_rect(particles[p]->pos, Vector(size,size), color, LAYER_OBJECTS+10); + } +} + +void load_object_gfx() +{ + img_trampoline = sprite_manager->load("trampoline"); + img_trampoline->start_animation(0); + img_flying_platform = sprite_manager->load("flying_platform"); + img_smoke_cloud = sprite_manager->load("stomp"); +}