1// SuperTux
2// Copyright (C) 2016 Hume2 <teratux.mail@gmail.com>
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 "editor/worldmap_objects.hpp"
18
19#include <physfs.h>
20
21#include "editor/editor.hpp"
22#include "sprite/sprite.hpp"
23#include "sprite/sprite_manager.hpp"
24#include "supertux/world.hpp"
25#include "util/file_system.hpp"
26#include "util/log.hpp"
27#include "util/reader_mapping.hpp"
28#include "util/writer.hpp"
29
30namespace worldmap_editor {
31
32WorldmapObject::WorldmapObject (const ReaderMapping& mapping, const std::string& default_sprite) :
33 MovingSprite(mapping, default_sprite),
34 m_tile_x(),
35 m_tile_y()
36{
37 m_col.m_bbox = Rectf(Vector(32 * m_col.m_bbox.get_left(),
38 32 * m_col.m_bbox.get_top()),
39 Sizef(32.0f, 32.0f));
40}
41
42WorldmapObject::WorldmapObject (const ReaderMapping& mapping) :
43 MovingSprite(mapping),
44 m_tile_x(),
45 m_tile_y()
46{
47 m_col.m_bbox.set_left(32 * m_col.m_bbox.get_left());
48 m_col.m_bbox.set_top(32 * m_col.m_bbox.get_top());
49 m_col.m_bbox.set_size(32, 32);
50}
51
52WorldmapObject::WorldmapObject (const Vector& pos, const std::string& default_sprite) :
53 MovingSprite(pos, default_sprite),
54 m_tile_x(),
55 m_tile_y()
56{
57 m_col.m_bbox.set_left(32 * m_col.m_bbox.get_left());
58 m_col.m_bbox.set_top(32 * m_col.m_bbox.get_top());
59 m_col.m_bbox.set_size(32, 32);
60}
61
62ObjectSettings
63WorldmapObject::get_settings()
64{
65 ObjectSettings result = MovingSprite::get_settings();
66
67 m_tile_x = static_cast<int>(m_col.m_bbox.get_left()) / 32;
68 m_tile_y = static_cast<int>(m_col.m_bbox.get_top()) / 32;
69
70 result.remove("x");
71 result.remove("y");
72
73 result.add_int(_("X"), &m_tile_x, "x", {}, OPTION_HIDDEN);
74 result.add_int(_("Y"), &m_tile_y, "y", {}, OPTION_HIDDEN);
75
76 return result;
77}
78
79void
80WorldmapObject::move_to(const Vector& pos)
81{
82 Vector new_pos;
83 new_pos.x = 32.0f * static_cast<float>(pos.x / 32);
84 new_pos.y = 32.0f * static_cast<float>(pos.y / 32);
85 set_pos(new_pos);
86}
87
88LevelDot::LevelDot(const ReaderMapping& mapping) :
89 WorldmapObject(mapping, "images/worldmap/common/leveldot.sprite"),
90 m_level_filename(),
91 m_extro_script(),
92 m_auto_play(false),
93 m_title_color(1, 1, 1)
94{
95 mapping.get("extro-script", m_extro_script);
96 mapping.get("auto-play", m_auto_play);
97 if (!mapping.get("level", m_level_filename)) {
98 // Hack for backward compatibility with 0.5.x level
99 m_level_filename = std::move(m_name);
100 }
101
102 std::vector<float> vColor;
103 if (mapping.get("color", vColor)) {
104 m_title_color = Color(vColor);
105 }
106}
107
108void
109LevelDot::draw(DrawingContext& context)
110{
111 m_sprite->draw(context.color(), m_col.m_bbox.p1() + Vector(16, 16), m_layer);
112}
113
114ObjectSettings
115LevelDot::get_settings()
116{
117 ObjectSettings result = WorldmapObject::get_settings();
118
119 std::string basedir = (Editor::current() && Editor::current()->get_world()) ?
120 Editor::current()->get_world()->get_basedir() : std::string();
121
122 // FIXME: hack to make the basedir absolute, making
123 // World::get_basedir() itself absolute would be correct, but
124 // invalidate savefiles.
125 if (!basedir.empty() && basedir.front() != '/') {
126 basedir = "/" + basedir;
127 }
128
129 result.add_level(_("Level"), &m_level_filename, "level", basedir);
130 result.add_script(_("Outro script"), &m_extro_script, "extro-script");
131 result.add_bool(_("Auto play"), &m_auto_play, "auto-play", false);
132 //result.add_sprite(_("Sprite"), &m_sprite_name, "sprite");
133 result.add_color(_("Title colour"), &m_title_color, "color", Color::WHITE);
134
135 result.reorder({"name", "sprite", "x", "y"});
136
137 return result;
138}
139
140void
141LevelDot::after_editor_set()
142{
143}
144
145Teleporter::Teleporter (const ReaderMapping& mapping) :
146 WorldmapObject(mapping, "images/worldmap/common/teleporterdot.sprite"),
147 m_worldmap(),
148 m_spawnpoint(),
149 m_message(),
150 m_automatic(),
151 m_change_worldmap()
152{
153 mapping.get("worldmap", m_worldmap);
154 mapping.get("spawnpoint", m_spawnpoint);
155 mapping.get("message", m_message);
156
157 mapping.get("automatic", m_automatic);
158
159 m_change_worldmap = m_worldmap.size() > 0;
160}
161
162void
163Teleporter::draw(DrawingContext& context)
164{
165 m_sprite->draw(context.color(), m_col.m_bbox.p1() + Vector(16, 16), m_layer);
166}
167
168ObjectSettings
169Teleporter::get_settings()
170{
171 ObjectSettings result = WorldmapObject::get_settings();
172
173 result.add_text(_("Spawnpoint"), &m_spawnpoint, "spawnpoint");
174 result.add_translatable_text(_("Message"), &m_message, "message");
175 result.add_bool(_("Automatic"), &m_automatic, "automatic", false);
176 // result.add_bool(_("Change worldmap"), &m_change_worldmap, "worldmap", true);
177 result.add_worldmap(_("Target worldmap"), &m_worldmap, "worldmap");
178 //result.add_sprite(_("Sprite"), &m_sprite_name, "sprite");
179
180 result.reorder({"spawnpoint", "automatic", "message", "sprite", "x", "y"});
181
182 return result;
183}
184
185WorldmapSpawnPoint::WorldmapSpawnPoint (const ReaderMapping& mapping) :
186 WorldmapObject(mapping, "images/worldmap/common/tux.png"),
187 m_dir(worldmap::Direction::NONE)
188{
189 mapping.get("name", m_name);
190
191 std::string auto_dir_str;
192 if (mapping.get("auto-dir", auto_dir_str)) {
193 m_dir = worldmap::string_to_direction(auto_dir_str);
194 }
195}
196
197WorldmapSpawnPoint::WorldmapSpawnPoint (const std::string& name_, const Vector& pos) :
198 WorldmapObject(pos, "images/worldmap/common/tux.png"),
199 m_dir(worldmap::Direction::NONE)
200{
201 m_name = name_;
202}
203
204ObjectSettings
205WorldmapSpawnPoint::get_settings()
206{
207 ObjectSettings result = WorldmapObject::get_settings();
208
209 result.add_worldmap_direction(_("Direction"), &m_dir, worldmap::Direction::NONE, "auto-dir");
210
211 result.reorder({"auto-dir", "name", "x", "y"});
212
213 return result;
214}
215
216SpriteChange::SpriteChange (const ReaderMapping& mapping) :
217 WorldmapObject(mapping, "images/engine/editor/spritechange.png"),
218 m_target_sprite(m_sprite_name),
219 m_stay_action(),
220 m_initial_stay_action(false),
221 m_stay_group(),
222 m_change_on_touch(true)
223{
224 // To make obvious where the sprite change is, let's use an universal 32×32 sprite
225 m_sprite = SpriteManager::current()->create("images/engine/editor/spritechange.png");
226
227 mapping.get("stay-action", m_stay_action);
228 mapping.get("initial-stay-action", m_initial_stay_action);
229 mapping.get("stay-group", m_stay_group);
230
231 mapping.get("change-on-touch", m_change_on_touch);
232}
233
234ObjectSettings
235SpriteChange::get_settings()
236{
237 ObjectSettings result = WorldmapObject::get_settings();
238
239 //result.add_sprite(_("Sprite"), &m_target_sprite, "sprite");
240 result.add_text(_("Stay action"), &m_stay_action, "stay-action");
241 result.add_bool(_("Initial stay action"), &m_initial_stay_action, "initial-stay-action");
242 result.add_text(_("Stay group"), &m_stay_group, "stay-group");
243 result.add_bool(_("Change on touch"), &m_change_on_touch, "change-on-touch");
244
245 result.reorder({"change-on-touch", "initial-stay-action", "stay-group", "sprite", "x", "y"});
246
247 return result;
248}
249
250SpecialTile::SpecialTile (const ReaderMapping& mapping) :
251 WorldmapObject(mapping, "images/worldmap/common/messagedot.png"),
252 m_map_message(),
253 m_script(),
254 m_passive_message(false),
255 m_invisible_tile(false),
256 m_apply_to_directions("north-east-south-west")
257{
258 mapping.get("map-message", m_map_message);
259 mapping.get("script", m_script);
260
261 mapping.get("passive-message", m_passive_message);
262 mapping.get("invisible-tile", m_invisible_tile);
263
264 mapping.get("apply-to-direction", m_apply_to_directions);
265}
266
267ObjectSettings
268SpecialTile::get_settings()
269{
270 ObjectSettings result = WorldmapObject::get_settings();
271
272 result.add_translatable_text(_("Message"), &m_map_message, "map-message");
273 result.add_bool(_("Show message"), &m_passive_message, "passive-message", false);
274 result.add_script(_("Script"), &m_script, "script");
275 result.add_bool(_("Invisible"), &m_invisible_tile, "invisible-tile", false);
276 result.add_text(_("Direction"), &m_apply_to_directions, "apply-to-direction", std::string("north-east-south-west"));
277 //result.add_sprite(_("Sprite"), &m_sprite_name, "sprite");
278
279 result.reorder({"map-message", "invisible-tile", "script", "passive-message", "apply-to-direction", "sprite", "x", "y"});
280
281 return result;
282}
283
284} // namespace worldmap_editor
285
286/* EOF */
287