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
17#include "object/infoblock.hpp"
18
19#include <algorithm>
20
21#include "editor/editor.hpp"
22#include "object/player.hpp"
23#include "supertux/info_box_line.hpp"
24#include "supertux/sector.hpp"
25#include "util/reader_mapping.hpp"
26#include "video/drawing_context.hpp"
27
28InfoBlock::InfoBlock(const ReaderMapping& mapping) :
29 Block(mapping, "images/objects/bonus_block/infoblock.sprite"),
30 m_message(),
31 m_shown_pct(0),
32 m_dest_pct(0),
33 m_lines(),
34 m_lines_height(0)
35{
36 if (!mapping.get("message", m_message) && !(Editor::is_active())) {
37 log_warning << "No message in InfoBlock" << std::endl;
38 }
39 //stopped = false;
40 //ringing = new AmbientSound(get_pos(), 0.5, 300, 1, "sounds/phone.wav");
41 //Sector::get().add_object(ringing);
42
43 // Split text string lines into a vector
44 m_lines = InfoBoxLine::split(m_message, 400);
45 for (const auto& line : m_lines) m_lines_height += line->get_height();
46}
47
48InfoBlock::~InfoBlock()
49{
50}
51
52ObjectSettings
53InfoBlock::get_settings()
54{
55 ObjectSettings result = Block::get_settings();
56
57 result.add_translatable_text(_("Message"), &m_message, "message");
58
59 result.reorder({"message", "x", "y"});
60
61 return result;
62}
63
64void
65InfoBlock::hit(Player& player)
66{
67 start_bounce(&player);
68
69 //if (!stopped) {
70 // ringing->remove_me();
71 // stopped = true;
72 //}
73
74 if (m_dest_pct != 1) {
75
76 // first hide all other InfoBlocks' messages in same sector
77 for (auto& block : Sector::get().get_objects_by_type<InfoBlock>())
78 {
79 if (&block != this)
80 {
81 block.hide_message();
82 }
83 }
84
85 show_message();
86
87 } else {
88 hide_message();
89 }
90}
91
92HitResponse
93InfoBlock::collision(GameObject& other, const CollisionHit& hit_)
94{
95 auto player = dynamic_cast<Player*> (&other);
96 if (player)
97 {
98 if (player->m_does_buttjump)
99 InfoBlock::hit(*player);
100 }
101 return Block::collision(other, hit_);
102}
103
104Player*
105InfoBlock::get_nearest_player() const
106{
107 return Sector::get().get_nearest_player (m_col.m_bbox);
108}
109
110void
111InfoBlock::update(float dt_sec)
112{
113 Block::update(dt_sec);
114
115 if (dt_sec == 0) return;
116
117 // hide message if player is too far away
118 if (m_dest_pct > 0) {
119 if (auto* player = get_nearest_player()) {
120 Vector p1 = m_col.m_bbox.get_middle();
121 Vector p2 = player->get_bbox().get_middle();
122 Vector dist = (p2 - p1);
123 float d = dist.norm();
124 if (d > 128) m_dest_pct = 0;
125 }
126 }
127
128 // handle soft fade-in and fade-out
129 if (m_shown_pct != m_dest_pct) {
130 if (m_dest_pct > m_shown_pct) m_shown_pct = std::min(m_shown_pct + 2 * dt_sec, m_dest_pct);
131 if (m_dest_pct < m_shown_pct) m_shown_pct = std::max(m_shown_pct - 2 * dt_sec, m_dest_pct);
132 }
133}
134
135void
136InfoBlock::draw(DrawingContext& context)
137{
138 Block::draw(context);
139
140 if (m_shown_pct <= 0) return;
141
142 context.push_transform();
143 //context.set_translation(Vector(0, 0));
144 context.set_alpha(m_shown_pct);
145
146 //float x1 = SCREEN_WIDTH/2-200;
147 //float y1 = SCREEN_HEIGHT/2-200;
148 float border = 8;
149 float width = 400; // this is the text width only
150 float height = m_lines_height; // this is the text height only
151 float x1 = (m_col.m_bbox.get_left() + m_col.m_bbox.get_right())/2 - width/2;
152 float x2 = (m_col.m_bbox.get_left() + m_col.m_bbox.get_right())/2 + width/2;
153 float y1 = m_original_y - height;
154
155 if (x1 < 0) {
156 x1 = 0;
157 x2 = width;
158 }
159
160 if (x2 > Sector::get().get_width()) {
161 x2 = Sector::get().get_width();
162 x1 = x2 - width;
163 }
164
165 // lines_height includes one ITEMS_SPACE too much, so the bottom border is reduced by 4px
166 context.color().draw_filled_rect(Rectf(Vector(x1-border, y1-border),
167 Sizef(width+2*border, height+2*border-4)),
168 Color(0.6f, 0.7f, 0.8f, 0.5f), LAYER_GUI-50);
169
170 float y = y1;
171 for (size_t i = 0; i < m_lines.size(); ++i) {
172 if (y >= y1 + height) {
173 //log_warning << "Too many lines of text in InfoBlock" << std::endl;
174 //dest_pct = 0;
175 //shown_pct = 0;
176 break;
177 }
178
179 m_lines[i]->draw(context, Rectf(x1, y, x2, y), LAYER_GUI-50+1);
180 y += m_lines[i]->get_height();
181 }
182
183 context.pop_transform();
184}
185
186void
187InfoBlock::show_message()
188{
189 m_dest_pct = 1;
190}
191
192void
193InfoBlock::hide_message()
194{
195 m_dest_pct = 0;
196}
197
198/* EOF */
199