1 #include "GameController.h"
2
3 #include "GameView.h"
4 #include "GameModel.h"
5
6 #include "RenderPreset.h"
7 #include "Menu.h"
8 #include "Tool.h"
9 #include "Brush.h"
10 #include "QuickOptions.h"
11 #include "GameModelException.h"
12
13 #include "Config.h"
14 #include "Format.h"
15 #include "Platform.h"
16 #include "Controller.h"
17 #include "Notification.h"
18
19 #include "client/GameSave.h"
20 #include "client/Client.h"
21
22 #include "gui/search/SearchController.h"
23 #include "gui/render/RenderController.h"
24 #include "gui/login/LoginController.h"
25 #include "gui/preview/PreviewController.h"
26 #include "gui/tags/TagsController.h"
27 #include "gui/console/ConsoleController.h"
28 #include "gui/localbrowser/LocalBrowserController.h"
29 #include "gui/options/OptionsController.h"
30
31 #include "gui/dialogues/ErrorMessage.h"
32 #include "gui/dialogues/InformationMessage.h"
33 #include "gui/dialogues/ConfirmPrompt.h"
34
35 #include "gui/elementsearch/ElementSearchActivity.h"
36 #include "gui/profile/ProfileActivity.h"
37 #include "gui/colourpicker/ColourPickerActivity.h"
38 #include "gui/update/UpdateActivity.h"
39 #include "gui/filebrowser/FileBrowserActivity.h"
40 #include "gui/save/LocalSaveActivity.h"
41 #include "gui/save/ServerSaveActivity.h"
42
43 #include "gui/tags/TagsView.h"
44 #include "gui/search/SearchView.h"
45 #include "gui/render/RenderView.h"
46 #include "gui/preview/PreviewView.h"
47 #include "gui/options/OptionsView.h"
48 #include "gui/login/LoginView.h"
49 #include "gui/localbrowser/LocalBrowserView.h"
50 #include "gui/console/ConsoleView.h"
51
52 #include "gui/interface/Keys.h"
53 #include "gui/interface/Mouse.h"
54 #include "gui/interface/Engine.h"
55
56 #include "debug/DebugInfo.h"
57 #include "debug/DebugParts.h"
58 #include "debug/ElementPopulation.h"
59 #include "debug/DebugLines.h"
60 #include "debug/ParticleDebug.h"
61
62 #ifdef LUACONSOLE
63 #include "lua/LuaScriptInterface.h"
64 #else
65 #include "lua/TPTScriptInterface.h"
66 #endif
67 #include "lua/LuaEvents.h"
68
69 #include "graphics/Renderer.h"
70
71 #include "simulation/Simulation.h"
72 #include "simulation/SimulationData.h"
73 #include "simulation/Air.h"
74 #include "simulation/Snapshot.h"
75 #include "simulation/ElementClasses.h"
76
77 #ifdef GetUserName
78 # undef GetUserName // dammit windows
79 #endif
80
GameController()81 GameController::GameController():
82 firstTick(true),
83 foundSignID(-1),
84 activePreview(NULL),
85 search(NULL),
86 renderOptions(NULL),
87 loginWindow(NULL),
88 console(NULL),
89 tagsWindow(NULL),
90 localBrowser(NULL),
91 options(NULL),
92 debugFlags(0),
93 HasDone(false)
94 {
95 gameView = new GameView();
96 gameModel = new GameModel();
97 gameModel->BuildQuickOptionMenu(this);
98
99 gameView->AttachController(this);
100 gameModel->AddObserver(gameView);
101
102 gameView->SetDebugHUD(Client::Ref().GetPrefBool("Renderer.DebugMode", false));
103
104 #ifdef LUACONSOLE
105 commandInterface = new LuaScriptInterface(this, gameModel);
106 #else
107 commandInterface = new TPTScriptInterface(this, gameModel);
108 #endif
109
110 Client::Ref().AddListener(this);
111
112 debugInfo.push_back(new DebugParts(0x1, gameModel->GetSimulation()));
113 debugInfo.push_back(new ElementPopulationDebug(0x2, gameModel->GetSimulation()));
114 debugInfo.push_back(new DebugLines(0x4, gameView, this));
115 debugInfo.push_back(new ParticleDebug(0x8, gameModel->GetSimulation(), gameModel));
116 }
117
~GameController()118 GameController::~GameController()
119 {
120 if(search)
121 {
122 delete search;
123 }
124 if(renderOptions)
125 {
126 delete renderOptions;
127 }
128 if(loginWindow)
129 {
130 delete loginWindow;
131 }
132 if(tagsWindow)
133 {
134 delete tagsWindow;
135 }
136 if(console)
137 {
138 delete console;
139 }
140 if(activePreview)
141 {
142 delete activePreview;
143 }
144 if(localBrowser)
145 {
146 delete localBrowser;
147 }
148 if (options)
149 {
150 delete options;
151 }
152 for(std::vector<DebugInfo*>::iterator iter = debugInfo.begin(), end = debugInfo.end(); iter != end; iter++)
153 {
154 delete *iter;
155 }
156 //deleted here because it refuses to be deleted when deleted from gameModel even with the same code
157 std::deque<Snapshot*> history = gameModel->GetHistory();
158 for(std::deque<Snapshot*>::iterator iter = history.begin(), end = history.end(); iter != end; ++iter)
159 {
160 delete *iter;
161 }
162 std::vector<QuickOption*> quickOptions = gameModel->GetQuickOptions();
163 for(std::vector<QuickOption*>::iterator iter = quickOptions.begin(), end = quickOptions.end(); iter != end; ++iter)
164 {
165 delete *iter;
166 }
167 std::vector<Notification*> notifications = gameModel->GetNotifications();
168 for(std::vector<Notification*>::iterator iter = notifications.begin(); iter != notifications.end(); ++iter)
169 {
170 delete *iter;
171 }
172 delete gameModel;
173 if (gameView->CloseActiveWindow())
174 {
175 delete gameView;
176 }
177 }
178
HistoryRestore()179 void GameController::HistoryRestore()
180 {
181 std::deque<Snapshot*> history = gameModel->GetHistory();
182 if (!history.size())
183 return;
184 unsigned int historyPosition = gameModel->GetHistoryPosition();
185 unsigned int newHistoryPosition = std::max((int)historyPosition-1, 0);
186 // When undoing, save the current state as a final redo
187 // This way ctrl+y will always bring you back to the point right before your last ctrl+z
188 if (historyPosition == history.size())
189 {
190 Snapshot * newSnap = gameModel->GetSimulation()->CreateSnapshot();
191 if (newSnap)
192 newSnap->Authors = Client::Ref().GetAuthorInfo();
193 delete gameModel->GetRedoHistory();
194 gameModel->SetRedoHistory(newSnap);
195 }
196 Snapshot * snap = history[newHistoryPosition];
197 gameModel->GetSimulation()->Restore(*snap);
198 Client::Ref().OverwriteAuthorInfo(snap->Authors);
199 gameModel->SetHistory(history);
200 gameModel->SetHistoryPosition(newHistoryPosition);
201 }
202
HistorySnapshot()203 void GameController::HistorySnapshot()
204 {
205 std::deque<Snapshot*> history = gameModel->GetHistory();
206 unsigned int historyPosition = gameModel->GetHistoryPosition();
207 Snapshot * newSnap = gameModel->GetSimulation()->CreateSnapshot();
208 if (newSnap)
209 {
210 newSnap->Authors = Client::Ref().GetAuthorInfo();
211 while (historyPosition < history.size())
212 {
213 Snapshot * snap = history.back();
214 history.pop_back();
215 delete snap;
216 }
217 if (history.size() >= gameModel->GetUndoHistoryLimit())
218 {
219 Snapshot * snap = history.front();
220 history.pop_front();
221 delete snap;
222 if (historyPosition > history.size())
223 historyPosition--;
224 }
225 history.push_back(newSnap);
226 gameModel->SetHistory(history);
227 gameModel->SetHistoryPosition(std::min((size_t)historyPosition+1, history.size()));
228 delete gameModel->GetRedoHistory();
229 gameModel->SetRedoHistory(NULL);
230 }
231 }
232
HistoryForward()233 void GameController::HistoryForward()
234 {
235 std::deque<Snapshot*> history = gameModel->GetHistory();
236 if (!history.size())
237 return;
238 unsigned int historyPosition = gameModel->GetHistoryPosition();
239 unsigned int newHistoryPosition = std::min((size_t)historyPosition+1, history.size());
240 Snapshot *snap;
241 if (newHistoryPosition == history.size())
242 snap = gameModel->GetRedoHistory();
243 else
244 snap = history[newHistoryPosition];
245 if (!snap)
246 return;
247 gameModel->GetSimulation()->Restore(*snap);
248 Client::Ref().OverwriteAuthorInfo(snap->Authors);
249 gameModel->SetHistoryPosition(newHistoryPosition);
250 }
251
GetView()252 GameView * GameController::GetView()
253 {
254 return gameView;
255 }
256
GetSignAt(int x,int y)257 int GameController::GetSignAt(int x, int y)
258 {
259 Simulation * sim = gameModel->GetSimulation();
260 for (int i = sim->signs.size()-1; i >= 0; i--)
261 {
262 int signx, signy, signw, signh;
263 sim->signs[i].getDisplayText(sim, signx, signy, signw, signh);
264 if (x>=signx && x<=signx+signw && y>=signy && y<=signy+signh)
265 return i;
266 }
267 return -1;
268 }
269
270 // assumed to already be a valid sign
GetSignText(int signID)271 String GameController::GetSignText(int signID)
272 {
273 return gameModel->GetSimulation()->signs[signID].text;
274 }
275
GetSignSplit(int signID)276 std::pair<int, sign::Type> GameController::GetSignSplit(int signID)
277 {
278 return gameModel->GetSimulation()->signs[signID].split();
279 }
280
PlaceSave(ui::Point position)281 void GameController::PlaceSave(ui::Point position)
282 {
283 GameSave *placeSave = gameModel->GetPlaceSave();
284 if (placeSave)
285 {
286 HistorySnapshot();
287 if (!gameModel->GetSimulation()->Load(placeSave, !gameView->ShiftBehaviour(), position.X, position.Y))
288 {
289 gameModel->SetPaused(placeSave->paused | gameModel->GetPaused());
290 Client::Ref().MergeStampAuthorInfo(placeSave->authors);
291 }
292 }
293 }
294
Install()295 void GameController::Install()
296 {
297 #if defined(MACOSX)
298 new InformationMessage("No installation necessary", "You don't need to install The Powder Toy on OS X", false);
299 #elif defined(WIN) || defined(LIN)
300 new ConfirmPrompt("Install The Powder Toy", "Do you wish to install The Powder Toy on this computer?\nThis allows you to open save files and saves directly from the website.", { [] {
301 if (Client::Ref().DoInstallation())
302 {
303 new InformationMessage("Success", "Installation completed", false);
304 }
305 else
306 {
307 new ErrorMessage("Could not install", "The installation did not complete due to an error");
308 }
309 } });
310 #else
311 new ErrorMessage("Cannot install", "You cannot install The Powder Toy on this platform");
312 #endif
313 }
314
AdjustGridSize(int direction)315 void GameController::AdjustGridSize(int direction)
316 {
317 if(direction > 0)
318 gameModel->GetRenderer()->SetGridSize((gameModel->GetRenderer()->GetGridSize()+1)%10);
319 else
320 gameModel->GetRenderer()->SetGridSize((gameModel->GetRenderer()->GetGridSize()+9)%10);
321 }
322
InvertAirSim()323 void GameController::InvertAirSim()
324 {
325 gameModel->GetSimulation()->air->Invert();
326 }
327
328
AdjustBrushSize(int delta,bool logarithmic,bool xAxis,bool yAxis)329 void GameController::AdjustBrushSize(int delta, bool logarithmic, bool xAxis, bool yAxis)
330 {
331 if(xAxis && yAxis)
332 return;
333
334 ui::Point newSize(0, 0);
335 ui::Point oldSize = gameModel->GetBrush()->GetRadius();
336 if(logarithmic)
337 newSize = gameModel->GetBrush()->GetRadius() + ui::Point(delta * std::max(gameModel->GetBrush()->GetRadius().X / 5, 1), delta * std::max(gameModel->GetBrush()->GetRadius().Y / 5, 1));
338 else
339 newSize = gameModel->GetBrush()->GetRadius() + ui::Point(delta, delta);
340 if(newSize.X < 0)
341 newSize.X = 0;
342 if(newSize.Y < 0)
343 newSize.Y = 0;
344 if(newSize.X > 200)
345 newSize.X = 200;
346 if(newSize.Y > 200)
347 newSize.Y = 200;
348
349 if(xAxis)
350 SetBrushSize(ui::Point(newSize.X, oldSize.Y));
351 else if(yAxis)
352 SetBrushSize(ui::Point(oldSize.X, newSize.Y));
353 else
354 SetBrushSize(newSize);
355 }
356
SetBrushSize(ui::Point newSize)357 void GameController::SetBrushSize(ui::Point newSize)
358 {
359 gameModel->GetBrush()->SetRadius(newSize);
360 }
361
AdjustZoomSize(int delta,bool logarithmic)362 void GameController::AdjustZoomSize(int delta, bool logarithmic)
363 {
364 int newSize;
365 if(logarithmic)
366 newSize = gameModel->GetZoomSize() + std::max(gameModel->GetZoomSize() / 10, 1) * delta;
367 else
368 newSize = gameModel->GetZoomSize() + delta;
369 if(newSize<5)
370 newSize = 5;
371 if(newSize>64)
372 newSize = 64;
373 gameModel->SetZoomSize(newSize);
374
375 int newZoomFactor = 256/newSize;
376 if(newZoomFactor<3)
377 newZoomFactor = 3;
378 gameModel->SetZoomFactor(newZoomFactor);
379 }
380
MouseInZoom(ui::Point position)381 bool GameController::MouseInZoom(ui::Point position)
382 {
383 if(position.X >= XRES)
384 position.X = XRES-1;
385 if(position.Y >= YRES)
386 position.Y = YRES-1;
387 if(position.Y < 0)
388 position.Y = 0;
389 if(position.X < 0)
390 position.X = 0;
391
392 return gameModel->MouseInZoom(position);
393 }
394
PointTranslate(ui::Point point)395 ui::Point GameController::PointTranslate(ui::Point point)
396 {
397 if(point.X >= XRES)
398 point.X = XRES-1;
399 if(point.Y >= YRES)
400 point.Y = YRES-1;
401 if(point.Y < 0)
402 point.Y = 0;
403 if(point.X < 0)
404 point.X = 0;
405
406 return gameModel->AdjustZoomCoords(point);
407 }
408
NormaliseBlockCoord(ui::Point point)409 ui::Point GameController::NormaliseBlockCoord(ui::Point point)
410 {
411 return (point/CELL)*CELL;
412 }
413
DrawRect(int toolSelection,ui::Point point1,ui::Point point2)414 void GameController::DrawRect(int toolSelection, ui::Point point1, ui::Point point2)
415 {
416 Simulation * sim = gameModel->GetSimulation();
417 Tool * activeTool = gameModel->GetActiveTool(toolSelection);
418 gameModel->SetLastTool(activeTool);
419 Brush * cBrush = gameModel->GetBrush();
420 if(!activeTool || !cBrush)
421 return;
422 activeTool->SetStrength(1.0f);
423 activeTool->DrawRect(sim, cBrush, point1, point2);
424 }
425
DrawLine(int toolSelection,ui::Point point1,ui::Point point2)426 void GameController::DrawLine(int toolSelection, ui::Point point1, ui::Point point2)
427 {
428 Simulation * sim = gameModel->GetSimulation();
429 Tool * activeTool = gameModel->GetActiveTool(toolSelection);
430 gameModel->SetLastTool(activeTool);
431 Brush * cBrush = gameModel->GetBrush();
432 if(!activeTool || !cBrush)
433 return;
434 activeTool->SetStrength(1.0f);
435 activeTool->DrawLine(sim, cBrush, point1, point2);
436 }
437
DrawFill(int toolSelection,ui::Point point)438 void GameController::DrawFill(int toolSelection, ui::Point point)
439 {
440 Simulation * sim = gameModel->GetSimulation();
441 Tool * activeTool = gameModel->GetActiveTool(toolSelection);
442 gameModel->SetLastTool(activeTool);
443 Brush * cBrush = gameModel->GetBrush();
444 if(!activeTool || !cBrush)
445 return;
446 activeTool->SetStrength(1.0f);
447 activeTool->DrawFill(sim, cBrush, point);
448 }
449
DrawPoints(int toolSelection,ui::Point oldPos,ui::Point newPos,bool held)450 void GameController::DrawPoints(int toolSelection, ui::Point oldPos, ui::Point newPos, bool held)
451 {
452 Simulation * sim = gameModel->GetSimulation();
453 Tool * activeTool = gameModel->GetActiveTool(toolSelection);
454 gameModel->SetLastTool(activeTool);
455 Brush * cBrush = gameModel->GetBrush();
456 if (!activeTool || !cBrush)
457 {
458 return;
459 }
460
461 activeTool->SetStrength(gameModel->GetToolStrength());
462 if (!held)
463 activeTool->Draw(sim, cBrush, newPos);
464 else
465 activeTool->DrawLine(sim, cBrush, oldPos, newPos, true);
466 }
467
LoadClipboard()468 bool GameController::LoadClipboard()
469 {
470 GameSave *clip = gameModel->GetClipboard();
471 if (!clip)
472 return false;
473 gameModel->SetPlaceSave(clip);
474 if (gameModel->GetPlaceSave() && gameModel->GetPlaceSave()->Collapsed())
475 gameModel->GetPlaceSave()->Expand();
476 return true;
477 }
478
LoadStamp(GameSave * stamp)479 void GameController::LoadStamp(GameSave *stamp)
480 {
481 gameModel->SetPlaceSave(stamp);
482 if(gameModel->GetPlaceSave() && gameModel->GetPlaceSave()->Collapsed())
483 gameModel->GetPlaceSave()->Expand();
484 }
485
TranslateSave(ui::Point point)486 void GameController::TranslateSave(ui::Point point)
487 {
488 vector2d translate = v2d_new(point.X, point.Y);
489 vector2d translated = gameModel->GetPlaceSave()->Translate(translate);
490 ui::Point currentPlaceSaveOffset = gameView->GetPlaceSaveOffset();
491 // resets placeSaveOffset to 0, which is why we back it up first
492 gameModel->SetPlaceSave(gameModel->GetPlaceSave());
493 gameView->SetPlaceSaveOffset(ui::Point(translated.x, translated.y) + currentPlaceSaveOffset);
494 }
495
TransformSave(matrix2d transform)496 void GameController::TransformSave(matrix2d transform)
497 {
498 vector2d translate = v2d_zero;
499 gameModel->GetPlaceSave()->Transform(transform, translate);
500 gameModel->SetPlaceSave(gameModel->GetPlaceSave());
501 }
502
ToolClick(int toolSelection,ui::Point point)503 void GameController::ToolClick(int toolSelection, ui::Point point)
504 {
505 Simulation * sim = gameModel->GetSimulation();
506 Tool * activeTool = gameModel->GetActiveTool(toolSelection);
507 Brush * cBrush = gameModel->GetBrush();
508 if(!activeTool || !cBrush)
509 return;
510 activeTool->Click(sim, cBrush, point);
511 }
512
StampRegion(ui::Point point1,ui::Point point2)513 ByteString GameController::StampRegion(ui::Point point1, ui::Point point2)
514 {
515 GameSave * newSave = gameModel->GetSimulation()->Save(gameModel->GetIncludePressure() != gameView->ShiftBehaviour(), point1.X, point1.Y, point2.X, point2.Y);
516 if(newSave)
517 {
518 newSave->paused = gameModel->GetPaused();
519 ByteString stampName = Client::Ref().AddStamp(newSave);
520 delete newSave;
521 if (stampName.length() == 0)
522 new ErrorMessage("Could not create stamp", "Error serializing save file");
523 return stampName;
524 }
525 else
526 {
527 new ErrorMessage("Could not create stamp", "Error generating save file");
528 return "";
529 }
530 }
531
CopyRegion(ui::Point point1,ui::Point point2)532 void GameController::CopyRegion(ui::Point point1, ui::Point point2)
533 {
534 GameSave * newSave = gameModel->GetSimulation()->Save(gameModel->GetIncludePressure() != gameView->ShiftBehaviour(), point1.X, point1.Y, point2.X, point2.Y);
535 if(newSave)
536 {
537 Json::Value clipboardInfo;
538 clipboardInfo["type"] = "clipboard";
539 clipboardInfo["username"] = Client::Ref().GetAuthUser().Username;
540 clipboardInfo["date"] = (Json::Value::UInt64)time(NULL);
541 Client::Ref().SaveAuthorInfo(&clipboardInfo);
542 newSave->authors = clipboardInfo;
543
544 newSave->paused = gameModel->GetPaused();
545 gameModel->SetClipboard(newSave);
546 }
547 }
548
CutRegion(ui::Point point1,ui::Point point2)549 void GameController::CutRegion(ui::Point point1, ui::Point point2)
550 {
551 CopyRegion(point1, point2);
552 gameModel->GetSimulation()->clear_area(point1.X, point1.Y, point2.X-point1.X, point2.Y-point1.Y);
553 }
554
MouseMove(int x,int y,int dx,int dy)555 bool GameController::MouseMove(int x, int y, int dx, int dy)
556 {
557 MouseMoveEvent ev(x, y, dx, dy);
558 return commandInterface->HandleEvent(LuaEvents::mousemove, &ev);
559 }
560
MouseDown(int x,int y,unsigned button)561 bool GameController::MouseDown(int x, int y, unsigned button)
562 {
563 MouseDownEvent ev(x, y, button);
564 bool ret = commandInterface->HandleEvent(LuaEvents::mousedown, &ev);
565 if (ret && y<YRES && x<XRES && !gameView->GetPlacingSave() && !gameView->GetPlacingZoom())
566 {
567 ui::Point point = gameModel->AdjustZoomCoords(ui::Point(x, y));
568 x = point.X;
569 y = point.Y;
570 if (!gameModel->GetActiveTool(0) || gameModel->GetActiveTool(0)->GetIdentifier() != "DEFAULT_UI_SIGN" || button != SDL_BUTTON_LEFT) //If it's not a sign tool or you are right/middle clicking
571 {
572 foundSignID = GetSignAt(x, y);
573 if (foundSignID != -1)
574 {
575 if (gameModel->GetSimulation()->signs[foundSignID].split().first)
576 {
577 return false;
578 }
579 }
580 }
581 }
582 return ret;
583 }
584
MouseUp(int x,int y,unsigned button,char type)585 bool GameController::MouseUp(int x, int y, unsigned button, char type)
586 {
587 MouseUpEvent ev(x, y, button, type);
588 bool ret = commandInterface->HandleEvent(LuaEvents::mouseup, &ev);
589 if (type)
590 return ret;
591 if (ret && foundSignID != -1 && y<YRES && x<XRES && !gameView->GetPlacingSave())
592 {
593 ui::Point point = gameModel->AdjustZoomCoords(ui::Point(x, y));
594 x = point.X;
595 y = point.Y;
596 if (!gameModel->GetActiveTool(0) || gameModel->GetActiveTool(0)->GetIdentifier() != "DEFAULT_UI_SIGN" || button != SDL_BUTTON_LEFT) //If it's not a sign tool or you are right/middle clicking
597 {
598 int foundSignID = GetSignAt(x, y);
599 if (foundSignID != -1)
600 {
601 sign &foundSign = gameModel->GetSimulation()->signs[foundSignID];
602 String str = foundSign.text;
603 auto si = gameModel->GetSimulation()->signs[foundSignID].split();
604 if (si.first)
605 {
606 ret = false;
607 switch (si.second)
608 {
609 case sign::Type::Save:
610 {
611 int saveID = str.Substr(3, si.first - 3).ToNumber<int>(true);
612 if (saveID)
613 OpenSavePreview(saveID, 0, false);
614 }
615 break;
616 case sign::Type::Thread:
617 Platform::OpenURI(ByteString::Build(SCHEME "powdertoy.co.uk/Discussions/Thread/View.html?Thread=", str.Substr(3, si.first - 3).ToUtf8()));
618 break;
619 case sign::Type::Search:
620 OpenSearch(str.Substr(3, si.first - 3));
621 break;
622 case sign::Type::Button:
623 gameModel->GetSimulation()->create_part(-1, foundSign.x, foundSign.y, PT_SPRK);
624 break;
625 default: break;
626 }
627 }
628 }
629 }
630 }
631 foundSignID = -1;
632 return ret;
633 }
634
MouseWheel(int x,int y,int d)635 bool GameController::MouseWheel(int x, int y, int d)
636 {
637 MouseWheelEvent ev(x, y, d);
638 return commandInterface->HandleEvent(LuaEvents::mousewheel, &ev);
639 }
640
TextInput(String text)641 bool GameController::TextInput(String text)
642 {
643 TextInputEvent ev(text);
644 return commandInterface->HandleEvent(LuaEvents::textinput, &ev);
645 }
646
KeyPress(int key,int scan,bool repeat,bool shift,bool ctrl,bool alt)647 bool GameController::KeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt)
648 {
649 KeyEvent ev(key, scan, repeat, shift, ctrl, alt);
650 bool ret = commandInterface->HandleEvent(LuaEvents::keypress, &ev);
651 if (repeat)
652 return ret;
653 if (ret)
654 {
655 Simulation * sim = gameModel->GetSimulation();
656 if (!gameView->GetPlacingSave())
657 {
658 // Go right command
659 if (key == SDLK_RIGHT)
660 {
661 sim->player.comm = (int)(sim->player.comm)|0x02;
662 }
663 // Go left command
664 else if (key == SDLK_LEFT)
665 {
666 sim->player.comm = (int)(sim->player.comm)|0x01;
667 }
668 // Use element command
669 else if (key == SDLK_DOWN && ((int)(sim->player.comm)&0x08)!=0x08)
670 {
671 sim->player.comm = (int)(sim->player.comm)|0x08;
672 }
673 // Jump command
674 else if (key == SDLK_UP && ((int)(sim->player.comm)&0x04)!=0x04)
675 {
676 sim->player.comm = (int)(sim->player.comm)|0x04;
677 }
678 }
679
680 // Go right command
681 if (scan == SDL_SCANCODE_D)
682 {
683 sim->player2.comm = (int)(sim->player2.comm)|0x02;
684 }
685 // Go left command
686 else if (scan == SDL_SCANCODE_A)
687 {
688 sim->player2.comm = (int)(sim->player2.comm)|0x01;
689 }
690 // Use element command
691 else if (scan == SDL_SCANCODE_S && ((int)(sim->player2.comm)&0x08)!=0x08)
692 {
693 sim->player2.comm = (int)(sim->player2.comm)|0x08;
694 }
695 // Jump command
696 else if (scan == SDL_SCANCODE_W && ((int)(sim->player2.comm)&0x04)!=0x04)
697 {
698 sim->player2.comm = (int)(sim->player2.comm)|0x04;
699 }
700
701 if (!sim->elementCount[PT_STKM2] || ctrl)
702 {
703 switch(scan)
704 {
705 case SDL_SCANCODE_W:
706 SwitchGravity();
707 break;
708 case SDL_SCANCODE_D:
709 gameView->SetDebugHUD(!gameView->GetDebugHUD());
710 break;
711 case SDL_SCANCODE_S:
712 gameView->BeginStampSelection();
713 break;
714 }
715 }
716
717 for(std::vector<DebugInfo*>::iterator iter = debugInfo.begin(), end = debugInfo.end(); iter != end; iter++)
718 {
719 if ((*iter)->debugID & debugFlags)
720 if (!(*iter)->KeyPress(key, scan, shift, ctrl, alt, gameView->GetMousePosition()))
721 ret = false;
722 }
723 }
724 return ret;
725 }
726
KeyRelease(int key,int scan,bool repeat,bool shift,bool ctrl,bool alt)727 bool GameController::KeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt)
728 {
729 KeyEvent ev(key, scan, repeat, shift, ctrl, alt);
730 bool ret = commandInterface->HandleEvent(LuaEvents::keyrelease, &ev);
731 if (repeat)
732 return ret;
733 if (ret)
734 {
735 Simulation * sim = gameModel->GetSimulation();
736 if (key == SDLK_RIGHT || key == SDLK_LEFT)
737 {
738 sim->player.pcomm = sim->player.comm; //Saving last movement
739 sim->player.comm = (int)(sim->player.comm)&12; //Stop command
740 }
741 else if (key == SDLK_UP)
742 {
743 sim->player.comm = (int)(sim->player.comm)&11;
744 }
745 else if (key == SDLK_DOWN)
746 {
747 sim->player.comm = (int)(sim->player.comm)&7;
748 }
749
750 if (scan == SDL_SCANCODE_D || scan == SDL_SCANCODE_A)
751 {
752 sim->player2.pcomm = sim->player2.comm; //Saving last movement
753 sim->player2.comm = (int)(sim->player2.comm)&12; //Stop command
754 }
755 else if (scan == SDL_SCANCODE_W)
756 {
757 sim->player2.comm = (int)(sim->player2.comm)&11;
758 }
759 else if (scan == SDL_SCANCODE_S)
760 {
761 sim->player2.comm = (int)(sim->player2.comm)&7;
762 }
763 }
764 return ret;
765 }
766
Tick()767 void GameController::Tick()
768 {
769 if(firstTick)
770 {
771 #ifdef LUACONSOLE
772 ((LuaScriptInterface*)commandInterface)->Init();
773 #endif
774 #if !defined(MACOSX) && !defined(NO_INSTALL_CHECK)
775 if (Client::Ref().IsFirstRun())
776 {
777 Install();
778 }
779 #endif
780 firstTick = false;
781 }
782 for(std::vector<DebugInfo*>::iterator iter = debugInfo.begin(), end = debugInfo.end(); iter != end; iter++)
783 {
784 if ((*iter)->debugID & debugFlags)
785 (*iter)->Draw();
786 }
787 commandInterface->OnTick();
788 }
789
Blur()790 void GameController::Blur()
791 {
792 // Tell lua that mouse is up (even if it really isn't)
793 MouseUp(0, 0, 0, 1);
794 BlurEvent ev;
795 commandInterface->HandleEvent(LuaEvents::blur, &ev);
796 }
797
Exit()798 void GameController::Exit()
799 {
800 CloseEvent ev;
801 commandInterface->HandleEvent(LuaEvents::close, &ev);
802 gameView->CloseActiveWindow();
803 HasDone = true;
804 }
805
ResetAir()806 void GameController::ResetAir()
807 {
808 Simulation * sim = gameModel->GetSimulation();
809 sim->air->Clear();
810 for (int i = 0; i < NPART; i++)
811 {
812 if (sim->parts[i].type == PT_QRTZ || sim->parts[i].type == PT_GLAS || sim->parts[i].type == PT_TUNG)
813 {
814 sim->parts[i].pavg[0] = sim->parts[i].pavg[1] = 0;
815 }
816 }
817 }
818
ResetSpark()819 void GameController::ResetSpark()
820 {
821 Simulation * sim = gameModel->GetSimulation();
822 for (int i = 0; i < NPART; i++)
823 if (sim->parts[i].type == PT_SPRK)
824 {
825 if (sim->parts[i].ctype >= 0 && sim->parts[i].ctype < PT_NUM && sim->elements[sim->parts[i].ctype].Enabled)
826 {
827 sim->parts[i].type = sim->parts[i].ctype;
828 sim->parts[i].ctype = sim->parts[i].life = 0;
829 }
830 else
831 sim->kill_part(i);
832 }
833 memset(sim->wireless, 0, sizeof(sim->wireless));
834 }
835
SwitchGravity()836 void GameController::SwitchGravity()
837 {
838 gameModel->GetSimulation()->gravityMode = (gameModel->GetSimulation()->gravityMode+1)%3;
839
840 switch (gameModel->GetSimulation()->gravityMode)
841 {
842 case 0:
843 gameModel->SetInfoTip("Gravity: Vertical");
844 break;
845 case 1:
846 gameModel->SetInfoTip("Gravity: Off");
847 break;
848 case 2:
849 gameModel->SetInfoTip("Gravity: Radial");
850 break;
851 }
852 }
853
SwitchAir()854 void GameController::SwitchAir()
855 {
856 gameModel->GetSimulation()->air->airMode = (gameModel->GetSimulation()->air->airMode+1)%5;
857
858 switch (gameModel->GetSimulation()->air->airMode)
859 {
860 case 0:
861 gameModel->SetInfoTip("Air: On");
862 break;
863 case 1:
864 gameModel->SetInfoTip("Air: Pressure Off");
865 break;
866 case 2:
867 gameModel->SetInfoTip("Air: Velocity Off");
868 break;
869 case 3:
870 gameModel->SetInfoTip("Air: Off");
871 break;
872 case 4:
873 gameModel->SetInfoTip("Air: No Update");
874 break;
875 }
876 }
877
ToggleAHeat()878 void GameController::ToggleAHeat()
879 {
880 gameModel->SetAHeatEnable(!gameModel->GetAHeatEnable());
881 }
882
GetAHeatEnable()883 bool GameController::GetAHeatEnable()
884 {
885 return gameModel->GetAHeatEnable();
886 }
887
ToggleNewtonianGravity()888 void GameController::ToggleNewtonianGravity()
889 {
890 gameModel->SetNewtonianGravity(!gameModel->GetNewtonianGrvity());
891 }
892
LoadRenderPreset(int presetNum)893 void GameController::LoadRenderPreset(int presetNum)
894 {
895 Renderer * renderer = gameModel->GetRenderer();
896 RenderPreset preset = renderer->renderModePresets[presetNum];
897 gameModel->SetInfoTip(preset.Name);
898 renderer->SetRenderMode(preset.RenderModes);
899 renderer->SetDisplayMode(preset.DisplayModes);
900 renderer->SetColourMode(preset.ColourMode);
901 }
902
Update()903 void GameController::Update()
904 {
905 ui::Point pos = gameView->GetMousePosition();
906 gameModel->GetRenderer()->mousePos = PointTranslate(pos);
907 if (pos.X < XRES && pos.Y < YRES)
908 gameView->SetSample(gameModel->GetSimulation()->GetSample(PointTranslate(pos).X, PointTranslate(pos).Y));
909 else
910 gameView->SetSample(gameModel->GetSimulation()->GetSample(pos.X, pos.Y));
911
912 Simulation * sim = gameModel->GetSimulation();
913 sim->BeforeSim();
914 if (!sim->sys_pause || sim->framerender)
915 {
916 sim->UpdateParticles(0, NPART);
917 sim->AfterSim();
918 }
919
920 //if either STKM or STK2 isn't out, reset it's selected element. Defaults to PT_DUST unless right selected is something else
921 //This won't run if the stickmen dies in a frame, since it respawns instantly
922 if (!sim->player.spwn || !sim->player2.spwn)
923 {
924 int rightSelected = PT_DUST;
925 Tool * activeTool = gameModel->GetActiveTool(1);
926 if (activeTool->GetIdentifier().BeginsWith("DEFAULT_PT_"))
927 {
928 int sr = activeTool->GetToolID();
929 if (sr && sim->IsValidElement(sr))
930 rightSelected = sr;
931 }
932
933 void Element_STKM_set_element(Simulation *sim, playerst *playerp, int element);
934 if (!sim->player.spwn)
935 Element_STKM_set_element(sim, &sim->player, rightSelected);
936 if (!sim->player2.spwn)
937 Element_STKM_set_element(sim, &sim->player2, rightSelected);
938 }
939 if(renderOptions && renderOptions->HasExited)
940 {
941 delete renderOptions;
942 renderOptions = NULL;
943 }
944
945 if(search && search->HasExited)
946 {
947 delete search;
948 search = NULL;
949 }
950
951 if(activePreview && activePreview->HasExited)
952 {
953 delete activePreview;
954 activePreview = NULL;
955 }
956
957 if(loginWindow && loginWindow->HasExited)
958 {
959 delete loginWindow;
960 loginWindow = NULL;
961 }
962
963 if(localBrowser && localBrowser->HasDone)
964 {
965 delete localBrowser;
966 localBrowser = NULL;
967 }
968 }
969
SetZoomEnabled(bool zoomEnabled)970 void GameController::SetZoomEnabled(bool zoomEnabled)
971 {
972 gameModel->SetZoomEnabled(zoomEnabled);
973 }
974
SetToolStrength(float value)975 void GameController::SetToolStrength(float value)
976 {
977 gameModel->SetToolStrength(value);
978 }
979
SetZoomPosition(ui::Point position)980 void GameController::SetZoomPosition(ui::Point position)
981 {
982 ui::Point zoomPosition = position-(gameModel->GetZoomSize()/2);
983 if(zoomPosition.X < 0)
984 zoomPosition.X = 0;
985 if(zoomPosition.Y < 0)
986 zoomPosition.Y = 0;
987 if(zoomPosition.X >= XRES-gameModel->GetZoomSize())
988 zoomPosition.X = XRES-gameModel->GetZoomSize();
989 if(zoomPosition.Y >= YRES-gameModel->GetZoomSize())
990 zoomPosition.Y = YRES-gameModel->GetZoomSize();
991
992 ui::Point zoomWindowPosition = ui::Point(0, 0);
993 if(position.X < XRES/2)
994 zoomWindowPosition.X = XRES-(gameModel->GetZoomSize()*gameModel->GetZoomFactor());
995
996 gameModel->SetZoomPosition(zoomPosition);
997 gameModel->SetZoomWindowPosition(zoomWindowPosition);
998 }
999
SetPaused(bool pauseState)1000 void GameController::SetPaused(bool pauseState)
1001 {
1002 gameModel->SetPaused(pauseState);
1003 }
1004
SetPaused()1005 void GameController::SetPaused()
1006 {
1007 gameModel->SetPaused(!gameModel->GetPaused());
1008 }
1009
SetDecoration(bool decorationState)1010 void GameController::SetDecoration(bool decorationState)
1011 {
1012 gameModel->SetDecoration(decorationState);
1013 }
1014
SetDecoration()1015 void GameController::SetDecoration()
1016 {
1017 gameModel->SetDecoration(!gameModel->GetDecoration());
1018 }
1019
ShowGravityGrid()1020 void GameController::ShowGravityGrid()
1021 {
1022 gameModel->ShowGravityGrid(!gameModel->GetGravityGrid());
1023 gameModel->UpdateQuickOptions();
1024 }
1025
SetHudEnable(bool hudState)1026 void GameController::SetHudEnable(bool hudState)
1027 {
1028 gameView->SetHudEnable(hudState);
1029 }
1030
GetHudEnable()1031 bool GameController::GetHudEnable()
1032 {
1033 return gameView->GetHudEnable();
1034 }
1035
SetDebugHUD(bool hudState)1036 void GameController::SetDebugHUD(bool hudState)
1037 {
1038 gameView->SetDebugHUD(hudState);
1039 }
1040
GetDebugHUD()1041 bool GameController::GetDebugHUD()
1042 {
1043 return gameView->GetDebugHUD();
1044 }
1045
SetActiveColourPreset(int preset)1046 void GameController::SetActiveColourPreset(int preset)
1047 {
1048 gameModel->SetActiveColourPreset(preset);
1049 }
1050
SetColour(ui::Colour colour)1051 void GameController::SetColour(ui::Colour colour)
1052 {
1053 gameModel->SetColourSelectorColour(colour);
1054 gameModel->SetPresetColour(colour);
1055 }
1056
SetActiveMenu(int menuID)1057 void GameController::SetActiveMenu(int menuID)
1058 {
1059 gameModel->SetActiveMenu(menuID);
1060 if(menuID == SC_DECO)
1061 gameModel->SetColourSelectorVisibility(true);
1062 else
1063 gameModel->SetColourSelectorVisibility(false);
1064 }
1065
GetMenuList()1066 std::vector<Menu*> GameController::GetMenuList()
1067 {
1068 return gameModel->GetMenuList();
1069 }
1070
GetNumMenus(bool onlyEnabled)1071 int GameController::GetNumMenus(bool onlyEnabled)
1072 {
1073 int count = 0;
1074 if (onlyEnabled)
1075 {
1076 std::vector<Menu*> menuList = gameModel->GetMenuList();
1077 for (std::vector<Menu*>::iterator it = menuList.begin(), end = menuList.end(); it != end; ++it)
1078 if ((*it)->GetVisible())
1079 count++;
1080 }
1081 else
1082 count = gameModel->GetMenuList().size();
1083 return count;
1084 }
1085
RebuildFavoritesMenu()1086 void GameController::RebuildFavoritesMenu()
1087 {
1088 gameModel->BuildFavoritesMenu();
1089 }
1090
GetActiveTool(int selection)1091 Tool * GameController::GetActiveTool(int selection)
1092 {
1093 return gameModel->GetActiveTool(selection);
1094 }
1095
SetActiveTool(int toolSelection,Tool * tool)1096 void GameController::SetActiveTool(int toolSelection, Tool * tool)
1097 {
1098 if (gameModel->GetActiveMenu() == SC_DECO && toolSelection == 2)
1099 toolSelection = 0;
1100 gameModel->SetActiveTool(toolSelection, tool);
1101 gameModel->GetRenderer()->gravityZonesEnabled = false;
1102 if (toolSelection == 3)
1103 gameModel->GetSimulation()->replaceModeSelected = tool->GetToolID();
1104 gameModel->SetLastTool(tool);
1105 for(int i = 0; i < 3; i++)
1106 {
1107 if(gameModel->GetActiveTool(i) == gameModel->GetMenuList().at(SC_WALL)->GetToolList().at(WL_GRAV))
1108 gameModel->GetRenderer()->gravityZonesEnabled = true;
1109 }
1110 if(tool->GetIdentifier() == "DEFAULT_UI_PROPERTY")
1111 ((PropertyTool *)tool)->OpenWindow(gameModel->GetSimulation());
1112 }
1113
SetActiveTool(int toolSelection,ByteString identifier)1114 void GameController::SetActiveTool(int toolSelection, ByteString identifier)
1115 {
1116 Tool *tool = gameModel->GetToolFromIdentifier(identifier);
1117 if (!tool)
1118 return;
1119 SetActiveTool(toolSelection, tool);
1120 }
1121
SetLastTool(Tool * tool)1122 void GameController::SetLastTool(Tool * tool)
1123 {
1124 gameModel->SetLastTool(tool);
1125 }
1126
GetReplaceModeFlags()1127 int GameController::GetReplaceModeFlags()
1128 {
1129 return gameModel->GetSimulation()->replaceModeFlags;
1130 }
1131
SetReplaceModeFlags(int flags)1132 void GameController::SetReplaceModeFlags(int flags)
1133 {
1134 int old_flags = gameModel->GetSimulation()->replaceModeFlags;
1135 if (!(old_flags & REPLACE_MODE) && (flags & REPLACE_MODE))
1136 {
1137 // if replace mode has just been enabled, disable specific delete
1138 flags &= ~SPECIFIC_DELETE;
1139 }
1140 if (!(old_flags & SPECIFIC_DELETE) && (flags & SPECIFIC_DELETE))
1141 {
1142 // if specific delete has just been enabled, disable replace mode
1143 flags &= ~REPLACE_MODE;
1144 }
1145 if ((flags & SPECIFIC_DELETE) && (flags & REPLACE_MODE))
1146 {
1147 // if both have just been enabled, arbitrarily disable one of them
1148 flags &= ~SPECIFIC_DELETE;
1149 }
1150 gameModel->GetSimulation()->replaceModeFlags = flags;
1151 }
1152
OpenSearch(String searchText)1153 void GameController::OpenSearch(String searchText)
1154 {
1155 if(!search)
1156 search = new SearchController([this] {
1157 if (search->GetLoadedSave())
1158 {
1159 try
1160 {
1161 HistorySnapshot();
1162 gameModel->SetSave(search->GetLoadedSave(), gameView->ShiftBehaviour());
1163 search->ReleaseLoadedSave();
1164 }
1165 catch(GameModelException & ex)
1166 {
1167 new ErrorMessage("Cannot open save", ByteString(ex.what()).FromUtf8());
1168 }
1169 }
1170 });
1171 if (searchText.length())
1172 search->DoSearch2(searchText);
1173 ui::Engine::Ref().ShowWindow(search->GetView());
1174 }
1175
OpenLocalSaveWindow(bool asCurrent)1176 void GameController::OpenLocalSaveWindow(bool asCurrent)
1177 {
1178 Simulation * sim = gameModel->GetSimulation();
1179 GameSave * gameSave = sim->Save(gameModel->GetIncludePressure() != gameView->ShiftBehaviour());
1180 if(!gameSave)
1181 {
1182 new ErrorMessage("Error", "Unable to build save.");
1183 }
1184 else
1185 {
1186 gameSave->paused = gameModel->GetPaused();
1187
1188 SaveFile tempSave("");
1189 if (gameModel->GetSaveFile())
1190 {
1191 tempSave.SetFileName(gameModel->GetSaveFile()->GetName());
1192 tempSave.SetDisplayName(gameModel->GetSaveFile()->GetDisplayName());
1193 }
1194 tempSave.SetGameSave(gameSave);
1195
1196 if (!asCurrent || !gameModel->GetSaveFile())
1197 {
1198 new LocalSaveActivity(tempSave, [this](SaveFile *file) {
1199 gameModel->SetSaveFile(file, gameView->ShiftBehaviour());
1200 });
1201 }
1202 else if (gameModel->GetSaveFile())
1203 {
1204 Json::Value localSaveInfo;
1205 localSaveInfo["type"] = "localsave";
1206 localSaveInfo["username"] = Client::Ref().GetAuthUser().Username;
1207 localSaveInfo["title"] = gameModel->GetSaveFile()->GetName();
1208 localSaveInfo["date"] = (Json::Value::UInt64)time(NULL);
1209 Client::Ref().SaveAuthorInfo(&localSaveInfo);
1210 gameSave->authors = localSaveInfo;
1211
1212 gameModel->SetSaveFile(&tempSave, gameView->ShiftBehaviour());
1213 Client::Ref().MakeDirectory(LOCAL_SAVE_DIR);
1214 std::vector<char> saveData = gameSave->Serialise();
1215 if (saveData.size() == 0)
1216 new ErrorMessage("Error", "Unable to serialize game data.");
1217 else if (Client::Ref().WriteFile(saveData, gameModel->GetSaveFile()->GetName()))
1218 new ErrorMessage("Error", "Unable to write save file.");
1219 else
1220 gameModel->SetInfoTip("Saved Successfully");
1221 }
1222 }
1223 }
1224
LoadSaveFile(SaveFile * file)1225 void GameController::LoadSaveFile(SaveFile * file)
1226 {
1227 gameModel->SetSaveFile(file, gameView->ShiftBehaviour());
1228 }
1229
1230
LoadSave(SaveInfo * save)1231 void GameController::LoadSave(SaveInfo * save)
1232 {
1233 gameModel->SetSave(save, gameView->ShiftBehaviour());
1234 }
1235
OpenSaveDone()1236 void GameController::OpenSaveDone()
1237 {
1238 if (activePreview->GetDoOpen() && activePreview->GetSaveInfo())
1239 {
1240 try
1241 {
1242 HistorySnapshot();
1243 LoadSave(activePreview->GetSaveInfo());
1244 }
1245 catch(GameModelException & ex)
1246 {
1247 new ErrorMessage("Cannot open save", ByteString(ex.what()).FromUtf8());
1248 }
1249 }
1250 }
1251
OpenSavePreview(int saveID,int saveDate,bool instant)1252 void GameController::OpenSavePreview(int saveID, int saveDate, bool instant)
1253 {
1254 activePreview = new PreviewController(saveID, saveDate, instant, [this] { OpenSaveDone(); });
1255 ui::Engine::Ref().ShowWindow(activePreview->GetView());
1256 }
1257
OpenSavePreview()1258 void GameController::OpenSavePreview()
1259 {
1260 if(gameModel->GetSave())
1261 {
1262 activePreview = new PreviewController(gameModel->GetSave()->GetID(), 0, false, [this] { OpenSaveDone(); });
1263 ui::Engine::Ref().ShowWindow(activePreview->GetView());
1264 }
1265 }
1266
OpenLocalBrowse()1267 void GameController::OpenLocalBrowse()
1268 {
1269 new FileBrowserActivity(LOCAL_SAVE_DIR PATH_SEP, [this](std::unique_ptr<SaveFile> file) {
1270 HistorySnapshot();
1271 LoadSaveFile(file.get());
1272 });
1273 }
1274
OpenLogin()1275 void GameController::OpenLogin()
1276 {
1277 loginWindow = new LoginController();
1278 ui::Engine::Ref().ShowWindow(loginWindow->GetView());
1279 }
1280
OpenProfile()1281 void GameController::OpenProfile()
1282 {
1283 if(Client::Ref().GetAuthUser().UserID)
1284 {
1285 new ProfileActivity(Client::Ref().GetAuthUser().Username);
1286 }
1287 else
1288 {
1289 loginWindow = new LoginController();
1290 ui::Engine::Ref().ShowWindow(loginWindow->GetView());
1291 }
1292 }
1293
OpenElementSearch()1294 void GameController::OpenElementSearch()
1295 {
1296 std::vector<Tool*> toolList;
1297 std::vector<Menu*> menuList = gameModel->GetMenuList();
1298 for(auto *mm : menuList)
1299 {
1300 if(!mm)
1301 continue;
1302 std::vector<Tool*> menuToolList = mm->GetToolList();
1303 if(!menuToolList.size())
1304 continue;
1305 toolList.insert(toolList.end(), menuToolList.begin(), menuToolList.end());
1306 }
1307 std::vector<Tool*> hiddenTools = gameModel->GetUnlistedTools();
1308 toolList.insert(toolList.end(), hiddenTools.begin(), hiddenTools.end());
1309 new ElementSearchActivity(this, toolList);
1310 }
1311
OpenColourPicker()1312 void GameController::OpenColourPicker()
1313 {
1314 new ColourPickerActivity(gameModel->GetColourSelectorColour(), [this](ui::Colour colour) {
1315 SetColour(colour);
1316 });
1317 }
1318
OpenTags()1319 void GameController::OpenTags()
1320 {
1321 if(gameModel->GetSave() && gameModel->GetSave()->GetID())
1322 {
1323 delete tagsWindow;
1324 tagsWindow = new TagsController([this] { gameView->NotifySaveChanged(gameModel); }, gameModel->GetSave());
1325 ui::Engine::Ref().ShowWindow(tagsWindow->GetView());
1326 }
1327 else
1328 {
1329 new ErrorMessage("Error", "No save open");
1330 }
1331 }
1332
OpenStamps()1333 void GameController::OpenStamps()
1334 {
1335 localBrowser = new LocalBrowserController([this] {
1336 SaveFile *file = localBrowser->GetSave();
1337 if (file)
1338 {
1339 if (file->GetError().length())
1340 new ErrorMessage("Error loading stamp", file->GetError());
1341 else if (localBrowser->GetMoveToFront())
1342 Client::Ref().MoveStampToFront(file->GetDisplayName().ToUtf8());
1343 LoadStamp(file->GetGameSave());
1344 }
1345 });
1346 ui::Engine::Ref().ShowWindow(localBrowser->GetView());
1347 }
1348
OpenOptions()1349 void GameController::OpenOptions()
1350 {
1351 options = new OptionsController(gameModel, [this] {
1352 gameModel->UpdateQuickOptions();
1353 Client::Ref().WritePrefs();
1354 });
1355 ui::Engine::Ref().ShowWindow(options->GetView());
1356
1357 }
1358
ShowConsole()1359 void GameController::ShowConsole()
1360 {
1361 if (!console)
1362 console = new ConsoleController(NULL, commandInterface);
1363 if (console->GetView() != ui::Engine::Ref().GetWindow())
1364 ui::Engine::Ref().ShowWindow(console->GetView());
1365 }
1366
HideConsole()1367 void GameController::HideConsole()
1368 {
1369 if (!console)
1370 return;
1371 console->GetView()->CloseActiveWindow();
1372 }
1373
OpenRenderOptions()1374 void GameController::OpenRenderOptions()
1375 {
1376 renderOptions = new RenderController(gameModel->GetRenderer(), NULL);
1377 ui::Engine::Ref().ShowWindow(renderOptions->GetView());
1378 }
1379
OpenSaveWindow()1380 void GameController::OpenSaveWindow()
1381 {
1382 if(gameModel->GetUser().UserID)
1383 {
1384 Simulation * sim = gameModel->GetSimulation();
1385 GameSave * gameSave = sim->Save(gameModel->GetIncludePressure() != gameView->ShiftBehaviour());
1386 if(!gameSave)
1387 {
1388 new ErrorMessage("Error", "Unable to build save.");
1389 }
1390 else
1391 {
1392 gameSave->paused = gameModel->GetPaused();
1393
1394 if(gameModel->GetSave())
1395 {
1396 SaveInfo tempSave(*gameModel->GetSave());
1397 tempSave.SetGameSave(gameSave);
1398 new ServerSaveActivity(tempSave, [this](SaveInfo &save) {
1399 save.SetVote(1);
1400 save.SetVotesUp(1);
1401 LoadSave(&save);
1402 });
1403 }
1404 else
1405 {
1406 SaveInfo tempSave(0, 0, 0, 0, 0, gameModel->GetUser().Username, "");
1407 tempSave.SetGameSave(gameSave);
1408 new ServerSaveActivity(tempSave, [this](SaveInfo &save) {
1409 save.SetVote(1);
1410 save.SetVotesUp(1);
1411 LoadSave(&save);
1412 });
1413 }
1414 }
1415 }
1416 else
1417 {
1418 new ErrorMessage("Error", "You need to login to upload saves.");
1419 }
1420 }
1421
SaveAsCurrent()1422 void GameController::SaveAsCurrent()
1423 {
1424 if(gameModel->GetSave() && gameModel->GetUser().UserID && gameModel->GetUser().Username == gameModel->GetSave()->GetUserName())
1425 {
1426 Simulation * sim = gameModel->GetSimulation();
1427 GameSave * gameSave = sim->Save(gameModel->GetIncludePressure() != gameView->ShiftBehaviour());
1428 if(!gameSave)
1429 {
1430 new ErrorMessage("Error", "Unable to build save.");
1431 }
1432 else
1433 {
1434 gameSave->paused = gameModel->GetPaused();
1435
1436 if(gameModel->GetSave())
1437 {
1438 SaveInfo tempSave(*gameModel->GetSave());
1439 tempSave.SetGameSave(gameSave);
1440 new ServerSaveActivity(tempSave, true, [this](SaveInfo &save) { LoadSave(&save); });
1441 }
1442 else
1443 {
1444 SaveInfo tempSave(0, 0, 0, 0, 0, gameModel->GetUser().Username, "");
1445 tempSave.SetGameSave(gameSave);
1446 new ServerSaveActivity(tempSave, true, [this](SaveInfo &save) { LoadSave(&save); });
1447 }
1448 }
1449 }
1450 else if(gameModel->GetUser().UserID)
1451 {
1452 OpenSaveWindow();
1453 }
1454 else
1455 {
1456 new ErrorMessage("Error", "You need to login to upload saves.");
1457 }
1458 }
1459
FrameStep()1460 void GameController::FrameStep()
1461 {
1462 gameModel->FrameStep(1);
1463 gameModel->SetPaused(true);
1464 }
1465
Vote(int direction)1466 void GameController::Vote(int direction)
1467 {
1468 if(gameModel->GetSave() && gameModel->GetUser().UserID && gameModel->GetSave()->GetID() && gameModel->GetSave()->GetVote()==0)
1469 {
1470 try
1471 {
1472 gameModel->SetVote(direction);
1473 }
1474 catch(GameModelException & ex)
1475 {
1476 new ErrorMessage("Error while voting", ByteString(ex.what()).FromUtf8());
1477 }
1478 }
1479 }
1480
ChangeBrush()1481 void GameController::ChangeBrush()
1482 {
1483 auto prev_size = gameModel->GetBrush()->GetRadius();
1484 gameModel->SetBrushID(gameModel->GetBrushID()+1);
1485 gameModel->GetBrush()->SetRadius(prev_size);
1486 }
1487
ClearSim()1488 void GameController::ClearSim()
1489 {
1490 HistorySnapshot();
1491 gameModel->SetSave(NULL, false);
1492 gameModel->ClearSimulation();
1493 }
1494
ElementResolve(int type,int ctype)1495 String GameController::ElementResolve(int type, int ctype)
1496 {
1497 if (gameModel && gameModel->GetSimulation())
1498 {
1499 return gameModel->GetSimulation()->ElementResolve(type, ctype);
1500 }
1501 return "";
1502 }
1503
BasicParticleInfo(Particle const & sample_part)1504 String GameController::BasicParticleInfo(Particle const &sample_part)
1505 {
1506 if (gameModel && gameModel->GetSimulation())
1507 {
1508 return gameModel->GetSimulation()->BasicParticleInfo(sample_part);
1509 }
1510 return "";
1511 }
1512
ReloadSim()1513 void GameController::ReloadSim()
1514 {
1515 if(gameModel->GetSave() && gameModel->GetSave()->GetGameSave())
1516 {
1517 HistorySnapshot();
1518 gameModel->SetSave(gameModel->GetSave(), gameView->ShiftBehaviour());
1519 }
1520 else if(gameModel->GetSaveFile() && gameModel->GetSaveFile()->GetGameSave())
1521 {
1522 HistorySnapshot();
1523 gameModel->SetSaveFile(gameModel->GetSaveFile(), gameView->ShiftBehaviour());
1524 }
1525 }
1526
IsValidElement(int type)1527 bool GameController::IsValidElement(int type)
1528 {
1529 if(gameModel && gameModel->GetSimulation())
1530 {
1531 return (type && gameModel->GetSimulation()->IsValidElement(type));
1532 }
1533 else
1534 return false;
1535 }
1536
WallName(int type)1537 String GameController::WallName(int type)
1538 {
1539 if(gameModel && gameModel->GetSimulation() && type >= 0 && type < UI_WALLCOUNT)
1540 return gameModel->GetSimulation()->wtypes[type].name;
1541 else
1542 return String();
1543 }
1544
Record(bool record)1545 int GameController::Record(bool record)
1546 {
1547 return gameView->Record(record);
1548 }
1549
NotifyAuthUserChanged(Client * sender)1550 void GameController::NotifyAuthUserChanged(Client * sender)
1551 {
1552 User newUser = sender->GetAuthUser();
1553 gameModel->SetUser(newUser);
1554 }
1555
NotifyNewNotification(Client * sender,std::pair<String,ByteString> notification)1556 void GameController::NotifyNewNotification(Client * sender, std::pair<String, ByteString> notification)
1557 {
1558 class LinkNotification : public Notification
1559 {
1560 ByteString link;
1561 public:
1562 LinkNotification(ByteString link_, String message) : Notification(message), link(link_) {}
1563 virtual ~LinkNotification() {}
1564
1565 void Action() override
1566 {
1567 Platform::OpenURI(link);
1568 }
1569 };
1570 gameModel->AddNotification(new LinkNotification(notification.second, notification.first));
1571 }
1572
NotifyUpdateAvailable(Client * sender)1573 void GameController::NotifyUpdateAvailable(Client * sender)
1574 {
1575 class UpdateNotification : public Notification
1576 {
1577 GameController * c;
1578 public:
1579 UpdateNotification(GameController * c, String message) : Notification(message), c(c) {}
1580 virtual ~UpdateNotification() {}
1581
1582 void Action() override
1583 {
1584 UpdateInfo info = Client::Ref().GetUpdateInfo();
1585 StringBuilder updateMessage;
1586 #ifndef MACOSX
1587 updateMessage << "Are you sure you want to run the updater? Please save any changes before updating.\n\nCurrent version:\n ";
1588 #else
1589 updateMessage << "Click \"Continue\" to download the latest version from our website.\n\nCurrent version:\n ";
1590 #endif
1591
1592 #ifdef SNAPSHOT
1593 updateMessage << "Snapshot " << SNAPSHOT_ID;
1594 #elif MOD_ID > 0
1595 updateMessage << "Mod version " << SNAPSHOT_ID;
1596 #elif defined(BETA)
1597 updateMessage << SAVE_VERSION << "." << MINOR_VERSION << " Beta, Build " << BUILD_NUM;
1598 #else
1599 updateMessage << SAVE_VERSION << "." << MINOR_VERSION << " Stable, Build " << BUILD_NUM;
1600 #endif
1601
1602 updateMessage << "\nNew version:\n ";
1603 if (info.Type == UpdateInfo::Beta)
1604 updateMessage << info.Major << "." << info.Minor << " Beta, Build " << info.Build;
1605 else if (info.Type == UpdateInfo::Snapshot)
1606 #if MOD_ID > 0
1607 updateMessage << "Mod version " << info.Time;
1608 #else
1609 updateMessage << "Snapshot " << info.Time;
1610 #endif
1611 else if(info.Type == UpdateInfo::Stable)
1612 updateMessage << info.Major << "." << info.Minor << " Stable, Build " << info.Build;
1613
1614 if (info.Changelog.length())
1615 updateMessage << "\n\nChangelog:\n" << info.Changelog;
1616
1617 new ConfirmPrompt("Run Updater", updateMessage.Build(), { [this] { c->RunUpdater(); } });
1618 }
1619 };
1620
1621 switch(sender->GetUpdateInfo().Type)
1622 {
1623 case UpdateInfo::Snapshot:
1624 #if MOD_ID > 0
1625 gameModel->AddNotification(new UpdateNotification(this, "A new mod update is available - click here to update"));
1626 #else
1627 gameModel->AddNotification(new UpdateNotification(this, "A new snapshot is available - click here to update"));
1628 #endif
1629 break;
1630 case UpdateInfo::Stable:
1631 gameModel->AddNotification(new UpdateNotification(this, "A new version is available - click here to update"));
1632 break;
1633 case UpdateInfo::Beta:
1634 gameModel->AddNotification(new UpdateNotification(this, "A new beta is available - click here to update"));
1635 break;
1636 }
1637 }
1638
RemoveNotification(Notification * notification)1639 void GameController::RemoveNotification(Notification * notification)
1640 {
1641 gameModel->RemoveNotification(notification);
1642 }
1643
RunUpdater()1644 void GameController::RunUpdater()
1645 {
1646 #ifndef MACOSX
1647 Exit();
1648 new UpdateActivity();
1649 #else
1650
1651 #ifdef UPDATESERVER
1652 ByteString file = ByteString::Build(SCHEME, UPDATESERVER, Client::Ref().GetUpdateInfo().File);
1653 #else
1654 ByteString file = ByteString::Build(SCHEME, SERVER, Client::Ref().GetUpdateInfo().File);
1655 #endif
1656
1657 Platform::OpenURI(file);
1658 #endif // MACOSX
1659 }
1660
GetMouseClickRequired()1661 bool GameController::GetMouseClickRequired()
1662 {
1663 return gameModel->GetMouseClickRequired();
1664 }
1665