From: Christoph Sommer Date: Sat, 26 May 2007 20:37:50 +0000 (+0000) Subject: GhostTree can now be killed X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=381dd34488c553c853f4e466f61fb9afb9414761;p=supertux.git GhostTree can now be killed SVN-Revision: 5040 --- diff --git a/data/images/creatures/ghosttree/ghosttree-swallow-0.png b/data/images/creatures/ghosttree/ghosttree-swallow-0.png new file mode 100644 index 000000000..ef5a4f0da Binary files /dev/null and b/data/images/creatures/ghosttree/ghosttree-swallow-0.png differ diff --git a/data/images/creatures/ghosttree/ghosttree-swallow-1.png b/data/images/creatures/ghosttree/ghosttree-swallow-1.png new file mode 100644 index 000000000..e96501e6b Binary files /dev/null and b/data/images/creatures/ghosttree/ghosttree-swallow-1.png differ diff --git a/data/images/creatures/ghosttree/ghosttree-swallow-2.png b/data/images/creatures/ghosttree/ghosttree-swallow-2.png new file mode 100644 index 000000000..e454edca4 Binary files /dev/null and b/data/images/creatures/ghosttree/ghosttree-swallow-2.png differ diff --git a/data/images/creatures/ghosttree/ghosttree-swallow-3.png b/data/images/creatures/ghosttree/ghosttree-swallow-3.png new file mode 100644 index 000000000..b6d661c73 Binary files /dev/null and b/data/images/creatures/ghosttree/ghosttree-swallow-3.png differ diff --git a/data/images/creatures/ghosttree/ghosttree.sprite b/data/images/creatures/ghosttree/ghosttree.sprite index fc57556b4..d1dd9a826 100644 --- a/data/images/creatures/ghosttree/ghosttree.sprite +++ b/data/images/creatures/ghosttree/ghosttree.sprite @@ -1,12 +1,25 @@ (supertux-sprite (action (name "default") + (hitbox 230 300 40 60) (images "ghosttree.png" ) ) (action + (name "swallow") + (hitbox 230 300 40 60) + (fps 16) + (images + "ghosttree-swallow-0.png" + "ghosttree-swallow-1.png" + "ghosttree-swallow-2.png" + "ghosttree-swallow-3.png" + ) + ) + (action (name "dying") + (hitbox 230 300 40 60) (fps 4) (images "ghosttree-dying-0.png" diff --git a/data/levels/test/treeboss.stl b/data/levels/test/treeboss.stl index c5a619389..49f12076b 100644 --- a/data/levels/test/treeboss.stl +++ b/data/levels/test/treeboss.stl @@ -226,13 +226,8 @@ ) ) (ghosttree - (x 500) - (y 250) - ) - (lantern - (x 540) - (y 448) - (color 0 0 0) + (x 730) + (y 550) ) (lantern (x 540) @@ -240,12 +235,12 @@ (color 0 0 0) ) (lantern - (x 540) + (x 940) (y 248) (color 0 0 0) ) (lantern - (x 540) + (x 1040) (y 148) (color 0 0 0) ) diff --git a/src/badguy/ghosttree.cpp b/src/badguy/ghosttree.cpp index b916b577a..973afa86b 100644 --- a/src/badguy/ghosttree.cpp +++ b/src/badguy/ghosttree.cpp @@ -23,17 +23,19 @@ #include "sprite/sprite_manager.hpp" #include "root.hpp" #include "random_generator.hpp" +#include "object/lantern.hpp" static const size_t WILLOWISP_COUNT = 10; -static const float ROOT_TOP_OFFSET = -64; -static const Vector SUCK_TARGET_OFFSET = Vector(-32,72); -static const float SUCK_TARGET_SPREAD = 16; +static const float ROOT_TOP_OFFSET = 64; +static const float WILLOWISP_TOP_OFFSET = -64; +static const Vector SUCK_TARGET_OFFSET = Vector(-16,-16); +static const float SUCK_TARGET_SPREAD = 8; GhostTree::GhostTree(const lisp::Lisp& lisp) : BadGuy(lisp, "images/creatures/ghosttree/ghosttree.sprite", - LAYER_OBJECTS - 10), + LAYER_OBJECTS - 10), mystate(STATE_IDLE), willo_spawn_y(0), willo_radius(200), willo_speed(1.8f), willo_color(0), - treecolor(0) + treecolor(0), suck_lantern(0) { glow_sprite.reset(sprite_manager->create("images/creatures/ghosttree/ghosttree-glow.sprite")); } @@ -45,6 +47,7 @@ GhostTree::~GhostTree() void GhostTree::die() { + mystate = STATE_DYING; sprite->set_action("dying", 1); glow_sprite->set_action("dying", 1); @@ -61,7 +64,7 @@ GhostTree::activate() willowisp_timer.start(1.0f, true); colorchange_timer.start(13, true); root_timer.start(5, true); - set_group(COLGROUP_DISABLED); + set_group(COLGROUP_TOUCHABLE); } void @@ -69,86 +72,128 @@ GhostTree::active_update(float elapsed_time) { (void) elapsed_time; - if(colorchange_timer.check()) { - sound_manager->play("sounds/tree_howling.ogg", get_pos()); - suck_timer.start(3); - treecolor = (treecolor + 1) % 3; - - Color col; - switch(treecolor) { - case 0: col = Color(1, 0, 0); break; - case 1: col = Color(0, 1, 0); break; - case 2: col = Color(0, 0, 1); break; - case 3: col = Color(1, 1, 0); break; - case 4: col = Color(1, 0, 1); break; - case 5: col = Color(0, 1, 1); break; - default: assert(false); + if (mystate == STATE_IDLE) { + if(colorchange_timer.check()) { + sound_manager->play("sounds/tree_howling.ogg", get_pos()); + suck_timer.start(3); + treecolor = (treecolor + 1) % 3; + + Color col; + switch(treecolor) { + case 0: col = Color(1, 0, 0); break; + case 1: col = Color(0, 1, 0); break; + case 2: col = Color(0, 0, 1); break; + case 3: col = Color(1, 1, 0); break; + case 4: col = Color(1, 0, 1); break; + case 5: col = Color(0, 1, 1); break; + default: assert(false); + } + glow_sprite->set_color(col); } - glow_sprite->set_color(col); - } - if(suck_timer.check()) { - Color col = glow_sprite->get_color(); - sound_manager->play("sounds/tree_suck.ogg", get_pos()); - std::vector::iterator iter; - for(iter = willowisps.begin(); iter != willowisps.end(); ++iter) { - TreeWillOWisp *willo = *iter; - if(willo->get_color() == col) { - willo->start_sucking(get_bbox().get_middle() + SUCK_TARGET_OFFSET + Vector(systemRandom.randf(-SUCK_TARGET_SPREAD, SUCK_TARGET_SPREAD), systemRandom.randf(-SUCK_TARGET_SPREAD, SUCK_TARGET_SPREAD))); + if(suck_timer.check()) { + Color col = glow_sprite->get_color(); + sound_manager->play("sounds/tree_suck.ogg", get_pos()); + std::vector::iterator iter; + for(iter = willowisps.begin(); iter != willowisps.end(); ++iter) { + TreeWillOWisp *willo = *iter; + if(willo->get_color() == col) { + willo->start_sucking(get_bbox().get_middle() + SUCK_TARGET_OFFSET + Vector(systemRandom.randf(-SUCK_TARGET_SPREAD, SUCK_TARGET_SPREAD), systemRandom.randf(-SUCK_TARGET_SPREAD, SUCK_TARGET_SPREAD))); + } } + mystate = STATE_SUCKING; } - } - - if(willowisp_timer.check()) { - if(willowisps.size() < WILLOWISP_COUNT) { - Vector pos = Vector(bbox.get_width() / 2, bbox.get_height() / 2 + willo_spawn_y); - TreeWillOWisp *willowisp - = new TreeWillOWisp(this, pos, 200 + willo_radius, willo_speed); - Sector::current()->add_object(willowisp); - willowisps.push_back(willowisp); - - willo_spawn_y -= 40; - if(willo_spawn_y < -160) - willo_spawn_y = 0; - - willo_radius += 20; - if(willo_radius > 120) - willo_radius = 0; + if(willowisp_timer.check()) { + if(willowisps.size() < WILLOWISP_COUNT) { + Vector pos = Vector(bbox.get_width() / 2, bbox.get_height() / 2 + willo_spawn_y + WILLOWISP_TOP_OFFSET); + TreeWillOWisp *willowisp + = new TreeWillOWisp(this, pos, 200 + willo_radius, willo_speed); + + Sector::current()->add_object(willowisp); + willowisps.push_back(willowisp); + + willo_spawn_y -= 40; + if(willo_spawn_y < -160) + willo_spawn_y = 0; + + willo_radius += 20; + if(willo_radius > 120) + willo_radius = 0; + + if(willo_speed == 1.8f) { + willo_speed = 1.5f; + } else { + willo_speed = 1.8f; + } + + do { + willo_color = (willo_color + 1) % 3; + } while(willo_color == treecolor); + + switch(willo_color) { + case 0: willowisp->set_color(Color(1, 0, 0)); break; + case 1: willowisp->set_color(Color(0, 1, 0)); break; + case 2: willowisp->set_color(Color(0, 0, 1)); break; + case 3: willowisp->set_color(Color(1, 1, 0)); break; + case 4: willowisp->set_color(Color(1, 0, 1)); break; + case 5: willowisp->set_color(Color(0, 1, 1)); break; + default: assert(false); + } + } + } - if(willo_speed == 1.8f) { - willo_speed = 1.5f; + if(root_timer.check()) { + /* TODO indicate root with an animation */ + Player* player = get_nearest_player(); + Root* root = new Root(Vector(player->get_bbox().get_left(), get_bbox().get_bottom()+ROOT_TOP_OFFSET)); + Sector::current()->add_object(root); + } + } else if (mystate == STATE_SWALLOWING) { + if (suck_lantern) { + // suck in lantern + assert (suck_lantern); + Vector pos = suck_lantern->get_pos(); + Vector delta = get_bbox().get_middle() + SUCK_TARGET_OFFSET - pos; + Vector dir = delta.unit(); + if (delta.norm() < 1) { + dir = delta; + suck_lantern->ungrab(*this, RIGHT); + suck_lantern->remove_me(); + suck_lantern = 0; + sprite->set_action("swallow", 1); } else { - willo_speed = 1.8f; + pos += dir; + suck_lantern->grab(*this, pos, RIGHT); } - - do { - willo_color = (willo_color + 1) % 3; - } while(willo_color == treecolor); - - switch(willo_color) { - case 0: willowisp->set_color(Color(1, 0, 0)); break; - case 1: willowisp->set_color(Color(0, 1, 0)); break; - case 2: willowisp->set_color(Color(0, 0, 1)); break; - case 3: willowisp->set_color(Color(1, 1, 0)); break; - case 4: willowisp->set_color(Color(1, 0, 1)); break; - case 5: willowisp->set_color(Color(0, 1, 1)); break; - default: assert(false); + } else { + // wait until lantern is swallowed + if (sprite->animation_done()) { + if (is_color_deadly(suck_lantern_color)) { + die(); + } else { + sprite->set_action("default"); + mystate = STATE_IDLE; + spawn_lantern(); + } } } } +} - if(root_timer.check()) { - /* TODO indicate root with an animation */ - Player* player = get_nearest_player(); - Root* root = new Root(Vector(player->get_bbox().get_left(), get_bbox().get_bottom()+ROOT_TOP_OFFSET)); - Sector::current()->add_object(root); - } +bool +GhostTree::is_color_deadly(Color color) const { + if (color == Color(0,0,0)) return false; + Color my_color = glow_sprite->get_color(); + return ((my_color.red != color.red) || (my_color.green != color.green) || (my_color.blue != color.blue)); } void GhostTree::willowisp_died(TreeWillOWisp *willowisp) { + if ((mystate == STATE_SUCKING) && (willowisp->was_sucked)) { + mystate = STATE_IDLE; + } willowisps.erase(std::find(willowisps.begin(), willowisps.end(), willowisp)); } @@ -158,11 +203,51 @@ GhostTree::draw(DrawingContext& context) BadGuy::draw(context); context.push_target(); + context.push_transform(); context.set_target(DrawingContext::LIGHTMAP); + if (mystate == STATE_SUCKING) { + context.set_alpha(0.5 + fmodf(game_time, 0.5)); + } else { + context.set_alpha(0.5); + } glow_sprite->draw(context, get_pos(), layer); + context.pop_transform(); context.pop_target(); } +bool +GhostTree::collides(GameObject& other, const CollisionHit& ) { + if (mystate != STATE_SUCKING) return false; + if (dynamic_cast(&other)) return true; + if (dynamic_cast(&other)) return true; + return false; +} + +HitResponse +GhostTree::collision(GameObject& other, const CollisionHit& ) { + if(mystate != STATE_SUCKING) return ABORT_MOVE; + + Player* player = dynamic_cast(&other); + if (player) { + player->kill(false); + } + + Lantern* lantern = dynamic_cast(&other); + if (lantern) { + suck_lantern = lantern; + suck_lantern->grab(*this, suck_lantern->get_pos(), RIGHT); + suck_lantern_color = lantern->get_color(); + mystate = STATE_SWALLOWING; + } + + return ABORT_MOVE; +} + +void +GhostTree::spawn_lantern() { + Lantern* lantern = new Lantern(get_bbox().get_middle() + SUCK_TARGET_OFFSET); + Sector::current()->add_object(lantern); +} IMPLEMENT_FACTORY(GhostTree, "ghosttree"); diff --git a/src/badguy/ghosttree.hpp b/src/badguy/ghosttree.hpp index c17792bb2..7e57d5c19 100644 --- a/src/badguy/ghosttree.hpp +++ b/src/badguy/ghosttree.hpp @@ -23,6 +23,7 @@ #include "badguy.hpp" class TreeWillOWisp; +class Lantern; class GhostTree : public BadGuy { @@ -30,14 +31,25 @@ public: GhostTree(const lisp::Lisp& lisp); ~GhostTree(); + virtual bool is_flammable() const { return false; } + virtual bool is_freezable() const { return false; } + virtual void kill_fall() { } + void activate(); void active_update(float elapsed_time); void willowisp_died(TreeWillOWisp* willowisp); virtual void draw(DrawingContext& context); + virtual bool collides(GameObject& other, const CollisionHit& hit); + virtual HitResponse collision(GameObject& other, const CollisionHit& hit); + void die(); private: + enum MyState { + STATE_IDLE, STATE_SUCKING, STATE_SWALLOWING, STATE_DYING + }; + MyState mystate; Timer willowisp_timer; float willo_spawn_y; float willo_radius; @@ -49,8 +61,14 @@ private: Timer suck_timer; Timer root_timer; int treecolor; + Color suck_lantern_color; + + Lantern* suck_lantern; /**< Lantern that is currently being sucked in */ std::vector willowisps; + + bool is_color_deadly(Color color) const; + void spawn_lantern(); }; #endif diff --git a/src/badguy/treewillowisp.cpp b/src/badguy/treewillowisp.cpp index 36d798e78..db417a6af 100644 --- a/src/badguy/treewillowisp.cpp +++ b/src/badguy/treewillowisp.cpp @@ -29,7 +29,7 @@ static const float SUCKSPEED = 25; TreeWillOWisp::TreeWillOWisp(GhostTree* tree, const Vector& pos, float radius, float speed) : BadGuy(Vector(0, 0), "images/creatures/willowisp/willowisp.sprite", - LAYER_OBJECTS - 20), mystate(STATE_DEFAULT), tree(tree) + LAYER_OBJECTS - 20), was_sucked(false), mystate(STATE_DEFAULT), tree(tree) { treepos_delta = pos; sound_manager->preload(SOUNDFILE); @@ -70,6 +70,7 @@ TreeWillOWisp::start_sucking(Vector suck_target) { mystate = STATE_SUCKED; this->suck_target = suck_target; + was_sucked = true; } HitResponse diff --git a/src/badguy/treewillowisp.hpp b/src/badguy/treewillowisp.hpp index 60fac85ba..9cea6714c 100644 --- a/src/badguy/treewillowisp.hpp +++ b/src/badguy/treewillowisp.hpp @@ -38,6 +38,7 @@ public: */ void vanish(); void start_sucking(Vector suck_target); + bool was_sucked; void active_update(float elapsed_time); void set_color(const Color& color); diff --git a/src/object/lantern.cpp b/src/object/lantern.cpp index 531ad9599..8812e4bf0 100644 --- a/src/object/lantern.cpp +++ b/src/object/lantern.cpp @@ -39,6 +39,16 @@ Lantern::Lantern(const lisp::Lisp& reader) sound_manager->preload("sounds/willocatch.wav"); } +Lantern::Lantern(const Vector& pos) + : Rock(pos, "images/objects/lantern/lantern.sprite"), + lightcolor(0.0f, 0.0f, 0.0f) +{ + lightsprite = sprite_manager->create("images/objects/lightmap_light/lightmap_light.sprite"); + lightsprite->set_blend(Blend(GL_SRC_ALPHA, GL_ONE)); + updateColor(); + sound_manager->preload("sounds/willocatch.wav"); +} + Lantern::~Lantern() { delete lightsprite; diff --git a/src/object/lantern.hpp b/src/object/lantern.hpp index a41e3869f..b8498a3db 100644 --- a/src/object/lantern.hpp +++ b/src/object/lantern.hpp @@ -29,6 +29,7 @@ class Lantern : public Rock { public: + Lantern(const Vector& pos); Lantern(const lisp::Lisp& reader); void draw(DrawingContext& context); ~Lantern(); @@ -43,6 +44,13 @@ public: */ bool is_open(); + /** + * returns the lamp's color + */ + Color get_color() const { + return lightcolor; + } + private: Color lightcolor; Sprite* lightsprite; diff --git a/src/object/rock.cpp b/src/object/rock.cpp index e1421f2ce..255a4e6de 100644 --- a/src/object/rock.cpp +++ b/src/object/rock.cpp @@ -29,6 +29,15 @@ namespace { const std::string ROCK_SOUND = "sounds/brick.wav"; //TODO use own sound. } +Rock::Rock(const Vector& pos, std::string spritename) + : MovingSprite(pos, spritename) +{ + sound_manager->preload(ROCK_SOUND); + on_ground = false; + grabbed = false; + set_group(COLGROUP_MOVING_STATIC); +} + Rock::Rock(const lisp::Lisp& reader) : MovingSprite(reader, "images/objects/rock/rock.sprite") { diff --git a/src/object/rock.hpp b/src/object/rock.hpp index 099d7cace..86a8e0e1b 100644 --- a/src/object/rock.hpp +++ b/src/object/rock.hpp @@ -31,6 +31,7 @@ class Sprite; class Rock : public MovingSprite, public Portable, protected UsesPhysic, public Serializable { public: + Rock(const Vector& pos, std::string spritename); Rock(const lisp::Lisp& reader); Rock(const lisp::Lisp& reader, std::string spritename); virtual Rock* clone() const { return new Rock(*this); }