2 Copyright (C) 2004-2011 Parallel Realities
3 Copyright (C) 2011-2015 Perpendicular Dimensions
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 See the GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 extern void doMusicInfo(unsigned int);
26 void createStatsPanel(int page)
28 SDL_Surface *image = graphics.getSprite("infoPanel", true)->image[0];
30 graphics.drawRect(1, 1, image->w - 2, image->h - 2, graphics.black, graphics.white, image);
38 graphics.setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
40 graphics.drawString(_("Metal Blob Solid : Statistics"), 200, y, true, image);
43 Sprite *arrows = graphics.getSprite("HubArrows", true);
48 graphics.drawString(_("Skill Level:"), x1, y += 20, false, image);
49 snprintf(string, sizeof string, "%s", _(skill[game.skill]));
50 graphics.drawString(string, x2, y, false, image);
52 graphics.drawString(_("Score:"), x1, y += 20, false, image);
53 snprintf(string, sizeof string, "%d", game.score);
54 graphics.drawString(string, x2, y, false, image);
56 graphics.drawString(_("MIAs Saved:"), x1, y += 20, false, image);
57 snprintf(string, sizeof string, "%d", game.totalMIAsRescued);
58 graphics.drawString(string, x2, y, false, image);
60 graphics.drawString(_("Objectives Completed:"), x1, y += 20, false, image);
61 snprintf(string, sizeof string, "%d", game.totalObjectivesCompleted);
62 graphics.drawString(string, x2, y, false, image);
64 // Don't do this on Extreme or it will always say 100%
67 graphics.drawString(_("Percentage Complete:"), x1, y += 20, false, image);
68 snprintf(string, sizeof string, "%d%%", gameData.getPercentageComplete());
69 graphics.drawString(string, x2, y, false, image);
72 snprintf(string, sizeof string, "%s - %.2d:%.2d:%.2d", _("Total Game Time"), game.totalHours, game.totalMinutes, game.totalSeconds);
73 graphics.drawString(string, 200, y += 110, true, image);
79 graphics.drawString(_("Enemies Defeated:"), x1, y += 20, false, image);
80 snprintf(string, sizeof string, "%d", game.totalEnemiesDefeated);
81 graphics.drawString(string, x2, y, false, image);
83 graphics.drawString(_("Items Collected:"), x1, y += 20, false, image);
84 snprintf(string, sizeof string, "%d", game.totalItemsCollected);
85 graphics.drawString(string, x2, y, false, image);
87 graphics.drawString(_("Bonuses Picked Up:"), x1, y += 20, false, image);
88 snprintf(string, sizeof string, "%d", game.totalBonusesCollected);
89 graphics.drawString(string, x2, y, false, image);
91 graphics.drawString(_("Best Combo:"), x1, y += 20, false, image);
92 snprintf(string, sizeof string, _("%d Hits"), game.maxComboHits);
93 graphics.drawString(string, x2, y, false, image);
95 graphics.drawString(_("Missions Started:"), x1, y += 20, false, image);
96 snprintf(string, sizeof string, "%d", game.levelsStarted);
97 graphics.drawString(string, x2, y, false, image);
99 graphics.drawString(_("Continues Used:"), x1, y += 20, false, image);
100 snprintf(string, sizeof string, "%d", game.continuesUsed);
101 graphics.drawString(string, x2, y, false, image);
103 if ((game.continuesUsed > 0) && (game.levelsStarted > 0))
105 graphics.drawString(_("Average Continue Usage:"), x1, y += 20, false, image);
106 snprintf(string, sizeof string, "%d", (game.continuesUsed / game.levelsStarted));
107 graphics.drawString(string, x2, y, false, image);
110 graphics.drawString(_("Escapes Used:"), x1, y += 20, false, image);
111 snprintf(string, sizeof string, "%d", game.escapes);
112 graphics.drawString(string, x2, y, false, image);
122 graphics.drawString(_("Weapon"), x1, y += 20, false, image);
123 graphics.drawString(_("Ammo Used"), x2, y, false, image);
124 graphics.drawString(_("Accuracy"), x3, y, false, image);
126 graphics.drawString(_("Pistol"), x1, y += 30, false, image);
127 snprintf(string, sizeof string, "%d", game.bulletsFired[WP_PISTOL]);
128 graphics.drawString(string, x2, y, false, image);
129 snprintf(string, sizeof string, "%d%%", game.getWeaponAccuracy(WP_PISTOL));
130 graphics.drawString(string, x3, y, false, image);
132 graphics.drawString(_("Machine Gun"), x1, y += 20, false, image);
133 snprintf(string, sizeof string, "%d", game.bulletsFired[WP_MACHINEGUN]);
134 graphics.drawString(string, x2, y, false, image);
135 snprintf(string, sizeof string, "%d%%", game.getWeaponAccuracy(WP_MACHINEGUN));
136 graphics.drawString(string, x3, y, false, image);
138 graphics.drawString(_("Laser Cannon"), x1, y += 20, false, image);
139 snprintf(string, sizeof string, "%d", game.bulletsFired[WP_LASER]);
140 graphics.drawString(string, x2, y, false, image);
141 snprintf(string, sizeof string, "%d%%", game.getWeaponAccuracy(WP_LASER));
142 graphics.drawString(string, x3, y, false, image);
144 graphics.drawString(_("Grenades"), x1, y += 20, false, image);
145 snprintf(string, sizeof string, "%d", game.bulletsFired[WP_GRENADES]);
146 graphics.drawString(string, x2, y, false, image);
147 snprintf(string, sizeof string, "%d%%", game.getWeaponAccuracy(WP_GRENADES));
148 graphics.drawString(string, x3, y, false, image);
150 graphics.drawString(_("Spread Gun"), x1, y += 20, false, image);
151 snprintf(string, sizeof string, "%d", game.bulletsFired[WP_SPREAD]);
152 graphics.drawString(string, x2, y, false, image);
153 snprintf(string, sizeof string, "%d%%", game.getWeaponAccuracy(WP_SPREAD));
154 graphics.drawString(string, x3, y, false, image);
156 graphics.drawString(_("Total"), x1, y += 30, false, image);
157 snprintf(string, sizeof string, "%d", game.getTotalBulletsFired());
158 graphics.drawString(string, x2, y, false, image);
159 snprintf(string, sizeof string, "%d%%", game.getTotalAccuracy());
160 graphics.drawString(string, x3, y, false, image);
162 snprintf(string, sizeof string, "%s - %s", _("Most Used Weapon"), _(weapon[game.getMostUsedWeapon()].name));
163 graphics.drawString(string, 200, y += 50, true, image);
168 graphics.blit(arrows->image[0], 150, 260, image, false);
169 graphics.blit(arrows->image[2], 200, 260, image, false);
172 graphics.blit(arrows->image[1], 150, 260, image, false);
175 graphics.blit(arrows->image[3], 200, 260, image, false);
178 void loadLevelBrief(const char *levelName)
180 char briefLine[1024];
182 if (!engine.loadData(_("data/levelBrief")))
184 graphics.showErrorAndExit("Couldn't load mission briefing file (%s)", _("data/levelBrief"));
187 char *line = strtok((char*)engine.dataBuffer, "\n");
188 bool collectData = false;
189 SDL_Surface *image = graphics.getSprite("infoPanel", true)->image[0];
193 graphics.clearChatString();
199 sscanf(line, "%[^\n\r]", briefLine);
201 if (strcmp(briefLine, "@EOF@") == 0)
207 graphics.createChatString(line);
213 sscanf(line, "%*c %[^]]", briefLine);
214 if (strcmp(briefLine, levelName) == 0)
219 line = strtok(NULL, "\n");
230 graphics.drawChatString(image, 40);
233 void createObjectivesPanel(const char *levelName)
235 SDL_Surface *image = graphics.getSprite("infoPanel", true)->image[0];
237 Data *data = (Data*)gameData.dataList.getHead();
241 graphics.drawRect(1, 1, image->w - 2, image->h - 2, graphics.black, graphics.white, image);
244 char levelMIAKey[100];
249 snprintf(levelMIAKey, sizeof levelMIAKey, "%s MIAs", levelName);
251 graphics.setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
253 snprintf(string, sizeof string, _("Information for %s"), _(levelName));
254 graphics.drawString(string, 200, y, true, image);
257 while (data->next != NULL)
259 data = (Data*)data->next;
261 if ((strcmp(data->key, levelName) == 0) || (strstr(data->key, levelMIAKey)))
265 if (strstr(data->key, "MIAs"))
267 // if it says 0 / 0 don't bother...
268 if (strcmp(data->value, "0 / 0"))
270 graphics.drawString(_("MIAs Rescued"), x1, y += 20, false, image);
271 snprintf(string, sizeof string, "%d / %d", data->current, data->target);
272 (data->isComplete()) ? graphics.setFontColor(0x00, 0xff, 0x00, 0x00, 0x00, 0x00) : graphics.setFontColor(0xff, 0x00, 0x00, 0x00, 0x00, 0x00);
273 graphics.drawString(string, x2, y, false, image);
276 else if (!strstr(data->value, "MIA_"))
278 if ((game.skill < 3) && (strstr(data->value, "L.R.T.S.")) && (!gameData.completedWorld))
280 graphics.drawString(_("???? ???????? ????"), x1, y += 20, false, image);
284 strlcpy(string, _(data->value), sizeof string);
286 if (strlen(string) >= 25)
289 // don't break unicode characters
290 while (((string[cut_char] >> 6) & 3) == 2)
295 string[cut_char++] = '.';
296 string[cut_char++] = '.';
297 string[cut_char++] = '.';
298 string[cut_char] = '\0';
301 graphics.drawString(string, x1, y += 20, false, image);
304 if (data->target == 1)
306 snprintf(string, sizeof string, "%s", (data->isComplete()) ? _("Completed") : _("Incomplete"));
310 snprintf(string, sizeof string, "%d / %d", data->current, data->target);
313 (data->isComplete()) ? graphics.setFontColor(0x00, 0xff, 0x00, 0x00, 0x00, 0x00) : graphics.setFontColor(0xff, 0x00, 0x00, 0x00, 0x00, 0x00);
314 graphics.drawString(string, x2, y, false, image);
318 graphics.setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
322 loadLevelBrief(levelName);
325 void createMIAPanel(int start, int max)
337 SDL_Surface *image = graphics.getSprite("infoPanel", true)->image[0];
339 Data *data = (Data*)gameData.dataList.getHead();
341 graphics.drawRect(1, 1, image->w - 2, image->h - 2, graphics.black, graphics.white, image);
343 graphics.setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
345 graphics.drawString(_("MIA Statistics"), 200, y, true, image);
347 graphics.drawString(_("Name"), x1, y += 20, false, image);
348 graphics.drawString(_("Location"), x2, y, false, image);
349 graphics.drawString(_("Status"), x3, y, false, image);
353 while (data->next != NULL)
355 data = (Data*)data->next;
357 if (strstr(data->value, "MIA_"))
365 snprintf(name, sizeof name, "%s", data->value);
368 snprintf(string, sizeof string, "%s", strtok(NULL, "_"));
369 graphics.drawString(string, x1, y += 20, false, image);
371 graphics.drawString(_(data->key), x2, y, false, image);
373 if (data->isComplete())
375 snprintf(string, sizeof string, "%s", _("Found"));
376 graphics.setFontColor(0x00, 0xff, 0x00, 0x00, 0x00, 0x00);
380 snprintf(string, sizeof string, "%s", _("Missing"));
381 graphics.setFontColor(0xff, 0x00, 0x00, 0x00, 0x00, 0x00);
384 graphics.drawString(string, x3, y, false, image);
386 graphics.setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
395 Sprite *arrows = graphics.getSprite("HubArrows", true);
398 graphics.blit(arrows->image[0], 150, 260, image, false);
400 graphics.blit(arrows->image[1], 150, 260, image, false);
402 if ((end == 9) && (current + 9 < max))
403 graphics.blit(arrows->image[2], 200, 260, image, false);
405 graphics.blit(arrows->image[3], 200, 260, image, false);
408 bool requirementMet(const char *requiredLevel)
410 if (strstr(requiredLevel, "Stages"))
413 sscanf(requiredLevel, "%*s %d", &stages);
415 if (game.stagesCleared >= stages)
417 presentPlayerMedal(requiredLevel);
422 if (engine.cheatLevels)
427 if (strcmp(requiredLevel, "@none@") == 0)
432 return gameData.requiredLevelCleared(requiredLevel);
437 SDL_FillRect(graphics.screen, NULL, graphics.black);
438 graphics.delay(1000);
443 graphics.loadBackground("gfx/main/worldMap.jpg");
444 audio.loadMusic("music/hub");
446 // we might want this now, for medals
447 audio.loadSound(SND_ITEM, "sound/item");
449 graphics.quickSprite("cheatHeader", graphics.loadImage("gfx/main/cheats.png"));
450 graphics.quickSprite("optionsHeader", graphics.loadImage("gfx/main/options.png"));
451 graphics.quickSprite("keyHeader", graphics.loadImage("gfx/main/keyConfig.png"));
452 graphics.quickSprite("joystickHeader", graphics.loadImage("gfx/main/joystickConfig.png"));
453 graphics.quickSprite("optionsBackground", graphics.loadImage("gfx/main/optionsBackground.png"));
457 Sprite *cursor = graphics.addSprite("Cursor");
458 for (int i = 0 ; i < 6 ; i++)
460 snprintf(string, sizeof string, "gfx/main/cursor%d.png", i + 1);
461 cursor->setFrame(i, graphics.loadImage(string), 10);
464 Sprite *newTarget = graphics.addSprite("NewTarget");
465 Sprite *visitedTarget = graphics.addSprite("VisitedTarget");
467 for (int i = 0 ; i < 5 ; i++)
469 snprintf(string, sizeof string, "gfx/sprites/miaSignal%d.png", i + 1);
471 newTarget->setFrame(i, graphics.loadImage(string, -60, 0, 0), 15);
472 visitedTarget->setFrame(i, graphics.loadImage(string, 0, 0, 0), 15);
475 Sprite *hubIcons = graphics.addSprite("HubIcons");
476 for (int i = 0 ; i < 6 ; i++)
478 snprintf(string, sizeof string, "gfx/main/hubIcon%d.png", i + 1);
479 hubIcons->setFrame(i, graphics.loadImage(string), 60);
482 SDL_Surface *infoPanel = graphics.quickSprite("infoPanel", graphics.createSurface(400, 300));
484 Sprite *hubArrows = graphics.addSprite("HubArrows");
485 hubArrows->setFrame(0, graphics.loadImage("gfx/main/hubArrowLeft.png"), 60);
486 hubArrows->setFrame(1, graphics.loadImage("gfx/main/hubArrowLeft2.png"), 60);
487 hubArrows->setFrame(2, graphics.loadImage("gfx/main/hubArrowRight.png"), 60);
488 hubArrows->setFrame(3, graphics.loadImage("gfx/main/hubArrowRight2.png"), 60);
493 engine.loadData("data/hub");
495 char *line = strtok((char*)engine.dataBuffer, "\n");
497 char name[50], level[50], requiredLevel[50];
504 graphics.setFontSize(0);
505 graphics.setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
507 int numberOfHubs = 0;
509 gameData.calculateWorldCompleted();
513 sscanf(line, "%*c %[^\"] %*c %*c %[^\"] %*c %d %d %*c %[^\"] %*c", name, level, &x, &y, requiredLevel);
515 if (strcmp(name, "@EOF@") == 0)
520 // don't show boss levels on Easy (they might be cheating!)
523 if (strstr(name, "BioMech"))
525 line = strtok(NULL, "\n");
530 if (requirementMet(requiredLevel))
532 if (!gameData.levelPrefectlyCleared(name))
534 hubPoint = new HubLevel;
535 hubPoint->set(name, level, x, y);
536 hubPoint->levelNameImage = graphics.getString(_(name), false);
538 (!gameData.stagePreviouslyCleared(name)) ? hubPoint->target = newTarget : hubPoint->target = visitedTarget;
540 hubList.add(hubPoint);
545 line = strtok(NULL, "\n");
550 strlcpy(level, "@none@", sizeof level);
551 strlcpy(game.stageName, "@none@", sizeof game.stageName);
553 bool showData = false;
554 bool showStats = false;
555 bool showMIAs = false;
563 Data *data = (Data*)gameData.dataList.getHead();
565 while (data->next != NULL)
567 data = (Data*)data->next;
569 if (strstr(data->value, "MIA_"))
575 bool validStage = false;
577 if ((numberOfHubs == 0) && (gameData.completedWorld))
579 game.setMapName("data/spaceStation");
580 strlcpy(game.stageName, "Space Station", sizeof game.stageName);
581 createObjectivesPanel("Space Station");
583 showStats = showMIAs = false;
586 // Wait wait wait... we're in easy mode. Game ends here.
590 return SECTION_EASYOVER;
593 presentPlayerMedal("World_Complete");
599 Uint32 frameLimit = SDL_GetTicks() + 16;
600 Uint32 now = SDL_GetTicks();
607 graphics.updateScreen();
608 graphics.drawBackground();
609 graphics.animateSprites();
613 static Graphics::SurfaceCache cache;
614 graphics.drawRect(10, 400, 620, 20, graphics.black, graphics.white, graphics.screen);
615 snprintf(string, sizeof string, "%s : %s", _("Selected Destination"), _(game.stageName));
616 graphics.drawString(string, 320, 409, true, graphics.screen, cache);
619 graphics.drawRect(10, 430, 620, 40, graphics.black, graphics.white, graphics.screen);
622 static Graphics::SurfaceCache posCache;
623 snprintf(pos, sizeof pos, "%.3d:%.3d", engine.getMouseX(), engine.getMouseY());
624 graphics.drawString(pos, 320, 15, true, graphics.screen, posCache);
630 if (config.isControl(CONTROL::RIGHT))
635 if (config.isControl(CONTROL::LEFT))
640 if (config.isControl(CONTROL::DOWN))
645 if (config.isControl(CONTROL::UP) || config.isControl(CONTROL::JUMP))
650 if ((mouseXDelta != 0) || (mouseYDelta != 0))
652 engine.setMouse(engine.getMouseX() + (int)mouseXDelta, engine.getMouseY() + (int)mouseYDelta);
657 hubPoint = (HubLevel*)hubList.getHead();
659 // Collisions for Hub Points
660 while (hubPoint->next != NULL)
662 hubPoint = (HubLevel*)hubPoint->next;
664 graphics.blit(hubPoint->target->getCurrentFrame(), hubPoint->x, hubPoint->y, graphics.screen, false);
666 if (Collision::collision(engine.getMouseX(), engine.getMouseY(), 1, 1, hubPoint->x, hubPoint->y, 16, 16))
668 labelX = engine.getMouseX();
669 labelY = engine.getMouseY() - 20;
671 labelWidth = hubPoint->levelNameImage->w / 2;
673 Math::limitInt(&labelX, 10 + labelWidth, 630 - labelWidth);
675 graphics.blit(hubPoint->levelNameImage, labelX, labelY, graphics.screen, true);
677 if (engine.mouseLeft || config.isControl(CONTROL::FIRE))
679 game.setMapName(hubPoint->filename);
680 game.setStageName(hubPoint->stageName);
682 engine.mouseLeft = 0;
683 config.resetControl(CONTROL::FIRE);
686 if (engine.mouseRight || config.isControl(CONTROL::MAP))
688 game.setMapName(hubPoint->filename);
689 game.setStageName(hubPoint->stageName);
690 createObjectivesPanel(game.stageName);
693 engine.mouseRight = 0;
694 config.resetControl(CONTROL::MAP);
699 // Collisions for Panel
700 for (int i = ((1 - validStage) * 2) ; i < 6 ; i++)
702 graphics.blit(hubIcons->image[i], 50 + (i * 100), 440, graphics.screen, false);
703 if (Collision::collision(engine.getMouseX(), engine.getMouseY(), 1, 1, 50 + (i * 100), 440, hubIcons->image[i]->w, hubIcons->image[i]->h))
705 if (engine.mouseLeft || config.isControl(CONTROL::FIRE))
713 createObjectivesPanel(game.stageName);
714 showData = !showData;
715 showStats = showMIAs = false;
718 createMIAPanel(miaStart, miaMax);
719 showStats = showData = false;
720 showMIAs = !showMIAs;
723 createStatsPanel(page);
724 showStats = !showStats;
725 showData = showMIAs = false;
729 graphics.setFontSize(0);
730 graphics.setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
737 engine.mouseLeft = false;
738 config.resetControl(CONTROL::FIRE);
743 // Collisions for Panel Buttons
744 if ((showMIAs) || (showStats))
746 // SDL_SCANCODE_LCTRL is the "fire" button.
747 if (engine.mouseLeft || config.isControl(CONTROL::FIRE))
749 if (Collision::collision(engine.getMouseX(), engine.getMouseY(), 1, 1, 270, 310, 32, 32))
755 Math::limitInt(&(miaStart -= 9), 0, miaMax);
756 createMIAPanel(miaStart, miaMax);
762 Math::limitInt(&(--page), 0, 2);
763 createStatsPanel(page);
766 engine.mouseLeft = 0;
767 config.resetControl(CONTROL::FIRE);
771 if (Collision::collision(engine.getMouseX(), engine.getMouseY(), 1, 1, 320, 310, 32, 32))
775 if (miaStart + 9 < miaMax)
777 Math::limitInt(&(miaStart += 9), 0, miaMax);
778 createMIAPanel(miaStart, miaMax);
784 Math::limitInt(&(++page), 0, 2);
785 createStatsPanel(page);
788 engine.mouseLeft = 0;
789 config.resetControl(CONTROL::FIRE);
794 if ((showData) || (showStats) || (showMIAs))
796 graphics.blit(infoPanel, 320, 200, graphics.screen, true);
797 if (engine.mouseLeft || config.isControl(CONTROL::FIRE))
799 showData = showStats = showMIAs = false;
803 graphics.blit(cursor->getCurrentFrame(), engine.getMouseX(), engine.getMouseY(), graphics.screen, true);
805 doMusicInfo(SDL_GetTicks() - (now + 60000));
806 engine.delay(frameLimit);
807 frameLimit = SDL_GetTicks() + 16;