2020-09-28 04:15:06 +02:00
|
|
|
#define SCRIPT_DEFINITION
|
2020-01-01 21:29:24 +01:00
|
|
|
#include "Script.h"
|
|
|
|
|
2021-02-16 03:49:24 +01:00
|
|
|
#include <limits.h>
|
2021-08-22 04:51:19 +02:00
|
|
|
#include <SDL_timer.h>
|
2021-02-16 03:49:24 +01:00
|
|
|
|
2021-02-20 08:19:09 +01:00
|
|
|
#include "CustomLevels.h"
|
2021-02-21 00:40:11 +01:00
|
|
|
#include "Editor.h"
|
2020-01-01 21:29:24 +01:00
|
|
|
#include "Entity.h"
|
2020-07-19 21:05:41 +02:00
|
|
|
#include "Enums.h"
|
2021-02-16 03:53:17 +01:00
|
|
|
#include "Exit.h"
|
Split glitchrunner mode into multiple versions
Previously, turning glitchrunner mode on essentially locked you to
emulating 2.0, and turning it off just meant normal 2.3 behavior. But
what if you wanted 2.2 behavior instead? Well, that's what I had to ask
when a TAS of mine would desync in 2.3 because of the two-frame delay
fix (glitchrunner off), but would also desync because of 2.0 warp lines
(glitchrunner on).
What I've done is made it so there are three states to glitchrunner mode
now: 2.0 (previously just the "on" state), 2.2 (previously a state you
couldn't use), and "off". Furthermore, I made it an enum, so in case
future versions of the game patch out more glitches, we can add them to
the enum (and the only other thing we have to update is a lookup table
in GlitchrunnerMode.c). Also, 2.2 glitches exist in 2.0, so you'll want
to use GlitchrunnerMode_less_than_or_equal() to check glitchrunner
version.
2021-08-05 02:09:49 +02:00
|
|
|
#include "GlitchrunnerMode.h"
|
2020-07-19 21:43:29 +02:00
|
|
|
#include "Graphics.h"
|
2020-01-01 21:29:24 +01:00
|
|
|
#include "KeyPoll.h"
|
|
|
|
#include "Map.h"
|
2020-07-19 21:43:29 +02:00
|
|
|
#include "Music.h"
|
2020-07-19 21:05:41 +02:00
|
|
|
#include "UtilityClass.h"
|
2021-02-24 00:21:29 +01:00
|
|
|
#include "Vlogging.h"
|
2021-08-22 04:51:19 +02:00
|
|
|
#include "Xoshiro.h"
|
2020-01-01 21:29:24 +01:00
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
scriptclass::scriptclass(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
position = 0;
|
|
|
|
scriptdelay = 0;
|
|
|
|
running = false;
|
|
|
|
|
|
|
|
b = 0;
|
|
|
|
g = 0;
|
|
|
|
i = 0;
|
|
|
|
j = 0;
|
|
|
|
k = 0;
|
|
|
|
loopcount = 0;
|
|
|
|
looppoint = 0;
|
|
|
|
r = 0;
|
|
|
|
textx = 0;
|
|
|
|
texty = 0;
|
|
|
|
textflipme = false;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void scriptclass::clearcustom(void)
|
2021-02-13 01:35:22 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
customscripts.clear();
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2021-08-12 04:32:36 +02:00
|
|
|
static bool argexists[NUM_SCRIPT_ARGS];
|
2022-02-12 23:56:27 +01:00
|
|
|
static std::string raw_words[NUM_SCRIPT_ARGS];
|
2021-08-12 04:32:36 +02:00
|
|
|
|
2020-07-05 01:01:35 +02:00
|
|
|
void scriptclass::tokenize( const std::string& t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
j = 0;
|
|
|
|
std::string tempword;
|
2022-02-12 23:56:27 +01:00
|
|
|
std::string temprawword;
|
2021-09-07 03:56:39 +02:00
|
|
|
char currentletter;
|
|
|
|
|
|
|
|
SDL_zeroa(argexists);
|
|
|
|
|
|
|
|
for (size_t i = 0; i < t.length(); i++)
|
|
|
|
{
|
|
|
|
currentletter = t[i];
|
|
|
|
if (currentletter == '(' || currentletter == ')' || currentletter == ',')
|
|
|
|
{
|
|
|
|
words[j] = tempword;
|
2022-02-12 23:56:27 +01:00
|
|
|
raw_words[j] = temprawword;
|
2021-09-07 03:56:39 +02:00
|
|
|
argexists[j] = words[j] != "";
|
|
|
|
for (size_t ii = 0; ii < words[j].length(); ii++)
|
|
|
|
{
|
|
|
|
words[j][ii] = SDL_tolower(words[j][ii]);
|
|
|
|
}
|
|
|
|
j++;
|
|
|
|
tempword = "";
|
2022-02-12 23:56:27 +01:00
|
|
|
temprawword = "";
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else if (currentletter == ' ')
|
|
|
|
{
|
2022-02-12 23:56:27 +01:00
|
|
|
/* Ignore spaces unless it's part of a script name. */
|
|
|
|
temprawword += currentletter;
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tempword += currentletter;
|
2022-02-12 23:56:27 +01:00
|
|
|
temprawword += currentletter;
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
if (j >= (int) SDL_arraysize(words))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (j < (int) SDL_arraysize(words))
|
|
|
|
{
|
|
|
|
const bool lastargexists = tempword != "";
|
|
|
|
if (lastargexists)
|
|
|
|
{
|
|
|
|
words[j] = tempword;
|
2022-02-12 23:56:27 +01:00
|
|
|
raw_words[j] = tempword;
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
argexists[j] = lastargexists;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Refactor colors in internal commands
Originally this started as a "deduplicate a bunch of duplicated code in script commands" PR,
but as I was working on that, I discovered there's a lot more that needs to be done than
just deduplication.
Anything which needs a crewmate entity now calls `getcrewmanfromname(name)`, and anything which
just needs the crewmate's color calls `getcolorfromname(name)`. This was done to make sure that
everything works consistently and no copy/pasting is required. Next is the fallback; instead of
giving up and doing various things when it can't find a specific color, it now attempts to treat
the color name as an ID, and if it can't then it returns -1, where each individual command handles
that return value. This means we can keep around AEM -- a bug used in custom levels -- by not
doing anything with the return value if it's -1.
Also, for some reason, there were two `crewcolour` functions, so I stripped out the one in
entityclass and left (and modified) the one in the graphics class, since the graphics class also
has the `crewcolourreal` function.
2021-09-01 00:09:51 +02:00
|
|
|
static int getcolorfromname(std::string name)
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
if (name == "player") return CYAN;
|
|
|
|
else if (name == "cyan") return CYAN;
|
|
|
|
else if (name == "red") return RED;
|
|
|
|
else if (name == "green") return GREEN;
|
|
|
|
else if (name == "yellow") return YELLOW;
|
|
|
|
else if (name == "blue") return BLUE;
|
|
|
|
else if (name == "purple") return PURPLE;
|
|
|
|
else if (name == "customcyan") return CYAN;
|
|
|
|
else if (name == "gray") return GRAY;
|
|
|
|
else if (name == "teleporter") return TELEPORTER;
|
|
|
|
|
|
|
|
int color = help.Int(name.c_str(), -1);
|
|
|
|
if (color < 0) return -1; // Not a number (or it's negative), so we give up
|
|
|
|
return color; // Last effort to give a valid color, maybe they just input the color?
|
Refactor colors in internal commands
Originally this started as a "deduplicate a bunch of duplicated code in script commands" PR,
but as I was working on that, I discovered there's a lot more that needs to be done than
just deduplication.
Anything which needs a crewmate entity now calls `getcrewmanfromname(name)`, and anything which
just needs the crewmate's color calls `getcolorfromname(name)`. This was done to make sure that
everything works consistently and no copy/pasting is required. Next is the fallback; instead of
giving up and doing various things when it can't find a specific color, it now attempts to treat
the color name as an ID, and if it can't then it returns -1, where each individual command handles
that return value. This means we can keep around AEM -- a bug used in custom levels -- by not
doing anything with the return value if it's -1.
Also, for some reason, there were two `crewcolour` functions, so I stripped out the one in
entityclass and left (and modified) the one in the graphics class, since the graphics class also
has the `crewcolourreal` function.
2021-09-01 00:09:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int getcrewmanfromname(std::string name)
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
if (name == "player") return obj.getplayer(); // Return the player
|
|
|
|
int color = getcolorfromname(name); // Maybe they passed in a crewmate name, or an id?
|
|
|
|
if (color == -1) return -1; // ...Nope, return -1
|
|
|
|
return obj.getcrewman(color);
|
Refactor colors in internal commands
Originally this started as a "deduplicate a bunch of duplicated code in script commands" PR,
but as I was working on that, I discovered there's a lot more that needs to be done than
just deduplication.
Anything which needs a crewmate entity now calls `getcrewmanfromname(name)`, and anything which
just needs the crewmate's color calls `getcolorfromname(name)`. This was done to make sure that
everything works consistently and no copy/pasting is required. Next is the fallback; instead of
giving up and doing various things when it can't find a specific color, it now attempts to treat
the color name as an ID, and if it can't then it returns -1, where each individual command handles
that return value. This means we can keep around AEM -- a bug used in custom levels -- by not
doing anything with the return value if it's -1.
Also, for some reason, there were two `crewcolour` functions, so I stripped out the one in
entityclass and left (and modified) the one in the graphics class, since the graphics class also
has the `crewcolourreal` function.
2021-09-01 00:09:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void scriptclass::run(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
if (!running)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This counter here will stop the function when it gets too high
|
|
|
|
short execution_counter = 0;
|
|
|
|
while(running && scriptdelay<=0 && !game.pausescript)
|
|
|
|
{
|
|
|
|
if (INBOUNDS_VEC(position, commands))
|
|
|
|
{
|
|
|
|
//Let's split or command in an array of words
|
|
|
|
tokenize(commands[position]);
|
|
|
|
|
|
|
|
//For script assisted input
|
|
|
|
game.press_left = false;
|
|
|
|
game.press_right = false;
|
|
|
|
game.press_action = false;
|
|
|
|
game.press_map = false;
|
|
|
|
|
|
|
|
//Ok, now we run a command based on that string
|
|
|
|
if (words[0] == "moveplayer")
|
|
|
|
{
|
|
|
|
//USAGE: moveplayer(x offset, y offset)
|
|
|
|
int player = obj.getplayer();
|
|
|
|
if (INBOUNDS_VEC(player, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[player].xp += ss_toi(words[1]);
|
|
|
|
obj.entities[player].yp += ss_toi(words[2]);
|
|
|
|
obj.entities[player].lerpoldxp = obj.entities[player].xp;
|
|
|
|
obj.entities[player].lerpoldyp = obj.entities[player].yp;
|
|
|
|
}
|
|
|
|
scriptdelay = 1;
|
|
|
|
}
|
2020-04-02 22:26:22 +02:00
|
|
|
#if !defined(NO_CUSTOM_LEVELS)
|
2021-09-07 03:56:39 +02:00
|
|
|
if (words[0] == "warpdir")
|
|
|
|
{
|
|
|
|
int temprx=ss_toi(words[1])-1;
|
|
|
|
int tempry=ss_toi(words[2])-1;
|
|
|
|
const RoomProperty* room;
|
|
|
|
cl.setroomwarpdir(temprx, tempry, ss_toi(words[3]));
|
|
|
|
|
|
|
|
room = cl.getroomprop(temprx, tempry);
|
|
|
|
|
|
|
|
//Do we update our own room?
|
|
|
|
if(game.roomx-100==temprx && game.roomy-100==tempry){
|
|
|
|
//If screen warping, then override all that:
|
|
|
|
graphics.backgrounddrawn = false;
|
|
|
|
map.warpx=false; map.warpy=false;
|
|
|
|
if(room->warpdir==0){
|
|
|
|
map.background = 1;
|
|
|
|
//Be careful, we could be in a Lab or Warp Zone room...
|
|
|
|
if(room->tileset==2){
|
|
|
|
//Lab
|
|
|
|
map.background = 2;
|
|
|
|
graphics.rcol = room->tilecol;
|
|
|
|
}else if(room->tileset==3){
|
|
|
|
//Warp Zone
|
|
|
|
map.background = 6;
|
|
|
|
}
|
|
|
|
}else if(room->warpdir==1){
|
|
|
|
map.warpx=true;
|
|
|
|
map.background=3;
|
|
|
|
graphics.rcol = cl.getwarpbackground(temprx,tempry);
|
|
|
|
}else if(room->warpdir==2){
|
|
|
|
map.warpy=true;
|
|
|
|
map.background=4;
|
|
|
|
graphics.rcol = cl.getwarpbackground(temprx,tempry);
|
|
|
|
}else if(room->warpdir==3){
|
|
|
|
map.warpx=true; map.warpy=true;
|
|
|
|
map.background = 5;
|
|
|
|
graphics.rcol = cl.getwarpbackground(temprx,tempry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (words[0] == "ifwarp")
|
|
|
|
{
|
|
|
|
const RoomProperty* const room = cl.getroomprop(ss_toi(words[1])-1, ss_toi(words[2])-1);
|
|
|
|
if (room->warpdir == ss_toi(words[3]))
|
|
|
|
{
|
2022-02-12 23:56:27 +01:00
|
|
|
load("custom_" + raw_words[4]);
|
2021-09-07 03:56:39 +02:00
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
2020-04-02 22:26:22 +02:00
|
|
|
#endif
|
2021-09-07 03:56:39 +02:00
|
|
|
if (words[0] == "destroy")
|
|
|
|
{
|
|
|
|
if(words[1]=="gravitylines"){
|
|
|
|
for(size_t edi=0; edi<obj.entities.size(); edi++){
|
|
|
|
if(obj.entities[edi].type==9) obj.disableentity(edi);
|
|
|
|
if(obj.entities[edi].type==10) obj.disableentity(edi);
|
|
|
|
}
|
|
|
|
}else if(words[1]=="warptokens"){
|
|
|
|
for(size_t edi=0; edi<obj.entities.size(); edi++){
|
|
|
|
if(obj.entities[edi].type==11) obj.disableentity(edi);
|
|
|
|
}
|
|
|
|
}else if(words[1]=="platforms"||words[1]=="moving"){
|
|
|
|
bool fixed=words[1]=="moving";
|
|
|
|
for(size_t edi=0; edi<obj.entities.size(); edi++){
|
|
|
|
if(fixed) obj.disableblockat(obj.entities[edi].xp, obj.entities[edi].yp);
|
|
|
|
if(obj.entities[edi].rule==2 && obj.entities[edi].animate==100) obj.disableentity(edi);
|
|
|
|
}
|
|
|
|
}else if(words[1]=="disappear"){
|
|
|
|
for(size_t edi=0; edi<obj.entities.size(); edi++){
|
|
|
|
obj.disableblockat(obj.entities[edi].xp, obj.entities[edi].yp);
|
|
|
|
if(obj.entities[edi].type==2 && obj.entities[edi].rule==3) obj.disableentity(edi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (words[0] == "customiftrinkets")
|
|
|
|
{
|
|
|
|
if (game.trinkets() >= ss_toi(words[1]))
|
|
|
|
{
|
2022-02-12 23:56:27 +01:00
|
|
|
load("custom_" + raw_words[2]);
|
2021-09-07 03:56:39 +02:00
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (words[0] == "customiftrinketsless")
|
|
|
|
{
|
|
|
|
if (game.trinkets() < ss_toi(words[1]))
|
|
|
|
{
|
2022-02-12 23:56:27 +01:00
|
|
|
load("custom_" + raw_words[2]);
|
2021-09-07 03:56:39 +02:00
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "customifflag")
|
|
|
|
{
|
|
|
|
int flag = ss_toi(words[1]);
|
|
|
|
if (INBOUNDS_ARR(flag, obj.flags) && obj.flags[flag])
|
|
|
|
{
|
2022-02-12 23:56:27 +01:00
|
|
|
load("custom_" + raw_words[2]);
|
2021-09-07 03:56:39 +02:00
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (words[0] == "custommap")
|
|
|
|
{
|
|
|
|
if(words[1]=="on"){
|
|
|
|
map.customshowmm=true;
|
|
|
|
}else if(words[1]=="off"){
|
|
|
|
map.customshowmm=false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (words[0] == "delay")
|
|
|
|
{
|
|
|
|
//USAGE: delay(frames)
|
|
|
|
scriptdelay = ss_toi(words[1]);
|
|
|
|
}
|
|
|
|
if (words[0] == "flag")
|
|
|
|
{
|
|
|
|
int flag = ss_toi(words[1]);
|
|
|
|
if (INBOUNDS_ARR(flag, obj.flags))
|
|
|
|
{
|
|
|
|
if (words[2] == "on")
|
|
|
|
{
|
|
|
|
obj.flags[flag] = true;
|
|
|
|
}
|
|
|
|
else if (words[2] == "off")
|
|
|
|
{
|
|
|
|
obj.flags[flag] = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (words[0] == "flash")
|
|
|
|
{
|
|
|
|
//USAGE: flash(frames)
|
|
|
|
game.flashlight = ss_toi(words[1]);
|
|
|
|
}
|
|
|
|
if (words[0] == "shake")
|
|
|
|
{
|
|
|
|
//USAGE: shake(frames)
|
|
|
|
game.screenshake = ss_toi(words[1]);
|
|
|
|
}
|
|
|
|
if (words[0] == "walk")
|
|
|
|
{
|
|
|
|
//USAGE: walk(dir,frames)
|
|
|
|
if (words[1] == "left")
|
|
|
|
{
|
|
|
|
game.press_left = true;
|
|
|
|
}
|
|
|
|
else if (words[1] == "right")
|
|
|
|
{
|
|
|
|
game.press_right = true;
|
|
|
|
}
|
|
|
|
scriptdelay = ss_toi(words[2]);
|
|
|
|
}
|
|
|
|
if (words[0] == "flip")
|
|
|
|
{
|
|
|
|
game.press_action = true;
|
|
|
|
scriptdelay = 1;
|
|
|
|
}
|
|
|
|
if (words[0] == "tofloor")
|
|
|
|
{
|
|
|
|
int player = obj.getplayer();
|
|
|
|
if(INBOUNDS_VEC(player, obj.entities) && obj.entities[player].onroof>0)
|
|
|
|
{
|
|
|
|
game.press_action = true;
|
|
|
|
scriptdelay = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (words[0] == "playef")
|
|
|
|
{
|
|
|
|
music.playef(ss_toi(words[1]));
|
|
|
|
}
|
|
|
|
if (words[0] == "play")
|
|
|
|
{
|
|
|
|
music.play(ss_toi(words[1]));
|
|
|
|
}
|
|
|
|
if (words[0] == "stopmusic")
|
|
|
|
{
|
|
|
|
music.haltdasmusik();
|
|
|
|
}
|
|
|
|
if (words[0] == "resumemusic")
|
|
|
|
{
|
|
|
|
music.resumefade(0);
|
|
|
|
}
|
|
|
|
if (words[0] == "musicfadeout")
|
|
|
|
{
|
|
|
|
music.fadeout(false);
|
|
|
|
}
|
|
|
|
if (words[0] == "musicfadein")
|
|
|
|
{
|
|
|
|
music.fadein();
|
|
|
|
}
|
|
|
|
if (words[0] == "trinketscriptmusic")
|
|
|
|
{
|
|
|
|
music.play(4);
|
|
|
|
}
|
|
|
|
if (words[0] == "gotoposition")
|
|
|
|
{
|
|
|
|
//USAGE: gotoposition(x position, y position, gravity position)
|
|
|
|
int player = obj.getplayer();
|
|
|
|
if (INBOUNDS_VEC(player, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[player].xp = ss_toi(words[1]);
|
|
|
|
obj.entities[player].yp = ss_toi(words[2]);
|
|
|
|
obj.entities[player].lerpoldxp = obj.entities[player].xp;
|
|
|
|
obj.entities[player].lerpoldyp = obj.entities[player].yp;
|
|
|
|
}
|
|
|
|
game.gravitycontrol = ss_toi(words[3]);
|
|
|
|
|
|
|
|
}
|
|
|
|
if (words[0] == "gotoroom")
|
|
|
|
{
|
|
|
|
//USAGE: gotoroom(x,y) (manually add 100)
|
|
|
|
map.gotoroom(ss_toi(words[1])+100, ss_toi(words[2])+100);
|
|
|
|
}
|
|
|
|
if (words[0] == "cutscene")
|
|
|
|
{
|
|
|
|
graphics.showcutscenebars = true;
|
|
|
|
}
|
|
|
|
if (words[0] == "endcutscene")
|
|
|
|
{
|
|
|
|
graphics.showcutscenebars = false;
|
|
|
|
}
|
|
|
|
if (words[0] == "audiopause")
|
|
|
|
{
|
|
|
|
if (words[1] == "on")
|
|
|
|
{
|
|
|
|
game.disabletemporaryaudiopause = false;
|
|
|
|
}
|
|
|
|
else if (words[1] == "off")
|
|
|
|
{
|
|
|
|
game.disabletemporaryaudiopause = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (words[0] == "untilbars")
|
|
|
|
{
|
|
|
|
if (graphics.showcutscenebars)
|
|
|
|
{
|
|
|
|
if (graphics.cutscenebarspos < 360)
|
|
|
|
{
|
|
|
|
scriptdelay = 1;
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (graphics.cutscenebarspos > 0)
|
|
|
|
{
|
|
|
|
scriptdelay = 1;
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "text")
|
|
|
|
{
|
|
|
|
//oh boy
|
|
|
|
//first word is the colour.
|
|
|
|
if (words[1] == "cyan")
|
|
|
|
{
|
|
|
|
r = 164;
|
|
|
|
g = 164;
|
|
|
|
b = 255;
|
|
|
|
}
|
|
|
|
else if (words[1] == "player")
|
|
|
|
{
|
|
|
|
r = 164;
|
|
|
|
g = 164;
|
|
|
|
b = 255;
|
|
|
|
}
|
|
|
|
else if (words[1] == "red")
|
|
|
|
{
|
|
|
|
r = 255;
|
|
|
|
g = 60;
|
|
|
|
b = 60;
|
|
|
|
}
|
|
|
|
else if (words[1] == "green")
|
|
|
|
{
|
|
|
|
r = 144;
|
|
|
|
g = 255;
|
|
|
|
b = 144;
|
|
|
|
}
|
|
|
|
else if (words[1] == "yellow")
|
|
|
|
{
|
|
|
|
r = 255;
|
|
|
|
g = 255;
|
|
|
|
b = 134;
|
|
|
|
}
|
|
|
|
else if (words[1] == "blue")
|
|
|
|
{
|
|
|
|
r = 95;
|
|
|
|
g = 95;
|
|
|
|
b = 255;
|
|
|
|
}
|
|
|
|
else if (words[1] == "purple")
|
|
|
|
{
|
|
|
|
r = 255;
|
|
|
|
g = 134;
|
|
|
|
b = 255;
|
|
|
|
}
|
|
|
|
else if (words[1] == "white")
|
|
|
|
{
|
|
|
|
r = 244;
|
|
|
|
g = 244;
|
|
|
|
b = 244;
|
|
|
|
}
|
|
|
|
else if (words[1] == "gray")
|
|
|
|
{
|
|
|
|
r = 174;
|
|
|
|
g = 174;
|
|
|
|
b = 174;
|
|
|
|
}
|
|
|
|
else if (words[1] == "orange")
|
|
|
|
{
|
|
|
|
r = 255;
|
|
|
|
g = 130;
|
|
|
|
b = 20;
|
|
|
|
}
|
Add `setactivityposition(x,y)`, add new textbox color `transparent` (#847)
* Add `setactivityposition(x,y)`, add new textbox color `transparent`
This commit adds a new internal command as a part of the visual activity zone changes I've been making.
This one allows the user to reposition the activity zone to anywhere on the screen.
In addition, this commit adds the textbox color `transparent`, which just sets r, g and b to 0.
rgb(0, 0, 0) normally creates the color black, however in VVVVVV textboxes, it makes the background
of them invisible, and makes the text the off-white color which the game uses elsewhere.
* add new variables to hardreset
* Fix unwanted text centering; offset position by 16, 4
It makes sense for `setactivityposition(0, 0)` to place the activity zone in the default position,
so the x has been offset by 16, and the y has been offset by 4.
Text was being automatically centered, meaning any activity zone which wasn't centered had misplaced text.
This has been fixed by calculating the center manually, and offsetting it by the passed value.
2021-10-14 00:38:51 +02:00
|
|
|
else if (words[1] == "transparent")
|
|
|
|
{
|
|
|
|
r = 0;
|
|
|
|
g = 0;
|
|
|
|
b = 0;
|
|
|
|
}
|
2021-09-07 03:56:39 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
//use a gray
|
|
|
|
r = 174;
|
|
|
|
g = 174;
|
|
|
|
b = 174;
|
|
|
|
}
|
|
|
|
|
|
|
|
//next are the x,y coordinates
|
|
|
|
textx = ss_toi(words[2]);
|
|
|
|
texty = ss_toi(words[3]);
|
|
|
|
|
|
|
|
//Number of lines for the textbox!
|
|
|
|
txt.clear();
|
|
|
|
for (int i = 0; i < ss_toi(words[4]); i++)
|
|
|
|
{
|
|
|
|
position++;
|
|
|
|
if (INBOUNDS_VEC(position, commands))
|
|
|
|
{
|
|
|
|
txt.push_back(commands[position]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "position")
|
|
|
|
{
|
|
|
|
//are we facing left or right? for some objects we don't care, default at 0.
|
|
|
|
j = 0;
|
|
|
|
|
|
|
|
//the first word is the object to position relative to
|
|
|
|
if (words[1] == "centerx")
|
|
|
|
{
|
|
|
|
words[2] = "donothing";
|
|
|
|
j = -1;
|
|
|
|
textx = -500;
|
|
|
|
}
|
|
|
|
else if (words[1] == "centery")
|
|
|
|
{
|
|
|
|
words[2] = "donothing";
|
|
|
|
j = -1;
|
|
|
|
texty = -500;
|
|
|
|
}
|
|
|
|
else if (words[1] == "center")
|
|
|
|
{
|
|
|
|
words[2] = "donothing";
|
|
|
|
j = -1;
|
|
|
|
textx = -500;
|
|
|
|
texty = -500;
|
|
|
|
}
|
|
|
|
else // Well, are they asking for a crewmate...?
|
|
|
|
{
|
|
|
|
i = getcrewmanfromname(words[1]);
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
j = obj.entities[i].dir;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//next is whether to position above or below
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities) && words[2] == "above")
|
|
|
|
{
|
|
|
|
if (j == 1) //left
|
|
|
|
{
|
|
|
|
textx = obj.entities[i].xp -10000; //tells the box to be oriented correctly later
|
|
|
|
texty = obj.entities[i].yp - 16 - (txt.size()*8);
|
|
|
|
}
|
|
|
|
else if (j == 0) //Right
|
|
|
|
{
|
|
|
|
textx = obj.entities[i].xp - 16;
|
|
|
|
texty = obj.entities[i].yp - 18 - (txt.size() * 8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
if (j == 1) //left
|
|
|
|
{
|
|
|
|
textx = obj.entities[i].xp -10000; //tells the box to be oriented correctly later
|
|
|
|
texty = obj.entities[i].yp + 26;
|
|
|
|
}
|
|
|
|
else if (j == 0) //Right
|
|
|
|
{
|
|
|
|
textx = obj.entities[i].xp - 16;
|
|
|
|
texty = obj.entities[i].yp + 26;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "customposition")
|
|
|
|
{
|
|
|
|
//are we facing left or right? for some objects we don't care, default at 0.
|
|
|
|
j = 0;
|
|
|
|
|
|
|
|
//the first word is the object to position relative to
|
|
|
|
if (words[1] == "player")
|
|
|
|
{
|
|
|
|
i = obj.getcustomcrewman(0);
|
|
|
|
j = obj.entities[i].dir;
|
|
|
|
}
|
|
|
|
else if (words[1] == "cyan")
|
|
|
|
{
|
|
|
|
i = obj.getcustomcrewman(0);
|
|
|
|
j = obj.entities[i].dir;
|
|
|
|
}
|
|
|
|
else if (words[1] == "purple")
|
|
|
|
{
|
|
|
|
i = obj.getcustomcrewman(1);
|
|
|
|
j = obj.entities[i].dir;
|
|
|
|
}
|
|
|
|
else if (words[1] == "yellow")
|
|
|
|
{
|
|
|
|
i = obj.getcustomcrewman(2);
|
|
|
|
j = obj.entities[i].dir;
|
|
|
|
}
|
|
|
|
else if (words[1] == "red")
|
|
|
|
{
|
|
|
|
i = obj.getcustomcrewman(3);
|
|
|
|
j = obj.entities[i].dir;
|
|
|
|
}
|
|
|
|
else if (words[1] == "green")
|
|
|
|
{
|
|
|
|
i = obj.getcustomcrewman(4);
|
|
|
|
j = obj.entities[i].dir;
|
|
|
|
}
|
|
|
|
else if (words[1] == "blue")
|
|
|
|
{
|
|
|
|
i = obj.getcustomcrewman(5);
|
|
|
|
j = obj.entities[i].dir;
|
|
|
|
}
|
|
|
|
else if (words[1] == "centerx")
|
|
|
|
{
|
|
|
|
words[2] = "donothing";
|
|
|
|
j = -1;
|
|
|
|
textx = -500;
|
|
|
|
}
|
|
|
|
else if (words[1] == "centery")
|
|
|
|
{
|
|
|
|
words[2] = "donothing";
|
|
|
|
j = -1;
|
|
|
|
texty = -500;
|
|
|
|
}
|
|
|
|
else if (words[1] == "center")
|
|
|
|
{
|
|
|
|
words[2] = "donothing";
|
|
|
|
j = -1;
|
|
|
|
textx = -500;
|
|
|
|
texty = -500;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(i==0 && words[1]!="player" && words[1]!="cyan"){
|
|
|
|
//Requested crewmate is not actually on screen
|
|
|
|
words[2] = "donothing";
|
|
|
|
j = -1;
|
|
|
|
textx = -500;
|
|
|
|
texty = -500;
|
|
|
|
}
|
|
|
|
|
|
|
|
//next is whether to position above or below
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities) && words[2] == "above")
|
|
|
|
{
|
|
|
|
if (j == 1) //left
|
|
|
|
{
|
|
|
|
textx = obj.entities[i].xp -10000; //tells the box to be oriented correctly later
|
|
|
|
texty = obj.entities[i].yp - 16 - (txt.size()*8);
|
|
|
|
}
|
|
|
|
else if (j == 0) //Right
|
|
|
|
{
|
|
|
|
textx = obj.entities[i].xp - 16;
|
|
|
|
texty = obj.entities[i].yp - 18 - (txt.size() * 8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
if (j == 1) //left
|
|
|
|
{
|
|
|
|
textx = obj.entities[i].xp -10000; //tells the box to be oriented correctly later
|
|
|
|
texty = obj.entities[i].yp + 26;
|
|
|
|
}
|
|
|
|
else if (j == 0) //Right
|
|
|
|
{
|
|
|
|
textx = obj.entities[i].xp - 16;
|
|
|
|
texty = obj.entities[i].yp + 26;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "backgroundtext")
|
|
|
|
{
|
|
|
|
game.backgroundtext = true;
|
|
|
|
}
|
|
|
|
else if (words[0] == "flipme")
|
|
|
|
{
|
|
|
|
textflipme = !textflipme;
|
|
|
|
}
|
|
|
|
else if (words[0] == "speak_active" || words[0] == "speak")
|
|
|
|
{
|
|
|
|
//Ok, actually display the textbox we've initilised now!
|
|
|
|
//If using "speak", don't make the textbox active (so we can use multiple textboxes)
|
|
|
|
if (txt.empty())
|
|
|
|
{
|
|
|
|
txt.resize(1);
|
|
|
|
}
|
|
|
|
graphics.createtextboxreal(txt[0], textx, texty, r, g, b, textflipme);
|
|
|
|
textflipme = false;
|
|
|
|
if ((int) txt.size() > 1)
|
|
|
|
{
|
|
|
|
for (i = 1; i < (int) txt.size(); i++)
|
|
|
|
{
|
|
|
|
graphics.addline(txt[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//the textbox cannot be outside the screen. Fix if it is.
|
|
|
|
if (textx <= -1000)
|
|
|
|
{
|
|
|
|
//position to the left of the player
|
|
|
|
textx += 10000;
|
|
|
|
textx -= graphics.textboxwidth();
|
|
|
|
textx += 16;
|
|
|
|
graphics.textboxmoveto(textx);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (textx == -500 || textx == -1)
|
|
|
|
{
|
|
|
|
graphics.textboxcenterx();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (texty == -500)
|
|
|
|
{
|
|
|
|
graphics.textboxcentery();
|
|
|
|
}
|
|
|
|
|
|
|
|
graphics.textboxadjust();
|
|
|
|
if (words[0] == "speak_active")
|
|
|
|
{
|
|
|
|
graphics.textboxactive();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!game.backgroundtext)
|
|
|
|
{
|
|
|
|
game.advancetext = true;
|
|
|
|
game.hascontrol = false;
|
|
|
|
game.pausescript = true;
|
|
|
|
if (key.isDown(90) || key.isDown(32) || key.isDown(86)
|
|
|
|
|| key.isDown(KEYBOARD_UP) || key.isDown(KEYBOARD_DOWN)) game.jumpheld = true;
|
|
|
|
}
|
|
|
|
game.backgroundtext = false;
|
|
|
|
}
|
|
|
|
else if (words[0] == "endtext")
|
|
|
|
{
|
|
|
|
graphics.textboxremove();
|
|
|
|
game.hascontrol = true;
|
|
|
|
game.advancetext = false;
|
|
|
|
}
|
|
|
|
else if (words[0] == "endtextfast")
|
|
|
|
{
|
|
|
|
graphics.textboxremovefast();
|
|
|
|
game.hascontrol = true;
|
|
|
|
game.advancetext = false;
|
|
|
|
}
|
|
|
|
else if (words[0] == "do")
|
|
|
|
{
|
|
|
|
//right, loop from this point
|
|
|
|
looppoint = position;
|
|
|
|
loopcount = ss_toi(words[1]);
|
|
|
|
}
|
|
|
|
else if (words[0] == "loop")
|
|
|
|
{
|
|
|
|
//right, loop from this point
|
|
|
|
loopcount--;
|
|
|
|
if (loopcount > 0)
|
|
|
|
{
|
|
|
|
position = looppoint;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "vvvvvvman")
|
|
|
|
{
|
|
|
|
//Create the super VVVVVV combo!
|
|
|
|
i = obj.getplayer();
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[i].xp = 30;
|
|
|
|
obj.entities[i].yp = 46;
|
|
|
|
obj.entities[i].size = 13;
|
|
|
|
obj.entities[i].colour = 23;
|
|
|
|
obj.entities[i].cx = 36;// 6;
|
|
|
|
obj.entities[i].cy = 12+80;// 2;
|
|
|
|
obj.entities[i].h = 126-80;// 21;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "undovvvvvvman")
|
|
|
|
{
|
|
|
|
//Create the super VVVVVV combo!
|
|
|
|
i = obj.getplayer();
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[i].xp = 100;
|
|
|
|
obj.entities[i].size = 0;
|
|
|
|
obj.entities[i].colour = 0;
|
|
|
|
obj.entities[i].cx = 6;
|
|
|
|
obj.entities[i].cy = 2;
|
|
|
|
obj.entities[i].h = 21;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "createentity")
|
|
|
|
{
|
|
|
|
std::string word6 = words[6];
|
|
|
|
std::string word7 = words[7];
|
|
|
|
std::string word8 = words[8];
|
|
|
|
std::string word9 = words[9];
|
|
|
|
if (!argexists[6]) words[6] = "0";
|
|
|
|
if (!argexists[7]) words[7] = "0";
|
|
|
|
if (!argexists[8]) words[8] = "320";
|
|
|
|
if (!argexists[9]) words[9] = "240";
|
|
|
|
obj.createentity(
|
|
|
|
ss_toi(words[1]),
|
|
|
|
ss_toi(words[2]),
|
|
|
|
ss_toi(words[3]),
|
|
|
|
ss_toi(words[4]),
|
|
|
|
ss_toi(words[5]),
|
|
|
|
ss_toi(words[6]),
|
|
|
|
ss_toi(words[7]),
|
|
|
|
ss_toi(words[8]),
|
|
|
|
ss_toi(words[9])
|
|
|
|
);
|
|
|
|
words[6] = word6;
|
|
|
|
words[7] = word7;
|
|
|
|
words[8] = word8;
|
|
|
|
words[9] = word9;
|
|
|
|
}
|
|
|
|
else if (words[0] == "createcrewman")
|
|
|
|
{
|
|
|
|
// Note: Do not change the "r" variable, it's used in custom levels
|
|
|
|
// to have glitchy textbox colors, where the game treats the value
|
|
|
|
// we set here as the red channel for the color.
|
|
|
|
r = getcolorfromname(words[3]);
|
|
|
|
if (r == -1) r = 19;
|
|
|
|
|
|
|
|
//convert the command to the right index
|
|
|
|
if (words[5] == "followplayer") words[5] = "10";
|
|
|
|
if (words[5] == "followpurple") words[5] = "11";
|
|
|
|
if (words[5] == "followyellow") words[5] = "12";
|
|
|
|
if (words[5] == "followred") words[5] = "13";
|
|
|
|
if (words[5] == "followgreen") words[5] = "14";
|
|
|
|
if (words[5] == "followblue") words[5] = "15";
|
|
|
|
|
|
|
|
if (words[5] == "followposition") words[5] = "16";
|
|
|
|
if (words[5] == "faceleft")
|
|
|
|
{
|
|
|
|
words[5] = "17";
|
|
|
|
words[6] = "0";
|
|
|
|
}
|
|
|
|
if (words[5] == "faceright")
|
|
|
|
{
|
|
|
|
words[5] = "17";
|
|
|
|
words[6] = "1";
|
|
|
|
}
|
|
|
|
if (words[5] == "faceplayer")
|
|
|
|
{
|
|
|
|
words[5] = "18";
|
|
|
|
words[6] = "0";
|
|
|
|
}
|
|
|
|
if (words[5] == "panic")
|
|
|
|
{
|
|
|
|
words[5] = "20";
|
|
|
|
words[6] = "0";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ss_toi(words[5]) >= 16)
|
|
|
|
{
|
|
|
|
obj.createentity(ss_toi(words[1]), ss_toi(words[2]), 18, r, ss_toi(words[4]), ss_toi(words[5]), ss_toi(words[6]));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
obj.createentity(ss_toi(words[1]), ss_toi(words[2]), 18, r, ss_toi(words[4]), ss_toi(words[5]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "changemood")
|
|
|
|
{
|
|
|
|
int crewmate = getcrewmanfromname(words[1]);
|
|
|
|
if (crewmate != -1) i = crewmate; // Ensure AEM is kept
|
|
|
|
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities) && ss_toi(words[2]) == 0)
|
|
|
|
{
|
|
|
|
obj.entities[i].tile = 0;
|
|
|
|
}
|
|
|
|
else if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[i].tile = 144;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "changecustommood")
|
|
|
|
{
|
|
|
|
if (words[1] == "player")
|
|
|
|
{
|
|
|
|
i=obj.getcustomcrewman(0);
|
|
|
|
obj.customcrewmoods[0]=ss_toi(words[2]);
|
|
|
|
}
|
|
|
|
else if (words[1] == "cyan")
|
|
|
|
{
|
|
|
|
i=obj.getcustomcrewman(0);
|
|
|
|
obj.customcrewmoods[0]=ss_toi(words[2]);
|
|
|
|
}
|
|
|
|
else if (words[1] == "customcyan")
|
|
|
|
{
|
|
|
|
i=obj.getcustomcrewman(0);
|
|
|
|
obj.customcrewmoods[0]=ss_toi(words[2]);
|
|
|
|
}
|
|
|
|
else if (words[1] == "red")
|
|
|
|
{
|
|
|
|
i=obj.getcustomcrewman(3);
|
|
|
|
obj.customcrewmoods[3]=ss_toi(words[2]);
|
|
|
|
}
|
|
|
|
else if (words[1] == "green")
|
|
|
|
{
|
|
|
|
i=obj.getcustomcrewman(4);
|
|
|
|
obj.customcrewmoods[4]=ss_toi(words[2]);
|
|
|
|
}
|
|
|
|
else if (words[1] == "yellow")
|
|
|
|
{
|
|
|
|
i=obj.getcustomcrewman(2);
|
|
|
|
obj.customcrewmoods[2]=ss_toi(words[2]);
|
|
|
|
}
|
|
|
|
else if (words[1] == "blue")
|
|
|
|
{
|
|
|
|
i=obj.getcustomcrewman(5);
|
|
|
|
obj.customcrewmoods[5]=ss_toi(words[2]);
|
|
|
|
}
|
|
|
|
else if (words[1] == "purple")
|
|
|
|
{
|
|
|
|
i=obj.getcustomcrewman(1);
|
|
|
|
obj.customcrewmoods[1]=ss_toi(words[2]);
|
|
|
|
}
|
|
|
|
else if (words[1] == "pink")
|
|
|
|
{
|
|
|
|
i=obj.getcustomcrewman(1);
|
|
|
|
obj.customcrewmoods[1]=ss_toi(words[2]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities) && ss_toi(words[2]) == 0)
|
|
|
|
{
|
|
|
|
obj.entities[i].tile = 0;
|
|
|
|
}
|
|
|
|
else if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[i].tile = 144;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "changetile")
|
|
|
|
{
|
|
|
|
int crewmate = getcrewmanfromname(words[1]);
|
|
|
|
if (crewmate != -1) i = crewmate; // Ensure AEM is kept
|
|
|
|
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[i].tile = ss_toi(words[2]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "flipgravity")
|
|
|
|
{
|
|
|
|
//not something I'll use a lot, I think. Doesn't need to be very robust!
|
|
|
|
if (words[1] == "player")
|
|
|
|
{
|
|
|
|
game.gravitycontrol = !game.gravitycontrol;
|
|
|
|
++game.totalflips;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int crewmate = getcrewmanfromname(words[1]);
|
|
|
|
if (crewmate != -1) i = crewmate; // Ensure AEM is kept
|
|
|
|
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities) && obj.entities[i].rule == 7)
|
|
|
|
{
|
|
|
|
obj.entities[i].rule = 6;
|
|
|
|
obj.entities[i].tile = 0;
|
|
|
|
}
|
|
|
|
else if (INBOUNDS_VEC(i, obj.entities) && obj.getplayer() != i) // Don't destroy player entity
|
|
|
|
{
|
|
|
|
obj.entities[i].rule = 7;
|
|
|
|
obj.entities[i].tile = 6;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "changegravity")
|
|
|
|
{
|
|
|
|
//not something I'll use a lot, I think. Doesn't need to be very robust!
|
|
|
|
int crewmate = getcrewmanfromname(words[1]);
|
|
|
|
if (crewmate != -1) i = crewmate; // Ensure AEM is kept
|
|
|
|
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[i].tile +=12;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "changedir")
|
|
|
|
{
|
|
|
|
int crewmate = getcrewmanfromname(words[1]);
|
|
|
|
if (crewmate != -1) i = crewmate; // Ensure AEM is kept
|
|
|
|
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities) && ss_toi(words[2]) == 0)
|
|
|
|
{
|
|
|
|
obj.entities[i].dir = 0;
|
|
|
|
}
|
|
|
|
else if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[i].dir = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "alarmon")
|
|
|
|
{
|
|
|
|
game.alarmon = true;
|
|
|
|
game.alarmdelay = 0;
|
|
|
|
}
|
|
|
|
else if (words[0] == "alarmoff")
|
|
|
|
{
|
|
|
|
game.alarmon = false;
|
|
|
|
}
|
|
|
|
else if (words[0] == "changeai")
|
|
|
|
{
|
|
|
|
int crewmate = getcrewmanfromname(words[1]);
|
|
|
|
if (crewmate != -1) i = crewmate; // Ensure AEM is kept
|
|
|
|
|
|
|
|
if (words[2] == "followplayer") words[2] = "10";
|
|
|
|
if (words[2] == "followpurple") words[2] = "11";
|
|
|
|
if (words[2] == "followyellow") words[2] = "12";
|
|
|
|
if (words[2] == "followred") words[2] = "13";
|
|
|
|
if (words[2] == "followgreen") words[2] = "14";
|
|
|
|
if (words[2] == "followblue") words[2] = "15";
|
|
|
|
|
|
|
|
if (words[2] == "followposition") words[2] = "16";
|
|
|
|
if (words[2] == "faceleft")
|
|
|
|
{
|
|
|
|
words[2] = "17";
|
|
|
|
words[3] = "0";
|
|
|
|
}
|
|
|
|
if (words[2] == "faceright")
|
|
|
|
{
|
|
|
|
words[2] = "17";
|
|
|
|
words[3] = "1";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[i].state = ss_toi(words[2]);
|
|
|
|
if (obj.entities[i].state == 16)
|
|
|
|
{
|
|
|
|
obj.entities[i].para=ss_toi(words[3]);
|
|
|
|
}
|
|
|
|
else if (obj.entities[i].state == 17)
|
|
|
|
{
|
|
|
|
obj.entities[i].dir=ss_toi(words[3]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "activateteleporter")
|
|
|
|
{
|
|
|
|
i = obj.getteleporter();
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[i].tile = 6;
|
|
|
|
obj.entities[i].colour = 102;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "changecolour")
|
|
|
|
{
|
|
|
|
int crewmate = getcrewmanfromname(words[1]);
|
|
|
|
if (crewmate != -1) i = crewmate; // Ensure AEM is kept
|
|
|
|
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[i].colour = getcolorfromname(words[2]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "squeak")
|
|
|
|
{
|
|
|
|
if (words[1] == "player")
|
|
|
|
{
|
|
|
|
music.playef(11);
|
|
|
|
}
|
|
|
|
else if (words[1] == "cyan")
|
|
|
|
{
|
|
|
|
music.playef(11);
|
|
|
|
}
|
|
|
|
else if (words[1] == "red")
|
|
|
|
{
|
|
|
|
music.playef(16);
|
|
|
|
}
|
|
|
|
else if (words[1] == "green")
|
|
|
|
{
|
|
|
|
music.playef(12);
|
|
|
|
}
|
|
|
|
else if (words[1] == "yellow")
|
|
|
|
{
|
|
|
|
music.playef(14);
|
|
|
|
}
|
|
|
|
else if (words[1] == "blue")
|
|
|
|
{
|
|
|
|
music.playef(13);
|
|
|
|
}
|
|
|
|
else if (words[1] == "purple")
|
|
|
|
{
|
|
|
|
music.playef(15);
|
|
|
|
}
|
|
|
|
else if (words[1] == "cry")
|
|
|
|
{
|
|
|
|
music.playef(2);
|
|
|
|
}
|
|
|
|
else if (words[1] == "terminal")
|
|
|
|
{
|
|
|
|
music.playef(20);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "blackout")
|
|
|
|
{
|
|
|
|
game.blackout = true;
|
|
|
|
}
|
|
|
|
else if (words[0] == "blackon")
|
|
|
|
{
|
|
|
|
game.blackout = false;
|
|
|
|
}
|
|
|
|
else if (words[0] == "setcheckpoint")
|
|
|
|
{
|
|
|
|
i = obj.getplayer();
|
|
|
|
game.savepoint = 0;
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
game.savex = obj.entities[i].xp ;
|
|
|
|
game.savey = obj.entities[i].yp;
|
|
|
|
}
|
|
|
|
game.savegc = game.gravitycontrol;
|
|
|
|
game.saverx = game.roomx;
|
|
|
|
game.savery = game.roomy;
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
game.savedir = obj.entities[i].dir;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "gamestate")
|
|
|
|
{
|
|
|
|
game.state = ss_toi(words[1]);
|
|
|
|
game.statedelay = 0;
|
|
|
|
}
|
|
|
|
else if (words[0] == "textboxactive")
|
|
|
|
{
|
|
|
|
graphics.textboxactive();
|
|
|
|
}
|
|
|
|
else if (words[0] == "gamemode")
|
|
|
|
{
|
|
|
|
if (words[1] == "teleporter")
|
|
|
|
{
|
|
|
|
game.gamestate = GAMEMODE; /* to set prevgamestate */
|
|
|
|
game.mapmenuchange(TELEPORTERMODE, false);
|
|
|
|
|
|
|
|
game.useteleporter = false; //good heavens don't actually use it
|
|
|
|
}
|
|
|
|
else if (words[1] == "game")
|
|
|
|
{
|
|
|
|
graphics.resumegamemode = true;
|
|
|
|
game.prevgamestate = GAMEMODE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "ifexplored")
|
|
|
|
{
|
|
|
|
if (map.isexplored(ss_toi(words[1]), ss_toi(words[2])))
|
|
|
|
{
|
2022-02-12 23:56:27 +01:00
|
|
|
load(raw_words[3]);
|
2021-09-07 03:56:39 +02:00
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "iflast")
|
|
|
|
{
|
|
|
|
if (game.lastsaved==ss_toi(words[1]))
|
|
|
|
{
|
2022-02-12 23:56:27 +01:00
|
|
|
load(raw_words[2]);
|
2021-09-07 03:56:39 +02:00
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "ifskip")
|
|
|
|
{
|
|
|
|
if (game.nocutscenes)
|
|
|
|
{
|
2022-02-12 23:56:27 +01:00
|
|
|
load(raw_words[1]);
|
2021-09-07 03:56:39 +02:00
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "ifflag")
|
|
|
|
{
|
|
|
|
int flag = ss_toi(words[1]);
|
|
|
|
if (INBOUNDS_ARR(flag, obj.flags) && obj.flags[flag])
|
|
|
|
{
|
2022-02-12 23:56:27 +01:00
|
|
|
load(raw_words[2]);
|
2021-09-07 03:56:39 +02:00
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "ifcrewlost")
|
|
|
|
{
|
|
|
|
int crewmate = ss_toi(words[1]);
|
|
|
|
if (INBOUNDS_ARR(crewmate, game.crewstats) && !game.crewstats[crewmate])
|
|
|
|
{
|
2022-02-12 23:56:27 +01:00
|
|
|
load(raw_words[2]);
|
2021-09-07 03:56:39 +02:00
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "iftrinkets")
|
|
|
|
{
|
|
|
|
if (game.trinkets() >= ss_toi(words[1]))
|
|
|
|
{
|
2022-02-12 23:56:27 +01:00
|
|
|
load(raw_words[2]);
|
2021-09-07 03:56:39 +02:00
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "iftrinketsless")
|
|
|
|
{
|
|
|
|
if (game.stat_trinkets < ss_toi(words[1]))
|
|
|
|
{
|
2022-02-12 23:56:27 +01:00
|
|
|
load(raw_words[2]);
|
2021-09-07 03:56:39 +02:00
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "hidecoordinates")
|
|
|
|
{
|
|
|
|
map.setexplored(ss_toi(words[1]), ss_toi(words[2]), false);
|
|
|
|
}
|
|
|
|
else if (words[0] == "showcoordinates")
|
|
|
|
{
|
|
|
|
map.setexplored(ss_toi(words[1]), ss_toi(words[2]), true);
|
|
|
|
}
|
|
|
|
else if (words[0] == "hideship")
|
|
|
|
{
|
|
|
|
map.hideship();
|
|
|
|
}
|
|
|
|
else if (words[0] == "showship")
|
|
|
|
{
|
|
|
|
map.showship();
|
|
|
|
}
|
|
|
|
else if (words[0] == "showsecretlab")
|
|
|
|
{
|
|
|
|
map.setexplored(16, 5, true);
|
|
|
|
map.setexplored(17, 5, true);
|
|
|
|
map.setexplored(18, 5, true);
|
|
|
|
map.setexplored(17, 6, true);
|
|
|
|
map.setexplored(18, 6, true);
|
|
|
|
map.setexplored(19, 6, true);
|
|
|
|
map.setexplored(19, 7, true);
|
|
|
|
map.setexplored(19, 8, true);
|
|
|
|
}
|
|
|
|
else if (words[0] == "hidesecretlab")
|
|
|
|
{
|
|
|
|
map.setexplored(16, 5, false);
|
|
|
|
map.setexplored(17, 5, false);
|
|
|
|
map.setexplored(18, 5, false);
|
|
|
|
map.setexplored(17, 6, false);
|
|
|
|
map.setexplored(18, 6, false);
|
|
|
|
map.setexplored(19, 6, false);
|
|
|
|
map.setexplored(19, 7, false);
|
|
|
|
map.setexplored(19, 8, false);
|
|
|
|
}
|
|
|
|
else if (words[0] == "showteleporters")
|
|
|
|
{
|
|
|
|
map.showteleporters = true;
|
|
|
|
}
|
|
|
|
else if (words[0] == "showtargets")
|
|
|
|
{
|
|
|
|
map.showtargets = true;
|
|
|
|
}
|
|
|
|
else if (words[0] == "showtrinkets")
|
|
|
|
{
|
|
|
|
map.showtrinkets = true;
|
|
|
|
}
|
|
|
|
else if (words[0] == "hideteleporters")
|
|
|
|
{
|
|
|
|
map.showteleporters = false;
|
|
|
|
}
|
|
|
|
else if (words[0] == "hidetargets")
|
|
|
|
{
|
|
|
|
map.showtargets = false;
|
|
|
|
}
|
|
|
|
else if (words[0] == "hidetrinkets")
|
|
|
|
{
|
|
|
|
map.showtrinkets = false;
|
|
|
|
}
|
|
|
|
else if (words[0] == "hideplayer")
|
|
|
|
{
|
|
|
|
int player = obj.getplayer();
|
|
|
|
if (INBOUNDS_VEC(player, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[player].invis = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "showplayer")
|
|
|
|
{
|
|
|
|
int player = obj.getplayer();
|
|
|
|
if (INBOUNDS_VEC(player, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[player].invis = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "teleportscript")
|
|
|
|
{
|
|
|
|
game.teleportscript = words[1];
|
|
|
|
}
|
|
|
|
else if (words[0] == "clearteleportscript")
|
|
|
|
{
|
|
|
|
game.teleportscript = "";
|
|
|
|
}
|
|
|
|
else if (words[0] == "nocontrol")
|
|
|
|
{
|
|
|
|
game.hascontrol = false;
|
|
|
|
}
|
|
|
|
else if (words[0] == "hascontrol")
|
|
|
|
{
|
|
|
|
game.hascontrol = true;
|
|
|
|
}
|
|
|
|
else if (words[0] == "companion")
|
|
|
|
{
|
|
|
|
game.companion = ss_toi(words[1]);
|
|
|
|
}
|
|
|
|
else if (words[0] == "befadein")
|
|
|
|
{
|
|
|
|
graphics.setfade(0);
|
Enumify all fade modes
This removes the magic numbers previously used for controlling the fade
mode, which are really not readable at all unless you already know what
they mean.
0: FADE_NONE
1: FADE_FULLY_BLACK
2: FADE_START_FADEOUT
3: FADE_FADING_OUT
4: FADE_START_FADEIN
5: FADE_FADING_IN
There is also the macro FADEMODE_IS_FADING, which indicates when the
intention is to only check if the game is fading right now, which wasn't
clearly conveyed previously.
I also took the opportunity to clean up the style of any lines I
touched. This included rewriting if-else chains into case-switches,
turning one-liner if-then statements into proper blocks, fixing up
comments, and even commenting the `fademode == FADE_NONE` on the tower
spike checks (which, it was previously undocumented why that check was
there, but I think I know why it's there).
As for type safety, we already get some by transforming the variable
types into the enum. Assignment is prohibited without a cast. But,
apparently, comparison is perfectly legal and won't even give so much as
a warning. To work around this and make absolutely sure I made all
existing comparisons now use the enum, I temporarily changed it to be an
`enum class`, which is a C++11 feature that makes it so all comparisons
are illegal. Unfortunately, it scopes them in a namespace with the same
name as a class, so I had to temporarily define macros to make sure my
existing code worked. I also had to temporarily up the standard in
CMakeLists.txt to get it to compile. But after all that was done, I
found the rest of the places where a comparison to an integer was used,
and fixed them.
2022-04-25 09:57:47 +02:00
|
|
|
graphics.fademode = FADE_NONE;
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else if (words[0] == "fadein")
|
|
|
|
{
|
Enumify all fade modes
This removes the magic numbers previously used for controlling the fade
mode, which are really not readable at all unless you already know what
they mean.
0: FADE_NONE
1: FADE_FULLY_BLACK
2: FADE_START_FADEOUT
3: FADE_FADING_OUT
4: FADE_START_FADEIN
5: FADE_FADING_IN
There is also the macro FADEMODE_IS_FADING, which indicates when the
intention is to only check if the game is fading right now, which wasn't
clearly conveyed previously.
I also took the opportunity to clean up the style of any lines I
touched. This included rewriting if-else chains into case-switches,
turning one-liner if-then statements into proper blocks, fixing up
comments, and even commenting the `fademode == FADE_NONE` on the tower
spike checks (which, it was previously undocumented why that check was
there, but I think I know why it's there).
As for type safety, we already get some by transforming the variable
types into the enum. Assignment is prohibited without a cast. But,
apparently, comparison is perfectly legal and won't even give so much as
a warning. To work around this and make absolutely sure I made all
existing comparisons now use the enum, I temporarily changed it to be an
`enum class`, which is a C++11 feature that makes it so all comparisons
are illegal. Unfortunately, it scopes them in a namespace with the same
name as a class, so I had to temporarily define macros to make sure my
existing code worked. I also had to temporarily up the standard in
CMakeLists.txt to get it to compile. But after all that was done, I
found the rest of the places where a comparison to an integer was used,
and fixed them.
2022-04-25 09:57:47 +02:00
|
|
|
graphics.fademode = FADE_START_FADEIN;
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else if (words[0] == "fadeout")
|
|
|
|
{
|
Enumify all fade modes
This removes the magic numbers previously used for controlling the fade
mode, which are really not readable at all unless you already know what
they mean.
0: FADE_NONE
1: FADE_FULLY_BLACK
2: FADE_START_FADEOUT
3: FADE_FADING_OUT
4: FADE_START_FADEIN
5: FADE_FADING_IN
There is also the macro FADEMODE_IS_FADING, which indicates when the
intention is to only check if the game is fading right now, which wasn't
clearly conveyed previously.
I also took the opportunity to clean up the style of any lines I
touched. This included rewriting if-else chains into case-switches,
turning one-liner if-then statements into proper blocks, fixing up
comments, and even commenting the `fademode == FADE_NONE` on the tower
spike checks (which, it was previously undocumented why that check was
there, but I think I know why it's there).
As for type safety, we already get some by transforming the variable
types into the enum. Assignment is prohibited without a cast. But,
apparently, comparison is perfectly legal and won't even give so much as
a warning. To work around this and make absolutely sure I made all
existing comparisons now use the enum, I temporarily changed it to be an
`enum class`, which is a C++11 feature that makes it so all comparisons
are illegal. Unfortunately, it scopes them in a namespace with the same
name as a class, so I had to temporarily define macros to make sure my
existing code worked. I also had to temporarily up the standard in
CMakeLists.txt to get it to compile. But after all that was done, I
found the rest of the places where a comparison to an integer was used,
and fixed them.
2022-04-25 09:57:47 +02:00
|
|
|
graphics.fademode = FADE_START_FADEOUT;
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else if (words[0] == "untilfade")
|
|
|
|
{
|
Enumify all fade modes
This removes the magic numbers previously used for controlling the fade
mode, which are really not readable at all unless you already know what
they mean.
0: FADE_NONE
1: FADE_FULLY_BLACK
2: FADE_START_FADEOUT
3: FADE_FADING_OUT
4: FADE_START_FADEIN
5: FADE_FADING_IN
There is also the macro FADEMODE_IS_FADING, which indicates when the
intention is to only check if the game is fading right now, which wasn't
clearly conveyed previously.
I also took the opportunity to clean up the style of any lines I
touched. This included rewriting if-else chains into case-switches,
turning one-liner if-then statements into proper blocks, fixing up
comments, and even commenting the `fademode == FADE_NONE` on the tower
spike checks (which, it was previously undocumented why that check was
there, but I think I know why it's there).
As for type safety, we already get some by transforming the variable
types into the enum. Assignment is prohibited without a cast. But,
apparently, comparison is perfectly legal and won't even give so much as
a warning. To work around this and make absolutely sure I made all
existing comparisons now use the enum, I temporarily changed it to be an
`enum class`, which is a C++11 feature that makes it so all comparisons
are illegal. Unfortunately, it scopes them in a namespace with the same
name as a class, so I had to temporarily define macros to make sure my
existing code worked. I also had to temporarily up the standard in
CMakeLists.txt to get it to compile. But after all that was done, I
found the rest of the places where a comparison to an integer was used,
and fixed them.
2022-04-25 09:57:47 +02:00
|
|
|
if (FADEMODE_IS_FADING(graphics.fademode))
|
2021-09-07 03:56:39 +02:00
|
|
|
{
|
|
|
|
scriptdelay = 1;
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "entersecretlab")
|
|
|
|
{
|
|
|
|
game.unlocknum(8);
|
|
|
|
game.insecretlab = true;
|
|
|
|
SDL_memset(map.explored, true, sizeof(map.explored));
|
|
|
|
}
|
|
|
|
else if (words[0] == "leavesecretlab")
|
|
|
|
{
|
|
|
|
game.insecretlab = false;
|
|
|
|
}
|
|
|
|
else if (words[0] == "resetgame")
|
|
|
|
{
|
|
|
|
map.resetnames();
|
|
|
|
map.resetmap();
|
|
|
|
map.resetplayer();
|
|
|
|
graphics.towerbg.tdrawback = true;
|
|
|
|
|
|
|
|
obj.resetallflags();
|
|
|
|
i = obj.getplayer();
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[i].tile = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < 100; i++)
|
|
|
|
{
|
|
|
|
obj.collect[i] = false;
|
|
|
|
obj.customcollect[i] = false;
|
|
|
|
}
|
|
|
|
game.deathcounts = 0;
|
|
|
|
game.advancetext = false;
|
|
|
|
game.hascontrol = true;
|
|
|
|
game.resetgameclock();
|
|
|
|
game.gravitycontrol = 0;
|
|
|
|
game.teleport = false;
|
|
|
|
game.companion = 0;
|
|
|
|
game.teleport_to_new_area = false;
|
|
|
|
game.teleport_to_x = 0;
|
|
|
|
game.teleport_to_y = 0;
|
|
|
|
|
|
|
|
game.teleportscript = "";
|
|
|
|
|
|
|
|
//get out of final level mode!
|
|
|
|
map.finalmode = false;
|
|
|
|
map.final_colormode = false;
|
|
|
|
map.final_mapcol = 0;
|
|
|
|
map.final_colorframe = 0;
|
|
|
|
map.finalstretch = false;
|
|
|
|
}
|
|
|
|
else if (words[0] == "loadscript")
|
|
|
|
{
|
2022-02-12 23:56:27 +01:00
|
|
|
load(raw_words[1]);
|
2021-09-07 03:56:39 +02:00
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (words[0] == "rollcredits")
|
|
|
|
{
|
2021-06-12 00:30:29 +02:00
|
|
|
#if !defined(NO_CUSTOM_LEVELS) && !defined(NO_EDITOR)
|
2021-09-07 03:56:39 +02:00
|
|
|
if (map.custommode && !map.custommodeforreal)
|
|
|
|
{
|
|
|
|
game.returntoeditor();
|
|
|
|
ed.note = "Rolled credits";
|
|
|
|
ed.notedelay = 45;
|
|
|
|
}
|
|
|
|
else
|
2021-06-12 00:30:29 +02:00
|
|
|
#endif
|
2021-09-07 03:56:39 +02:00
|
|
|
{
|
|
|
|
game.gamestate = GAMECOMPLETE;
|
Enumify all fade modes
This removes the magic numbers previously used for controlling the fade
mode, which are really not readable at all unless you already know what
they mean.
0: FADE_NONE
1: FADE_FULLY_BLACK
2: FADE_START_FADEOUT
3: FADE_FADING_OUT
4: FADE_START_FADEIN
5: FADE_FADING_IN
There is also the macro FADEMODE_IS_FADING, which indicates when the
intention is to only check if the game is fading right now, which wasn't
clearly conveyed previously.
I also took the opportunity to clean up the style of any lines I
touched. This included rewriting if-else chains into case-switches,
turning one-liner if-then statements into proper blocks, fixing up
comments, and even commenting the `fademode == FADE_NONE` on the tower
spike checks (which, it was previously undocumented why that check was
there, but I think I know why it's there).
As for type safety, we already get some by transforming the variable
types into the enum. Assignment is prohibited without a cast. But,
apparently, comparison is perfectly legal and won't even give so much as
a warning. To work around this and make absolutely sure I made all
existing comparisons now use the enum, I temporarily changed it to be an
`enum class`, which is a C++11 feature that makes it so all comparisons
are illegal. Unfortunately, it scopes them in a namespace with the same
name as a class, so I had to temporarily define macros to make sure my
existing code worked. I also had to temporarily up the standard in
CMakeLists.txt to get it to compile. But after all that was done, I
found the rest of the places where a comparison to an integer was used,
and fixed them.
2022-04-25 09:57:47 +02:00
|
|
|
graphics.fademode = FADE_START_FADEIN;
|
2021-09-07 03:56:39 +02:00
|
|
|
game.creditposition = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "finalmode")
|
|
|
|
{
|
|
|
|
map.finalmode = true;
|
|
|
|
map.gotoroom(ss_toi(words[1]), ss_toi(words[2]));
|
|
|
|
}
|
|
|
|
else if (words[0] == "rescued")
|
|
|
|
{
|
|
|
|
if (words[1] == "red")
|
|
|
|
{
|
|
|
|
game.crewstats[3] = true;
|
|
|
|
}
|
|
|
|
else if (words[1] == "green")
|
|
|
|
{
|
|
|
|
game.crewstats[4] = true;
|
|
|
|
}
|
|
|
|
else if (words[1] == "yellow")
|
|
|
|
{
|
|
|
|
game.crewstats[2] = true;
|
|
|
|
}
|
|
|
|
else if (words[1] == "blue")
|
|
|
|
{
|
|
|
|
game.crewstats[5] = true;
|
|
|
|
}
|
|
|
|
else if (words[1] == "purple")
|
|
|
|
{
|
|
|
|
game.crewstats[1] = true;
|
|
|
|
}
|
|
|
|
else if (words[1] == "player")
|
|
|
|
{
|
|
|
|
game.crewstats[0] = true;
|
|
|
|
}
|
|
|
|
else if (words[1] == "cyan")
|
|
|
|
{
|
|
|
|
game.crewstats[0] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "missing")
|
|
|
|
{
|
|
|
|
if (words[1] == "red")
|
|
|
|
{
|
|
|
|
game.crewstats[3] = false;
|
|
|
|
}
|
|
|
|
else if (words[1] == "green")
|
|
|
|
{
|
|
|
|
game.crewstats[4] = false;
|
|
|
|
}
|
|
|
|
else if (words[1] == "yellow")
|
|
|
|
{
|
|
|
|
game.crewstats[2] = false;
|
|
|
|
}
|
|
|
|
else if (words[1] == "blue")
|
|
|
|
{
|
|
|
|
game.crewstats[5] = false;
|
|
|
|
}
|
|
|
|
else if (words[1] == "purple")
|
|
|
|
{
|
|
|
|
game.crewstats[1] = false;
|
|
|
|
}
|
|
|
|
else if (words[1] == "player")
|
|
|
|
{
|
|
|
|
game.crewstats[0] = false;
|
|
|
|
}
|
|
|
|
else if (words[1] == "cyan")
|
|
|
|
{
|
|
|
|
game.crewstats[0] = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "face")
|
|
|
|
{
|
|
|
|
int crewmate = getcrewmanfromname(words[1]);
|
|
|
|
if (crewmate != -1) i = crewmate; // Ensure AEM is kept
|
|
|
|
|
|
|
|
crewmate = getcrewmanfromname(words[2]);
|
|
|
|
if (crewmate != -1) j = crewmate; // Ensure AEM is kept
|
|
|
|
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities) && INBOUNDS_VEC(j, obj.entities) && obj.entities[j].xp > obj.entities[i].xp + 5)
|
|
|
|
{
|
|
|
|
obj.entities[i].dir = 1;
|
|
|
|
}
|
|
|
|
else if (INBOUNDS_VEC(i, obj.entities) && INBOUNDS_VEC(j, obj.entities) && obj.entities[j].xp < obj.entities[i].xp - 5)
|
|
|
|
{
|
|
|
|
obj.entities[i].dir = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "jukebox")
|
|
|
|
{
|
|
|
|
for (j = 0; j < (int) obj.entities.size(); j++)
|
|
|
|
{
|
|
|
|
if (obj.entities[j].type == 13)
|
|
|
|
{
|
|
|
|
obj.entities[j].colour = 4;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ss_toi(words[1]) == 1)
|
|
|
|
{
|
|
|
|
obj.createblock(5, 88 - 4, 80, 20, 16, 25);
|
|
|
|
for (j = 0; j < (int) obj.entities.size(); j++)
|
|
|
|
{
|
|
|
|
if (obj.entities[j].xp == 88 && obj.entities[j].yp==80)
|
|
|
|
{
|
|
|
|
obj.entities[j].colour = 5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (ss_toi(words[1]) == 2)
|
|
|
|
{
|
|
|
|
obj.createblock(5, 128 - 4, 80, 20, 16, 26);
|
|
|
|
for (j = 0; j < (int) obj.entities.size(); j++)
|
|
|
|
{
|
|
|
|
if (obj.entities[j].xp == 128 && obj.entities[j].yp==80)
|
|
|
|
{
|
|
|
|
obj.entities[j].colour = 5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (ss_toi(words[1]) == 3)
|
|
|
|
{
|
|
|
|
obj.createblock(5, 176 - 4, 80, 20, 16, 27);
|
|
|
|
for (j = 0; j < (int) obj.entities.size(); j++)
|
|
|
|
{
|
|
|
|
if (obj.entities[j].xp == 176 && obj.entities[j].yp==80)
|
|
|
|
{
|
|
|
|
obj.entities[j].colour = 5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (ss_toi(words[1]) == 4)
|
|
|
|
{
|
|
|
|
obj.createblock(5, 216 - 4, 80, 20, 16, 28);
|
|
|
|
for (j = 0; j < (int) obj.entities.size(); j++)
|
|
|
|
{
|
|
|
|
if (obj.entities[j].xp == 216 && obj.entities[j].yp==80)
|
|
|
|
{
|
|
|
|
obj.entities[j].colour = 5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (ss_toi(words[1]) == 5)
|
|
|
|
{
|
|
|
|
obj.createblock(5, 88 - 4, 128, 20, 16, 29);
|
|
|
|
for (j = 0; j < (int) obj.entities.size(); j++)
|
|
|
|
{
|
|
|
|
if (obj.entities[j].xp == 88 && obj.entities[j].yp==128)
|
|
|
|
{
|
|
|
|
obj.entities[j].colour = 5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (ss_toi(words[1]) == 6)
|
|
|
|
{
|
|
|
|
obj.createblock(5, 176 - 4, 128, 20, 16, 30);
|
|
|
|
for (j = 0; j < (int) obj.entities.size(); j++)
|
|
|
|
{
|
|
|
|
if (obj.entities[j].xp == 176 && obj.entities[j].yp==128)
|
|
|
|
{
|
|
|
|
obj.entities[j].colour = 5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (ss_toi(words[1]) == 7)
|
|
|
|
{
|
|
|
|
obj.createblock(5, 40 - 4, 40, 20, 16, 31);
|
|
|
|
for (j = 0; j < (int) obj.entities.size(); j++)
|
|
|
|
{
|
|
|
|
if (obj.entities[j].xp == 40 && obj.entities[j].yp==40)
|
|
|
|
{
|
|
|
|
obj.entities[j].colour = 5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (ss_toi(words[1]) == 8)
|
|
|
|
{
|
|
|
|
obj.createblock(5, 216 - 4, 128, 20, 16, 32);
|
|
|
|
for (j = 0; j < (int) obj.entities.size(); j++)
|
|
|
|
{
|
|
|
|
if (obj.entities[j].xp == 216 && obj.entities[j].yp==128)
|
|
|
|
{
|
|
|
|
obj.entities[j].colour = 5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (ss_toi(words[1]) == 9)
|
|
|
|
{
|
|
|
|
obj.createblock(5, 128 - 4, 128, 20, 16, 33);
|
|
|
|
for (j = 0; j < (int) obj.entities.size(); j++)
|
|
|
|
{
|
|
|
|
if (obj.entities[j].xp == 128 && obj.entities[j].yp==128)
|
|
|
|
{
|
|
|
|
obj.entities[j].colour = 5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (ss_toi(words[1]) == 10)
|
|
|
|
{
|
|
|
|
obj.createblock(5, 264 - 4, 40, 20, 16, 34);
|
|
|
|
for (j = 0; j < (int) obj.entities.size(); j++)
|
|
|
|
{
|
|
|
|
if (obj.entities[j].xp == 264 && obj.entities[j].yp==40)
|
|
|
|
{
|
|
|
|
obj.entities[j].colour = 5;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "createactivityzone")
|
|
|
|
{
|
|
|
|
int crew_color = i; // stay consistent with past behavior!
|
|
|
|
if (words[1] == "red")
|
|
|
|
{
|
|
|
|
i = 3;
|
|
|
|
crew_color = RED;
|
|
|
|
}
|
|
|
|
else if (words[1] == "green")
|
|
|
|
{
|
|
|
|
i = 4;
|
|
|
|
crew_color = GREEN;
|
|
|
|
}
|
|
|
|
else if (words[1] == "yellow")
|
|
|
|
{
|
|
|
|
i = 2;
|
|
|
|
crew_color = YELLOW;
|
|
|
|
}
|
|
|
|
else if (words[1] == "blue")
|
|
|
|
{
|
|
|
|
i = 5;
|
|
|
|
crew_color = BLUE;
|
|
|
|
}
|
|
|
|
else if (words[1] == "purple")
|
|
|
|
{
|
|
|
|
i = 1;
|
|
|
|
crew_color = PURPLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int crewman = obj.getcrewman(crew_color);
|
|
|
|
if (INBOUNDS_VEC(crewman, obj.entities) && crew_color == GREEN)
|
|
|
|
{
|
|
|
|
obj.createblock(5, obj.entities[crewman].xp - 32, obj.entities[crewman].yp-20, 96, 60, i, "", (i == 35));
|
|
|
|
}
|
|
|
|
else if (INBOUNDS_VEC(crewman, obj.entities))
|
|
|
|
{
|
|
|
|
obj.createblock(5, obj.entities[crewman].xp - 32, 0, 96, 240, i, "", (i == 35));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "setactivitycolour")
|
|
|
|
{
|
|
|
|
obj.customactivitycolour = words[1];
|
|
|
|
}
|
|
|
|
else if (words[0] == "setactivitytext")
|
|
|
|
{
|
|
|
|
++position;
|
|
|
|
if (INBOUNDS_VEC(position, commands))
|
|
|
|
{
|
|
|
|
obj.customactivitytext = commands[position];
|
|
|
|
}
|
|
|
|
}
|
Add `setactivityposition(x,y)`, add new textbox color `transparent` (#847)
* Add `setactivityposition(x,y)`, add new textbox color `transparent`
This commit adds a new internal command as a part of the visual activity zone changes I've been making.
This one allows the user to reposition the activity zone to anywhere on the screen.
In addition, this commit adds the textbox color `transparent`, which just sets r, g and b to 0.
rgb(0, 0, 0) normally creates the color black, however in VVVVVV textboxes, it makes the background
of them invisible, and makes the text the off-white color which the game uses elsewhere.
* add new variables to hardreset
* Fix unwanted text centering; offset position by 16, 4
It makes sense for `setactivityposition(0, 0)` to place the activity zone in the default position,
so the x has been offset by 16, and the y has been offset by 4.
Text was being automatically centered, meaning any activity zone which wasn't centered had misplaced text.
This has been fixed by calculating the center manually, and offsetting it by the passed value.
2021-10-14 00:38:51 +02:00
|
|
|
else if (words[0] == "setactivityposition")
|
|
|
|
{
|
|
|
|
obj.customactivitypositionx = ss_toi(words[1]);
|
|
|
|
obj.customactivitypositiony = ss_toi(words[2]);
|
|
|
|
}
|
2021-09-07 03:56:39 +02:00
|
|
|
else if (words[0] == "createrescuedcrew")
|
|
|
|
{
|
|
|
|
//special for final level cutscene
|
|
|
|
//starting at 180, create the rescued crewmembers (ingoring violet, who's at 155)
|
|
|
|
i = 215;
|
|
|
|
if (game.crewstats[2] && game.lastsaved!=2)
|
|
|
|
{
|
|
|
|
obj.createentity(i, 153, 18, 14, 0, 17, 0);
|
|
|
|
i += 25;
|
|
|
|
}
|
|
|
|
if (game.crewstats[3] && game.lastsaved!=3)
|
|
|
|
{
|
|
|
|
obj.createentity(i, 153, 18, 15, 0, 17, 0);
|
|
|
|
i += 25;
|
|
|
|
}
|
|
|
|
if (game.crewstats[4] && game.lastsaved!=4)
|
|
|
|
{
|
|
|
|
obj.createentity(i, 153, 18, 13, 0, 17, 0);
|
|
|
|
i += 25;
|
|
|
|
}
|
|
|
|
if (game.crewstats[5] && game.lastsaved!=5)
|
|
|
|
{
|
|
|
|
obj.createentity(i, 153, 18, 16, 0, 17, 0);
|
|
|
|
i += 25;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "restoreplayercolour")
|
|
|
|
{
|
|
|
|
i = obj.getplayer();
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[i].colour = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "changeplayercolour")
|
|
|
|
{
|
|
|
|
i = obj.getplayer();
|
|
|
|
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[i].colour = getcolorfromname(words[1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "changerespawncolour")
|
|
|
|
{
|
|
|
|
game.savecolour = getcolorfromname(words[1]);
|
|
|
|
}
|
|
|
|
else if (words[0] == "altstates")
|
|
|
|
{
|
|
|
|
obj.altstates = ss_toi(words[1]);
|
|
|
|
}
|
|
|
|
else if (words[0] == "activeteleporter")
|
|
|
|
{
|
|
|
|
i = obj.getteleporter();
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[i].colour = 101;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "foundtrinket")
|
|
|
|
{
|
|
|
|
music.silencedasmusik();
|
|
|
|
music.playef(3);
|
|
|
|
|
|
|
|
size_t trinket = ss_toi(words[1]);
|
|
|
|
if (trinket < SDL_arraysize(obj.collect))
|
|
|
|
{
|
|
|
|
obj.collect[trinket] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
graphics.textboxremovefast();
|
|
|
|
|
|
|
|
graphics.createtextboxflipme(" Congratulations! ", 50, 85, 174, 174, 174);
|
|
|
|
graphics.addline("");
|
|
|
|
graphics.addline("You have found a shiny trinket!");
|
|
|
|
graphics.textboxcenterx();
|
|
|
|
|
|
|
|
std::string usethisnum;
|
2020-04-09 06:56:47 +02:00
|
|
|
#if !defined(NO_CUSTOM_LEVELS)
|
2021-09-07 03:56:39 +02:00
|
|
|
if (map.custommode)
|
|
|
|
{
|
2021-09-26 00:08:13 +02:00
|
|
|
usethisnum = help.number_words(cl.numtrinkets());
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else
|
2020-04-09 06:56:47 +02:00
|
|
|
#endif
|
2021-09-07 03:56:39 +02:00
|
|
|
{
|
|
|
|
usethisnum = "Twenty";
|
|
|
|
}
|
2021-09-26 00:08:13 +02:00
|
|
|
graphics.createtextboxflipme(" " + help.number_words(game.trinkets()) + " out of " + usethisnum + " ", 50, 135, 174, 174, 174);
|
2021-09-07 03:56:39 +02:00
|
|
|
graphics.textboxcenterx();
|
|
|
|
|
|
|
|
if (!game.backgroundtext)
|
|
|
|
{
|
|
|
|
game.advancetext = true;
|
|
|
|
game.hascontrol = false;
|
|
|
|
game.pausescript = true;
|
|
|
|
if (key.isDown(90) || key.isDown(32) || key.isDown(86)
|
|
|
|
|| key.isDown(KEYBOARD_UP) || key.isDown(KEYBOARD_DOWN)) game.jumpheld = true;
|
|
|
|
}
|
|
|
|
game.backgroundtext = false;
|
|
|
|
}
|
|
|
|
else if (words[0] == "foundlab")
|
|
|
|
{
|
|
|
|
music.playef(3);
|
|
|
|
|
|
|
|
graphics.textboxremovefast();
|
|
|
|
|
|
|
|
graphics.createtextbox(" Congratulations! ", 50, 85, 174, 174, 174);
|
|
|
|
graphics.addline("");
|
|
|
|
graphics.addline("You have found the secret lab!");
|
|
|
|
graphics.textboxcenterx();
|
|
|
|
graphics.textboxcentery();
|
|
|
|
|
|
|
|
if (!game.backgroundtext)
|
|
|
|
{
|
|
|
|
game.advancetext = true;
|
|
|
|
game.hascontrol = false;
|
|
|
|
game.pausescript = true;
|
|
|
|
if (key.isDown(90) || key.isDown(32) || key.isDown(86)
|
|
|
|
|| key.isDown(KEYBOARD_UP) || key.isDown(KEYBOARD_DOWN)) game.jumpheld = true;
|
|
|
|
}
|
|
|
|
game.backgroundtext = false;
|
|
|
|
}
|
|
|
|
else if (words[0] == "foundlab2")
|
|
|
|
{
|
|
|
|
graphics.textboxremovefast();
|
|
|
|
|
|
|
|
graphics.createtextbox("The secret lab is separate from", 50, 85, 174, 174, 174);
|
|
|
|
graphics.addline("the rest of the game. You can");
|
|
|
|
graphics.addline("now come back here at any time");
|
|
|
|
graphics.addline("by selecting the new SECRET LAB");
|
|
|
|
graphics.addline("option in the play menu.");
|
|
|
|
graphics.textboxcenterx();
|
|
|
|
graphics.textboxcentery();
|
|
|
|
|
|
|
|
if (!game.backgroundtext)
|
|
|
|
{
|
|
|
|
game.advancetext = true;
|
|
|
|
game.hascontrol = false;
|
|
|
|
game.pausescript = true;
|
|
|
|
if (key.isDown(90) || key.isDown(32) || key.isDown(86)
|
|
|
|
|| key.isDown(KEYBOARD_UP) || key.isDown(KEYBOARD_DOWN)) game.jumpheld = true;
|
|
|
|
}
|
|
|
|
game.backgroundtext = false;
|
|
|
|
}
|
|
|
|
else if (words[0] == "everybodysad")
|
|
|
|
{
|
|
|
|
for (i = 0; i < (int) obj.entities.size(); i++)
|
|
|
|
{
|
|
|
|
if (obj.entities[i].rule == 6 || obj.entities[i].rule == 0)
|
|
|
|
{
|
|
|
|
obj.entities[i].tile = 144;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "startintermission2")
|
|
|
|
{
|
|
|
|
map.finalmode = true; //Enable final level mode
|
|
|
|
|
|
|
|
game.savex = 228;
|
|
|
|
game.savey = 129;
|
|
|
|
game.saverx = 53;
|
|
|
|
game.savery = 49;
|
|
|
|
game.savegc = 0;
|
|
|
|
game.savedir = 0; //Intermission level 2
|
|
|
|
game.savepoint = 0;
|
|
|
|
game.gravitycontrol = 0;
|
|
|
|
|
|
|
|
map.gotoroom(46, 54);
|
|
|
|
}
|
|
|
|
else if (words[0] == "telesave")
|
|
|
|
{
|
|
|
|
if (!game.intimetrial && !game.nodeathmode && !game.inintermission) game.savetele();
|
|
|
|
}
|
|
|
|
else if (words[0] == "createlastrescued")
|
|
|
|
{
|
|
|
|
r = graphics.crewcolour(game.lastsaved);
|
|
|
|
if (r == 0 || r == PURPLE)
|
|
|
|
{
|
|
|
|
r = GRAY; // Default to gray if invalid color.
|
|
|
|
}
|
|
|
|
|
|
|
|
obj.createentity(200, 153, 18, r, 0, 19, 30);
|
|
|
|
i = obj.getcrewman(game.lastsaved);
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[i].dir = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "specialline")
|
|
|
|
{
|
|
|
|
switch(ss_toi(words[1]))
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
txt.resize(1);
|
|
|
|
|
|
|
|
txt[0] = "I'm worried about " + game.unrescued() + ", Doctor!";
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
txt.resize(3);
|
|
|
|
|
|
|
|
if (game.crewrescued() < 5)
|
|
|
|
{
|
|
|
|
txt[1] = "to helping you find the";
|
|
|
|
txt[2] = "rest of the crew!";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
txt.resize(2);
|
|
|
|
txt[1] = "to helping you find " + game.unrescued() + "!";
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "trinketbluecontrol")
|
|
|
|
{
|
|
|
|
if (game.trinkets() == 20 && obj.flags[67])
|
|
|
|
{
|
|
|
|
load("talkblue_trinket6");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (game.trinkets() >= 19 && !obj.flags[67])
|
|
|
|
{
|
|
|
|
load("talkblue_trinket5");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
load("talkblue_trinket4");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "trinketyellowcontrol")
|
|
|
|
{
|
|
|
|
if (game.trinkets() >= 19)
|
|
|
|
{
|
|
|
|
load("talkyellow_trinket3");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
load("talkyellow_trinket2");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "redcontrol")
|
|
|
|
{
|
|
|
|
if (game.insecretlab)
|
|
|
|
{
|
|
|
|
load("talkred_14");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (game.roomx != 104)
|
|
|
|
{
|
|
|
|
if (game.roomx == 100)
|
|
|
|
{
|
|
|
|
load("talkred_10");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (game.roomx == 107)
|
|
|
|
{
|
|
|
|
load("talkred_11");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (game.roomx == 114)
|
|
|
|
{
|
|
|
|
load("talkred_12");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (obj.flags[67])
|
|
|
|
{
|
|
|
|
//game complete
|
|
|
|
load("talkred_13");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (obj.flags[35] && !obj.flags[52])
|
|
|
|
{
|
|
|
|
//Intermission level
|
|
|
|
obj.flags[52] = true;
|
|
|
|
load("talkred_9");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[51])
|
|
|
|
{
|
|
|
|
//We're back home!
|
|
|
|
obj.flags[51] = true;
|
|
|
|
load("talkred_5");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[48] && game.crewstats[5])
|
|
|
|
{
|
|
|
|
//Victoria's back
|
|
|
|
obj.flags[48] = true;
|
|
|
|
load("talkred_6");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[49] && game.crewstats[4])
|
|
|
|
{
|
|
|
|
//Verdigris' back
|
|
|
|
obj.flags[49] = true;
|
|
|
|
load("talkred_7");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[50] && game.crewstats[2])
|
|
|
|
{
|
|
|
|
//Vitellary's back
|
|
|
|
obj.flags[50] = true;
|
|
|
|
load("talkred_8");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[45] && !game.crewstats[5])
|
|
|
|
{
|
|
|
|
obj.flags[45] = true;
|
|
|
|
load("talkred_2");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[46] && !game.crewstats[4])
|
|
|
|
{
|
|
|
|
obj.flags[46] = true;
|
|
|
|
load("talkred_3");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[47] && !game.crewstats[2])
|
|
|
|
{
|
|
|
|
obj.flags[47] = true;
|
|
|
|
load("talkred_4");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
obj.flags[45] = false;
|
|
|
|
obj.flags[46] = false;
|
|
|
|
obj.flags[47] = false;
|
|
|
|
load("talkred_1");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//TODO: Non Urgent fix compiler nesting errors without adding complexity
|
|
|
|
if (words[0] == "greencontrol")
|
|
|
|
{
|
|
|
|
if (game.insecretlab)
|
|
|
|
{
|
|
|
|
load("talkgreen_11");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (game.roomx == 103 && game.roomy == 109)
|
|
|
|
{
|
|
|
|
load("talkgreen_8");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (game.roomx == 101 && game.roomy == 109)
|
|
|
|
{
|
|
|
|
load("talkgreen_9");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (obj.flags[67])
|
|
|
|
{
|
|
|
|
//game complete
|
|
|
|
load("talkgreen_10");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (obj.flags[34] && !obj.flags[57])
|
|
|
|
{
|
|
|
|
//Intermission level
|
|
|
|
obj.flags[57] = true;
|
|
|
|
load("talkgreen_7");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[53])
|
|
|
|
{
|
|
|
|
//Home!
|
|
|
|
obj.flags[53] = true;
|
|
|
|
load("talkgreen_6");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[54] && game.crewstats[2])
|
|
|
|
{
|
|
|
|
obj.flags[54] = true;
|
|
|
|
load("talkgreen_5");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[55] && game.crewstats[3])
|
|
|
|
{
|
|
|
|
obj.flags[55] = true;
|
|
|
|
load("talkgreen_4");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[56] && game.crewstats[5])
|
|
|
|
{
|
|
|
|
obj.flags[56] = true;
|
|
|
|
load("talkgreen_3");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[58])
|
|
|
|
{
|
|
|
|
obj.flags[58] = true;
|
|
|
|
load("talkgreen_2");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
load("talkgreen_1");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "bluecontrol")
|
|
|
|
{
|
|
|
|
if (game.insecretlab)
|
|
|
|
{
|
|
|
|
load("talkblue_9");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (obj.flags[67])
|
|
|
|
{
|
|
|
|
//game complete, everything changes for victoria
|
|
|
|
if (obj.flags[41] && !obj.flags[42])
|
|
|
|
{
|
|
|
|
//second trinket conversation
|
|
|
|
obj.flags[42] = true;
|
|
|
|
load("talkblue_trinket2");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[41] && !obj.flags[42])
|
|
|
|
{
|
|
|
|
//Third trinket conversation
|
|
|
|
obj.flags[42] = true;
|
|
|
|
load("talkblue_trinket3");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//Ok, we've already dealt with the trinket thing; so either you have them all, or you don't. If you do:
|
|
|
|
if (game.trinkets() >= 20)
|
|
|
|
{
|
|
|
|
load("startepilogue");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
load("talkblue_8");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (obj.flags[33] && !obj.flags[40])
|
|
|
|
{
|
|
|
|
//Intermission level
|
|
|
|
obj.flags[40] = true;
|
|
|
|
load("talkblue_7");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[36] && game.crewstats[5])
|
|
|
|
{
|
|
|
|
//Back on the ship!
|
|
|
|
obj.flags[36] = true;
|
|
|
|
load("talkblue_3");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[41] && game.crewrescued() <= 4)
|
|
|
|
{
|
|
|
|
//First trinket conversation
|
|
|
|
obj.flags[41] = true;
|
|
|
|
load("talkblue_trinket1");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (obj.flags[41] && !obj.flags[42] && game.crewrescued() == 5)
|
|
|
|
{
|
|
|
|
//second trinket conversation
|
|
|
|
obj.flags[42] = true;
|
|
|
|
load("talkblue_trinket2");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[41] && !obj.flags[42] && game.crewrescued() == 5)
|
|
|
|
{
|
|
|
|
//Third trinket conversation
|
|
|
|
obj.flags[42] = true;
|
|
|
|
load("talkblue_trinket3");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[37] && game.crewstats[2])
|
|
|
|
{
|
|
|
|
obj.flags[37] = true;
|
|
|
|
load("talkblue_4");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[38] && game.crewstats[3])
|
|
|
|
{
|
|
|
|
obj.flags[38] = true;
|
|
|
|
load("talkblue_5");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[39] && game.crewstats[4])
|
|
|
|
{
|
|
|
|
obj.flags[39] = true;
|
|
|
|
load("talkblue_6");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//if all else fails:
|
|
|
|
//if yellow is found
|
|
|
|
if (game.crewstats[2])
|
|
|
|
{
|
|
|
|
load("talkblue_2");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
load("talkblue_1");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "yellowcontrol")
|
|
|
|
{
|
|
|
|
if (game.insecretlab)
|
|
|
|
{
|
|
|
|
load("talkyellow_12");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (obj.flags[67])
|
|
|
|
{
|
|
|
|
//game complete
|
|
|
|
load("talkyellow_11");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (obj.flags[32] && !obj.flags[31])
|
|
|
|
{
|
|
|
|
//Intermission level
|
|
|
|
obj.flags[31] = true;
|
|
|
|
load("talkyellow_6");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[27] && game.crewstats[2])
|
|
|
|
{
|
|
|
|
//Back on the ship!
|
|
|
|
obj.flags[27] = true;
|
|
|
|
load("talkyellow_10");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[43] && game.crewrescued() == 5 && !game.crewstats[5])
|
|
|
|
{
|
|
|
|
//If by chance we've rescued everyone except Victoria by the end, Vitellary provides you with
|
|
|
|
//the trinket information instead.
|
|
|
|
obj.flags[43] = true;
|
|
|
|
obj.flags[42] = true;
|
|
|
|
obj.flags[41] = true;
|
|
|
|
load("talkyellow_trinket1");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[24] && game.crewstats[5])
|
|
|
|
{
|
|
|
|
obj.flags[24] = true;
|
|
|
|
load("talkyellow_8");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[26] && game.crewstats[4])
|
|
|
|
{
|
|
|
|
obj.flags[26] = true;
|
|
|
|
load("talkyellow_7");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[25] && game.crewstats[3])
|
|
|
|
{
|
|
|
|
obj.flags[25] = true;
|
|
|
|
load("talkyellow_9");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[28])
|
|
|
|
{
|
|
|
|
obj.flags[28] = true;
|
|
|
|
load("talkyellow_3");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[29])
|
|
|
|
{
|
|
|
|
obj.flags[29] = true;
|
|
|
|
load("talkyellow_4");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[30])
|
|
|
|
{
|
|
|
|
obj.flags[30] = true;
|
|
|
|
load("talkyellow_5");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[23])
|
|
|
|
{
|
|
|
|
obj.flags[23] = true;
|
|
|
|
load("talkyellow_2");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
load("talkyellow_1");
|
|
|
|
position--;
|
|
|
|
obj.flags[23] = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (words[0] == "purplecontrol")
|
|
|
|
{
|
|
|
|
//Controls Purple's conversion
|
|
|
|
//Crew rescued:
|
|
|
|
if (game.insecretlab)
|
|
|
|
{
|
|
|
|
load("talkpurple_9");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (obj.flags[67])
|
|
|
|
{
|
|
|
|
//game complete
|
|
|
|
load("talkpurple_8");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[17] && game.crewstats[4])
|
|
|
|
{
|
|
|
|
obj.flags[17] = true;
|
|
|
|
load("talkpurple_6");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[15] && game.crewstats[5])
|
|
|
|
{
|
|
|
|
obj.flags[15] = true;
|
|
|
|
load("talkpurple_4");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[16] && game.crewstats[3])
|
|
|
|
{
|
|
|
|
obj.flags[16] = true;
|
|
|
|
load("talkpurple_5");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[18] && game.crewstats[2])
|
|
|
|
{
|
|
|
|
obj.flags[18] = true;
|
|
|
|
load("talkpurple_7");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (obj.flags[19] && !obj.flags[20] && !obj.flags[21])
|
|
|
|
{
|
|
|
|
//intermission one: if played one / not had first conversation / not played two [conversation one]
|
|
|
|
obj.flags[21] = true;
|
|
|
|
load("talkpurple_intermission1");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (obj.flags[20] && obj.flags[21] && !obj.flags[22])
|
|
|
|
{
|
|
|
|
//intermission two: if played two / had first conversation / not had second conversation [conversation two]
|
|
|
|
obj.flags[22] = true;
|
|
|
|
load("talkpurple_intermission2");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (obj.flags[20] && !obj.flags[21] && !obj.flags[22])
|
|
|
|
{
|
|
|
|
//intermission two: if played two / not had first conversation / not had second conversation [conversation three]
|
|
|
|
obj.flags[22] = true;
|
|
|
|
load("talkpurple_intermission3");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[12])
|
|
|
|
{
|
|
|
|
//Intro conversation
|
|
|
|
obj.flags[12] = true;
|
|
|
|
load("talkpurple_intro");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else if (!obj.flags[14])
|
|
|
|
{
|
|
|
|
//Shorter intro conversation
|
|
|
|
obj.flags[14] = true;
|
|
|
|
load("talkpurple_3");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//if all else fails:
|
|
|
|
//if green is found
|
|
|
|
if (game.crewstats[4])
|
|
|
|
{
|
|
|
|
load("talkpurple_2");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
load("talkpurple_1");
|
|
|
|
position--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
position++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
running = false;
|
|
|
|
}
|
|
|
|
// Don't increment if we're at the max, signed int overflow is UB
|
|
|
|
if (execution_counter == SHRT_MAX)
|
|
|
|
{
|
|
|
|
// We must be in an infinite loop
|
|
|
|
vlog_warn("Warning: execution counter got to %i, stopping script", SHRT_MAX);
|
|
|
|
running = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
execution_counter++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(scriptdelay>0)
|
|
|
|
{
|
|
|
|
scriptdelay--;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void scriptclass::resetgametomenu(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
obj.entities.clear();
|
|
|
|
game.quittomenu();
|
|
|
|
game.createmenu(Menu::gameover);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2021-08-07 05:57:34 +02:00
|
|
|
static void gotoerrorloadinglevel(void)
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
game.createmenu(Menu::errorloadinglevel);
|
|
|
|
map.nexttowercolour();
|
Enumify all fade modes
This removes the magic numbers previously used for controlling the fade
mode, which are really not readable at all unless you already know what
they mean.
0: FADE_NONE
1: FADE_FULLY_BLACK
2: FADE_START_FADEOUT
3: FADE_FADING_OUT
4: FADE_START_FADEIN
5: FADE_FADING_IN
There is also the macro FADEMODE_IS_FADING, which indicates when the
intention is to only check if the game is fading right now, which wasn't
clearly conveyed previously.
I also took the opportunity to clean up the style of any lines I
touched. This included rewriting if-else chains into case-switches,
turning one-liner if-then statements into proper blocks, fixing up
comments, and even commenting the `fademode == FADE_NONE` on the tower
spike checks (which, it was previously undocumented why that check was
there, but I think I know why it's there).
As for type safety, we already get some by transforming the variable
types into the enum. Assignment is prohibited without a cast. But,
apparently, comparison is perfectly legal and won't even give so much as
a warning. To work around this and make absolutely sure I made all
existing comparisons now use the enum, I temporarily changed it to be an
`enum class`, which is a C++11 feature that makes it so all comparisons
are illegal. Unfortunately, it scopes them in a namespace with the same
name as a class, so I had to temporarily define macros to make sure my
existing code worked. I also had to temporarily up the standard in
CMakeLists.txt to get it to compile. But after all that was done, I
found the rest of the places where a comparison to an integer was used,
and fixed them.
2022-04-25 09:57:47 +02:00
|
|
|
graphics.fademode = FADE_START_FADEIN; /* start fade in */
|
2021-09-07 03:56:39 +02:00
|
|
|
music.currentsong = -1; /* otherwise music.play won't work */
|
|
|
|
music.play(6); /* title screen music */
|
2021-08-07 05:57:34 +02:00
|
|
|
}
|
|
|
|
|
2020-03-31 21:38:52 +02:00
|
|
|
void scriptclass::startgamemode( int t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
switch(t)
|
|
|
|
{
|
|
|
|
case 0: //Normal new game
|
|
|
|
game.gamestate = GAMEMODE;
|
|
|
|
hardreset();
|
|
|
|
game.start();
|
|
|
|
game.jumpheld = true;
|
|
|
|
graphics.showcutscenebars = true;
|
|
|
|
graphics.setbars(320);
|
|
|
|
|
|
|
|
//set flipmode
|
|
|
|
if (graphics.setflipmode) graphics.flipmode = true;
|
|
|
|
else obj.flags[73] = true;
|
|
|
|
|
|
|
|
if(obj.entities.empty())
|
|
|
|
{
|
|
|
|
obj.createentity(game.savex, game.savey, 0, 0); //In this game, constant, never destroyed
|
|
|
|
}
|
|
|
|
map.resetplayer();
|
|
|
|
map.gotoroom(game.saverx, game.savery);
|
|
|
|
map.initmapdata();
|
|
|
|
|
|
|
|
load("intro");
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
game.gamestate = GAMEMODE;
|
|
|
|
hardreset();
|
|
|
|
game.start();
|
|
|
|
game.loadtele();
|
|
|
|
game.gravitycontrol = game.savegc;
|
|
|
|
game.jumpheld = true;
|
|
|
|
|
|
|
|
//set flipmode
|
|
|
|
if (graphics.setflipmode) graphics.flipmode = true;
|
|
|
|
else obj.flags[73] = true;
|
|
|
|
|
|
|
|
if(obj.entities.empty())
|
|
|
|
{
|
|
|
|
obj.createentity(game.savex, game.savey, 0, 0); //In this game, constant, never destroyed
|
|
|
|
}
|
|
|
|
map.resetplayer();
|
|
|
|
map.gotoroom(game.saverx, game.savery);
|
|
|
|
map.initmapdata();
|
Enumify all fade modes
This removes the magic numbers previously used for controlling the fade
mode, which are really not readable at all unless you already know what
they mean.
0: FADE_NONE
1: FADE_FULLY_BLACK
2: FADE_START_FADEOUT
3: FADE_FADING_OUT
4: FADE_START_FADEIN
5: FADE_FADING_IN
There is also the macro FADEMODE_IS_FADING, which indicates when the
intention is to only check if the game is fading right now, which wasn't
clearly conveyed previously.
I also took the opportunity to clean up the style of any lines I
touched. This included rewriting if-else chains into case-switches,
turning one-liner if-then statements into proper blocks, fixing up
comments, and even commenting the `fademode == FADE_NONE` on the tower
spike checks (which, it was previously undocumented why that check was
there, but I think I know why it's there).
As for type safety, we already get some by transforming the variable
types into the enum. Assignment is prohibited without a cast. But,
apparently, comparison is perfectly legal and won't even give so much as
a warning. To work around this and make absolutely sure I made all
existing comparisons now use the enum, I temporarily changed it to be an
`enum class`, which is a C++11 feature that makes it so all comparisons
are illegal. Unfortunately, it scopes them in a namespace with the same
name as a class, so I had to temporarily define macros to make sure my
existing code worked. I also had to temporarily up the standard in
CMakeLists.txt to get it to compile. But after all that was done, I
found the rest of the places where a comparison to an integer was used,
and fixed them.
2022-04-25 09:57:47 +02:00
|
|
|
graphics.fademode = FADE_START_FADEIN;
|
2021-09-07 03:56:39 +02:00
|
|
|
break;
|
|
|
|
case 2: //Load Quicksave
|
|
|
|
game.gamestate = GAMEMODE;
|
|
|
|
hardreset();
|
|
|
|
game.start();
|
|
|
|
game.loadquick();
|
|
|
|
game.gravitycontrol = game.savegc;
|
|
|
|
game.jumpheld = true;
|
|
|
|
|
|
|
|
//set flipmode
|
|
|
|
if (graphics.setflipmode) graphics.flipmode = true;
|
|
|
|
else obj.flags[73] = true;
|
|
|
|
|
|
|
|
if(obj.entities.empty())
|
|
|
|
{
|
|
|
|
obj.createentity(game.savex, game.savey, 0, 0); //In this game, constant, never destroyed
|
|
|
|
}
|
|
|
|
map.resetplayer();
|
|
|
|
map.gotoroom(game.saverx, game.savery);
|
|
|
|
map.initmapdata();
|
|
|
|
//a very special case for here needs to ensure that the tower is set correctly
|
|
|
|
if (map.towermode)
|
|
|
|
{
|
|
|
|
map.resetplayer();
|
|
|
|
|
|
|
|
i = obj.getplayer();
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
map.ypos = obj.entities[i].yp - 120;
|
|
|
|
map.oldypos = map.ypos;
|
|
|
|
}
|
|
|
|
map.setbgobjlerp(graphics.towerbg);
|
|
|
|
map.cameramode = 0;
|
|
|
|
map.colsuperstate = 0;
|
|
|
|
}
|
Enumify all fade modes
This removes the magic numbers previously used for controlling the fade
mode, which are really not readable at all unless you already know what
they mean.
0: FADE_NONE
1: FADE_FULLY_BLACK
2: FADE_START_FADEOUT
3: FADE_FADING_OUT
4: FADE_START_FADEIN
5: FADE_FADING_IN
There is also the macro FADEMODE_IS_FADING, which indicates when the
intention is to only check if the game is fading right now, which wasn't
clearly conveyed previously.
I also took the opportunity to clean up the style of any lines I
touched. This included rewriting if-else chains into case-switches,
turning one-liner if-then statements into proper blocks, fixing up
comments, and even commenting the `fademode == FADE_NONE` on the tower
spike checks (which, it was previously undocumented why that check was
there, but I think I know why it's there).
As for type safety, we already get some by transforming the variable
types into the enum. Assignment is prohibited without a cast. But,
apparently, comparison is perfectly legal and won't even give so much as
a warning. To work around this and make absolutely sure I made all
existing comparisons now use the enum, I temporarily changed it to be an
`enum class`, which is a C++11 feature that makes it so all comparisons
are illegal. Unfortunately, it scopes them in a namespace with the same
name as a class, so I had to temporarily define macros to make sure my
existing code worked. I also had to temporarily up the standard in
CMakeLists.txt to get it to compile. But after all that was done, I
found the rest of the places where a comparison to an integer was used,
and fixed them.
2022-04-25 09:57:47 +02:00
|
|
|
graphics.fademode = FADE_START_FADEIN;
|
2021-09-07 03:56:39 +02:00
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
case 4:
|
|
|
|
case 5:
|
|
|
|
case 6:
|
|
|
|
case 7:
|
|
|
|
case 8:
|
|
|
|
//Start Time Trial
|
|
|
|
music.fadeout();
|
|
|
|
|
|
|
|
hardreset();
|
|
|
|
game.nocutscenes = true;
|
|
|
|
game.intimetrial = true;
|
|
|
|
game.timetrialcountdown = 150;
|
|
|
|
game.timetrialparlost = false;
|
|
|
|
game.timetriallevel = t - 3;
|
|
|
|
|
|
|
|
switch (t)
|
|
|
|
{
|
|
|
|
case 3:
|
|
|
|
game.timetrialpar = 75;
|
|
|
|
game.timetrialshinytarget = 2;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
game.timetrialpar = 165;
|
|
|
|
game.timetrialshinytarget = 4;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
game.timetrialpar = 105;
|
|
|
|
game.timetrialshinytarget = 2;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
game.timetrialpar = 200;
|
|
|
|
game.timetrialshinytarget = 5;
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
game.timetrialpar = 120;
|
|
|
|
game.timetrialshinytarget = 1;
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
game.timetrialpar = 135;
|
|
|
|
game.timetrialshinytarget = 1;
|
|
|
|
map.finalmode = true; //Enable final level mode
|
|
|
|
map.final_colormode = false;
|
|
|
|
map.final_mapcol = 0;
|
|
|
|
map.final_colorframe = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
game.gamestate = GAMEMODE;
|
|
|
|
game.starttrial(game.timetriallevel);
|
|
|
|
game.jumpheld = true;
|
|
|
|
|
|
|
|
if (graphics.setflipmode) graphics.flipmode = true;//set flipmode
|
|
|
|
if (obj.entities.empty())
|
|
|
|
{
|
|
|
|
obj.createentity(game.savex, game.savey, 0, 0); //In this game, constant, never destroyed
|
|
|
|
}
|
|
|
|
map.resetplayer();
|
|
|
|
map.gotoroom(game.saverx, game.savery);
|
|
|
|
map.initmapdata();
|
Enumify all fade modes
This removes the magic numbers previously used for controlling the fade
mode, which are really not readable at all unless you already know what
they mean.
0: FADE_NONE
1: FADE_FULLY_BLACK
2: FADE_START_FADEOUT
3: FADE_FADING_OUT
4: FADE_START_FADEIN
5: FADE_FADING_IN
There is also the macro FADEMODE_IS_FADING, which indicates when the
intention is to only check if the game is fading right now, which wasn't
clearly conveyed previously.
I also took the opportunity to clean up the style of any lines I
touched. This included rewriting if-else chains into case-switches,
turning one-liner if-then statements into proper blocks, fixing up
comments, and even commenting the `fademode == FADE_NONE` on the tower
spike checks (which, it was previously undocumented why that check was
there, but I think I know why it's there).
As for type safety, we already get some by transforming the variable
types into the enum. Assignment is prohibited without a cast. But,
apparently, comparison is perfectly legal and won't even give so much as
a warning. To work around this and make absolutely sure I made all
existing comparisons now use the enum, I temporarily changed it to be an
`enum class`, which is a C++11 feature that makes it so all comparisons
are illegal. Unfortunately, it scopes them in a namespace with the same
name as a class, so I had to temporarily define macros to make sure my
existing code worked. I also had to temporarily up the standard in
CMakeLists.txt to get it to compile. But after all that was done, I
found the rest of the places where a comparison to an integer was used,
and fixed them.
2022-04-25 09:57:47 +02:00
|
|
|
graphics.fademode = FADE_START_FADEIN;
|
2021-09-07 03:56:39 +02:00
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
game.gamestate = GAMEMODE;
|
|
|
|
hardreset();
|
|
|
|
game.nodeathmode = true;
|
|
|
|
game.start();
|
|
|
|
game.jumpheld = true;
|
|
|
|
graphics.showcutscenebars = true;
|
|
|
|
graphics.setbars(320);
|
|
|
|
|
|
|
|
//set flipmode
|
|
|
|
if (graphics.setflipmode) graphics.flipmode = true;
|
|
|
|
|
|
|
|
if(obj.entities.empty())
|
|
|
|
{
|
|
|
|
obj.createentity(game.savex, game.savey, 0, 0); //In this game, constant, never destroyed
|
|
|
|
}
|
|
|
|
map.resetplayer();
|
|
|
|
map.gotoroom(game.saverx, game.savery);
|
|
|
|
map.initmapdata();
|
|
|
|
|
|
|
|
|
|
|
|
load("intro");
|
|
|
|
break;
|
|
|
|
case 10:
|
|
|
|
game.gamestate = GAMEMODE;
|
|
|
|
hardreset();
|
|
|
|
game.nodeathmode = true;
|
|
|
|
game.nocutscenes = true;
|
|
|
|
|
|
|
|
game.start();
|
|
|
|
game.jumpheld = true;
|
|
|
|
graphics.showcutscenebars = true;
|
|
|
|
graphics.setbars(320);
|
|
|
|
|
|
|
|
//set flipmode
|
|
|
|
if (graphics.setflipmode) graphics.flipmode = true;
|
|
|
|
|
|
|
|
if(obj.entities.empty())
|
|
|
|
{
|
|
|
|
obj.createentity(game.savex, game.savey, 0, 0); //In this game, constant, never destroyed
|
|
|
|
}
|
|
|
|
map.resetplayer();
|
|
|
|
map.gotoroom(game.saverx, game.savery);
|
|
|
|
map.initmapdata();
|
|
|
|
|
|
|
|
|
|
|
|
load("intro");
|
|
|
|
break;
|
|
|
|
case 11:
|
|
|
|
game.gamestate = GAMEMODE;
|
|
|
|
hardreset();
|
|
|
|
|
|
|
|
game.startspecial(0);
|
|
|
|
game.jumpheld = true;
|
|
|
|
|
|
|
|
//Secret lab, so reveal the map, give them all 20 trinkets
|
|
|
|
SDL_memset(obj.collect, true, sizeof(obj.collect[0]) * 20);
|
|
|
|
SDL_memset(map.explored, true, sizeof(map.explored));
|
|
|
|
i = 400; /* previously a nested for-loop set this */
|
|
|
|
game.insecretlab = true;
|
|
|
|
map.showteleporters = true;
|
|
|
|
|
|
|
|
//set flipmode
|
|
|
|
if (graphics.setflipmode) graphics.flipmode = true;
|
|
|
|
|
|
|
|
if(obj.entities.empty())
|
|
|
|
{
|
|
|
|
obj.createentity(game.savex, game.savey, 0, 0); //In this game, constant, never destroyed
|
|
|
|
}
|
|
|
|
map.resetplayer();
|
|
|
|
map.gotoroom(game.saverx, game.savery);
|
|
|
|
map.initmapdata();
|
|
|
|
music.play(11);
|
Enumify all fade modes
This removes the magic numbers previously used for controlling the fade
mode, which are really not readable at all unless you already know what
they mean.
0: FADE_NONE
1: FADE_FULLY_BLACK
2: FADE_START_FADEOUT
3: FADE_FADING_OUT
4: FADE_START_FADEIN
5: FADE_FADING_IN
There is also the macro FADEMODE_IS_FADING, which indicates when the
intention is to only check if the game is fading right now, which wasn't
clearly conveyed previously.
I also took the opportunity to clean up the style of any lines I
touched. This included rewriting if-else chains into case-switches,
turning one-liner if-then statements into proper blocks, fixing up
comments, and even commenting the `fademode == FADE_NONE` on the tower
spike checks (which, it was previously undocumented why that check was
there, but I think I know why it's there).
As for type safety, we already get some by transforming the variable
types into the enum. Assignment is prohibited without a cast. But,
apparently, comparison is perfectly legal and won't even give so much as
a warning. To work around this and make absolutely sure I made all
existing comparisons now use the enum, I temporarily changed it to be an
`enum class`, which is a C++11 feature that makes it so all comparisons
are illegal. Unfortunately, it scopes them in a namespace with the same
name as a class, so I had to temporarily define macros to make sure my
existing code worked. I also had to temporarily up the standard in
CMakeLists.txt to get it to compile. But after all that was done, I
found the rest of the places where a comparison to an integer was used,
and fixed them.
2022-04-25 09:57:47 +02:00
|
|
|
graphics.fademode = FADE_START_FADEIN;
|
2021-09-07 03:56:39 +02:00
|
|
|
break;
|
|
|
|
case 12:
|
|
|
|
game.gamestate = GAMEMODE;
|
|
|
|
hardreset();
|
|
|
|
music.fadeout();
|
|
|
|
|
|
|
|
game.lastsaved = 2;
|
|
|
|
|
|
|
|
game.crewstats[game.lastsaved] = true;
|
|
|
|
game.inintermission = true;
|
|
|
|
game.companion = 11;
|
|
|
|
game.supercrewmate = true;
|
|
|
|
game.scmprogress = 0;
|
|
|
|
map.finalmode = true;
|
|
|
|
map.final_colormode = false;
|
|
|
|
map.final_mapcol = 0;
|
|
|
|
map.final_colorframe = 0;
|
|
|
|
game.startspecial(1);
|
|
|
|
game.jumpheld = true;
|
|
|
|
|
|
|
|
//set flipmode
|
|
|
|
if (graphics.setflipmode) graphics.flipmode = true;
|
|
|
|
if(obj.entities.empty())
|
|
|
|
{
|
|
|
|
obj.createentity(game.savex, game.savey, 0, 0); //In this game, constant, never destroyed
|
|
|
|
}
|
|
|
|
map.resetplayer();
|
|
|
|
map.gotoroom(game.saverx, game.savery);
|
|
|
|
map.initmapdata();
|
|
|
|
|
|
|
|
load("intermission_1");
|
|
|
|
break;
|
|
|
|
case 13:
|
|
|
|
game.gamestate = GAMEMODE;
|
|
|
|
hardreset();
|
|
|
|
music.fadeout();
|
|
|
|
|
|
|
|
game.lastsaved = 3;
|
|
|
|
|
|
|
|
game.crewstats[game.lastsaved] = true;
|
|
|
|
game.inintermission = true;
|
|
|
|
game.companion = 11;
|
|
|
|
game.supercrewmate = true;
|
|
|
|
game.scmprogress = 0;
|
|
|
|
map.finalmode = true;
|
|
|
|
map.final_colormode = false;
|
|
|
|
map.final_mapcol = 0;
|
|
|
|
map.final_colorframe = 0;
|
|
|
|
game.startspecial(1);
|
|
|
|
game.jumpheld = true;
|
|
|
|
|
|
|
|
//set flipmode
|
|
|
|
if (graphics.setflipmode) graphics.flipmode = true;
|
|
|
|
if(obj.entities.empty())
|
|
|
|
{
|
|
|
|
obj.createentity(game.savex, game.savey, 0, 0); //In this game, constant, never destroyed
|
|
|
|
}
|
|
|
|
map.resetplayer();
|
|
|
|
map.gotoroom(game.saverx, game.savery);
|
|
|
|
map.initmapdata();
|
|
|
|
|
|
|
|
load("intermission_1");
|
|
|
|
break;
|
|
|
|
case 14:
|
|
|
|
game.gamestate = GAMEMODE;
|
|
|
|
hardreset();
|
|
|
|
music.fadeout();
|
|
|
|
|
|
|
|
game.lastsaved = 4;
|
|
|
|
|
|
|
|
game.crewstats[game.lastsaved] = true;
|
|
|
|
game.inintermission = true;
|
|
|
|
game.companion = 11;
|
|
|
|
game.supercrewmate = true;
|
|
|
|
game.scmprogress = 0;
|
|
|
|
map.finalmode = true;
|
|
|
|
map.final_colormode = false;
|
|
|
|
map.final_mapcol = 0;
|
|
|
|
map.final_colorframe = 0;
|
|
|
|
game.startspecial(1);
|
|
|
|
game.jumpheld = true;
|
|
|
|
|
|
|
|
//set flipmode
|
|
|
|
if (graphics.setflipmode) graphics.flipmode = true;
|
|
|
|
if(obj.entities.empty())
|
|
|
|
{
|
|
|
|
obj.createentity(game.savex, game.savey, 0, 0); //In this game, constant, never destroyed
|
|
|
|
}
|
|
|
|
map.resetplayer();
|
|
|
|
map.gotoroom(game.saverx, game.savery);
|
|
|
|
map.initmapdata();
|
|
|
|
|
|
|
|
load("intermission_1");
|
|
|
|
break;
|
|
|
|
case 15:
|
|
|
|
game.gamestate = GAMEMODE;
|
|
|
|
hardreset();
|
|
|
|
music.fadeout();
|
|
|
|
|
|
|
|
game.lastsaved = 5;
|
|
|
|
|
|
|
|
game.crewstats[game.lastsaved] = true;
|
|
|
|
game.inintermission = true;
|
|
|
|
game.companion = 11;
|
|
|
|
game.supercrewmate = true;
|
|
|
|
game.scmprogress = 0;
|
|
|
|
map.finalmode = true;
|
|
|
|
map.final_colormode = false;
|
|
|
|
map.final_mapcol = 0;
|
|
|
|
map.final_colorframe = 0;
|
|
|
|
game.startspecial(1);
|
|
|
|
game.jumpheld = true;
|
|
|
|
|
|
|
|
//set flipmode
|
|
|
|
if (graphics.setflipmode) graphics.flipmode = true;
|
|
|
|
if(obj.entities.empty())
|
|
|
|
{
|
|
|
|
obj.createentity(game.savex, game.savey, 0, 0); //In this game, constant, never destroyed
|
|
|
|
}
|
|
|
|
map.resetplayer();
|
|
|
|
map.gotoroom(game.saverx, game.savery);
|
|
|
|
map.initmapdata();
|
|
|
|
|
|
|
|
load("intermission_1");
|
|
|
|
break;
|
|
|
|
case 16:
|
|
|
|
game.gamestate = GAMEMODE;
|
|
|
|
hardreset();
|
|
|
|
music.fadeout();
|
|
|
|
|
|
|
|
game.lastsaved = 2;
|
|
|
|
|
|
|
|
game.crewstats[game.lastsaved] = true;
|
|
|
|
game.inintermission = true;
|
|
|
|
map.finalmode = true;
|
|
|
|
map.final_colormode = false;
|
|
|
|
map.final_mapcol = 0;
|
|
|
|
map.final_colorframe = 0;
|
|
|
|
game.startspecial(1);
|
|
|
|
game.jumpheld = true;
|
|
|
|
|
|
|
|
//set flipmode
|
|
|
|
if (graphics.setflipmode) graphics.flipmode = true;
|
|
|
|
if(obj.entities.empty())
|
|
|
|
{
|
|
|
|
obj.createentity(game.savex, game.savey, 0, 0); //In this game, constant, never destroyed
|
|
|
|
}
|
|
|
|
map.resetplayer();
|
|
|
|
map.gotoroom(game.saverx, game.savery);
|
|
|
|
map.initmapdata();
|
|
|
|
|
|
|
|
load("intermission_2");
|
|
|
|
break;
|
|
|
|
case 17:
|
|
|
|
game.gamestate = GAMEMODE;
|
|
|
|
hardreset();
|
|
|
|
music.fadeout();
|
|
|
|
|
|
|
|
game.lastsaved = 3;
|
|
|
|
|
|
|
|
game.crewstats[game.lastsaved] = true;
|
|
|
|
game.inintermission = true;
|
|
|
|
map.finalmode = true;
|
|
|
|
map.final_colormode = false;
|
|
|
|
map.final_mapcol = 0;
|
|
|
|
map.final_colorframe = 0;
|
|
|
|
game.startspecial(1);
|
|
|
|
game.jumpheld = true;
|
|
|
|
|
|
|
|
//set flipmode
|
|
|
|
if (graphics.setflipmode) graphics.flipmode = true;
|
|
|
|
if(obj.entities.empty())
|
|
|
|
{
|
|
|
|
obj.createentity(game.savex, game.savey, 0, 0); //In this game, constant, never destroyed
|
|
|
|
}
|
|
|
|
map.resetplayer();
|
|
|
|
map.gotoroom(game.saverx, game.savery);
|
|
|
|
map.initmapdata();
|
|
|
|
|
|
|
|
load("intermission_2");
|
|
|
|
break;
|
|
|
|
case 18:
|
|
|
|
game.gamestate = GAMEMODE;
|
|
|
|
hardreset();
|
|
|
|
music.fadeout();
|
|
|
|
|
|
|
|
game.lastsaved = 4;
|
|
|
|
|
|
|
|
game.crewstats[game.lastsaved] = true;
|
|
|
|
game.inintermission = true;
|
|
|
|
map.finalmode = true;
|
|
|
|
map.final_colormode = false;
|
|
|
|
map.final_mapcol = 0;
|
|
|
|
map.final_colorframe = 0;
|
|
|
|
game.startspecial(1);
|
|
|
|
game.jumpheld = true;
|
|
|
|
|
|
|
|
//set flipmode
|
|
|
|
if (graphics.setflipmode) graphics.flipmode = true;
|
|
|
|
if(obj.entities.empty())
|
|
|
|
{
|
|
|
|
obj.createentity(game.savex, game.savey, 0, 0); //In this game, constant, never destroyed
|
|
|
|
}
|
|
|
|
map.resetplayer();
|
|
|
|
map.gotoroom(game.saverx, game.savery);
|
|
|
|
map.initmapdata();
|
|
|
|
|
|
|
|
load("intermission_2");
|
|
|
|
break;
|
|
|
|
case 19:
|
|
|
|
game.gamestate = GAMEMODE;
|
|
|
|
hardreset();
|
|
|
|
music.fadeout();
|
|
|
|
|
|
|
|
game.lastsaved = 5;
|
|
|
|
|
|
|
|
game.crewstats[game.lastsaved] = true;
|
|
|
|
game.inintermission = true;
|
|
|
|
map.finalmode = true;
|
|
|
|
map.final_colormode = false;
|
|
|
|
map.final_mapcol = 0;
|
|
|
|
map.final_colorframe = 0;
|
|
|
|
game.startspecial(1);
|
|
|
|
game.jumpheld = true;
|
|
|
|
|
|
|
|
//set flipmode
|
|
|
|
if (graphics.setflipmode) graphics.flipmode = true;
|
|
|
|
if(obj.entities.empty())
|
|
|
|
{
|
|
|
|
obj.createentity(game.savex, game.savey, 0, 0); //In this game, constant, never destroyed
|
|
|
|
}
|
|
|
|
map.resetplayer();
|
|
|
|
map.gotoroom(game.saverx, game.savery);
|
|
|
|
map.initmapdata();
|
|
|
|
|
|
|
|
load("intermission_2");
|
|
|
|
break;
|
2021-02-21 00:40:11 +01:00
|
|
|
#ifndef NO_CUSTOM_LEVELS
|
|
|
|
# ifndef NO_EDITOR
|
2021-09-07 03:56:39 +02:00
|
|
|
case 20:
|
|
|
|
//Level editor
|
|
|
|
hardreset();
|
|
|
|
cl.reset();
|
|
|
|
ed.reset();
|
|
|
|
music.fadeout();
|
|
|
|
map.custommode = true;
|
|
|
|
map.custommodeforreal = false;
|
|
|
|
|
|
|
|
game.gamestate = EDITORMODE;
|
|
|
|
game.jumpheld = true;
|
|
|
|
|
|
|
|
if (graphics.setflipmode) graphics.flipmode = true;//set flipmode
|
|
|
|
if(obj.entities.empty())
|
|
|
|
{
|
|
|
|
obj.createentity(game.savex, game.savey, 0, 0); //In this game, constant, never destroyed
|
|
|
|
}
|
|
|
|
map.resetplayer();
|
|
|
|
map.gotoroom(game.saverx, game.savery);
|
|
|
|
map.initmapdata();
|
Enumify all fade modes
This removes the magic numbers previously used for controlling the fade
mode, which are really not readable at all unless you already know what
they mean.
0: FADE_NONE
1: FADE_FULLY_BLACK
2: FADE_START_FADEOUT
3: FADE_FADING_OUT
4: FADE_START_FADEIN
5: FADE_FADING_IN
There is also the macro FADEMODE_IS_FADING, which indicates when the
intention is to only check if the game is fading right now, which wasn't
clearly conveyed previously.
I also took the opportunity to clean up the style of any lines I
touched. This included rewriting if-else chains into case-switches,
turning one-liner if-then statements into proper blocks, fixing up
comments, and even commenting the `fademode == FADE_NONE` on the tower
spike checks (which, it was previously undocumented why that check was
there, but I think I know why it's there).
As for type safety, we already get some by transforming the variable
types into the enum. Assignment is prohibited without a cast. But,
apparently, comparison is perfectly legal and won't even give so much as
a warning. To work around this and make absolutely sure I made all
existing comparisons now use the enum, I temporarily changed it to be an
`enum class`, which is a C++11 feature that makes it so all comparisons
are illegal. Unfortunately, it scopes them in a namespace with the same
name as a class, so I had to temporarily define macros to make sure my
existing code worked. I also had to temporarily up the standard in
CMakeLists.txt to get it to compile. But after all that was done, I
found the rest of the places where a comparison to an integer was used,
and fixed them.
2022-04-25 09:57:47 +02:00
|
|
|
graphics.fademode = FADE_START_FADEIN;
|
2021-09-07 03:56:39 +02:00
|
|
|
break;
|
|
|
|
case 21: //play custom level (in editor)
|
|
|
|
game.gamestate = GAMEMODE;
|
|
|
|
music.fadeout();
|
|
|
|
hardreset();
|
|
|
|
//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++)
|
|
|
|
{
|
|
|
|
ed.kludgewarpdir[i+(j*cl.maxwidth)]=cl.roomproperties[i+(j*cl.maxwidth)].warpdir;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
game.customstart();
|
|
|
|
game.jumpheld = true;
|
|
|
|
|
|
|
|
ed.ghosts.clear();
|
|
|
|
|
|
|
|
map.custommode = true;
|
|
|
|
|
|
|
|
//set flipmode
|
|
|
|
if (graphics.setflipmode) graphics.flipmode = true;
|
|
|
|
|
|
|
|
if(obj.entities.empty())
|
|
|
|
{
|
|
|
|
obj.createentity(game.savex, game.savey, 0, 0); //In this game, constant, never destroyed
|
|
|
|
}
|
|
|
|
map.resetplayer();
|
|
|
|
map.gotoroom(game.saverx, game.savery);
|
|
|
|
map.initmapdata();
|
2022-11-30 17:17:05 +01:00
|
|
|
|
|
|
|
cl.generatecustomminimap();
|
|
|
|
map.customshowmm = true;
|
|
|
|
|
|
|
|
if (cl.levmusic > 0)
|
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
music.play(cl.levmusic);
|
2022-11-30 17:17:05 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
music.currentsong = -1;
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
break;
|
2021-02-21 00:40:11 +01:00
|
|
|
# endif /* NO_EDITOR */
|
2021-09-07 03:56:39 +02:00
|
|
|
case 22: //play custom level (in game)
|
|
|
|
{
|
|
|
|
//Initilise the level
|
|
|
|
//First up, find the start point
|
|
|
|
std::string filename = std::string(cl.ListOfMetaData[game.playcustomlevel].filename);
|
|
|
|
if (!cl.load(filename))
|
|
|
|
{
|
|
|
|
gotoerrorloadinglevel();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
cl.findstartpoint();
|
|
|
|
|
|
|
|
game.gamestate = GAMEMODE;
|
|
|
|
music.fadeout();
|
|
|
|
hardreset();
|
|
|
|
game.customstart();
|
|
|
|
game.jumpheld = true;
|
|
|
|
|
|
|
|
map.custommodeforreal = true;
|
|
|
|
map.custommode = true;
|
|
|
|
|
|
|
|
//set flipmode
|
|
|
|
if (graphics.setflipmode) graphics.flipmode = true;
|
|
|
|
|
|
|
|
if(obj.entities.empty())
|
|
|
|
{
|
|
|
|
obj.createentity(game.savex, game.savey, 0, 0); //In this game, constant, never destroyed
|
|
|
|
}
|
|
|
|
map.resetplayer();
|
|
|
|
map.gotoroom(game.saverx, game.savery);
|
|
|
|
map.initmapdata();
|
|
|
|
|
|
|
|
cl.generatecustomminimap();
|
|
|
|
map.customshowmm=true;
|
|
|
|
if(cl.levmusic>0){
|
|
|
|
music.play(cl.levmusic);
|
|
|
|
}else{
|
|
|
|
music.currentsong=-1;
|
|
|
|
}
|
Enumify all fade modes
This removes the magic numbers previously used for controlling the fade
mode, which are really not readable at all unless you already know what
they mean.
0: FADE_NONE
1: FADE_FULLY_BLACK
2: FADE_START_FADEOUT
3: FADE_FADING_OUT
4: FADE_START_FADEIN
5: FADE_FADING_IN
There is also the macro FADEMODE_IS_FADING, which indicates when the
intention is to only check if the game is fading right now, which wasn't
clearly conveyed previously.
I also took the opportunity to clean up the style of any lines I
touched. This included rewriting if-else chains into case-switches,
turning one-liner if-then statements into proper blocks, fixing up
comments, and even commenting the `fademode == FADE_NONE` on the tower
spike checks (which, it was previously undocumented why that check was
there, but I think I know why it's there).
As for type safety, we already get some by transforming the variable
types into the enum. Assignment is prohibited without a cast. But,
apparently, comparison is perfectly legal and won't even give so much as
a warning. To work around this and make absolutely sure I made all
existing comparisons now use the enum, I temporarily changed it to be an
`enum class`, which is a C++11 feature that makes it so all comparisons
are illegal. Unfortunately, it scopes them in a namespace with the same
name as a class, so I had to temporarily define macros to make sure my
existing code worked. I also had to temporarily up the standard in
CMakeLists.txt to get it to compile. But after all that was done, I
found the rest of the places where a comparison to an integer was used,
and fixed them.
2022-04-25 09:57:47 +02:00
|
|
|
graphics.fademode = FADE_START_FADEIN;
|
2021-09-07 03:56:39 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 23: //Continue in custom level
|
|
|
|
{
|
|
|
|
//Initilise the level
|
|
|
|
//First up, find the start point
|
|
|
|
std::string filename = std::string(cl.ListOfMetaData[game.playcustomlevel].filename);
|
|
|
|
if (!cl.load(filename))
|
|
|
|
{
|
|
|
|
gotoerrorloadinglevel();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
cl.findstartpoint();
|
|
|
|
|
|
|
|
game.gamestate = GAMEMODE;
|
|
|
|
music.fadeout();
|
|
|
|
hardreset();
|
|
|
|
map.custommodeforreal = true;
|
|
|
|
map.custommode = true;
|
|
|
|
|
|
|
|
game.customstart();
|
|
|
|
game.customloadquick(cl.ListOfMetaData[game.playcustomlevel].filename);
|
|
|
|
game.jumpheld = true;
|
|
|
|
game.gravitycontrol = game.savegc;
|
|
|
|
|
|
|
|
|
|
|
|
//set flipmode
|
|
|
|
if (graphics.setflipmode) graphics.flipmode = true;
|
|
|
|
|
|
|
|
if(obj.entities.empty())
|
|
|
|
{
|
|
|
|
obj.createentity(game.savex, game.savey, 0, 0); //In this game, constant, never destroyed
|
|
|
|
}
|
|
|
|
map.resetplayer();
|
|
|
|
map.gotoroom(game.saverx, game.savery);
|
|
|
|
map.initmapdata();
|
|
|
|
cl.generatecustomminimap();
|
Enumify all fade modes
This removes the magic numbers previously used for controlling the fade
mode, which are really not readable at all unless you already know what
they mean.
0: FADE_NONE
1: FADE_FULLY_BLACK
2: FADE_START_FADEOUT
3: FADE_FADING_OUT
4: FADE_START_FADEIN
5: FADE_FADING_IN
There is also the macro FADEMODE_IS_FADING, which indicates when the
intention is to only check if the game is fading right now, which wasn't
clearly conveyed previously.
I also took the opportunity to clean up the style of any lines I
touched. This included rewriting if-else chains into case-switches,
turning one-liner if-then statements into proper blocks, fixing up
comments, and even commenting the `fademode == FADE_NONE` on the tower
spike checks (which, it was previously undocumented why that check was
there, but I think I know why it's there).
As for type safety, we already get some by transforming the variable
types into the enum. Assignment is prohibited without a cast. But,
apparently, comparison is perfectly legal and won't even give so much as
a warning. To work around this and make absolutely sure I made all
existing comparisons now use the enum, I temporarily changed it to be an
`enum class`, which is a C++11 feature that makes it so all comparisons
are illegal. Unfortunately, it scopes them in a namespace with the same
name as a class, so I had to temporarily define macros to make sure my
existing code worked. I also had to temporarily up the standard in
CMakeLists.txt to get it to compile. But after all that was done, I
found the rest of the places where a comparison to an integer was used,
and fixed them.
2022-04-25 09:57:47 +02:00
|
|
|
graphics.fademode = FADE_START_FADEIN;
|
2021-09-07 03:56:39 +02:00
|
|
|
break;
|
|
|
|
}
|
2021-02-21 00:40:11 +01:00
|
|
|
#endif /* NO_CUSTOM_LEVELS */
|
2021-09-07 03:56:39 +02:00
|
|
|
case 100:
|
|
|
|
VVV_exit(0);
|
|
|
|
break;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void scriptclass::teleport(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
//er, ok! Teleport to a new area, so!
|
|
|
|
//A general rule of thumb: if you teleport with a companion, get rid of them!
|
|
|
|
game.companion = 0;
|
|
|
|
|
|
|
|
i = obj.getplayer(); //less likely to have a serious collision error if the player is centered
|
|
|
|
if (INBOUNDS_VEC(i, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[i].xp = 150;
|
|
|
|
obj.entities[i].yp = 110;
|
|
|
|
if(game.teleport_to_x==17 && game.teleport_to_y==17) obj.entities[i].xp = 88; //prevent falling!
|
|
|
|
obj.entities[i].lerpoldxp = obj.entities[i].xp;
|
|
|
|
obj.entities[i].lerpoldyp = obj.entities[i].yp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (game.teleportscript == "levelonecomplete")
|
|
|
|
{
|
|
|
|
game.teleport_to_x = 2;
|
|
|
|
game.teleport_to_y = 11;
|
|
|
|
}
|
|
|
|
else if (game.teleportscript == "gamecomplete")
|
|
|
|
{
|
|
|
|
game.teleport_to_x = 2;
|
|
|
|
game.teleport_to_y = 11;
|
|
|
|
}
|
|
|
|
|
|
|
|
game.gravitycontrol = 0;
|
|
|
|
map.gotoroom(100+game.teleport_to_x, 100+game.teleport_to_y);
|
|
|
|
j = obj.getteleporter();
|
|
|
|
if (INBOUNDS_VEC(j, obj.entities))
|
|
|
|
{
|
|
|
|
obj.entities[j].state = 2;
|
|
|
|
}
|
|
|
|
game.teleport_to_new_area = false;
|
|
|
|
|
|
|
|
if (INBOUNDS_VEC(j, obj.entities))
|
|
|
|
{
|
|
|
|
game.savepoint = obj.entities[j].para;
|
|
|
|
game.savex = obj.entities[j].xp + 44;
|
|
|
|
game.savey = obj.entities[j].yp + 44;
|
|
|
|
}
|
|
|
|
game.savegc = 0;
|
|
|
|
|
|
|
|
game.saverx = game.roomx;
|
|
|
|
game.savery = game.roomy;
|
|
|
|
int player = obj.getplayer();
|
|
|
|
if (INBOUNDS_VEC(player, obj.entities))
|
|
|
|
{
|
|
|
|
game.savedir = obj.entities[player].dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(game.teleport_to_x==0 && game.teleport_to_y==0)
|
|
|
|
{
|
2022-12-07 00:20:48 +01:00
|
|
|
game.setstate(4020);
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else if(game.teleport_to_x==0 && game.teleport_to_y==16)
|
|
|
|
{
|
2022-12-07 00:20:48 +01:00
|
|
|
game.setstate(4030);
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else if(game.teleport_to_x==7 && game.teleport_to_y==9)
|
|
|
|
{
|
2022-12-07 00:20:48 +01:00
|
|
|
game.setstate(4040);
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else if(game.teleport_to_x==8 && game.teleport_to_y==11)
|
|
|
|
{
|
2022-12-07 00:20:48 +01:00
|
|
|
game.setstate(4050);
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else if(game.teleport_to_x==14 && game.teleport_to_y==19)
|
|
|
|
{
|
2022-12-07 00:20:48 +01:00
|
|
|
game.setstate(4030);
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else if(game.teleport_to_x==17 && game.teleport_to_y==12)
|
|
|
|
{
|
2022-12-07 00:20:48 +01:00
|
|
|
game.setstate(4020);
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else if(game.teleport_to_x==17 && game.teleport_to_y==17)
|
|
|
|
{
|
2022-12-07 00:20:48 +01:00
|
|
|
game.setstate(4020);
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else if(game.teleport_to_x==18 && game.teleport_to_y==7)
|
|
|
|
{
|
2022-12-07 00:20:48 +01:00
|
|
|
game.setstate(4060);
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-12-07 00:20:48 +01:00
|
|
|
game.setstate(4010);
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (game.teleportscript != "")
|
|
|
|
{
|
2022-12-07 00:20:48 +01:00
|
|
|
game.setstate(0);
|
2021-09-07 03:56:39 +02:00
|
|
|
load(game.teleportscript);
|
|
|
|
game.teleportscript = "";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//change music based on location
|
|
|
|
if (game.teleport_to_x == 2 && game.teleport_to_y == 11)
|
|
|
|
{
|
|
|
|
/* Special case: Ship music needs to be set here;
|
|
|
|
* ship teleporter on music map is -1 for jukebox. */
|
|
|
|
music.niceplay(4);
|
|
|
|
}
|
|
|
|
game.savetele_textbox();
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Explicitly declare void for all void parameter functions (#628)
Apparently in C, if you have `void test();`, it's completely okay to do
`test(2);`. The function will take in the argument, but just discard it
and throw it away. It's like a trash can, and a rude one at that. If you
declare it like `void test(void);`, this is prevented.
This is not a problem in C++ - doing `void test();` and `test(2);` is
guaranteed to result in a compile error (this also means that right now,
at least in all `.cpp` files, nobody is ever calling a void parameter
function with arguments and having their arguments be thrown away).
However, we may not be using C++ in the future, so I just want to lay
down the precedent that if a function takes in no arguments, you must
explicitly declare it as such.
I would've added `-Wstrict-prototypes`, but it produces an annoying
warning message saying it doesn't work in C++ mode if you're compiling
in C++ mode. So it can be added later.
2021-02-25 23:23:59 +01:00
|
|
|
void scriptclass::hardreset(void)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
const bool version2_2 = GlitchrunnerMode_less_than_or_equal(Glitchrunner2_2);
|
|
|
|
|
2022-11-14 23:10:24 +01:00
|
|
|
if (game.seed_use_sdl_getticks)
|
|
|
|
{
|
|
|
|
/* The RNG is 32-bit. We don't _really_ need 64-bit... */
|
|
|
|
xoshiro_seed((Uint32) SDL_GetTicks64());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
xoshiro_seed(game.framecounter);
|
|
|
|
}
|
2021-09-07 03:56:39 +02:00
|
|
|
|
|
|
|
//Game:
|
|
|
|
game.hascontrol = true;
|
|
|
|
game.gravitycontrol = 0;
|
|
|
|
game.teleport = false;
|
|
|
|
game.companion = 0;
|
|
|
|
if (!version2_2)
|
|
|
|
{
|
|
|
|
// Ironically, resetting more variables makes the janky fadeout system in glitchrunnermode even more glitchy
|
|
|
|
game.roomx = 0;
|
|
|
|
game.roomy = 0;
|
|
|
|
}
|
|
|
|
game.prevroomx = 0;
|
|
|
|
game.prevroomy = 0;
|
|
|
|
game.teleport_to_new_area = false;
|
|
|
|
game.teleport_to_x = 0;
|
|
|
|
game.teleport_to_y = 0;
|
|
|
|
game.teleportscript = "";
|
|
|
|
|
|
|
|
game.tapleft = 0;
|
|
|
|
game.tapright = 0;
|
|
|
|
game.startscript = false;
|
|
|
|
game.newscript = "";
|
|
|
|
game.alarmon = false;
|
|
|
|
game.alarmdelay = 0;
|
|
|
|
game.blackout = false;
|
|
|
|
game.useteleporter = false;
|
|
|
|
game.teleport_to_teleporter = 0;
|
|
|
|
|
|
|
|
game.nodeathmode = false;
|
|
|
|
game.nocutscenes = false;
|
|
|
|
|
|
|
|
for (i = 0; i < (int) SDL_arraysize(game.crewstats); i++)
|
|
|
|
{
|
|
|
|
game.crewstats[i] = false;
|
|
|
|
}
|
|
|
|
game.crewstats[0] = true;
|
|
|
|
game.lastsaved = 0;
|
|
|
|
|
|
|
|
game.deathcounts = 0;
|
|
|
|
game.gameoverdelay = 0;
|
|
|
|
game.resetgameclock();
|
|
|
|
game.gamesaved = false;
|
|
|
|
game.gamesavefailed = false;
|
|
|
|
game.savetime = "00:00";
|
|
|
|
game.savearea = "nowhere";
|
|
|
|
game.savetrinkets = 0;
|
|
|
|
if (!version2_2)
|
|
|
|
{
|
|
|
|
// Ironically, resetting more variables makes the janky fadeout system in glitchrunnermode even more glitchy
|
|
|
|
game.saverx = 0;
|
|
|
|
game.savery = 0;
|
|
|
|
}
|
|
|
|
game.savecolour = 0;
|
|
|
|
|
|
|
|
game.intimetrial = false;
|
|
|
|
game.timetrialcountdown = 0;
|
|
|
|
game.timetrialshinytarget = 0;
|
|
|
|
game.timetrialparlost = false;
|
|
|
|
game.timetrialpar = 0;
|
|
|
|
|
|
|
|
game.totalflips = 0;
|
|
|
|
game.hardestroom = "Welcome Aboard";
|
|
|
|
game.hardestroomdeaths = 0;
|
|
|
|
game.currentroomdeaths=0;
|
|
|
|
|
|
|
|
game.swnmode = false;
|
|
|
|
game.swntimer = 0;
|
|
|
|
game.swngame = 0;//Not playing sine wave ninja!
|
|
|
|
game.swnstate = 0;
|
|
|
|
game.swnstate2 = 0;
|
|
|
|
game.swnstate3 = 0;
|
|
|
|
game.swnstate4 = 0;
|
|
|
|
game.swndelay = 0;
|
|
|
|
game.swndeaths = 0;
|
|
|
|
game.supercrewmate = false;
|
|
|
|
game.scmhurt = false;
|
|
|
|
game.scmprogress = 0;
|
|
|
|
game.swncolstate = 0;
|
|
|
|
game.swncoldelay = 0;
|
|
|
|
game.swnrank = 0;
|
|
|
|
game.swnmessage = 0;
|
|
|
|
game.creditposx = 0;
|
|
|
|
game.creditposy = 0;
|
|
|
|
game.creditposdelay = 0;
|
|
|
|
|
|
|
|
game.inintermission = false;
|
|
|
|
game.insecretlab = false;
|
|
|
|
|
2022-12-07 00:20:48 +01:00
|
|
|
game.unlockstate();
|
2021-09-07 03:56:39 +02:00
|
|
|
game.state = 0;
|
|
|
|
game.statedelay = 0;
|
|
|
|
|
|
|
|
game.hascontrol = true;
|
|
|
|
if (!GlitchrunnerMode_less_than_or_equal(Glitchrunner2_0))
|
|
|
|
{
|
|
|
|
// Keep the "- Press ACTION to advance text -" prompt around,
|
|
|
|
// apparently the speedrunners call it the "text storage" glitch
|
|
|
|
game.advancetext = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
game.pausescript = false;
|
|
|
|
game.completestop = false;
|
|
|
|
|
|
|
|
game.flashlight = 0;
|
|
|
|
game.screenshake = 0;
|
|
|
|
|
|
|
|
game.activeactivity = -1;
|
|
|
|
game.act_fade = 5;
|
|
|
|
|
|
|
|
game.disabletemporaryaudiopause = true;
|
|
|
|
|
2021-12-18 08:39:26 +01:00
|
|
|
game.ingame_titlemode = false;
|
|
|
|
|
2021-09-07 03:56:39 +02:00
|
|
|
//dwgraphicsclass
|
|
|
|
graphics.backgrounddrawn = false;
|
2021-09-13 06:02:15 +02:00
|
|
|
graphics.textboxes.clear();
|
2021-09-07 03:56:39 +02:00
|
|
|
graphics.flipmode = false; //This will be reset if needs be elsewhere
|
|
|
|
graphics.showcutscenebars = false;
|
|
|
|
graphics.setbars(0);
|
|
|
|
|
|
|
|
//mapclass
|
|
|
|
map.warpx = false;
|
|
|
|
map.warpy = false;
|
|
|
|
map.showteleporters = false;
|
|
|
|
map.showtargets = false;
|
|
|
|
map.showtrinkets = false;
|
|
|
|
map.finalmode = false;
|
|
|
|
map.finalstretch = false;
|
|
|
|
map.final_colormode = false;
|
|
|
|
map.final_colorframe = 0;
|
|
|
|
map.final_colorframedelay = 0;
|
|
|
|
map.final_mapcol = 0;
|
|
|
|
map.final_aniframe = 0;
|
|
|
|
map.final_aniframedelay = 0;
|
|
|
|
map.rcol = 0;
|
|
|
|
map.resetnames();
|
|
|
|
map.custommode=false;
|
|
|
|
map.custommodeforreal=false;
|
|
|
|
if (!version2_2)
|
|
|
|
{
|
|
|
|
// Ironically, resetting more variables makes the janky fadeout system even more glitchy
|
|
|
|
map.towermode=false;
|
|
|
|
}
|
|
|
|
map.cameraseekframe = 0;
|
|
|
|
map.resumedelay = 0;
|
|
|
|
graphics.towerbg.scrolldir = 0;
|
|
|
|
map.customshowmm=true;
|
|
|
|
|
|
|
|
SDL_memset(map.roomdeaths, 0, sizeof(map.roomdeaths));
|
|
|
|
SDL_memset(map.roomdeathsfinal, 0, sizeof(map.roomdeathsfinal));
|
|
|
|
map.resetmap();
|
|
|
|
//entityclass
|
|
|
|
obj.nearelephant = false;
|
|
|
|
obj.upsetmode = false;
|
|
|
|
obj.upset = 0;
|
|
|
|
|
|
|
|
obj.trophytext = 0 ;
|
|
|
|
obj.trophytype = 0;
|
|
|
|
obj.altstates = 0;
|
|
|
|
|
|
|
|
obj.resetallflags();
|
|
|
|
|
|
|
|
for (i = 0; i < (int) SDL_arraysize(obj.customcrewmoods); i++){
|
|
|
|
obj.customcrewmoods[i]=true;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDL_memset(obj.collect, false, sizeof(obj.collect));
|
|
|
|
SDL_memset(obj.customcollect, false, sizeof(obj.customcollect));
|
|
|
|
i = 100; //previously a for-loop iterating over collect/customcollect set this to 100
|
|
|
|
|
|
|
|
int theplayer = obj.getplayer();
|
|
|
|
if (INBOUNDS_VEC(theplayer, obj.entities)){
|
|
|
|
obj.entities[theplayer].tile = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Disable duplicate player entities */
|
|
|
|
for (int i = 0; i < (int) obj.entities.size(); i++)
|
|
|
|
{
|
|
|
|
if (obj.entities[i].rule == 0 && i != theplayer)
|
|
|
|
{
|
|
|
|
obj.disableentity(i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
obj.customscript = "";
|
|
|
|
|
|
|
|
//Script Stuff
|
|
|
|
position = 0;
|
|
|
|
commands.clear();
|
|
|
|
scriptdelay = 0;
|
|
|
|
scriptname = "null";
|
|
|
|
running = false;
|
2022-02-12 23:56:27 +01:00
|
|
|
for (size_t ii = 0; ii < NUM_SCRIPT_ARGS; ++ii)
|
2021-09-07 03:56:39 +02:00
|
|
|
{
|
|
|
|
words[ii] = "";
|
2022-02-12 23:56:27 +01:00
|
|
|
raw_words[ii] = "";
|
2021-09-07 03:56:39 +02:00
|
|
|
}
|
2021-08-31 20:07:38 +02:00
|
|
|
|
|
|
|
obj.customactivitycolour = "";
|
|
|
|
obj.customactivitytext = "";
|
Add `setactivityposition(x,y)`, add new textbox color `transparent` (#847)
* Add `setactivityposition(x,y)`, add new textbox color `transparent`
This commit adds a new internal command as a part of the visual activity zone changes I've been making.
This one allows the user to reposition the activity zone to anywhere on the screen.
In addition, this commit adds the textbox color `transparent`, which just sets r, g and b to 0.
rgb(0, 0, 0) normally creates the color black, however in VVVVVV textboxes, it makes the background
of them invisible, and makes the text the off-white color which the game uses elsewhere.
* add new variables to hardreset
* Fix unwanted text centering; offset position by 16, 4
It makes sense for `setactivityposition(0, 0)` to place the activity zone in the default position,
so the x has been offset by 16, and the y has been offset by 4.
Text was being automatically centered, meaning any activity zone which wasn't centered had misplaced text.
This has been fixed by calculating the center manually, and offsetting it by the passed value.
2021-10-14 00:38:51 +02:00
|
|
|
obj.customactivitypositionx = -1;
|
|
|
|
obj.customactivitypositiony = -1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-05-18 19:08:34 +02:00
|
|
|
|
2020-07-05 01:01:35 +02:00
|
|
|
void scriptclass::loadcustom(const std::string& t)
|
2020-05-18 19:08:34 +02:00
|
|
|
{
|
2021-09-07 03:56:39 +02:00
|
|
|
//this magic function breaks down the custom script and turns into real scripting!
|
|
|
|
std::string cscriptname="";
|
|
|
|
for(size_t i=0; i<t.length(); i++){
|
|
|
|
if(i>=7) cscriptname+=t[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string tstring;
|
|
|
|
|
|
|
|
std::vector<std::string>* contents = NULL;
|
|
|
|
for(size_t i = 0; i < customscripts.size(); i++){
|
|
|
|
Script& script_ = customscripts[i];
|
|
|
|
|
|
|
|
if(script_.name == cscriptname){
|
|
|
|
contents = &script_.contents;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(contents == NULL){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string>& lines = *contents;
|
|
|
|
|
|
|
|
//Ok, we've got the relavent script segment, we do a pass to assess it, then run it!
|
|
|
|
int customcutscenemode=0;
|
|
|
|
for(size_t i=0; i<lines.size(); i++){
|
|
|
|
tokenize(lines[i]);
|
|
|
|
if(words[0] == "say"){
|
|
|
|
customcutscenemode=1;
|
|
|
|
}else if(words[0] == "reply"){
|
|
|
|
customcutscenemode=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(customcutscenemode==1){
|
|
|
|
add("cutscene()");
|
|
|
|
add("untilbars()");
|
|
|
|
}
|
|
|
|
int customtextmode=0;
|
|
|
|
int speakermode=0; //0, terminal, numbers for crew
|
|
|
|
int squeakmode=0;//default on
|
|
|
|
//Now run the script
|
|
|
|
for(size_t i=0; i<lines.size(); i++){
|
|
|
|
words[0]="nothing"; //Default!
|
|
|
|
words[1]="1"; //Default!
|
|
|
|
tokenize(lines[i]);
|
|
|
|
for (size_t ii = 0; ii < words[0].length(); ii++)
|
|
|
|
{
|
|
|
|
words[0][ii] = SDL_tolower(words[0][ii]);
|
|
|
|
}
|
|
|
|
if(words[0] == "music"){
|
|
|
|
if(customtextmode==1){ add("endtext"); customtextmode=0;}
|
|
|
|
if(words[1]=="0"){
|
|
|
|
tstring="stopmusic()";
|
|
|
|
}else{
|
|
|
|
if(words[1]=="11"){ tstring="play(14)";
|
|
|
|
}else if(words[1]=="10"){ tstring="play(13)";
|
|
|
|
}else if(words[1]=="9"){ tstring="play(12)";
|
|
|
|
}else if(words[1]=="8"){ tstring="play(11)";
|
|
|
|
}else if(words[1]=="7"){ tstring="play(10)";
|
|
|
|
}else if(words[1]=="6"){ tstring="play(8)";
|
|
|
|
}else if(words[1]=="5"){ tstring="play(6)";
|
|
|
|
}else { tstring="play("+words[1]+")"; }
|
|
|
|
}
|
|
|
|
add(tstring);
|
|
|
|
}else if(words[0] == "playremix"){
|
|
|
|
add("play(15)");
|
|
|
|
}else if(words[0] == "flash"){
|
|
|
|
if(customtextmode==1){ add("endtext"); customtextmode=0;}
|
|
|
|
add("flash(5)");
|
|
|
|
add("shake(20)");
|
|
|
|
add("playef(9)");
|
|
|
|
}else if(words[0] == "sad" || words[0] == "cry"){
|
|
|
|
if(customtextmode==1){ add("endtext"); customtextmode=0;}
|
|
|
|
if(words[1]=="player"){
|
|
|
|
add("changemood(player,1)");
|
|
|
|
}else if(words[1]=="cyan" || words[1]=="viridian" || words[1]=="1"){
|
|
|
|
add("changecustommood(customcyan,1)");
|
|
|
|
}else if(words[1]=="purple" || words[1]=="violet" || words[1]=="pink" || words[1]=="2"){
|
|
|
|
add("changecustommood(purple,1)");
|
|
|
|
}else if(words[1]=="yellow" || words[1]=="vitellary" || words[1]=="3"){
|
|
|
|
add("changecustommood(yellow,1)");
|
|
|
|
}else if(words[1]=="red" || words[1]=="vermilion" || words[1]=="4"){
|
|
|
|
add("changecustommood(red,1)");
|
|
|
|
}else if(words[1]=="green" || words[1]=="verdigris" || words[1]=="5"){
|
|
|
|
add("changecustommood(green,1)");
|
|
|
|
}else if(words[1]=="blue" || words[1]=="victoria" || words[1]=="6"){
|
|
|
|
add("changecustommood(blue,1)");
|
|
|
|
}else if(words[1]=="all" || words[1]=="everybody" || words[1]=="everyone"){
|
|
|
|
add("changemood(player,1)");
|
|
|
|
add("changecustommood(customcyan,1)");
|
|
|
|
add("changecustommood(purple,1)");
|
|
|
|
add("changecustommood(yellow,1)");
|
|
|
|
add("changecustommood(red,1)");
|
|
|
|
add("changecustommood(green,1)");
|
|
|
|
add("changecustommood(blue,1)");
|
|
|
|
}else{
|
|
|
|
add("changemood(player,1)");
|
|
|
|
}
|
|
|
|
if(squeakmode==0) add("squeak(cry)");
|
|
|
|
}else if(words[0] == "happy"){
|
|
|
|
if(customtextmode==1){ add("endtext"); customtextmode=0;}
|
|
|
|
if(words[1]=="player"){
|
|
|
|
add("changemood(player,0)");
|
|
|
|
if(squeakmode==0) add("squeak(player)");
|
|
|
|
}else if(words[1]=="cyan" || words[1]=="viridian" || words[1]=="1"){
|
|
|
|
add("changecustommood(customcyan,0)");
|
|
|
|
if(squeakmode==0) add("squeak(player)");
|
|
|
|
}else if(words[1]=="purple" || words[1]=="violet" || words[1]=="pink" || words[1]=="2"){
|
|
|
|
add("changecustommood(purple,0)");
|
|
|
|
if(squeakmode==0) add("squeak(purple)");
|
|
|
|
}else if(words[1]=="yellow" || words[1]=="vitellary" || words[1]=="3"){
|
|
|
|
add("changecustommood(yellow,0)");
|
|
|
|
if(squeakmode==0) add("squeak(yellow)");
|
|
|
|
}else if(words[1]=="red" || words[1]=="vermilion" || words[1]=="4"){
|
|
|
|
add("changecustommood(red,0)");
|
|
|
|
if(squeakmode==0) add("squeak(red)");
|
|
|
|
}else if(words[1]=="green" || words[1]=="verdigris" || words[1]=="5"){
|
|
|
|
add("changecustommood(green,0)");
|
|
|
|
if(squeakmode==0) add("squeak(green)");
|
|
|
|
}else if(words[1]=="blue" || words[1]=="victoria" || words[1]=="6"){
|
|
|
|
add("changecustommood(blue,0)");
|
|
|
|
if(squeakmode==0) add("squeak(blue)");
|
|
|
|
}else if(words[1]=="all" || words[1]=="everybody" || words[1]=="everyone"){
|
|
|
|
add("changemood(player,0)");
|
|
|
|
add("changecustommood(customcyan,0)");
|
|
|
|
add("changecustommood(purple,0)");
|
|
|
|
add("changecustommood(yellow,0)");
|
|
|
|
add("changecustommood(red,0)");
|
|
|
|
add("changecustommood(green,0)");
|
|
|
|
add("changecustommood(blue,0)");
|
|
|
|
}else{
|
|
|
|
add("changemood(player,0)");
|
|
|
|
if(squeakmode==0) add("squeak(player)");
|
|
|
|
}
|
|
|
|
}else if(words[0] == "squeak"){
|
|
|
|
if(customtextmode==1){ add("endtext"); customtextmode=0;}
|
|
|
|
if(words[1]=="player"){
|
|
|
|
add("squeak(player)");
|
|
|
|
}else if(words[1]=="cyan" || words[1]=="viridian" || words[1]=="1"){
|
|
|
|
add("squeak(player)");
|
|
|
|
}else if(words[1]=="purple" || words[1]=="violet" || words[1]=="pink" || words[1]=="2"){
|
|
|
|
add("squeak(purple)");
|
|
|
|
}else if(words[1]=="yellow" || words[1]=="vitellary" || words[1]=="3"){
|
|
|
|
add("squeak(yellow)");
|
|
|
|
}else if(words[1]=="red" || words[1]=="vermilion" || words[1]=="4"){
|
|
|
|
add("squeak(red)");
|
|
|
|
}else if(words[1]=="green" || words[1]=="verdigris" || words[1]=="5"){
|
|
|
|
add("squeak(green)");
|
|
|
|
}else if(words[1]=="blue" || words[1]=="victoria" || words[1]=="6"){
|
|
|
|
add("squeak(blue)");
|
|
|
|
}else if(words[1]=="cry" || words[1]=="sad"){
|
|
|
|
add("squeak(cry)");
|
|
|
|
}else if(words[1]=="on"){
|
|
|
|
squeakmode=0;
|
|
|
|
}else if(words[1]=="off"){
|
|
|
|
squeakmode=1;
|
|
|
|
}
|
|
|
|
}else if(words[0] == "delay"){
|
|
|
|
if(customtextmode==1){ add("endtext"); customtextmode=0;}
|
|
|
|
add(lines[i]);
|
|
|
|
}else if(words[0] == "flag"){
|
|
|
|
if(customtextmode==1){ add("endtext"); customtextmode=0;}
|
|
|
|
add(lines[i]);
|
|
|
|
}else if(words[0] == "map"){
|
|
|
|
if(customtextmode==1){ add("endtext"); customtextmode=0;}
|
|
|
|
add("custom"+lines[i]);
|
|
|
|
}else if(words[0] == "warpdir"){
|
|
|
|
if(customtextmode==1){ add("endtext"); customtextmode=0;}
|
|
|
|
add(lines[i]);
|
|
|
|
}else if(words[0] == "ifwarp"){
|
|
|
|
if(customtextmode==1){ add("endtext"); customtextmode=0;}
|
|
|
|
add(lines[i]);
|
|
|
|
}else if(words[0] == "iftrinkets"){
|
|
|
|
if(customtextmode==1){ add("endtext"); customtextmode=0;}
|
|
|
|
add("custom"+lines[i]);
|
|
|
|
}else if(words[0] == "ifflag"){
|
|
|
|
if(customtextmode==1){ add("endtext"); customtextmode=0;}
|
|
|
|
add("custom"+lines[i]);
|
|
|
|
}else if(words[0] == "iftrinketsless"){
|
|
|
|
if(customtextmode==1){ add("endtext"); customtextmode=0;}
|
|
|
|
add("custom"+lines[i]);
|
|
|
|
}else if(words[0] == "destroy"){
|
|
|
|
if(customtextmode==1){ add("endtext"); customtextmode=0;}
|
|
|
|
add(lines[i]);
|
|
|
|
}else if(words[0] == "speaker"){
|
|
|
|
speakermode=0;
|
|
|
|
if(words[1]=="gray" || words[1]=="grey" || words[1]=="terminal" || words[1]=="0") speakermode=0;
|
|
|
|
if(words[1]=="cyan" || words[1]=="viridian" || words[1]=="player" || words[1]=="1") speakermode=1;
|
|
|
|
if(words[1]=="purple" || words[1]=="violet" || words[1]=="pink" || words[1]=="2") speakermode=2;
|
|
|
|
if(words[1]=="yellow" || words[1]=="vitellary" || words[1]=="3") speakermode=3;
|
|
|
|
if(words[1]=="red" || words[1]=="vermilion" || words[1]=="4") speakermode=4;
|
|
|
|
if(words[1]=="green" || words[1]=="verdigris" || words[1]=="5") speakermode=5;
|
|
|
|
if(words[1]=="blue" || words[1]=="victoria" || words[1]=="6") speakermode=6;
|
|
|
|
}else if(words[0] == "say"){
|
|
|
|
//Speakers!
|
|
|
|
if(words[2]=="terminal" || words[2]=="gray" || words[2]=="grey" || words[2]=="0") speakermode=0;
|
|
|
|
if(words[2]=="cyan" || words[2]=="viridian" || words[2]=="player" || words[2]=="1") speakermode=1;
|
|
|
|
if(words[2]=="purple" || words[2]=="violet" || words[2]=="pink" || words[2]=="2") speakermode=2;
|
|
|
|
if(words[2]=="yellow" || words[2]=="vitellary" || words[2]=="3") speakermode=3;
|
|
|
|
if(words[2]=="red" || words[2]=="vermilion" || words[2]=="4") speakermode=4;
|
|
|
|
if(words[2]=="green" || words[2]=="verdigris" || words[2]=="5") speakermode=5;
|
|
|
|
if(words[2]=="blue" || words[2]=="victoria" || words[2]=="6") speakermode=6;
|
|
|
|
switch(speakermode){
|
|
|
|
case 0:
|
|
|
|
if(squeakmode==0) add("squeak(terminal)");
|
|
|
|
add("text(gray,0,114,"+words[1]+")");
|
|
|
|
break;
|
|
|
|
case 1: //NOT THE PLAYER
|
|
|
|
if(squeakmode==0) add("squeak(cyan)");
|
|
|
|
add("text(cyan,0,0,"+words[1]+")");
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if(squeakmode==0) add("squeak(purple)");
|
|
|
|
add("text(purple,0,0,"+words[1]+")");
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if(squeakmode==0) add("squeak(yellow)");
|
|
|
|
add("text(yellow,0,0,"+words[1]+")");
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
if(squeakmode==0) add("squeak(red)");
|
|
|
|
add("text(red,0,0,"+words[1]+")");
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
if(squeakmode==0) add("squeak(green)");
|
|
|
|
add("text(green,0,0,"+words[1]+")");
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
if(squeakmode==0) add("squeak(blue)");
|
|
|
|
add("text(blue,0,0,"+words[1]+")");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
int ti=help.Int(words[1].c_str());
|
2022-11-30 00:04:46 +01:00
|
|
|
int nti = ti>=0 ? ti : 1;
|
2021-09-07 03:56:39 +02:00
|
|
|
for(int ti2=0; ti2<nti; ti2++){
|
|
|
|
i++;
|
|
|
|
if(INBOUNDS_VEC(i, lines)){
|
|
|
|
add(lines[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(speakermode){
|
|
|
|
case 0: add("customposition(center)"); break;
|
|
|
|
case 1: add("customposition(cyan,above)"); break;
|
|
|
|
case 2: add("customposition(purple,above)"); break;
|
|
|
|
case 3: add("customposition(yellow,above)"); break;
|
|
|
|
case 4: add("customposition(red,above)"); break;
|
|
|
|
case 5: add("customposition(green,above)"); break;
|
|
|
|
case 6: add("customposition(blue,above)"); break;
|
|
|
|
}
|
|
|
|
add("speak_active");
|
|
|
|
customtextmode=1;
|
|
|
|
}else if(words[0] == "reply"){
|
|
|
|
//For this version, terminal only
|
|
|
|
if(squeakmode==0) add("squeak(player)");
|
|
|
|
add("text(cyan,0,0,"+words[1]+")");
|
|
|
|
|
|
|
|
int ti=help.Int(words[1].c_str());
|
2022-11-30 00:04:46 +01:00
|
|
|
int nti = ti>=0 ? ti : 1;
|
2021-09-07 03:56:39 +02:00
|
|
|
for(int ti2=0; ti2<nti; ti2++){
|
|
|
|
i++;
|
|
|
|
if(INBOUNDS_VEC(i, lines)){
|
|
|
|
add(lines[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
add("position(player,above)");
|
|
|
|
add("speak_active");
|
|
|
|
customtextmode=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(customtextmode==1){ add("endtext"); customtextmode=0;}
|
|
|
|
if(customcutscenemode==1){
|
|
|
|
add("endcutscene()");
|
|
|
|
add("untilbars()");
|
|
|
|
}
|
2020-05-18 19:08:34 +02:00
|
|
|
}
|