Downloads containing Fio_drawing.asc

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

File preview

#include "Fio_utils.asc"

namespace fioDraw {

	const int ANIMATION_GEM_TICKS = 70;
	const int QUEST_BOX_HEIGHT = 120;
	const int QUEST_DISPLAY_TICKS = 770;
	const int TEXT_BOX_HEIGHT = 160;
	const int TEXT_DISPLAY_TICKS = 770;
	const int TOOL_TIP_DISPLAY_TICKS = 630;
	
	bool levelHasCoins = false;
	
	float gemScale = DEFAULT_GEM_SCALE;
	
	int elapsedGem = ANIMATION_GEM_TICKS;
	int elapsedQuestDisplay = 0;
	int elapsedTextDisplay = 0;
	int purpleGemAmount = 0;
	int questTextIndex = 0;
	int textIndex = -1;
	
	// Cheap hack for displaying score penalty warnings, etc.
	string textCustom;
	
	array<string> texts;
	array<string> questTexts;
	
	void animateHud() {
		if (elapsedGem < ANIMATION_GEM_TICKS / 2) {
			gemScale += 0.05;
			elapsedGem++;
		} else if (elapsedGem < ANIMATION_GEM_TICKS) {
			gemScale -= 0.05;
			elapsedGem++;
		}
	}
	
	bool canPlayerAffordAnArmoryItem() {
		for (uint i = 0; i < armoryItems.length(); i++) {
			if (play.coins >= armoryItems[i].cost) {
			 return true;
			}
		}
		return false;
	}
	
	void controlHud() {
		if (elapsedTextDisplay > 0) {
			elapsedTextDisplay--;
		}
		
		if (elapsedQuestDisplay > 0) {
			elapsedQuestDisplay--;
		}
	}
	
	void doGemAnimation() {
		gemScale = DEFAULT_GEM_SCALE;
		elapsedGem = 0;
	}
	
	void doShowOptionalQuest(int setQuestTextIndex) {
		elapsedQuestDisplay = QUEST_DISPLAY_TICKS;
		questTextIndex = setQuestTextIndex;
	}
	
	void doShowText(int setTextIndex) {
		if (uint(setTextIndex) < texts.length()) {
			elapsedTextDisplay = TEXT_DISPLAY_TICKS;
			textIndex = setTextIndex;
		} else {
			jjAlert("|WARNING: Attempted to show a text with index " + setTextIndex + " being out of bounds!");
		}
	}
	
	void doShowTextCustom(string setTextCustom) {
		elapsedTextDisplay = TEXT_DISPLAY_TICKS + 140; // To allow for longer texts to be displayed just slightly longer
		textCustom = setTextCustom;
	}
	
	void drawArmoryAtPos(jjCANVAS@ canvas, int xPos, int yPos, uint8 color = 25) {
		canvas.drawSprite(xPos, yPos, ANIM::BONUS, 0, jjGameTicks / 7 % 10, 0, SPRITE::TINTED, color);
	}
	
	// drawAlternative hack just for Fio3_b...
	void drawArmoryInterface(jjCANVAS@ canvas, uint8 armoryBackgroundColor = 30, bool drawAlternative = false) {
		const string coinsStringColor = canPlayerAffordAnArmoryItem() ? "|" : "";
		const string currentCoinsString = "Current coins: " + coinsStringColor + play.coins + "x";
		const string header = drawAlternative ? "||||Armory of Zyrus" : "||||Infernal Armory";
		const string subHeaderOne = drawAlternative ? "Welcome to the underground armory of Zyrus!" : "The keeper of the infernal armory sells several";
		const string subHeaderTwo = drawAlternative ? "You may find valuable items for your excursion here for a feasible price!" : "items and upgrades to the mortals in the underworld.";
		const int armoryTextBeginningY = jjSubscreenHeight / 4 * 3 - 32;
	
		canvas.drawRectangle(0, 0, jjSubscreenWidth, jjSubscreenHeight, armoryBackgroundColor);
		
		for (uint i = 0; i < armoryItems.length(); i++) {
			armoryItems[i].draw(canvas, i, armoryItems.length());
		}
		
		// Item curtain top
		canvas.drawRectangle(0, 0, jjSubscreenWidth, jjSubscreenHeight / 10, armoryBackgroundColor);
		canvas.drawRectangle(0, jjSubscreenHeight / 10, jjSubscreenWidth, jjSubscreenHeight / 10 + 10, armoryBackgroundColor, SPRITE::BLEND_NORMAL, 128);
		canvas.drawRectangle(0, armoryTextBeginningY - 56, jjSubscreenWidth, jjSubscreenHeight, armoryBackgroundColor); 
		
		// Item curtain bottom (won't fit to the screen on smaller resolutions than 800x600)
		if (jjSubscreenHeight >= 600) {
			canvas.drawRectangle(0, armoryTextBeginningY - 128, jjSubscreenWidth, 64, armoryBackgroundColor, SPRITE::BLEND_NORMAL, 128); 
		}
		
		canvas.drawString(jjSubscreenWidth / 2, armoryTextBeginningY, header, STRING::MEDIUM, centeredText);
		canvas.drawString(jjSubscreenWidth / 2, armoryTextBeginningY + 32, subHeaderOne, STRING::SMALL, centeredText);
		canvas.drawString(jjSubscreenWidth / 2, armoryTextBeginningY + 48, subHeaderTwo, STRING::SMALL, centeredText);
		canvas.drawString(jjSubscreenWidth / 2, armoryTextBeginningY + 80, "Choose an item by arrow keys.", STRING::SMALL, centeredText);
		canvas.drawString(jjSubscreenWidth / 2, armoryTextBeginningY + 96, "Press space/enter to buy.", STRING::SMALL, centeredText);
		canvas.drawString(jjSubscreenWidth / 2, armoryTextBeginningY + 128, currentCoinsString, STRING::SMALL, centeredText);
		canvas.drawSprite(jjSubscreenWidth / 2 + 16 + jjGetStringWidth(currentCoinsString, STRING::SMALL, centeredText)  / 2, armoryTextBeginningY + 124,
				ANIM::PICKUPS, 84, 0 ,0);
		canvas.drawString(jjSubscreenWidth / 2, jjSubscreenHeight - 8, "||(Coins won't carry over to the next level)", STRING::SMALL, centeredText);
		
		if (!areArmoryItemsInMotion) {
			if (selectedArmoryItem > 0) {
				canvas.drawRotatedSprite(jjSubscreenWidth / 2, 32, ANIM::FLAG, 0, 0, 195, 1, 1, SPRITE::PALSHIFT, 40);
			}
			if (selectedArmoryItem < armoryItems.length() - 1) {
				canvas.drawRotatedSprite(jjSubscreenWidth / 2, armoryTextBeginningY - 48, ANIM::FLAG, 0, 0, 695, 1, 1, SPRITE::PALSHIFT, 40);
			}
		}
		
		canvas.drawRotatedSprite(44, jjSubscreenHeight - 32, ANIM::FLAG, 0, 0, 445, 1, 1, SPRITE::PALSHIFT, 40);
		canvas.drawRotatedSprite(jjSubscreenWidth - 44, jjSubscreenHeight - 32, ANIM::FLAG, 0, 0, 945, 1, 1, SPRITE::PALSHIFT, 40);
		canvas.drawString(32, jjSubscreenHeight - 8, "EXIT", STRING::SMALL, centeredText);
		canvas.drawString(jjSubscreenWidth - 32, jjSubscreenHeight - 8, "EXIT", STRING::SMALL, centeredText);
	}
	
	void drawArrowUp(jjCANVAS@ canvas, int x, int y, float scale = 1) {
		canvas.drawRotatedSprite(
				x,
				y,
				ANIM::FLAG,
				0,
				0,
				ARROW_UP_ANGLE,
				scale,
				scale,
				SPRITE::PALSHIFT,
				40
		);
	}
	
	void drawBox(jjCANVAS@ canvas, int originX, int originY, int width, int height, uint8 bodyColor,
			SPRITE::Mode spriteMode = SPRITE::NORMAL, bool borders = false, uint8 borderColor = 0) {
		canvas.drawRectangle(originX, originY, width, height, bodyColor, spriteMode);
		if (borders) {
			canvas.drawRectangle(originX, originY, width, 1, borderColor, spriteMode);
			canvas.drawRectangle(originX, originY, 1, height, borderColor, spriteMode);
			canvas.drawRectangle(originX, originY + height, width, 1, borderColor, spriteMode);
			canvas.drawRectangle(originX + width, originY, 1, height, borderColor, spriteMode);
		}
	}
	
	void drawCoins(jjPLAYER@ play, jjCANVAS@ canvas) {
		drawItem(canvas,
				(totalGemsInLevel > 0 ? 269 : 179),
				30, -15, 84, 0, 1.f, 1.f, 58, -10,
				(play.coins < 10 ? "0" + play.coins : "" + play.coins));
	}
	
	void drawFrameAtPlayerPos(jjPLAYER@ play, jjCANVAS@ canvas, int setId, uint8 animation,
			uint8 frame, int8 direction = 0,
			SPRITE::Mode spriteMode = SPRITE::NORMAL, uint8 spriteParam = 0) {
		canvas.drawSprite(int(play.xPos), int(play.yPos), setId, animation, frame, direction, spriteMode, spriteParam);
	}
	
	void drawGems(jjPLAYER@ play, jjCANVAS@ canvas) {
		const string questColor = play.gems[GEM::PURPLE] >= totalGemsInLevel
				? "|||"
				: play.gems[GEM::PURPLE] >= questGemsInLevel
						? "|" : "";
		drawItem(canvas, 179, 20, -16, 22, 0, gemScale, gemScale, 58, -10,
				questColor + play.gems[GEM::PURPLE] + "/" + (play.gems[GEM::PURPLE] >= questGemsInLevel ? totalGemsInLevel : questGemsInLevel),
				SPRITE::GEM, 3);
	}

	void drawHud(jjPLAYER@ play, jjCANVAS@ canvas, bool isInCutscene = false) {
		if (elapsedTextDisplay > 0 && (textIndex >= 0 || textCustom.length() > 0)) {
			drawTextBox(canvas);
		} else if (elapsedTextDisplay <= 0) {
			textCustom = "";
		}
		
		if (elapsedQuestDisplay > 0 && questTexts.length() > 0) {
			drawQuestBox(canvas);
		} else if (!isInCutscene) {
			if (@currentGameSession !is null) {
				drawPocketCarrots(canvas);
				drawInvincibilities(canvas);
			}
			
			if (questGemsInLevel > 0) {
				drawGems(play, canvas);
			}
			
			if (levelHasCoins) {
				drawCoins(play, canvas);
			}
		}
	}
	
	void drawInvincibilities(jjCANVAS@ canvas) {
		drawItem(canvas, 89, 24, -10, 72, 5, 0.85, 0.85, 58, -10, currentGameSession.invincibilities + "/" + MAX_INVINCIBILITIES);
		
		if (fio::canConsumeInvincibility()) {
			canvas.drawString(170, jjSubscreenHeight - 22, "I", STRING::SMALL, centeredText);
		}
	}
	
	void drawItem(jjCANVAS@ canvas, int originX, int spriteOffsetX, int spriteOffsetY, uint8 spriteAnimation, uint8 spriteFrame,
			float spriteScaleX, float spriteScaleY, int textOffsetX, int textOffsetY, string text,
			SPRITE::Mode spriteMode = SPRITE::NORMAL, uint8 spriteModeParam = 0) {
		drawBox(canvas, originX, jjSubscreenHeight - 34, 90, 34, HUD_BAR_BACKGROUND_COLOR, SPRITE::TRANSLUCENT, true, HUD_BAR_BORDER_COLOR);
		canvas.drawResizedSprite(originX + spriteOffsetX, jjSubscreenHeight + spriteOffsetY, ANIM::PICKUPS, spriteAnimation, spriteFrame,
				spriteScaleX, spriteScaleY, spriteMode, spriteModeParam);
		canvas.drawString(originX + textOffsetX, jjSubscreenHeight + textOffsetY, text, STRING::SMALL, centeredText);
	}
	
	void drawPocketCarrots(jjCANVAS@ canvas) {
		drawItem(canvas, -1, 22, -14, 21, 0, 0.85, 0.85, 58, -10, currentGameSession.pocketCarrots + "/" + MAX_POCKET_CARROTS);
		
		if (fio::canConsumePocketCarrot()) {
			canvas.drawString(78, jjSubscreenHeight - 22, "P", STRING::SMALL, centeredText);
		}
	}
	
	void drawQuestBox(jjCANVAS@ canvas) {
	
		drawBox(canvas, -1, jjSubscreenHeight - 120, jjSubscreenWidth + 1, QUEST_BOX_HEIGHT,
				HUD_BAR_BACKGROUND_COLOR, SPRITE::TRANSLUCENT, true, HUD_BAR_BORDER_COLOR);
		canvas.drawString(jjSubscreenWidth / 2, jjSubscreenHeight - 96, questTexts[questTextIndex], STRING::MEDIUM, centeredText);
		
		if (elapsedQuestDisplay < TOOL_TIP_DISPLAY_TICKS) {
			string tooltip = "Press up (   ) to close (Automatically closing in " + elapsedQuestDisplay / SECOND + "... )";
			int arrowX = jjSubscreenWidth / 2 - jjGetStringWidth(tooltip, STRING::SMALL, centeredText) + 380;
			drawArrowUp(canvas, arrowX, jjSubscreenHeight - 10, 0.66);
			canvas.drawString(
					jjSubscreenWidth / 2,
					jjSubscreenHeight - 16,
					tooltip,
					STRING::SMALL,
					centeredText);
		}
	}
	
	void drawTextBox(jjCANVAS@ canvas) {
		const int textBoxOriginX = jjSubscreenWidth / 6;
		const int textBoxOriginY = 32;
		const int textBoxWidth = jjSubscreenWidth / 3 * 2;
	
		// Check that textIndex points to an actual index to ensure no text is attempted to be displayed prematurely at the beginning of the level
		drawBox(canvas, textBoxOriginX, textBoxOriginY, textBoxWidth, TEXT_BOX_HEIGHT,
				HUD_BAR_BACKGROUND_COLOR, SPRITE::TRANSLUCENT, true, HUD_BAR_BORDER_COLOR);
		if (textIndex >= 0) {
			string processedText = fioUtils::processText(texts[textIndex], jjSubscreenWidth / 2);
			canvas.drawString(jjSubscreenWidth / 2, getTextYPosByNumberOfRows(processedText, textBoxOriginY), processedText,
					STRING::SMALL, centeredText);
		} else if (textCustom.length() > 0) {
			string processedTextCustom = fioUtils::processText(textCustom, jjSubscreenWidth / 2);
			canvas.drawString(jjSubscreenWidth / 2, getTextYPosByNumberOfRows(processedTextCustom, textBoxOriginY), processedTextCustom,
					STRING::SMALL, centeredText);
		}
		if (elapsedTextDisplay < TOOL_TIP_DISPLAY_TICKS) {
			string elapsedText = ":X (" + elapsedTextDisplay / SECOND + "... )";
			drawArrowUp(canvas,
					textBoxOriginX + textBoxWidth - jjGetStringWidth(elapsedText, STRING::SMALL, centeredText) - 10,
					textBoxOriginY + TEXT_BOX_HEIGHT - 6,
					0.66);
			canvas.drawString(
					textBoxOriginX + textBoxWidth - 46,
					textBoxOriginY + TEXT_BOX_HEIGHT - 12,
					elapsedText,
					STRING::SMALL,
					centeredText);
		}
		
		// Apparently some (or all?) onDraw-hooks are called more often than 70 times per second, so don't decrement elapsedTextDisplay here,
		// but in controlHud and call it in e.g. onMain()
	}
	
	int getTextYPosByNumberOfRows(string text, int textBoxOriginY) {
		array<string> rows = text.split("@");
		return textBoxOriginY + (TEXT_BOX_HEIGHT / 2) - ((rows.length() - 1) * 8);
	}
	
	void initializeDrawing(
			array<string> newTexts,
			array<string> newQuestTexts,
			bool newLevelHasCoins = false) {
		texts = newTexts;
		questTexts = newQuestTexts;
		levelHasCoins = newLevelHasCoins;
		
		if (levelHasCoins) {
			jjAnimSets[ANIM::BONUS].load();
		}
		
		gemScale = DEFAULT_GEM_SCALE;
		elapsedGem = ANIMATION_GEM_TICKS;
		elapsedQuestDisplay = 0;
		elapsedTextDisplay = 0;
		questTextIndex = 0;
		textIndex = -1;
	}
}