1 /*
2 * Hedgewars, a free turn based strategy game
3 * Copyright (c) 2004-2015 Andrey Korotaev <unC0Rr@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 2 of the License
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include <QApplication>
20
21 #include <QString>
22 #include <QCheckBox>
23 #include <QByteArray>
24 #include <QUuid>
25 #include <QColor>
26 #include <QStringListModel>
27 #include <QTextStream>
28 #include <utility>
29
30 #include "hwform.h"
31 #include "ui/page/pageoptions.h"
32 #include "ui/page/pagetraining.h"
33 #include "ui/page/pagecampaign.h"
34 #include "game.h"
35 #include "hwconsts.h"
36 #include "gameuiconfig.h"
37 #include "gamecfgwidget.h"
38 #include "teamselect.h"
39 #include "proto.h"
40 #include "binds.h"
41 #include "campaign.h"
42
43 #include <QTextStream>
44 #include "ThemeModel.h"
45
46 // last game info
47 QList<QVariant> lastGameStartArgs = QList<QVariant>();
48 GameType lastGameType = gtNone;
49 GameCFGWidget * lastGameCfg = NULL;
50 QString lastGameAmmo = NULL;
51 TeamSelWidget * lastGameTeamSel = NULL;
52
53 QString trainingName, trainingScript, trainingTeam, campaign, campaignScript, campaignTeam; // TODO: Cleaner solution?
54
HWGame(GameUIConfig * config,GameCFGWidget * gamecfg,QString ammo,TeamSelWidget * pTeamSelWidget)55 HWGame::HWGame(GameUIConfig * config, GameCFGWidget * gamecfg, QString ammo, TeamSelWidget* pTeamSelWidget) :
56 TCPBase(true, !config->language().isEmpty(), 0),
57 ammostr(ammo),
58 m_pTeamSelWidget(pTeamSelWidget)
59 {
60 this->config = config;
61 this->gamecfg = gamecfg;
62 netSuspend = false;
63
64 lastGameCfg = gamecfg;
65 lastGameAmmo = ammo;
66 lastGameTeamSel = pTeamSelWidget;
67
68 gameState = gsNotStarted;
69 gameType = gtNone;
70 }
71
~HWGame()72 HWGame::~HWGame()
73 {
74 SetGameState(gsDestroyed);
75 }
76
onClientDisconnect()77 void HWGame::onClientDisconnect()
78 {
79 if (demoIsPresent)
80 {
81 switch (gameType)
82 {
83 case gtDemo:
84 // for video recording we need demo anyway
85 emit HaveRecord(rtNeither, demo);
86 break;
87 case gtNet:
88 emit HaveRecord(rtDemo, demo);
89 break;
90 default:
91 if (gameState == gsInterrupted || gameState == gsHalted)
92 emit HaveRecord(rtSave, demo);
93 else if (gameState == gsFinished)
94 emit HaveRecord(rtDemo, demo);
95 else
96 emit HaveRecord(rtNeither, demo);
97 }
98 }
99 else
100 {
101 emit HaveRecord(rtNeither, demo);
102 }
103 SetGameState(gsStopped);
104 }
105
commonConfig()106 void HWGame::commonConfig()
107 {
108 QByteArray buf;
109 QString gt;
110 switch (gameType)
111 {
112 case gtDemo:
113 gt = "TD";
114 break;
115 case gtNet:
116 gt = "TN";
117 break;
118 default:
119 gt = "TL";
120 }
121 HWProto::addStringToBuffer(buf, gt);
122
123 buf += gamecfg->getFullConfig();
124
125 if (m_pTeamSelWidget)
126 {
127 foreach(HWTeam team, m_pTeamSelWidget->getPlayingTeams())
128 {
129 HWProto::addStringToBuffer(buf, QString("eammloadt %1").arg(ammostr.mid(0, cAmmoNumber)));
130 HWProto::addStringToBuffer(buf, QString("eammprob %1").arg(ammostr.mid(cAmmoNumber, cAmmoNumber)));
131 HWProto::addStringToBuffer(buf, QString("eammdelay %1").arg(ammostr.mid(2 * cAmmoNumber, cAmmoNumber)));
132 HWProto::addStringToBuffer(buf, QString("eammreinf %1").arg(ammostr.mid(3 * cAmmoNumber, cAmmoNumber)));
133 if(gamecfg->schemeData(15).toBool() || !gamecfg->schemeData(21).toBool()) HWProto::addStringToBuffer(buf, QString("eammstore"));
134 HWProto::addStringListToBuffer(buf,
135 team.teamGameConfig(gamecfg->getInitHealth()));
136 ;
137 }
138 }
139
140 RawSendIPC(buf);
141 }
142
SendConfig()143 void HWGame::SendConfig()
144 {
145 commonConfig();
146 }
147
SendQuickConfig()148 void HWGame::SendQuickConfig()
149 {
150 /* Load and increase Quick Game experience level.
151 Experience increases by 1 for each started game and maxes out
152 at 20. Low experience levels will introduce a "beginner's bias" to make
153 the first quick games easier and simpler. The max. possible difficulty
154 increases progressively the longer you play.
155 If experience is maxed out, the beginner's bias is gone and quick games
156 are completely random. */
157 int exp = config->quickGameExperience();
158 if(exp < 20)
159 {
160 config->setQuickGameExperience(exp + 1);
161 }
162 qDebug("Starting quick game ...");
163 qDebug("Quick Game experience level: %d", exp);
164
165 // Init stuff
166 QByteArray teamscfg;
167 QAbstractItemModel * themeModel = DataManager::instance().themeModel()->withoutHidden();
168
169 HWProto::addStringToBuffer(teamscfg, "TL");
170
171 // Random seed
172 HWProto::addStringToBuffer(teamscfg, "eseed " + QUuid::createUuid().toString());
173
174 int r, minhogs, maxhogs;
175
176 // Random map type
177 r = rand() % 10000;
178 if(r < 3000) { // 30%
179 // Random
180 r = 0;
181 } else if(r < 5250) { // 22.5%
182 // Maze
183 if(exp <= 3)
184 r = 0;
185 else
186 r = 1;
187 } else if(r < 7490) { // 22.4%
188 // Perlin
189 if(exp <= 7)
190 r = 1;
191 else
192 r = 2;
193 } else if(r < 7500 && exp >= 5) { // 0.1%
194 // Floating Flowers (just for fun)
195 r = 5;
196 } else if(r < 8750) { // 12.5%
197 // Image map
198 r = 3;
199 } else { // 12.5%
200 // Forts
201 r = 4;
202 }
203 switch(r)
204 {
205 // Random map
206 default:
207 case 0: {
208 r = rand() % 3;
209 if(r == 0)
210 {
211 // small island
212 HWProto::addStringToBuffer(teamscfg, "e$template_filter 1");
213 minhogs = 3;
214 maxhogs = 4;
215 }
216 else if(r == 1 || exp <= 6)
217 {
218 // medium island
219 HWProto::addStringToBuffer(teamscfg, "e$template_filter 2");
220 minhogs = 4;
221 maxhogs = 5;
222 }
223 else
224 {
225 // cave (locked at low experience because these maps can be huge)
226 HWProto::addStringToBuffer(teamscfg, "e$template_filter 4");
227 minhogs = 4;
228 maxhogs = 6;
229 }
230 HWProto::addStringToBuffer(teamscfg, "e$feature_size "+QString::number(rand()%18+4));
231 break;
232 }
233 // Maze
234 case 1: {
235 minhogs = 4;
236 maxhogs = 6;
237 HWProto::addStringToBuffer(teamscfg, "e$mapgen 1");
238 HWProto::addStringToBuffer(teamscfg, "e$template_filter "+QString::number(rand()%6));
239 HWProto::addStringToBuffer(teamscfg, "e$feature_size "+QString::number(rand()%16+6));
240 break;
241 }
242 // Perlin
243 case 2: {
244 minhogs = 4;
245 maxhogs = 6;
246 HWProto::addStringToBuffer(teamscfg, "e$mapgen 2");
247 HWProto::addStringToBuffer(teamscfg, "e$template_filter "+QString::number(rand()%6));
248 HWProto::addStringToBuffer(teamscfg, "e$feature_size "+QString::number(rand()%18+4));
249 break;
250 }
251 // Image map
252 case 3: {
253 minhogs = 4;
254 maxhogs = 6;
255 HWProto::addStringToBuffer(teamscfg, "e$mapgen 3");
256 // Select map from hardcoded list.
257 // TODO: find a more dynamic solution.
258 r = rand() % cQuickGameMaps.count();
259 HWProto::addStringToBuffer(teamscfg, "e$map " + cQuickGameMaps[r]);
260 break;
261 }
262 // Forts
263 case 4: {
264 minhogs = 4;
265 maxhogs = 6;
266 HWProto::addStringToBuffer(teamscfg, "e$mapgen 4");
267 HWProto::addStringToBuffer(teamscfg, "e$feature_size "+QString::number(rand()%20+1));
268 break;
269 }
270 // Floating Flowers
271 // (actually empty map; this forces the engine to generate fallback structures to have
272 // something for hogs to stand on)
273 case 5: {
274 minhogs = 4;
275 maxhogs = 8;
276 HWProto::addStringToBuffer(teamscfg, "e$mapgen 3");
277 HWProto::addStringToBuffer(teamscfg, "e$feature_size "+QString::number(rand()%4+3));
278 break;
279 }
280 }
281
282 // Theme
283 HWProto::addStringToBuffer(teamscfg, QString("etheme %1")
284 .arg((themeModel->rowCount() > 0) ? themeModel->index(rand() % themeModel->rowCount(), 0).data(ThemeModel::ActualNameRole).toString() : "Nature"));
285
286 int hogs = minhogs + rand() % (maxhogs-minhogs+1);
287 // Cap hog count at low experience
288 if((exp <= 8) && (hogs > 5))
289 hogs = 5;
290 else if((exp <= 5) && (hogs > 4))
291 hogs = 4;
292
293 // Teams
294 // Player team
295 HWTeam team1;
296 team1.setDifficulty(0);
297 team1.setColor(0);
298 team1.setNumHedgehogs(hogs);
299 HWNamegen::teamRandomEverything(team1);
300 team1.setVoicepack("Default_qau");
301
302 // Computer team
303 HWTeam team2;
304 // Random difficulty.
305 // Max. possible difficulty is capped at low experience levels.
306 if(exp >= 15) // very easy to very hard (full range)
307 r = 5 - rand() % 5;
308 else if(exp >= 9) // very easy to hard
309 r = 5 - rand() % 4;
310 else if(exp >= 6) // very easy to medium
311 r = 5 - rand() % 3;
312 else if(exp >= 2) // very easy to easy
313 r = 5 - rand() % 2;
314 else // very easy
315 r = 5;
316 team2.setDifficulty(r);
317 team2.setColor(1);
318 team2.setNumHedgehogs(hogs);
319 // Make sure the team names are not equal
320 do
321 HWNamegen::teamRandomEverything(team2);
322 while(!team2.name().compare(team1.name()) || !team2.hedgehog(0).Hat.compare(team1.hedgehog(0).Hat));
323 team2.setVoicepack("Default_qau");
324
325 // Team play order
326 r = rand() % 2;
327 if(r == 0 || exp <= 4) // player plays first
328 {
329 HWProto::addStringListToBuffer(teamscfg, team1.teamGameConfig(100));
330 HWProto::addStringListToBuffer(teamscfg, team2.teamGameConfig(100));
331 }
332 else // computer plays first
333 {
334 HWProto::addStringListToBuffer(teamscfg, team2.teamGameConfig(100));
335 HWProto::addStringListToBuffer(teamscfg, team1.teamGameConfig(100));
336 }
337
338 // Ammo scheme "Default"
339 // TODO: Random schemes
340 HWProto::addStringToBuffer(teamscfg, QString("eammloadt %1").arg(cDefaultAmmoStore->mid(0, cAmmoNumber)));
341 HWProto::addStringToBuffer(teamscfg, QString("eammprob %1").arg(cDefaultAmmoStore->mid(cAmmoNumber, cAmmoNumber)));
342 HWProto::addStringToBuffer(teamscfg, QString("eammdelay %1").arg(cDefaultAmmoStore->mid(2 * cAmmoNumber, cAmmoNumber)));
343 HWProto::addStringToBuffer(teamscfg, QString("eammreinf %1").arg(cDefaultAmmoStore->mid(3 * cAmmoNumber, cAmmoNumber)));
344 HWProto::addStringToBuffer(teamscfg, QString("eammstore"));
345 HWProto::addStringToBuffer(teamscfg, QString("eammstore"));
346
347 RawSendIPC(teamscfg);
348 }
349
SendTrainingConfig()350 void HWGame::SendTrainingConfig()
351 {
352 QByteArray traincfg;
353 HWProto::addStringToBuffer(traincfg, "TL");
354
355 HWTeam missionTeam = HWTeam();
356 missionTeam.setName(config->Form->ui.pageTraining->CBTeam->currentText());
357 missionTeam.loadFromFile();
358 missionTeam.setNumHedgehogs(HEDGEHOGS_PER_TEAM);
359 missionTeam.setMissionTeam(true);
360 HWProto::addStringListToBuffer(traincfg, missionTeam.teamGameConfig(100));
361
362 HWProto::addStringToBuffer(traincfg, "eseed " + QUuid::createUuid().toString());
363 HWProto::addStringToBuffer(traincfg, "escript " + trainingScript);
364
365 RawSendIPC(traincfg);
366 }
367
SendCampaignConfig()368 void HWGame::SendCampaignConfig()
369 {
370 QByteArray campaigncfg;
371 HWProto::addStringToBuffer(campaigncfg, "TL");
372
373 HWTeam missionTeam = HWTeam();
374 missionTeam.setName(config->Form->ui.pageCampaign->CBTeam->currentText());
375 missionTeam.loadFromFile();
376 missionTeam.setNumHedgehogs(HEDGEHOGS_PER_TEAM);
377 missionTeam.setMissionTeam(true);
378 HWProto::addStringListToBuffer(campaigncfg, missionTeam.teamGameConfig(100));
379
380 HWProto::addStringToBuffer(campaigncfg, "eseed " + QUuid::createUuid().toString());
381 HWProto::addStringToBuffer(campaigncfg, "escript " + campaignScript);
382
383 RawSendIPC(campaigncfg);
384 }
385
SendNetConfig()386 void HWGame::SendNetConfig()
387 {
388 commonConfig();
389 }
390
ParseMessage(const QByteArray & msg)391 void HWGame::ParseMessage(const QByteArray & msg)
392 {
393 switch(msg.at(1))
394 {
395 case '?':
396 {
397 SendIPC("!");
398 break;
399 }
400 case 'C':
401 {
402 switch (gameType)
403 {
404 case gtLocal:
405 {
406 SendConfig();
407 break;
408 }
409 case gtQLocal:
410 {
411 SendQuickConfig();
412 break;
413 }
414 case gtNone:
415 case gtSave:
416 case gtDemo:
417 break;
418 case gtNet:
419 {
420 SendNetConfig();
421 break;
422 }
423 case gtTraining:
424 {
425 SendTrainingConfig();
426 break;
427 }
428 case gtCampaign:
429 {
430 SendCampaignConfig();
431 break;
432 }
433 }
434 break;
435 }
436 case 'E':
437 {
438 int size = msg.size();
439 emit ErrorMessage(
440 tr("A fatal ERROR occured! The game engine had to stop.\n\n"
441 "We are very sorry for the inconvenience. :-(\n\n"
442 "If this keeps happening, please click the 'Feedback' button in the main menu!\n\n"
443 "Last engine message:\n%1")
444 .arg(QString::fromUtf8(msg.mid(2).left(size - 4))));
445 return;
446 }
447 case 'i':
448 {
449 emit GameStats(msg.at(2), QString::fromUtf8(msg.mid(3)));
450 break;
451 }
452 case 'Q':
453 {
454 SetGameState(gsInterrupted);
455 break;
456 }
457 case 'q':
458 {
459 SetGameState(gsFinished);
460 break;
461 }
462 case 'm':
463 {
464 SetDemoPresence(false);
465 break;
466 }
467 case 'H':
468 {
469 SetGameState(gsHalted);
470 break;
471 }
472 case 's':
473 {
474 int size = msg.size();
475 QString msgbody = QString::fromUtf8(msg.mid(2).left(size - 4));
476 emit SendChat(msgbody);
477 QByteArray buf;
478 HWProto::addStringToBuffer(buf, "s" + HWProto::formatChatMsg(config->netNick(), msgbody) + "\x20\x20");
479 demo.append(buf);
480 break;
481 }
482 case 'b':
483 {
484 int size = msg.size();
485 QString msgbody = QString::fromUtf8(msg.mid(2).left(size - 4));
486 emit SendTeamMessage(msgbody);
487 break;
488 }
489 case 'V':
490 {
491 if (msg.at(2) == '?')
492 sendCampaignVar(msg.right(msg.size() - 3));
493 else if (msg.at(2) == '!')
494 writeCampaignVar(msg.right(msg.size() - 3));
495 break;
496 }
497 case 'v':
498 {
499 if (msg.at(2) == '?')
500 sendMissionVar(msg.right(msg.size() - 3));
501 else if (msg.at(2) == '!')
502 writeMissionVar(msg.right(msg.size() - 3));
503 break;
504 }
505 case 'W':
506 {
507 // fetch new window resolution via IPC and save it in the settings
508 int size = msg.size();
509 QString newResolution = QString().append(msg.mid(2)).left(size - 4);
510 bool windowMaximized;
511 if (newResolution.endsWith('M'))
512 {
513 windowMaximized = true;
514 newResolution.chop(1);
515 }
516 else
517 {
518 windowMaximized = false;
519 }
520 QStringList wh = newResolution.split('x');
521 config->Form->ui.pageOptions->windowWidthEdit->setValue(wh[0].toInt());
522 config->Form->ui.pageOptions->windowHeightEdit->setValue(wh[1].toInt());
523 config->vid_SetMaximized(windowMaximized);
524 break;
525 }
526 case '~':
527 {
528 int size = msg.size();
529 QString msgbody = QString::fromUtf8(msg.mid(2).left(size - 4));
530 emit SendConsoleCommand(msgbody);
531 break;
532 }
533 default:
534 {
535 if (gameType == gtNet && !netSuspend)
536 m_netSendBuffer.append(msg);
537
538 demo.append(msg);
539 }
540 }
541 }
542
FromNet(const QByteArray & msg)543 void HWGame::FromNet(const QByteArray & msg)
544 {
545 RawSendIPC(msg);
546 }
547
FromNetChat(const QString & msg)548 void HWGame::FromNetChat(const QString & msg)
549 {
550 QByteArray buf;
551 HWProto::addStringToBuffer(buf, 's' + msg + "\x20\x20");
552 RawSendIPC(buf);
553 }
554
FromNetWarning(const QString & msg)555 void HWGame::FromNetWarning(const QString & msg)
556 {
557 QByteArray buf;
558 HWProto::addStringToBuffer(buf, "s\x00" + msg + "\x20\x20");
559 RawSendIPC(buf);
560 }
561
FromNetError(const QString & msg)562 void HWGame::FromNetError(const QString & msg)
563 {
564 QByteArray buf;
565 HWProto::addStringToBuffer(buf, "s\x05" + msg + "\x20\x20");
566 RawSendIPC(buf);
567 }
568
onClientRead()569 void HWGame::onClientRead()
570 {
571 quint8 msglen;
572 quint32 bufsize;
573 while (!readbuffer.isEmpty() && ((bufsize = readbuffer.size()) > 0) &&
574 ((msglen = readbuffer.data()[0]) < bufsize))
575 {
576 QByteArray msg = readbuffer.left(msglen + 1);
577 readbuffer.remove(0, msglen + 1);
578 ParseMessage(msg);
579 }
580
581 flushNetBuffer();
582 }
583
flushNetBuffer()584 void HWGame::flushNetBuffer()
585 {
586 if(m_netSendBuffer.size())
587 {
588 emit SendNet(m_netSendBuffer);
589
590 m_netSendBuffer.clear();
591 }
592 }
593
getArguments()594 QStringList HWGame::getArguments()
595 {
596 QStringList arguments;
597 std::pair<QRect, QRect> resolutions = config->vid_ResolutionPair();
598 QString nick = config->netNick().toUtf8().toBase64();
599
600 arguments << "--internal"; //Must be passed as first argument
601 arguments << "--port";
602 arguments << QString("%1").arg(ipc_port);
603 arguments << "--prefix";
604 arguments << datadir->absolutePath();
605 arguments << "--user-prefix";
606 arguments << cfgdir->absolutePath();
607 arguments << "--locale";
608 // TODO: Don't bother translators with this nonsense and detect this file automatically.
609 //: IMPORTANT: This text has a special meaning, do not translate it directly. This is the file name of translation files for the game engine, found in Data/Locale/. Usually, you replace “en” with the ISO-639-1 language code of your language.
610 arguments << tr("en.txt");
611 arguments << "--frame-interval";
612 arguments << QString::number(config->timerInterval());
613 arguments << "--volume";
614 arguments << QString::number(config->volume());
615 arguments << "--fullscreen-width";
616 arguments << QString::number(resolutions.first.width());
617 arguments << "--fullscreen-height";
618 arguments << QString::number(resolutions.first.height());
619 arguments << "--width";
620 arguments << QString::number(resolutions.second.width());
621 arguments << "--height";
622 arguments << QString::number(resolutions.second.height());
623 if (config->vid_Maximized())
624 arguments << "--maximized";
625 if (config->zoom() != 100) {
626 arguments << "--zoom";
627 arguments << QString::number(config->zoom());
628 }
629 arguments << "--raw-quality";
630 arguments << QString::number(config->translateQuality());
631 arguments << "--stereo";
632 arguments << QString::number(config->stereoMode());
633 if (config->vid_Fullscreen())
634 arguments << "--fullscreen";
635 if (config->isShowFPSEnabled())
636 arguments << "--showfps";
637 if (config->isAltDamageEnabled())
638 arguments << "--altdmg";
639 if (!config->isSoundEnabled())
640 arguments << "--nosound";
641 if (!config->isMusicEnabled())
642 arguments << "--nomusic";
643 if (!config->isAudioDampenEnabled())
644 arguments << "--nodampen";
645 if (!nick.isEmpty()) {
646 arguments << "--nick";
647 arguments << nick;
648 }
649
650 if (!config->Form->ui.pageOptions->CBTeamTag->isChecked())
651 arguments << "--no-teamtag";
652 if (!config->Form->ui.pageOptions->CBHogTag->isChecked())
653 arguments << "--no-hogtag";
654 if (!config->Form->ui.pageOptions->CBHealthTag->isChecked())
655 arguments << "--no-healthtag";
656 if (config->Form->ui.pageOptions->CBTagOpacity->isChecked())
657 arguments << "--translucent-tags";
658 if (!config->isHolidaySillinessEnabled())
659 arguments << "--no-holiday-silliness";
660
661 return arguments;
662 }
663
PlayDemo(const QString & demofilename,bool isSave)664 void HWGame::PlayDemo(const QString & demofilename, bool isSave)
665 {
666 gameType = isSave ? gtSave : gtDemo;
667 lastGameType = gameType;
668 QFile demofile(demofilename);
669 if (!demofile.open(QIODevice::ReadOnly))
670 {
671 emit ErrorMessage(tr("Cannot open demofile %1").arg(demofilename));
672 return ;
673 }
674
675 // read demo
676 toSendBuf = demofile.readAll();
677
678 // run engine
679 demo.clear();
680 Start(false);
681 SetGameState(gsStarted);
682 }
683
PlayOfficialServerDemo()684 void HWGame::PlayOfficialServerDemo()
685 {
686 // TODO: Use gtDemo so fast-forward is available.
687 // Needs engine support first.
688 lastGameStartArgs.clear();
689 lastGameType = gtLocal;
690
691 gameType = gtLocal;
692 demo.clear();
693 Start(false);
694 SetGameState(gsStarted);
695 }
696
StartNet()697 void HWGame::StartNet()
698 {
699 lastGameStartArgs.clear();
700 lastGameType = gtNet;
701
702 gameType = gtNet;
703 demo.clear();
704 Start(false);
705 SetGameState(gsStarted);
706 }
707
StartLocal()708 void HWGame::StartLocal()
709 {
710 lastGameStartArgs.clear();
711 lastGameType = gtLocal;
712
713 gameType = gtLocal;
714 demo.clear();
715 Start(false);
716 SetGameState(gsStarted);
717 }
718
StartQuick()719 void HWGame::StartQuick()
720 {
721 lastGameStartArgs.clear();
722 lastGameType = gtQLocal;
723
724 gameType = gtQLocal;
725 demo.clear();
726 Start(false);
727 SetGameState(gsStarted);
728 }
729
StartTraining(const QString & file,const QString & subFolder,const QString & trainTeam)730 void HWGame::StartTraining(const QString & file, const QString & subFolder, const QString & trainTeam)
731 {
732 lastGameStartArgs.clear();
733 lastGameStartArgs.append(file);
734 lastGameStartArgs.append(subFolder);
735 lastGameStartArgs.append(trainTeam);
736 lastGameType = gtTraining;
737
738 gameType = gtTraining;
739
740 trainingScript = "Missions/" + subFolder + "/" + file + ".lua";
741 trainingName = file;
742 trainingTeam = trainTeam;
743 demo.clear();
744 Start(false);
745 SetGameState(gsStarted);
746 }
747
StartCampaign(const QString & camp,const QString & campScript,const QString & campTeam)748 void HWGame::StartCampaign(const QString & camp, const QString & campScript, const QString & campTeam)
749 {
750 lastGameStartArgs.clear();
751 lastGameStartArgs.append(camp);
752 lastGameStartArgs.append(campScript);
753 lastGameStartArgs.append(campTeam);
754 lastGameType = gtCampaign;
755
756 gameType = gtCampaign;
757 campaign = camp;
758 campaignScript = "Missions/Campaign/" + camp + "/" + campScript;
759 campaignTeam = campTeam;
760 demo.clear();
761 Start(false);
762 SetGameState(gsStarted);
763 }
764
SetGameState(GameState state)765 void HWGame::SetGameState(GameState state)
766 {
767 gameState = state;
768 emit GameStateChanged(state);
769 if (gameType == gtCampaign)
770 {
771 emit CampStateChanged(state);
772 }
773 else if (gameType == gtTraining)
774 {
775 emit TrainingStateChanged(1);
776 }
777 }
778
SetDemoPresence(bool hasDemo)779 void HWGame::SetDemoPresence(bool hasDemo)
780 {
781 emit DemoPresenceChanged(hasDemo);
782 }
783
abort()784 void HWGame::abort()
785 {
786 QByteArray buf;
787 HWProto::addStringToBuffer(buf, QString("eforcequit"));
788 RawSendIPC(buf);
789 }
790
sendCampaignVar(const QByteArray & varToSend)791 void HWGame::sendCampaignVar(const QByteArray &varToSend)
792 {
793 QString varToFind = QString::fromUtf8(varToSend);
794 QSettings teamfile(QString(cfgdir->absolutePath() + "/Teams/%1.hwt").arg(campaignTeam), QSettings::IniFormat, 0);
795 teamfile.setIniCodec("UTF-8");
796 QString varValue = teamfile.value("Campaign " + campaign + "/" + varToFind, "").toString();
797 QByteArray command;
798 HWProto::addStringToBuffer(command, "V." + varValue);
799 RawSendIPC(command);
800 }
801
writeCampaignVar(const QByteArray & varVal)802 void HWGame::writeCampaignVar(const QByteArray & varVal)
803 {
804 int i = varVal.indexOf(" ");
805 if(i < 0)
806 return;
807
808 QString varToWrite = QString::fromUtf8(varVal.left(i));
809 QString varValue = QString::fromUtf8(varVal.mid(i + 1));
810
811 QSettings teamfile(QString(cfgdir->absolutePath() + "/Teams/%1.hwt").arg(campaignTeam), QSettings::IniFormat, 0);
812 teamfile.setIniCodec("UTF-8");
813 teamfile.setValue("Campaign " + campaign + "/" + varToWrite, varValue);
814 }
815
sendMissionVar(const QByteArray & varToSend)816 void HWGame::sendMissionVar(const QByteArray &varToSend)
817 {
818 QString varToFind = QString::fromUtf8(varToSend);
819 QSettings teamfile(QString(cfgdir->absolutePath() + "/Teams/%1.hwt").arg(trainingTeam), QSettings::IniFormat, 0);
820 teamfile.setIniCodec("UTF-8");
821 QString varValue = teamfile.value("Mission " + trainingName + "/" + varToFind, "").toString();
822 QByteArray command;
823 HWProto::addStringToBuffer(command, "v." + varValue);
824 RawSendIPC(command);
825 }
826
writeMissionVar(const QByteArray & varVal)827 void HWGame::writeMissionVar(const QByteArray & varVal)
828 {
829 int i = varVal.indexOf(" ");
830 if(i < 0)
831 return;
832
833 QString varToWrite = QString::fromUtf8(varVal.left(i));
834 QString varValue = QString::fromUtf8(varVal.mid(i + 1));
835
836 QSettings teamfile(QString(cfgdir->absolutePath() + "/Teams/%1.hwt").arg(trainingTeam), QSettings::IniFormat, 0);
837 teamfile.setIniCodec("UTF-8");
838 teamfile.setValue("Mission " + trainingName + "/" + varToWrite, varValue);
839 }
840
841