Downloads containing Fio_globals.asc

Downloads
Name Author Game Mode Rating
JJ2+ Only: Find It Out (Single Player)Featured Download Superjazz Single player 8.7 Download file

File preview

/* Common global values for all levels */

#include "Fio_entities.asc"
#include "Fio_utils.asc"

// Custom states for more detail besides obj.state
enum StateAttack { STATE_ATTACK_CHARGE, STATE_ATTACK_FLY, STATE_ATTACK_RETURN };

enum StateBall { STATE_BALL_APPEAR, STATE_BALL_DEFAULT, STATE_BALL_FALL };

enum StateHellKnight { STATE_HELL_KNIGHT_APPEAR, STATE_HELL_KNIGHT_ATTACK_EXPAND_RING,
		STATE_HELL_KNIGHT_ATTACK_FOCUS_RING, STATE_HELL_KNIGHT_IDLE, STATE_HELL_KNIGHT_DIE };
			
enum StateStaticPlayerRender {
		STATE_STATIC_PLAYER_RENDER_OFF,
		STATE_STATIC_PLAYER_RENDER_IDLE,
		STATE_STATIC_PLAYER_RENDER_FOCUSED,
		STATE_STATIC_PLAYER_RENDER_FRIGHTENED,
		STATE_STATIC_PLAYER_RENDER_FALLING
};
			
enum StateRabbit { STATE_RABBIT_CONFUSED, STATE_RABBIT_DEFAULT, STATE_RABBIT_FALL,
		STATE_RABBIT_FRIGHTENED, STATE_RABBIT_HURT, STATE_RABBIT_RUN, STATE_RABBIT_SKID,
		STATE_RABBIT_TELEIN, STATE_RABBIT_TELEOUT, STATE_RABBIT_WAITING };

const bool isDebugModeOn = false;

const float BOSS_HEALTH_BAR_OFFSET_X = 40.f;
const float DESTRUCT_SCENERY_HEALTH_BAR_OFFSET_X = 20.f;
const float DESTRUCT_SCENERY_HEALTH_BAR_OFFSET_Y = 20.f;
const float DEFAULT_GEM_SCALE = 1.f;

const int ARMORY_ITEM_MOTION_DURATION = 35;
const int ARROW_UP_ANGLE = 190;
const int BOSS_HEALTH_BAR_LENGTH = 80;
const int DESTRUCT_SCENERY_HEALTH_BAR_LENGTH = 40.f;
const int FRAME_RATE_INTRO_RABBIT = 2;
const int INVINCIBILITY_DURATION = SECOND * 10;
const int LIGHTING_DARK = 60;
const int LIGHTING_STANDARD = 100;
const int LIGHTING_TWILIGHT = 80;
const int MAXIMUM_AMMO = 99;
const int MAXIMUM_HEADER_OPACITY = 255;
const int MINIMUM_HEADER_OPACITY = 80; // For some weird reason the real opacity resets to minimum at somewhere around value 96 o_o
const int PLAYER_POINT_LOSS_FOR_DEATH = 1000;

const uint8 CUSTOM_ENEMY_JUST_HIT_LENGTH = 5;
const uint8 HUD_BAR_BACKGROUND_COLOR = 47;
const uint8 HUD_BAR_BORDER_COLOR = 24;
const uint8 KEY_CODE_ARROW_DOWN = 40;
const uint8 KEY_CODE_ARROW_UP = 38;
const uint8 KEY_CODE_P = 80;
const uint8 KEY_CODE_ENTER = 13;
const uint8 KEY_CODE_I = 73;
const uint8 KEY_CODE_SPACE = 32;
const uint8 MAX_INVINCIBILITIES = 1; // Max 1 to balance boss fights
const uint8 MAX_POCKET_CARROTS = 3; // Should not be too many to avoid health stacking
const uint8 MINDSTONE_COMMUNICATION_BACKGROUND_COLOR = 31;

const uint CYCLE_DELAY_FINISH = 35;
const uint CUTSCENE_SECOND = 35;
const uint SECOND = 70;
const uint TILE = 32;

const string BOSS_THEME_FILENAME = "Boss2.j2b";
const string KEY_MOUSE_LEFT_CLICK = "left mouse";
const string GAME_SESSIONS_FILENAME = "Fio_game_sessions.asdat";
const string RESPAWN_WARNING_TEXT = "||||Welcome back to life! However, Although your lives are infinite, beware of dying too much, "
		+ "for every respawn from now on will cost you ||||||" + PLAYER_POINT_LOSS_FOR_DEATH + "|| points, down to score 0.";

float playerXPosOnHold;
float playerYPosOnHold;

int armoryItemIndexInvincibility = -1;
int armoryItemIndexPocketCarrot = -1;
int armoryItemsMotionElapsed = 0; // Upper level counter to ensure that player cannot change selected armory item during motion
int idlePlayerDirection = 0;
int questGemsInLevel;
int questRewardPoints;
int questPerfectRewardPoints;
int totalGemsInLevel;

uint selectedArmoryItem = 0;

// Quick hack for rendering static falling animation
uint8 playerFallingFrame = 0;

array<uint16> mindstoneCommunicationTileIds;

bool areArmoryItemsInMotion = false;
bool bonusRewardGiven = false;
bool isCustomBossActivated = false;
bool forceMoveRight = false;
bool hasLevelCycleBeenInitiated = false; // To ensure that the process won't get called multiple tiles, e.g. from multiple text event functions
bool isPlayerInArmory = false;
bool isPlayerHiddenAndUnableToMove = false;
bool isPlayerUnableToMove = false;
bool keyFireReleased = true;
bool perfectBonusRewardGiven = false;
bool playerPropertiesReinitialized = false;
bool shouldStorePlayerEquipment = true; // To be set to false when the player enters a boss fight to preserve ammo upon death
bool wasEquipmentPreserveAlertDisplayed = false;

array<bool> activeTriggers(32, false);

array<Key> keys(256);

array<ArmoryItem@> armoryItems;

array<Checkpoint@> checkpoints;

array<GameSession@> gameSessions;

jjPLAYER@ play = jjLocalPlayers[0];

jjTEXTAPPEARANCE centeredText();

StateStaticPlayerRender staticPlayerRenderState = STATE_STATIC_PLAYER_RENDER_OFF;

GameSession@ currentGameSession;

Player@ asPlay;

void calculateTotalCoinAmountFromLevelForDebug() {
	jjLAYER@ spriteLayer = jjLayers[4];
	int count = 0;
	
	for (int y = 0; y < spriteLayer.height; ++y) {
		// No tileWidth checkbox used for sprite layers so far
		for (int x = 0; x < spriteLayer.width; ++x) {
			int eventID = jjEventGet(uint16(x), uint16(y));
			if (eventID == OBJECT::SILVERCOIN) {
				count++;
			} else if (eventID == OBJECT::GOLDCOIN) {
				count += 5;
			}
		}
	}
	jjAlert("total coin count: " + count);
}

int calculateTotalGemAmountFromLevel() {
	jjLAYER@ spriteLayer = jjLayers[4];
	int count = 0;
	
	for (int y = 0; y < spriteLayer.height; ++y) {
		// No tileWidth checkbox used for sprite layers so far
		for (int x = 0; x < spriteLayer.width; ++x) {
			int eventID = jjEventGet(uint16(x), uint16(y));
			if (eventID == OBJECT::PURPLEGEM) {
				count++;
			} else if (eventID == OBJECT::GEMBARREL || eventID == OBJECT::GEMCRATE) {
				if (isDebugModeOn) {
					jjAlert("Barrel or crate gem count: " + (jjParameterGet(x, y, 12, 4)));
				}
				count += jjParameterGet(x, y, 12, 4);
			}
		}
	}
	if (isDebugModeOn) {
		jjAlert("total purple gem count: " + count);
	}
	return count;
}

int getRandomUnusedGameId() {
	if (gameSessions.length() > 10000) {
		jjAlert("|WARNING: The amount of stored game sessions became dangerously high (over 10 thousand)!");
		jjAlert("|Finishing the level will cause existing game sessions to be cleared out to avoid memory issues.");
		jjAlert("|This may be a cause of new game sesions not being started and stored naturally");
		jjAlert("|or you have been playing like a maniac.");
		gameSessions = array<GameSession@>(0);
	}
	
	int randomId = jjRandom();
	
	// There should be way less than 100k food available throughout the whole episode, so the real player food value should never conflict with the ID
	while (randomId < 100000 || isIdExisting(randomId)) {
		randomId = jjRandom();
	}
	return randomId;
}

void initializeGameSessions(bool shouldLevelCycleWriteNewGameSessionToFile) {
	fioUtils::readGameSessionsFromFile();
	@currentGameSession = fioUtils::getCurrentGameSessionByPlayerFood(play);
	if (@currentGameSession is null) {
		// Always ensure a non-null handle on currentGameSession so that we don't have to perform null-checks everywhere,
		// but instead skip this one from the gameSessions that get written on file if shouldLevelCycleWriteNewGameSessionToFile equals to false
		@currentGameSession = GameSession();
		currentGameSession.id = getRandomUnusedGameId();
		currentGameSession.startedTime = jjUnixTimeMs();
		currentGameSession.charOrig = play.charOrig;
		currentGameSession.difficulty = jjDifficultyOrig;
		if (shouldLevelCycleWriteNewGameSessionToFile) {
			gameSessions.insertLast(currentGameSession);
		}
		play.food = 0; // Just in case the game session re-initializes after failing to load game sessions from a save point or something
	} else {
		play.food = currentGameSession.food;
	}
}

void initializeGlobals(
		array<Checkpoint@> checkPointsFromLevel,
		int questGemAmountFromLevel = 0,
		int questRewardPointsFromLevel = 7000,
		int questPerfectRewardPointsFromLevel = 3000,
		bool shouldLevelCycleWriteNewGameSessionToFile = true) {
	
	// Always initialize game session stuff, so that even cutscene levels can modify currentGameSession.cutscenesWatched
	initializeGameSessions(shouldLevelCycleWriteNewGameSessionToFile);
	@asPlay = Player(play);
	staticPlayerRenderState = STATE_STATIC_PLAYER_RENDER_OFF;
	playerFallingFrame = 0; // Don't remember why I need to reset this here
	
	// Basically meant to be infinite by replenishing this value with +1 in every reloadGlobals call (via onLevelReload and handleLevelReload in common)	
	play.lives = 999;
	
	checkpoints = checkPointsFromLevel;
	questGemsInLevel = questGemAmountFromLevel;
	totalGemsInLevel = calculateTotalGemAmountFromLevel();
	questRewardPoints = questRewardPointsFromLevel;
	questPerfectRewardPoints = questPerfectRewardPointsFromLevel;
	
	if (isDebugModeOn) {
		calculateTotalCoinAmountFromLevelForDebug();
	}
	
	centeredText.align = STRING::CENTER;
	centeredText.pipe = STRING::SPECIALSIGN;
	centeredText.at = STRING::SPECIALSIGN;
	centeredText.newline = STRING::SPECIALSIGN;
	centeredText.section = STRING::SPECIALSIGN;
	
	jjUseLayer8Speeds = true;
	
	jjObjectPresets[OBJECT::DESTRUCTSCENERY].points = 0;
	jjObjectPresets[OBJECT::STOMPSCENERY].points = 0;
	jjObjectPresets[OBJECT::TRIGGERCRATE].points = 0;
	jjObjectPresets[OBJECT::SPRINGCRATE].points = 0;
	jjObjectPresets[OBJECT::SPIKEBOLL].bulletHandling = HANDLING::DESTROYBULLET;
	
	jjWeapons[WEAPON::SEEKER].comesFromGunCrates = false;
	
	PurpleGem(jjObjectPresets[OBJECT::PURPLEGEM]);
	
	RemovableAmmo15(jjObjectPresets[OBJECT::BOUNCERAMMO15]);
	RemovableAmmo15(jjObjectPresets[OBJECT::ICEAMMO15]);
	RemovableAmmo15(jjObjectPresets[OBJECT::RFAMMO15]);
	RemovableAmmo15(jjObjectPresets[OBJECT::SEEKERAMMO15]);
	RemovableAmmo15(jjObjectPresets[OBJECT::TOASTERAMMO15]);
	
	RemovableCrate(jjObjectPresets[OBJECT::BOMBCRATE]);
	RemovableCrate(jjObjectPresets[OBJECT::CARROTBARREL]);
	RemovableCrate(jjObjectPresets[OBJECT::CARROTCRATE]);
	RemovableCrate(jjObjectPresets[OBJECT::GEMBARREL]);
	RemovableCrate(jjObjectPresets[OBJECT::GEMCRATE]);
	RemovableCrate(jjObjectPresets[OBJECT::GUNCRATE]);
	RemovableCrate(jjObjectPresets[OBJECT::GUNBARREL]);
	RemovableCrate(jjObjectPresets[OBJECT::ONEUPBARREL]);
	RemovableCrate(jjObjectPresets[OBJECT::ONEUPCRATE]);
	RemovableCrate(jjObjectPresets[OBJECT::TRIGGERCRATE]);
	
	RemovableEnemy(jjObjectPresets[OBJECT::BAT]);
	RemovableEnemy(jjObjectPresets[OBJECT::DEMON]);
	RemovableEnemy(jjObjectPresets[OBJECT::DOGGYDOGG]);
	RemovableEnemy(jjObjectPresets[OBJECT::DRAGON]);
	RemovableEnemy(jjObjectPresets[OBJECT::FATCHICK]);
	RemovableEnemy(jjObjectPresets[OBJECT::FLOATLIZARD]);
	RemovableEnemy(jjObjectPresets[OBJECT::HELMUT]);
	RemovableEnemy(jjObjectPresets[OBJECT::LIZARD]);
	RemovableEnemy(jjObjectPresets[OBJECT::RAPIER]);
	RemovableEnemy(jjObjectPresets[OBJECT::RAVEN]);
	RemovableEnemy(jjObjectPresets[OBJECT::SKELETON]);
	RemovableEnemy(jjObjectPresets[OBJECT::SUCKER]);
	RemovableEnemy(jjObjectPresets[OBJECT::TUFTURT]);
	
	RemovableMonitor(jjObjectPresets[OBJECT::FIRESHIELD]);
	
	RemovablePickup(jjObjectPresets[OBJECT::APPLE]);
	RemovablePickup(jjObjectPresets[OBJECT::BOUNCERAMMO3]);
	RemovablePickup(jjObjectPresets[OBJECT::BURGER]);
	RemovablePickup(jjObjectPresets[OBJECT::CARROT]);
	RemovablePickup(jjObjectPresets[OBJECT::CHEESE]);
	RemovablePickup(jjObjectPresets[OBJECT::CHERRY]);
	RemovablePickup(jjObjectPresets[OBJECT::CHICKENLEG]);
	RemovablePickup(jjObjectPresets[OBJECT::CHOCBAR]);
	RemovablePickup(jjObjectPresets[OBJECT::CUCUMB]);
	RemovablePickup(jjObjectPresets[OBJECT::EGGPLANT]);
	RemovablePickup(jjObjectPresets[OBJECT::FASTFIRE]);
	RemovablePickup(jjObjectPresets[OBJECT::FRIES]);
	RemovablePickup(jjObjectPresets[OBJECT::FULLENERGY]);
	RemovablePickup(jjObjectPresets[OBJECT::GOLDCOIN]);
	RemovablePickup(jjObjectPresets[OBJECT::GRAPES]);
	RemovablePickup(jjObjectPresets[OBJECT::GUN8AMMO3]);
	RemovablePickup(jjObjectPresets[OBJECT::HAM]);
	RemovablePickup(jjObjectPresets[OBJECT::ICEAMMO3]);
	RemovablePickup(jjObjectPresets[OBJECT::LEMON]);
	RemovablePickup(jjObjectPresets[OBJECT::LETTUCE]);
	RemovablePickup(jjObjectPresets[OBJECT::LIME]);
	RemovablePickup(jjObjectPresets[OBJECT::ORANGE]);
	RemovablePickup(jjObjectPresets[OBJECT::PEACH]);
	RemovablePickup(jjObjectPresets[OBJECT::PEAR]);
	RemovablePickup(jjObjectPresets[OBJECT::PEPSI]);
	RemovablePickup(jjObjectPresets[OBJECT::PIZZA]);
	RemovablePickup(jjObjectPresets[OBJECT::PRETZEL]);
	RemovablePickup(jjObjectPresets[OBJECT::RFAMMO3]);
	RemovablePickup(jjObjectPresets[OBJECT::SANDWICH]);
	RemovablePickup(jjObjectPresets[OBJECT::SEEKERAMMO3]);
	RemovablePickup(jjObjectPresets[OBJECT::SILVERCOIN]);
	RemovablePickup(jjObjectPresets[OBJECT::SODAPOP]);
	RemovablePickup(jjObjectPresets[OBJECT::TACO]);
	RemovablePickup(jjObjectPresets[OBJECT::TOASTERAMMO3]);
	RemovablePickup(jjObjectPresets[OBJECT::WATERMELON]);
	RemovablePickup(jjObjectPresets[OBJECT::WEENIE]);
	
	// Fireball Gun can be enabled e.g. in onLevelLoad() with jjChat("/fireball on"), but a console text will be displayed
	// Not sure if that would bother me in the level beginning or not, but let's see, maybe I get used to it...
	// EDIT: Fireball is definitely too OP against bosses, therefore disable it unless you can figure out a way to nerf it down a bit...
	// jjChat("/fireball on");
}

bool isIdExisting(int id) {
	for (uint i = 0; i < gameSessions.length(); ++i) {
		if (gameSessions[i].id == id) {
			return true;
		}
	}
	return false;
}

void reloadGlobals() {
	isPlayerInArmory = false;
	if (play.lives < 999) {
		play.lives = 999;
	}
}