ScummVM API documentation
puzzle_all.h
1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #ifndef QDENGINE_MINIGAMES_PUZZLE_ALL_H
23 #define QDENGINE_MINIGAMES_PUZZLE_ALL_H
24 
25 #include "common/debug.h"
26 
27 #include "qdengine/qd_fwd.h"
28 #include "qdengine/qdcore/qd_minigame_interface.h"
29 
30 namespace QDEngine {
31 
32 const int puzzle_ep01[] = {
33  220, 193, 340, 186, 464, 193, 577, 186, 227, 306,
34  340, 306, 465, 305, 585, 306, 220, 419, 340, 426,
35  464, 418, 577, 426
36 };
37 
38 const int puzzle_ep02[] = {
39  218, 197, 335, 194, 465, 178, 579, 181, 220, 305,
40  347, 304, 473, 300, 582, 298, 222, 410, 342, 416,
41  469, 426, 579, 427
42 };
43 
44 const int puzzle_ep04[] = {
45  205, 224, 298, 224, 404, 195, 503, 189, 601, 204,
46  218, 319, 306, 308, 416, 287, 504, 263, 587, 285,
47  218, 400, 313, 408, 418, 386, 504, 387, 588, 384
48 };
49 
50 const int puzzle_ep05[] = {
51  205, 223, 297, 223, 404, 194, 503, 189, 601, 203,
52  217, 316, 305, 306, 415, 287, 503, 262, 586, 284,
53  217, 397, 312, 405, 417, 384, 503, 384, 587, 382
54 };
55 
56 const int puzzle_ep07[] = {
57  199, 188, 276, 185, 362, 177, 444, 172, 531, 185,
58  601, 183, 202, 263, 282, 258, 362, 245, 440, 248,
59  524, 254, 598, 265, 200, 342, 282, 341, 357, 342,
60  439, 341, 519, 344, 595, 340, 203, 423, 276, 420,
61  359, 425, 441, 421, 525, 419, 602, 414
62 };
63 
64 const int puzzle_ep08[] = {
65  217, 188, 337, 181, 462, 188, 575, 181, 224, 302,
66  338, 301, 462, 301, 582, 301, 217, 415, 337, 422,
67  462, 414, 575, 421
68 };
69 
70 const int puzzle_ep13[] = {
71  196, 194, 273, 194, 362, 169, 445, 164, 538, 188,
72  606, 188, 197, 266, 283, 255, 365, 231, 438, 235,
73  533, 246, 593, 271, 197, 345, 283, 341, 354, 344,
74  437, 341, 516, 348, 592, 340, 197, 425, 270, 424,
75  357, 430, 440, 427, 526, 416, 601, 412
76 };
77 
79 public:
80  qdPuzzleAllMiniGame(Common::String dll, Common::Language language) : _dll(dll), _language(language) {
81  for (uint i = 0; i < ARRAYSIZE(_pieces); i++)
82  _pieces[i] = nullptr;
83  }
84  ~qdPuzzleAllMiniGame() {};
85 
86  bool init(const qdEngineInterface *engine_interface) {
87  debugC(1, kDebugMinigames, "PuzzleAll::init(), dll: %s lang: %d", _dll.c_str(), _language);
88 
89  _engine = engine_interface;
90  _scene = _engine->current_scene_interface();
91  if (!_scene)
92  return 0;
93 
94  if (_dll == "DLL\\Puzzle_ep01.dll") { // worm
95  _numPieces = 12;
96  _pieceCoords = puzzle_ep01;
97  } else if (_dll == "DLL\\Puzzle_ep02.dll") { // mushrooms
98  _numPieces = 12;
99  _pieceCoords = puzzle_ep02;
100  } else if (_dll == "DLL\\Puzzle_ep04.dll") { // bird
101  _numPieces = 15;
102  _pieceCoords = puzzle_ep04;
103  } else if (_dll == "DLL\\Puzzle_ep05.dll") { // forest
104  _numPieces = 15;
105  _pieceCoords = puzzle_ep05;
106  } else if (_dll == "DLL\\Puzzle_ep07.dll") { // bears
107  _numPieces = 24;
108  _pieceCoords = puzzle_ep07;
109  } else if (_dll == "DLL\\Puzzle_ep08.dll") { // house
110  _numPieces = 12;
111  _pieceCoords = puzzle_ep08;
112  } else if (_dll == "DLL\\Puzzle_ep13.dll") { // harbor
113  _numPieces = 24;
114  _pieceCoords = puzzle_ep13;
115  }
116 
117  for (int i = 0; i < _numPieces; i++)
118  _pieces[i] = _scene->object_interface(Common::String::format("\xee\xe1\xfa\xe5\xea\xf2_%i", i + 1).c_str()); // "объект_%i"
119 
120  _objFinal = _scene->object_interface("$\xf4\xe8\xed\xe0\xeb"); // "$финал"
121  _objRan = _scene->object_interface("$\xe7\xe0\xef\xf3\xf1\xf2\xe8\xeb\xe8"); // "$запустили""
122  _wasInited = false;
123 
124  if (_objFinal->is_state_active("\xed\xe5\xf2")) { // "нет"
125  _isFinal = false;
126 
127  _minDepthPiece = findMinDepthPiece();
128  return true;
129  } else {
130  if (_objFinal->is_state_active("\xe4\xe0")) // "да"
131  _isFinal = true;
132 
133  _minDepthPiece = findMinDepthPiece();
134  return true;
135  }
136 
137  return true;
138  }
139 
140  bool quant(float dt) {
141  debugC(3, kDebugMinigames, "PuzzleAll::quant(%f)", dt);
142 
143  if (!_wasInited && _objRan->is_state_active("\xed\xe5\xf2")) { // "нет"
144  _rotatingPiece = -1;
145  _currentPieceState = -1;
146  _pieceIsPut = false;
147  _isFinal = false;
148  _wasInited = 1;
149  _objRan->set_state("\xe4\xe0"); // "да"
150  }
151 
152  if (_isFinal)
153  return true;
154 
155  if (!checkSolution() || _scene->mouse_object_interface()) {
157 
158  if (_pieceIsPut) {
159  for (int i = 0; i < _numPieces; i++) {
160  if (_pieces[i]->is_state_active("to_inv_flag_0")
161  || _pieces[i]->is_state_active("to_inv_flag_90")
162  || _pieces[i]->is_state_active("to_inv_flag_180")
163  || _pieces[i]->is_state_active("to_inv_flag_270")) {
164 
165  if (_pieces[i]->is_state_active("to_inv_flag_0"))
166  _currentPieceState = _pieces[i]->state_index("inv_0");
167  else if (_pieces[i]->is_state_active("to_inv_flag_90"))
168  _currentPieceState = _pieces[i]->state_index("inv_90");
169  else if (_pieces[i]->is_state_active("to_inv_flag_180"))
170  _currentPieceState = _pieces[i]->state_index("inv_180");
171  else if (_pieces[i]->is_state_active("to_inv_flag_270"))
172  _currentPieceState = _pieces[i]->state_index("inv_270");
173 
174  _rotatingPiece = i;
175  _pieces[i]->set_state("to_inv");
176  _pieceIsPut = false;
177  }
178  }
179  }
180 
181  if (mouseObj) {
182  if (_rotatingPiece != -1) {
183  _pieces[_rotatingPiece]->set_state(_currentPieceState);
184  _currentPieceState = -1;
185  _rotatingPiece = -1;
186  }
187  }
188 
190  mgVect2i mousePos = _engine->mouse_cursor_position();
192 
193  if (obj) {
194  if (obj->is_state_active("inv_0"))
195  obj->set_state("0");
196  else if (obj->is_state_active("inv_90"))
197  obj->set_state("90");
198  else if (obj->is_state_active("inv_180"))
199  obj->set_state("180");
200  else if (obj->is_state_active("inv_270"))
201  obj->set_state("270");
202 
203  _minDepthPiece -= 250.0;
204 
205  mgVect3f coords = _scene->screen2world_coords(mousePos, _minDepthPiece);
206  obj->set_R(coords);
207 
208  snapPieces();
209  } else {
210  _pieceIsPut = true;
211  }
212  }
213  }
214 
217 
218  if (obj) {
219  if (obj->is_state_active("inv_0"))
220  obj->set_state("inv_270");
221  else if (obj->is_state_active("inv_90"))
222  obj->set_state("inv_0");
223  else if (obj->is_state_active("inv_180"))
224  obj->set_state("inv_90");
225  else if (obj->is_state_active("inv_270"))
226  obj->set_state("inv_180");
227  }
228  }
229 
230  return true;
231  }
232 
233  bool checkSolution() {
234  if (_scene->mouse_object_interface())
235  return false;
236 
237  for (int i = 0; i < _numPieces; i++)
238  if (!_pieces[0]->is_state_active("0"))
239  return false;
240 
241  mgVect2i piecePos;
242 
243  for (int i = 0; i < _numPieces; i++) {
244  piecePos = _pieces[i]->screen_R();
245 
246  if (ABS(_pieceCoords[i * 2 + 0] - piecePos.x) > 10 ||
247  ABS(_pieceCoords[i * 2 + 1] - piecePos.y) > 10)
248  return false;
249  }
250 
251  _isFinal = true;
252  _objFinal->set_state("\xe4\xe0"); // "да"
253 
254  _minDepthPiece -= 250.0;
255 
256  mgVect3f coords = _scene->screen2world_coords(_objFinal->screen_R(), _minDepthPiece);
257  _objFinal->set_R(coords);
258 
259  return true;
260  }
261 
262  void snapPieces() {
263  mgVect2i piecePos;
264  mgVect3f newPiecePos;
265 
266  for (int i = 0; i < _numPieces; i++) {
267  piecePos = _pieces[i]->screen_R();
268  float depth = _scene->screen_depth(_pieces[i]->R());
269 
270  if (_pieces[i]->is_state_active("0")) {
271  if (ABS(_pieceCoords[i * 2 + 0] - piecePos.x) <= 10 &&
272  ABS(_pieceCoords[i * 2 + 1] - piecePos.y) <= 10) {
273  piecePos.x = _pieceCoords[i * 2 + 0];
274  piecePos.y = _pieceCoords[i * 2 + 1];
275 
276  newPiecePos = _scene->screen2world_coords(piecePos, depth);
277  _pieces[i]->set_R(newPiecePos);
278  }
279  }
280  }
281  }
282 
283  bool finit() {
284  debugC(1, kDebugMinigames, "PuzzleAll::finit()");
285 
286  if (_scene) {
287  _engine->release_scene_interface(_scene);
288  _scene = 0;
289  }
290 
291  return true;
292  }
293 
294  bool new_game(const qdEngineInterface *engine_interface) {
295  return true;
296  }
297 
298  int save_game(const qdEngineInterface *engine_interface, const qdMinigameSceneInterface *scene_interface, char *buffer, int buffer_size) {
299  return 0;
300  }
301 
302  int load_game(const qdEngineInterface *engine_interface, const qdMinigameSceneInterface *scene_interface, const char *buffer, int buffer_size) {
303  return 0;
304  }
305 
306  enum { INTERFACE_VERSION = 112 };
307  int version() const {
308  return INTERFACE_VERSION;
309  }
310 
311 private:
312  float findMinDepthPiece() {
313  float min = 100000.0;
314 
315  for (int i = 0; i < _numPieces; i++) {
316  float depth = _scene->screen_depth(_pieces[i]->R());
317 
318  if (min > depth)
319  min = depth;
320  }
321 
322  return min;
323  }
324 
325 private:
326  const qdEngineInterface *_engine = nullptr;
327  qdMinigameSceneInterface *_scene = nullptr;
328 
329  qdMinigameObjectInterface *_pieces[24];
330  const int *_pieceCoords = nullptr;
331 
332  qdMinigameObjectInterface *_objFinal = nullptr;
333  qdMinigameObjectInterface *_objRan = nullptr;
334 
335  bool _wasInited = false;
336  bool _isFinal = false;
337 
338  float _minDepthPiece = 0.0;
339  int _rotatingPiece = -1;
340  bool _pieceIsPut = true;
341  int _currentPieceState = 0;
342 
343  int _numPieces = 12;
344 
345  Common::String _dll;
346  Common::Language _language;
347 };
348 
349 } // namespace QDEngine
350 
351 #endif // QDENGINE_MINIGAMES_PUZZLE_ALL_H
#define ARRAYSIZE(x)
Definition: util.h:91
int save_game(const qdEngineInterface *engine_interface, const qdMinigameSceneInterface *scene_interface, char *buffer, int buffer_size)
Сохранение данных, вызывается при сохранении сцены, на которую повешена миниигра. ...
Definition: puzzle_all.h:298
virtual mgVect3f screen2world_coords(const mgVect2i &screen_pos, float screen_depth=0) const =0
Преобразование из экранных координат в мировые.
Definition: str.h:59
static String format(MSVC_PRINTF const char *fmt,...) GCC_PRINTF(1
virtual mgVect2i screen_R() const =0
Возвращает координаты объекта в экранной системе координат.
virtual int state_index(const char *state_name) const =0
Возвращает номер состояния с именем state_name.
Нажатие левой кнопки.
Definition: qd_minigame_interface.h:372
Definition: qd_minigame_interface.h:78
bool init(const qdEngineInterface *engine_interface)
Инициализация игры.
Definition: puzzle_all.h:86
bool quant(float dt)
Обсчёт логики игры, параметр - время, которое должно пройти в игре (в секундах).
Definition: puzzle_all.h:140
virtual mgVect2i mouse_cursor_position() const =0
Возвращает текущие координаты мышиного курсора.
Definition: qd_minigame_interface.h:365
virtual bool is_state_active(const char *state_name) const =0
Возвращает true, если состояние с именем state_name включено в данный момент.
Базовый класс для игровых ресурсов.
Definition: console.h:28
Нажатие правой кнопки.
Definition: qd_minigame_interface.h:374
virtual float screen_depth(const mgVect3f &pos) const =0
Возвращает "глубину" точки с координатами pos в мировой системе координат
Интерфейс к динамическому объекту.
Definition: qd_minigame_interface.h:230
Definition: puzzle_all.h:78
Интерфейс к сцене.
Definition: qd_minigame_interface.h:315
virtual bool set_state(const char *state_name)=0
Включает состояние с именем state_name.
virtual void set_R(const mgVect3f &r)=0
Устанавливает координаты объекта в мировой системе координат.
virtual qdMinigameObjectInterface * object_interface(const char *object_name)=0
Создаёт интерфейс к объекту с именем object_name.
bool new_game(const qdEngineInterface *engine_interface)
Инициализация миниигры, вызывается при старте и перезапуске игры.
Definition: puzzle_all.h:294
virtual bool is_mouse_event_active(qdMinigameMouseEvent event_id) const =0
Возвращает true, если в данный момент произошло событие event_id.
void void void void void debugC(int level, uint32 debugChannels, MSVC_PRINTF const char *s,...) GCC_PRINTF(3
T ABS(T x)
Definition: util.h:56
int load_game(const qdEngineInterface *engine_interface, const qdMinigameSceneInterface *scene_interface, const char *buffer, int buffer_size)
Загрузка данных, вызывается при загрузке сцены, на которую повешена миниигра.
Definition: puzzle_all.h:302
bool finit()
Деинициализация игры.
Definition: puzzle_all.h:283
Language
Definition: language.h:45
virtual qdMinigameObjectInterface * mouse_object_interface() const =0
Создаёт интерфейс к объекту, который взят мышью в данный момент.