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 | |
28 | InfoBlock::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 | |
48 | InfoBlock::~InfoBlock() |
49 | { |
50 | } |
51 | |
52 | ObjectSettings |
53 | InfoBlock::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 | |
64 | void |
65 | InfoBlock::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 | |
92 | HitResponse |
93 | InfoBlock::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 | |
104 | Player* |
105 | InfoBlock::get_nearest_player() const |
106 | { |
107 | return Sector::get().get_nearest_player (m_col.m_bbox); |
108 | } |
109 | |
110 | void |
111 | InfoBlock::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 | |
135 | void |
136 | InfoBlock::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 | |
186 | void |
187 | InfoBlock::show_message() |
188 | { |
189 | m_dest_pct = 1; |
190 | } |
191 | |
192 | void |
193 | InfoBlock::hide_message() |
194 | { |
195 | m_dest_pct = 0; |
196 | } |
197 | |
198 | /* EOF */ |
199 | |