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 "scripting/functions.hpp"
18
19#include "audio/sound_manager.hpp"
20#include "math/random.hpp"
21#include "object/camera.hpp"
22#include "object/player.hpp"
23#include "physfs/ifile_stream.hpp"
24#include "supertux/console.hpp"
25#include "supertux/debug.hpp"
26#include "supertux/game_manager.hpp"
27#include "supertux/game_session.hpp"
28#include "supertux/gameconfig.hpp"
29#include "supertux/level.hpp"
30#include "supertux/screen_manager.hpp"
31#include "supertux/sector.hpp"
32#include "supertux/shrinkfade.hpp"
33#include "supertux/textscroller_screen.hpp"
34#include "supertux/tile.hpp"
35#include "video/renderer.hpp"
36#include "video/video_system.hpp"
37#include "video/viewport.hpp"
38#include "worldmap/tux.hpp"
39#include "worldmap/worldmap.hpp"
40#include "worldmap/worldmap_screen.hpp"
41
42namespace {
43
44// not added to header, function to only be used by others
45// in this file
46bool validate_sector_player()
47{
48 if (::Sector::current() == nullptr)
49 {
50 log_info << "No current sector." << std::endl;
51 return false;
52 }
53
54 return true;
55}
56
57} // namespace
58
59namespace scripting {
60
61SQInteger display(HSQUIRRELVM vm)
62{
63 ConsoleBuffer::output << squirrel2string(vm, -1) << std::endl;
64 return 0;
65}
66
67void print_stacktrace(HSQUIRRELVM vm)
68{
69 print_squirrel_stack(vm);
70}
71
72SQInteger get_current_thread(HSQUIRRELVM vm)
73{
74 sq_pushthread(vm, vm);
75 return 1;
76}
77
78bool is_christmas()
79{
80 return g_config->christmas_mode;
81}
82
83void wait(HSQUIRRELVM vm, float seconds)
84{
85 if (auto squirrelenv = static_cast<SquirrelEnvironment*>(sq_getforeignptr(vm)))
86 {
87 squirrelenv->wait_for_seconds(vm, seconds);
88 }
89 else if (auto squirrelvm = static_cast<SquirrelVirtualMachine*>(sq_getsharedforeignptr(vm)))
90 {
91 squirrelvm->wait_for_seconds(vm, seconds);
92 }
93 else
94 {
95 log_warning << "wait(): no VM or environment available\n";
96 }
97}
98
99void wait_for_screenswitch(HSQUIRRELVM vm)
100{
101 auto squirrelvm = static_cast<SquirrelVirtualMachine*>(sq_getsharedforeignptr(vm));
102 //auto squirrelenv = static_cast<SquirrelEnvironment*>(sq_getforeignptr(vm));
103 squirrelvm->wait_for_screenswitch(vm);
104}
105
106void exit_screen()
107{
108 ScreenManager::current()->pop_screen();
109}
110
111std::string translate(const std::string& text)
112{
113 return g_dictionary_manager->get_dictionary().translate(text);
114}
115
116std::string _(const std::string& text)
117{
118 return translate(text);
119}
120
121std::string translate_plural(const std::string& text, const std::string& text_plural, int num)
122{
123 return g_dictionary_manager->get_dictionary().translate_plural(text, text_plural, num);
124}
125
126std::string __(const std::string& text, const std::string& text_plural, int num)
127{
128 return translate_plural(text, text_plural, num);
129}
130
131void display_text_file(const std::string& filename)
132{
133 ScreenManager::current()->push_screen(std::make_unique<TextScrollerScreen>(filename));
134}
135
136void load_worldmap(const std::string& filename)
137{
138 using namespace worldmap;
139
140 if (!WorldMap::current())
141 {
142 throw std::runtime_error("Can't start Worldmap without active WorldMap");
143 }
144 else
145 {
146 ScreenManager::current()->push_screen(std::make_unique<WorldMapScreen>(
147 std::make_unique<WorldMap>(filename, WorldMap::current()->get_savegame())));
148 }
149}
150
151void set_next_worldmap(const std::string& dirname, const std::string& spawnpoint)
152{
153 GameManager::current()->set_next_worldmap(dirname, spawnpoint);
154}
155
156void load_level(const std::string& filename)
157{
158 if (!GameSession::current())
159 {
160 throw std::runtime_error("Can't start level without active level.");
161 }
162 else
163 {
164 ScreenManager::current()->push_screen(std::make_unique<GameSession>(filename, GameSession::current()->get_savegame()));
165 }
166}
167
168void import(HSQUIRRELVM vm, const std::string& filename)
169{
170 IFileStream in(filename);
171 compile_and_run(vm, in, filename);
172}
173
174void debug_collrects(bool enable)
175{
176 g_debug.show_collision_rects = enable;
177}
178
179void debug_show_fps(bool enable)
180{
181 g_config->show_fps = enable;
182}
183
184void debug_draw_solids_only(bool enable)
185{
186 ::Sector::s_draw_solids_only = enable;
187}
188
189void debug_draw_editor_images(bool enable)
190{
191 Tile::draw_editor_images = enable;
192}
193
194void debug_worldmap_ghost(bool enable)
195{
196 auto worldmap = worldmap::WorldMap::current();
197
198 if (worldmap == nullptr)
199 throw std::runtime_error("Can't change ghost mode without active WorldMap");
200
201 auto& tux = worldmap->get_singleton_by_type<worldmap::Tux>();
202 tux.set_ghost_mode(enable);
203}
204
205void save_state()
206{
207 auto worldmap = worldmap::WorldMap::current();
208
209 if (!worldmap)
210 {
211 throw std::runtime_error("Can't save state without active Worldmap");
212 }
213 else
214 {
215 worldmap->save_state();
216 }
217}
218
219void load_state()
220{
221 auto worldmap = worldmap::WorldMap::current();
222
223 if (!worldmap)
224 {
225 throw std::runtime_error("Can't save state without active Worldmap");
226 }
227 else
228 {
229 worldmap->load_state();
230 }
231}
232
233void play_music(const std::string& filename)
234{
235 SoundManager::current()->play_music(filename);
236}
237
238void stop_music(float fadetime)
239{
240 SoundManager::current()->stop_music(fadetime);
241}
242
243void play_sound(const std::string& filename)
244{
245 SoundManager::current()->play(filename);
246}
247
248void grease()
249{
250 if (!validate_sector_player()) return;
251 ::Player& tux = ::Sector::get().get_player(); // scripting::Player != ::Player
252 tux.get_physic().set_velocity_x(tux.get_physic().get_velocity_x()*3);
253}
254
255void invincible()
256{
257 if (!validate_sector_player()) return;
258 ::Player& tux = ::Sector::get().get_player();
259 tux.m_invincible_timer.start(10000);
260}
261
262void ghost()
263{
264 if (!validate_sector_player()) return;
265 ::Player& tux = ::Sector::get().get_player();
266 tux.set_ghost_mode(true);
267}
268
269void mortal()
270{
271 if (!validate_sector_player()) return;
272 ::Player& tux = ::Sector::get().get_player();
273 tux.m_invincible_timer.stop();
274 tux.set_ghost_mode(false);
275}
276
277void restart()
278{
279 auto session = GameSession::current();
280 if (session == nullptr)
281 {
282 log_info << "No game session" << std::endl;
283 return;
284 }
285 session->restart_level();
286}
287
288void whereami()
289{
290 if (!validate_sector_player()) return;
291 ::Player& tux = ::Sector::get().get_player();
292 log_info << "You are at x " << (static_cast<int>(tux.get_pos().x)) << ", y " << (static_cast<int>(tux.get_pos().y)) << std::endl;
293}
294
295void gotoend()
296{
297 if (!validate_sector_player()) return;
298 ::Player& tux = ::Sector::get().get_player();
299 tux.move(Vector(
300 (::Sector::get().get_width()) - (static_cast<float>(SCREEN_WIDTH) * 2.0f), 0));
301 ::Sector::get().get_camera().reset(
302 Vector(tux.get_pos().x, tux.get_pos().y));
303}
304
305void warp(float offset_x, float offset_y)
306{
307 if (!validate_sector_player()) return;
308 ::Player& tux = ::Sector::get().get_player();
309 tux.move(Vector(
310 tux.get_pos().x + (offset_x*32), tux.get_pos().y - (offset_y*32)));
311 ::Sector::get().get_camera().reset(
312 Vector(tux.get_pos().x, tux.get_pos().y));
313}
314
315void camera()
316{
317 if (!validate_sector_player()) return;
318 const auto& cam_pos = ::Sector::get().get_camera().get_translation();
319 log_info << "Camera is at " << cam_pos.x << "," << cam_pos.y << std::endl;
320}
321
322void set_gamma(float gamma)
323{
324 VideoSystem::current()->set_gamma(gamma);
325}
326
327void quit()
328{
329 ScreenManager::current()->quit();
330}
331
332int rand()
333{
334 return gameRandom.rand();
335}
336
337void set_game_speed(float speed)
338{
339 ::g_debug.set_game_speed_multiplier(speed);
340}
341
342void record_demo(const std::string& filename)
343{
344 if (GameSession::current() == nullptr)
345 {
346 log_info << "No game session" << std::endl;
347 return;
348 }
349 GameSession::current()->restart_level();
350 GameSession::current()->record_demo(filename);
351}
352
353void play_demo(const std::string& filename)
354{
355 auto session = GameSession::current();
356 if (session == nullptr)
357 {
358 log_info << "No game session" << std::endl;
359 return;
360 }
361 // Reset random seed
362 g_config->random_seed = session->get_demo_random_seed(filename);
363 gameRandom.seed(g_config->random_seed);
364 session->restart_level();
365 session->play_demo(filename);
366}
367
368}
369
370/* EOF */
371