new sounds
massive improvements to localization
efficiency tweaks
+move to SDL2
+menus reworked
+addon manager improved
+new tilemap- halloween
Supertux Release 0.3.4 (2013-07)
--------------------------------
-It's been more than three years since the last development snapshot for
-Milestone 2 of SuperTux, making this a bit overdue. Once again it is hard to
-say what the most notable changes are, but one thing players should notice is
+It's been more than three years since the last development snapshot for
+Milestone 2 of SuperTux, making this a bit overdue. Once again it is hard to
+say what the most notable changes are, but one thing players should notice is
a greater wealth of levels to play through an expanded avalibility of add-ons.
Additionally, SuperTux development has moved to Google Code. Check it out at:
http://code.google.com/p/supertux/
-If you are intersted in contribuiting to SuperTux, please do so. The more
-people working on the project, the faster development can continue. The hope
-is that this release will generate more interest which will lead to more
-frequent releases. You can refer to the wiki page on "Contributing" to get
+If you are intersted in contribuiting to SuperTux, please do so. The more
+people working on the project, the faster development can continue. The hope
+is that this release will generate more interest which will lead to more
+frequent releases. You can refer to the wiki page on "Contributing" to get
started:
http://supertux.lethargik.org/wiki/Contributing
* final boss for Icy Island
* brand new Forest World with new badguys and new game objects
* new and improved soundtrack, immersive sound effects
- * much more...
+ * much more...
The changes in more detail: The SuperTux 0.1 engine was nearly
completely rewritten. The game is translatable now, a new camera
algorithm allows scrolling in all four directions. Collision
-detection supports slopes and moving objects now. We have scripting
+detection supports slopes and moving objects now. We have scripting
support for dynamic level events and animations. New game objects
include trampolines, switches, portable stones, upside-down
levels, wind, moving platforms and particle effects. The sound
case 12: contents = CONTENT_CUSTOM;
object = std::make_shared<PowerUp>(get_pos(), "images/powerups/potions/red-potion.sprite");
break;
+ case 13: contents = CONTENT_AIRGROW; break;
+ case 14: contents = CONTENT_EARTHGROW; break;
default:
log_warning << "Invalid box contents" << std::endl;
contents = CONTENT_COIN;
contents = CONTENT_FIREGROW;
} else if(contentstring == "icegrow") {
contents = CONTENT_ICEGROW;
+ } else if(contentstring == "airgrow") {
+ contents = CONTENT_AIRGROW;
+ } else if(contentstring == "earthgrow") {
+ contents = CONTENT_EARTHGROW;
} else if(contentstring == "star") {
contents = CONTENT_STAR;
} else if(contentstring == "1up") {
break;
}
+ case CONTENT_AIRGROW:
+ {
+ if(player->get_status()->bonus == NO_BONUS) {
+ auto riser = std::make_shared<SpecialRiser>(get_pos(), std::make_shared<GrowUp>(direction));
+ sector->add_object(riser);
+ } else {
+ auto riser = std::make_shared<SpecialRiser>(
+ get_pos(), std::make_shared<Flower>(AIR_BONUS));
+ sector->add_object(riser);
+ }
+ SoundManager::current()->play("sounds/upgrade.wav");
+ break;
+ }
+
+ case CONTENT_EARTHGROW:
+ {
+ if(player->get_status()->bonus == NO_BONUS) {
+ auto riser = std::make_shared<SpecialRiser>(get_pos(), std::make_shared<GrowUp>(direction));
+ sector->add_object(riser);
+ } else {
+ auto riser = std::make_shared<SpecialRiser>(
+ get_pos(), std::make_shared<Flower>(EARTH_BONUS));
+ sector->add_object(riser);
+ }
+ SoundManager::current()->play("sounds/upgrade.wav");
+ break;
+ }
+
case CONTENT_STAR:
{
sector->add_object(std::make_shared<Star>(get_pos() + Vector(0, -32), direction));
break;
}
+ case CONTENT_AIRGROW:
+ {
+ sector->add_object(std::make_shared<PowerUp>(get_pos() + Vector(0, 32), "images/powerups/iceflower/iceflower.sprite"));
+ SoundManager::current()->play("sounds/upgrade.wav");
+ countdown = true;
+ break;
+ }
+
+ case CONTENT_EARTHGROW:
+ {
+ sector->add_object(std::make_shared<PowerUp>(get_pos() + Vector(0, 32), "images/powerups/fireflower/fireflower.sprite"));
+ SoundManager::current()->play("sounds/upgrade.wav");
+ countdown = true;
+ break;
+ }
+
case CONTENT_STAR:
{
sector->add_object(std::make_shared<Star>(get_pos() + Vector(0, 32), direction));
CONTENT_COIN,
CONTENT_FIREGROW,
CONTENT_ICEGROW,
+ CONTENT_AIRGROW,
+ CONTENT_EARTHGROW,
CONTENT_STAR,
CONTENT_1UP,
CONTENT_CUSTOM,
sprite = SpriteManager::current()->create("images/powerups/iceflower/iceflower.sprite");
SoundManager::current()->preload("sounds/fire-flower.wav");
lightsprite->set_color(Color(0.0f, 0.1f, 0.2f));
+ }
+ else if(type == AIR_BONUS) {
+ sprite = SpriteManager::current()->create("images/powerups/iceflower/iceflower.sprite");
+ SoundManager::current()->preload("sounds/fire-flower.wav");
+ lightsprite->set_color(Color(0.15f, 0.0f, 0.15f));
+ }
+ else if(type == EARTH_BONUS) {
+ sprite = SpriteManager::current()->create("images/powerups/fireflower/fireflower.sprite");
+ SoundManager::current()->preload("sounds/fire-flower.wav");
+ lightsprite->set_color(Color(0.0f, 0.3f, 0.0f));
} else {
assert(false);
}
type = FIRE_BONUS;
} else if(bonustype == "iceflower") {
type = ICE_BONUS;
+ } else if(bonustype == "airflower") {
+ type = AIR_BONUS;
+ } else if(bonustype == "earthflower") {
+ type = EARTH_BONUS;
} else if(bonustype == "none") {
type = NO_BONUS;
} else {
// ignore GROWUP_BONUS if we're already big
if (type == GROWUP_BONUS) {
- if (player_status->bonus == GROWUP_BONUS)
- return true;
- if (player_status->bonus == FIRE_BONUS)
- return true;
- if (player_status->bonus == ICE_BONUS)
+ if (!player_status->bonus == NO_BONUS)
return true;
}
Sector::current()->add_object(std::make_shared<SpriteParticle>("images/objects/particles/icetux-cap.sprite", action, ppos, ANCHOR_TOP, pspeed, paccel, LAYER_OBJECTS-1));
if (climbing) stop_climbing(*climbing);
}
+ if ((player_status->bonus == AIR_BONUS) && (animate)) {
+ // visually lose hat
+ Vector ppos = Vector((bbox.p1.x + bbox.p2.x) / 2, bbox.p1.y);
+ Vector pspeed = Vector(((dir==LEFT) ? +100 : -100), -300);
+ Vector paccel = Vector(0, 1000);
+ std::string action = (dir==LEFT)?"left":"right";
+ Sector::current()->add_object(std::make_shared<SpriteParticle>("images/objects/particles/icetux-cap.sprite", action, ppos, ANCHOR_TOP, pspeed, paccel, LAYER_OBJECTS-1));
+ if (climbing) stop_climbing(*climbing);
+ }
+ if ((player_status->bonus == EARTH_BONUS) && (animate)) {
+ // visually lose hard-hat
+ Vector ppos = Vector((bbox.p1.x + bbox.p2.x) / 2, bbox.p1.y);
+ Vector pspeed = Vector(((dir==LEFT) ? +100 : -100), -300);
+ Vector paccel = Vector(0, 1000);
+ std::string action = (dir==LEFT)?"left":"right";
+ Sector::current()->add_object(std::make_shared<SpriteParticle>("images/objects/particles/firetux-helmet.sprite", action, ppos, ANCHOR_TOP, pspeed, paccel, LAYER_OBJECTS-1));
+ if (climbing) stop_climbing(*climbing);
+ }
player_status->max_fire_bullets = 0;
player_status->max_ice_bullets = 0;
+ player_status->max_air_time = 0;
+ player_status->max_earth_time = 0;
}
if (type == FIRE_BONUS) player_status->max_fire_bullets++;
if (type == ICE_BONUS) player_status->max_ice_bullets++;
+ if (type == AIR_BONUS) player_status->max_air_time++;
+ if (type == EARTH_BONUS) player_status->max_earth_time++;
player_status->bonus = type;
return true;
sa_prefix = "fire";
else if (player_status->bonus == ICE_BONUS)
sa_prefix = "ice";
+ else if (player_status->bonus == AIR_BONUS)
+ sa_prefix = "ice";
+ else if (player_status->bonus == EARTH_BONUS)
+ sa_prefix = "fire";
else
sa_prefix = "small";
SoundManager::current()->play("sounds/hurt.wav");
if(player_status->bonus == FIRE_BONUS
- || player_status->bonus == ICE_BONUS) {
+ || player_status->bonus == ICE_BONUS
+ || player_status->bonus == AIR_BONUS
+ || player_status->bonus == EARTH_BONUS) {
safe_timer.start(TUX_SAFE_TIME);
set_bonus(GROWUP_BONUS, true);
} else if(player_status->bonus == GROWUP_BONUS) {
case ICE_BONUS:
writer.write("bonus", "iceflower");
break;
+ case AIR_BONUS:
+ writer.write("bonus", "airflower");
+ break;
+ case EARTH_BONUS:
+ writer.write("bonus", "earthflower");
+ break;
default:
log_warning << "Unknown bonus type." << std::endl;
writer.write("bonus", "none");
}
writer.write("fireflowers", max_fire_bullets);
writer.write("iceflowers", max_ice_bullets);
+ writer.write("airflowers", max_air_time);
+ writer.write("earthflowers", max_earth_time);
writer.write("coins", coins);
}
bonus = FIRE_BONUS;
} else if(bonusname == "iceflower") {
bonus = ICE_BONUS;
+ } else if(bonusname == "airflower") {
+ bonus = AIR_BONUS;
+ } else if(bonusname == "earthflower") {
+ bonus = EARTH_BONUS;
} else {
log_warning << "Unknown bonus '" << bonusname << "' in savefile" << std::endl;
bonus = NO_BONUS;
}
lisp.get("fireflowers", max_fire_bullets);
lisp.get("iceflowers", max_ice_bullets);
+ lisp.get("airflowers", max_air_time);
+ lisp.get("earthflowers", max_earth_time);
lisp.get("coins", coins);
}
static const float BORDER_Y = 10;
enum BonusType {
- NO_BONUS, GROWUP_BONUS, FIRE_BONUS, ICE_BONUS
+ NO_BONUS, GROWUP_BONUS, FIRE_BONUS, ICE_BONUS, AIR_BONUS, EARTH_BONUS
};
class DrawingContext;
BonusType bonus;
int max_fire_bullets; /**< maximum number of fire bullets in play */
int max_ice_bullets; /**< maximum number of ice bullets in play */
+ int max_air_time; /**< maximum number of seconds player can float in air */
+ int max_earth_time; /**< maximum number of seconds player can turn to stone */
private:
int displayed_coins;