ScummVM API documentation
masky_order.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_MASKY_ORDER_H
23 #define QDENGINE_MINIGAMES_MASKY_ORDER_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 pieceCoordsFront[24] = {
33  280, 93, 284, 163, 394, 140, 505, 120, 511, 225,
34  392, 255, 296, 288, 444, 369, 309, 406, 446, 479,
35  289, 478, 548, 420,
36 };
37 
38 const int pieceCoordsBack[24] = {
39  516, 94, 511, 162, 398, 139, 293, 120, 286, 227,
40  404, 247, 500, 287, 353, 363, 488, 407, 354, 476,
41  508, 478, 247, 420,
42 };
43 
44 
46 public:
48  for (uint i = 0; i < ARRAYSIZE(_pieces); i++)
49  _pieces[i] = nullptr;
50  }
52 
53  bool init(const qdEngineInterface *engine_interface) {
54  debugC(1, kDebugMinigames, "MaskyOrder::init()");
55 
56  _engine = engine_interface;
57  _scene = _engine->current_scene_interface();
58  if (!_scene)
59  return false;
60 
61  for (int i = 0; i < 12; i++)
62  _pieces[i] = _scene->object_interface(_scene->minigame_parameter(Common::String::format("object_%i", i + 1).c_str()));
63 
64  _finalObj = _scene->object_interface(_scene->minigame_parameter("final"));
65  _doneObj = _scene->object_interface(_scene->minigame_parameter("done_object"));
66  _object3Flag = _scene->object_interface(_scene->minigame_parameter("object_3_flag"));
67  _loadGameObj = _scene->object_interface(_scene->minigame_parameter("loadgame"));
68 
69  _wasInited = false;
70 
71  _isFinal = false;
72  _minDepthPiece = findMinDepthPiece();
73 
74  return true;
75  }
76 
77  bool quant(float dt) {
78  debugC(3, kDebugMinigames, "MaskyOrder::quant(%f)", dt);
79 
80  if (!_wasInited && _loadGameObj->is_state_active("\xed\xe5\xf2")) { // "нет"
81  _rotatingPiece = -1;
82  _currentPieceState = -1;
83  _pieceIsPut = false;
84  _isFinal = false;
85  _flipped = false;
86  _wasInited = true;
87  _loadGameObj->set_state("\xe4\xe0"); // "да"
88  }
89 
90  if ( _object3Flag->is_state_active("\xe4\xe0")) { // "да"
91  _flipped = true;
92  _pieces[2]->set_state("back");
93  _object3Flag->set_state("\xed\xe5\xf2"); // "нет"
94 
95  _minDepthPiece = findMinDepthPiece();
96 
97  mgVect3f coords = _scene->screen2world_coords(_pieces[2]->screen_R(), _minDepthPiece);
98  _pieces[2]->set_R(coords);
99  }
100 
101  if (_isFinal)
102  return true;
103 
104  if (!checkSolution() || _scene->mouse_object_interface()) {
106 
107  if (_pieceIsPut) {
108  for (int i = 0; i < 12; i++) {
109  if (_pieces[i]->is_state_active("to_inv_flag_back")
110  || _pieces[i]->is_state_active("to_inv_flag_front")) {
111 
112  if (_pieces[i]->is_state_active("to_inv_flag_back"))
113  _currentPieceState = _pieces[i]->state_index("inv_back");
114  else if (_pieces[i]->is_state_active("to_inv_flag_front"))
115  _currentPieceState = _pieces[i]->state_index("inv_front");
116 
117  _rotatingPiece = i;
118  _pieces[i]->set_state("to_inv");
119  _pieceIsPut = false;
120  }
121  }
122  }
123 
124  if (mouseObj) {
125  if (_rotatingPiece != -1) {
126  _pieces[_rotatingPiece]->set_state(_currentPieceState);
127  _currentPieceState = -1;
128  _rotatingPiece = -1;
129  }
130  }
131 
133  mgVect2i mousePos = _engine->mouse_cursor_position();
135 
136  if (obj) {
137  if (obj->is_state_active("inv_back"))
138  obj->set_state("back");
139  else if (obj->is_state_active("inv_front"))
140  obj->set_state("front");
141 
142  _minDepthPiece -= 60.0;
143 
144  mgVect3f coords = _scene->screen2world_coords(mousePos, _minDepthPiece);
145  obj->set_R(coords);
146 
147  snapPieces();
148  } else {
149  _pieceIsPut = true;
150  }
151  }
152  }
153 
156 
157  if (obj) {
158  if (obj->is_state_active("inv_back"))
159  obj->set_state("inv_front");
160  else if (obj->is_state_active("inv_front"))
161  obj->set_state("inv_back");
162  }
163  }
164 
165  return true;
166  }
167 
168  bool checkSolution() {
169  if (_scene->mouse_object_interface())
170  return false;
171 
172  if (_pieces[0]->is_state_active("front")) {
173  for (int i = 0; i < 12; i++)
174  if (!_pieces[0]->is_state_active("front"))
175  return false;
176  } else if (_pieces[0]->is_state_active("back")) {
177  for (int i = 0; i < 12; i++)
178  if (!_pieces[0]->is_state_active("back"))
179  return false;
180  } else {
181  return false;
182  }
183 
184  mgVect2i piecePos;
185 
186  if (_pieces[0]->is_state_active("front"))
187  for (int i = 0; i < 12; i++) {
188  piecePos = _pieces[i]->screen_R();
189 
190  if (ABS(pieceCoordsFront[i * 2 + 0] - piecePos.x) > 10 ||
191  ABS(pieceCoordsFront[i * 2 + 1] - piecePos.y) > 10)
192  return false;
193  }
194 
195  if (_pieces[0]->is_state_active("back"))
196  for (int i = 0; i < 12; i++) {
197  piecePos = _pieces[i]->screen_R();
198 
199  if (ABS(pieceCoordsBack[i * 2 + 0] - piecePos.x) > 10 ||
200  ABS(pieceCoordsBack[i * 2 + 1] - piecePos.y) > 10)
201  return false;
202  }
203 
204  _isFinal = true;
205  _finalObj->set_state("\xe4\xe0"); // "да"
206 
207  setPiecePositions();
208 
209  return true;
210  }
211 
212  void snapPieces() {
213  mgVect2i piecePos;
214  mgVect3f newPiecePos;
215 
216  for (int i = 0; i < 12; i++) {
217  piecePos = _pieces[i]->screen_R();
218  float depth = _scene->screen_depth(_pieces[i]->R());
219  bool modified = false;
220 
221  if (_pieces[i]->is_state_active("front")) {
222  if (ABS(pieceCoordsFront[i * 2 + 0] - piecePos.x) <= 10 &&
223  ABS(pieceCoordsFront[i * 2 + 1] - piecePos.y) <= 10) {
224  piecePos.x = pieceCoordsFront[i * 2 + 0];
225  piecePos.y = pieceCoordsFront[i * 2 + 1];
226 
227  modified = true;
228  }
229  }
230 
231  if (_pieces[i]->is_state_active("back")) {
232  if (ABS(pieceCoordsBack[i * 2 + 0] - piecePos.x) <= 10 &&
233  ABS(pieceCoordsBack[i * 2 + 1] - piecePos.y) <= 10) {
234  piecePos.x = pieceCoordsBack[i * 2 + 0];
235  piecePos.y = pieceCoordsBack[i * 2 + 1];
236 
237  modified = true;
238  }
239  }
240 
241  if (modified) {
242  newPiecePos = _scene->screen2world_coords(piecePos, depth);
243  _pieces[i]->set_R(newPiecePos);
244  }
245  }
246  }
247 
248  bool finit() {
249  debugC(1, kDebugMinigames, "MaskyOrder::finit()");
250 
251  if (_scene) {
252  _engine->release_scene_interface(_scene);
253  _scene = 0;
254  }
255 
256  return true;
257  }
258 
259  bool new_game(const qdEngineInterface *engine_interface) {
260  return true;
261  }
262 
263  int save_game(const qdEngineInterface *engine_interface, const qdMinigameSceneInterface *scene_interface, char *buffer, int buffer_size) {
264  return 0;
265  }
266 
267  int load_game(const qdEngineInterface *engine_interface, const qdMinigameSceneInterface *scene_interface, const char *buffer, int buffer_size) {
268  return 0;
269  }
270 
271  enum { INTERFACE_VERSION = 112 };
272  int version() const {
273  return INTERFACE_VERSION;
274  }
275 
276 private:
277  float findMinDepthPiece() {
278  float min = 100000.0;
279 
280  for (int i = 0; i < 12; i++) {
281  float depth = _scene->screen_depth(_pieces[i]->R());
282 
283  if (min > depth)
284  min = depth;
285  }
286 
287  return min;
288  }
289 
290  void setPiecePositions() {
291  mgVect3f coords(1000.0, 1000.0, 0.0);
292 
293  for (int i = 0; i < 12; i++) {
294  _pieces[i]->set_R(coords);
295  }
296 
297  if (_pieces[0]->is_state_active("back"))
298  _doneObj->set_state("back");
299  else
300  _doneObj->set_state("front");
301  }
302 
303 private:
304  const qdEngineInterface *_engine = nullptr;
305  qdMinigameSceneInterface *_scene = nullptr;
306 
307  qdMinigameObjectInterface *_pieces[12];
308 
309  qdMinigameObjectInterface *_finalObj = nullptr;
310  qdMinigameObjectInterface *_doneObj = nullptr;
311  qdMinigameObjectInterface *_object3Flag = nullptr;
312  qdMinigameObjectInterface *_loadGameObj = nullptr;
313 
314  bool _wasInited = false;
315  bool _isFinal = false;
316  bool _flipped = false;
317 
318  float _minDepthPiece = 0.0;
319  int _rotatingPiece = -1;
320  bool _pieceIsPut = true;
321  int _currentPieceState = 0;
322 };
323 
324 } // namespace QDEngine
325 
326 #endif // QDENGINE_MINIGAMES_MASKY_ORDER_H
#define ARRAYSIZE(x)
Definition: util.h:91
virtual mgVect3f screen2world_coords(const mgVect2i &screen_pos, float screen_depth=0) const =0
Преобразование из экранных координат в мировые.
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
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
bool new_game(const qdEngineInterface *engine_interface)
Инициализация миниигры, вызывается при старте и перезапуске игры.
Definition: masky_order.h:259
Нажатие правой кнопки.
Definition: qd_minigame_interface.h:374
bool init(const qdEngineInterface *engine_interface)
Инициализация игры.
Definition: masky_order.h:53
virtual float screen_depth(const mgVect3f &pos) const =0
Возвращает "глубину" точки с координатами pos в мировой системе координат
Интерфейс к динамическому объекту.
Definition: qd_minigame_interface.h:230
Интерфейс к сцене.
Definition: qd_minigame_interface.h:315
virtual bool set_state(const char *state_name)=0
Включает состояние с именем state_name.
Definition: masky_order.h:45
virtual void set_R(const mgVect3f &r)=0
Устанавливает координаты объекта в мировой системе координат.
bool finit()
Деинициализация игры.
Definition: masky_order.h:248
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
int load_game(const qdEngineInterface *engine_interface, const qdMinigameSceneInterface *scene_interface, const char *buffer, int buffer_size)
Загрузка данных, вызывается при загрузке сцены, на которую повешена миниигра.
Definition: masky_order.h:267
bool quant(float dt)
Обсчёт логики игры, параметр - время, которое должно пройти в игре (в секундах).
Definition: masky_order.h:77
int save_game(const qdEngineInterface *engine_interface, const qdMinigameSceneInterface *scene_interface, char *buffer, int buffer_size)
Сохранение данных, вызывается при сохранении сцены, на которую повешена миниигра. ...
Definition: masky_order.h:263
virtual qdMinigameObjectInterface * mouse_object_interface() const =0
Создаёт интерфейс к объекту, который взят мышью в данный момент.