ScummVM API documentation
shveik_shkatulka.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_SHVEIK_SHKATULKA_H
23 #define QDENGINE_MINIGAMES_SHVEIK_SHKATULKA_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:
36 
37  bool init(const qdEngineInterface *engine_interface) {
38  debugC(1, kDebugMinigames, "ShveikShkatulka::init()");
39 
40  _engine = engine_interface;
41  _scene = engine_interface->current_scene_interface();
42  if (!_scene)
43  return false;
44 
45  _stones[0] = _scene->object_interface("\xea\xe0\xec\xe5\xed\xfc\x31"); // "камень1"
46  _stones[1] = _scene->object_interface("\xea\xe0\xec\xe5\xed\xfc\x32"); // "камень2"
47  _stones[2] = _scene->object_interface("\xea\xe0\xec\xe5\xed\xfc\x33"); // "камень3"
48  _stones[3] = _scene->object_interface("\xea\xe0\xec\xe5\xed\xfc\x34"); // "камень4"
49  _stones[4] = _scene->object_interface("\xea\xe0\xec\xe5\xed\xfc\x35"); // "камень5"
50  _stones[5] = _scene->object_interface("\xea\xe0\xec\xe5\xed\xfc\x36"); // "камень6"
51  _stones[6] = _scene->object_interface("\xea\xe0\xec\xe5\xed\xfc\x37"); // "камень7"
52  _stones[7] = _scene->object_interface("\xea\xe0\xec\xe5\xed\xfc\x38"); // "камень8"
53  _stones[8] = _scene->object_interface("\xea\xe0\xec\xe5\xed\xfc\x39"); // "камень9"
54  _stones[9] = _scene->object_interface("\xea\xe0\xec\xe5\xed\xfc\x31\x30"); // "камень10"
55  _stones[10] = _scene->object_interface("\xea\xe0\xec\xe5\xed\xfc\x31\x31"); // "камень11"
56  _stones[11] = _scene->object_interface("\xea\xe0\xec\xe5\xed\xfc\x31\x32"); // "камень12"
57  _stones[12] = _scene->object_interface("\xea\xe0\xec\xe5\xed\xfc\x31\x33"); // "камень13"
58  _stones[13] = _scene->object_interface("\xea\xe0\xec\xe5\xed\xfc\x31\x34"); // "камень14"
59 
60  _cursorObj = _scene->object_interface("\xea\xf3\xf0\xf1\xee\xf0"); // "курсор"
61  _doneObj = _scene->object_interface("$done");
62  _startObj = _scene->object_interface("\x24\xe7\xe0\xef\xf3\xf1\xea"); // "$запуск"
63  _jumpSoundObj = _scene->object_interface("\xe7\xe2\xf3\xea\x20\xef\xe5\xf0\xe5\xf1\xea\xee\xea\xe0"); // "звук перескока"
64 
65  _direction = kDirNone;
66  _cursorTakenFlag = 0;
67  _someVar3 = 0;
68  _needSnap = false;
69 
70  if (_startObj->is_state_active("\xed\xe5\x20\xe1\xfb\xeb")) { // "не был"
71  resetStones();
72  _startObj->set_state("\xe1\xfb\xeb"); // "был"
73  }
74 
75  return true;
76  }
77 
78  enum {
79  kDirNone,
80  kDirUp,
81  kDirRight,
82  kDirDown,
83  kDirLeft
84  };
85 
86  bool quant(float dt) {
87  debugC(3, kDebugMinigames, "ShveikShkatulka::quant(%f)", dt);
88 
89  if (checkSolution()) {
90  _doneObj->set_state("\xe4\xe0"); // "да"
91  _cursorObj->set_state("nottaken");
92  _draggedStone = 0;
93  _direction = kDirNone;
94  _cursorTakenFlag = 0;
95  _someVar3 = 0;
96  _needSnap = 0;
97 
98  return true;
99  }
100 
102  && _scene->mouse_click_object_interface()) {
103  const char *state = _scene->mouse_click_object_interface()->current_state_name();
104 
105  if (state[0] == '1' || state[0] == '2') {
106  _draggedStone = _scene->mouse_click_object_interface();
107 
108  _mousePos = _engine->mouse_cursor_position();
109  _cursorTakenFlag = 1;
110  _someVar3 = 1;
111  } else if (state[0] == '0') {
112  resetStones();
113  }
114  }
115 
116  if (_engine->is_mouse_event_active(qdmg::qdEngineInterfaceImpl::MOUSE_EV_LEFT_UP) && _cursorTakenFlag) {
117  _draggedStone = 0;
118  _cursorTakenFlag = 0;
119  _someVar3 = 0;
120  _needSnap = false;
121  _direction = kDirNone;
122  }
123 
124  mgVect2i curPos = _engine->mouse_cursor_position();
125 
126  if (_cursorTakenFlag) {
127  if (!_needSnap) {
128  _mouseDelta.x = curPos.x - _mousePos.x;
129  _mouseDelta.y = curPos.y - _mousePos.y;
130 
131  if (ABS(_mouseDelta.x) <= ABS(_mouseDelta.y)) { // Going down
132  const char *state = _draggedStone->current_state_name();
133  int draggedStonePos;
134 
135  if (state[2] == '\0')
136  draggedStonePos = state[1] - '0';
137  else if (state[2] == '0')
138  draggedStonePos = 10;
139  else
140  draggedStonePos = 11;
141 
142  int off = 60;
143  if (draggedStonePos == 3 || draggedStonePos == 8) {
144  int delta = 0;
145 
146  if (curPos.y <= _mousePos.y) {
147  if (draggedStonePos == 3)
148  delta = 186;
149  else
150  delta = 0;
151  } else {
152  if (draggedStonePos == 8)
153  delta = 196;
154  else
155  delta = 0;
156  }
157  off = delta + 150;
158  }
159 
160  if (ABS(_mouseDelta.y) > off) {
161  if (curPos.y <= _mousePos.y)
162  _direction = kDirUp;
163  else
164  _direction = kDirDown;
165 
166  _needSnap = true;
167  }
168  } else if (ABS(_mouseDelta.x) > 60) {
169  if (curPos.x <= _mousePos.x)
170  _direction = kDirLeft;
171  else
172  _direction = kDirRight;
173 
174  _needSnap = true;
175  }
176  }
177 
178  if (_cursorTakenFlag && _needSnap) {
179  const char *state = _draggedStone->current_state_name();
180  int draggedStonePos;
181 
182  if (state[2] == '\0')
183  draggedStonePos = state[1] - '0';
184  else if (state[2] == '0')
185  draggedStonePos = 10;
186  else
187  draggedStonePos = 11;
188 
189  int side = state[0] - '0';
190  int pos = -1;
191 
192  if (side == 1) {
193  switch (_direction) {
194  case kDirUp:
195  if (draggedStonePos != 8 || checkStonePosition(3, 1) || checkStonePosition(8, 2))
196  break;
197 
198  pos = 3;
199  break;
200  case kDirRight:
201  if (draggedStonePos == 4
202  || draggedStonePos == 11
203  || checkStonePosition(draggedStonePos + 1, 1)
204  || checkStonePosition(draggedStonePos, 2))
205  break;
206 
207  pos = draggedStonePos + 1;
208  break;
209  case kDirDown:
210  if (draggedStonePos != 3 || checkStonePosition(8, 1) || checkStonePosition(8, 2))
211  break;
212 
213  pos = 8;
214  break;
215  case kDirLeft:
216  if (draggedStonePos == 1
217  || draggedStonePos == 5
218  || checkStonePosition(draggedStonePos - 1, 1)
219  || checkStonePosition(draggedStonePos - 1, 2))
220  break;
221 
222  pos = draggedStonePos - 1;
223  break;
224 
225  default:
226  break;
227  }
228  } else {
229  switch (_direction) {
230  case kDirUp:
231  if (draggedStonePos != 8 || checkStonePosition(3, 1) || checkStonePosition(3, 2))
232  break;
233 
234  pos = 3;
235  break;
236 
237  case kDirRight:
238  if (draggedStonePos == 4
239  || draggedStonePos == 11
240  || checkStonePosition(draggedStonePos + 1, 1)
241  || checkStonePosition(draggedStonePos + 1, 2))
242  break;
243 
244  pos = draggedStonePos + 1;
245  break;
246 
247  case kDirDown:
248  if (draggedStonePos != 3 || checkStonePosition(8, 2) || checkStonePosition(3, 1))
249  break;
250 
251  pos = 8;
252  break;
253 
254  case kDirLeft:
255  if (draggedStonePos == 1
256  || draggedStonePos == 5
257  || checkStonePosition(draggedStonePos, 1)
258  || checkStonePosition(draggedStonePos - 1, 2))
259  break;
260 
261  pos = draggedStonePos - 1;
262  break;
263 
264  default:
265  break;
266  }
267  }
268 
269  if (pos == -1) {
270  _cursorTakenFlag = 0;
271  _someVar3 = 0;
272  } else {
273  _draggedStone->set_state(Common::String::format("%d%d", side, pos).c_str());
274  _mousePos = curPos;
275  _jumpSoundObj->set_state("\xe4\xe0"); // "да"
276  }
277 
278  _direction = kDirNone;
279  _needSnap = false;
280  }
281  }
282 
283  if (_cursorTakenFlag)
284  _cursorObj->set_state("taken");
285  else
286  _cursorObj->set_state("nottaken");
287 
288  return true;
289  }
290 
291  bool finit() {
292  debugC(1, kDebugMinigames, "ShveikShkatulka::finit()");
293 
294  if (_scene) {
295  _engine->release_scene_interface(_scene);
296  _scene = 0;
297  }
298 
299  return true;
300  }
301 
302  bool new_game(const qdEngineInterface *engine_interface) {
303  return true;
304  }
305 
306  int save_game(const qdEngineInterface *engine_interface, const qdMinigameSceneInterface *scene_interface, char *buffer, int buffer_size) {
307  return 0;
308  }
309 
310  int load_game(const qdEngineInterface *engine_interface, const qdMinigameSceneInterface *scene_interface, const char *buffer, int buffer_size) {
311  return 0;
312  }
313 
314  enum { INTERFACE_VERSION = 112 };
315  int version() const {
316  return INTERFACE_VERSION;
317  }
318 
319 private:
320  void resetStones() {
321  _stones[0]->set_state("15");
322  _stones[1]->set_state("16");
323  _stones[2]->set_state("17");
324  _stones[3]->set_state("110");
325  _stones[4]->set_state("11");
326  _stones[5]->set_state("12");
327  _stones[6]->set_state("14");
328  _stones[7]->set_state("26");
329  _stones[8]->set_state("27");
330  _stones[9]->set_state("210");
331  _stones[10]->set_state("211");
332  _stones[11]->set_state("21");
333  _stones[12]->set_state("22");
334  _stones[13]->set_state("24");
335  }
336 
337  bool checkSolution() {
338  return
339  _stones[0]->is_state_active("110")
340  && _stones[1]->is_state_active("16")
341  && _stones[2]->is_state_active("17")
342  && _stones[3]->is_state_active("18")
343  && _stones[4]->is_state_active("15")
344  && _stones[5]->is_state_active("111")
345  && _stones[6]->is_state_active("19")
346  && _stones[7]->is_state_active("26")
347  && _stones[8]->is_state_active("28")
348  && _stones[9]->is_state_active("210")
349  && _stones[10]->is_state_active("211")
350  && _stones[11]->is_state_active("29")
351  && _stones[12]->is_state_active("27")
352  && _stones[13]->is_state_active("25");
353  }
354 
355  bool checkStonePosition(int targetPos, int leftStones) {
356  int n = leftStones == 1 ? 0 : 7;
357 
358  for (int i = 0; i < 7; i++) {
359  const char *state = _stones[n + i]->current_state_name();
360  int pos;
361 
362  if (state[2] == '\0')
363  pos = state[1] - '0';
364  else if (state[2] == '0')
365  pos = 10;
366  else
367  pos = 11;
368 
369  if (pos == targetPos)
370  return true;
371  }
372 
373  return false;
374  }
375 
376 private:
377  const qdEngineInterface *_engine = nullptr;
378  qdMinigameSceneInterface *_scene = nullptr;
379 
380  int _direction = kDirNone;
381  bool _cursorTakenFlag = false;
382 
383  mgVect2i _mousePos;
384  mgVect2i _mouseDelta;
385  int _someVar3 = 0;
386  bool _needSnap = false;
387 
388  qdMinigameObjectInterface *_stones[14] = { nullptr };
389  qdMinigameObjectInterface *_draggedStone = nullptr;
390  qdMinigameObjectInterface *_cursorObj = nullptr;
391  qdMinigameObjectInterface *_doneObj = nullptr;
392  qdMinigameObjectInterface *_startObj = nullptr;
393  qdMinigameObjectInterface *_jumpSoundObj = nullptr;
394 };
395 
396 } // namespace QDEngine
397 
398 #endif // QDENGINE_MINIGAMES_SHVEIK_SHKATULKA_H
bool init(const qdEngineInterface *engine_interface)
Инициализация игры.
Definition: shveik_shkatulka.h:37
static String format(MSVC_PRINTF const char *fmt,...) GCC_PRINTF(1
Отжатие левой кнопки.
Definition: qd_minigame_interface.h:380
Нажатие левой кнопки.
Definition: qd_minigame_interface.h:372
Definition: qd_minigame_interface.h:78
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
int load_game(const qdEngineInterface *engine_interface, const qdMinigameSceneInterface *scene_interface, const char *buffer, int buffer_size)
Загрузка данных, вызывается при загрузке сцены, на которую повешена миниигра.
Definition: shveik_shkatulka.h:310
virtual qdMinigameObjectInterface * mouse_click_object_interface() const =0
Создаёт интерфейс к объекту, по которому кликнули мышью.
int save_game(const qdEngineInterface *engine_interface, const qdMinigameSceneInterface *scene_interface, char *buffer, int buffer_size)
Сохранение данных, вызывается при сохранении сцены, на которую повешена миниигра. ...
Definition: shveik_shkatulka.h:306
bool new_game(const qdEngineInterface *engine_interface)
Инициализация миниигры, вызывается при старте и перезапуске игры.
Definition: shveik_shkatulka.h:302
Интерфейс к динамическому объекту.
Definition: qd_minigame_interface.h:230
virtual const char * current_state_name() const =0
Интерфейс к сцене.
Definition: qd_minigame_interface.h:315
virtual bool set_state(const char *state_name)=0
Включает состояние с именем state_name.
bool quant(float dt)
Обсчёт логики игры, параметр - время, которое должно пройти в игре (в секундах).
Definition: shveik_shkatulka.h:86
Definition: shveik_shkatulka.h:32
virtual qdMinigameObjectInterface * object_interface(const char *object_name)=0
Создаёт интерфейс к объекту с именем object_name.
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
bool finit()
Деинициализация игры.
Definition: shveik_shkatulka.h:291