--- /dev/null
+(supertux-sprite
+ (action
+ (name "walking-left")
+ (images "walking1.png" "walking2.png" "walking3.png" "walking4.png")
+ )
+ (action
+ (name "walking-right")
+ (mirror-action "walking-left")
+ )
+ (action
+ (name "stacked-left")
+ (images "stacked.png")
+ )
+ (action
+ (name "stacked-right")
+ (mirror-action "stacked-left")
+ )
+ (action
+ (name "squished-left")
+ (images "squished.png")
+ )
+ (action
+ (name "squished-right")
+ (mirror-action "squished-left")
+ )
+
+ )
--- /dev/null
+;; Generated by Flexlay Editor
+(supertux-level
+ (version 2)
+ (name (_ "Totem Test"))
+ (author "Marek")
+ (sector
+ (name "main")
+ (gravity 10.000000)
+ (tilemap
+ (layer "background")
+ (solid #f)
+ (speed 1.000000)
+ (width 30)
+ (height 30)
+ (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 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ ))
+ (tilemap
+ (layer "interactive")
+ (solid #t)
+ (speed 1.000000)
+ (width 30)
+ (height 30)
+ (tiles
+ 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 61 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 61
+ 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
+ ))
+ (tilemap
+ (layer "foreground")
+ (solid #f)
+ (speed 1.000000)
+ (width 30)
+ (height 30)
+ (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 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+ ))
+ (camera
+ (mode "normal")
+ )
+
+ (background
+ (image "images/background/arctis.jpg")
+ (speed 0.500000)
+ )
+
+ (totem (x 100) (y 850))
+ (totem (x 700) (y 850))
+ (totem (x 800) (y 850))
+ (totem (x 900) (y 850))
+ (powerup (x 100) (y 700) (sprite "images/powerups/egg/egg.sprite"))
+ (spawnpoint (name "main") (x 40) (y 700))
+ )
+ )
+
+;; EOF ;;
--- /dev/null
+// $Id: totem.cpp 3096 2006-03-17 12:03:02Z sommer $
+//
+// SuperTux - "Totem" Badguy
+// Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+// 02111-1307, USA.
+
+#include <config.h>
+
+#include "totem.hpp"
+#include "msg.hpp"
+
+static const float WALKSPEED = 100;
+static const float WALKSPEED_SMALL = 120;
+static const float INVINCIBLE_TIME = 1;
+
+static const float JUMP_OFF_SPEED_Y = 500;
+
+Totem::Totem(const lisp::Lisp& reader)
+{
+ stay_on_platform = false;
+ carrying = 0;
+ carried_by = 0;
+ bbox.set_size(48, 49);
+
+ reader.get("x", start_position.x);
+ reader.get("y", start_position.y);
+ reader.get("stay-on-platform", stay_on_platform);
+ sprite = sprite_manager->create("images/creatures/totem/totem.sprite");
+}
+
+Totem::~Totem()
+{
+ if (carrying) carrying->jump_off();
+ if (carried_by) jump_off();
+}
+
+void
+Totem::write(lisp::Writer& writer)
+{
+ writer.start_list("totem");
+
+ writer.write_float("x", start_position.x);
+ writer.write_float("y", start_position.y);
+ writer.write_bool("stay-on-platform", stay_on_platform);
+
+ writer.end_list("totem");
+}
+
+void
+Totem::activate()
+{
+ if (!carried_by) {
+ physic.set_velocity_x(dir == LEFT ? -WALKSPEED : WALKSPEED);
+ sprite->set_action(dir == LEFT ? "walking-left" : "walking-right");
+ return;
+ } else {
+ synchronize_with(carried_by);
+ sprite->set_action(dir == LEFT ? "stacked-left" : "stacked-right");
+ return;
+ }
+}
+
+void
+Totem::active_update(float elapsed_time)
+{
+ BadGuy::active_update(elapsed_time);
+
+ if (!carried_by) {
+ if (stay_on_platform && may_fall_off_platform())
+ {
+ dir = (dir == LEFT ? RIGHT : LEFT);
+ activate();
+ }
+ }
+
+ if (carried_by) {
+ this->synchronize_with(carried_by);
+ }
+
+ if (carrying) {
+ carrying->synchronize_with(this);
+ }
+
+}
+
+bool
+Totem::collision_squished(Player& player)
+{
+ if (carrying) carrying->jump_off();
+ if (carried_by) {
+ player.bounce(*this);
+ jump_off();
+ }
+
+ sprite->set_action(dir == LEFT ? "squished-left" : "squished-right");
+ this->bbox.set_size(48, 45);
+ kill_squished(player);
+ return true;
+}
+
+HitResponse
+Totem::collision_solid(GameObject& object, const CollisionHit& hit)
+{
+ // if we are being carried around, pass event to bottom of stack and ignore it
+ if (carried_by) {
+ carried_by->collision_solid(object, hit);
+ return CONTINUE;
+ }
+
+ // If we hit something from above or below: stop moving in this direction
+ if (hit.normal.y != 0) {
+ physic.set_velocity_y(0);
+ }
+
+ // If we are hit from the direction we are facing: turn around
+ if ((hit.normal.x > .8) && (dir == LEFT)) {
+ dir = RIGHT;
+ activate();
+ }
+ if ((hit.normal.x < -.8) && (dir == RIGHT)) {
+ dir = LEFT;
+ activate();
+ }
+
+ return CONTINUE;
+}
+
+HitResponse
+Totem::collision_badguy(BadGuy& badguy, const CollisionHit& hit)
+{
+ // if we are being carried around, pass event to bottom of stack and ignore it
+ if (carried_by) {
+ carried_by->collision_badguy(badguy, hit);
+ return CONTINUE;
+ }
+
+ // if we hit a Totem that is not from our stack: have our base jump on its top
+ Totem* totem = dynamic_cast<Totem*>(&badguy);
+ if (totem) {
+ Totem* thisBase = this; while (thisBase->carried_by) thisBase=thisBase->carried_by;
+ Totem* srcBase = totem; while (srcBase->carried_by) srcBase=srcBase->carried_by;
+ Totem* thisTop = this; while (thisTop->carrying) thisTop=thisTop->carrying;
+ if (srcBase != thisBase) {
+ srcBase->jump_on(thisTop);
+ }
+ }
+
+ // If we are hit from the direction we are facing: turn around
+ if ((hit.normal.x > .8) && (dir == LEFT)) {
+ dir = RIGHT;
+ activate();
+ }
+ if ((hit.normal.x < -.8) && (dir == RIGHT)) {
+ dir = LEFT;
+ activate();
+ }
+
+ return CONTINUE;
+}
+
+void
+Totem::kill_fall()
+{
+ if (carrying) carrying->jump_off();
+ if (carried_by) jump_off();
+
+ BadGuy::kill_fall();
+}
+
+void
+Totem::jump_on(Totem* target)
+{
+ if (target->carrying) {
+ msg_warning("target is already carrying someone");
+ return;
+ }
+
+ target->carrying = this;
+
+ this->carried_by = target;
+ this->bbox.set_size(48, 45);
+ this->activate();
+
+ this->synchronize_with(target);
+}
+
+void
+Totem::jump_off() {
+ if (!carried_by) {
+ msg_warning("not carried by anyone");
+ return;
+ }
+
+ carried_by->carrying = 0;
+
+ this->carried_by = 0;
+ this->bbox.set_size(48, 49);
+
+ this->activate();
+
+ physic.set_velocity_y(JUMP_OFF_SPEED_Y);
+}
+
+void
+Totem::synchronize_with(Totem* base)
+{
+
+ if (dir != base->dir) {
+ dir = base->dir;
+ sprite->set_action(dir == LEFT ? "stacked-left" : "stacked-right");
+ }
+
+ Vector pos = base->get_pos();
+ pos.y -= 45;
+ set_pos(pos);
+
+ physic.set_velocity_x(base->physic.get_velocity_x());
+ physic.set_velocity_y(base->physic.get_velocity_y());
+}
+
+
+IMPLEMENT_FACTORY(Totem, "totem")
+
--- /dev/null
+// $Id: totem.cpp 3096 2006-03-17 12:03:02Z sommer $
+//
+// SuperTux - "Totem" Badguy
+// Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.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 __TOTEM_H__
+#define __TOTEM_H__
+
+#include "badguy.hpp"
+
+/**
+ * "Totem" Badguy - A variable-height stack of wooden blocks
+ */
+class Totem : public BadGuy
+{
+public:
+ Totem(const lisp::Lisp& reader);
+ ~Totem();
+
+ void activate();
+ void active_update(float elapsed_time);
+ void write(lisp::Writer& writer);
+ HitResponse collision_solid(GameObject& other, const CollisionHit& hit);
+ HitResponse collision_badguy(BadGuy& badguy, const CollisionHit& hit);
+
+protected:
+ bool stay_on_platform; /**< change direction before falling off a ledge */
+
+ Totem* carrying; /**< Totem we are currently carrying (or 0) */
+ Totem* carried_by; /**< Totem by which we are currently carried (or 0) */
+
+ bool collision_squished(Player& player);
+ void kill_fall();
+
+ void jump_on(Totem* target); /**< jump on target */
+ void jump_off(); /**< jump off current base */
+
+ void synchronize_with(Totem* baseTotem); /**< synchronize position and movement with baseTotem */
+};
+
+#endif
+