ScummVM API documentation
kartiny.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_KARTINY_H
23 #define QDENGINE_MINIGAMES_KARTINY_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 
33 public:
35  ~qdKartinyMiniGame() {}
36 
37  bool init(const qdEngineInterface *engine_interface) {
38  debugC(1, kDebugMinigames, "Kartiny::init()");
39 
40  _engine = engine_interface;
41  _scene = engine_interface->current_scene_interface();
42  if (!_scene)
43  return 0;
44 
45  _bg_clickObj = _scene->object_interface(_scene->minigame_parameter("zad_click_flag_name"));
46  _bg1_l2Obj = _scene->object_interface(_scene->minigame_parameter("zad1_l2_object_name"));
47  _bg2_l2Obj = _scene->object_interface(_scene->minigame_parameter("zad2_l2_object_name"));
48  _bg3_l2Obj = _scene->object_interface(_scene->minigame_parameter("zad3_l2_object_name"));
49  _bg4_l2Obj = _scene->object_interface(_scene->minigame_parameter("zad4_l2_object_name"));
50  _doneObj = _scene->object_interface(_scene->minigame_parameter("done"));
51  _startObj = _scene->object_interface(_scene->minigame_parameter("start"));
52  _activateObj = _scene->object_interface(_scene->minigame_parameter("activate"));
53  _zFlagObj = _scene->object_interface(_scene->minigame_parameter("z_flag"));
54  _startObj2 = _scene->object_interface(_scene->minigame_parameter("start"));
55 
56  _wasInited = 0;
57  _artDepth = -1.0;
58  return true;
59  }
60 
61  bool quant(float dt) {
62  debugC(3, kDebugMinigames, "Kartiny::quant(%f)", dt);
63 
64  mgVect3f newPiecePos;
65  mgVect2i piecePos;
66 
67  float depth1 = _scene->screen_depth(_bg1_l2Obj->R());
68  float depth2 = _scene->screen_depth(_bg2_l2Obj->R());
69  float depth3 = _scene->screen_depth(_bg3_l2Obj->R());
70  float depth4 = _scene->screen_depth(_bg4_l2Obj->R());
71 
72  if (depth4 >= depth3 || depth3 >= depth2 || depth2 >= depth1)
73  _zFlagObj->set_state("\xed\xe5\xf2"); // "нет"
74  else
75  _zFlagObj->set_state("\xe4\xe0"); // "да"
76 
77  if (!_wasInited) {
78  if (_startObj->is_state_active("\xe7\xe0\xe4\xed\xe8\xea\xe8 \xee\xef\xf3\xf9\xe5\xed\xfb")) // "задники опущены"
79  _wasInited = 1;
80 
81  if (!_wasInited) {
82  if (_startObj->is_state_active("\xed\xe5\xf2")) { // "нет"
83  _bg1_l2Obj->set_R(_scene->screen2world_coords(mgVect2i(400, -300), 600.0));
84  _bg2_l2Obj->set_R(_scene->screen2world_coords(mgVect2i(200, -300), 400.0));
85  _bg3_l2Obj->set_R(_scene->screen2world_coords(mgVect2i(400, -300), 200.0));
86  _bg4_l2Obj->set_R(_scene->screen2world_coords(mgVect2i(600, -300), 0.0));
87 
88  _stage = 4;
89  _artDepth = -50.0;
90 
91  _activateObj->set_state("\xe7\xe0\xe4\xed\xe8\xea\x34"); // "задник4"
92  _startObj->set_state("\xe4\xe0"); // "да"
93  } else {
94  if (_startObj->is_state_active("\xe4\xe0")) { // "да"
95  if (_bg1_l2Obj->screen_R().y < 100) {
96  piecePos.x = 400;
97  piecePos.y = _bg1_l2Obj->screen_R().y + 3;
98  _bg1_l2Obj->set_R(_scene->screen2world_coords(piecePos, 600.0));
99  }
100 
101  if (_bg2_l2Obj->screen_R().y < 50) {
102  piecePos.x = 200;
103  piecePos.y = _bg2_l2Obj->screen_R().y + 2;
104  _bg2_l2Obj->set_R(_scene->screen2world_coords(piecePos, 400.0));
105  }
106 
107  if (_bg3_l2Obj->screen_R().y < 85) {
108  piecePos.x = 400;
109  piecePos.y = _bg3_l2Obj->screen_R().y + 2;
110  _bg3_l2Obj->set_R(_scene->screen2world_coords(piecePos, 200.0));
111  }
112 
113  if (_bg4_l2Obj->screen_R().y < 0) {
114  piecePos.x = 600;
115  piecePos.y = _bg4_l2Obj->screen_R().y + 2;
116  _bg4_l2Obj->set_R(_scene->screen2world_coords(piecePos, 0.0));
117  }
118 
119  if (_bg1_l2Obj->screen_R().y >= 100
120  && _bg2_l2Obj->screen_R().y >= 50
121  && _bg3_l2Obj->screen_R().y >= 85
122  && _bg4_l2Obj->screen_R().y >= 0) {
123  _wasInited = 1;
124  _startObj->set_state("\xe7\xe0\xe4\xed\xe8\xea\xe8 \xee\xef\xf3\xf9\xe5\xed\xfb"); // "задники опущены"
125  }
126  }
127 
128  if (_startObj->is_state_active("\xe7\xe0\xe4\xed\xe8\xea\xe8 \xee\xef\xf3\xf9\xe5\xed\xfb") // "задники опущены"
129  && _artDepth == -1.0) {
130  _artState[0].depth = _scene->screen_depth(_bg1_l2Obj->R());
131  _artState[0].num = 1;
132  _artState[1].depth = _scene->screen_depth(_bg2_l2Obj->R());
133  _artState[1].num = 2;
134  _artState[2].depth = _scene->screen_depth(_bg3_l2Obj->R());
135  _artState[2].num = 3;
136  _artState[3].depth = _scene->screen_depth(_bg4_l2Obj->R());
137  _artState[3].num = 4;
138 
139  // Sort
140  for (int i = 0; i < 3; i++) {
141  while (_artState[i + 1].depth < _artState[i].depth) {
142  int num = _artState[i].num;
143  float depth = _artState[i].depth;
144 
145  _artState[i].depth = _artState[i + 1].depth;
146  _artState[i].num = _artState[i + 1].num;
147  _artState[i + 1].depth = depth;
148  _artState[i + 1].num = num;
149 
150  i = 0;
151  }
152  }
153 
154  _wasInited = 1;
155 
156  _stage = _artState[0].num;
157  _artDepth = _artState[0].depth;
158  }
159  }
160  }
161  }
162 
163  if (!checkSolution() && _wasInited) {
164  _doneObj->set_state("false");
165 
166  if (_engine->is_key_pressed(VK_LEFT)
167  || _engine->is_key_pressed(VK_RIGHT)
168  || _engine->is_key_pressed(VK_UP)
169  || _engine->is_key_pressed(VK_DOWN)) {
170  ++_keyDownCounter;
171  } else {
172  _keyDownCounter = 0;
173  }
174 
175  if (_engine->is_key_pressed(VK_LEFT)) {
176  switch (_stage) {
177  case 1:
178  moveLeft(_bg1_l2Obj);
179  break;
180  case 2:
181  moveLeft(_bg2_l2Obj);
182  break;
183  case 3:
184  moveLeft(_bg3_l2Obj);
185  break;
186  case 4:
187  moveLeft(_bg4_l2Obj);
188  break;
189  default:
190  break;
191  }
192  }
193 
194  if (_engine->is_key_pressed(VK_RIGHT)) {
195  switch (_stage) {
196  case 1:
197  moveRight(_bg1_l2Obj);
198  break;
199  case 2:
200  moveRight(_bg2_l2Obj);
201  break;
202  case 3:
203  moveRight(_bg3_l2Obj);
204  break;
205  case 4:
206  moveRight(_bg4_l2Obj);
207  break;
208  default:
209  break;
210  }
211  }
212 
213  if (_engine->is_key_pressed(VK_UP)) {
214  switch (_stage) {
215  case 1:
216  moveUp(_bg1_l2Obj);
217  break;
218  case 2:
219  moveUp(_bg2_l2Obj);
220  break;
221  case 3:
222  moveUp(_bg3_l2Obj);
223  break;
224  case 4:
225  moveUp(_bg4_l2Obj);
226  break;
227  default:
228  break;
229  }
230  }
231 
232  if (_engine->is_key_pressed(VK_DOWN)) {
233  switch (_stage) {
234  case 1:
235  moveDown(_bg1_l2Obj);
236  break;
237  case 2:
238  moveDown(_bg2_l2Obj);
239  break;
240  case 3:
241  moveDown(_bg3_l2Obj);
242  break;
243  case 4:
244  moveDown(_bg4_l2Obj);
245  break;
246  default:
247  break;
248  }
249  }
250 
251  if ((_bg_clickObj->is_state_active("zad1_level2")
252  || _activateObj->is_state_active("\xe7\xe0\xe4\xed\xe8\xea\x31")) && _stage != 1) { // "задник1"
253  _stage = 1;
254  _activateObj->set_state("\xe7\xe0\xe4\xed\xe8\xea\x31"); // "задник1"
255  _artDepth -= 200.0;
256  _bg1_l2Obj->set_R(_scene->screen2world_coords(_bg1_l2Obj->screen_R(), _artDepth));
257 
258  snapPieces();
259  }
260 
261  if ((_bg_clickObj->is_state_active("zad2_level2")
262  || _activateObj->is_state_active("\xe7\xe0\xe4\xed\xe8\xea\x32")) && _stage != 2) { // "задник2"
263  _stage = 2;
264  _activateObj->set_state("\xe7\xe0\xe4\xed\xe8\xea\x32"); // "задник2"
265  _artDepth -= 200.0;
266  _bg2_l2Obj->set_R(_scene->screen2world_coords(_bg2_l2Obj->screen_R(), _artDepth));
267 
268  snapPieces();
269  }
270 
271  if ((_bg_clickObj->is_state_active("zad3_level2")
272  || _activateObj->is_state_active("\xe7\xe0\xe4\xed\xe8\xea\x33")) && _stage != 3) { // "задник3"
273  _stage = 3;
274  _activateObj->set_state("\xe7\xe0\xe4\xed\xe8\xea\x33"); // "задник3"
275  _artDepth -= 200.0;
276  _bg3_l2Obj->set_R(_scene->screen2world_coords(_bg3_l2Obj->screen_R(), _artDepth));
277 
278  snapPieces();
279  }
280 
281  if ((_bg_clickObj->is_state_active("zad4_level2")
282  || _activateObj->is_state_active("\xe7\xe0\xe4\xed\xe8\xea\x34")) && _stage != 4) { // "задник4"
283  _stage = 4;
284  _activateObj->set_state("\xe7\xe0\xe4\xed\xe8\xea\x34"); // "задник4"
285  _artDepth -= 200.0;
286  _bg4_l2Obj->set_R(_scene->screen2world_coords(_bg4_l2Obj->screen_R(), _artDepth));
287 
288  snapPieces();
289  }
290  }
291 
292  return true;
293  }
294 
295  bool finit() {
296  debugC(1, kDebugMinigames, "Kartiny::finit()");
297 
298  if (_scene) {
299  _engine->release_scene_interface(_scene);
300  _scene = 0;
301  }
302 
303  return true;
304  }
305 
306  bool new_game(const qdEngineInterface *engine_interface) {
307  return true;
308  }
309 
310  int save_game(const qdEngineInterface *engine_interface, const qdMinigameSceneInterface *scene_interface, char *buffer, int buffer_size) {
311  return 0;
312  }
313 
314  int load_game(const qdEngineInterface *engine_interface, const qdMinigameSceneInterface *scene_interface, const char *buffer, int buffer_size) {
315  return 0;
316  }
317 
318  enum { INTERFACE_VERSION = 99 };
319  int version() const {
320  return INTERFACE_VERSION;
321  }
322 
323 private:
324  void snapPieces() {
325  mgVect2i piecePos;
326  mgVect3f newPiecePos;
327  float depth;
328 
329  piecePos = _bg1_l2Obj->screen_R();
330  depth = _scene->screen_depth(_bg1_l2Obj->R());
331 
332  if (ABS(399 - ABS(piecePos.x)) <= 10 && ABS(278 - ABS(piecePos.y)) <= 10) {
333  piecePos.x = 399;
334  piecePos.y = 278;
335 
336  newPiecePos = _scene->screen2world_coords(piecePos, depth);
337  _bg1_l2Obj->set_R(newPiecePos);
338  }
339 
340  piecePos = _bg2_l2Obj->screen_R();
341  depth = _scene->screen_depth(_bg2_l2Obj->R());
342 
343  if (piecePos.x >= 387 && piecePos.x <= 440 && ABS(267 - ABS(piecePos.y)) <= 20) {
344  piecePos.x = 408;
345  piecePos.y = 267;
346 
347  newPiecePos = _scene->screen2world_coords(piecePos, depth);
348  _bg2_l2Obj->set_R(newPiecePos);
349  }
350 
351  piecePos = _bg3_l2Obj->screen_R();
352  depth = _scene->screen_depth(_bg3_l2Obj->R());
353 
354  if (ABS(ABS(piecePos.x) - 413) < 25 && ABS(ABS(piecePos.y) - 43) < 40) {
355  piecePos.x = 406;
356  piecePos.y = -43;
357 
358  newPiecePos = _scene->screen2world_coords(piecePos, depth);
359  _bg3_l2Obj->set_R(newPiecePos);
360  }
361  }
362 
363  void moveDown(qdMinigameObjectInterface *obj) {
364  int speed = MAX(10, _keyDownCounter / 10 + 1);
365  int maxCoords;
366 
367  if (obj == _bg1_l2Obj)
368  maxCoords = 279;
369  else if (obj == _bg2_l2Obj)
370  maxCoords = 267;
371  // FIXME: Remove this as covered by the default case?
372  //else if (obj == _bg3_l2Obj)
373  // maxCoords = 258;
374  else
375  maxCoords = 258;
376 
377  mgVect2i objPos = obj->screen_R();
378 
379  if (objPos.y + speed < maxCoords)
380  objPos.y += speed;
381 
382  obj->set_R(_scene->screen2world_coords(objPos, _artDepth));
383  }
384 
385  void moveUp(qdMinigameObjectInterface *obj) {
386  int speed = MAX(10, _keyDownCounter / 10 + 1);
387  mgVect2i objPos = obj->screen_R();
388 
389  if (objPos.y > -100)
390  objPos.y -= speed;
391 
392  obj->set_R(_scene->screen2world_coords(objPos, _artDepth));
393  }
394 
395  void moveRight(qdMinigameObjectInterface *obj) {
396  int speed = MAX(10, _keyDownCounter / 10 + 1);
397  mgVect2i objPos = obj->screen_R();
398 
399  if (objPos.x < 900)
400  objPos.x += speed;
401 
402  obj->set_R(_scene->screen2world_coords(objPos, _artDepth));
403  }
404 
405  void moveLeft(qdMinigameObjectInterface *obj) {
406  int speed = MAX(10, _keyDownCounter / 10 + 1);
407  mgVect2i objPos = obj->screen_R();
408 
409  if (objPos.x > -100)
410  objPos.x -= speed;
411 
412  obj->set_R(_scene->screen2world_coords(objPos, _artDepth));
413  }
414 
415  bool checkSolution() {
416  if (_scene->screen_depth(_bg1_l2Obj->R()) < _scene->screen_depth(_bg2_l2Obj->R()))
417  return false;
418 
419  if (_scene->screen_depth(_bg2_l2Obj->R()) < _scene->screen_depth(_bg3_l2Obj->R()))
420  return false;
421 
422  if (_scene->screen_depth(_bg3_l2Obj->R()) < _scene->screen_depth(_bg4_l2Obj->R()))
423  return false;
424 
425  if (ABS(_bg1_l2Obj->screen_R().x - 399) > 5
426  || ABS(_bg1_l2Obj->screen_R().y - 278) > 5
427  || (ABS(_bg2_l2Obj->screen_R().x - 407) > 10
428  && ABS(_bg2_l2Obj->screen_R().x - 420) > 10)) // copy/paste error in the originaL?
429  return false;
430 
431  if (ABS(_bg2_l2Obj->screen_R().y - 267) > 10)
432  return false;
433 
434  if (_bg2_l2Obj->screen_R().x - _bg3_l2Obj->screen_R().x > 6)
435  return false;
436 
437  if (_bg3_l2Obj->screen_R().x - _bg2_l2Obj->screen_R().x > 5)
438  return false;
439 
440  if (ABS(_bg3_l2Obj->screen_R().y + 43) > 10)
441  return false;
442 
443  if (_bg4_l2Obj->screen_R().x - _bg3_l2Obj->screen_R().x > 5)
444  return false;
445 
446  if (_bg3_l2Obj->screen_R().x - _bg4_l2Obj->screen_R().x > 3)
447  return false;
448 
449  if (ABS(_bg4_l2Obj->screen_R().y + 42) > 10)
450  return false;
451 
452  if (ABS(_bg4_l2Obj->screen_R().y) - ABS(_bg3_l2Obj->screen_R().y) > 3)
453  return false;
454 
455 
456  _doneObj->set_state("true");
457 
458  return true;
459  }
460 
461 private:
462  const qdEngineInterface *_engine = nullptr;
463  qdMinigameSceneInterface *_scene = nullptr;
464 
465  qdMinigameObjectInterface *_bg_clickObj = nullptr;
466  qdMinigameObjectInterface *_bg1_l2Obj = nullptr;
467  qdMinigameObjectInterface *_bg2_l2Obj = nullptr;
468  qdMinigameObjectInterface *_bg3_l2Obj = nullptr;
469  qdMinigameObjectInterface *_bg4_l2Obj = nullptr;
470  qdMinigameObjectInterface *_doneObj = nullptr;
471  qdMinigameObjectInterface *_startObj = nullptr;
472  qdMinigameObjectInterface *_activateObj = nullptr;
473  qdMinigameObjectInterface *_zFlagObj = nullptr;
474  qdMinigameObjectInterface *_startObj2 = nullptr;
475 
476  bool _wasInited = false;
477  float _artDepth = -1.0;
478  int _keyDownCounter = 0;
479 
480  int _stage = 0;
481 
482  struct {
483  float depth = 0;
484  int num = 0;
485  } _artState[4];
486 };
487 
488 } // namespace QDEngine
489 
490 #endif // QDENGINE_MINIGAMES_KARTINY_H
virtual mgVect3f R() const =0
Возвращает координаты объекта в мировой системе координат.
virtual mgVect3f screen2world_coords(const mgVect2i &screen_pos, float screen_depth=0) const =0
Преобразование из экранных координат в мировые.
bool quant(float dt)
Обсчёт логики игры, параметр - время, которое должно пройти в игре (в секундах).
Definition: kartiny.h:61
virtual mgVect2i screen_R() const =0
Возвращает координаты объекта в экранной системе координат.
Definition: kartiny.h:32
virtual bool is_key_pressed(int vkey) const =0
Возвращает true, если на клавиатуре нажата кнопка vkey.
Definition: qd_minigame_interface.h:78
int load_game(const qdEngineInterface *engine_interface, const qdMinigameSceneInterface *scene_interface, const char *buffer, int buffer_size)
Загрузка данных, вызывается при загрузке сцены, на которую повешена миниигра.
Definition: kartiny.h:314
Definition: qd_minigame_interface.h:365
int save_game(const qdEngineInterface *engine_interface, const qdMinigameSceneInterface *scene_interface, char *buffer, int buffer_size)
Сохранение данных, вызывается при сохранении сцены, на которую повешена миниигра. ...
Definition: kartiny.h:310
virtual bool is_state_active(const char *state_name) const =0
Возвращает true, если состояние с именем state_name включено в данный момент.
Базовый класс для игровых ресурсов.
Definition: console.h:28
virtual float screen_depth(const mgVect3f &pos) const =0
Возвращает "глубину" точки с координатами pos в мировой системе координат
Интерфейс к динамическому объекту.
Definition: qd_minigame_interface.h:230
bool init(const qdEngineInterface *engine_interface)
Инициализация игры.
Definition: kartiny.h:37
Интерфейс к сцене.
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: kartiny.h:306
T MAX(T a, T b)
Definition: util.h:62
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
bool finit()
Деинициализация игры.
Definition: kartiny.h:295