mirror of
https://github.com/TerryCavanagh/VVVVVV.git
synced 2024-12-23 01:59:43 +01:00
7961 lines
220 KiB
C++
7961 lines
220 KiB
C++
#define GAME_DEFINITION
|
|
#include "Game.h"
|
|
|
|
#include <sstream>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <tinyxml2.h>
|
|
|
|
#include "ButtonGlyphs.h"
|
|
#include "Constants.h"
|
|
#include "CustomLevels.h"
|
|
#include "DeferCallbacks.h"
|
|
#include "Editor.h"
|
|
#include "Entity.h"
|
|
#include "Enums.h"
|
|
#include "FileSystemUtils.h"
|
|
#include "GlitchrunnerMode.h"
|
|
#include "Graphics.h"
|
|
#include "LevelDebugger.h"
|
|
#include "Localization.h"
|
|
#include "LocalizationStorage.h"
|
|
#include "KeyPoll.h"
|
|
#include "MakeAndPlay.h"
|
|
#include "Map.h"
|
|
#include "Music.h"
|
|
#include "Network.h"
|
|
#include "RoomnameTranslator.h"
|
|
#include "Screen.h"
|
|
#include "Script.h"
|
|
#include "Unused.h"
|
|
#include "UTF8.h"
|
|
#include "UtilityClass.h"
|
|
#include "VFormat.h"
|
|
#include "Vlogging.h"
|
|
#include "XMLUtils.h"
|
|
|
|
static bool GetButtonFromString(const char *pText, SDL_GameControllerButton *button)
|
|
{
|
|
if (*pText == '0' ||
|
|
*pText == 'a' ||
|
|
*pText == 'A')
|
|
{
|
|
*button = SDL_CONTROLLER_BUTTON_A;
|
|
return true;
|
|
}
|
|
if (SDL_strcmp(pText, "1") == 0 ||
|
|
*pText == 'b' ||
|
|
*pText == 'B')
|
|
{
|
|
*button = SDL_CONTROLLER_BUTTON_B;
|
|
return true;
|
|
}
|
|
if (*pText == '2' ||
|
|
*pText == 'x' ||
|
|
*pText == 'X')
|
|
{
|
|
*button = SDL_CONTROLLER_BUTTON_X;
|
|
return true;
|
|
}
|
|
if (*pText == '3' ||
|
|
*pText == 'y' ||
|
|
*pText == 'Y')
|
|
{
|
|
*button = SDL_CONTROLLER_BUTTON_Y;
|
|
return true;
|
|
}
|
|
if (*pText == '4' ||
|
|
SDL_strcasecmp(pText, "BACK") == 0)
|
|
{
|
|
*button = SDL_CONTROLLER_BUTTON_BACK;
|
|
return true;
|
|
}
|
|
if (*pText == '5' ||
|
|
SDL_strcasecmp(pText, "GUIDE") == 0)
|
|
{
|
|
*button = SDL_CONTROLLER_BUTTON_GUIDE;
|
|
return true;
|
|
}
|
|
if (*pText == '6' ||
|
|
SDL_strcasecmp(pText, "START") == 0)
|
|
{
|
|
*button = SDL_CONTROLLER_BUTTON_START;
|
|
return true;
|
|
}
|
|
if (*pText == '7' ||
|
|
SDL_strcasecmp(pText, "LS") == 0)
|
|
{
|
|
*button = SDL_CONTROLLER_BUTTON_LEFTSTICK;
|
|
return true;
|
|
}
|
|
if (*pText == '8' ||
|
|
SDL_strcasecmp(pText, "RS") == 0)
|
|
{
|
|
*button = SDL_CONTROLLER_BUTTON_RIGHTSTICK;
|
|
return true;
|
|
}
|
|
if (*pText == '9' ||
|
|
SDL_strcasecmp(pText, "LB") == 0)
|
|
{
|
|
*button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
|
|
return true;
|
|
}
|
|
if (SDL_strcmp(pText, "10") == 0 ||
|
|
SDL_strcasecmp(pText, "RB") == 0)
|
|
{
|
|
*button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Unfortunate forward-declare... My hands are pretty tied
|
|
static void loadthissummary(
|
|
const char* filename,
|
|
struct Game::Summary* summary,
|
|
tinyxml2::XMLDocument& doc
|
|
);
|
|
|
|
static struct Game::Summary get_summary(
|
|
const char* filename,
|
|
const char* savename,
|
|
tinyxml2::XMLDocument& doc
|
|
) {
|
|
tinyxml2::XMLHandle hDoc(&doc);
|
|
struct Game::Summary summary;
|
|
SDL_zero(summary);
|
|
|
|
if (!FILESYSTEM_loadTiXml2Document(filename, doc))
|
|
{
|
|
vlog_info("%s not found", savename);
|
|
return summary;
|
|
}
|
|
|
|
loadthissummary(savename, &summary, doc);
|
|
|
|
return summary;
|
|
}
|
|
|
|
void Game::init(void)
|
|
{
|
|
SDL_strlcpy(magic, "[vVvVvV]game", sizeof(magic));
|
|
|
|
roomx = 0;
|
|
roomy = 0;
|
|
prevroomx = 0;
|
|
prevroomy = 0;
|
|
saverx = 0;
|
|
savery = 0;
|
|
savecolour = 0;
|
|
|
|
mutebutton = 0;
|
|
muted = false;
|
|
musicmuted = false;
|
|
musicmutebutton = 0;
|
|
|
|
glitchrunkludge = false;
|
|
gamestate = TITLEMODE;
|
|
prevgamestate = TITLEMODE;
|
|
hascontrol = true;
|
|
jumpheld = false;
|
|
advancetext = false;
|
|
jumppressed = 0;
|
|
gravitycontrol = 0;
|
|
teleport = false;
|
|
edteleportent = 0; //Added in the port!
|
|
companion = 0;
|
|
|
|
|
|
quickrestartkludge = false;
|
|
|
|
tapleft = 0;
|
|
tapright = 0;
|
|
|
|
press_right = false;
|
|
press_left = false;
|
|
press_action = false;
|
|
press_map = false;
|
|
press_interact = false;
|
|
interactheld = false;
|
|
separate_interact = false;
|
|
mapheld = false;
|
|
|
|
|
|
pausescript = false;
|
|
completestop = false;
|
|
activeactivity = -1;
|
|
act_fade = 0;
|
|
prev_act_fade = 0;
|
|
backgroundtext = false;
|
|
startscript = false;
|
|
inintermission = false;
|
|
|
|
alarmon = false;
|
|
alarmdelay = 0;
|
|
blackout = false;
|
|
creditposx = 0;
|
|
creditposy = 0;
|
|
creditposdelay = 0;
|
|
oldcreditposx = 0;
|
|
|
|
useteleporter = false;
|
|
teleport_to_teleporter = 0;
|
|
|
|
activetele = false;
|
|
readytotele = 0;
|
|
oldreadytotele = 0;
|
|
activity_r = 0;
|
|
activity_g = 0;
|
|
activity_b = 0;
|
|
activity_y = 0;
|
|
creditposition = 0;
|
|
oldcreditposition = 0;
|
|
bestgamedeaths = -1;
|
|
|
|
//Accessibility Options
|
|
colourblindmode = false;
|
|
noflashingmode = false;
|
|
slowdown = 30;
|
|
|
|
nodeathmode = false;
|
|
nocutscenes = false;
|
|
ndmresultcrewrescued = 0;
|
|
ndmresulttrinkets = 0;
|
|
ndmresulthardestroom.clear();
|
|
ndmresulthardestroom_x = hardestroom_x;
|
|
ndmresulthardestroom_y = hardestroom_y;
|
|
ndmresulthardestroom_specialname = false;
|
|
nodeatheligible = false;
|
|
|
|
customcol=0;
|
|
|
|
SDL_memset(crewstats, false, sizeof(crewstats));
|
|
SDL_memset(ndmresultcrewstats, false, sizeof(ndmresultcrewstats));
|
|
SDL_memset(besttimes, -1, sizeof(besttimes));
|
|
SDL_memset(bestframes, -1, sizeof(bestframes));
|
|
SDL_memset(besttrinkets, -1, sizeof(besttrinkets));
|
|
SDL_memset(bestlives, -1, sizeof(bestlives));
|
|
SDL_memset(bestrank, -1, sizeof(bestrank));
|
|
|
|
crewstats[0] = true;
|
|
lastsaved = 0;
|
|
|
|
//Menu stuff initiliased here:
|
|
SDL_memset(unlock, false, sizeof(unlock));
|
|
SDL_memset(unlocknotify, false, sizeof(unlock));
|
|
|
|
currentmenuoption = 0;
|
|
menutestmode = false;
|
|
current_credits_list_index = 0;
|
|
translator_credits_pagenum = 0;
|
|
menuxoff = 0;
|
|
menuyoff = 0;
|
|
menucountdown = 0;
|
|
levelpage=0;
|
|
playcustomlevel=0;
|
|
|
|
silence_settings_error = false;
|
|
|
|
deathcounts = 0;
|
|
gameoverdelay = 0;
|
|
framecounter = 0;
|
|
seed_use_sdl_getticks = false;
|
|
editor_disabled = false;
|
|
resetgameclock();
|
|
gamesaved = false;
|
|
gamesavefailed = false;
|
|
savetime = "00:00";
|
|
savetrinkets = 0;
|
|
|
|
/* These are only used some of the time. */
|
|
saveframes = 0;
|
|
saveseconds = 0;
|
|
|
|
intimetrial = false;
|
|
timetrialcountdown = 0;
|
|
timetrialshinytarget = 0;
|
|
timetrialparlost = false;
|
|
timetrialpar = 0;
|
|
timetrialcheater = false;
|
|
timetrialresulttime = 0;
|
|
timetrialresultframes = 0;
|
|
timetrialresultshinytarget = 0;
|
|
timetrialresulttrinkets = 0;
|
|
timetrialresultpar = 0;
|
|
timetrialresultdeaths = 0;
|
|
start_translator_exploring = false;
|
|
translator_exploring = false;
|
|
translator_exploring_allowtele = false;
|
|
translator_cutscene_test = false;
|
|
|
|
totalflips = 0;
|
|
hardestroom = "Welcome Aboard";
|
|
hardestroomdeaths = 0;
|
|
hardestroom_x = 13;
|
|
hardestroom_y = 5;
|
|
hardestroom_specialname = false;
|
|
hardestroom_finalstretch = false;
|
|
currentroomdeaths=0;
|
|
|
|
inertia = 1.1f;
|
|
swnmode = false;
|
|
swntimer = 0;
|
|
swngame = SWN_NONE; // Not playing sine wave ninja!
|
|
swnstate = 0;
|
|
swnstate2 = 0;
|
|
swnstate3 = 0;
|
|
swnstate4 = 0;
|
|
swndelay = 0;
|
|
swndeaths = 0;
|
|
supercrewmate = false;
|
|
scmhurt = false;
|
|
scmprogress = 0;
|
|
swncolstate = 0;
|
|
swncoldelay = 0;
|
|
swnrecord = 0;
|
|
swnbestrank = 0;
|
|
swnrank = 0;
|
|
swnmessage = 0;
|
|
|
|
clearcustomlevelstats();
|
|
|
|
saveFilePath = FILESYSTEM_getUserSaveDirectory();
|
|
|
|
tinyxml2::XMLDocument doc;
|
|
last_quicksave = get_summary("saves/qsave.vvv", "qsave.vvv", doc);
|
|
|
|
|
|
tinyxml2::XMLDocument docTele;
|
|
last_telesave = get_summary("saves/tsave.vvv", "tsave.vvv", doc);
|
|
|
|
screenshake = flashlight = 0 ;
|
|
|
|
stat_trinkets = 0;
|
|
|
|
state = 1;
|
|
statedelay = 0;
|
|
statelocked = false;
|
|
//updatestate();
|
|
|
|
skipfakeload = false;
|
|
|
|
ghostsenabled = false;
|
|
|
|
cliplaytest = false;
|
|
playx = 0;
|
|
playy = 0;
|
|
playrx = 0;
|
|
playry = 0;
|
|
playgc = 0;
|
|
|
|
fadetomenu = false;
|
|
fadetomenudelay = 0;
|
|
fadetolab = false;
|
|
fadetolabdelay = 0;
|
|
|
|
over30mode = true;
|
|
showingametimer = false;
|
|
|
|
ingame_titlemode = false;
|
|
ingame_editormode = false;
|
|
|
|
kludge_ingametemp = Menu::mainmenu;
|
|
slidermode = SLIDER_NONE;
|
|
|
|
disablepause = false;
|
|
disableaudiopause = false;
|
|
disabletemporaryaudiopause = true;
|
|
inputdelay = false;
|
|
|
|
old_skip_message_timer = 0;
|
|
skip_message_timer = 0;
|
|
|
|
old_mode_indicator_timer = 0;
|
|
mode_indicator_timer = 0;
|
|
|
|
old_screenshot_border_timer = 0;
|
|
screenshot_border_timer = 0;
|
|
screenshot_saved_success = false;
|
|
|
|
#ifdef __ANDROID__
|
|
checkpoint_saving = true;
|
|
#else
|
|
checkpoint_saving = false;
|
|
#endif
|
|
|
|
setdefaultcontrollerbuttons();
|
|
}
|
|
|
|
void Game::setdefaultcontrollerbuttons(void)
|
|
{
|
|
if (controllerButton_flip.size() < 1)
|
|
{
|
|
controllerButton_flip.push_back(SDL_CONTROLLER_BUTTON_A);
|
|
}
|
|
if (controllerButton_map.size() < 1)
|
|
{
|
|
controllerButton_map.push_back(SDL_CONTROLLER_BUTTON_Y);
|
|
}
|
|
if (controllerButton_esc.size() < 1)
|
|
{
|
|
controllerButton_esc.push_back(SDL_CONTROLLER_BUTTON_B);
|
|
}
|
|
if (controllerButton_restart.size() < 1)
|
|
{
|
|
controllerButton_restart.push_back(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
|
|
}
|
|
if (controllerButton_interact.size() < 1)
|
|
{
|
|
controllerButton_interact.push_back(SDL_CONTROLLER_BUTTON_X);
|
|
}
|
|
|
|
/* If one of the arrays was empty, and others weren't, we might now have conflicts...
|
|
* A crucial one is if the ACTION button is also "ESC", because then you can't
|
|
* fix it with just a controller anymore, which might make the game unplayable.
|
|
* This is similar to updatebuttonmappings() in Input.cpp, except less... complete? */
|
|
for (size_t f = 0; f < controllerButton_flip.size(); f++)
|
|
{
|
|
for (size_t e = 0; e < controllerButton_esc.size(); e++)
|
|
{
|
|
if (controllerButton_flip[f] == controllerButton_esc[e])
|
|
{
|
|
controllerButton_esc.erase(controllerButton_esc.begin() + e);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Game::lifesequence(void)
|
|
{
|
|
if (lifeseq > 0)
|
|
{
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].invis = false;
|
|
if (lifeseq == 2) obj.entities[i].invis = true;
|
|
if (lifeseq == 6) obj.entities[i].invis = true;
|
|
if (lifeseq >= 8) obj.entities[i].invis = true;
|
|
}
|
|
if (lifeseq > 5) gravitycontrol = savegc;
|
|
|
|
lifeseq--;
|
|
if (INBOUNDS_VEC(i, obj.entities) && (lifeseq <= 0 || noflashingmode))
|
|
{
|
|
obj.entities[i].invis = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Game::clearcustomlevelstats(void)
|
|
{
|
|
//just clearing the array
|
|
customlevelstats.clear();
|
|
}
|
|
|
|
|
|
void Game::updatecustomlevelstats(std::string clevel, int cscore)
|
|
{
|
|
if (!map.custommodeforreal)
|
|
{
|
|
/* We are playtesting, don't update level stats */
|
|
return;
|
|
}
|
|
|
|
if (clevel.find("levels/") != std::string::npos)
|
|
{
|
|
clevel = clevel.substr(7);
|
|
}
|
|
if (customlevelstats.count(clevel) == 0 || cscore > customlevelstats[clevel])
|
|
{
|
|
customlevelstats[clevel] = cscore;
|
|
}
|
|
savecustomlevelstats();
|
|
}
|
|
|
|
void Game::deletecustomlevelstats(void)
|
|
{
|
|
customlevelstats.clear();
|
|
|
|
if (!FILESYSTEM_delete("saves/levelstats.vvv"))
|
|
{
|
|
vlog_error("Error deleting levelstats.vvv");
|
|
}
|
|
}
|
|
|
|
#define LOAD_ARRAY_RENAME(ARRAY_NAME, DEST) \
|
|
if (SDL_strcmp(pKey, #ARRAY_NAME) == 0 && pText[0] != '\0') \
|
|
{ \
|
|
/* We're loading in 32-bit integers. If we need more than 16 chars,
|
|
* something is seriously wrong */ \
|
|
char buffer[16]; \
|
|
size_t start = 0; \
|
|
size_t i = 0; \
|
|
\
|
|
while (next_split_s(buffer, sizeof(buffer), &start, pText, ',')) \
|
|
{ \
|
|
if (i >= SDL_arraysize(DEST)) \
|
|
{ \
|
|
break; \
|
|
} \
|
|
\
|
|
DEST[i] = help.Int(buffer); \
|
|
++i; \
|
|
} \
|
|
}
|
|
|
|
#define LOAD_ARRAY(ARRAY_NAME) LOAD_ARRAY_RENAME(ARRAY_NAME, ARRAY_NAME)
|
|
|
|
void Game::loadcustomlevelstats(void)
|
|
{
|
|
tinyxml2::XMLDocument doc;
|
|
tinyxml2::XMLHandle hDoc(&doc);
|
|
|
|
if (!FILESYSTEM_loadTiXml2Document("saves/levelstats.vvv", doc))
|
|
{
|
|
//No levelstats file exists; start new
|
|
customlevelstats.clear();
|
|
savecustomlevelstats();
|
|
return;
|
|
}
|
|
|
|
if (doc.Error())
|
|
{
|
|
vlog_error("Error parsing levelstats.vvv: %s", doc.ErrorStr());
|
|
return;
|
|
}
|
|
|
|
customlevelstats.clear();
|
|
|
|
tinyxml2::XMLElement* pElem;
|
|
tinyxml2::XMLElement* firstElement;
|
|
|
|
firstElement = hDoc
|
|
.FirstChildElement()
|
|
.FirstChildElement("Data")
|
|
.FirstChildElement()
|
|
.ToElement();
|
|
|
|
// First pass, look for the new system of storing stats
|
|
// If they don't exist, then fall back to the old system
|
|
for (pElem = firstElement; pElem != NULL; pElem = pElem->NextSiblingElement())
|
|
{
|
|
const char* pKey = pElem->Value();
|
|
const char* pText = pElem->GetText();
|
|
if (pText == NULL)
|
|
{
|
|
pText = "";
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "stats") == 0)
|
|
{
|
|
bool file_has_duplicates = false;
|
|
|
|
for (tinyxml2::XMLElement* stat_el = pElem->FirstChildElement(); stat_el; stat_el = stat_el->NextSiblingElement())
|
|
{
|
|
int score = 0;
|
|
std::string name;
|
|
|
|
if (stat_el->GetText() != NULL)
|
|
{
|
|
score = help.Int(stat_el->GetText());
|
|
}
|
|
|
|
if (stat_el->Attribute("name"))
|
|
{
|
|
name = stat_el->Attribute("name");
|
|
}
|
|
|
|
int existing = customlevelstats.count(name);
|
|
if (existing > 0)
|
|
{
|
|
file_has_duplicates = true;
|
|
}
|
|
|
|
if (existing == 0 || score > customlevelstats[name])
|
|
{
|
|
customlevelstats[name] = score;
|
|
}
|
|
}
|
|
|
|
if (file_has_duplicates)
|
|
{
|
|
/* This might be really inflated, so simply save the map we have now,
|
|
* so we don't have to keep loading a 90 MB file. */
|
|
savecustomlevelstats();
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
// Since we're still here, we must be on the old system
|
|
std::vector<std::string> customlevelnames;
|
|
std::vector<int> customlevelscores;
|
|
|
|
for (pElem = firstElement; pElem; pElem=pElem->NextSiblingElement())
|
|
{
|
|
const char* pKey = pElem->Value();
|
|
const char* pText = pElem->GetText() ;
|
|
if(pText == NULL)
|
|
{
|
|
pText = "";
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "customlevelscore") == 0 && pText[0] != '\0')
|
|
{
|
|
char buffer[16];
|
|
size_t start = 0;
|
|
|
|
while (next_split_s(buffer, sizeof(buffer), &start, pText, ','))
|
|
{
|
|
customlevelscores.push_back(help.Int(buffer));
|
|
}
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "customlevelstats") == 0 && pText[0] != '\0')
|
|
{
|
|
size_t start = 0;
|
|
size_t len = 0;
|
|
size_t prev_start = 0;
|
|
|
|
while (next_split(&start, &len, &pText[start], '|'))
|
|
{
|
|
customlevelnames.push_back(std::string(&pText[prev_start], len));
|
|
|
|
prev_start = start;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If the two arrays happen to differ in length, just go with the smallest one
|
|
for (size_t i = 0; i < SDL_min(customlevelnames.size(), customlevelscores.size()); i++)
|
|
{
|
|
const std::string& name = customlevelnames[i];
|
|
const int score = customlevelscores[i];
|
|
|
|
if (customlevelstats.count(name) == 0 || score > customlevelstats[name])
|
|
{
|
|
customlevelstats[name] = score;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Game::savecustomlevelstats(void)
|
|
{
|
|
tinyxml2::XMLDocument doc;
|
|
bool already_exists = FILESYSTEM_loadTiXml2Document("saves/levelstats.vvv", doc);
|
|
if (!already_exists)
|
|
{
|
|
vlog_info("No levelstats.vvv found. Creating new file");
|
|
}
|
|
else if (doc.Error())
|
|
{
|
|
vlog_error("Error parsing existing levelstats.vvv: %s", doc.ErrorStr());
|
|
vlog_info("Creating new levelstats.vvv");
|
|
}
|
|
|
|
xml::update_declaration(doc);
|
|
|
|
tinyxml2::XMLElement * root = xml::update_element(doc, "Levelstats");
|
|
|
|
xml::update_comment(root, " Levelstats Save file ");
|
|
|
|
tinyxml2::XMLElement * msgs = xml::update_element(root, "Data");
|
|
|
|
int numcustomlevelstats = customlevelstats.size();
|
|
if(numcustomlevelstats>=200)numcustomlevelstats=199;
|
|
xml::update_tag(msgs, "numcustomlevelstats", numcustomlevelstats);
|
|
|
|
std::string customlevelscorestr;
|
|
std::string customlevelstatsstr;
|
|
std::map<std::string, int>::iterator iter;
|
|
for (iter = customlevelstats.begin(); iter != customlevelstats.end(); iter++)
|
|
{
|
|
customlevelscorestr += help.String(iter->second) + ",";
|
|
customlevelstatsstr += iter->first + "|";
|
|
}
|
|
xml::update_tag(msgs, "customlevelscore", customlevelscorestr.c_str());
|
|
xml::update_tag(msgs, "customlevelstats", customlevelstatsstr.c_str());
|
|
|
|
// New system
|
|
tinyxml2::XMLElement* msg = xml::update_element_delete_contents(msgs, "stats");
|
|
tinyxml2::XMLElement* stat_el;
|
|
for (iter = customlevelstats.begin(); iter != customlevelstats.end(); iter++)
|
|
{
|
|
stat_el = doc.NewElement("stat");
|
|
|
|
stat_el->SetAttribute("name", iter->first.c_str());
|
|
stat_el->LinkEndChild(doc.NewText(help.String(iter->second).c_str()));
|
|
|
|
msg->LinkEndChild(stat_el);
|
|
}
|
|
|
|
if(FILESYSTEM_saveTiXml2Document("saves/levelstats.vvv", doc))
|
|
{
|
|
vlog_info("Level stats saved");
|
|
}
|
|
else
|
|
{
|
|
vlog_error("Could Not Save level stats!");
|
|
vlog_error("Failed: %s%s", saveFilePath, "levelstats.vvv");
|
|
}
|
|
}
|
|
|
|
void Game::levelcomplete_textbox(void)
|
|
{
|
|
graphics.createtextboxflipme("", -1, 12, TEXT_COLOUR("cyan"));
|
|
graphics.addline(" ");
|
|
graphics.addline("");
|
|
graphics.addline("");
|
|
graphics.textboxoriginalcontextauto();
|
|
graphics.textboxprintflags(PR_FONT_8X8);
|
|
graphics.textboxcenterx();
|
|
graphics.setimage(TEXTIMAGE_LEVELCOMPLETE);
|
|
graphics.setlinegap(0);
|
|
graphics.textboxapplyposition();
|
|
}
|
|
|
|
static void compute_crewmate_textbox(textboxclass* THIS)
|
|
{
|
|
THIS->lines.clear();
|
|
THIS->addline("");
|
|
|
|
const int extra_cjk_height = (font::height(PR_FONT_INTERFACE) * 4) - 32;
|
|
THIS->yp = 64 + 8 + 16 - extra_cjk_height/2;
|
|
|
|
/* This is a special case for wrapping, we MUST have two lines.
|
|
* So just make sure it can't fit in one line. */
|
|
const char* text = loc::gettext("You have rescued a crew member!");
|
|
std::string wrapped = font::string_wordwrap_balanced(PR_FONT_INTERFACE, text, font::len(PR_FONT_INTERFACE, text)-1);
|
|
|
|
size_t startline = 0;
|
|
size_t newline;
|
|
do {
|
|
size_t pos_n = wrapped.find('\n', startline);
|
|
size_t pos_p = wrapped.find('|', startline);
|
|
newline = SDL_min(pos_n, pos_p);
|
|
THIS->addline(wrapped.substr(startline, newline-startline));
|
|
startline = newline+1;
|
|
} while (newline != std::string::npos);
|
|
|
|
THIS->addline("");
|
|
THIS->centertext();
|
|
float spaces_per_8 = font::len(PR_FONT_INTERFACE, " ")/8.0f;
|
|
THIS->pad(SDL_ceilf(5/spaces_per_8), SDL_ceilf(2/spaces_per_8));
|
|
if (!THIS->sprites.empty())
|
|
{
|
|
THIS->sprites[0].y = 12 + extra_cjk_height/2;
|
|
}
|
|
}
|
|
|
|
void Game::crewmate_textbox(const int color)
|
|
{
|
|
const int extra_cjk_height = (font::height(PR_FONT_INTERFACE) * 4) - 32;
|
|
graphics.createtextboxflipme("", -1, 64 + 8 + 16, TEXT_COLOUR("gray"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE);
|
|
graphics.textboxcenterx();
|
|
graphics.addsprite(14, 12 + extra_cjk_height/2, 0, color);
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, compute_crewmate_textbox);
|
|
graphics.setlinegap(0);
|
|
graphics.textboxapplyposition();
|
|
}
|
|
|
|
static void compute_remaining_textbox(textboxclass* THIS)
|
|
{
|
|
extern Game game;
|
|
const int remaining = 6 - game.crewrescued();
|
|
char buffer[SCREEN_WIDTH_CHARS + 1];
|
|
if (remaining > 0)
|
|
{
|
|
loc::gettext_plural_fill(buffer, sizeof(buffer), "{n_crew|wordy} remain", "{n_crew|wordy} remains", "n_crew:int", remaining);
|
|
}
|
|
else
|
|
{
|
|
SDL_strlcpy(buffer, loc::gettext("All Crew Members Rescued!"), sizeof(buffer));
|
|
}
|
|
|
|
THIS->lines.clear();
|
|
THIS->lines.push_back(buffer);
|
|
|
|
// In CJK, the "You have rescued" box becomes so big we should lower this one a bit...
|
|
const int cjk_lowering = font::height(PR_FONT_INTERFACE) - 8;
|
|
THIS->yp = 128 + 16 + cjk_lowering;
|
|
THIS->pad(2, 2);
|
|
|
|
}
|
|
|
|
void Game::remaining_textbox(void)
|
|
{
|
|
graphics.createtextboxflipme("", -1, 128 + 16, TEXT_COLOUR("gray"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE);
|
|
graphics.textboxcenterx();
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, compute_remaining_textbox);
|
|
graphics.textboxapplyposition();
|
|
}
|
|
|
|
static void compute_actionprompt_textbox(textboxclass* THIS)
|
|
{
|
|
THIS->lines.clear();
|
|
|
|
char buffer[SCREEN_WIDTH_CHARS + 1];
|
|
vformat_buf(
|
|
buffer, sizeof(buffer),
|
|
loc::gettext("Press {button} to continue"),
|
|
"button:but",
|
|
vformat_button(ActionSet_InGame, Action_InGame_ACTION)
|
|
);
|
|
|
|
THIS->lines.push_back(buffer);
|
|
THIS->pad(1, 1);
|
|
}
|
|
|
|
void Game::actionprompt_textbox(void)
|
|
{
|
|
graphics.createtextboxflipme("", -1, 196, TEXT_COLOUR("cyan"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE);
|
|
graphics.textboxcenterx();
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, compute_actionprompt_textbox);
|
|
graphics.textboxapplyposition();
|
|
}
|
|
|
|
static void savetele_textbox_success(textboxclass* THIS)
|
|
{
|
|
THIS->lines.clear();
|
|
THIS->lines.push_back(loc::gettext("Game Saved"));
|
|
THIS->pad(3, 3);
|
|
}
|
|
|
|
static void save_textbox_fail(textboxclass* THIS)
|
|
{
|
|
THIS->lines.clear();
|
|
THIS->lines.push_back(loc::gettext("ERROR: Could not save game!"));
|
|
THIS->wrap(2);
|
|
THIS->pad(1, 1);
|
|
}
|
|
|
|
void Game::show_save_fail(void)
|
|
{
|
|
graphics.createtextboxflipme("", -1, 12, TEXT_COLOUR("red"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE);
|
|
graphics.textboxcenterx();
|
|
graphics.textboxtimer(50);
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, save_textbox_fail);
|
|
}
|
|
|
|
void Game::checkpoint_save(void)
|
|
{
|
|
if (checkpoint_saving && !inspecial())
|
|
{
|
|
bool success = map.custommode ? customsavequick(cl.ListOfMetaData[playcustomlevel].filename) : savequick();
|
|
gamesaved = success;
|
|
gamesavefailed = !success;
|
|
|
|
if (gamesavefailed)
|
|
{
|
|
show_save_fail();
|
|
graphics.textboxapplyposition();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Game::savetele_textbox(void)
|
|
{
|
|
if (inspecial() || map.custommode)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (savetele())
|
|
{
|
|
graphics.createtextboxflipme("", -1, 12, TEXT_COLOUR("gray"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE);
|
|
graphics.textboxcenterx();
|
|
graphics.textboxtimer(25);
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, savetele_textbox_success);
|
|
}
|
|
else
|
|
{
|
|
show_save_fail();
|
|
}
|
|
graphics.textboxapplyposition();
|
|
}
|
|
|
|
static void wasd_textbox(textboxclass* THIS)
|
|
{
|
|
THIS->lines.clear();
|
|
THIS->lines.push_back(BUTTONGLYPHS_get_wasd_text());
|
|
THIS->wrap(4);
|
|
THIS->centertext();
|
|
THIS->pad(2, 2);
|
|
}
|
|
|
|
static void flip_textbox(textboxclass* THIS)
|
|
{
|
|
THIS->lines.clear();
|
|
|
|
char buffer[SCREEN_WIDTH_CHARS*3 + 1];
|
|
vformat_buf(
|
|
buffer, sizeof(buffer),
|
|
loc::gettext("Press {button} to flip"),
|
|
"button:but",
|
|
vformat_button(ActionSet_InGame, Action_InGame_ACTION)
|
|
);
|
|
THIS->lines.push_back(buffer);
|
|
THIS->wrap(4);
|
|
THIS->centertext();
|
|
THIS->pad(2, 2);
|
|
}
|
|
|
|
static void arrowkey_textbox(textboxclass* THIS)
|
|
{
|
|
THIS->lines.clear();
|
|
THIS->lines.push_back(loc::gettext("If you prefer, you can press UP or DOWN instead of ACTION to flip."));
|
|
THIS->wrap(2);
|
|
THIS->centertext();
|
|
THIS->pad(1, 1);
|
|
}
|
|
|
|
static void map_textbox(textboxclass* THIS)
|
|
{
|
|
THIS->lines.clear();
|
|
|
|
char buffer[SCREEN_WIDTH_CHARS*3 + 1];
|
|
vformat_buf(
|
|
buffer, sizeof(buffer),
|
|
loc::gettext("Press {button} to view map and quicksave"),
|
|
"button:but",
|
|
vformat_button(ActionSet_InGame, Action_InGame_Map)
|
|
);
|
|
|
|
THIS->lines.push_back(buffer);
|
|
THIS->wrap(4);
|
|
THIS->centertext();
|
|
THIS->pad(2, 2);
|
|
}
|
|
|
|
static void im1_instructions_textbox1(textboxclass* THIS)
|
|
{
|
|
extern Game game;
|
|
THIS->lines.clear();
|
|
|
|
// Intermission 1 instructional textbox, depends on last saved
|
|
const char* floorceiling = graphics.flipmode ? "ceiling" : "floor";
|
|
const char* crewmate;
|
|
switch (game.lastsaved)
|
|
{
|
|
case 2:
|
|
crewmate = "Vitellary";
|
|
break;
|
|
case 3:
|
|
crewmate = "Vermilion";
|
|
break;
|
|
case 4:
|
|
crewmate = "Verdigris";
|
|
break;
|
|
case 5:
|
|
crewmate = "Victoria";
|
|
break;
|
|
default:
|
|
crewmate = "your companion";
|
|
}
|
|
char english[SCREEN_WIDTH_TILES*3 + 1]; /* ASCII only */
|
|
vformat_buf(english, sizeof(english),
|
|
"When you're standing on the {floorceiling}, {crewmate} will try to walk to you.",
|
|
"floorceiling:str, crewmate:str",
|
|
floorceiling, crewmate
|
|
);
|
|
|
|
THIS->lines.push_back(loc::gettext(english));
|
|
THIS->wrap(2);
|
|
THIS->padtowidth(36*8);
|
|
}
|
|
|
|
static void im1_instructions_textbox2(textboxclass* THIS)
|
|
{
|
|
extern Game game;
|
|
THIS->lines.clear();
|
|
|
|
// Intermission 1 instructional textbox, depends on last saved
|
|
const char* floorceiling = graphics.flipmode ? "ceiling" : "floor";
|
|
const char* crewmate;
|
|
switch (game.lastsaved)
|
|
{
|
|
case 2:
|
|
crewmate = "Vitellary";
|
|
break;
|
|
case 3:
|
|
crewmate = "Vermilion";
|
|
break;
|
|
case 4:
|
|
crewmate = "Verdigris";
|
|
break;
|
|
case 5:
|
|
crewmate = "Victoria";
|
|
break;
|
|
default:
|
|
crewmate = "your companion";
|
|
}
|
|
char english[SCREEN_WIDTH_TILES*3 + 1]; /* ASCII only */
|
|
vformat_buf(english, sizeof(english),
|
|
"When you're NOT standing on the {floorceiling}, {crewmate} will stop and wait for you.",
|
|
"floorceiling:str, crewmate:str",
|
|
floorceiling, crewmate
|
|
);
|
|
|
|
THIS->lines.push_back(loc::gettext(english));
|
|
THIS->wrap(2);
|
|
THIS->padtowidth(36*8);
|
|
}
|
|
|
|
static void im1_instructions_textbox3(textboxclass* THIS)
|
|
{
|
|
extern Game game;
|
|
THIS->lines.clear();
|
|
|
|
// Intermission 1 instructional textbox, depends on last saved
|
|
const char* english;
|
|
switch (game.lastsaved)
|
|
{
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
english = "You can't continue to the next room until he is safely across.";
|
|
break;
|
|
case 5:
|
|
english = "You can't continue to the next room until she is safely across.";
|
|
break;
|
|
default:
|
|
english = "You can't continue to the next room until they are safely across.";
|
|
}
|
|
|
|
THIS->lines.push_back(loc::gettext(english));
|
|
THIS->wrap(2);
|
|
THIS->padtowidth(36*8);
|
|
}
|
|
|
|
/* Also used in foundtrinket() script command. */
|
|
void foundtrinket_textbox1(textboxclass* THIS)
|
|
{
|
|
THIS->lines.clear();
|
|
|
|
THIS->lines.push_back(loc::gettext("Congratulations!\n\nYou have found a shiny trinket!"));
|
|
THIS->wrap(2);
|
|
THIS->centertext();
|
|
THIS->pad(1, 1);
|
|
}
|
|
|
|
/* Also used in foundtrinket() script command. */
|
|
void foundtrinket_textbox2(textboxclass* THIS)
|
|
{
|
|
extern Game game;
|
|
THIS->lines.clear();
|
|
|
|
const int max_trinkets = map.custommode ? cl.numtrinkets() : 20;
|
|
|
|
char buffer[SCREEN_WIDTH_CHARS + 1];
|
|
vformat_buf(
|
|
buffer, sizeof(buffer),
|
|
loc::gettext("{n_trinkets|wordy} out of {max_trinkets|wordy}"),
|
|
"n_trinkets:int, max_trinkets:int",
|
|
game.trinkets(), max_trinkets
|
|
);
|
|
THIS->lines.push_back(buffer);
|
|
|
|
if (INBOUNDS_VEC(THIS->other_textbox_index, graphics.textboxes)
|
|
&& &graphics.textboxes[THIS->other_textbox_index] != THIS)
|
|
{
|
|
THIS->yp = 95 + graphics.textboxes[THIS->other_textbox_index].h;
|
|
}
|
|
THIS->wrap(2);
|
|
THIS->centertext();
|
|
THIS->pad(1, 1);
|
|
}
|
|
|
|
static void foundcrewmate_textbox1(textboxclass* THIS)
|
|
{
|
|
THIS->lines.clear();
|
|
|
|
THIS->lines.push_back(loc::gettext("Congratulations!\n\nYou have found a lost crewmate!"));
|
|
THIS->wrap(2);
|
|
THIS->centertext();
|
|
THIS->pad(1, 1);
|
|
}
|
|
|
|
static void foundcrewmate_textbox2(textboxclass* THIS)
|
|
{
|
|
extern Game game;
|
|
THIS->lines.clear();
|
|
|
|
const int num_remaining = cl.numcrewmates() - game.crewmates();
|
|
if (num_remaining == 0)
|
|
{
|
|
THIS->lines.push_back(loc::gettext("All crewmates rescued!"));
|
|
}
|
|
else
|
|
{
|
|
char buffer[SCREEN_WIDTH_CHARS + 1];
|
|
loc::gettext_plural_fill(
|
|
buffer, sizeof(buffer),
|
|
"{n_crew|wordy} remain", "{n_crew|wordy} remains",
|
|
"n_crew:int",
|
|
num_remaining
|
|
);
|
|
THIS->lines.push_back(buffer);
|
|
}
|
|
|
|
if (INBOUNDS_VEC(THIS->other_textbox_index, graphics.textboxes)
|
|
&& &graphics.textboxes[THIS->other_textbox_index] != THIS)
|
|
{
|
|
THIS->yp = 95 + graphics.textboxes[THIS->other_textbox_index].h;
|
|
}
|
|
THIS->wrap(4);
|
|
THIS->centertext();
|
|
THIS->pad(2, 2);
|
|
}
|
|
|
|
static void gamecomplete_textbox2(textboxclass* THIS)
|
|
{
|
|
THIS->lines.clear();
|
|
THIS->lines.push_back(loc::gettext("All Crew Members Rescued!"));
|
|
}
|
|
|
|
static void gamecomplete_textbox3(textboxclass* THIS)
|
|
{
|
|
THIS->lines.clear();
|
|
|
|
const char* label = loc::gettext("Trinkets Found:");
|
|
THIS->lines.push_back(label);
|
|
THIS->xp = 170 - font::len(PR_FONT_INTERFACE, label);
|
|
}
|
|
|
|
static void gamecomplete_textbox4(textboxclass* THIS)
|
|
{
|
|
extern Game game;
|
|
THIS->lines.clear();
|
|
|
|
char buffer[SCREEN_WIDTH_CHARS + 1];
|
|
vformat_buf(buffer, sizeof(buffer),
|
|
loc::gettext("{gamecomplete_n_trinkets|wordy}"),
|
|
"gamecomplete_n_trinkets:int",
|
|
game.trinkets()
|
|
);
|
|
THIS->lines.push_back(buffer);
|
|
}
|
|
|
|
static void gamecomplete_textbox5(textboxclass* THIS)
|
|
{
|
|
THIS->lines.clear();
|
|
|
|
const char* label = loc::gettext("Game Time:");
|
|
THIS->lines.push_back(label);
|
|
THIS->xp = 170 - font::len(PR_FONT_INTERFACE, label);
|
|
}
|
|
|
|
static void gamecomplete_textbox6(textboxclass* THIS)
|
|
{
|
|
extern Game game;
|
|
THIS->lines.clear();
|
|
|
|
char buffer[SCREEN_WIDTH_CHARS + 1];
|
|
help.format_time(buffer, sizeof(buffer), game.saveseconds, game.saveframes, true);
|
|
THIS->lines.push_back(buffer);
|
|
}
|
|
|
|
static void gamecomplete_textbox7(textboxclass* THIS)
|
|
{
|
|
THIS->lines.clear();
|
|
|
|
const char* label = loc::gettext("Total Flips:");
|
|
THIS->lines.push_back(label);
|
|
THIS->xp = 170 - font::len(PR_FONT_INTERFACE, label);
|
|
}
|
|
|
|
static void gamecomplete_textbox9(textboxclass* THIS)
|
|
{
|
|
THIS->lines.clear();
|
|
|
|
const char* label = loc::gettext("Total Deaths:");
|
|
THIS->lines.push_back(label);
|
|
THIS->xp = 170 - font::len(PR_FONT_INTERFACE, label);
|
|
}
|
|
|
|
static void gamecomplete_textbox11(textboxclass* THIS)
|
|
{
|
|
extern Game game;
|
|
THIS->lines.clear();
|
|
|
|
char buffer[SCREEN_WIDTH_CHARS + 1];
|
|
loc::gettext_plural_fill(
|
|
buffer, sizeof(buffer),
|
|
"Hardest Room (with {n_deaths} deaths)",
|
|
"Hardest Room (with {n_deaths} death)",
|
|
"n_deaths:int",
|
|
game.hardestroomdeaths
|
|
);
|
|
THIS->lines.push_back(buffer);
|
|
}
|
|
|
|
static void gamecomplete_textbox12(textboxclass* THIS)
|
|
{
|
|
extern Game game;
|
|
THIS->lines.clear();
|
|
|
|
THIS->lines.push_back(
|
|
loc::gettext_roomname(
|
|
map.custommode,
|
|
game.hardestroom_x, game.hardestroom_y,
|
|
game.hardestroom.c_str(), game.hardestroom_specialname
|
|
)
|
|
);
|
|
}
|
|
|
|
void Game::setstate(const int gamestate)
|
|
{
|
|
if (!statelocked || GlitchrunnerMode_less_than_or_equal(Glitchrunner2_2))
|
|
{
|
|
state = gamestate;
|
|
}
|
|
}
|
|
|
|
void Game::incstate(void)
|
|
{
|
|
if (!statelocked || GlitchrunnerMode_less_than_or_equal(Glitchrunner2_2))
|
|
{
|
|
state++;
|
|
}
|
|
}
|
|
|
|
void Game::setstatedelay(const int delay)
|
|
{
|
|
if (!statelocked || GlitchrunnerMode_less_than_or_equal(Glitchrunner2_2))
|
|
{
|
|
statedelay = delay;
|
|
}
|
|
}
|
|
|
|
void Game::lockstate(void)
|
|
{
|
|
statelocked = true;
|
|
}
|
|
|
|
void Game::unlockstate(void)
|
|
{
|
|
statelocked = false;
|
|
}
|
|
|
|
void Game::updatestate(void)
|
|
{
|
|
statedelay--;
|
|
if (statedelay <= 0)
|
|
{
|
|
statedelay = 0;
|
|
glitchrunkludge=false;
|
|
}
|
|
if (statedelay <= 0)
|
|
{
|
|
switch(state)
|
|
{
|
|
case 0:
|
|
//Do nothing here! Standard game state
|
|
|
|
if (script.running)
|
|
{
|
|
if (pausescript && !advancetext)
|
|
{
|
|
/* Prevent softlocks if we somehow don't have advancetext */
|
|
pausescript = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (completestop)
|
|
{
|
|
/* Close potential collection dialogue if warping to ship */
|
|
graphics.textboxremove();
|
|
graphics.showcutscenebars = false;
|
|
}
|
|
/* Prevent softlocks if there's no cutscene running right now */
|
|
hascontrol = true;
|
|
completestop = false;
|
|
}
|
|
break;
|
|
case 1:
|
|
//Game initilisation
|
|
setstate(0);
|
|
break;
|
|
case 2:
|
|
//Opening cutscene
|
|
advancetext = true;
|
|
hascontrol = false;
|
|
setstate(3);
|
|
graphics.createtextbox("To do: write quick", 50, 80, TEXT_COLOUR("cyan"));
|
|
graphics.addline("intro to story!");
|
|
graphics.textboxoriginalcontextauto();
|
|
graphics.textboxprintflags(PR_FONT_8X8);
|
|
//Oh no! what happen to rest of crew etc crash into dimension
|
|
break;
|
|
case 4:
|
|
//End of opening cutscene for now
|
|
graphics.createtextbox("", -1, 195, TEXT_COLOUR("gray"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE);
|
|
graphics.textboxcenterx();
|
|
graphics.textboxtimer(60);
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, wasd_textbox);
|
|
graphics.textboxapplyposition();
|
|
setstate(0);
|
|
break;
|
|
case 5:
|
|
//Demo over
|
|
advancetext = true;
|
|
hascontrol = false;
|
|
|
|
startscript = true;
|
|
newscript="returntohub";
|
|
obj.removetrigger(5);
|
|
setstate(6);
|
|
break;
|
|
case 7:
|
|
//End of opening cutscene for now
|
|
graphics.textboxremove();
|
|
hascontrol = true;
|
|
advancetext = false;
|
|
setstate(0);
|
|
break;
|
|
case 8:
|
|
//Enter dialogue
|
|
obj.removetrigger(8);
|
|
if (!obj.flags[13])
|
|
{
|
|
obj.flags[13] = true;
|
|
|
|
graphics.createtextbox("", -1, 155, TEXT_COLOUR("gray"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE);
|
|
graphics.textboxcenterx();
|
|
graphics.textboxtimer(60);
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, map_textbox);
|
|
graphics.textboxapplyposition();
|
|
}
|
|
setstate(0);
|
|
break;
|
|
|
|
case 9:
|
|
if (!map.custommode && nocompetitive())
|
|
{
|
|
returntolab();
|
|
|
|
startscript = true;
|
|
newscript = "disableaccessibility";
|
|
|
|
setstate(0);
|
|
break;
|
|
}
|
|
|
|
//Start SWN Minigame Mode B
|
|
obj.removetrigger(9);
|
|
|
|
swnmode = true;
|
|
swngame = SWN_START_SUPERGRAVITRON_STEP_1;
|
|
swndelay = 150;
|
|
swntimer = 60 * 30;
|
|
|
|
//set the checkpoint in the middle of the screen
|
|
savepoint = 0;
|
|
savex = 148;
|
|
savey = 100;
|
|
savegc = 0;
|
|
saverx = roomx;
|
|
savery = roomy;
|
|
savedir = 0;
|
|
|
|
setstate(0);
|
|
break;
|
|
|
|
case 10:
|
|
//Start SWN Minigame Mode A
|
|
obj.removetrigger(10);
|
|
|
|
swnmode = true;
|
|
swngame = SWN_START_GRAVITRON_STEP_1;
|
|
swndelay = 150;
|
|
swntimer = 60 * 30;
|
|
|
|
//set the checkpoint in the middle of the screen
|
|
savepoint = 0;
|
|
savex = 148;
|
|
savey = 100;
|
|
savegc = 0;
|
|
saverx = roomx;
|
|
savery = roomy;
|
|
savedir = 0;
|
|
|
|
setstate(0);
|
|
break;
|
|
|
|
case 11:
|
|
graphics.textboxremovefast();
|
|
graphics.createtextbox("", -1, 3, TEXT_COLOUR("gray"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE);
|
|
graphics.textboxcenterx();
|
|
graphics.textboxtimer(180);
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, im1_instructions_textbox2);
|
|
graphics.textboxapplyposition();
|
|
setstate(0);
|
|
break;
|
|
case 12:
|
|
obj.removetrigger(12);
|
|
if (!obj.flags[61])
|
|
{
|
|
obj.flags[61] = true;
|
|
graphics.textboxremovefast();
|
|
graphics.createtextbox("", -1, 3, TEXT_COLOUR("gray"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE);
|
|
graphics.textboxcenterx();
|
|
graphics.textboxtimer(120);
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, im1_instructions_textbox3);
|
|
graphics.textboxapplyposition();
|
|
}
|
|
setstate(0);
|
|
break;
|
|
case 13:
|
|
//textbox removal
|
|
obj.removetrigger(13);
|
|
graphics.textboxremovefast();
|
|
setstate(0);
|
|
break;
|
|
case 14:
|
|
graphics.createtextbox("", -1, 3, TEXT_COLOUR("gray"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE);
|
|
graphics.textboxcenterx();
|
|
graphics.textboxtimer(280);
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, im1_instructions_textbox1);
|
|
graphics.textboxapplyposition();
|
|
|
|
setstate(0);
|
|
break;
|
|
case 15:
|
|
{
|
|
//leaving the naughty corner
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[obj.getplayer()].tile = 0;
|
|
}
|
|
setstate(0);
|
|
break;
|
|
}
|
|
case 16:
|
|
{
|
|
//entering the naughty corner
|
|
int i = obj.getplayer();
|
|
if(INBOUNDS_VEC(i, obj.entities) && obj.entities[i].tile == 0)
|
|
{
|
|
obj.entities[i].tile = 144;
|
|
music.playef(Sound_CRY);
|
|
}
|
|
setstate(0);
|
|
break;
|
|
}
|
|
|
|
case 17:
|
|
//Arrow key tutorial
|
|
obj.removetrigger(17);
|
|
if (BUTTONGLYPHS_keyboard_is_active())
|
|
{
|
|
graphics.createtextbox("", -1, 187, TEXT_COLOUR("gray"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE);
|
|
graphics.textboxcenterx();
|
|
graphics.textboxtimer(100);
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, arrowkey_textbox);
|
|
graphics.textboxapplyposition();
|
|
}
|
|
setstate(0);
|
|
break;
|
|
|
|
case 20:
|
|
if (!obj.flags[1])
|
|
{
|
|
obj.flags[1] = true;
|
|
setstate(0);
|
|
graphics.textboxremove();
|
|
}
|
|
obj.removetrigger(20);
|
|
break;
|
|
case 21:
|
|
if (!obj.flags[2])
|
|
{
|
|
obj.flags[2] = true;
|
|
setstate(0);
|
|
graphics.textboxremove();
|
|
}
|
|
obj.removetrigger(21);
|
|
break;
|
|
case 22:
|
|
if (!obj.flags[3])
|
|
{
|
|
graphics.textboxremovefast();
|
|
obj.flags[3] = true;
|
|
setstate(0);
|
|
|
|
graphics.createtextbox("", -1, 25, TEXT_COLOUR("gray"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE);
|
|
graphics.textboxcenterx();
|
|
graphics.textboxtimer(60);
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, flip_textbox);
|
|
graphics.textboxapplyposition();
|
|
}
|
|
obj.removetrigger(22);
|
|
break;
|
|
|
|
case 30:
|
|
//Generic "run script"
|
|
if (!obj.flags[4])
|
|
{
|
|
obj.flags[4] = true;
|
|
startscript = true;
|
|
newscript="firststeps";
|
|
setstate(0);
|
|
}
|
|
obj.removetrigger(30);
|
|
setstate(0);
|
|
break;
|
|
case 31:
|
|
//state = 55; setstatedelay(50);
|
|
setstate(0);
|
|
setstatedelay(0);
|
|
if (!obj.flags[6])
|
|
{
|
|
obj.flags[6] = true;
|
|
|
|
obj.flags[5] = true;
|
|
startscript = true;
|
|
newscript="communicationstation";
|
|
setstate(0);
|
|
setstatedelay(0);
|
|
}
|
|
obj.removetrigger(31);
|
|
break;
|
|
case 32:
|
|
//Generic "run script"
|
|
if (!obj.flags[7])
|
|
{
|
|
obj.flags[7] = true;
|
|
startscript = true;
|
|
newscript="teleporterback";
|
|
setstate(0);
|
|
}
|
|
obj.removetrigger(32);
|
|
setstate(0);
|
|
break;
|
|
case 33:
|
|
//Generic "run script"
|
|
if (!obj.flags[9])
|
|
{
|
|
obj.flags[9] = true;
|
|
startscript = true;
|
|
newscript="rescueblue";
|
|
setstate(0);
|
|
}
|
|
obj.removetrigger(33);
|
|
setstate(0);
|
|
break;
|
|
case 34:
|
|
//Generic "run script"
|
|
if (!obj.flags[10])
|
|
{
|
|
obj.flags[10] = true;
|
|
startscript = true;
|
|
newscript="rescueyellow";
|
|
setstate(0);
|
|
}
|
|
obj.removetrigger(34);
|
|
setstate(0);
|
|
break;
|
|
case 35:
|
|
//Generic "run script"
|
|
if (!obj.flags[11])
|
|
{
|
|
obj.flags[11] = true;
|
|
startscript = true;
|
|
newscript="rescuegreen";
|
|
setstate(0);
|
|
}
|
|
obj.removetrigger(35);
|
|
setstate(0);
|
|
break;
|
|
case 36:
|
|
//Generic "run script"
|
|
if (!obj.flags[8])
|
|
{
|
|
obj.flags[8] = true;
|
|
startscript = true;
|
|
newscript="rescuered";
|
|
setstate(0);
|
|
}
|
|
obj.removetrigger(36);
|
|
setstate(0);
|
|
break;
|
|
|
|
case 37:
|
|
//Generic "run script"
|
|
if (companion == 0)
|
|
{
|
|
startscript = true;
|
|
newscript="int2_yellow";
|
|
setstate(0);
|
|
}
|
|
obj.removetrigger(37);
|
|
setstate(0);
|
|
break;
|
|
case 38:
|
|
//Generic "run script"
|
|
if (companion == 0)
|
|
{
|
|
startscript = true;
|
|
newscript="int2_red";
|
|
setstate(0);
|
|
}
|
|
obj.removetrigger(38);
|
|
setstate(0);
|
|
break;
|
|
case 39:
|
|
//Generic "run script"
|
|
if (companion == 0)
|
|
{
|
|
startscript = true;
|
|
newscript="int2_green";
|
|
setstate(0);
|
|
}
|
|
obj.removetrigger(39);
|
|
setstate(0);
|
|
break;
|
|
case 40:
|
|
//Generic "run script"
|
|
if (companion == 0)
|
|
{
|
|
startscript = true;
|
|
newscript="int2_blue";
|
|
setstate(0);
|
|
}
|
|
obj.removetrigger(40);
|
|
setstate(0);
|
|
break;
|
|
|
|
case 41:
|
|
//Generic "run script"
|
|
if (!obj.flags[60])
|
|
{
|
|
obj.flags[60] = true;
|
|
startscript = true;
|
|
if (lastsaved == 2)
|
|
{
|
|
newscript = "int1yellow_2";
|
|
}
|
|
else if (lastsaved == 3)
|
|
{
|
|
newscript = "int1red_2";
|
|
}
|
|
else if (lastsaved == 4)
|
|
{
|
|
newscript = "int1green_2";
|
|
}
|
|
else if (lastsaved == 5)
|
|
{
|
|
newscript = "int1blue_2";
|
|
}
|
|
setstate(0);
|
|
}
|
|
obj.removetrigger(41);
|
|
setstate(0);
|
|
break;
|
|
case 42:
|
|
//Generic "run script"
|
|
if (!obj.flags[62])
|
|
{
|
|
obj.flags[62] = true;
|
|
startscript = true;
|
|
if (lastsaved == 2)
|
|
{
|
|
newscript = "int1yellow_3";
|
|
}
|
|
else if (lastsaved == 3)
|
|
{
|
|
newscript = "int1red_3";
|
|
}
|
|
else if (lastsaved == 4)
|
|
{
|
|
newscript = "int1green_3";
|
|
}
|
|
else if (lastsaved == 5)
|
|
{
|
|
newscript = "int1blue_3";
|
|
}
|
|
setstate(0);
|
|
}
|
|
obj.removetrigger(42);
|
|
setstate(0);
|
|
break;
|
|
case 43:
|
|
//Generic "run script"
|
|
if (!obj.flags[63])
|
|
{
|
|
obj.flags[63] = true;
|
|
startscript = true;
|
|
if (lastsaved == 2)
|
|
{
|
|
newscript = "int1yellow_4";
|
|
}
|
|
else if (lastsaved == 3)
|
|
{
|
|
newscript = "int1red_4";
|
|
}
|
|
else if (lastsaved == 4)
|
|
{
|
|
newscript = "int1green_4";
|
|
}
|
|
else if (lastsaved == 5)
|
|
{
|
|
newscript = "int1blue_4";
|
|
}
|
|
setstate(0);
|
|
}
|
|
obj.removetrigger(43);
|
|
setstate(0);
|
|
break;
|
|
case 44:
|
|
//Generic "run script"
|
|
if (!obj.flags[64])
|
|
{
|
|
obj.flags[64] = true;
|
|
startscript = true;
|
|
if (lastsaved == 2)
|
|
{
|
|
newscript = "int1yellow_5";
|
|
}
|
|
else if (lastsaved == 3)
|
|
{
|
|
newscript = "int1red_5";
|
|
}
|
|
else if (lastsaved == 4)
|
|
{
|
|
newscript = "int1green_5";
|
|
}
|
|
else if (lastsaved == 5)
|
|
{
|
|
newscript = "int1blue_5";
|
|
}
|
|
setstate(0);
|
|
}
|
|
obj.removetrigger(44);
|
|
setstate(0);
|
|
break;
|
|
case 45:
|
|
//Generic "run script"
|
|
if (!obj.flags[65])
|
|
{
|
|
obj.flags[65] = true;
|
|
startscript = true;
|
|
if (lastsaved == 2)
|
|
{
|
|
newscript = "int1yellow_6";
|
|
}
|
|
else if (lastsaved == 3)
|
|
{
|
|
newscript = "int1red_6";
|
|
}
|
|
else if (lastsaved == 4)
|
|
{
|
|
newscript = "int1green_6";
|
|
}
|
|
else if (lastsaved == 5)
|
|
{
|
|
newscript = "int1blue_6";
|
|
}
|
|
setstate(0);
|
|
}
|
|
obj.removetrigger(45);
|
|
setstate(0);
|
|
break;
|
|
case 46:
|
|
//Generic "run script"
|
|
if (!obj.flags[66])
|
|
{
|
|
obj.flags[66] = true;
|
|
startscript = true;
|
|
if (lastsaved == 2)
|
|
{
|
|
newscript = "int1yellow_7";
|
|
}
|
|
else if (lastsaved == 3)
|
|
{
|
|
newscript = "int1red_7";
|
|
}
|
|
else if (lastsaved == 4)
|
|
{
|
|
newscript = "int1green_7";
|
|
}
|
|
else if (lastsaved == 5)
|
|
{
|
|
newscript = "int1blue_7";
|
|
}
|
|
setstate(0);
|
|
}
|
|
obj.removetrigger(46);
|
|
setstate(0);
|
|
break;
|
|
|
|
case 47:
|
|
//Generic "run script"
|
|
if (!obj.flags[69])
|
|
{
|
|
obj.flags[69] = true;
|
|
startscript = true;
|
|
newscript="trenchwarfare";
|
|
setstate(0);
|
|
}
|
|
obj.removetrigger(47);
|
|
setstate(0);
|
|
break;
|
|
case 48:
|
|
//Generic "run script"
|
|
if (!obj.flags[70])
|
|
{
|
|
obj.flags[70] = true;
|
|
startscript = true;
|
|
newscript="trinketcollector";
|
|
setstate(0);
|
|
}
|
|
obj.removetrigger(48);
|
|
setstate(0);
|
|
break;
|
|
case 49:
|
|
//Start final level music
|
|
if (!obj.flags[71])
|
|
{
|
|
obj.flags[71] = true;
|
|
music.niceplay(Music_PREDESTINEDFATEREMIX);
|
|
setstate(0);
|
|
}
|
|
obj.removetrigger(49);
|
|
setstate(0);
|
|
break;
|
|
|
|
case 50:
|
|
music.playef(Sound_VIOLET);
|
|
graphics.createtextbox("", 5, 8, TEXT_COLOUR("purple"));
|
|
graphics.textboxcommsrelay("Help! Can anyone hear this message?");
|
|
graphics.textboxtimer(60);
|
|
incstate();
|
|
setstatedelay(100);
|
|
break;
|
|
case 51:
|
|
music.playef(Sound_VIOLET);
|
|
graphics.createtextbox("", 5, 8, TEXT_COLOUR("purple"));
|
|
graphics.textboxcommsrelay("Verdigris? Are you out there? Are you ok?");
|
|
graphics.textboxtimer(60);
|
|
incstate();
|
|
setstatedelay(100);
|
|
break;
|
|
case 52:
|
|
music.playef(Sound_VIOLET);
|
|
graphics.createtextbox("", 5, 8, TEXT_COLOUR("purple"));
|
|
graphics.textboxcommsrelay("Please help us! We've crashed and need assistance!");
|
|
graphics.textboxtimer(60);
|
|
incstate();
|
|
setstatedelay(100);
|
|
break;
|
|
case 53:
|
|
music.playef(Sound_VIOLET);
|
|
graphics.createtextbox("", 5, 8, TEXT_COLOUR("purple"));
|
|
graphics.textboxcommsrelay("Hello? Anyone out there?");
|
|
graphics.textboxtimer(60);
|
|
incstate();
|
|
setstatedelay(100);
|
|
break;
|
|
case 54:
|
|
music.playef(Sound_VIOLET);
|
|
graphics.createtextbox("", 5, 8, TEXT_COLOUR("purple"));
|
|
graphics.textboxcommsrelay("This is Doctor Violet from the D.S.S. Souleye! Please respond!");
|
|
graphics.textboxtimer(60);
|
|
incstate();
|
|
setstatedelay(100);
|
|
break;
|
|
case 55:
|
|
music.playef(Sound_VIOLET);
|
|
graphics.createtextbox("", 5, 8, TEXT_COLOUR("purple"));
|
|
graphics.textboxcommsrelay("Please... Anyone...");
|
|
graphics.textboxtimer(60);
|
|
incstate();
|
|
setstatedelay(100);
|
|
break;
|
|
case 56:
|
|
music.playef(Sound_VIOLET);
|
|
graphics.createtextbox("", 5, 8, TEXT_COLOUR("purple"));
|
|
graphics.textboxcommsrelay("Please be alright, everyone...");
|
|
graphics.textboxtimer(60);
|
|
setstate(50);
|
|
setstatedelay(100);
|
|
break;
|
|
|
|
|
|
case 80:
|
|
//Used to return to menu from the game
|
|
if (graphics.fademode == FADE_FULLY_BLACK)
|
|
{
|
|
incstate();
|
|
}
|
|
break;
|
|
case 81:
|
|
quittomenu();
|
|
music.play(Music_PRESENTINGVVVVVV); //should be after quittomenu()
|
|
setstate(0);
|
|
break;
|
|
|
|
case 82:
|
|
//Time Trial Complete!
|
|
obj.removetrigger(82);
|
|
if (map.custommode && !map.custommodeforreal)
|
|
{
|
|
returntoeditor();
|
|
ed.show_note(loc::gettext("Time trial completed"));
|
|
break;
|
|
}
|
|
|
|
if (translator_exploring)
|
|
{
|
|
translator_exploring_allowtele = true;
|
|
setstate(0);
|
|
break;
|
|
}
|
|
hascontrol = false;
|
|
|
|
if (timetrialcheater)
|
|
{
|
|
SDL_zeroa(obj.collect);
|
|
}
|
|
|
|
timetrialresulttime = help.hms_to_seconds(hours, minutes, seconds);
|
|
timetrialresultframes = frames;
|
|
timetrialresulttrinkets = trinkets();
|
|
timetrialresultshinytarget = timetrialshinytarget;
|
|
timetrialresultpar = timetrialpar;
|
|
timetrialresultdeaths = deathcounts;
|
|
|
|
timetrialrank = 0;
|
|
if (timetrialresulttime <= timetrialpar) timetrialrank++;
|
|
if (trinkets() >= timetrialshinytarget) timetrialrank++;
|
|
if (deathcounts == 0) timetrialrank++;
|
|
|
|
if (timetrialresulttime < besttimes[timetriallevel]
|
|
|| (timetrialresulttime == besttimes[timetriallevel] && timetrialresultframes < bestframes[timetriallevel])
|
|
|| besttimes[timetriallevel]==-1)
|
|
{
|
|
besttimes[timetriallevel] = timetrialresulttime;
|
|
bestframes[timetriallevel] = timetrialresultframes;
|
|
}
|
|
if (timetrialresulttrinkets > besttrinkets[timetriallevel] || besttrinkets[timetriallevel]==-1)
|
|
{
|
|
besttrinkets[timetriallevel] = trinkets();
|
|
}
|
|
if (deathcounts < bestlives[timetriallevel] || bestlives[timetriallevel]==-1)
|
|
{
|
|
bestlives[timetriallevel] = deathcounts;
|
|
}
|
|
if (timetrialrank > bestrank[timetriallevel] || bestrank[timetriallevel]==-1)
|
|
{
|
|
bestrank[timetriallevel] = timetrialrank;
|
|
if (timetrialrank >= 3)
|
|
{
|
|
switch (timetriallevel)
|
|
{
|
|
case TimeTrial_SPACESTATION1:
|
|
unlockAchievement("vvvvvvtimetrial_station1_fixed");
|
|
break;
|
|
case TimeTrial_LABORATORY:
|
|
unlockAchievement("vvvvvvtimetrial_lab_fixed");
|
|
break;
|
|
case TimeTrial_TOWER:
|
|
unlockAchievement("vvvvvvtimetrial_tower_fixed");
|
|
break;
|
|
case TimeTrial_SPACESTATION2:
|
|
unlockAchievement("vvvvvvtimetrial_station2_fixed");
|
|
break;
|
|
case TimeTrial_WARPZONE:
|
|
unlockAchievement("vvvvvvtimetrial_warp_fixed");
|
|
break;
|
|
case TimeTrial_FINALLEVEL:
|
|
unlockAchievement("vvvvvvtimetrial_final_fixed");
|
|
}
|
|
}
|
|
}
|
|
|
|
savestatsandsettings();
|
|
|
|
graphics.fademode = FADE_START_FADEOUT;
|
|
music.fadeout();
|
|
incstate();
|
|
break;
|
|
case 83:
|
|
frames--;
|
|
if (graphics.fademode == FADE_FULLY_BLACK)
|
|
{
|
|
incstate();
|
|
}
|
|
break;
|
|
case 84:
|
|
quittomenu();
|
|
createmenu(Menu::timetrialcomplete);
|
|
setstate(0);
|
|
break;
|
|
|
|
|
|
case 85:
|
|
//Cutscene skip version of final level change
|
|
obj.removetrigger(85);
|
|
//Init final stretch
|
|
incstate();
|
|
music.playef(Sound_FLASH);
|
|
music.play(Music_POSITIVEFORCE);
|
|
obj.flags[72] = true;
|
|
|
|
screenshake = 10;
|
|
flashlight = 5;
|
|
map.finalstretch = true;
|
|
map.warpx = false;
|
|
map.warpy = false;
|
|
map.background = 6;
|
|
|
|
map.final_colormode = true;
|
|
map.final_colorframe = 1;
|
|
|
|
setstate(0);
|
|
break;
|
|
|
|
//From 90-100 are run scripts for the eurogamer expo only, remove later
|
|
case 90:
|
|
//Generic "run script"
|
|
startscript = true;
|
|
newscript="startexpolevel_station1";
|
|
obj.removetrigger(90);
|
|
setstate(0);
|
|
break;
|
|
case 91:
|
|
//Generic "run script"
|
|
startscript = true;
|
|
newscript="startexpolevel_lab";
|
|
obj.removetrigger(91);
|
|
setstate(0);
|
|
break;
|
|
case 92:
|
|
//Generic "run script"
|
|
startscript = true;
|
|
newscript="startexpolevel_warp";
|
|
obj.removetrigger(92);
|
|
setstate(0);
|
|
break;
|
|
case 93:
|
|
//Generic "run script"
|
|
startscript = true;
|
|
newscript="startexpolevel_tower";
|
|
obj.removetrigger(93);
|
|
setstate(0);
|
|
break;
|
|
case 94:
|
|
//Generic "run script"
|
|
startscript = true;
|
|
newscript="startexpolevel_station2";
|
|
obj.removetrigger(94);
|
|
setstate(0);
|
|
break;
|
|
case 95:
|
|
//Generic "run script"
|
|
startscript = true;
|
|
newscript="startexpolevel_final";
|
|
obj.removetrigger(95);
|
|
setstate(0);
|
|
break;
|
|
|
|
case 96:
|
|
//Used to return to gravitron to game
|
|
if (graphics.fademode == FADE_FULLY_BLACK)
|
|
{
|
|
incstate();
|
|
}
|
|
break;
|
|
case 97:
|
|
returntolab();
|
|
setstate(0);
|
|
break;
|
|
|
|
case 100:
|
|
//
|
|
// Meeting crewmate in the warpzone
|
|
//
|
|
obj.removetrigger(100);
|
|
if (!obj.flags[4])
|
|
{
|
|
obj.flags[4] = true;
|
|
incstate();
|
|
}
|
|
break;
|
|
case 101:
|
|
{
|
|
|
|
|
|
int i = obj.getplayer();
|
|
hascontrol = false;
|
|
if (INBOUNDS_VEC(i, obj.entities) && obj.entities[i].onroof > 0 && gravitycontrol == 1)
|
|
{
|
|
gravitycontrol = 0;
|
|
music.playef(Sound_UNFLIP);
|
|
}
|
|
if (INBOUNDS_VEC(i, obj.entities) && obj.entities[i].onground > 0)
|
|
{
|
|
incstate();
|
|
}
|
|
}
|
|
break;
|
|
case 102:
|
|
{
|
|
|
|
|
|
companion = 6;
|
|
int i = obj.getcompanion();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].tile = 0;
|
|
obj.entities[i].state = 1;
|
|
}
|
|
|
|
advancetext = true;
|
|
hascontrol = false;
|
|
|
|
graphics.createtextbox("Captain! I've been so worried!", 60, 90, 164, 255, 164);
|
|
graphics.textboxoriginalcontextauto();
|
|
graphics.textboxprintflags(PR_FONT_8X8);
|
|
incstate();
|
|
music.playef(Sound_VERDIGRIS);
|
|
}
|
|
break;
|
|
case 104:
|
|
graphics.createtextbox("I'm glad you're ok!", 135, 152, TEXT_COLOUR("cyan"));
|
|
graphics.textboxoriginalcontextauto();
|
|
graphics.textboxprintflags(PR_FONT_8X8);
|
|
incstate();
|
|
music.playef(Sound_VIRIDIAN);
|
|
graphics.textboxactive();
|
|
break;
|
|
case 106:
|
|
{
|
|
graphics.createtextbox("I've been trying to find a", 74, 70, 164, 255, 164);
|
|
graphics.addline("way out, but I keep going");
|
|
graphics.addline("around in circles...");
|
|
graphics.textboxoriginalcontextauto();
|
|
graphics.textboxprintflags(PR_FONT_8X8);
|
|
incstate();
|
|
music.playef(Sound_CRY);
|
|
graphics.textboxactive();
|
|
int i = obj.getcompanion();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].tile = 54;
|
|
obj.entities[i].state = 0;
|
|
}
|
|
}
|
|
break;
|
|
case 108:
|
|
graphics.createtextbox("Don't worry! I have a", 125, 152, TEXT_COLOUR("cyan"));
|
|
graphics.addline("teleporter key!");
|
|
graphics.textboxoriginalcontextauto();
|
|
graphics.textboxprintflags(PR_FONT_8X8);
|
|
incstate();
|
|
music.playef(Sound_VIRIDIAN);
|
|
graphics.textboxactive();
|
|
break;
|
|
case 110:
|
|
{
|
|
|
|
int i = obj.getcompanion();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].tile = 0;
|
|
obj.entities[i].state = 1;
|
|
}
|
|
graphics.createtextbox("Follow me!", 185, 154, TEXT_COLOUR("cyan"));
|
|
graphics.textboxoriginalcontextauto();
|
|
graphics.textboxprintflags(PR_FONT_8X8);
|
|
incstate();
|
|
music.playef(Sound_VIRIDIAN);
|
|
graphics.textboxactive();
|
|
|
|
}
|
|
break;
|
|
case 112:
|
|
graphics.textboxremove();
|
|
hascontrol = true;
|
|
advancetext = false;
|
|
|
|
setstate(0);
|
|
break;
|
|
|
|
case 115:
|
|
//
|
|
// Test script for space station, totally delete me!
|
|
//
|
|
hascontrol = false;
|
|
incstate();
|
|
break;
|
|
case 116:
|
|
advancetext = true;
|
|
hascontrol = false;
|
|
|
|
graphics.createtextbox("Sorry Eurogamers! Teleporting around", 60 - 20, 200, 255, 64, 64);
|
|
graphics.addline("the map doesn't work in this version!");
|
|
graphics.textboxoriginalcontextauto();
|
|
graphics.textboxprintflags(PR_FONT_8X8);
|
|
graphics.textboxcenterx();
|
|
incstate();
|
|
break;
|
|
case 118:
|
|
graphics.textboxremove();
|
|
hascontrol = true;
|
|
advancetext = false;
|
|
|
|
setstate(0);
|
|
break;
|
|
|
|
case 120:
|
|
//
|
|
// Meeting crewmate in the space station
|
|
//
|
|
obj.removetrigger(120);
|
|
if (!obj.flags[5])
|
|
{
|
|
obj.flags[5] = true;
|
|
incstate();
|
|
}
|
|
break;
|
|
case 121:
|
|
{
|
|
|
|
int i = obj.getplayer();
|
|
hascontrol = false;
|
|
if (INBOUNDS_VEC(i, obj.entities) && obj.entities[i].onground > 0 && gravitycontrol == 0)
|
|
{
|
|
gravitycontrol = 1;
|
|
music.playef(Sound_UNFLIP);
|
|
}
|
|
if (INBOUNDS_VEC(i, obj.entities) && obj.entities[i].onroof > 0)
|
|
{
|
|
incstate();
|
|
}
|
|
|
|
}
|
|
break;
|
|
case 122:
|
|
{
|
|
companion = 7;
|
|
int i = obj.getcompanion();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].tile = 6;
|
|
obj.entities[i].state = 1;
|
|
}
|
|
|
|
advancetext = true;
|
|
hascontrol = false;
|
|
|
|
graphics.createtextbox("Captain! You're ok!", 60-10, 90-40, TEXT_COLOUR("yellow"));
|
|
graphics.textboxoriginalcontextauto();
|
|
graphics.textboxprintflags(PR_FONT_8X8);
|
|
incstate();
|
|
music.playef(Sound_VITELLARY);
|
|
break;
|
|
}
|
|
case 124:
|
|
{
|
|
graphics.createtextbox("I've found a teleporter, but", 60-20, 90 - 40, TEXT_COLOUR("yellow"));
|
|
graphics.addline("I can't get it to go anywhere...");
|
|
graphics.textboxoriginalcontextauto();
|
|
graphics.textboxprintflags(PR_FONT_8X8);
|
|
incstate();
|
|
music.playef(Sound_CRY);
|
|
graphics.textboxactive();
|
|
break;
|
|
}
|
|
case 126:
|
|
graphics.createtextbox("I can help with that!", 125, 152-40, TEXT_COLOUR("cyan"));
|
|
graphics.textboxoriginalcontextauto();
|
|
graphics.textboxprintflags(PR_FONT_8X8);
|
|
incstate();
|
|
music.playef(Sound_VIRIDIAN);
|
|
graphics.textboxactive();
|
|
break;
|
|
case 128:
|
|
graphics.createtextbox("I have the teleporter", 130, 152-35, TEXT_COLOUR("cyan"));
|
|
graphics.addline("codex for our ship!");
|
|
graphics.textboxoriginalcontextauto();
|
|
graphics.textboxprintflags(PR_FONT_8X8);
|
|
incstate();
|
|
music.playef(Sound_VIRIDIAN);
|
|
graphics.textboxactive();
|
|
break;
|
|
|
|
case 130:
|
|
{
|
|
graphics.createtextbox("Yey! Let's go home!", 60-30, 90-35, TEXT_COLOUR("yellow"));
|
|
graphics.textboxoriginalcontextauto();
|
|
graphics.textboxprintflags(PR_FONT_8X8);
|
|
incstate();
|
|
music.playef(Sound_VITELLARY);
|
|
graphics.textboxactive();
|
|
int i = obj.getcompanion();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].tile = 6;
|
|
obj.entities[i].state = 1;
|
|
}
|
|
break;
|
|
}
|
|
case 132:
|
|
graphics.textboxremove();
|
|
hascontrol = true;
|
|
advancetext = false;
|
|
|
|
setstate(0);
|
|
break;
|
|
|
|
case 200:
|
|
//Init final stretch
|
|
incstate();
|
|
music.playef(Sound_FLASH);
|
|
obj.flags[72] = true;
|
|
|
|
screenshake = 10;
|
|
flashlight = 5;
|
|
map.finalstretch = true;
|
|
map.warpx = false;
|
|
map.warpy = false;
|
|
map.background = 6;
|
|
|
|
map.final_colormode = true;
|
|
map.final_colorframe = 1;
|
|
|
|
startscript = true;
|
|
newscript="finalterminal_finish";
|
|
setstate(0);
|
|
break;
|
|
|
|
|
|
// WARNING: If updating this code, make sure to update Map.cpp mapclass::twoframedelayfix()
|
|
case 300:
|
|
case 301:
|
|
case 302:
|
|
case 303:
|
|
case 304:
|
|
case 305:
|
|
case 306:
|
|
case 307:
|
|
case 308:
|
|
case 309:
|
|
case 310:
|
|
case 311:
|
|
case 312:
|
|
case 313:
|
|
case 314:
|
|
case 315:
|
|
case 316:
|
|
case 317:
|
|
case 318:
|
|
case 319:
|
|
case 320:
|
|
case 321:
|
|
case 322:
|
|
case 323:
|
|
case 324:
|
|
case 325:
|
|
case 326:
|
|
case 327:
|
|
case 328:
|
|
case 329:
|
|
case 330:
|
|
case 331:
|
|
case 332:
|
|
case 333:
|
|
case 334:
|
|
case 335:
|
|
case 336:
|
|
startscript = true;
|
|
newscript="custom_"+customscript[state - 300];
|
|
obj.removetrigger(state);
|
|
setstate(0);
|
|
break;
|
|
|
|
case 1000:
|
|
graphics.showcutscenebars = true;
|
|
hascontrol = false;
|
|
completestop = true;
|
|
incstate();
|
|
setstatedelay(15);
|
|
break;
|
|
case 1001:
|
|
//Found a trinket!
|
|
advancetext = true;
|
|
incstate();
|
|
graphics.createtextboxflipme("", 50, 85, TEXT_COLOUR("gray"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE);
|
|
graphics.textboxcenterx();
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, foundtrinket_textbox1);
|
|
graphics.textboxapplyposition();
|
|
|
|
graphics.createtextboxflipme("", 50, 95, TEXT_COLOUR("gray"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE);
|
|
graphics.textboxcenterx();
|
|
graphics.textboxindex(graphics.textboxes.size() - 2);
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, foundtrinket_textbox2);
|
|
graphics.textboxapplyposition();
|
|
break;
|
|
case 1002:
|
|
if (!advancetext)
|
|
{
|
|
// Prevent softlocks if we somehow don't have advancetext
|
|
incstate();
|
|
}
|
|
break;
|
|
case 1003:
|
|
graphics.textboxremove();
|
|
hascontrol = true;
|
|
advancetext = false;
|
|
completestop = false;
|
|
setstate(0);
|
|
if (music.currentsong > -1)
|
|
{
|
|
music.fadeMusicVolumeIn(3000);
|
|
}
|
|
graphics.showcutscenebars = false;
|
|
break;
|
|
|
|
case 1010:
|
|
graphics.showcutscenebars = true;
|
|
hascontrol = false;
|
|
completestop = true;
|
|
incstate();
|
|
setstatedelay(15);
|
|
break;
|
|
case 1011:
|
|
//Found a crewmate!
|
|
advancetext = true;
|
|
incstate();
|
|
graphics.createtextboxflipme("", 50, 85, TEXT_COLOUR("gray"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE);
|
|
graphics.textboxcenterx();
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, foundcrewmate_textbox1);
|
|
graphics.textboxapplyposition();
|
|
|
|
graphics.createtextboxflipme("", 50, 95, TEXT_COLOUR("gray"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE);
|
|
graphics.textboxcenterx();
|
|
graphics.textboxindex(graphics.textboxes.size() - 2);
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, foundcrewmate_textbox2);
|
|
graphics.textboxapplyposition();
|
|
break;
|
|
case 1012:
|
|
if (!advancetext)
|
|
{
|
|
// Prevent softlocks if we somehow don't have advancetext
|
|
incstate();
|
|
}
|
|
break;
|
|
case 1013:
|
|
graphics.textboxremove();
|
|
hascontrol = true;
|
|
advancetext = false;
|
|
completestop = false;
|
|
setstate(0);
|
|
|
|
if(cl.numcrewmates()-crewmates()==0)
|
|
{
|
|
if(map.custommodeforreal)
|
|
{
|
|
graphics.fademode = FADE_START_FADEOUT;
|
|
setstate(1014);
|
|
}
|
|
else
|
|
{
|
|
returntoeditor();
|
|
ed.show_note(loc::gettext("Level completed"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (cl.levmusic > 0)
|
|
{
|
|
music.fadeMusicVolumeIn(3000);
|
|
}
|
|
}
|
|
graphics.showcutscenebars = false;
|
|
break;
|
|
case 1014:
|
|
frames--;
|
|
if (graphics.fademode == FADE_FULLY_BLACK)
|
|
{
|
|
incstate();
|
|
}
|
|
break;
|
|
case 1015:
|
|
//Update level stats
|
|
/* FIXME: Have to add check to not save stats for the dumb hack
|
|
* `special/stdin.vvvvvv` filename... see elsewhere, grep for
|
|
* `special/stdin`! */
|
|
if(cl.numcrewmates()-crewmates()==0 && customlevelfilename != "levels/special/stdin.vvvvvv")
|
|
{
|
|
//Finished level
|
|
if (trinkets() >= cl.numtrinkets())
|
|
{
|
|
//and got all the trinkets!
|
|
updatecustomlevelstats(customlevelfilename, 3);
|
|
}
|
|
else
|
|
{
|
|
updatecustomlevelstats(customlevelfilename, 1);
|
|
}
|
|
}
|
|
|
|
quittomenu();
|
|
music.play(Music_PRESENTINGVVVVVV); //should be after quittomenu()
|
|
setstate(0);
|
|
break;
|
|
|
|
|
|
case 2000:
|
|
//Game Saved!
|
|
savetele_textbox();
|
|
setstate(0);
|
|
break;
|
|
|
|
case 2500:
|
|
|
|
music.play(Music_PAUSE);
|
|
//Activating a teleporter (appear)
|
|
incstate();
|
|
setstatedelay(15);
|
|
flashlight = 5;
|
|
screenshake = 90;
|
|
music.playef(Sound_FLASH);
|
|
break;
|
|
case 2501:
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(0);
|
|
flashlight = 5;
|
|
screenshake = 0;
|
|
//we're done here!
|
|
music.playef(Sound_TELEPORT);
|
|
break;
|
|
case 2502:
|
|
{
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(5);
|
|
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].colour = 0;
|
|
obj.entities[i].invis = false;
|
|
|
|
int j = obj.getteleporter();
|
|
if (INBOUNDS_VEC(j, obj.entities))
|
|
{
|
|
obj.entities[i].xp = obj.entities[j].xp+44;
|
|
obj.entities[i].yp = obj.entities[j].yp+44;
|
|
obj.entities[i].lerpoldxp = obj.entities[i].xp;
|
|
obj.entities[i].lerpoldyp = obj.entities[i].yp;
|
|
}
|
|
obj.entities[i].ay = -6;
|
|
obj.entities[i].ax = 6;
|
|
obj.entities[i].vy = -6;
|
|
obj.entities[i].vx = 6;
|
|
}
|
|
|
|
i = obj.getteleporter();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].tile = 1;
|
|
obj.entities[i].colour = 101;
|
|
}
|
|
break;
|
|
}
|
|
case 2503:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 10;
|
|
}
|
|
break;
|
|
}
|
|
case 2504:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
//obj.entities[i].xp += 10;
|
|
}
|
|
break;
|
|
}
|
|
case 2505:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 8;
|
|
}
|
|
break;
|
|
}
|
|
case 2506:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 6;
|
|
}
|
|
break;
|
|
}
|
|
case 2507:
|
|
{
|
|
incstate();
|
|
break;
|
|
}
|
|
case 2508:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 2;
|
|
}
|
|
break;
|
|
}
|
|
case 2509:
|
|
{
|
|
incstate();
|
|
setstatedelay(15);
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 1;
|
|
}
|
|
break;
|
|
}
|
|
case 2510:
|
|
advancetext = true;
|
|
hascontrol = false;
|
|
graphics.createtextbox("Hello?", 125+24, 152-20, TEXT_COLOUR("cyan"));
|
|
graphics.textboxoriginalcontextauto();
|
|
graphics.textboxprintflags(PR_FONT_8X8);
|
|
incstate();
|
|
music.playef(Sound_VIRIDIAN);
|
|
graphics.textboxactive();
|
|
break;
|
|
case 2512:
|
|
advancetext = true;
|
|
hascontrol = false;
|
|
graphics.createtextbox("Is anyone there?", 125+8, 152-24, TEXT_COLOUR("cyan"));
|
|
graphics.textboxoriginalcontextauto();
|
|
graphics.textboxprintflags(PR_FONT_8X8);
|
|
incstate();
|
|
music.playef(Sound_VIRIDIAN);
|
|
graphics.textboxactive();
|
|
break;
|
|
case 2514:
|
|
graphics.textboxremove();
|
|
hascontrol = true;
|
|
advancetext = false;
|
|
|
|
setstate(0);
|
|
music.play(Music_POTENTIALFORANYTHING);
|
|
break;
|
|
|
|
|
|
case 3000:
|
|
//Activating a teleporter (long version for level complete)
|
|
incstate();
|
|
setstatedelay(30);
|
|
flashlight = 5;
|
|
screenshake = 90;
|
|
music.playef(Sound_FLASH);
|
|
break;
|
|
case 3001:
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(15);
|
|
flashlight = 5;
|
|
music.playef(Sound_FLASH);
|
|
break;
|
|
case 3002:
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(15);
|
|
flashlight = 5;
|
|
music.playef(Sound_FLASH);
|
|
break;
|
|
case 3003:
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(15);
|
|
flashlight = 5;
|
|
music.playef(Sound_FLASH);
|
|
break;
|
|
case 3004:
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(0);
|
|
flashlight = 5;
|
|
screenshake = 0;
|
|
//we're done here!
|
|
music.playef(Sound_TELEPORT);
|
|
break;
|
|
case 3005:
|
|
{
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(50);
|
|
switch(companion)
|
|
{
|
|
case 6:
|
|
setstate(3006);
|
|
break; //Warp Zone
|
|
case 7:
|
|
setstate(3020);
|
|
break; //Space Station
|
|
case 8:
|
|
setstate(3040);
|
|
break; //Lab
|
|
case 9:
|
|
setstate(3060);
|
|
break; //Tower
|
|
case 10:
|
|
setstate(3080);
|
|
break; //Intermission 2
|
|
case 11:
|
|
setstate(3085);
|
|
break; //Intermission 1
|
|
}
|
|
|
|
if (translator_exploring_allowtele)
|
|
{
|
|
setstate(3090);
|
|
}
|
|
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].colour = 0;
|
|
obj.entities[i].invis = true;
|
|
}
|
|
|
|
i = obj.getcompanion();
|
|
if(INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.disableentity(i);
|
|
}
|
|
|
|
i = obj.getteleporter();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].tile = 1;
|
|
obj.entities[i].colour = 100;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 3006:
|
|
//Level complete! (warp zone)
|
|
unlocknum(Unlock_WARPZONE_COMPLETE);
|
|
lastsaved = 4;
|
|
music.play(Music_PATHCOMPLETE);
|
|
incstate();
|
|
setstatedelay(75);
|
|
|
|
levelcomplete_textbox();
|
|
break;
|
|
case 3007:
|
|
incstate();
|
|
setstatedelay(45);
|
|
|
|
crewmate_textbox(13);
|
|
break;
|
|
case 3008:
|
|
incstate();
|
|
setstatedelay(45);
|
|
|
|
remaining_textbox();
|
|
break;
|
|
case 3009:
|
|
incstate();
|
|
setstatedelay(0);
|
|
|
|
actionprompt_textbox();
|
|
break;
|
|
case 3010:
|
|
if (jumppressed)
|
|
{
|
|
incstate();
|
|
setstatedelay(30);
|
|
graphics.textboxremove();
|
|
}
|
|
break;
|
|
case 3011:
|
|
setstate(3070);
|
|
setstatedelay(0);
|
|
break;
|
|
|
|
case 3020:
|
|
//Level complete! (Space Station 2)
|
|
unlocknum(Unlock_SPACESTATION2_COMPLETE);
|
|
lastsaved = 2;
|
|
music.play(Music_PATHCOMPLETE);
|
|
incstate();
|
|
setstatedelay(75);
|
|
|
|
|
|
levelcomplete_textbox();
|
|
break;
|
|
case 3021:
|
|
incstate();
|
|
setstatedelay(45);
|
|
|
|
crewmate_textbox(14);
|
|
break;
|
|
case 3022:
|
|
incstate();
|
|
setstatedelay(45);
|
|
|
|
remaining_textbox();
|
|
break;
|
|
case 3023:
|
|
incstate();
|
|
setstatedelay(0);
|
|
|
|
actionprompt_textbox();
|
|
break;
|
|
case 3024:
|
|
if (jumppressed)
|
|
{
|
|
incstate();
|
|
setstatedelay(30);
|
|
graphics.textboxremove();
|
|
}
|
|
break;
|
|
case 3025:
|
|
setstate(3070);
|
|
setstatedelay(0);
|
|
break;
|
|
|
|
case 3040:
|
|
//Level complete! (Lab)
|
|
unlocknum(Unlock_LABORATORY_COMPLETE);
|
|
lastsaved = 5;
|
|
music.play(Music_PATHCOMPLETE);
|
|
incstate();
|
|
setstatedelay(75);
|
|
|
|
levelcomplete_textbox();
|
|
break;
|
|
case 3041:
|
|
incstate();
|
|
setstatedelay(45);
|
|
|
|
crewmate_textbox(16);
|
|
break;
|
|
case 3042:
|
|
incstate();
|
|
setstatedelay(45);
|
|
|
|
remaining_textbox();
|
|
break;
|
|
case 3043:
|
|
incstate();
|
|
setstatedelay(0);
|
|
|
|
actionprompt_textbox();
|
|
break;
|
|
case 3044:
|
|
if (jumppressed)
|
|
{
|
|
incstate();
|
|
setstatedelay(30);
|
|
graphics.textboxremove();
|
|
}
|
|
break;
|
|
case 3045:
|
|
setstate(3070);
|
|
setstatedelay(0);
|
|
break;
|
|
|
|
case 3050:
|
|
//Level complete! (Space Station 1)
|
|
unlocknum(Unlock_SPACESTATION1_COMPLETE);
|
|
lastsaved = 1;
|
|
music.play(Music_PATHCOMPLETE);
|
|
incstate();
|
|
setstatedelay(75);
|
|
|
|
|
|
levelcomplete_textbox();
|
|
break;
|
|
case 3051:
|
|
incstate();
|
|
setstatedelay(45);
|
|
|
|
crewmate_textbox(20);
|
|
break;
|
|
case 3052:
|
|
incstate();
|
|
setstatedelay(45);
|
|
|
|
remaining_textbox();
|
|
break;
|
|
case 3053:
|
|
incstate();
|
|
setstatedelay(0);
|
|
|
|
actionprompt_textbox();
|
|
break;
|
|
case 3054:
|
|
if (jumppressed)
|
|
{
|
|
incstate();
|
|
setstatedelay(30);
|
|
graphics.textboxremove();
|
|
teleportscript = "";
|
|
}
|
|
break;
|
|
case 3055:
|
|
graphics.fademode = FADE_START_FADEOUT;
|
|
incstate();
|
|
setstatedelay(10);
|
|
break;
|
|
case 3056:
|
|
if (graphics.fademode == FADE_FULLY_BLACK)
|
|
{
|
|
startscript = true;
|
|
if (crewrescued() == 6)
|
|
{
|
|
newscript = "startlevel_final";
|
|
}
|
|
else
|
|
{
|
|
if (nocutscenes)
|
|
{
|
|
newscript="bigopenworldskip";
|
|
}
|
|
else
|
|
{
|
|
newscript = "bigopenworld";
|
|
}
|
|
}
|
|
setstate(0);
|
|
}
|
|
break;
|
|
|
|
|
|
case 3060:
|
|
//Level complete! (Tower)
|
|
unlocknum(Unlock_TOWER_COMPLETE);
|
|
lastsaved = 3;
|
|
music.play(Music_PATHCOMPLETE);
|
|
incstate();
|
|
setstatedelay(75);
|
|
|
|
levelcomplete_textbox();
|
|
break;
|
|
case 3061:
|
|
incstate();
|
|
setstatedelay(45);
|
|
|
|
crewmate_textbox(15);
|
|
break;
|
|
case 3062:
|
|
incstate();
|
|
setstatedelay(45);
|
|
|
|
remaining_textbox();
|
|
break;
|
|
case 3063:
|
|
incstate();
|
|
setstatedelay(0);
|
|
|
|
actionprompt_textbox();
|
|
break;
|
|
case 3064:
|
|
if (jumppressed)
|
|
{
|
|
incstate();
|
|
setstatedelay(30);
|
|
graphics.textboxremove();
|
|
}
|
|
break;
|
|
case 3065:
|
|
setstate(3070);
|
|
setstatedelay(0);
|
|
break;
|
|
|
|
|
|
case 3070:
|
|
graphics.fademode = FADE_START_FADEOUT;
|
|
incstate();
|
|
break;
|
|
case 3071:
|
|
if (graphics.fademode == FADE_FULLY_BLACK)
|
|
{
|
|
incstate();
|
|
}
|
|
break;
|
|
case 3072:
|
|
//Ok, we need to adjust some flags based on who've we've rescued. Some of there conversation options
|
|
//change depending on when they get back to the ship.
|
|
if (lastsaved == 2)
|
|
{
|
|
if (crewstats[3]) obj.flags[25] = true;
|
|
if (crewstats[4]) obj.flags[26] = true;
|
|
if (crewstats[5]) obj.flags[24] = true;
|
|
}
|
|
else if (lastsaved == 3)
|
|
{
|
|
if (crewstats[2]) obj.flags[50] = true;
|
|
if (crewstats[4]) obj.flags[49] = true;
|
|
if (crewstats[5]) obj.flags[48] = true;
|
|
}
|
|
else if (lastsaved == 4)
|
|
{
|
|
if (crewstats[2]) obj.flags[54] = true;
|
|
if (crewstats[3]) obj.flags[55] = true;
|
|
if (crewstats[5]) obj.flags[56] = true;
|
|
}
|
|
else if (lastsaved == 5)
|
|
{
|
|
if (crewstats[2]) obj.flags[37] = true;
|
|
if (crewstats[3]) obj.flags[38] = true;
|
|
if (crewstats[4]) obj.flags[39] = true;
|
|
}
|
|
//We're pitch black now, make a decision
|
|
companion = 0;
|
|
if (crewrescued() == 6)
|
|
{
|
|
startscript = true;
|
|
newscript="startlevel_final";
|
|
setstate(0);
|
|
}
|
|
else if (crewrescued() == 4)
|
|
{
|
|
companion = 11;
|
|
supercrewmate = true;
|
|
scmprogress = 0;
|
|
|
|
startscript = true;
|
|
newscript = "intermission_1";
|
|
obj.flags[19] = true;
|
|
if (lastsaved == 2) obj.flags[32] = true;
|
|
if (lastsaved == 3) obj.flags[35] = true;
|
|
if (lastsaved == 4) obj.flags[34] = true;
|
|
if (lastsaved == 5) obj.flags[33] = true;
|
|
setstate(0);
|
|
}
|
|
else if (crewrescued() == 5)
|
|
{
|
|
startscript = true;
|
|
newscript = "intermission_2";
|
|
obj.flags[20] = true;
|
|
if (lastsaved == 2) obj.flags[32] = true;
|
|
if (lastsaved == 3) obj.flags[35] = true;
|
|
if (lastsaved == 4) obj.flags[34] = true;
|
|
if (lastsaved == 5) obj.flags[33] = true;
|
|
setstate(0);
|
|
}
|
|
else
|
|
{
|
|
startscript = true;
|
|
newscript="regularreturn";
|
|
setstate(0);
|
|
}
|
|
break;
|
|
|
|
case 3080:
|
|
//returning from an intermission, very like 3070
|
|
if (inintermission)
|
|
{
|
|
graphics.fademode = FADE_START_FADEOUT;
|
|
companion = 0;
|
|
setstate(3100);
|
|
}
|
|
else
|
|
{
|
|
unlocknum(Unlock_INTERMISSION2_COMPLETE);
|
|
graphics.fademode = FADE_START_FADEOUT;
|
|
companion = 0;
|
|
incstate();
|
|
}
|
|
break;
|
|
case 3081:
|
|
if (graphics.fademode == FADE_FULLY_BLACK)
|
|
{
|
|
incstate();
|
|
}
|
|
break;
|
|
case 3082:
|
|
map.finalmode = false;
|
|
startscript = true;
|
|
newscript="regularreturn";
|
|
setstate(0);
|
|
break;
|
|
|
|
case 3085:
|
|
//returning from an intermission, very like 3070
|
|
//return to menu from here
|
|
if (inintermission)
|
|
{
|
|
companion = 0;
|
|
supercrewmate = false;
|
|
incstate();
|
|
graphics.fademode = FADE_START_FADEOUT;
|
|
music.fadeout();
|
|
setstate(3100);
|
|
}
|
|
else
|
|
{
|
|
unlocknum(Unlock_INTERMISSION1_COMPLETE);
|
|
graphics.fademode = FADE_START_FADEOUT;
|
|
companion = 0;
|
|
supercrewmate = false;
|
|
incstate();
|
|
}
|
|
break;
|
|
case 3086:
|
|
if (graphics.fademode == FADE_FULLY_BLACK)
|
|
{
|
|
incstate();
|
|
}
|
|
break;
|
|
case 3087:
|
|
map.finalmode = false;
|
|
startscript = true;
|
|
newscript="regularreturn";
|
|
setstate(0);
|
|
break;
|
|
|
|
case 3090:
|
|
/* Teleporting in translator_exploring should be just like
|
|
* the intermission replays: simply return to the menu */
|
|
companion = 0;
|
|
supercrewmate = false;
|
|
graphics.fademode = FADE_START_FADEOUT;
|
|
music.fadeout();
|
|
setstate(3100);
|
|
break;
|
|
case 3091:
|
|
/* Different Final Level ending for translator_exploring */
|
|
music.fadeout();
|
|
incstate();
|
|
setstatedelay(60);
|
|
break;
|
|
case 3092:
|
|
graphics.fademode = FADE_START_FADEOUT;
|
|
setstate(3100);
|
|
break;
|
|
|
|
case 3100:
|
|
if (graphics.fademode == FADE_FULLY_BLACK)
|
|
{
|
|
incstate();
|
|
}
|
|
break;
|
|
case 3101:
|
|
quittomenu();
|
|
music.play(Music_PRESENTINGVVVVVV); //should be after quittomenu();
|
|
setstate(0);
|
|
break;
|
|
|
|
case 3500:
|
|
music.fadeout();
|
|
incstate();
|
|
setstatedelay(120);
|
|
break;
|
|
case 3501:
|
|
//Game complete!
|
|
unlockAchievement("vvvvvvgamecomplete");
|
|
unlocknum(UnlockTrophy_GAME_COMPLETE);
|
|
crewstats[0] = true;
|
|
incstate();
|
|
setstatedelay(75);
|
|
music.play(Music_PLENARY);
|
|
|
|
graphics.createtextboxflipme("", -1, 12, TEXT_COLOUR("cyan"));
|
|
graphics.addline(" ");
|
|
graphics.addline("");
|
|
graphics.addline("");
|
|
graphics.textboxoriginalcontextauto();
|
|
graphics.textboxprintflags(PR_FONT_8X8);
|
|
graphics.textboxcenterx();
|
|
graphics.setimage(TEXTIMAGE_GAMECOMPLETE);
|
|
graphics.setlinegap(0);
|
|
graphics.textboxapplyposition();
|
|
break;
|
|
case 3502:
|
|
incstate();
|
|
setstatedelay(45+15);
|
|
|
|
graphics.createtextboxflipme("", -1, 64, TEXT_COLOUR("transparent"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE);
|
|
graphics.textboxcenterx();
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, gamecomplete_textbox2);
|
|
graphics.textboxapplyposition();
|
|
saveframes = frames;
|
|
saveseconds = help.hms_to_seconds(hours, minutes, seconds);
|
|
break;
|
|
case 3503:
|
|
incstate();
|
|
setstatedelay(45);
|
|
|
|
graphics.createtextboxflipme("", 170, 84, TEXT_COLOUR("transparent"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE | PR_RTL_XFLIP);
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, gamecomplete_textbox3);
|
|
graphics.textboxapplyposition();
|
|
graphics.createtextboxflipme("", 180, 84, TEXT_COLOUR("transparent"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE | PR_RTL_XFLIP);
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, gamecomplete_textbox4);
|
|
graphics.textboxapplyposition();
|
|
break;
|
|
case 3504:
|
|
incstate();
|
|
setstatedelay(45+15);
|
|
|
|
graphics.createtextboxflipme("", 170, 96, TEXT_COLOUR("transparent"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE | PR_RTL_XFLIP);
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, gamecomplete_textbox5);
|
|
graphics.textboxapplyposition();
|
|
graphics.createtextboxflipme("", 180, 96, TEXT_COLOUR("transparent"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE | PR_RTL_XFLIP);
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, gamecomplete_textbox6);
|
|
graphics.textboxapplyposition();
|
|
break;
|
|
case 3505:
|
|
incstate();
|
|
setstatedelay(45);
|
|
|
|
graphics.createtextboxflipme("", 170, 123, TEXT_COLOUR("transparent"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE | PR_RTL_XFLIP);
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, gamecomplete_textbox7);
|
|
graphics.textboxapplyposition();
|
|
graphics.createtextboxflipme(help.String(totalflips), 180, 123, TEXT_COLOUR("transparent"));
|
|
graphics.textboxoriginalcontextauto();
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE | PR_RTL_XFLIP);
|
|
break;
|
|
case 3506:
|
|
incstate();
|
|
setstatedelay(45+15);
|
|
|
|
graphics.createtextboxflipme("", 170, 135, TEXT_COLOUR("transparent"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE | PR_RTL_XFLIP);
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, gamecomplete_textbox9);
|
|
graphics.textboxapplyposition();
|
|
graphics.createtextboxflipme(help.String(deathcounts), 180, 135, TEXT_COLOUR("transparent"));
|
|
graphics.textboxoriginalcontextauto();
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE | PR_RTL_XFLIP);
|
|
break;
|
|
case 3507:
|
|
incstate();
|
|
setstatedelay(45+15);
|
|
|
|
graphics.createtextboxflipme("", -1, 158, TEXT_COLOUR("transparent"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE);
|
|
graphics.textboxcenterx();
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, gamecomplete_textbox11);
|
|
graphics.textboxapplyposition();
|
|
graphics.createtextboxflipme("", -1, 170, TEXT_COLOUR("transparent"));
|
|
graphics.textboxprintflags(PR_FONT_INTERFACE);
|
|
graphics.textboxcenterx();
|
|
graphics.textboxtranslate(TEXTTRANSLATE_FUNCTION, gamecomplete_textbox12);
|
|
graphics.textboxapplyposition();
|
|
break;
|
|
case 3508:
|
|
incstate();
|
|
setstatedelay(0);
|
|
|
|
actionprompt_textbox();
|
|
break;
|
|
case 3509:
|
|
if (jumppressed)
|
|
{
|
|
incstate();
|
|
setstatedelay(30);
|
|
graphics.textboxremove();
|
|
}
|
|
break;
|
|
case 3510:
|
|
//Save stats and stuff here
|
|
if (!obj.flags[73])
|
|
{
|
|
//flip mode complete
|
|
unlockAchievement("vvvvvvgamecompleteflip");
|
|
unlocknum(UnlockTrophy_FLIPMODE_COMPLETE);
|
|
}
|
|
|
|
#ifndef MAKEANDPLAY
|
|
if (!map.custommode)
|
|
{
|
|
if (bestgamedeaths == -1)
|
|
{
|
|
bestgamedeaths = deathcounts;
|
|
}
|
|
else
|
|
{
|
|
if (deathcounts < bestgamedeaths)
|
|
{
|
|
bestgamedeaths = deathcounts;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (bestgamedeaths > -1) {
|
|
if (bestgamedeaths <= 500) {
|
|
unlockAchievement("vvvvvvcomplete500");
|
|
}
|
|
if (bestgamedeaths <= 250) {
|
|
unlockAchievement("vvvvvvcomplete250");
|
|
}
|
|
if (bestgamedeaths <= 100) {
|
|
unlockAchievement("vvvvvvcomplete100");
|
|
}
|
|
if (bestgamedeaths <= 50) {
|
|
unlockAchievement("vvvvvvcomplete50");
|
|
}
|
|
}
|
|
|
|
if (nodeathmode || nodeatheligible)
|
|
{
|
|
unlockAchievement("vvvvvvmaster"); //bloody hell
|
|
unlocknum(UnlockTrophy_NODEATHMODE_COMPLETE);
|
|
}
|
|
|
|
if (nodeathmode)
|
|
{
|
|
setstate(3520);
|
|
setstatedelay(0);
|
|
}
|
|
else
|
|
{
|
|
setstatedelay(120);
|
|
incstate();
|
|
}
|
|
|
|
savestatsandsettings();
|
|
break;
|
|
case 3511:
|
|
{
|
|
//Activating a teleporter (long version for level complete)
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].colour = 102;
|
|
}
|
|
|
|
incstate();
|
|
setstatedelay(30);
|
|
flashlight = 5;
|
|
screenshake = 90;
|
|
music.playef(Sound_FLASH);
|
|
break;
|
|
}
|
|
case 3512:
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(15);
|
|
flashlight = 5;
|
|
music.playef(Sound_FLASH);
|
|
break;
|
|
case 3513:
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(15);
|
|
flashlight = 5;
|
|
music.playef(Sound_FLASH);
|
|
break;
|
|
case 3514:
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(15);
|
|
flashlight = 5;
|
|
music.playef(Sound_FLASH);
|
|
break;
|
|
case 3515:
|
|
{
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(0);
|
|
flashlight = 5;
|
|
screenshake = 0;
|
|
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].colour = 0;
|
|
obj.entities[i].invis = true;
|
|
}
|
|
|
|
//we're done here!
|
|
music.playef(Sound_TELEPORT);
|
|
setstatedelay(60);
|
|
break;
|
|
}
|
|
case 3516:
|
|
graphics.fademode = FADE_START_FADEOUT;
|
|
incstate();
|
|
break;
|
|
case 3517:
|
|
if (graphics.fademode == FADE_FULLY_BLACK)
|
|
{
|
|
incstate();
|
|
setstatedelay(30);
|
|
}
|
|
break;
|
|
case 3518:
|
|
graphics.fademode = FADE_START_FADEIN;
|
|
setstate(0);
|
|
setstatedelay(30);
|
|
|
|
map.finalmode = false;
|
|
map.final_colormode = false;
|
|
map.final_mapcol = 0;
|
|
map.final_colorframe = 0;
|
|
map.finalstretch = false;
|
|
obj.flags[72] = false;
|
|
|
|
graphics.setbars(320);
|
|
|
|
teleport_to_new_area = true;
|
|
teleportscript = "gamecomplete";
|
|
break;
|
|
|
|
case 3520:
|
|
//NO DEATH MODE COMPLETE JESUS
|
|
hascontrol = false;
|
|
crewstats[0] = true;
|
|
|
|
graphics.fademode = FADE_START_FADEOUT;
|
|
incstate();
|
|
break;
|
|
case 3521:
|
|
if (graphics.fademode == FADE_FULLY_BLACK)
|
|
{
|
|
incstate();
|
|
}
|
|
break;
|
|
case 3522:
|
|
copyndmresults();
|
|
quittomenu();
|
|
createmenu(Menu::nodeathmodecomplete);
|
|
setstate(0);
|
|
break;
|
|
|
|
case 4000:
|
|
//Activating a teleporter (short version)
|
|
state++; // Increment manually -- gamestate modification might be locked at this point
|
|
statedelay = 10;
|
|
flashlight = 5;
|
|
screenshake = 10;
|
|
music.playef(Sound_FLASH);
|
|
break;
|
|
case 4001:
|
|
//Activating a teleporter 2
|
|
state++;
|
|
statedelay = 0;
|
|
flashlight = 5;
|
|
screenshake = 0;
|
|
//we're done here!
|
|
music.playef(Sound_TELEPORT);
|
|
break;
|
|
case 4002:
|
|
{
|
|
//Activating a teleporter 2
|
|
state++;
|
|
statedelay = 10;
|
|
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].colour = 0;
|
|
obj.entities[i].invis = true;
|
|
}
|
|
|
|
i = obj.getteleporter();
|
|
if(INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].tile = 1;
|
|
obj.entities[i].colour = 100;
|
|
}
|
|
break;
|
|
}
|
|
case 4003:
|
|
state = 0;
|
|
statedelay = 0;
|
|
teleport_to_new_area = true;
|
|
unlockstate();
|
|
break;
|
|
|
|
case 4010:
|
|
//Activating a teleporter (default appear)
|
|
incstate();
|
|
setstatedelay(15);
|
|
flashlight = 5;
|
|
screenshake = 90;
|
|
music.playef(Sound_FLASH);
|
|
break;
|
|
case 4011:
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(0);
|
|
flashlight = 5;
|
|
screenshake = 0;
|
|
music.playef(Sound_TELEPORT);
|
|
break;
|
|
case 4012:
|
|
{
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(5);
|
|
|
|
int i = obj.getplayer();
|
|
int j = obj.getteleporter();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
if (INBOUNDS_VEC(j, obj.entities))
|
|
{
|
|
obj.entities[i].xp = obj.entities[j].xp+44;
|
|
obj.entities[i].yp = obj.entities[j].yp+44;
|
|
obj.entities[i].lerpoldxp = obj.entities[i].xp;
|
|
obj.entities[i].lerpoldyp = obj.entities[i].yp;
|
|
obj.entities[j].tile = 2;
|
|
obj.entities[j].colour = 101;
|
|
}
|
|
obj.entities[i].colour = 0;
|
|
obj.entities[i].invis = false;
|
|
obj.entities[i].dir = 1;
|
|
|
|
obj.entities[i].ay = -6;
|
|
obj.entities[i].ax = 6;
|
|
obj.entities[i].vy = -6;
|
|
obj.entities[i].vx = 6;
|
|
}
|
|
break;
|
|
}
|
|
case 4013:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 10;
|
|
}
|
|
break;
|
|
}
|
|
case 4014:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 10;
|
|
}
|
|
break;
|
|
}
|
|
case 4015:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 8;
|
|
}
|
|
break;
|
|
}
|
|
case 4016:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 6;
|
|
}
|
|
break;
|
|
}
|
|
case 4017:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 3;
|
|
}
|
|
break;
|
|
}
|
|
case 4018:
|
|
{
|
|
incstate();
|
|
setstatedelay(15);
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 1;
|
|
}
|
|
break;
|
|
}
|
|
case 4019:
|
|
{
|
|
if (intimetrial || nodeathmode || inintermission)
|
|
{
|
|
}
|
|
else
|
|
{
|
|
savetele();
|
|
}
|
|
int i = obj.getteleporter();
|
|
activetele = true;
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
teleblock.x = obj.entities[i].xp - 32;
|
|
teleblock.y = obj.entities[i].yp - 32;
|
|
}
|
|
teleblock.w = 160;
|
|
teleblock.h = 160;
|
|
hascontrol = true;
|
|
advancetext = false;
|
|
setstate(0);
|
|
break;
|
|
}
|
|
|
|
case 4020:
|
|
//Activating a teleporter (default appear)
|
|
incstate();
|
|
setstatedelay(15);
|
|
flashlight = 5;
|
|
screenshake = 90;
|
|
music.playef(Sound_FLASH);
|
|
break;
|
|
case 4021:
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(0);
|
|
flashlight = 5;
|
|
screenshake = 0;
|
|
music.playef(Sound_TELEPORT);
|
|
break;
|
|
case 4022:
|
|
{
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(5);
|
|
|
|
int i = obj.getplayer();
|
|
int j = obj.getteleporter();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
if (INBOUNDS_VEC(j, obj.entities))
|
|
{
|
|
obj.entities[i].xp = obj.entities[j].xp+44;
|
|
obj.entities[i].yp = obj.entities[j].yp+44;
|
|
obj.entities[i].lerpoldxp = obj.entities[i].xp;
|
|
obj.entities[i].lerpoldyp = obj.entities[i].yp;
|
|
obj.entities[j].tile = 2;
|
|
obj.entities[j].colour = 101;
|
|
}
|
|
obj.entities[i].colour = 0;
|
|
obj.entities[i].invis = false;
|
|
obj.entities[i].dir = 1;
|
|
|
|
obj.entities[i].ay = -6;
|
|
obj.entities[i].ax = 6;
|
|
obj.entities[i].vy = -6;
|
|
obj.entities[i].vx = 6;
|
|
}
|
|
break;
|
|
}
|
|
case 4023:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 12;
|
|
}
|
|
break;
|
|
}
|
|
case 4024:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 12;
|
|
}
|
|
break;
|
|
}
|
|
case 4025:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 10;
|
|
}
|
|
break;
|
|
}
|
|
case 4026:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 8;
|
|
}
|
|
break;
|
|
}
|
|
case 4027:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 5;
|
|
}
|
|
break;
|
|
}
|
|
case 4028:
|
|
{
|
|
incstate();
|
|
setstatedelay(15);
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 2;
|
|
}
|
|
break;
|
|
}
|
|
case 4029:
|
|
hascontrol = true;
|
|
advancetext = false;
|
|
setstate(0);
|
|
break;
|
|
|
|
case 4030:
|
|
//Activating a teleporter (default appear)
|
|
incstate();
|
|
setstatedelay(15);
|
|
flashlight = 5;
|
|
screenshake = 90;
|
|
music.playef(Sound_FLASH);
|
|
break;
|
|
case 4031:
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(0);
|
|
flashlight = 5;
|
|
screenshake = 0;
|
|
music.playef(Sound_TELEPORT);
|
|
break;
|
|
case 4032:
|
|
{
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(5);
|
|
|
|
int i = obj.getplayer();
|
|
int j = obj.getteleporter();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
if (INBOUNDS_VEC(j, obj.entities))
|
|
{
|
|
obj.entities[i].xp = obj.entities[j].xp+44;
|
|
obj.entities[i].yp = obj.entities[j].yp+44;
|
|
obj.entities[i].lerpoldxp = obj.entities[i].xp;
|
|
obj.entities[i].lerpoldyp = obj.entities[i].yp;
|
|
obj.entities[j].tile = 2;
|
|
obj.entities[j].colour = 101;
|
|
}
|
|
obj.entities[i].colour = 0;
|
|
obj.entities[i].invis = false;
|
|
obj.entities[i].dir = 0;
|
|
|
|
obj.entities[i].ay = -6;
|
|
obj.entities[i].ax = -6;
|
|
obj.entities[i].vy = -6;
|
|
obj.entities[i].vx = -6;
|
|
}
|
|
break;
|
|
}
|
|
case 4033:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp -= 12;
|
|
}
|
|
break;
|
|
}
|
|
case 4034:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp -= 12;
|
|
}
|
|
break;
|
|
}
|
|
case 4035:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp -= 10;
|
|
}
|
|
break;
|
|
}
|
|
case 4036:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp -= 8;
|
|
}
|
|
break;
|
|
}
|
|
case 4037:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp -= 5;
|
|
}
|
|
break;
|
|
}
|
|
case 4038:
|
|
{
|
|
incstate();
|
|
setstatedelay(15);
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp -= 2;
|
|
}
|
|
break;
|
|
}
|
|
case 4039:
|
|
hascontrol = true;
|
|
advancetext = false;
|
|
setstate(0);
|
|
break;
|
|
|
|
case 4040:
|
|
//Activating a teleporter (default appear)
|
|
incstate();
|
|
setstatedelay(15);
|
|
flashlight = 5;
|
|
screenshake = 90;
|
|
music.playef(Sound_FLASH);
|
|
break;
|
|
case 4041:
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(0);
|
|
flashlight = 5;
|
|
screenshake = 0;
|
|
music.playef(Sound_TELEPORT);
|
|
break;
|
|
case 4042:
|
|
{
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(5);
|
|
|
|
int i = obj.getplayer();
|
|
int j = obj.getteleporter();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
if (INBOUNDS_VEC(j, obj.entities))
|
|
{
|
|
obj.entities[i].xp = obj.entities[j].xp+44;
|
|
obj.entities[i].yp = obj.entities[j].yp+44;
|
|
obj.entities[i].lerpoldxp = obj.entities[i].xp;
|
|
obj.entities[i].lerpoldyp = obj.entities[i].yp;
|
|
obj.entities[j].tile = 2;
|
|
obj.entities[j].colour = 101;
|
|
}
|
|
obj.entities[i].colour = 0;
|
|
obj.entities[i].invis = false;
|
|
obj.entities[i].dir = 1;
|
|
|
|
obj.entities[i].ay = -6;
|
|
obj.entities[i].ax = 6;
|
|
obj.entities[i].vy = -6;
|
|
obj.entities[i].vx = 6;
|
|
}
|
|
break;
|
|
}
|
|
case 4043:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 12;
|
|
obj.entities[i].yp -= 15;
|
|
}
|
|
break;
|
|
}
|
|
case 4044:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 12;
|
|
obj.entities[i].yp -= 10;
|
|
}
|
|
break;
|
|
}
|
|
case 4045:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 12;
|
|
obj.entities[i].yp -= 10;
|
|
}
|
|
break;
|
|
}
|
|
case 4046:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 8;
|
|
obj.entities[i].yp -= 8;
|
|
}
|
|
break;
|
|
}
|
|
case 4047:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 6;
|
|
obj.entities[i].yp -= 8;
|
|
}
|
|
break;
|
|
}
|
|
case 4048:
|
|
{
|
|
incstate();
|
|
setstatedelay(15);
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 3;
|
|
}
|
|
break;
|
|
}
|
|
case 4049:
|
|
hascontrol = true;
|
|
advancetext = false;
|
|
setstate(0);
|
|
break;
|
|
|
|
case 4050:
|
|
//Activating a teleporter (default appear)
|
|
incstate();
|
|
setstatedelay(15);
|
|
flashlight = 5;
|
|
screenshake = 90;
|
|
music.playef(Sound_FLASH);
|
|
break;
|
|
case 4051:
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(0);
|
|
flashlight = 5;
|
|
screenshake = 0;
|
|
music.playef(Sound_TELEPORT);
|
|
break;
|
|
case 4052:
|
|
{
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(5);
|
|
|
|
int i = obj.getplayer();
|
|
int j = obj.getteleporter();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
if (INBOUNDS_VEC(j, obj.entities))
|
|
{
|
|
obj.entities[i].xp = obj.entities[j].xp+44;
|
|
obj.entities[i].yp = obj.entities[j].yp+44;
|
|
obj.entities[i].lerpoldxp = obj.entities[i].xp;
|
|
obj.entities[i].lerpoldyp = obj.entities[i].yp;
|
|
obj.entities[j].tile = 2;
|
|
obj.entities[j].colour = 101;
|
|
}
|
|
obj.entities[i].colour = 0;
|
|
obj.entities[i].invis = false;
|
|
obj.entities[i].dir = 1;
|
|
|
|
obj.entities[i].ay = -6;
|
|
obj.entities[i].ax = 6;
|
|
obj.entities[i].vy = -6;
|
|
obj.entities[i].vx = 6;
|
|
}
|
|
break;
|
|
}
|
|
case 4053:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 4;
|
|
obj.entities[i].yp -= 15;
|
|
}
|
|
break;
|
|
}
|
|
case 4054:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 4;
|
|
obj.entities[i].yp -= 10;
|
|
}
|
|
break;
|
|
}
|
|
case 4055:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 4;
|
|
obj.entities[i].yp -= 10;
|
|
}
|
|
break;
|
|
}
|
|
case 4056:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 4;
|
|
obj.entities[i].yp -= 8;
|
|
}
|
|
break;
|
|
}
|
|
case 4057:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 2;
|
|
obj.entities[i].yp -= 8;
|
|
}
|
|
break;
|
|
}
|
|
case 4058:
|
|
{
|
|
incstate();
|
|
setstatedelay(15);
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 1;
|
|
}
|
|
break;
|
|
}
|
|
case 4059:
|
|
hascontrol = true;
|
|
advancetext = false;
|
|
setstate(0);
|
|
break;
|
|
|
|
case 4060:
|
|
//Activating a teleporter (default appear)
|
|
incstate();
|
|
setstatedelay(15);
|
|
flashlight = 5;
|
|
screenshake = 90;
|
|
music.playef(Sound_FLASH);
|
|
break;
|
|
case 4061:
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(0);
|
|
flashlight = 5;
|
|
screenshake = 0;
|
|
music.playef(Sound_TELEPORT);
|
|
break;
|
|
case 4062:
|
|
{
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(5);
|
|
|
|
int i = obj.getplayer();
|
|
int j = obj.getteleporter();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
if (INBOUNDS_VEC(j, obj.entities))
|
|
{
|
|
obj.entities[i].xp = obj.entities[j].xp+44;
|
|
obj.entities[i].yp = obj.entities[j].yp+44;
|
|
obj.entities[i].lerpoldxp = obj.entities[i].xp;
|
|
obj.entities[i].lerpoldyp = obj.entities[i].yp;
|
|
obj.entities[j].tile = 2;
|
|
obj.entities[j].colour = 101;
|
|
}
|
|
obj.entities[i].colour = 0;
|
|
obj.entities[i].invis = false;
|
|
obj.entities[i].dir = 0;
|
|
|
|
obj.entities[i].ay = -6;
|
|
obj.entities[i].ax = -6;
|
|
obj.entities[i].vy = -6;
|
|
obj.entities[i].vx = -6;
|
|
}
|
|
break;
|
|
}
|
|
case 4063:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp -= 28;
|
|
obj.entities[i].yp -= 8;
|
|
}
|
|
break;
|
|
}
|
|
case 4064:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp -= 28;
|
|
obj.entities[i].yp -= 8;
|
|
}
|
|
break;
|
|
}
|
|
case 4065:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp -= 25;
|
|
}
|
|
break;
|
|
}
|
|
case 4066:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp -= 25;
|
|
}
|
|
break;
|
|
}
|
|
case 4067:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp -= 20;
|
|
}
|
|
break;
|
|
}
|
|
case 4068:
|
|
{
|
|
incstate();
|
|
setstatedelay(15);
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp -= 16;
|
|
}
|
|
break;
|
|
}
|
|
case 4069:
|
|
hascontrol = true;
|
|
advancetext = false;
|
|
setstate(0);
|
|
break;
|
|
|
|
|
|
case 4070:
|
|
//Activating a teleporter (special for final script, player has colour changed to match rescued crewmate)
|
|
incstate();
|
|
setstatedelay(15);
|
|
flashlight = 5;
|
|
screenshake = 90;
|
|
music.playef(Sound_FLASH);
|
|
break;
|
|
case 4071:
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(0);
|
|
flashlight = 5;
|
|
screenshake = 0;
|
|
music.playef(Sound_TELEPORT);
|
|
break;
|
|
case 4072:
|
|
{
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(5);
|
|
|
|
int i = obj.getplayer();
|
|
int j = obj.getteleporter();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
if (INBOUNDS_VEC(j, obj.entities))
|
|
{
|
|
obj.entities[i].xp = obj.entities[j].xp+44;
|
|
obj.entities[i].yp = obj.entities[j].yp+44;
|
|
obj.entities[i].lerpoldxp = obj.entities[i].xp;
|
|
obj.entities[i].lerpoldyp = obj.entities[i].yp;
|
|
obj.entities[j].tile = 2;
|
|
obj.entities[j].colour = 101;
|
|
}
|
|
obj.entities[i].invis = false;
|
|
obj.entities[i].dir = 1;
|
|
obj.entities[i].colour = graphics.crewcolour(lastsaved);
|
|
|
|
obj.entities[i].ay = -6;
|
|
obj.entities[i].ax = 6;
|
|
obj.entities[i].vy = -6;
|
|
obj.entities[i].vx = 6;
|
|
}
|
|
break;
|
|
}
|
|
case 4073:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 10;
|
|
}
|
|
break;
|
|
}
|
|
case 4074:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 10;
|
|
}
|
|
break;
|
|
}
|
|
case 4075:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 8;
|
|
}
|
|
break;
|
|
}
|
|
case 4076:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 6;
|
|
}
|
|
break;
|
|
}
|
|
case 4077:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 3;
|
|
}
|
|
break;
|
|
}
|
|
case 4078:
|
|
{
|
|
incstate();
|
|
setstatedelay(15);
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 1;
|
|
}
|
|
break;
|
|
}
|
|
case 4079:
|
|
setstate(0);
|
|
startscript = true;
|
|
newscript = "finallevel_teleporter";
|
|
break;
|
|
|
|
case 4080:
|
|
//Activating a teleporter (default appear)
|
|
incstate();
|
|
setstatedelay(15);
|
|
flashlight = 5;
|
|
screenshake = 90;
|
|
music.playef(Sound_FLASH);
|
|
break;
|
|
case 4081:
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(0);
|
|
flashlight = 5;
|
|
screenshake = 0;
|
|
music.playef(Sound_TELEPORT);
|
|
break;
|
|
case 4082:
|
|
{
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(5);
|
|
|
|
int i = obj.getplayer();
|
|
int j = obj.getteleporter();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
if (INBOUNDS_VEC(j, obj.entities))
|
|
{
|
|
obj.entities[i].xp = obj.entities[j].xp+44;
|
|
obj.entities[i].yp = obj.entities[j].yp+44;
|
|
obj.entities[i].lerpoldxp = obj.entities[i].xp;
|
|
obj.entities[i].lerpoldyp = obj.entities[i].yp;
|
|
obj.entities[j].tile = 2;
|
|
obj.entities[j].colour = 101;
|
|
}
|
|
obj.entities[i].colour = 0;
|
|
obj.entities[i].invis = false;
|
|
obj.entities[i].dir = 1;
|
|
|
|
obj.entities[i].ay = -6;
|
|
obj.entities[i].ax = 6;
|
|
obj.entities[i].vy = -6;
|
|
obj.entities[i].vx = 6;
|
|
}
|
|
break;
|
|
}
|
|
case 4083:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 10;
|
|
}
|
|
break;
|
|
}
|
|
case 4084:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 10;
|
|
}
|
|
break;
|
|
}
|
|
case 4085:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 8;
|
|
}
|
|
break;
|
|
}
|
|
case 4086:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 6;
|
|
}
|
|
break;
|
|
}
|
|
case 4087:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 3;
|
|
}
|
|
break;
|
|
}
|
|
case 4088:
|
|
{
|
|
incstate();
|
|
setstatedelay(15);
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 1;
|
|
}
|
|
break;
|
|
}
|
|
case 4089:
|
|
startscript = true;
|
|
newscript = "gamecomplete_ending";
|
|
setstate(0);
|
|
break;
|
|
|
|
case 4090:
|
|
//Activating a teleporter (default appear)
|
|
incstate();
|
|
setstatedelay(15);
|
|
flashlight = 5;
|
|
screenshake = 90;
|
|
music.playef(Sound_FLASH);
|
|
break;
|
|
case 4091:
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(0);
|
|
flashlight = 5;
|
|
screenshake = 0;
|
|
music.playef(Sound_TELEPORT);
|
|
break;
|
|
case 4092:
|
|
{
|
|
//Activating a teleporter 2
|
|
incstate();
|
|
setstatedelay(5);
|
|
|
|
int i = obj.getplayer();
|
|
int j = obj.getteleporter();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
if (INBOUNDS_VEC(j, obj.entities))
|
|
{
|
|
obj.entities[i].xp = obj.entities[j].xp+44;
|
|
obj.entities[i].yp = obj.entities[j].yp+44;
|
|
obj.entities[i].lerpoldxp = obj.entities[i].xp;
|
|
obj.entities[i].lerpoldyp = obj.entities[i].yp;
|
|
obj.entities[j].tile = 2;
|
|
obj.entities[j].colour = 101;
|
|
}
|
|
obj.entities[i].colour = 0;
|
|
obj.entities[i].invis = false;
|
|
obj.entities[i].dir = 1;
|
|
|
|
obj.entities[i].ay = -6;
|
|
obj.entities[i].ax = 6;
|
|
obj.entities[i].vy = -6;
|
|
obj.entities[i].vx = 6;
|
|
}
|
|
break;
|
|
}
|
|
case 4093:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 10;
|
|
}
|
|
break;
|
|
}
|
|
case 4094:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 10;
|
|
}
|
|
break;
|
|
}
|
|
case 4095:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 8;
|
|
}
|
|
break;
|
|
}
|
|
case 4096:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 6;
|
|
}
|
|
break;
|
|
}
|
|
case 4097:
|
|
{
|
|
incstate();
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 3;
|
|
}
|
|
break;
|
|
}
|
|
case 4098:
|
|
{
|
|
incstate();
|
|
setstatedelay(15);
|
|
int i = obj.getplayer();
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].xp += 1;
|
|
}
|
|
break;
|
|
}
|
|
case 4099:
|
|
if (nocutscenes)
|
|
{
|
|
startscript = true;
|
|
newscript = "levelonecompleteskip";
|
|
}
|
|
else
|
|
{
|
|
startscript = true;
|
|
newscript = "levelonecomplete_ending";
|
|
}
|
|
setstate(0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Game::gethardestroom(void)
|
|
{
|
|
if (currentroomdeaths > hardestroomdeaths)
|
|
{
|
|
hardestroomdeaths = currentroomdeaths;
|
|
|
|
hardestroom_x = roomx;
|
|
hardestroom_y = roomy;
|
|
hardestroom_finalstretch = map.finalstretch;
|
|
|
|
if (map.roomname[0] == '\0')
|
|
{
|
|
hardestroom = map.hiddenname;
|
|
hardestroom_specialname = true;
|
|
}
|
|
else
|
|
{
|
|
hardestroom = map.roomname;
|
|
hardestroom_specialname = map.roomname_special;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Game::deletestats(void)
|
|
{
|
|
if (!FILESYSTEM_delete("saves/unlock.vvv"))
|
|
{
|
|
vlog_error("Error deleting saves/unlock.vvv");
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < numunlock; i++)
|
|
{
|
|
unlock[i] = false;
|
|
unlocknotify[i] = false;
|
|
}
|
|
for (int i = 0; i < numtrials; i++)
|
|
{
|
|
besttimes[i] = -1;
|
|
bestframes[i] = -1;
|
|
besttrinkets[i] = -1;
|
|
bestlives[i] = -1;
|
|
bestrank[i] = -1;
|
|
}
|
|
swnrecord = 0;
|
|
swnbestrank = 0;
|
|
bestgamedeaths = -1;
|
|
#ifndef MAKEANDPLAY
|
|
graphics.setflipmode = false;
|
|
#endif
|
|
stat_trinkets = 0;
|
|
}
|
|
}
|
|
|
|
void Game::deletesettings(void)
|
|
{
|
|
if (!FILESYSTEM_delete("saves/settings.vvv"))
|
|
{
|
|
vlog_error("Error deleting saves/settings.vvv");
|
|
}
|
|
}
|
|
|
|
void Game::unlocknum( int t )
|
|
{
|
|
#ifdef MAKEANDPLAY
|
|
UNUSED(t);
|
|
#else
|
|
if (map.custommode)
|
|
{
|
|
//Don't let custom levels unlock things!
|
|
return;
|
|
}
|
|
|
|
unlock[t] = true;
|
|
savestatsandsettings();
|
|
#endif
|
|
}
|
|
|
|
static bool stats_loaded = false;
|
|
|
|
void Game::loadstats(struct ScreenSettings* screen_settings)
|
|
{
|
|
tinyxml2::XMLDocument doc;
|
|
tinyxml2::XMLHandle hDoc(&doc);
|
|
tinyxml2::XMLElement* pElem;
|
|
tinyxml2::XMLElement* dataNode;
|
|
|
|
stats_loaded = true;
|
|
|
|
if (!FILESYSTEM_loadTiXml2Document("saves/unlock.vvv", doc))
|
|
{
|
|
// Save unlock.vvv only. Maybe we have a settings.vvv laying around too,
|
|
// and we don't want to overwrite that!
|
|
savestats(screen_settings);
|
|
return;
|
|
}
|
|
|
|
if (doc.Error())
|
|
{
|
|
vlog_error("Error parsing unlock.vvv: %s", doc.ErrorStr());
|
|
return;
|
|
}
|
|
|
|
dataNode = hDoc
|
|
.FirstChildElement()
|
|
.FirstChildElement("Data")
|
|
.FirstChildElement()
|
|
.ToElement();
|
|
|
|
for (pElem = dataNode; pElem != NULL; pElem=pElem->NextSiblingElement())
|
|
{
|
|
const char* pKey = pElem->Value();
|
|
const char* pText = pElem->GetText() ;
|
|
|
|
if (pText == NULL)
|
|
{
|
|
pText = "";
|
|
}
|
|
|
|
LOAD_ARRAY(unlock)
|
|
|
|
LOAD_ARRAY(unlocknotify)
|
|
|
|
LOAD_ARRAY(besttimes)
|
|
|
|
LOAD_ARRAY(bestframes)
|
|
|
|
LOAD_ARRAY(besttrinkets)
|
|
|
|
|
|
LOAD_ARRAY(bestlives)
|
|
|
|
|
|
LOAD_ARRAY(bestrank)
|
|
|
|
|
|
|
|
if (SDL_strcmp(pKey, "bestgamedeaths") == 0)
|
|
{
|
|
bestgamedeaths = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "stat_trinkets") == 0)
|
|
{
|
|
stat_trinkets = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "swnbestrank") == 0)
|
|
{
|
|
swnbestrank = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "swnrecord") == 0)
|
|
{
|
|
swnrecord = help.Int(pText);
|
|
}
|
|
}
|
|
|
|
deserializesettings(dataNode, screen_settings);
|
|
}
|
|
|
|
void Game::deserializesettings(tinyxml2::XMLElement* dataNode, struct ScreenSettings* screen_settings)
|
|
{
|
|
// Don't duplicate controller buttons!
|
|
controllerButton_flip.clear();
|
|
controllerButton_map.clear();
|
|
controllerButton_esc.clear();
|
|
controllerButton_restart.clear();
|
|
controllerButton_interact.clear();
|
|
|
|
for (tinyxml2::XMLElement* pElem = dataNode;
|
|
pElem != NULL;
|
|
pElem = pElem->NextSiblingElement())
|
|
{
|
|
const char* pKey = pElem->Value();
|
|
const char* pText = pElem->GetText();
|
|
|
|
if (pText == NULL)
|
|
{
|
|
pText = "";
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "fullscreen") == 0)
|
|
{
|
|
screen_settings->fullscreen = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "stretch") == 0)
|
|
{
|
|
int mode = help.Int(pText);
|
|
if (mode < 0 || mode >= NUM_SCALING_MODES)
|
|
{
|
|
/* Pick a sane default. */
|
|
mode = SCALING_INTEGER;
|
|
}
|
|
screen_settings->scalingMode = mode;
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "useLinearFilter") == 0)
|
|
{
|
|
screen_settings->linearFilter = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "window_display") == 0)
|
|
{
|
|
screen_settings->windowDisplay = help.Int(pText);
|
|
}
|
|
if (SDL_strcmp(pKey, "window_width") == 0)
|
|
{
|
|
screen_settings->windowWidth = help.Int(pText);
|
|
}
|
|
if (SDL_strcmp(pKey, "window_height") == 0)
|
|
{
|
|
screen_settings->windowHeight = help.Int(pText);
|
|
}
|
|
|
|
|
|
if (SDL_strcmp(pKey, "noflashingmode") == 0)
|
|
{
|
|
noflashingmode = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "colourblindmode") == 0)
|
|
{
|
|
colourblindmode = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "setflipmode") == 0)
|
|
{
|
|
graphics.setflipmode = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "invincibility") == 0)
|
|
{
|
|
map.invincibility = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "slowdown") == 0)
|
|
{
|
|
slowdown = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "advanced_smoothing") == 0)
|
|
{
|
|
screen_settings->badSignal = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "usingmmmmmm") == 0)
|
|
{
|
|
music.usingmmmmmm = (bool) help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "ghostsenabled") == 0)
|
|
{
|
|
ghostsenabled = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "skipfakeload") == 0)
|
|
{
|
|
skipfakeload = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "disablepause") == 0)
|
|
{
|
|
disablepause = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "disableaudiopause") == 0)
|
|
{
|
|
disableaudiopause = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "over30mode") == 0)
|
|
{
|
|
over30mode = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "inputdelay") == 0)
|
|
{
|
|
inputdelay = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "glitchrunnermode") == 0)
|
|
{
|
|
GlitchrunnerMode_set(GlitchrunnerMode_string_to_enum(pText));
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "showingametimer") == 0)
|
|
{
|
|
showingametimer = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "vsync") == 0)
|
|
{
|
|
screen_settings->useVsync = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "notextoutline") == 0)
|
|
{
|
|
graphics.notextoutline = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "translucentroomname") == 0)
|
|
{
|
|
graphics.translucentroomname = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "musicvolume") == 0)
|
|
{
|
|
music.user_music_volume = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "soundvolume") == 0)
|
|
{
|
|
music.user_sound_volume = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "separate_interact") == 0)
|
|
{
|
|
separate_interact = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "flipButton") == 0)
|
|
{
|
|
SDL_GameControllerButton newButton;
|
|
if (GetButtonFromString(pText, &newButton))
|
|
{
|
|
controllerButton_flip.push_back(newButton);
|
|
}
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "enterButton") == 0)
|
|
{
|
|
SDL_GameControllerButton newButton;
|
|
if (GetButtonFromString(pText, &newButton))
|
|
{
|
|
controllerButton_map.push_back(newButton);
|
|
}
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "escButton") == 0)
|
|
{
|
|
SDL_GameControllerButton newButton;
|
|
if (GetButtonFromString(pText, &newButton))
|
|
{
|
|
controllerButton_esc.push_back(newButton);
|
|
}
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "restartButton") == 0)
|
|
{
|
|
SDL_GameControllerButton newButton;
|
|
if (GetButtonFromString(pText, &newButton))
|
|
{
|
|
controllerButton_restart.push_back(newButton);
|
|
}
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "interactButton") == 0)
|
|
{
|
|
SDL_GameControllerButton newButton;
|
|
if (GetButtonFromString(pText, &newButton))
|
|
{
|
|
controllerButton_interact.push_back(newButton);
|
|
}
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "controllerSensitivity") == 0)
|
|
{
|
|
key.sensitivity = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "lang") == 0)
|
|
{
|
|
loc::lang = std::string(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "lang_set") == 0)
|
|
{
|
|
loc::lang_set = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "english_sprites") == 0)
|
|
{
|
|
loc::english_sprites = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "new_level_font") == 0)
|
|
{
|
|
loc::new_level_font = std::string(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "roomname_translator") == 0 && loc::show_translator_menu)
|
|
{
|
|
roomname_translator::set_enabled(help.Int(pText));
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "checkpoint_saving") == 0)
|
|
{
|
|
checkpoint_saving = help.Int(pText);
|
|
}
|
|
}
|
|
|
|
setdefaultcontrollerbuttons();
|
|
}
|
|
|
|
bool Game::savestats(bool sync /*= true*/)
|
|
{
|
|
struct ScreenSettings screen_settings;
|
|
SDL_zero(screen_settings);
|
|
gameScreen.GetSettings(&screen_settings);
|
|
|
|
return savestats(&screen_settings, sync);
|
|
}
|
|
|
|
bool Game::savestats(const struct ScreenSettings* screen_settings, bool sync /*= true*/)
|
|
{
|
|
tinyxml2::XMLDocument doc;
|
|
bool already_exists;
|
|
|
|
if (!stats_loaded)
|
|
{
|
|
vlog_warn("Stats not loaded! Not writing unlock.vvv.");
|
|
return false;
|
|
}
|
|
|
|
already_exists = FILESYSTEM_loadTiXml2Document("saves/unlock.vvv", doc);
|
|
if (!already_exists)
|
|
{
|
|
vlog_info("No unlock.vvv found. Creating new file");
|
|
}
|
|
else if (doc.Error())
|
|
{
|
|
vlog_error("Error parsing existing unlock.vvv: %s", doc.ErrorStr());
|
|
vlog_info("Creating new unlock.vvv");
|
|
}
|
|
|
|
xml::update_declaration(doc);
|
|
|
|
tinyxml2::XMLElement * root = xml::update_element(doc, "Save");
|
|
|
|
xml::update_comment(root, " Save file " );
|
|
|
|
tinyxml2::XMLElement * dataNode = xml::update_element(root, "Data");
|
|
|
|
std::string s_unlock;
|
|
for(size_t i = 0; i < SDL_arraysize(unlock); i++ )
|
|
{
|
|
s_unlock += help.String(unlock[i]) + ",";
|
|
}
|
|
xml::update_tag(dataNode, "unlock", s_unlock.c_str());
|
|
|
|
std::string s_unlocknotify;
|
|
for(size_t i = 0; i < SDL_arraysize(unlocknotify); i++ )
|
|
{
|
|
s_unlocknotify += help.String(unlocknotify[i]) + ",";
|
|
}
|
|
xml::update_tag(dataNode, "unlocknotify", s_unlocknotify.c_str());
|
|
|
|
std::string s_besttimes;
|
|
for(size_t i = 0; i < SDL_arraysize(besttimes); i++ )
|
|
{
|
|
s_besttimes += help.String(besttimes[i]) + ",";
|
|
}
|
|
xml::update_tag(dataNode, "besttimes", s_besttimes.c_str());
|
|
|
|
std::string s_bestframes;
|
|
for (size_t i = 0; i < SDL_arraysize(bestframes); i++)
|
|
{
|
|
s_bestframes += help.String(bestframes[i]) + ",";
|
|
}
|
|
xml::update_tag(dataNode, "bestframes", s_bestframes.c_str());
|
|
|
|
std::string s_besttrinkets;
|
|
for(size_t i = 0; i < SDL_arraysize(besttrinkets); i++ )
|
|
{
|
|
s_besttrinkets += help.String(besttrinkets[i]) + ",";
|
|
}
|
|
xml::update_tag(dataNode, "besttrinkets", s_besttrinkets.c_str());
|
|
|
|
std::string s_bestlives;
|
|
for(size_t i = 0; i < SDL_arraysize(bestlives); i++ )
|
|
{
|
|
s_bestlives += help.String(bestlives[i]) + ",";
|
|
}
|
|
xml::update_tag(dataNode, "bestlives", s_bestlives.c_str());
|
|
|
|
std::string s_bestrank;
|
|
for(size_t i = 0; i < SDL_arraysize(bestrank); i++ )
|
|
{
|
|
s_bestrank += help.String(bestrank[i]) + ",";
|
|
}
|
|
xml::update_tag(dataNode, "bestrank", s_bestrank.c_str());
|
|
|
|
xml::update_tag(dataNode, "bestgamedeaths", bestgamedeaths);
|
|
|
|
xml::update_tag(dataNode, "stat_trinkets", stat_trinkets);
|
|
|
|
xml::update_tag(dataNode, "swnbestrank", swnbestrank);
|
|
|
|
xml::update_tag(dataNode, "swnrecord", swnrecord);
|
|
|
|
serializesettings(dataNode, screen_settings);
|
|
|
|
return FILESYSTEM_saveTiXml2Document("saves/unlock.vvv", doc, sync);
|
|
}
|
|
|
|
bool Game::savestatsandsettings(void)
|
|
{
|
|
const bool stats_saved = savestats(false);
|
|
|
|
const bool settings_saved = savesettings();
|
|
|
|
return stats_saved && settings_saved; // Not the same as `savestats() && savesettings()`!
|
|
}
|
|
|
|
void Game::savestatsandsettings_menu(void)
|
|
{
|
|
// Call Game::savestatsandsettings(), but upon failure, go to the save error screen
|
|
if (!savestatsandsettings() && !silence_settings_error)
|
|
{
|
|
createmenu(Menu::errorsavingsettings);
|
|
map.nexttowercolour();
|
|
}
|
|
}
|
|
|
|
void Game::serializesettings(tinyxml2::XMLElement* dataNode, const struct ScreenSettings* screen_settings)
|
|
{
|
|
tinyxml2::XMLDocument& doc = xml::get_document(dataNode);
|
|
|
|
xml::update_tag(dataNode, "fullscreen", (int) screen_settings->fullscreen);
|
|
|
|
xml::update_tag(dataNode, "stretch", screen_settings->scalingMode);
|
|
|
|
xml::update_tag(dataNode, "useLinearFilter", (int) screen_settings->linearFilter);
|
|
|
|
xml::update_tag(dataNode, "window_display", screen_settings->windowDisplay);
|
|
|
|
xml::update_tag(dataNode, "window_width", screen_settings->windowWidth);
|
|
|
|
xml::update_tag(dataNode, "window_height", screen_settings->windowHeight);
|
|
|
|
xml::update_tag(dataNode, "noflashingmode", noflashingmode);
|
|
|
|
xml::update_tag(dataNode, "colourblindmode", colourblindmode);
|
|
|
|
xml::update_tag(dataNode, "setflipmode", graphics.setflipmode);
|
|
|
|
xml::update_tag(dataNode, "invincibility", map.invincibility);
|
|
|
|
xml::update_tag(dataNode, "slowdown", slowdown);
|
|
|
|
|
|
xml::update_tag(dataNode, "advanced_smoothing", (int) screen_settings->badSignal);
|
|
|
|
|
|
xml::update_tag(dataNode, "usingmmmmmm", music.usingmmmmmm);
|
|
|
|
xml::update_tag(dataNode, "ghostsenabled", (int) ghostsenabled);
|
|
|
|
xml::update_tag(dataNode, "skipfakeload", (int) skipfakeload);
|
|
|
|
xml::update_tag(dataNode, "disablepause", (int) disablepause);
|
|
|
|
xml::update_tag(dataNode, "disableaudiopause", (int) disableaudiopause);
|
|
|
|
xml::update_tag(dataNode, "notextoutline", (int) graphics.notextoutline);
|
|
|
|
xml::update_tag(dataNode, "translucentroomname", (int) graphics.translucentroomname);
|
|
|
|
xml::update_tag(dataNode, "over30mode", (int) over30mode);
|
|
|
|
xml::update_tag(dataNode, "inputdelay", (int) inputdelay);
|
|
|
|
xml::update_tag(
|
|
dataNode,
|
|
"glitchrunnermode",
|
|
GlitchrunnerMode_enum_to_string(GlitchrunnerMode_get())
|
|
);
|
|
|
|
xml::update_tag(dataNode, "showingametimer", (int) showingametimer);
|
|
|
|
xml::update_tag(dataNode, "vsync", (int) screen_settings->useVsync);
|
|
|
|
xml::update_tag(dataNode, "musicvolume", music.user_music_volume);
|
|
|
|
xml::update_tag(dataNode, "soundvolume", music.user_sound_volume);
|
|
|
|
xml::update_tag(dataNode, "separate_interact", (int) separate_interact);
|
|
|
|
// Delete all controller buttons we had previously.
|
|
// dataNode->FirstChildElement() shouldn't be NULL at this point...
|
|
// we've already added a bunch of elements
|
|
for (tinyxml2::XMLElement* element = dataNode->FirstChildElement();
|
|
element != NULL;
|
|
/* Increment code handled separately */)
|
|
{
|
|
const char* name = element->Name();
|
|
|
|
if (SDL_strcmp(name, "flipButton") == 0
|
|
|| SDL_strcmp(name, "enterButton") == 0
|
|
|| SDL_strcmp(name, "escButton") == 0
|
|
|| SDL_strcmp(name, "restartButton") == 0
|
|
|| SDL_strcmp(name, "interactButton") == 0)
|
|
{
|
|
// Can't just doc.DeleteNode(element) and then go to next,
|
|
// element->NextSiblingElement() will be NULL.
|
|
// Instead, store pointer of element we want to delete. Then
|
|
// increment `element`. And THEN delete the element.
|
|
tinyxml2::XMLElement* delete_this = element;
|
|
|
|
element = element->NextSiblingElement();
|
|
|
|
doc.DeleteNode(delete_this);
|
|
continue;
|
|
}
|
|
|
|
element = element->NextSiblingElement();
|
|
}
|
|
|
|
// Now add them
|
|
for (size_t i = 0; i < controllerButton_flip.size(); i += 1)
|
|
{
|
|
tinyxml2::XMLElement* msg = doc.NewElement("flipButton");
|
|
msg->LinkEndChild(doc.NewText(help.String((int) controllerButton_flip[i]).c_str()));
|
|
dataNode->LinkEndChild(msg);
|
|
}
|
|
for (size_t i = 0; i < controllerButton_map.size(); i += 1)
|
|
{
|
|
tinyxml2::XMLElement* msg = doc.NewElement("enterButton");
|
|
msg->LinkEndChild(doc.NewText(help.String((int) controllerButton_map[i]).c_str()));
|
|
dataNode->LinkEndChild(msg);
|
|
}
|
|
for (size_t i = 0; i < controllerButton_esc.size(); i += 1)
|
|
{
|
|
tinyxml2::XMLElement* msg = doc.NewElement("escButton");
|
|
msg->LinkEndChild(doc.NewText(help.String((int) controllerButton_esc[i]).c_str()));
|
|
dataNode->LinkEndChild(msg);
|
|
}
|
|
for (size_t i = 0; i < controllerButton_restart.size(); i += 1)
|
|
{
|
|
tinyxml2::XMLElement* msg = doc.NewElement("restartButton");
|
|
msg->LinkEndChild(doc.NewText(help.String((int) controllerButton_restart[i]).c_str()));
|
|
dataNode->LinkEndChild(msg);
|
|
}
|
|
for (size_t i = 0; i < controllerButton_interact.size(); i += 1)
|
|
{
|
|
tinyxml2::XMLElement* msg = doc.NewElement("interactButton");
|
|
msg->LinkEndChild(doc.NewText(help.String((int) controllerButton_interact[i]).c_str()));
|
|
dataNode->LinkEndChild(msg);
|
|
}
|
|
|
|
xml::update_tag(dataNode, "controllerSensitivity", key.sensitivity);
|
|
|
|
xml::update_tag(dataNode, "lang", loc::lang.c_str());
|
|
xml::update_tag(dataNode, "lang_set", (int) loc::lang_set);
|
|
xml::update_tag(dataNode, "english_sprites", (int) loc::english_sprites);
|
|
xml::update_tag(dataNode, "new_level_font", loc::new_level_font.c_str());
|
|
xml::update_tag(dataNode, "roomname_translator", (int) roomname_translator::enabled);
|
|
|
|
xml::update_tag(dataNode, "checkpoint_saving", (int) checkpoint_saving);
|
|
}
|
|
|
|
static bool settings_loaded = false;
|
|
|
|
void Game::loadsettings(struct ScreenSettings* screen_settings)
|
|
{
|
|
tinyxml2::XMLDocument doc;
|
|
tinyxml2::XMLHandle hDoc(&doc);
|
|
tinyxml2::XMLElement* dataNode;
|
|
|
|
settings_loaded = true;
|
|
|
|
if (!FILESYSTEM_loadTiXml2Document("saves/settings.vvv", doc))
|
|
{
|
|
savesettings(screen_settings);
|
|
return;
|
|
}
|
|
|
|
if (doc.Error())
|
|
{
|
|
vlog_error("Error parsing settings.vvv: %s", doc.ErrorStr());
|
|
return;
|
|
}
|
|
|
|
dataNode = hDoc
|
|
.FirstChildElement()
|
|
.FirstChildElement("Data")
|
|
.FirstChildElement()
|
|
.ToElement();
|
|
|
|
deserializesettings(dataNode, screen_settings);
|
|
}
|
|
|
|
bool Game::savesettings(void)
|
|
{
|
|
struct ScreenSettings screen_settings;
|
|
SDL_zero(screen_settings);
|
|
gameScreen.GetSettings(&screen_settings);
|
|
|
|
return savesettings(&screen_settings);
|
|
}
|
|
|
|
bool Game::savesettings(const struct ScreenSettings* screen_settings)
|
|
{
|
|
tinyxml2::XMLDocument doc;
|
|
bool already_exists;
|
|
|
|
if (!settings_loaded)
|
|
{
|
|
vlog_warn("Settings not loaded! Not writing settings.vvv.");
|
|
return false;
|
|
}
|
|
|
|
already_exists = FILESYSTEM_loadTiXml2Document("saves/settings.vvv", doc);
|
|
if (!already_exists)
|
|
{
|
|
vlog_info("No settings.vvv found. Creating new file");
|
|
}
|
|
else if (doc.Error())
|
|
{
|
|
vlog_error("Error parsing existing settings.vvv: %s", doc.ErrorStr());
|
|
vlog_info("Creating new settings.vvv");
|
|
}
|
|
|
|
xml::update_declaration(doc);
|
|
|
|
tinyxml2::XMLElement* root = xml::update_element(doc, "Settings");
|
|
|
|
xml::update_comment(root, " Settings (duplicated from unlock.vvv) ");
|
|
|
|
tinyxml2::XMLElement* dataNode = xml::update_element(root, "Data");
|
|
|
|
serializesettings(dataNode, screen_settings);
|
|
|
|
return FILESYSTEM_saveTiXml2Document("saves/settings.vvv", doc);
|
|
}
|
|
|
|
void Game::customstart(void)
|
|
{
|
|
jumpheld = true;
|
|
|
|
savex = edsavex;
|
|
savey = edsavey;
|
|
saverx = edsaverx;
|
|
savery = edsavery;
|
|
|
|
savegc = edsavegc;
|
|
savedir = edsavedir; //Worldmap Start
|
|
savepoint = 0;
|
|
gravitycontrol = savegc;
|
|
|
|
setstate(0);
|
|
deathseq = -1;
|
|
lifeseq = 0;
|
|
}
|
|
|
|
void Game::start(void)
|
|
{
|
|
jumpheld = true;
|
|
|
|
savex = 232;
|
|
savey = 113;
|
|
saverx = 104;
|
|
savery = 110;
|
|
savegc = 0;
|
|
savedir = 1; //Worldmap Start
|
|
savepoint = 0;
|
|
gravitycontrol = savegc;
|
|
|
|
setstate(0);
|
|
deathseq = -1;
|
|
lifeseq = 0;
|
|
|
|
if (!nocutscenes)
|
|
{
|
|
music.play(Music_PAUSE);
|
|
}
|
|
}
|
|
|
|
void Game::deathsequence(void)
|
|
{
|
|
int i;
|
|
if (supercrewmate && scmhurt)
|
|
{
|
|
i = obj.getscm();
|
|
}
|
|
else
|
|
{
|
|
i = obj.getplayer();
|
|
}
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
{
|
|
obj.entities[i].colour = 1;
|
|
|
|
obj.entities[i].invis = false;
|
|
}
|
|
if (deathseq == 30)
|
|
{
|
|
if (nodeathmode)
|
|
{
|
|
music.fadeout();
|
|
gameoverdelay = 60;
|
|
|
|
/* Fix a bug being able to play music on the Game Over screen */
|
|
music.nicefade = false;
|
|
}
|
|
deathcounts++;
|
|
music.playef(Sound_CRY);
|
|
if (INBOUNDS_VEC(i, obj.entities) && !noflashingmode)
|
|
{
|
|
obj.entities[i].invis = true;
|
|
}
|
|
if (map.finalmode)
|
|
{
|
|
if (roomx - 41 >= 0 && roomx - 41 < 20 && roomy - 48 >= 0 && roomy - 48 < 20)
|
|
{
|
|
map.roomdeathsfinal[roomx - 41 + (20 * (roomy - 48))]++;
|
|
currentroomdeaths = map.roomdeathsfinal[roomx - 41 + (20 * (roomy - 48))];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (roomx - 100 >= 0 && roomx - 100 < 20 && roomy - 100 >= 0 && roomy - 100 < 20)
|
|
{
|
|
map.roomdeaths[roomx - 100 + (20*(roomy - 100))]++;
|
|
currentroomdeaths = map.roomdeaths[roomx - 100 + (20 * (roomy - 100))];
|
|
}
|
|
}
|
|
}
|
|
if (INBOUNDS_VEC(i, obj.entities) && !noflashingmode)
|
|
{
|
|
if (deathseq == 25) obj.entities[i].invis = true;
|
|
if (deathseq == 20) obj.entities[i].invis = true;
|
|
if (deathseq == 16) obj.entities[i].invis = true;
|
|
if (deathseq == 14) obj.entities[i].invis = true;
|
|
if (deathseq == 12) obj.entities[i].invis = true;
|
|
if (deathseq < 10) obj.entities[i].invis = true;
|
|
}
|
|
if (!nodeathmode)
|
|
{
|
|
if (INBOUNDS_VEC(i, obj.entities) && deathseq <= 1) obj.entities[i].invis = false;
|
|
}
|
|
else
|
|
{
|
|
gameoverdelay--;
|
|
}
|
|
}
|
|
|
|
void Game::startspecial( int t )
|
|
{
|
|
jumpheld = true;
|
|
|
|
switch(t)
|
|
{
|
|
case 0: //Secret Lab
|
|
savex = 104;
|
|
savey = 169;
|
|
saverx = 118;
|
|
savery = 106;
|
|
savegc = 0;
|
|
savedir = 1;
|
|
break;
|
|
case 1: //Intermission 1 (any)
|
|
savex = 80;
|
|
savey = 57;
|
|
saverx = 41;
|
|
savery = 56;
|
|
savegc = 0;
|
|
savedir = 0;
|
|
break;
|
|
default:
|
|
savex = 232;
|
|
savey = 113;
|
|
saverx = 104;
|
|
savery = 110;
|
|
savegc = 0;
|
|
savedir = 1; //Worldmap Start
|
|
break;
|
|
}
|
|
|
|
savepoint = 0;
|
|
gravitycontrol = savegc;
|
|
setstate(0);
|
|
deathseq = -1;
|
|
lifeseq = 0;
|
|
}
|
|
|
|
void Game::starttrial( int t )
|
|
{
|
|
jumpheld = true;
|
|
|
|
switch(t)
|
|
{
|
|
case 0: //Space Station 1
|
|
savex = 200;
|
|
savey = 161;
|
|
saverx = 113;
|
|
savery = 105;
|
|
savegc = 0;
|
|
savedir = 1;
|
|
break;
|
|
case 1: //Lab
|
|
savex = 191;
|
|
savey = 33;
|
|
saverx = 102;
|
|
savery = 116;
|
|
savegc = 0;
|
|
savedir = 1;
|
|
break;
|
|
case 2: //Tower
|
|
savex = 84;
|
|
savey = 193, saverx = 108;
|
|
savery = 109;
|
|
savegc = 0;
|
|
savedir = 1;
|
|
break;
|
|
case 3: //Space Station 2
|
|
savex = 148;
|
|
savey = 38;
|
|
saverx = 112;
|
|
savery = 114;
|
|
savegc = 1;
|
|
savedir = 0;
|
|
break;
|
|
case 4: //Warp
|
|
savex = 52;
|
|
savey = 73;
|
|
saverx = 114;
|
|
savery = 101;
|
|
savegc = 0;
|
|
savedir = 1;
|
|
break;
|
|
case 5: //Final
|
|
savex = 101;
|
|
savey = 113;
|
|
saverx = 46;
|
|
savery = 54;
|
|
savegc = 0;
|
|
savedir = 1;
|
|
break;
|
|
default:
|
|
savex = 232;
|
|
savey = 113;
|
|
saverx = 104;
|
|
savery = 110;
|
|
savegc = 0;
|
|
savedir = 1; //Worldmap Start
|
|
break;
|
|
}
|
|
|
|
savepoint = 0;
|
|
gravitycontrol = savegc;
|
|
|
|
setstate(0);
|
|
deathseq = -1;
|
|
lifeseq = 0;
|
|
}
|
|
|
|
void Game::loadquick(void)
|
|
{
|
|
tinyxml2::XMLDocument doc;
|
|
if (!FILESYSTEM_loadTiXml2Document("saves/qsave.vvv", doc)) return;
|
|
|
|
readmaingamesave("qsave.vvv", doc);
|
|
}
|
|
|
|
void Game::readmaingamesave(const char* savename, tinyxml2::XMLDocument& doc)
|
|
{
|
|
tinyxml2::XMLHandle hDoc(&doc);
|
|
tinyxml2::XMLElement* pElem;
|
|
|
|
if (doc.Error())
|
|
{
|
|
vlog_error("Error parsing %s: %s", savename, doc.ErrorStr());
|
|
return;
|
|
}
|
|
|
|
/* Even if we want the default hardest room to be Welcome Aboard, there are pre-2.4
|
|
* saves with JUST <hardestroom> which should take priority over the coords */
|
|
hardestroom_x = -1;
|
|
hardestroom_y = -1;
|
|
hardestroom_specialname = false;
|
|
hardestroom_finalstretch = false;
|
|
|
|
for (pElem = hDoc
|
|
.FirstChildElement()
|
|
.FirstChildElement("Data")
|
|
.FirstChildElement()
|
|
.ToElement();
|
|
pElem != NULL;
|
|
pElem = pElem->NextSiblingElement())
|
|
{
|
|
const char* pKey = pElem->Value();
|
|
const char* pText = pElem->GetText();
|
|
if(pText == NULL)
|
|
{
|
|
pText = "";
|
|
}
|
|
|
|
LOAD_ARRAY_RENAME(worldmap, map.explored)
|
|
|
|
LOAD_ARRAY_RENAME(flags, obj.flags)
|
|
|
|
LOAD_ARRAY(crewstats)
|
|
|
|
LOAD_ARRAY_RENAME(collect, obj.collect)
|
|
|
|
if (SDL_strcmp(pKey, "finalmode") == 0)
|
|
{
|
|
map.finalmode = help.Int(pText);
|
|
}
|
|
if (SDL_strcmp(pKey, "finalstretch") == 0)
|
|
{
|
|
map.finalstretch = help.Int(pText);
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "savex") == 0)
|
|
{
|
|
savex = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "savey") == 0)
|
|
{
|
|
savey = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "saverx") == 0)
|
|
{
|
|
saverx = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "savery") == 0)
|
|
{
|
|
savery = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "savegc") == 0)
|
|
{
|
|
savegc = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "savedir") == 0)
|
|
{
|
|
savedir= help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "savepoint") == 0)
|
|
{
|
|
savepoint = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "companion") == 0)
|
|
{
|
|
companion = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "lastsaved") == 0)
|
|
{
|
|
lastsaved = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "teleportscript") == 0)
|
|
{
|
|
teleportscript = pText;
|
|
}
|
|
else if (SDL_strcmp(pKey, "supercrewmate") == 0)
|
|
{
|
|
supercrewmate = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "scmprogress") == 0)
|
|
{
|
|
scmprogress = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "frames") == 0)
|
|
{
|
|
frames = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "seconds") == 0)
|
|
{
|
|
seconds = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "minutes") == 0)
|
|
{
|
|
minutes = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "hours") == 0)
|
|
{
|
|
hours = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "deathcounts") == 0)
|
|
{
|
|
deathcounts = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "totalflips") == 0)
|
|
{
|
|
totalflips = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "hardestroom") == 0)
|
|
{
|
|
hardestroom = pText;
|
|
}
|
|
else if (SDL_strcmp(pKey, "hardestroomdeaths") == 0)
|
|
{
|
|
hardestroomdeaths = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "hardestroom_x") == 0)
|
|
{
|
|
hardestroom_x = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "hardestroom_y") == 0)
|
|
{
|
|
hardestroom_y = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "hardestroom_specialname") == 0)
|
|
{
|
|
hardestroom_specialname = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "hardestroom_finalstretch") == 0)
|
|
{
|
|
hardestroom_finalstretch = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "currentsong") == 0)
|
|
{
|
|
int song = help.Int(pText);
|
|
if (song != -1)
|
|
{
|
|
music.play(song);
|
|
}
|
|
}
|
|
else if (SDL_strcmp(pKey, "showtargets") == 0)
|
|
{
|
|
map.showtargets = help.Int(pText);
|
|
}
|
|
|
|
}
|
|
|
|
if (map.finalmode)
|
|
{
|
|
map.final_colormode = false;
|
|
map.final_mapcol = 0;
|
|
map.final_colorframe = 0;
|
|
}
|
|
if (map.finalstretch)
|
|
{
|
|
map.finalstretch = true;
|
|
map.final_colormode = true;
|
|
map.final_mapcol = 0;
|
|
map.final_colorframe = 1;
|
|
}
|
|
|
|
map.showteleporters = true;
|
|
if(obj.flags[12]) map.showtargets = true;
|
|
if (obj.flags[42]) map.showtrinkets = true;
|
|
|
|
|
|
}
|
|
|
|
void Game::customloadquick(const std::string& savfile)
|
|
{
|
|
tinyxml2::XMLDocument doc;
|
|
tinyxml2::XMLHandle hDoc(&doc);
|
|
tinyxml2::XMLElement* pElem;
|
|
std::string levelfile;
|
|
|
|
if (cliplaytest)
|
|
{
|
|
savex = playx;
|
|
savey = playy;
|
|
saverx = playrx;
|
|
savery = playry;
|
|
savegc = playgc;
|
|
if (playmusic > -1)
|
|
{
|
|
music.play(playmusic);
|
|
}
|
|
return;
|
|
}
|
|
|
|
levelfile = savfile.substr(7);
|
|
if (!FILESYSTEM_loadTiXml2Document(("saves/"+levelfile+".vvv").c_str(), doc))
|
|
{
|
|
vlog_error("%s.vvv not found", levelfile.c_str());
|
|
return;
|
|
}
|
|
|
|
if (doc.Error())
|
|
{
|
|
vlog_error("Error parsing %s.vvv: %s", levelfile.c_str(), doc.ErrorStr());
|
|
return;
|
|
}
|
|
|
|
// Like readmaingamesave(...), old saves have just <hardestroom>
|
|
hardestroom_x = -1;
|
|
hardestroom_y = -1;
|
|
hardestroom_specialname = false;
|
|
hardestroom_finalstretch = false;
|
|
|
|
for (pElem = hDoc
|
|
.FirstChildElement()
|
|
.FirstChildElement("Data")
|
|
.FirstChildElement()
|
|
.ToElement();
|
|
pElem != NULL;
|
|
pElem = pElem->NextSiblingElement())
|
|
{
|
|
const char* pKey = pElem->Value();
|
|
const char* pText = pElem->GetText() ;
|
|
if(pText == NULL)
|
|
{
|
|
pText = "";
|
|
}
|
|
|
|
LOAD_ARRAY_RENAME(worldmap, map.explored)
|
|
|
|
LOAD_ARRAY_RENAME(flags, obj.flags)
|
|
|
|
LOAD_ARRAY_RENAME(moods, obj.customcrewmoods)
|
|
|
|
LOAD_ARRAY(crewstats)
|
|
|
|
LOAD_ARRAY_RENAME(collect, obj.collect)
|
|
|
|
LOAD_ARRAY_RENAME(customcollect, obj.customcollect)
|
|
|
|
if (SDL_strcmp(pKey, "finalmode") == 0)
|
|
{
|
|
map.finalmode = help.Int(pText);
|
|
}
|
|
if (SDL_strcmp(pKey, "finalstretch") == 0)
|
|
{
|
|
map.finalstretch = help.Int(pText);
|
|
}
|
|
|
|
if (map.finalmode)
|
|
{
|
|
map.final_colormode = false;
|
|
map.final_mapcol = 0;
|
|
map.final_colorframe = 0;
|
|
}
|
|
if (map.finalstretch)
|
|
{
|
|
map.finalstretch = true;
|
|
map.final_colormode = true;
|
|
map.final_mapcol = 0;
|
|
map.final_colorframe = 1;
|
|
}
|
|
|
|
|
|
if (SDL_strcmp(pKey, "savex") == 0)
|
|
{
|
|
savex = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "savey") == 0)
|
|
{
|
|
savey = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "saverx") == 0)
|
|
{
|
|
saverx = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "savery") == 0)
|
|
{
|
|
savery = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "savegc") == 0)
|
|
{
|
|
savegc = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "savedir") == 0)
|
|
{
|
|
savedir= help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "savepoint") == 0)
|
|
{
|
|
savepoint = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "savecolour") == 0)
|
|
{
|
|
savecolour = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "companion") == 0)
|
|
{
|
|
companion = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "lastsaved") == 0)
|
|
{
|
|
lastsaved = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "teleportscript") == 0)
|
|
{
|
|
teleportscript = pText;
|
|
}
|
|
else if (SDL_strcmp(pKey, "supercrewmate") == 0)
|
|
{
|
|
supercrewmate = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "scmprogress") == 0)
|
|
{
|
|
scmprogress = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "frames") == 0)
|
|
{
|
|
frames = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "seconds") == 0)
|
|
{
|
|
seconds = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "minutes") == 0)
|
|
{
|
|
minutes = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "hours") == 0)
|
|
{
|
|
hours = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "deathcounts") == 0)
|
|
{
|
|
deathcounts = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "totalflips") == 0)
|
|
{
|
|
totalflips = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "hardestroom") == 0)
|
|
{
|
|
hardestroom = pText;
|
|
}
|
|
else if (SDL_strcmp(pKey, "hardestroomdeaths") == 0)
|
|
{
|
|
hardestroomdeaths = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "hardestroom_x") == 0)
|
|
{
|
|
hardestroom_x = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "hardestroom_y") == 0)
|
|
{
|
|
hardestroom_y = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "hardestroom_specialname") == 0)
|
|
{
|
|
hardestroom_specialname = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "hardestroom_finalstretch") == 0)
|
|
{
|
|
hardestroom_finalstretch = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "currentsong") == 0)
|
|
{
|
|
int song = help.Int(pText);
|
|
if (song != -1)
|
|
{
|
|
music.play(song);
|
|
}
|
|
}
|
|
else if (SDL_strcmp(pKey, "lang_custom") == 0)
|
|
{
|
|
loc::lang_custom = pText;
|
|
if (pText[0] != '\0')
|
|
{
|
|
loc::loadtext_custom(NULL);
|
|
}
|
|
}
|
|
else if (SDL_strcmp(pKey, "showminimap") == 0)
|
|
{
|
|
map.customshowmm = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "mapreveal") == 0)
|
|
{
|
|
map.revealmap = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "disabletemporaryaudiopause") == 0)
|
|
{
|
|
disabletemporaryaudiopause = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "showtrinkets") == 0)
|
|
{
|
|
map.showtrinkets = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "roomname") == 0)
|
|
{
|
|
map.setroomname(pText);
|
|
map.roomnameset = true;
|
|
map.roomname_special = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void loadthissummary(
|
|
const char* filename,
|
|
struct Game::Summary* summary,
|
|
tinyxml2::XMLDocument& doc
|
|
) {
|
|
tinyxml2::XMLHandle hDoc(&doc);
|
|
tinyxml2::XMLElement* pElem;
|
|
|
|
if (doc.Error())
|
|
{
|
|
vlog_error("Error parsing %s: %s", filename, doc.ErrorStr());
|
|
return;
|
|
}
|
|
|
|
summary->exists = true;
|
|
|
|
for (pElem = hDoc
|
|
.FirstChildElement()
|
|
.FirstChildElement("Data")
|
|
.FirstChildElement()
|
|
.ToElement();
|
|
pElem != NULL;
|
|
pElem = pElem->NextSiblingElement())
|
|
{
|
|
const char* pKey = pElem->Value();
|
|
const char* pText = pElem->GetText();
|
|
|
|
if (pText == NULL)
|
|
{
|
|
pText = "";
|
|
}
|
|
|
|
if (SDL_strcmp(pKey, "seconds") == 0)
|
|
{
|
|
summary->seconds = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "minutes") == 0)
|
|
{
|
|
summary->minutes = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "hours") == 0)
|
|
{
|
|
summary->hours = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "saverx") == 0)
|
|
{
|
|
summary->saverx = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "savery") == 0)
|
|
{
|
|
summary->savery = help.Int(pText);
|
|
}
|
|
else if (SDL_strcmp(pKey, "trinkets") == 0)
|
|
{
|
|
summary->trinkets = help.Int(pText);
|
|
}
|
|
|
|
LOAD_ARRAY_RENAME(crewstats, summary->crewstats)
|
|
}
|
|
}
|
|
|
|
void Game::loadsummary(void)
|
|
{
|
|
tinyxml2::XMLDocument doc;
|
|
|
|
SDL_zero(last_telesave);
|
|
SDL_zero(last_quicksave);
|
|
|
|
if (FILESYSTEM_loadTiXml2Document("saves/tsave.vvv", doc))
|
|
{
|
|
loadthissummary("tsave.vvv", &last_telesave, doc);
|
|
}
|
|
|
|
if (FILESYSTEM_loadTiXml2Document("saves/qsave.vvv", doc))
|
|
{
|
|
loadthissummary("qsave.vvv", &last_quicksave, doc);
|
|
}
|
|
}
|
|
|
|
void Game::initteleportermode(void)
|
|
{
|
|
//Set the teleporter variable to the right position!
|
|
teleport_to_teleporter = 0;
|
|
|
|
for (size_t i = 0; i < map.teleporters.size(); i++)
|
|
{
|
|
if (roomx == map.teleporters[i].x + 100 && roomy == map.teleporters[i].y + 100)
|
|
{
|
|
teleport_to_teleporter = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Game::savetele(void)
|
|
{
|
|
if (map.custommode || inspecial())
|
|
{
|
|
//Don't trash save data!
|
|
return false;
|
|
}
|
|
|
|
tinyxml2::XMLDocument doc;
|
|
bool already_exists = FILESYSTEM_loadTiXml2Document("saves/tsave.vvv", doc);
|
|
if (!already_exists)
|
|
{
|
|
vlog_info("No tsave.vvv found. Creating new file");
|
|
}
|
|
else if (doc.Error())
|
|
{
|
|
vlog_error("Error parsing existing tsave.vvv: %s", doc.ErrorStr());
|
|
vlog_info("Creating new tsave.vvv");
|
|
}
|
|
|
|
last_telesave = writemaingamesave(doc);
|
|
|
|
if(!FILESYSTEM_saveTiXml2Document("saves/tsave.vvv", doc))
|
|
{
|
|
vlog_error("Could Not Save game!");
|
|
vlog_error("Failed: %s%s", saveFilePath, "tsave.vvv");
|
|
return false;
|
|
}
|
|
vlog_info("Game saved");
|
|
return true;
|
|
}
|
|
|
|
|
|
bool Game::savequick(void)
|
|
{
|
|
if (map.custommode || inspecial())
|
|
{
|
|
//Don't trash save data!
|
|
return false;
|
|
}
|
|
|
|
tinyxml2::XMLDocument doc;
|
|
bool already_exists = FILESYSTEM_loadTiXml2Document("saves/qsave.vvv", doc);
|
|
if (!already_exists)
|
|
{
|
|
vlog_info("No qsave.vvv found. Creating new file");
|
|
}
|
|
else if (doc.Error())
|
|
{
|
|
vlog_error("Error parsing existing qsave.vvv: %s", doc.ErrorStr());
|
|
vlog_info("Creating new qsave.vvv");
|
|
}
|
|
|
|
last_quicksave = writemaingamesave(doc);
|
|
|
|
if(!FILESYSTEM_saveTiXml2Document("saves/qsave.vvv", doc))
|
|
{
|
|
vlog_error("Could Not Save game!");
|
|
vlog_error("Failed: %s%s", saveFilePath, "qsave.vvv");
|
|
return false;
|
|
}
|
|
vlog_info("Game saved");
|
|
return true;
|
|
}
|
|
|
|
// Returns summary of save
|
|
struct Game::Summary Game::writemaingamesave(tinyxml2::XMLDocument& doc)
|
|
{
|
|
//TODO make this code a bit cleaner.
|
|
|
|
struct Game::Summary summary;
|
|
SDL_zero(summary);
|
|
|
|
if (map.custommode || inspecial())
|
|
{
|
|
//Don't trash save data!
|
|
return summary;
|
|
}
|
|
|
|
xml::update_declaration(doc);
|
|
|
|
tinyxml2::XMLElement * root = xml::update_element(doc, "Save");
|
|
|
|
xml::update_comment(root, " Save file " );
|
|
|
|
tinyxml2::XMLElement * msgs = xml::update_element(root, "Data");
|
|
|
|
|
|
//Flags, map and stats
|
|
|
|
std::string mapExplored;
|
|
for(size_t i = 0; i < SDL_arraysize(map.explored); i++ )
|
|
{
|
|
mapExplored += help.String(map.explored[i]) + ",";
|
|
}
|
|
xml::update_tag(msgs, "worldmap", mapExplored.c_str());
|
|
|
|
std::string flags;
|
|
for(size_t i = 0; i < SDL_arraysize(obj.flags); i++ )
|
|
{
|
|
flags += help.String((int) obj.flags[i]) + ",";
|
|
}
|
|
xml::update_tag(msgs, "flags", flags.c_str());
|
|
|
|
std::string crewstatsString;
|
|
for(size_t i = 0; i < SDL_arraysize(crewstats); i++ )
|
|
{
|
|
crewstatsString += help.String(crewstats[i]) + ",";
|
|
}
|
|
xml::update_tag(msgs, "crewstats", crewstatsString.c_str());
|
|
|
|
std::string collect;
|
|
for(size_t i = 0; i < SDL_arraysize(obj.collect); i++ )
|
|
{
|
|
collect += help.String((int) obj.collect[i]) + ",";
|
|
}
|
|
xml::update_tag(msgs, "collect", collect.c_str());
|
|
|
|
//Position
|
|
|
|
xml::update_tag(msgs, "savex", savex);
|
|
|
|
xml::update_tag(msgs, "savey", savey);
|
|
|
|
xml::update_tag(msgs, "saverx", saverx);
|
|
|
|
xml::update_tag(msgs, "savery", savery);
|
|
|
|
xml::update_tag(msgs, "savegc", savegc);
|
|
|
|
xml::update_tag(msgs, "savedir", savedir);
|
|
|
|
xml::update_tag(msgs, "savepoint", savepoint);
|
|
|
|
int n_trinkets = trinkets();
|
|
xml::update_tag(msgs, "trinkets", n_trinkets);
|
|
|
|
|
|
//Special stats
|
|
|
|
if (music.nicefade)
|
|
{
|
|
xml::update_tag(msgs, "currentsong", music.nicechange);
|
|
}
|
|
else
|
|
{
|
|
xml::update_tag(msgs, "currentsong", music.currentsong);
|
|
}
|
|
|
|
xml::update_tag(msgs, "showtargets", (int) map.showtargets);
|
|
|
|
xml::update_tag(msgs, "teleportscript", teleportscript.c_str());
|
|
xml::update_tag(msgs, "companion", companion);
|
|
|
|
xml::update_tag(msgs, "lastsaved", lastsaved);
|
|
xml::update_tag(msgs, "supercrewmate", (int) supercrewmate);
|
|
|
|
xml::update_tag(msgs, "scmprogress", scmprogress);
|
|
|
|
|
|
xml::update_tag(msgs, "frames", frames);
|
|
xml::update_tag(msgs, "seconds", seconds);
|
|
|
|
xml::update_tag(msgs, "minutes", minutes);
|
|
xml::update_tag(msgs, "hours", hours);
|
|
|
|
xml::update_tag(msgs, "deathcounts", deathcounts);
|
|
xml::update_tag(msgs, "totalflips", totalflips);
|
|
|
|
xml::update_tag(msgs, "hardestroom", hardestroom.c_str());
|
|
xml::update_tag(msgs, "hardestroomdeaths", hardestroomdeaths);
|
|
xml::update_tag(msgs, "hardestroom_x", hardestroom_x);
|
|
xml::update_tag(msgs, "hardestroom_y", hardestroom_y);
|
|
xml::update_tag(msgs, "hardestroom_specialname", (int) hardestroom_specialname);
|
|
xml::update_tag(msgs, "hardestroom_finalstretch", (int) hardestroom_finalstretch);
|
|
|
|
xml::update_tag(msgs, "finalmode", (int) map.finalmode);
|
|
xml::update_tag(msgs, "finalstretch", (int) map.finalstretch);
|
|
|
|
|
|
std::string legacy_summary = std::string(map.currentarea(saverx, savery)) + ", " + timestring();
|
|
xml::update_tag(msgs, "summary", legacy_summary.c_str());
|
|
|
|
|
|
summary.exists = true;
|
|
summary.seconds = seconds;
|
|
summary.minutes = minutes;
|
|
summary.hours = hours;
|
|
summary.saverx = saverx;
|
|
summary.savery = savery;
|
|
summary.trinkets = n_trinkets;
|
|
SDL_memcpy(summary.crewstats, crewstats, sizeof(summary.crewstats));
|
|
|
|
return summary;
|
|
}
|
|
|
|
|
|
bool Game::customsavequick(const std::string& savfile)
|
|
{
|
|
const std::string levelfile = savfile.substr(7);
|
|
|
|
tinyxml2::XMLDocument doc;
|
|
bool already_exists = FILESYSTEM_loadTiXml2Document(("saves/" + levelfile + ".vvv").c_str(), doc);
|
|
if (!already_exists)
|
|
{
|
|
vlog_info("No %s.vvv found. Creating new file", levelfile.c_str());
|
|
}
|
|
else if (doc.Error())
|
|
{
|
|
vlog_error("Error parsing existing %s.vvv: %s", levelfile.c_str(), doc.ErrorStr());
|
|
vlog_info("Creating new %s.vvv", levelfile.c_str());
|
|
}
|
|
|
|
xml::update_declaration(doc);
|
|
|
|
tinyxml2::XMLElement * root = xml::update_element(doc, "Save");
|
|
|
|
xml::update_comment(root, " Save file ");
|
|
|
|
tinyxml2::XMLElement * msgs = xml::update_element(root, "Data");
|
|
|
|
|
|
//Flags, map and stats
|
|
|
|
std::string mapExplored;
|
|
for(size_t i = 0; i < SDL_arraysize(map.explored); i++ )
|
|
{
|
|
mapExplored += help.String(map.explored[i]) + ",";
|
|
}
|
|
xml::update_tag(msgs, "worldmap", mapExplored.c_str());
|
|
|
|
std::string flags;
|
|
for(size_t i = 0; i < SDL_arraysize(obj.flags); i++ )
|
|
{
|
|
flags += help.String((int) obj.flags[i]) + ",";
|
|
}
|
|
xml::update_tag(msgs, "flags", flags.c_str());
|
|
|
|
std::string moods;
|
|
for(size_t i = 0; i < SDL_arraysize(obj.customcrewmoods); i++ )
|
|
{
|
|
moods += help.String(obj.customcrewmoods[i]) + ",";
|
|
}
|
|
xml::update_tag(msgs, "moods", moods.c_str());
|
|
|
|
std::string crewstatsString;
|
|
for(size_t i = 0; i < SDL_arraysize(crewstats); i++ )
|
|
{
|
|
crewstatsString += help.String(crewstats[i]) + ",";
|
|
}
|
|
xml::update_tag(msgs, "crewstats", crewstatsString.c_str());
|
|
|
|
std::string collect;
|
|
for(size_t i = 0; i < SDL_arraysize(obj.collect); i++ )
|
|
{
|
|
collect += help.String((int) obj.collect[i]) + ",";
|
|
}
|
|
xml::update_tag(msgs, "collect", collect.c_str());
|
|
|
|
std::string customcollect;
|
|
for(size_t i = 0; i < SDL_arraysize(obj.customcollect); i++ )
|
|
{
|
|
customcollect += help.String((int) obj.customcollect[i]) + ",";
|
|
}
|
|
xml::update_tag(msgs, "customcollect", customcollect.c_str());
|
|
|
|
//Position
|
|
|
|
xml::update_tag(msgs, "savex", savex);
|
|
|
|
xml::update_tag(msgs, "savey", savey);
|
|
|
|
xml::update_tag(msgs, "saverx", saverx);
|
|
|
|
xml::update_tag(msgs, "savery", savery);
|
|
|
|
xml::update_tag(msgs, "savegc", savegc);
|
|
|
|
xml::update_tag(msgs, "savedir", savedir);
|
|
|
|
xml::update_tag(msgs, "savepoint", savepoint);
|
|
|
|
xml::update_tag(msgs, "savecolour", savecolour);
|
|
|
|
xml::update_tag(msgs, "trinkets", trinkets());
|
|
|
|
xml::update_tag(msgs, "crewmates", crewmates());
|
|
|
|
|
|
//Special stats
|
|
|
|
if (music.nicefade)
|
|
{
|
|
xml::update_tag(msgs, "currentsong", music.nicechange );
|
|
}
|
|
else
|
|
{
|
|
xml::update_tag(msgs, "currentsong", music.currentsong);
|
|
}
|
|
|
|
xml::update_tag(msgs, "lang_custom", loc::lang_custom.c_str());
|
|
|
|
xml::update_tag(msgs, "teleportscript", teleportscript.c_str());
|
|
xml::update_tag(msgs, "companion", companion);
|
|
|
|
xml::update_tag(msgs, "lastsaved", lastsaved);
|
|
xml::update_tag(msgs, "supercrewmate", (int) supercrewmate);
|
|
|
|
xml::update_tag(msgs, "scmprogress", scmprogress);
|
|
|
|
|
|
xml::update_tag(msgs, "frames", frames);
|
|
xml::update_tag(msgs, "seconds", seconds);
|
|
|
|
xml::update_tag(msgs, "minutes", minutes);
|
|
xml::update_tag(msgs, "hours", hours);
|
|
|
|
xml::update_tag(msgs, "deathcounts", deathcounts);
|
|
xml::update_tag(msgs, "totalflips", totalflips);
|
|
|
|
xml::update_tag(msgs, "hardestroom", hardestroom.c_str());
|
|
xml::update_tag(msgs, "hardestroomdeaths", hardestroomdeaths);
|
|
xml::update_tag(msgs, "hardestroom_x", hardestroom_x);
|
|
xml::update_tag(msgs, "hardestroom_y", hardestroom_y);
|
|
xml::update_tag(msgs, "hardestroom_specialname", (int) hardestroom_specialname);
|
|
xml::update_tag(msgs, "hardestroom_finalstretch", (int) hardestroom_finalstretch);
|
|
|
|
xml::update_tag(msgs, "showminimap", (int) map.customshowmm);
|
|
|
|
xml::update_tag(msgs, "mapreveal", (int) map.revealmap);
|
|
|
|
xml::update_tag(msgs, "disabletemporaryaudiopause", (int) disabletemporaryaudiopause);
|
|
|
|
xml::update_tag(msgs, "showtrinkets", (int) map.showtrinkets);
|
|
|
|
if (map.roomnameset)
|
|
{
|
|
xml::update_tag(msgs, "roomname", map.roomname);
|
|
}
|
|
else
|
|
{
|
|
// If there's roomname tags, remove them. There will probably only always be one, but just in case...
|
|
tinyxml2::XMLElement* element;
|
|
while ((element = msgs->FirstChildElement("roomname")) != NULL)
|
|
{
|
|
doc.DeleteNode(element);
|
|
}
|
|
}
|
|
|
|
std::string legacy_summary = customleveltitle + ", " + timestring();
|
|
xml::update_tag(msgs, "summary", legacy_summary.c_str());
|
|
|
|
if(!FILESYSTEM_saveTiXml2Document(("saves/"+levelfile+".vvv").c_str(), doc))
|
|
{
|
|
vlog_error("Could Not Save game!");
|
|
vlog_error("Failed: %s%s%s", saveFilePath, levelfile.c_str(), ".vvv");
|
|
return false;
|
|
}
|
|
vlog_info("Game saved");
|
|
return true;
|
|
}
|
|
|
|
|
|
void Game::loadtele(void)
|
|
{
|
|
tinyxml2::XMLDocument doc;
|
|
if (!FILESYSTEM_loadTiXml2Document("saves/tsave.vvv", doc)) return;
|
|
|
|
readmaingamesave("tsave.vvv", doc);
|
|
}
|
|
|
|
std::string Game::unrescued(void)
|
|
{
|
|
//Randomly return the name of an unrescued crewmate
|
|
//Localization is handled with regular cutscene dialogue
|
|
if (fRandom() * 100 > 50)
|
|
{
|
|
if (!crewstats[5]) return "Victoria";
|
|
if (!crewstats[2]) return "Vitellary";
|
|
if (!crewstats[4]) return "Verdigris";
|
|
if (!crewstats[3]) return "Vermilion";
|
|
}
|
|
else
|
|
{
|
|
if (fRandom() * 100 > 50)
|
|
{
|
|
if (!crewstats[2]) return "Vitellary";
|
|
if (!crewstats[4]) return "Verdigris";
|
|
if (!crewstats[3]) return "Vermilion";
|
|
if (!crewstats[5]) return "Victoria";
|
|
}
|
|
else
|
|
{
|
|
if (!crewstats[4]) return "Verdigris";
|
|
if (!crewstats[3]) return "Vermilion";
|
|
if (!crewstats[5]) return "Victoria";
|
|
if (!crewstats[2]) return "Vitellary";
|
|
}
|
|
}
|
|
return "you";
|
|
}
|
|
|
|
void Game::gameclock(void)
|
|
{
|
|
if (timetrialcountdown > 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
frames++;
|
|
if (frames >= 30)
|
|
{
|
|
frames -= 30;
|
|
seconds++;
|
|
if (seconds >= 60)
|
|
{
|
|
seconds -= 60;
|
|
minutes++;
|
|
if (minutes >= 60)
|
|
{
|
|
minutes -= 60;
|
|
hours++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string Game::giventimestring( int hrs, int min, int sec )
|
|
{
|
|
return timetstring(help.hms_to_seconds(hrs, min, sec));
|
|
}
|
|
|
|
std::string Game::timestring(void)
|
|
{
|
|
return giventimestring(hours, minutes, seconds);
|
|
}
|
|
|
|
std::string Game::resulttimestring(void)
|
|
{
|
|
//given result time in seconds:
|
|
char output[SCREEN_WIDTH_CHARS + 1];
|
|
help.format_time(output, sizeof(output), timetrialresulttime, timetrialresultframes, true);
|
|
return output;
|
|
}
|
|
|
|
std::string Game::timetstring( int t )
|
|
{
|
|
//given par time in seconds:
|
|
char output[SCREEN_WIDTH_CHARS + 1];
|
|
help.format_time(output, sizeof(output), t, -1, true);
|
|
return output;
|
|
}
|
|
|
|
void Game::timestringcenti(char* buffer, const size_t buffer_size)
|
|
{
|
|
help.format_time(buffer, buffer_size, help.hms_to_seconds(hours, minutes, seconds), frames, true);
|
|
}
|
|
|
|
void Game::returnmenu(void)
|
|
{
|
|
if (menustack.empty())
|
|
{
|
|
vlog_error("Error: returning to previous menu frame on empty stack!");
|
|
return;
|
|
}
|
|
|
|
/* FIXME: Super bad kludge, don't hardcode this! */
|
|
if (currentmenuname == Menu::ed_music)
|
|
{
|
|
music.fadeout();
|
|
}
|
|
else if (currentmenuname == Menu::gamecompletecontinue
|
|
|| currentmenuname == Menu::timetrialcomplete3
|
|
|| currentmenuname == Menu::gameover2
|
|
|| currentmenuname == Menu::nodeathmodecomplete2)
|
|
{
|
|
music.play(Music_PRESENTINGVVVVVV);
|
|
}
|
|
enum Menu::MenuName camefrom = currentmenuname;
|
|
|
|
MenuStackFrame& frame = menustack[menustack.size()-1];
|
|
|
|
//Store this in case createmenu() removes the stack frame
|
|
int previousoption = frame.option;
|
|
|
|
createmenu(frame.name, true);
|
|
currentmenuoption = previousoption;
|
|
|
|
//Remove the stackframe now, but createmenu() might have already gotten to it
|
|
//if we were returning to the main menu
|
|
if (!menustack.empty())
|
|
{
|
|
menustack.pop_back();
|
|
}
|
|
|
|
/* FIXME: Even more horrible kludge! */
|
|
if (camefrom == Menu::timetrialcomplete3)
|
|
{
|
|
if (can_unlock_ndm())
|
|
{
|
|
unlock_ndm();
|
|
}
|
|
}
|
|
}
|
|
|
|
void Game::returntomenu(enum Menu::MenuName t)
|
|
{
|
|
if (currentmenuname == t)
|
|
{
|
|
createmenu(t, true);
|
|
return;
|
|
}
|
|
|
|
//Unwind the menu stack until we reach our desired menu
|
|
int i = menustack.size() - 1;
|
|
while (i >= 0)
|
|
{
|
|
//If we pop it off we can't reference it anymore, so check for it now
|
|
bool is_the_menu_we_want = menustack[i].name == t;
|
|
|
|
returnmenu();
|
|
|
|
if (is_the_menu_we_want)
|
|
{
|
|
break;
|
|
}
|
|
|
|
i--;
|
|
}
|
|
}
|
|
|
|
void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ )
|
|
{
|
|
if (t == Menu::mainmenu && !menutestmode)
|
|
{
|
|
//Either we've just booted up the game or returned from gamemode
|
|
//Whichever it is, we shouldn't have a stack,
|
|
//and most likely don't have a current stackframe
|
|
menustack.clear();
|
|
}
|
|
else if (!samemenu)
|
|
{
|
|
MenuStackFrame frame;
|
|
frame.option = currentmenuoption;
|
|
frame.name = currentmenuname;
|
|
menustack.push_back(frame);
|
|
currentmenuoption = 0;
|
|
}
|
|
|
|
currentmenuname = t;
|
|
menuyoff = 0;
|
|
int maxspacing = 30; // maximum value for menuspacing, can only become lower.
|
|
menucountdown = 0;
|
|
menuoptions.clear();
|
|
|
|
switch (t)
|
|
{
|
|
case Menu::mainmenu:
|
|
if (ingame_titlemode)
|
|
{
|
|
/* We shouldn't be here! */
|
|
SDL_assert(0 && "Entering main menu from in-game options!");
|
|
break;
|
|
}
|
|
#if !defined(MAKEANDPLAY)
|
|
option(loc::gettext("play"));
|
|
#endif
|
|
option(loc::gettext("levels"));
|
|
option(loc::gettext("options"));
|
|
if (loc::show_translator_menu)
|
|
{
|
|
option(loc::gettext("translator"));
|
|
}
|
|
option(loc::gettext("credits"));
|
|
option(loc::gettext("quit"));
|
|
menuyoff = -10;
|
|
maxspacing = 15;
|
|
break;
|
|
case Menu::playerworlds:
|
|
option(loc::gettext("play a level"));
|
|
option(loc::gettext("level editor"), !editor_disabled);
|
|
if (!editor_disabled)
|
|
{
|
|
option(loc::gettext("open level folder"), FILESYSTEM_openDirectoryEnabled());
|
|
option(loc::gettext("show level folder path"));
|
|
}
|
|
option(loc::gettext("return"));
|
|
menuyoff = -40;
|
|
maxspacing = 15;
|
|
break;
|
|
case Menu::confirmshowlevelspath:
|
|
option(loc::gettext("no, don't show me"));
|
|
option(loc::gettext("yes, reveal the path"));
|
|
menuyoff = -10;
|
|
break;
|
|
case Menu::showlevelspath:
|
|
option(loc::gettext("return to levels"));
|
|
menuyoff = 60;
|
|
break;
|
|
case Menu::levellist:
|
|
if(cl.ListOfMetaData.size()==0)
|
|
{
|
|
option(loc::gettext("ok"));
|
|
menuyoff = -20;
|
|
}
|
|
else
|
|
{
|
|
for(int i=0; i<(int) cl.ListOfMetaData.size(); i++) // FIXME: int/size_t! -flibit
|
|
{
|
|
if(i>=levelpage*8 && i< (levelpage*8)+8)
|
|
{
|
|
const std::string filename = cl.ListOfMetaData[i].filename.substr(7);
|
|
int score = 0;
|
|
if (customlevelstats.count(filename) > 0)
|
|
{
|
|
score = customlevelstats[filename];
|
|
}
|
|
const char* prefix;
|
|
switch (score)
|
|
{
|
|
case 0:
|
|
{
|
|
static const char tmp[] = " ";
|
|
prefix = tmp;
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
static const char tmp[] = " * ";
|
|
prefix = tmp;
|
|
break;
|
|
}
|
|
case 3:
|
|
{
|
|
static const char tmp[] = "** ";
|
|
prefix = tmp;
|
|
break;
|
|
}
|
|
default:
|
|
SDL_assert(0 && "Unhandled menu text prefix!");
|
|
prefix = "";
|
|
break;
|
|
}
|
|
const char* title = cl.ListOfMetaData[i].title.c_str();
|
|
if (cl.ListOfMetaData[i].title_is_gettext)
|
|
{
|
|
title = loc::gettext(title);
|
|
}
|
|
/* We have to make sure the stars and spaces are consistently on the
|
|
* correct side of the title, no matter what bidi characters are in there.
|
|
* So just always let the bidi engine handle it, with a few control chars. */
|
|
char text[MENU_TEXT_BYTES];
|
|
SDL_snprintf(
|
|
text, sizeof(text),
|
|
"%s%s%s%s%s",
|
|
// LRM or RLM depending on UI language, to make the stars aligned to left or right
|
|
UTF8_encode(font::is_rtl(PR_FONT_INTERFACE) ? 0x200F : 0x200E).bytes,
|
|
prefix,
|
|
// FIRST STRONG ISOLATE, to start an isolated block oriented however bidi sees fit
|
|
UTF8_encode(0x2068).bytes,
|
|
title,
|
|
// POP DIRECTIONAL ISOLATE, exit isolated level title
|
|
UTF8_encode(0x2069).bytes
|
|
);
|
|
for (size_t ii = 0; text[ii] != '\0'; ++ii)
|
|
{
|
|
text[ii] = SDL_tolower(text[ii]);
|
|
}
|
|
option(
|
|
text,
|
|
true,
|
|
(cl.ListOfMetaData[i].title_is_gettext ? PR_FONT_INTERFACE : PR_FONT_IDX(
|
|
cl.ListOfMetaData[i].level_main_font_idx, font::is_rtl(PR_FONT_INTERFACE)
|
|
)) | PR_RTL_XFLIP
|
|
);
|
|
}
|
|
}
|
|
if (cl.ListOfMetaData.size() > 8)
|
|
{
|
|
if((size_t) ((levelpage*8)+8) <cl.ListOfMetaData.size())
|
|
{
|
|
option(loc::gettext("next page"));
|
|
}
|
|
else
|
|
{
|
|
option(loc::gettext("first page"));
|
|
}
|
|
if (levelpage == 0)
|
|
{
|
|
option(loc::gettext("last page"));
|
|
}
|
|
else
|
|
{
|
|
option(loc::gettext("previous page"));
|
|
}
|
|
}
|
|
option(loc::gettext("return"));
|
|
|
|
menuxoff = 20;
|
|
menuyoff = 70-(menuoptions.size()*10);
|
|
menuspacing = 5;
|
|
return; // skip automatic centering, will turn out bad with levels list
|
|
}
|
|
break;
|
|
case Menu::quickloadlevel:
|
|
option(loc::gettext("continue from save"));
|
|
option(loc::gettext("start from beginning"));
|
|
option(loc::gettext("delete save"));
|
|
option(loc::gettext("back to levels"));
|
|
menuyoff = -30;
|
|
break;
|
|
case Menu::deletequicklevel:
|
|
option(loc::gettext("no! don't delete"));
|
|
option(loc::gettext("yes, delete save"));
|
|
menuyoff = 64;
|
|
break;
|
|
case Menu::youwannaquit:
|
|
option(loc::gettext("yes, quit"));
|
|
option(loc::gettext("no, return"));
|
|
menuyoff = -20;
|
|
break;
|
|
case Menu::errornostart:
|
|
option(loc::gettext("ok"));
|
|
menuyoff = -20;
|
|
break;
|
|
case Menu::gameplayoptions:
|
|
#if !defined(MAKEANDPLAY)
|
|
if (ingame_titlemode && unlock[Unlock_FLIPMODE])
|
|
#endif
|
|
{
|
|
option(loc::gettext("flip mode"));
|
|
}
|
|
option(loc::gettext("toggle fps"));
|
|
option(loc::gettext("speedrun options"));
|
|
option(loc::gettext("advanced options"));
|
|
option(loc::gettext("clear main game data"));
|
|
option(loc::gettext("clear custom level data"));
|
|
option(loc::gettext("return"));
|
|
menuyoff = -10;
|
|
maxspacing = 15;
|
|
break;
|
|
case Menu::graphicoptions:
|
|
if (!gameScreen.isForcedFullscreen())
|
|
{
|
|
option(loc::gettext("toggle fullscreen"));
|
|
}
|
|
option(loc::gettext("scaling mode"));
|
|
if (!gameScreen.isForcedFullscreen())
|
|
{
|
|
option(loc::gettext("resize to nearest"), gameScreen.isWindowed);
|
|
}
|
|
option(loc::gettext("toggle filter"));
|
|
option(loc::gettext("toggle analogue"));
|
|
option(loc::gettext("toggle vsync"));
|
|
option(loc::gettext("return"));
|
|
menuyoff = -10;
|
|
maxspacing = 15;
|
|
break;
|
|
case Menu::ed_settings:
|
|
option(loc::gettext("change description"));
|
|
option(loc::gettext("edit scripts"));
|
|
option(loc::gettext("change music"));
|
|
option(loc::gettext("editor ghosts"));
|
|
option(loc::gettext("load level"));
|
|
option(loc::gettext("save level"));
|
|
option(loc::gettext("options"));
|
|
option(loc::gettext("quit to main menu"));
|
|
|
|
menuyoff = -20;
|
|
maxspacing = 15;
|
|
break;
|
|
case Menu::ed_desc:
|
|
option(loc::gettext("change name"));
|
|
option(loc::gettext("change author"));
|
|
option(loc::gettext("change description"));
|
|
option(loc::gettext("change website"));
|
|
option(loc::gettext("change font"));
|
|
option(loc::gettext("return"));
|
|
|
|
menuyoff = 6;
|
|
maxspacing = 15;
|
|
break;
|
|
case Menu::ed_music:
|
|
option(loc::gettext("next song"));
|
|
option(loc::gettext("previous song"));
|
|
option(loc::gettext("return"));
|
|
menuyoff = 16;
|
|
maxspacing = 15;
|
|
break;
|
|
case Menu::ed_quit:
|
|
option(loc::gettext("yes, save and quit"));
|
|
option(loc::gettext("no, quit without saving"));
|
|
option(loc::gettext("return to editor"));
|
|
menuyoff = 8;
|
|
maxspacing = 15;
|
|
break;
|
|
case Menu::ed_font:
|
|
{
|
|
int option_match = -1;
|
|
for (uint8_t i = 0; i < font::font_idx_options_n; i++)
|
|
{
|
|
uint8_t idx = font::font_idx_options[i];
|
|
option(font::get_main_font_display_name(idx), true, PR_FONT_IDX(idx, font::is_rtl(PR_FONT_INTERFACE)) | PR_RTL_XFLIP);
|
|
if (font::level_font_is_main_idx(idx))
|
|
{
|
|
option_match = i;
|
|
}
|
|
}
|
|
|
|
currentmenuoption = option_match != -1 ? option_match : 0;
|
|
maxspacing = 15;
|
|
break;
|
|
}
|
|
case Menu::options:
|
|
option(loc::gettext("gameplay"));
|
|
option(loc::gettext("graphics"));
|
|
option(loc::gettext("audio"));
|
|
option(loc::gettext("game pad"));
|
|
option(loc::gettext("accessibility"));
|
|
option(loc::gettext("language"), !translator_cutscene_test);
|
|
option(loc::gettext("return"));
|
|
menuyoff = 0;
|
|
maxspacing = 15;
|
|
break;
|
|
case Menu::speedrunneroptions:
|
|
option(loc::gettext("glitchrunner mode"));
|
|
option(loc::gettext("input delay"));
|
|
option(loc::gettext("interact button"));
|
|
option(loc::gettext("fake load screen"));
|
|
option(loc::gettext("toggle in-game timer"));
|
|
option(loc::gettext("english sprites"));
|
|
option(loc::gettext("return"));
|
|
menuyoff = 0;
|
|
maxspacing = 15;
|
|
break;
|
|
case Menu::setglitchrunner:
|
|
{
|
|
int i;
|
|
|
|
option(loc::gettext("none"));
|
|
|
|
for (i = 1; i < GlitchrunnerNumVersions; ++i)
|
|
{
|
|
option(loc::gettext(GlitchrunnerMode_enum_to_string((enum GlitchrunnerMode) i)));
|
|
}
|
|
break;
|
|
}
|
|
case Menu::advancedoptions:
|
|
option(loc::gettext("unfocus pause"));
|
|
option(loc::gettext("unfocus audio pause"));
|
|
option(loc::gettext("room name background"));
|
|
option(loc::gettext("checkpoint saving"));
|
|
option(loc::gettext("return"));
|
|
menuyoff = 0;
|
|
maxspacing = 15;
|
|
break;
|
|
case Menu::audiooptions:
|
|
option(loc::gettext("music volume"));
|
|
option(loc::gettext("sound volume"));
|
|
if (music.mmmmmm)
|
|
{
|
|
option(loc::gettext("soundtrack"));
|
|
}
|
|
option(loc::gettext("return"));
|
|
menuyoff = 0;
|
|
maxspacing = 15;
|
|
break;
|
|
case Menu::accessibility:
|
|
#if !defined(MAKEANDPLAY)
|
|
option(loc::gettext("unlock play modes"));
|
|
#endif
|
|
option(loc::gettext("invincibility"), !ingame_titlemode || !incompetitive());
|
|
option(loc::gettext("slowdown"), !ingame_titlemode || !incompetitive());
|
|
option(loc::gettext("animated backgrounds"));
|
|
option(loc::gettext("screen effects"));
|
|
option(loc::gettext("text outline"));
|
|
option(loc::gettext("return"));
|
|
menuyoff = 0;
|
|
maxspacing = 15;
|
|
break;
|
|
case Menu::controller:
|
|
option(loc::gettext("analog stick sensitivity"));
|
|
option(loc::gettext("bind flip"));
|
|
option(loc::gettext("bind enter"));
|
|
option(loc::gettext("bind menu"));
|
|
option(loc::gettext("bind restart"));
|
|
option(loc::gettext("bind interact"), separate_interact);
|
|
option(loc::gettext("return"));
|
|
menuyoff = 0;
|
|
maxspacing = 10;
|
|
break;
|
|
case Menu::language:
|
|
if (loc::languagelist.empty())
|
|
{
|
|
option(loc::gettext("ok"));
|
|
menuyoff = -20;
|
|
}
|
|
else
|
|
{
|
|
for (size_t i = 0; i < loc::languagelist.size(); i++)
|
|
{
|
|
if (loc::languagelist[i].nativename.empty())
|
|
{
|
|
option(loc::languagelist[i].code.c_str());
|
|
}
|
|
else
|
|
{
|
|
option(
|
|
loc::languagelist[i].nativename.c_str(),
|
|
true,
|
|
PR_FONT_IDX(loc::languagelist[i].font_idx, loc::languagelist[i].rtl)
|
|
);
|
|
}
|
|
}
|
|
|
|
menuyoff = 70-(menuoptions.size()*10);
|
|
maxspacing = 5;
|
|
}
|
|
break;
|
|
case Menu::translator_main:
|
|
option(loc::gettext("translator options"));
|
|
option(loc::gettext("maintenance"));
|
|
option(loc::gettext("open lang folder"), FILESYSTEM_openDirectoryEnabled());
|
|
option(loc::gettext("return"));
|
|
menuyoff = 0;
|
|
break;
|
|
case Menu::translator_options:
|
|
option(loc::gettext("language statistics"));
|
|
option(loc::gettext("translate room names"));
|
|
option(loc::gettext("explore game"));
|
|
option(loc::gettext("menu test"));
|
|
option(loc::gettext("cutscene test"), loc::lang != "en");
|
|
option(loc::gettext("limits check"));
|
|
option(loc::gettext("return"));
|
|
menuyoff = 0;
|
|
break;
|
|
case Menu::translator_options_limitscheck:
|
|
option(loc::gettext("next page"));
|
|
option(loc::gettext("return"));
|
|
menuyoff = 64;
|
|
break;
|
|
case Menu::translator_options_stats:
|
|
option(loc::gettext("return"));
|
|
menuyoff = 64;
|
|
break;
|
|
case Menu::translator_options_exploregame:
|
|
option(loc::gettext("space station 1"));
|
|
option(loc::gettext("the laboratory"));
|
|
option(loc::gettext("the tower"));
|
|
option(loc::gettext("space station 2"));
|
|
option(loc::gettext("the warp zone"));
|
|
option(loc::gettext("intermission 1"));
|
|
option(loc::gettext("intermission 2"));
|
|
option(loc::gettext("the final level"));
|
|
option(loc::gettext("return"));
|
|
menuyoff = -20;
|
|
break;
|
|
case Menu::translator_options_cutscenetest:
|
|
for (
|
|
size_t i = (cutscenetest_menu_page*14);
|
|
i < (cutscenetest_menu_page*14)+14 && i < loc::testable_script_ids.size();
|
|
i++
|
|
)
|
|
{
|
|
option(loc::testable_script_ids[i].c_str());
|
|
}
|
|
if((cutscenetest_menu_page*14)+14 < loc::testable_script_ids.size())
|
|
{
|
|
option(loc::gettext("next page"));
|
|
}
|
|
else
|
|
{
|
|
option(loc::gettext("first page"));
|
|
}
|
|
if (cutscenetest_menu_page == 0)
|
|
{
|
|
option(loc::gettext("last page"));
|
|
}
|
|
else
|
|
{
|
|
option(loc::gettext("previous page"));
|
|
}
|
|
option(loc::gettext("from clipboard"));
|
|
option(loc::gettext("return"));
|
|
|
|
menuxoff = 20;
|
|
menuyoff = 55-(menuoptions.size()*10);
|
|
menuspacing = 5;
|
|
return; // skip automatic centering, will turn out bad with scripts list
|
|
case Menu::translator_maintenance:
|
|
option(loc::gettext("sync language files"));
|
|
option(loc::gettext("global statistics"), false);
|
|
option(loc::gettext("global limits check"));
|
|
option(loc::gettext("return"));
|
|
menuyoff = 0;
|
|
break;
|
|
case Menu::translator_maintenance_sync:
|
|
option(loc::gettext("sync"));
|
|
option(loc::gettext("return"));
|
|
menuyoff = 64;
|
|
break;
|
|
case Menu::translator_error_setlangwritedir:
|
|
option(loc::gettext("ok"));
|
|
menuyoff = 10;
|
|
break;
|
|
case Menu::cleardatamenu:
|
|
case Menu::clearcustomdatamenu:
|
|
option(loc::gettext("no! don't delete"));
|
|
option(loc::gettext("yes, delete everything"));
|
|
menuyoff = 64;
|
|
break;
|
|
case Menu::setinvincibility:
|
|
option(loc::gettext("no, return to options"));
|
|
option(loc::gettext("yes, enable"));
|
|
menuyoff = 64;
|
|
break;
|
|
case Menu::setslowdown:
|
|
option(loc::gettext("normal speed"));
|
|
option(loc::gettext("80% speed"));
|
|
option(loc::gettext("60% speed"));
|
|
option(loc::gettext("40% speed"));
|
|
menuyoff = 16;
|
|
break;
|
|
case Menu::unlockmenu:
|
|
option(loc::gettext("unlock time trials"));
|
|
option(loc::gettext("unlock intermissions"), !unlock[Unlock_INTERMISSION_REPLAYS]);
|
|
option(loc::gettext("unlock no death mode"), !unlock[Unlock_NODEATHMODE]);
|
|
option(loc::gettext("unlock flip mode"), !unlock[Unlock_FLIPMODE]);
|
|
option(loc::gettext("unlock ship jukebox"), (stat_trinkets<20));
|
|
option(loc::gettext("unlock secret lab"), !unlock[Unlock_SECRETLAB]);
|
|
option(loc::gettext("return"));
|
|
menuyoff = -20;
|
|
break;
|
|
case Menu::credits:
|
|
option(loc::gettext("next page"));
|
|
option(loc::gettext("last page"));
|
|
option(loc::gettext("return"));
|
|
menuyoff = 64;
|
|
break;
|
|
case Menu::credits2:
|
|
case Menu::credits25:
|
|
case Menu::credits3:
|
|
case Menu::credits4:
|
|
case Menu::credits5:
|
|
case Menu::credits_localisations_implementation:
|
|
case Menu::credits_localisations_translations:
|
|
option(loc::gettext("next page"));
|
|
option(loc::gettext("previous page"));
|
|
option(loc::gettext("return"));
|
|
menuyoff = 64;
|
|
break;
|
|
case Menu::credits6:
|
|
option(loc::gettext("first page"));
|
|
option(loc::gettext("previous page"));
|
|
option(loc::gettext("return"));
|
|
menuyoff = 64;
|
|
break;
|
|
case Menu::play:
|
|
{
|
|
//Ok, here's where the unlock stuff comes into it:
|
|
//First up, time trials:
|
|
int temp = 0;
|
|
if (unlock[Unlock_SPACESTATION1_COMPLETE]
|
|
&& stat_trinkets >= 3
|
|
&& !unlocknotify[Unlock_TIMETRIAL_SPACESTATION1])
|
|
{
|
|
temp++;
|
|
}
|
|
if (unlock[Unlock_LABORATORY_COMPLETE]
|
|
&& stat_trinkets >= 6
|
|
&& !unlocknotify[Unlock_TIMETRIAL_LABORATORY])
|
|
{
|
|
temp++;
|
|
}
|
|
if (unlock[Unlock_TOWER_COMPLETE]
|
|
&& stat_trinkets >= 9
|
|
&& !unlocknotify[Unlock_TIMETRIAL_TOWER])
|
|
{
|
|
temp++;
|
|
}
|
|
if (unlock[Unlock_SPACESTATION2_COMPLETE]
|
|
&& stat_trinkets >= 12
|
|
&& !unlocknotify[Unlock_TIMETRIAL_SPACESTATION2])
|
|
{
|
|
temp++;
|
|
}
|
|
if (unlock[Unlock_WARPZONE_COMPLETE]
|
|
&& stat_trinkets >= 15
|
|
&& !unlocknotify[Unlock_TIMETRIAL_WARPZONE])
|
|
{
|
|
temp++;
|
|
}
|
|
if (unlock[UnlockTrophy_GAME_COMPLETE]
|
|
&& stat_trinkets >= 18
|
|
&& !unlocknotify[Unlock_TIMETRIAL_FINALLEVEL])
|
|
{
|
|
temp++;
|
|
}
|
|
if (temp > 0)
|
|
{
|
|
//you've unlocked a time trial!
|
|
if (unlock[Unlock_SPACESTATION1_COMPLETE] && stat_trinkets >= 3)
|
|
{
|
|
unlocknotify[Unlock_TIMETRIAL_SPACESTATION1] = true;
|
|
unlock[Unlock_TIMETRIAL_SPACESTATION1] = true;
|
|
}
|
|
if (unlock[Unlock_LABORATORY_COMPLETE] && stat_trinkets >= 6)
|
|
{
|
|
unlocknotify[Unlock_TIMETRIAL_LABORATORY] = true;
|
|
unlock[Unlock_TIMETRIAL_LABORATORY] = true;
|
|
}
|
|
if (unlock[Unlock_TOWER_COMPLETE] && stat_trinkets >= 9)
|
|
{
|
|
unlocknotify[Unlock_TIMETRIAL_TOWER] = true;
|
|
unlock[Unlock_TIMETRIAL_TOWER] = true;
|
|
}
|
|
if (unlock[Unlock_SPACESTATION2_COMPLETE] && stat_trinkets >= 12)
|
|
{
|
|
unlocknotify[Unlock_TIMETRIAL_SPACESTATION2] = true;
|
|
unlock[Unlock_TIMETRIAL_SPACESTATION2] = true;
|
|
}
|
|
if (unlock[Unlock_WARPZONE_COMPLETE] && stat_trinkets >= 15)
|
|
{
|
|
unlocknotify[Unlock_TIMETRIAL_WARPZONE] = true;
|
|
unlock[Unlock_TIMETRIAL_WARPZONE] = true;
|
|
}
|
|
if (unlock[UnlockTrophy_GAME_COMPLETE] && stat_trinkets >= 18)
|
|
{
|
|
unlocknotify[Unlock_TIMETRIAL_FINALLEVEL] = true;
|
|
unlock[Unlock_TIMETRIAL_FINALLEVEL] = true;
|
|
}
|
|
|
|
if (temp == 1)
|
|
{
|
|
createmenu(Menu::unlocktimetrial, true);
|
|
savestatsandsettings();
|
|
}
|
|
else if (temp > 1)
|
|
{
|
|
createmenu(Menu::unlocktimetrials, true);
|
|
savestatsandsettings();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Alright, we haven't unlocked any time trials. How about no death mode?
|
|
if (can_unlock_ndm())
|
|
{
|
|
unlock_ndm();
|
|
}
|
|
//Alright then! Flip mode?
|
|
else if (unlock[UnlockTrophy_GAME_COMPLETE]
|
|
&& !unlocknotify[Unlock_FLIPMODE])
|
|
{
|
|
unlock[Unlock_FLIPMODE] = true;
|
|
unlocknotify[Unlock_FLIPMODE] = true;
|
|
createmenu(Menu::unlockflipmode, true);
|
|
savestatsandsettings();
|
|
}
|
|
//What about the intermission levels?
|
|
else if (unlock[Unlock_INTERMISSION2_COMPLETE]
|
|
&& !unlocknotify[Unlock_INTERMISSION_REPLAYS])
|
|
{
|
|
unlock[Unlock_INTERMISSION_REPLAYS] = true;
|
|
unlocknotify[Unlock_INTERMISSION_REPLAYS] = true;
|
|
createmenu(Menu::unlockintermission, true);
|
|
savestatsandsettings();
|
|
}
|
|
else
|
|
{
|
|
if (save_exists())
|
|
{
|
|
option(loc::gettext("continue"));
|
|
}
|
|
else
|
|
{
|
|
option(loc::gettext("new game"));
|
|
}
|
|
//ok, secret lab! no notification, but test:
|
|
if (unlock[Unlock_SECRETLAB])
|
|
{
|
|
option(loc::gettext("secret lab"));
|
|
}
|
|
option(loc::gettext("play modes"));
|
|
if (save_exists())
|
|
{
|
|
option(loc::gettext("new game"));
|
|
}
|
|
option(loc::gettext("return"));
|
|
if (unlock[Unlock_SECRETLAB])
|
|
{
|
|
menuyoff = -30;
|
|
}
|
|
else
|
|
{
|
|
menuyoff = -40;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case Menu::unlocktimetrial:
|
|
case Menu::unlocktimetrials:
|
|
case Menu::unlocknodeathmode:
|
|
case Menu::unlockintermission:
|
|
case Menu::unlockflipmode:
|
|
option(loc::gettext("proceed"));
|
|
menuyoff = 70;
|
|
break;
|
|
case Menu::newgamewarning:
|
|
option(loc::gettext("start new game"));
|
|
option(loc::gettext("return"));
|
|
menuyoff = 64;
|
|
break;
|
|
case Menu::playmodes:
|
|
option(loc::gettext("time trials"), !nocompetitive_unless_translator());
|
|
option(loc::gettext("intermissions"), unlock[Unlock_INTERMISSION_REPLAYS]);
|
|
option(loc::gettext("no death mode"), unlock[Unlock_NODEATHMODE] && !nocompetitive());
|
|
option(loc::gettext("flip mode"), unlock[Unlock_FLIPMODE]);
|
|
option(loc::gettext("return"));
|
|
menuyoff = 8;
|
|
maxspacing = 20;
|
|
break;
|
|
case Menu::intermissionmenu:
|
|
option(loc::gettext("play intermission 1"));
|
|
option(loc::gettext("play intermission 2"));
|
|
option(loc::gettext("return"));
|
|
menuyoff = -35;
|
|
break;
|
|
case Menu::playint1:
|
|
start_translator_exploring = false;
|
|
option(loc::gettext_case("Vitellary", 1));
|
|
option(loc::gettext_case("Vermilion", 1));
|
|
option(loc::gettext_case("Verdigris", 1));
|
|
option(loc::gettext_case("Victoria", 1));
|
|
option(loc::gettext("return"));
|
|
menuyoff = 10;
|
|
break;
|
|
case Menu::playint2:
|
|
start_translator_exploring = false;
|
|
option(loc::gettext_case("Vitellary", 1));
|
|
option(loc::gettext_case("Vermilion", 1));
|
|
option(loc::gettext_case("Verdigris", 1));
|
|
option(loc::gettext_case("Victoria", 1));
|
|
option(loc::gettext("return"));
|
|
menuyoff = 10;
|
|
break;
|
|
case Menu::continuemenu:
|
|
map.settowercolour(3);
|
|
option(loc::gettext("continue from teleporter"));
|
|
option(loc::gettext("continue from quicksave"));
|
|
option(loc::gettext("return"));
|
|
menuyoff = 20;
|
|
break;
|
|
case Menu::startnodeathmode:
|
|
option(loc::gettext("disable cutscenes"));
|
|
option(loc::gettext("enable cutscenes"));
|
|
option(loc::gettext("return"));
|
|
menuyoff = 40;
|
|
break;
|
|
case Menu::gameover:
|
|
menucountdown = 120;
|
|
menudest=Menu::gameover2;
|
|
break;
|
|
case Menu::gameover2:
|
|
option(loc::gettext("return to play menu"));
|
|
menuyoff = 80;
|
|
break;
|
|
case Menu::unlockmenutrials:
|
|
option(loc::gettext("space station 1"), !unlock[Unlock_TIMETRIAL_SPACESTATION1]);
|
|
option(loc::gettext("the laboratory"), !unlock[Unlock_TIMETRIAL_LABORATORY]);
|
|
option(loc::gettext("the tower"), !unlock[Unlock_TIMETRIAL_TOWER]);
|
|
option(loc::gettext("space station 2"), !unlock[Unlock_TIMETRIAL_SPACESTATION2]);
|
|
option(loc::gettext("the warp zone"), !unlock[Unlock_TIMETRIAL_WARPZONE]);
|
|
option(loc::gettext("the final level"), !unlock[Unlock_TIMETRIAL_FINALLEVEL]);
|
|
|
|
option(loc::gettext("return"));
|
|
menuyoff = 0;
|
|
break;
|
|
case Menu::timetrials:
|
|
option(loc::gettext(unlock[Unlock_TIMETRIAL_SPACESTATION1] ? "space station 1" : "???"),
|
|
unlock[Unlock_TIMETRIAL_SPACESTATION1]);
|
|
option(loc::gettext(unlock[Unlock_TIMETRIAL_LABORATORY] ? "the laboratory" : "???"),
|
|
unlock[Unlock_TIMETRIAL_LABORATORY]);
|
|
option(loc::gettext(unlock[Unlock_TIMETRIAL_TOWER] ? "the tower" : "???"),
|
|
unlock[Unlock_TIMETRIAL_TOWER]);
|
|
option(loc::gettext(unlock[Unlock_TIMETRIAL_SPACESTATION2] ? "space station 2" : "???"),
|
|
unlock[Unlock_TIMETRIAL_SPACESTATION2]);
|
|
option(loc::gettext(unlock[Unlock_TIMETRIAL_WARPZONE] ? "the warp zone" : "???"),
|
|
unlock[Unlock_TIMETRIAL_WARPZONE]);
|
|
option(loc::gettext(unlock[Unlock_TIMETRIAL_FINALLEVEL] ? "the final level" : "???"),
|
|
unlock[Unlock_TIMETRIAL_FINALLEVEL]);
|
|
|
|
option(loc::gettext("return"));
|
|
menuyoff = 0;
|
|
maxspacing = 15;
|
|
break;
|
|
case Menu::nodeathmodecomplete:
|
|
menucountdown = 90;
|
|
menudest = Menu::nodeathmodecomplete2;
|
|
break;
|
|
case Menu::nodeathmodecomplete2:
|
|
option(loc::gettext("return to play menu"));
|
|
menuyoff = 70;
|
|
break;
|
|
case Menu::timetrialcomplete:
|
|
menucountdown = 90;
|
|
menudest=Menu::timetrialcomplete2;
|
|
break;
|
|
case Menu::timetrialcomplete2:
|
|
menucountdown = 60;
|
|
menudest=Menu::timetrialcomplete3;
|
|
break;
|
|
case Menu::timetrialcomplete3:
|
|
option(loc::gettext("return to play menu"));
|
|
option(loc::gettext("try again"));
|
|
menuyoff = 70;
|
|
break;
|
|
case Menu::gamecompletecontinue:
|
|
option(loc::gettext("return to play menu"));
|
|
menuyoff = 70;
|
|
break;
|
|
case Menu::errorsavingsettings:
|
|
option(loc::gettext("ok"));
|
|
option(loc::gettext("silence"));
|
|
menuyoff = 10;
|
|
break;
|
|
case Menu::errorloadinglevel:
|
|
case Menu::warninglevellist:
|
|
option(loc::gettext("ok"));
|
|
menuyoff = 50;
|
|
break;
|
|
}
|
|
|
|
// Automatically center the menu. We must check the width of the menu with the initial horizontal spacing.
|
|
// If it's too wide, reduce the horizontal spacing by 5 and retry.
|
|
// Try to limit the menu width to 272 pixels: 320 minus 16*2 for square brackets, minus 8*2 padding.
|
|
// The square brackets fall outside the menu width (i.e. selected menu options are printed 16 pixels to the left)
|
|
bool done_once = false;
|
|
int menuwidth = 0;
|
|
for (; !done_once || (menuwidth > 272 && menuspacing > 0); maxspacing -= 5)
|
|
{
|
|
done_once = true;
|
|
menuspacing = maxspacing;
|
|
menuwidth = 0;
|
|
for (size_t i = 0; i < menuoptions.size(); i++)
|
|
{
|
|
int width = i*menuspacing + font::len(menuoptions[i].print_flags, menuoptions[i].text);
|
|
if (width > menuwidth)
|
|
menuwidth = width;
|
|
}
|
|
}
|
|
menuxoff = (320-menuwidth)/2;
|
|
}
|
|
|
|
bool Game::can_unlock_ndm(void)
|
|
{
|
|
int temp = 0;
|
|
if (bestrank[TimeTrial_SPACESTATION1] >= 2) temp++;
|
|
if (bestrank[TimeTrial_LABORATORY] >= 2) temp++;
|
|
if (bestrank[TimeTrial_TOWER] >= 2) temp++;
|
|
if (bestrank[TimeTrial_SPACESTATION2] >= 2) temp++;
|
|
if (bestrank[TimeTrial_WARPZONE] >= 2) temp++;
|
|
if (bestrank[TimeTrial_FINALLEVEL] >= 2) temp++;
|
|
return temp >= 4 && !unlocknotify[Unlock_NODEATHMODE];
|
|
}
|
|
|
|
void Game::unlock_ndm(void)
|
|
{
|
|
unlocknotify[Unlock_NODEATHMODE] = true;
|
|
unlock[Unlock_NODEATHMODE] = true;
|
|
createmenu(Menu::unlocknodeathmode, true);
|
|
savestatsandsettings();
|
|
}
|
|
|
|
void Game::deletequick(void)
|
|
{
|
|
if (inspecial() || map.custommode)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!FILESYSTEM_delete("saves/qsave.vvv"))
|
|
{
|
|
vlog_error("Error deleting saves/qsave.vvv");
|
|
}
|
|
else
|
|
{
|
|
SDL_zero(last_quicksave);
|
|
}
|
|
}
|
|
|
|
void Game::deletetele(void)
|
|
{
|
|
if (inspecial() || map.custommode)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!FILESYSTEM_delete("saves/tsave.vvv"))
|
|
{
|
|
vlog_error("Error deleting saves/tsave.vvv");
|
|
}
|
|
else
|
|
{
|
|
SDL_zero(last_telesave);
|
|
}
|
|
}
|
|
|
|
void Game::customdeletequick(const std::string& file)
|
|
{
|
|
const std::string path = "saves/" + file.substr(7) + ".vvv";
|
|
|
|
if (!FILESYSTEM_delete(path.c_str()))
|
|
{
|
|
vlog_error("Error deleting %s", path.c_str());
|
|
}
|
|
}
|
|
|
|
void Game::swnpenalty(void)
|
|
{
|
|
//set the SWN clock back to the closest 5 second interval
|
|
if (swntimer <= 150)
|
|
{
|
|
swntimer += 8;
|
|
if (swntimer > 150) swntimer = 150;
|
|
}
|
|
else if (swntimer <= 300)
|
|
{
|
|
swntimer += 8;
|
|
if (swntimer > 300) swntimer = 300;
|
|
}
|
|
else if (swntimer <= 450)
|
|
{
|
|
swntimer += 8;
|
|
if (swntimer > 450) swntimer = 450;
|
|
}
|
|
else if (swntimer <= 600)
|
|
{
|
|
swntimer += 8;
|
|
if (swntimer > 600) swntimer = 600;
|
|
}
|
|
else if (swntimer <= 750)
|
|
{
|
|
swntimer += 8;
|
|
if (swntimer > 750) swntimer = 750;
|
|
}
|
|
else if (swntimer <= 900)
|
|
{
|
|
swntimer += 8;
|
|
if (swntimer > 900) swntimer = 900;
|
|
}
|
|
else if (swntimer <= 1050)
|
|
{
|
|
swntimer += 8;
|
|
if (swntimer > 1050) swntimer = 1050;
|
|
}
|
|
else if (swntimer <= 1200)
|
|
{
|
|
swntimer += 8;
|
|
if (swntimer > 1200) swntimer = 1200;
|
|
}
|
|
else if (swntimer <= 1350)
|
|
{
|
|
swntimer += 8;
|
|
if (swntimer > 1350) swntimer = 1350;
|
|
}
|
|
else if (swntimer <= 1500)
|
|
{
|
|
swntimer += 8;
|
|
if (swntimer > 1500) swntimer = 1500;
|
|
}
|
|
else if (swntimer <= 1650)
|
|
{
|
|
swntimer += 8;
|
|
if (swntimer > 1650) swntimer = 1650;
|
|
}
|
|
else if (swntimer <= 1800)
|
|
{
|
|
swntimer += 8;
|
|
if (swntimer > 1800) swntimer = 1800;
|
|
}
|
|
else if (swntimer <= 2100)
|
|
{
|
|
swntimer += 8;
|
|
if (swntimer > 2100) swntimer = 2100;
|
|
}
|
|
else if (swntimer <= 2400)
|
|
{
|
|
swntimer += 8;
|
|
if (swntimer > 2400) swntimer = 2400;
|
|
}
|
|
}
|
|
|
|
int Game::crewrescued(void)
|
|
{
|
|
int temp = 0;
|
|
for (size_t i = 0; i < SDL_arraysize(crewstats); i++)
|
|
{
|
|
if (crewstats[i])
|
|
{
|
|
temp++;
|
|
}
|
|
}
|
|
return temp;
|
|
}
|
|
|
|
void Game::resetgameclock(void)
|
|
{
|
|
frames = 0;
|
|
seconds = 0;
|
|
minutes = 0;
|
|
hours = 0;
|
|
}
|
|
|
|
int Game::trinkets(void)
|
|
{
|
|
int temp = 0;
|
|
for (size_t i = 0; i < SDL_arraysize(obj.collect); i++)
|
|
{
|
|
if (obj.collect[i])
|
|
{
|
|
temp++;
|
|
}
|
|
}
|
|
return temp;
|
|
}
|
|
|
|
int Game::crewmates(void)
|
|
{
|
|
int temp = 0;
|
|
for (size_t i = 0; i < SDL_arraysize(obj.customcollect); i++)
|
|
{
|
|
if (obj.customcollect[i])
|
|
{
|
|
temp++;
|
|
}
|
|
}
|
|
return temp;
|
|
}
|
|
|
|
bool Game::anything_unlocked(void)
|
|
{
|
|
for (size_t i = 0; i < SDL_arraysize(unlock); i++)
|
|
{
|
|
if (unlock[i] &&
|
|
(i == 8 // Secret Lab
|
|
|| (i >= 9 && i <= 14) // any Time Trial
|
|
|| i == 16 // Intermission replays
|
|
|| i == 17 // No Death Mode
|
|
|| i == 18)) // Flip Mode
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool Game::save_exists(void)
|
|
{
|
|
return last_telesave.exists || last_quicksave.exists;
|
|
}
|
|
|
|
static void hardreset(void)
|
|
{
|
|
script.hardreset();
|
|
}
|
|
|
|
static void returntoeditor_callback(void)
|
|
{
|
|
extern Game game;
|
|
game.returntoeditor();
|
|
ed.show_note(loc::gettext("Level quits to menu"));
|
|
}
|
|
|
|
void Game::quittomenu(void)
|
|
{
|
|
if (gamestate != EDITORMODE && map.custommode && !map.custommodeforreal)
|
|
{
|
|
/* We are playtesting! Go back to the editor
|
|
* instead of losing unsaved changes. */
|
|
/* This needs to be deferred, otherwise some state would persist. */
|
|
DEFER_CALLBACK(returntoeditor_callback);
|
|
return;
|
|
}
|
|
|
|
gamestate = TITLEMODE;
|
|
graphics.fademode = FADE_START_FADEIN;
|
|
FILESYSTEM_unmountAssets();
|
|
loc::unloadtext_custom();
|
|
font::unload_custom();
|
|
cliplaytest = false;
|
|
graphics.titlebg.tdrawback = true;
|
|
graphics.flipmode = false;
|
|
//Don't be stuck on the summary screen,
|
|
//or "who do you want to play the level with?"
|
|
//or "do you want cutscenes?"
|
|
//or the confirm-load-quicksave menu
|
|
if (translator_cutscene_test)
|
|
{
|
|
returntomenu(Menu::translator_options_cutscenetest);
|
|
}
|
|
else if (translator_exploring)
|
|
{
|
|
returntomenu(Menu::translator_options_exploregame);
|
|
}
|
|
else if (intimetrial)
|
|
{
|
|
returntomenu(Menu::timetrials);
|
|
}
|
|
else if (inintermission)
|
|
{
|
|
returntomenu(Menu::intermissionmenu);
|
|
}
|
|
else if (nodeathmode)
|
|
{
|
|
returntomenu(Menu::playmodes);
|
|
}
|
|
else if (map.custommode)
|
|
{
|
|
if (map.custommodeforreal)
|
|
{
|
|
returntomenu(Menu::levellist);
|
|
}
|
|
else
|
|
{
|
|
//Returning from editor
|
|
editor_disabled = !BUTTONGLYPHS_keyboard_is_available();
|
|
returntomenu(Menu::playerworlds);
|
|
}
|
|
}
|
|
else if (save_exists() || anything_unlocked())
|
|
{
|
|
returntomenu(Menu::play);
|
|
if (!insecretlab)
|
|
{
|
|
//Select "continue"
|
|
currentmenuoption = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
createmenu(Menu::mainmenu);
|
|
}
|
|
/* We might not be at the end of the frame yet.
|
|
* If we hardreset() now, some state might still persist. */
|
|
DEFER_CALLBACK(hardreset);
|
|
}
|
|
|
|
void Game::returntolab(void)
|
|
{
|
|
gamestate = GAMEMODE;
|
|
graphics.fademode = FADE_START_FADEIN;
|
|
map.gotoroom(119, 107);
|
|
int player = obj.getplayer();
|
|
if (INBOUNDS_VEC(player, obj.entities))
|
|
{
|
|
obj.entities[player].xp = 132;
|
|
obj.entities[player].yp = 137;
|
|
}
|
|
gravitycontrol = 0;
|
|
|
|
savepoint = 0;
|
|
saverx = 119;
|
|
savery = 107;
|
|
savex = 132;
|
|
savey = 137;
|
|
savegc = 0;
|
|
if (INBOUNDS_VEC(player, obj.entities))
|
|
{
|
|
savedir = obj.entities[player].dir;
|
|
}
|
|
|
|
music.play(Music_PIPEDREAM);
|
|
}
|
|
|
|
static void resetbg(void)
|
|
{
|
|
graphics.backgrounddrawn = false;
|
|
}
|
|
|
|
void Game::returntoeditor(void)
|
|
{
|
|
gamestate = EDITORMODE;
|
|
|
|
graphics.textboxes.clear();
|
|
hascontrol = true;
|
|
advancetext = false;
|
|
completestop = false;
|
|
setstate(0);
|
|
graphics.showcutscenebars = false;
|
|
graphics.fademode = FADE_NONE;
|
|
|
|
ed.keydelay = 6;
|
|
ed.settingskey = true;
|
|
ed.old_note_timer = 0;
|
|
ed.note_timer = 0;
|
|
ed.roomnamehide = 0;
|
|
|
|
// Might've been changed in a script
|
|
font::set_level_font(cl.level_font_name.c_str());
|
|
|
|
DEFER_CALLBACK(resetbg);
|
|
music.fadeout();
|
|
//If warpdir() is used during playtesting, we need to set it back after!
|
|
for (int j = 0; j < cl.maxheight; j++)
|
|
{
|
|
for (int i = 0; i < cl.maxwidth; i++)
|
|
{
|
|
cl.roomproperties[i+(j*cl.maxwidth)].warpdir=ed.kludgewarpdir[i+(j*cl.maxwidth)];
|
|
}
|
|
}
|
|
graphics.titlebg.scrolldir = 0;
|
|
graphics.backgrounddrawn = false;
|
|
graphics.foregrounddrawn = false;
|
|
}
|
|
|
|
static void returntoingametemp(void)
|
|
{
|
|
extern Game game;
|
|
game.returntomenu(game.kludge_ingametemp);
|
|
}
|
|
|
|
static void returntoedsettings(void)
|
|
{
|
|
extern Game game;
|
|
game.returntomenu(Menu::ed_settings);
|
|
}
|
|
|
|
static void nextbgcolor(void)
|
|
{
|
|
map.nexttowercolour();
|
|
}
|
|
|
|
static void setfademode(void)
|
|
{
|
|
graphics.fademode = graphics.ingame_fademode;
|
|
}
|
|
|
|
static void setflipmode(void)
|
|
{
|
|
graphics.flipmode = graphics.setflipmode;
|
|
}
|
|
|
|
void Game::returntoingame(void)
|
|
{
|
|
ingame_titlemode = false;
|
|
mapheld = true;
|
|
|
|
if (ingame_editormode)
|
|
{
|
|
ingame_editormode = false;
|
|
DEFER_CALLBACK(returntoedsettings);
|
|
gamestate = EDITORMODE;
|
|
ed.settingskey = true;
|
|
}
|
|
else
|
|
{
|
|
DEFER_CALLBACK(returntoingametemp);
|
|
gamestate = MAPMODE;
|
|
DEFER_CALLBACK(setflipmode);
|
|
DEFER_CALLBACK(setfademode);
|
|
if (!map.custommode && !graphics.setflipmode)
|
|
{
|
|
obj.flags[73] = true;
|
|
}
|
|
}
|
|
DEFER_CALLBACK(nextbgcolor);
|
|
|
|
if (nocompetitive())
|
|
{
|
|
invalidate_ndm_trophy();
|
|
}
|
|
}
|
|
|
|
void Game::unlockAchievement(const char* name)
|
|
{
|
|
#ifdef MAKEANDPLAY
|
|
UNUSED(name);
|
|
#else
|
|
if (map.custommode)
|
|
{
|
|
return;
|
|
}
|
|
|
|
vlog_debug("Achievement \"%s\" unlocked.", name);
|
|
NETWORK_unlockAchievement(name);
|
|
#endif
|
|
}
|
|
|
|
void Game::mapmenuchange(const enum GameGamestate newgamestate, const bool user_initiated)
|
|
{
|
|
if (user_initiated && graphics.resumegamemode)
|
|
{
|
|
return;
|
|
}
|
|
|
|
prevgamestate = gamestate;
|
|
gamestate = newgamestate;
|
|
graphics.resumegamemode = false;
|
|
mapheld = true;
|
|
gameScreen.recacheTextures();
|
|
|
|
if (prevgamestate == GAMEMODE)
|
|
{
|
|
graphics.menuoffset = 240;
|
|
}
|
|
else
|
|
{
|
|
graphics.menuoffset = 0;
|
|
}
|
|
graphics.oldmenuoffset = graphics.menuoffset;
|
|
}
|
|
|
|
void Game::copyndmresults(void)
|
|
{
|
|
ndmresultcrewrescued = crewrescued();
|
|
ndmresulttrinkets = trinkets();
|
|
ndmresulthardestroom = hardestroom;
|
|
ndmresulthardestroom_x = hardestroom_x;
|
|
ndmresulthardestroom_y = hardestroom_y;
|
|
ndmresulthardestroom_specialname = hardestroom_specialname;
|
|
SDL_memcpy(ndmresultcrewstats, crewstats, sizeof(ndmresultcrewstats));
|
|
}
|
|
|
|
void Game::invalidate_ndm_trophy(void)
|
|
{
|
|
if (nodeatheligible)
|
|
{
|
|
vlog_debug("NDM trophy is invalidated!");
|
|
}
|
|
nodeatheligible = false;
|
|
}
|
|
|
|
static inline int get_framerate(const int slowdown, const int deathseq)
|
|
{
|
|
if (deathseq != -1)
|
|
{
|
|
return 34;
|
|
}
|
|
|
|
switch (slowdown)
|
|
{
|
|
case 30:
|
|
return 34;
|
|
case 24:
|
|
return 41;
|
|
case 18:
|
|
return 55;
|
|
case 12:
|
|
return 83;
|
|
}
|
|
|
|
return 34;
|
|
}
|
|
|
|
int Game::get_timestep(void)
|
|
{
|
|
if ((gamestate == GAMEMODE || (gamestate == TELEPORTERMODE && !useteleporter)) &&
|
|
level_debugger::is_active() &&
|
|
!level_debugger::is_pausing() &&
|
|
key.isDown(SDLK_f))
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
switch (gamestate)
|
|
{
|
|
case GAMEMODE:
|
|
return get_framerate(slowdown, deathseq);
|
|
default:
|
|
return 34;
|
|
}
|
|
}
|
|
|
|
bool Game::physics_frozen(void)
|
|
{
|
|
return roomname_translator::is_pausing() || level_debugger::is_pausing();
|
|
}
|
|
|
|
bool Game::incompetitive(void)
|
|
{
|
|
return (
|
|
!map.custommode
|
|
&& swnmode
|
|
&& (swngame == SWN_SUPERGRAVITRON ||
|
|
swngame == SWN_START_SUPERGRAVITRON_STEP_1 ||
|
|
swngame == SWN_START_SUPERGRAVITRON_STEP_2)
|
|
)
|
|
|| intimetrial
|
|
|| nodeathmode;
|
|
}
|
|
|
|
bool Game::nocompetitive(void)
|
|
{
|
|
return slowdown < 30 || map.invincibility;
|
|
}
|
|
|
|
bool Game::nocompetitive_unless_translator(void)
|
|
{
|
|
return slowdown < 30 || (map.invincibility && !roomname_translator::enabled);
|
|
}
|
|
|
|
void Game::sabotage_time_trial(void)
|
|
{
|
|
timetrialcheater = true;
|
|
hours++;
|
|
deathcounts += 100;
|
|
timetrialparlost = true;
|
|
}
|
|
|
|
bool Game::isingamecompletescreen(void)
|
|
{
|
|
return (state >= 3501 && state <= 3518) || (state >= 3520 && state <= 3522);
|
|
}
|