powerup.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. // SuperTux
  2. // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. #include "object/powerup.hpp"
  17. #include "audio/sound_manager.hpp"
  18. #include "math/random.hpp"
  19. #include "object/player.hpp"
  20. #include "object/sprite_particle.hpp"
  21. #include "sprite/sprite.hpp"
  22. #include "sprite/sprite_manager.hpp"
  23. #include "supertux/flip_level_transformer.hpp"
  24. #include "supertux/game_session.hpp"
  25. #include "supertux/sector.hpp"
  26. #include "util/reader_mapping.hpp"
  27. PowerUp::PowerUp(const ReaderMapping& mapping) :
  28. MovingSprite(mapping, "images/powerups/egg/egg.sprite", LAYER_OBJECTS, COLGROUP_MOVING),
  29. physic(),
  30. script(),
  31. no_physics(),
  32. lightsprite(SpriteManager::current()->create("images/objects/lightmap_light/lightmap_light-small.sprite"))
  33. {
  34. parse_type(mapping);
  35. mapping.get("script", script, "");
  36. mapping.get("disable-physics", no_physics, false);
  37. initialize();
  38. }
  39. PowerUp::PowerUp(const Vector& pos, int type) :
  40. MovingSprite(pos, "images/powerups/egg/egg.sprite", LAYER_OBJECTS, COLGROUP_MOVING),
  41. physic(),
  42. script(),
  43. no_physics(false),
  44. lightsprite(SpriteManager::current()->create("images/objects/lightmap_light/lightmap_light-small.sprite"))
  45. {
  46. m_type = type;
  47. on_type_change(TypeChange::INITIAL);
  48. update_version();
  49. initialize();
  50. }
  51. GameObjectTypes
  52. PowerUp::get_types() const
  53. {
  54. return {
  55. { "egg", _("Egg") },
  56. { "fire", _("Fire Flower") },
  57. { "ice", _("Ice Flower") },
  58. { "air", _("Air Flower") },
  59. { "earth", _("Earth Flower") },
  60. { "star", _("Star") },
  61. { "oneup", _("Tux Doll") },
  62. { "flip", _("Flip Potion") },
  63. { "mints", _("Mints") },
  64. { "coffee", _("Coffee") },
  65. { "herring", _("Herring") }
  66. };
  67. }
  68. std::string
  69. PowerUp::get_default_sprite_name() const
  70. {
  71. switch (m_type)
  72. {
  73. case FIRE:
  74. return "images/powerups/fireflower/fireflower.sprite";
  75. case ICE:
  76. return "images/powerups/iceflower/iceflower.sprite";
  77. case AIR:
  78. return "images/powerups/airflower/airflower.sprite";
  79. case EARTH:
  80. return "images/powerups/earthflower/earthflower.sprite";
  81. case STAR:
  82. return "images/powerups/star/star.sprite";
  83. case ONEUP:
  84. return "images/powerups/1up/1up.sprite";
  85. case FLIP:
  86. return "images/powerups/potions/red-potion.sprite";
  87. case MINTS:
  88. return "images/powerups/retro/mints.png";
  89. case COFFEE:
  90. return "images/powerups/retro/coffee.png";
  91. case HERRING:
  92. return "images/powerups/retro/golden_herring.png";
  93. default:
  94. return m_default_sprite_name;
  95. }
  96. }
  97. void
  98. PowerUp::initialize()
  99. {
  100. physic.enable_gravity(true);
  101. SoundManager::current()->preload("sounds/grow.ogg");
  102. SoundManager::current()->preload("sounds/fire-flower.wav");
  103. SoundManager::current()->preload("sounds/gulp.wav");
  104. // Older levels utilize hardcoded behaviour from the chosen sprite
  105. if (get_version() == 1)
  106. {
  107. if (matches_sprite("images/powerups/egg/egg.sprite"))
  108. m_type = EGG;
  109. else if (matches_sprite("images/powerups/fireflower/fireflower.sprite"))
  110. m_type = FIRE;
  111. else if (matches_sprite("images/powerups/iceflower/iceflower.sprite"))
  112. m_type = ICE;
  113. else if (matches_sprite("images/powerups/airflower/airflower.sprite"))
  114. m_type = AIR;
  115. else if (matches_sprite("images/powerups/earthflower/earthflower.sprite"))
  116. m_type = EARTH;
  117. else if (matches_sprite("images/powerups/star/star.sprite"))
  118. m_type = STAR;
  119. else if (matches_sprite("images/powerups/1up/1up.sprite"))
  120. m_type = ONEUP;
  121. else if (matches_sprite("images/powerups/potions/red-potion.sprite"))
  122. m_type = FLIP;
  123. }
  124. setup_lightsprite();
  125. }
  126. void
  127. PowerUp::setup_lightsprite()
  128. {
  129. lightsprite->set_blend(Blend::ADD);
  130. lightsprite->set_color(Color(0.0f, 0.0f, 0.0f));
  131. // Set default light for glow effect for default sprites.
  132. if (matches_sprite(get_default_sprite_name()))
  133. {
  134. switch (m_type)
  135. {
  136. case EGG:
  137. lightsprite->set_color(Color(0.2f, 0.2f, 0.0f));
  138. break;
  139. case FIRE:
  140. lightsprite->set_color(Color(0.3f, 0.0f, 0.0f));
  141. break;
  142. case ICE:
  143. lightsprite->set_color(Color(0.0f, 0.1f, 0.2f));
  144. break;
  145. case AIR:
  146. lightsprite->set_color(Color(0.15f, 0.0f, 0.15f));
  147. break;
  148. case EARTH:
  149. lightsprite->set_color(Color(0.0f, 0.3f, 0.0f));
  150. break;
  151. case STAR:
  152. lightsprite->set_color(Color(0.4f, 0.4f, 0.4f));
  153. break;
  154. }
  155. }
  156. }
  157. void
  158. PowerUp::after_editor_set()
  159. {
  160. MovingSprite::after_editor_set();
  161. setup_lightsprite();
  162. }
  163. void
  164. PowerUp::collision_solid(const CollisionHit& hit)
  165. {
  166. if (hit.bottom) {
  167. physic.set_velocity_y(0);
  168. }
  169. if (hit.right || hit.left) {
  170. physic.set_velocity_x(-physic.get_velocity_x());
  171. }
  172. }
  173. HitResponse
  174. PowerUp::collision(GameObject& other, const CollisionHit&)
  175. {
  176. Player* player = dynamic_cast<Player*>(&other);
  177. if (!player)
  178. return FORCE_MOVE;
  179. if (m_type == FLIP)
  180. SoundManager::current()->play("sounds/gulp.wav", get_pos());
  181. if (!script.empty())
  182. {
  183. Sector::get().run_script(script, "powerup-script");
  184. remove_me();
  185. return ABORT_MOVE;
  186. }
  187. switch (m_type)
  188. {
  189. case EGG:
  190. case MINTS:
  191. if (!player->add_bonus(GROWUP_BONUS, true))
  192. return FORCE_MOVE;
  193. SoundManager::current()->play("sounds/grow.ogg", get_pos());
  194. break;
  195. case FIRE:
  196. case COFFEE:
  197. if (!player->add_bonus(FIRE_BONUS, true))
  198. return FORCE_MOVE;
  199. SoundManager::current()->play("sounds/fire-flower.wav", get_pos());
  200. break;
  201. case ICE:
  202. if (!player->add_bonus(ICE_BONUS, true))
  203. return FORCE_MOVE;
  204. SoundManager::current()->play("sounds/fire-flower.wav", get_pos());
  205. break;
  206. case AIR:
  207. if (!player->add_bonus(AIR_BONUS, true))
  208. return FORCE_MOVE;
  209. SoundManager::current()->play("sounds/fire-flower.wav", get_pos());
  210. break;
  211. case EARTH:
  212. if (!player->add_bonus(EARTH_BONUS, true))
  213. return FORCE_MOVE;
  214. SoundManager::current()->play("sounds/fire-flower.wav", get_pos());
  215. break;
  216. case STAR:
  217. case HERRING:
  218. player->make_invincible();
  219. break;
  220. case ONEUP:
  221. player->get_status().add_coins(100);
  222. break;
  223. case FLIP:
  224. FlipLevelTransformer flip_transformer;
  225. flip_transformer.transform(GameSession::current()->get_current_level());
  226. break;
  227. }
  228. remove_me();
  229. return ABORT_MOVE;
  230. }
  231. void
  232. PowerUp::update(float dt_sec)
  233. {
  234. if (!no_physics)
  235. m_col.set_movement(physic.get_movement(dt_sec));
  236. // Stars and herrings should sparkle when close to Tux.
  237. if (m_type == STAR || m_type == HERRING)
  238. {
  239. if (auto* player = Sector::get().get_nearest_player(m_col.m_bbox))
  240. {
  241. float disp_x = player->get_bbox().get_left() - m_col.m_bbox.get_left();
  242. float disp_y = player->get_bbox().get_top() - m_col.m_bbox.get_top();
  243. if (disp_x*disp_x + disp_y*disp_y <= 256*256)
  244. {
  245. if (graphicsRandom.rand(0, 2) == 0) {
  246. float px = graphicsRandom.randf(m_col.m_bbox.get_left() * 1.0f, m_col.m_bbox.get_right() * 1.0f);
  247. float py = graphicsRandom.randf(m_col.m_bbox.get_top() * 1.0f, m_col.m_bbox.get_bottom() * 1.0f);
  248. Vector ppos = Vector(px, py);
  249. Vector pspeed = Vector(0, 0);
  250. Vector paccel = Vector(0, 0);
  251. Sector::get().add<SpriteParticle>(
  252. "images/particles/sparkle.sprite",
  253. // draw bright sparkles when very close to Tux, dark sparkles when slightly further
  254. (disp_x*disp_x + disp_y*disp_y <= 128*128) ?
  255. // make every other a longer sparkle to make trail a bit fuzzy
  256. (size_t(g_game_time*20)%2) ? "small" : "medium" : "dark",
  257. ppos, ANCHOR_MIDDLE, pspeed, paccel, LAYER_OBJECTS+1+5);
  258. }
  259. }
  260. }
  261. }
  262. }
  263. void
  264. PowerUp::draw(DrawingContext& context)
  265. {
  266. m_sprite->draw(context.color(), get_pos(), m_layer, m_flip);
  267. // Stars and herrings are brighter.
  268. if (m_type == STAR || m_type == HERRING)
  269. m_sprite->draw(context.color(), get_pos(), m_layer, m_flip);
  270. lightsprite->draw(context.light(), m_col.m_bbox.get_middle(), 0);
  271. }
  272. ObjectSettings
  273. PowerUp::get_settings()
  274. {
  275. ObjectSettings result = MovingSprite::get_settings();
  276. result.add_script(_("Script"), &script, "script");
  277. result.add_bool(_("Disable gravity"), &no_physics, "disable-physics", false);
  278. result.reorder({"script", "disable-physics", "sprite", "x", "y"});
  279. return result;
  280. }
  281. std::vector<std::string>
  282. PowerUp::get_patches() const
  283. {
  284. return { _("Sprites no longer define the behaviour of the object.\nObject types are used instead.") };
  285. }
  286. void
  287. PowerUp::on_flip(float height)
  288. {
  289. MovingSprite::on_flip(height);
  290. if (no_physics)
  291. FlipLevelTransformer::transform_flip(m_flip);
  292. }
  293. /* EOF */