1 | // SuperTux - MagicBlock |
2 | // |
3 | // Magic Blocks are tile-like game objects that are sensitive to |
4 | // lighting conditions. They are rendered in a color and |
5 | // will only be solid as long as light of the same color shines |
6 | // on the block. |
7 | // |
8 | // Copyright (C) 2006 Wolfgang Becker <uafr@gmx.de> |
9 | // |
10 | // This program is free software: you can redistribute it and/or modify |
11 | // it under the terms of the GNU General Public License as published by |
12 | // the Free Software Foundation, either version 3 of the License, or |
13 | // (at your option) any later version. |
14 | // |
15 | // This program is distributed in the hope that it will be useful, |
16 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | // GNU General Public License for more details. |
19 | // |
20 | // You should have received a copy of the GNU General Public License |
21 | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
22 | |
23 | #include "object/magicblock.hpp" |
24 | |
25 | #include "editor/editor.hpp" |
26 | #include "object/camera.hpp" |
27 | #include "sprite/sprite.hpp" |
28 | #include "supertux/constants.hpp" |
29 | #include "supertux/sector.hpp" |
30 | #include "util/reader_mapping.hpp" |
31 | #include "video/video_system.hpp" |
32 | #include "video/viewport.hpp" |
33 | |
34 | namespace { |
35 | |
36 | const float MIN_INTENSITY = 0.8f; |
37 | const float ALPHA_SOLID = 0.7f; |
38 | const float ALPHA_NONSOLID = 0.3f; |
39 | const float MIN_SOLIDTIME = 1.0f; |
40 | const float SWITCH_DELAY = 0.06f; /**< seconds to wait for stable conditions until switching solidity */ |
41 | |
42 | } // namespace |
43 | |
44 | MagicBlock::MagicBlock(const ReaderMapping& mapping) : |
45 | MovingSprite(mapping, "images/objects/magicblock/magicblock.sprite" ), |
46 | m_is_solid(false), |
47 | m_trigger_red(), |
48 | m_trigger_green(), |
49 | m_trigger_blue(), |
50 | m_solid_time(0), |
51 | m_switch_delay(0), |
52 | m_solid_box(), |
53 | m_color(), |
54 | m_light(std::make_shared<Color>(1.0f,1.0f,1.0f)), |
55 | m_center(), |
56 | m_black() |
57 | { |
58 | set_group(COLGROUP_STATIC); |
59 | |
60 | std::vector<float> vColor; |
61 | if (mapping.get("color" , vColor )) { |
62 | m_color = Color( vColor ); |
63 | } else { |
64 | m_color = Color(0, 0, 0); |
65 | } |
66 | |
67 | if (!Editor::is_active()) { |
68 | // all alpha to make the sprite still visible |
69 | m_color.alpha = ALPHA_SOLID; |
70 | |
71 | // set trigger |
72 | if (m_color.red == 0 && m_color.green == 0 && m_color.blue == 0) { // is it black? |
73 | m_black = true; |
74 | m_trigger_red = MIN_INTENSITY; |
75 | m_trigger_green = MIN_INTENSITY; |
76 | m_trigger_blue = MIN_INTENSITY; |
77 | } else { |
78 | m_black = false; |
79 | m_trigger_red = m_color.red; |
80 | m_trigger_green = m_color.green; |
81 | m_trigger_blue = m_color.blue; |
82 | } |
83 | } |
84 | |
85 | m_center = m_col.m_bbox.get_middle(); |
86 | m_solid_box = Rectf(m_col.m_bbox.get_left() + SHIFT_DELTA, m_col.m_bbox.get_top() + SHIFT_DELTA, m_col.m_bbox.get_right() - SHIFT_DELTA, m_col.m_bbox.get_bottom() - SHIFT_DELTA); |
87 | } |
88 | |
89 | ObjectSettings |
90 | MagicBlock::get_settings() |
91 | { |
92 | ObjectSettings result = MovingSprite::get_settings(); |
93 | |
94 | result.add_rgb(_("Color" ), &m_color, "color" , Color::BLACK); |
95 | |
96 | result.reorder({"color" , "x" , "y" }); |
97 | |
98 | return result; |
99 | } |
100 | |
101 | void |
102 | MagicBlock::after_editor_set() |
103 | { |
104 | if (m_color.red == 0 && m_color.green == 0 && m_color.blue == 0) { //is it black? |
105 | m_black = true; |
106 | m_trigger_red = MIN_INTENSITY; |
107 | m_trigger_green = MIN_INTENSITY; |
108 | m_trigger_blue = MIN_INTENSITY; |
109 | } else { |
110 | m_black = false; |
111 | m_trigger_red = m_color.red; |
112 | m_trigger_green = m_color.green; |
113 | m_trigger_blue = m_color.blue; |
114 | } |
115 | m_sprite->set_color(m_color); |
116 | } |
117 | |
118 | void |
119 | MagicBlock::update(float dt_sec) |
120 | { |
121 | // Check if center of this block is on screen. |
122 | // Don't update if not, because there is no light off screen. |
123 | float screen_left = Sector::get().get_camera().get_translation().x; |
124 | float screen_top = Sector::get().get_camera().get_translation().y; |
125 | float screen_right = screen_left + static_cast<float>(SCREEN_WIDTH); |
126 | float screen_bottom = screen_top + static_cast<float>(SCREEN_HEIGHT); |
127 | if ((m_center.x > screen_right ) || (m_center.y > screen_bottom) || |
128 | (m_center.x < screen_left) || (m_center.y < screen_top)) { |
129 | m_switch_delay = SWITCH_DELAY; |
130 | return; |
131 | } |
132 | |
133 | bool lighting_ok; |
134 | if (m_black) { |
135 | lighting_ok = (m_light->red >= m_trigger_red || |
136 | m_light->green >= m_trigger_green || |
137 | m_light->blue >= m_trigger_blue); |
138 | } else { |
139 | lighting_ok = (m_light->red >= m_trigger_red && |
140 | m_light->green >= m_trigger_green && |
141 | m_light->blue >= m_trigger_blue); |
142 | } |
143 | |
144 | // overrule lighting_ok if switch_delay has not yet passed |
145 | if (lighting_ok == m_is_solid) { |
146 | m_switch_delay = SWITCH_DELAY; |
147 | } else { |
148 | if (m_switch_delay > 0) { |
149 | lighting_ok = m_is_solid; |
150 | m_switch_delay -= dt_sec; |
151 | } |
152 | } |
153 | |
154 | if (lighting_ok) { |
155 | // lighting suggests going solid |
156 | |
157 | if (!m_is_solid) { |
158 | if (Sector::get().is_free_of_movingstatics(m_solid_box, this)) { |
159 | m_is_solid = true; |
160 | m_solid_time = 0; |
161 | m_switch_delay = SWITCH_DELAY; |
162 | } |
163 | } |
164 | } else { |
165 | // lighting suggests going nonsolid |
166 | |
167 | if ( m_solid_time >= MIN_SOLIDTIME ){ |
168 | m_is_solid = false; |
169 | } |
170 | } |
171 | |
172 | // Update Sprite. |
173 | if (m_is_solid) { |
174 | m_solid_time+=dt_sec; |
175 | m_color.alpha = ALPHA_SOLID; |
176 | m_sprite->set_action("solid" ); |
177 | set_group(COLGROUP_STATIC); |
178 | } else { |
179 | m_color.alpha = ALPHA_NONSOLID; |
180 | m_sprite->set_action("normal" ); |
181 | set_group(COLGROUP_DISABLED); |
182 | } |
183 | } |
184 | |
185 | void |
186 | MagicBlock::draw(DrawingContext& context) |
187 | { |
188 | // Ask for update about lightmap at center of this block |
189 | context.light().get_pixel(m_center, m_light); |
190 | |
191 | MovingSprite::draw(context); |
192 | context.color().draw_filled_rect(m_col.m_bbox, m_color, m_layer); |
193 | } |
194 | |
195 | bool |
196 | MagicBlock::collides(GameObject& /*other*/, const CollisionHit& /*hit*/) const |
197 | { |
198 | return m_is_solid; |
199 | } |
200 | |
201 | HitResponse |
202 | MagicBlock::collision(GameObject& /*other*/, const CollisionHit& /*hit*/) |
203 | { |
204 | return FORCE_MOVE; |
205 | } |
206 | |
207 | /* EOF */ |
208 | |