1 | // SuperTux - Climbable area |
2 | // Copyright (C) 2007 Christoph Sommer <christoph.sommer@2007.expires.deltadevelopment.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 "trigger/climbable.hpp" |
18 | |
19 | #include "editor/editor.hpp" |
20 | #include "object/player.hpp" |
21 | #include "supertux/debug.hpp" |
22 | #include "supertux/resources.hpp" |
23 | #include "util/reader_mapping.hpp" |
24 | #include "video/drawing_context.hpp" |
25 | #include "video/video_system.hpp" |
26 | #include "video/viewport.hpp" |
27 | |
28 | namespace { |
29 | const float GRACE_DX = 8; // how far off may the player's bounding-box be x-wise |
30 | const float GRACE_DY = 8; // how far off may the player's bounding-box be y-wise |
31 | const float ACTIVATE_TRY_FOR = 1; // how long to try correcting mis-alignment of player and climbable before giving up |
32 | const float POSITION_FIX_AX = 30; // x-wise acceleration applied to player when trying to align player and Climbable |
33 | const float POSITION_FIX_AY = 50; // y-wise acceleration applied to player when trying to align player and Climbable |
34 | } |
35 | |
36 | Climbable::Climbable(const ReaderMapping& reader) : |
37 | climbed_by(nullptr), |
38 | activate_try_timer(), |
39 | message(), |
40 | new_size() |
41 | { |
42 | reader.get("x" , m_col.m_bbox.get_left()); |
43 | reader.get("y" , m_col.m_bbox.get_top()); |
44 | float w = 32, h = 32; |
45 | reader.get("width" , w); |
46 | reader.get("height" , h); |
47 | m_col.m_bbox.set_size(w, h); |
48 | new_size.x = w; |
49 | new_size.y = h; |
50 | reader.get("message" , message); |
51 | } |
52 | |
53 | Climbable::Climbable(const Rectf& area) : |
54 | climbed_by(nullptr), |
55 | activate_try_timer(), |
56 | message(), |
57 | new_size() |
58 | { |
59 | m_col.m_bbox = area; |
60 | } |
61 | |
62 | Climbable::~Climbable() |
63 | { |
64 | if (climbed_by) { |
65 | climbed_by->stop_climbing(*this); |
66 | climbed_by = nullptr; |
67 | } |
68 | } |
69 | |
70 | ObjectSettings |
71 | Climbable::get_settings() |
72 | { |
73 | new_size.x = m_col.m_bbox.get_width(); |
74 | new_size.y = m_col.m_bbox.get_height(); |
75 | |
76 | ObjectSettings result = TriggerBase::get_settings(); |
77 | |
78 | // result.add_float(_("Width"), &new_size.x, "width"); |
79 | // result.add_float(_("Height"), &new_size.y, "height"); |
80 | |
81 | result.add_translatable_text(_("Message" ), &message, "message" ); |
82 | |
83 | result.reorder({"message" , "region" , "x" , "y" }); |
84 | |
85 | return result; |
86 | } |
87 | |
88 | void |
89 | Climbable::after_editor_set() { |
90 | m_col.m_bbox.set_size(new_size.x, new_size.y); |
91 | } |
92 | |
93 | void |
94 | Climbable::update(float /*dt_sec*/) |
95 | { |
96 | if (!climbed_by) return; |
97 | |
98 | if (!may_climb(*climbed_by)) { |
99 | climbed_by->stop_climbing(*this); |
100 | climbed_by = nullptr; |
101 | } |
102 | } |
103 | |
104 | void |
105 | Climbable::draw(DrawingContext& context) |
106 | { |
107 | if (climbed_by && !message.empty()) { |
108 | context.push_transform(); |
109 | context.set_translation(Vector(0, 0)); |
110 | Vector pos = Vector(0, static_cast<float>(SCREEN_HEIGHT) / 2.0f - Resources::normal_font->get_height() / 2.0f); |
111 | context.color().draw_center_text(Resources::normal_font, _(message), pos, LAYER_HUD, Climbable::text_color); |
112 | context.pop_transform(); |
113 | } |
114 | if (Editor::is_active() || g_debug.show_collision_rects) { |
115 | context.color().draw_filled_rect(m_col.m_bbox, Color(1.0f, 1.0f, 0.0f, 0.6f), |
116 | 0.0f, LAYER_OBJECTS); |
117 | } |
118 | } |
119 | |
120 | void |
121 | Climbable::event(Player& player, EventType type) |
122 | { |
123 | if ((type == EVENT_ACTIVATE) || (activate_try_timer.started())) { |
124 | if (player.get_grabbed_object() == nullptr){ |
125 | if (may_climb(player)) { |
126 | climbed_by = &player; |
127 | player.start_climbing(*this); |
128 | activate_try_timer.stop(); |
129 | } else { |
130 | if (type == EVENT_ACTIVATE) activate_try_timer.start(ACTIVATE_TRY_FOR); |
131 | // the "-13" to y velocity prevents Tux from walking in place on the ground for horizonal adjustments |
132 | if (player.get_bbox().get_left() < m_col.m_bbox.get_left() - GRACE_DX) player.add_velocity(Vector(POSITION_FIX_AX,-13)); |
133 | if (player.get_bbox().get_right() > m_col.m_bbox.get_right() + GRACE_DX) player.add_velocity(Vector(-POSITION_FIX_AX,-13)); |
134 | if (player.get_bbox().get_top() < m_col.m_bbox.get_top() - GRACE_DY) player.add_velocity(Vector(0,POSITION_FIX_AY)); |
135 | if (player.get_bbox().get_bottom() > m_col.m_bbox.get_bottom() + GRACE_DY) player.add_velocity(Vector(0,-POSITION_FIX_AY)); |
136 | } |
137 | } |
138 | } |
139 | if (type == EVENT_LOSETOUCH) { |
140 | player.stop_climbing(*this); |
141 | climbed_by = nullptr; |
142 | } |
143 | } |
144 | |
145 | bool |
146 | Climbable::may_climb(Player& player) const |
147 | { |
148 | if (player.get_bbox().get_left() < m_col.m_bbox.get_left() - GRACE_DX) return false; |
149 | if (player.get_bbox().get_right() > m_col.m_bbox.get_right() + GRACE_DX) return false; |
150 | if (player.get_bbox().get_top() < m_col.m_bbox.get_top() - GRACE_DY) return false; |
151 | if (player.get_bbox().get_bottom() > m_col.m_bbox.get_bottom() + GRACE_DY) return false; |
152 | return true; |
153 | } |
154 | |
155 | /* EOF */ |
156 | |