Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Academy | Superjazz | Battle | N/A |
namespace acDrawing {
void drawAreaOfEffect(jjPLAYER@ play, float radius) {
Player@ asPlayer = players[play.playerID];
Spell@ selectedSpell = cast<Spell@>(spells[asPlayer.selectedSpellKey]);
float radiusInTiles = radius * TILE;
jjANIMFRAME@ sprite = jjAnimFrames[jjAnimations[jjAnimSets[ANIM::FLARE].firstAnim].firstFrame + 5];
float scaledRadius = float(sprite.width * radius / 2);
jjTEXTAPPEARANCE centeredText();
centeredText.align = STRING::CENTER;
centeredText.pipe = STRING::SPECIALSIGN;
jjDrawResizedSprite(play.xPos, play.yPos, ANIM::FLARE, 0, 5, radius, radius, SPRITE::TRANSLUCENTCOLOR, AREA_OF_EFFECT_COLOR, 1);
jjDrawString(play.xPos, play.yPos-64, "||Channeling " + selectedSpell.name, STRING::SMALL, centeredText, 0, SPRITE::PALSHIFT,
0, 1);
int8[] targets = acUtils::getTargets(play, selectedSpell, scaledRadius);
if (selectedSpell.enumValue != SPELL_DISPEL) {
array<int8> magicMirrorPlayerIds = acUtils::getMagicMirrorPlayerIdsFromTargets(targets);
for (uint i = 0; i < magicMirrorPlayerIds.length(); i++) {
int8[] additionalTargets = acUtils::getTargets(jjPlayers[magicMirrorPlayerIds[i]], selectedSpell,
scaledRadius, true);
for (uint j = 0; j < additionalTargets.length(); j++) {
if (targets.find(additionalTargets[j]) < 0) {
targets.insertLast(additionalTargets[j]);
}
}
}
acUtils::filterOutMagicMirrorTargets(targets, selectedSpell.enumValue);
}
if (acUtils::areAllTargetsMagicMirrors(targets) && selectedSpell.enumValue != SPELL_DEATH_RIPPLE
&& selectedSpell.enumValue != SPELL_ARMAGEDDON) {
return;
}
for (uint i = 0; i < targets.length(); i++) {
jjDrawResizedSprite(jjPlayers[targets[i]].xPos, jjPlayers[targets[i]].yPos, ANIM::VINE, 0, 0, 2, 3, SPRITE::TRANSLUCENTCOLOR, AREA_OF_EFFECT_TARGET_COLOR, 1);
}
}
void drawBulletPointer(jjPLAYER@ play, Player@ asPlayer) {
if (asPlayer.selectedSpellKey != "") {
Spell@ spell = cast<Spell@>(spells[asPlayer.selectedSpellKey]);
switch (spell.enumValue) {
case SPELL_MAGIC_ARROW:
{
int angle = play.direction >= 0 ? 950 : 425;
int distance = BULLET_POINTER_MAX_DISTANCE*TILE;
drawBulletPointerTrail(play, distance, play.direction);
distance = play.direction >= 0 ? distance : -distance;
jjDrawRotatedSprite(play.xPos+distance, play.yPos, ANIM::FLAG, 0, 0, angle, 1.5, 1.5, SPRITE::TRANSLUCENTCOLOR, AREA_OF_EFFECT_COLOR, 1);
}
break;
case SPELL_ICE_BOLT:
{
int angle = play.direction >= 0 ? 0 : 540;
int distance = BULLET_POINTER_MAX_DISTANCE*TILE;
drawBulletPointerTrail(play, distance, play.direction);
distance = play.direction >= 0 ? distance : -distance;
jjDrawRotatedSprite(play.xPos+distance, play.yPos, ANIM::AMMO, 11, 0, angle, 1.5, 1.5, SPRITE::TRANSLUCENTCOLOR, AREA_OF_EFFECT_COLOR, 1);
}
break;
case SPELL_FIREBALL:
{
int angle = play.direction >= 0 ? 0 : 540;
int distance = acUtils::getBulletPointerDistance(play.xPos, play.yPos, play.direction);
drawBulletPointerTrail(play, distance, play.direction);
distance = play.direction >= 0 ? distance : -distance;
jjDrawRotatedSprite(play.xPos+distance, play.yPos, ANIM::AMMO, 14, 0, angle, 1.5, 1.5, SPRITE::TRANSLUCENTCOLOR, AREA_OF_EFFECT_COLOR, 1);
}
break;
}
}
}
void drawBulletPointerTrail(jjPLAYER@ play, int distance, int direction) {
if (direction >= 0) {
for (float x = play.xPos; x < play.xPos+distance; x += 16) {
jjDrawRectangle(x-1, play.yPos-1, 3, 3, AREA_OF_EFFECT_COLOR, SPRITE::TRANSLUCENT, 1);
}
} else {
for (float x = play.xPos; x > play.xPos-distance; x -= 16) {
jjDrawRectangle(x-1, play.yPos-1, 3, 3, AREA_OF_EFFECT_COLOR, SPRITE::TRANSLUCENT, 1);
}
}
}
// If a player is already "chained" from one target, it cannot be chained from another anymore,
// thus additional targets in the same group may appear "loose" from the chain
void drawChain(ChainLightningTarget@ target, ChainLightningTarget@ parentTarget) {
jjPLAYER@ targetPlayer = jjPlayers[target.playerID];
jjPLAYER@ parentTargetPlayer = jjPlayers[parentTarget.playerID];
float xStart = targetPlayer.xPos <= parentTargetPlayer.xPos ? targetPlayer.xPos : parentTargetPlayer.xPos;
float xEnd = targetPlayer.xPos <= parentTargetPlayer.xPos ? parentTargetPlayer.xPos : targetPlayer.xPos;
float yStart = targetPlayer.yPos <= parentTargetPlayer.yPos ? targetPlayer.yPos : parentTargetPlayer.yPos;
float yEnd = targetPlayer.yPos <= parentTargetPlayer.yPos ? parentTargetPlayer.yPos : targetPlayer.yPos;
float xDist = abs(xEnd - xStart);
float yDist = abs(yEnd - yStart);
if (xDist >= yDist) {
uint yDim = 0;
for (float x = xStart; x < xEnd; x += 8) {
float percentage = (x - xStart) / xDist;
yDim = uint(percentage * 255);
float yDiff = 0;
if ((targetPlayer.xPos <= parentTargetPlayer.xPos && targetPlayer.yPos <= parentTargetPlayer.yPos) ||
(targetPlayer.xPos > parentTargetPlayer.xPos && targetPlayer.yPos > parentTargetPlayer.yPos)) {
yDiff = jjSin(yDim) * yDist;
} else {
yDiff = jjCos(yDim) * yDist;
}
jjDrawRotatedSprite(x, yStart + yDiff, ANIM::AMMO, 4, 0, jjRandom() % 1024, 1, 1, SPRITE::NORMAL, 0, 1);
}
}
else {
uint xDim = 0;
for (float y = yStart; y < yEnd; y += 8) {
float percentage = (y - yStart) / yDist;
xDim = uint(percentage * 255);
float xDiff = 0;
if ((targetPlayer.xPos <= parentTargetPlayer.xPos && targetPlayer.yPos <= parentTargetPlayer.yPos) ||
(targetPlayer.xPos > parentTargetPlayer.xPos && targetPlayer.yPos > parentTargetPlayer.yPos)) {
xDiff = jjSin(xDim) * xDist;
} else {
xDiff = jjCos(xDim) * xDist;
}
jjDrawRotatedSprite(xStart + xDiff, y, ANIM::AMMO, 4, 0, jjRandom() % 1024, 1, 1, SPRITE::NORMAL, 0, 1);
}
}
}
void drawChainLightnings() {
int newIndexGroups = 0;
int chainLightningTargetGroupsLength = chainLightningTargetGroups.length();
for (int i = 0; i < chainLightningTargetGroupsLength; i++) {
array<ChainLightningTarget@> chainLightningTargets = chainLightningTargetGroups[i];
int newIndexTargets = 0;
int chainLightningTargetsLength = chainLightningTargets.length();
for (int j = 0; j < chainLightningTargetsLength; j++) {
ChainLightningTarget@ target = chainLightningTargets[j];
if (target.elapsed > 0) {
jjPLAYER@ play = jjPlayers[target.playerID];
jjDrawRotatedSprite(play.xPos, play.yPos, ANIM::AMMO, 4, 0, jjRandom() % 1024,
CHAIN_LIGHTNING_TARGET_SCALE, CHAIN_LIGHTNING_TARGET_SCALE, SPRITE::NORMAL, 0, 1);
if (target.parentID >= 0) {
ChainLightningTarget@ parentTarget = acUtils::findParentTarget(
chainLightningTargets, target.parentID);
drawChain(target, parentTarget);
}
target.elapsed--;
@chainLightningTargets[newIndexTargets] = target;
newIndexTargets++;
}
}
chainLightningTargets.removeRange(newIndexTargets, chainLightningTargetsLength - newIndexTargets);
if (chainLightningTargetsLength > 0) {
chainLightningTargetGroups[newIndexGroups] = chainLightningTargets;
newIndexGroups++;
}
}
chainLightningTargetGroups.removeRange(newIndexGroups, chainLightningTargetGroupsLength - newIndexGroups);
}
void drawChainLightningTargets(jjPLAYER@ play) {
Spell@ spell = cast<Spell@>(spells["L"]);
float scaledRadius = acUtils::getScaledRadius(spell.radius, ANIM::FLARE, 5);
int8[] targets = acUtils::getTargets(play, spell, scaledRadius);
for (uint i = 0; i < targets.length(); i++) {
int8 targetPlayerID = targets[i];
int8[] newTargets = acUtils::getTargets(jjPlayers[targetPlayerID], spell, scaledRadius);
for (uint j = 0; j < newTargets.length(); j++) {
if (targets.find(newTargets[j]) < 0) {
targets.insertLast(newTargets[j]);
}
}
}
if (!acUtils::areAllTargetsMagicMirrors(targets)) {
for (uint i = 0; i < targets.length(); i++) {
jjDrawResizedSprite(jjPlayers[targets[i]].xPos, jjPlayers[targets[i]].yPos, ANIM::VINE, 0, 0, 2, 3, SPRITE::TRANSLUCENTCOLOR, AREA_OF_EFFECT_TARGET_COLOR, 1);
}
}
}
void drawChannelingBar(jjPLAYER@ play, jjCANVAS@ canvas) {
Spell@ spell = cast<Spell@>(spells[players[play.playerID].selectedSpellKey]);
int channelingBarXOrigin = jjSubscreenWidth / CHANNELING_BAR_ORIGIN_LEFT -
int(spell.channelingTime * SECOND);
int channelingBarYOrigin = jjSubscreenHeight / CHANNELING_BAR_ORIGIN_TOP;
int channelingBarWidth = int(spell.channelingTime * SECOND * 2);
int channelingPercent = channelingElapsed * 2;
acDrawingGeneral::drawBox(canvas, channelingBarXOrigin, channelingBarYOrigin, channelingBarWidth, CHANNELING_BAR_HEIGHT,
CHANNELING_BAR_BODY_COLOR, SPRITE::TRANSLUCENT, true, CHANNELING_BAR_BORDER_COLOR);
acDrawingGeneral::drawBox(canvas, channelingBarXOrigin, channelingBarYOrigin, channelingPercent, CHANNELING_BAR_HEIGHT,
CHANNELING_COLOR, SPRITE::TRANSLUCENT);
}
bool drawHUDObjects(jjPLAYER@ play, jjCANVAS@ canvas) {
Player@ asPlayer = players[play.playerID];
jjTEXTAPPEARANCE spinning(STRING::SPIN);
spinning.xAmp = 0;
spinning.yAmp = -1;
jjTEXTAPPEARANCE centeredText();
centeredText.align = STRING::CENTER;
centeredText.pipe = STRING::SPECIALSIGN;
if (keyMenuState == 2) {
acDrawing::drawKeyMenu(canvas, centeredText);
}
if (infoOpen) {
acDrawing::drawInfo(canvas, asPlayer, centeredText);
} else if (skillsOpen) {
acDrawing::drawSkills(asPlayer, canvas, centeredText);
}
if (players[play.playerID].isChanneling && play.isLocal) {
acDrawing::drawChannelingBar(play, canvas);
}
if (spellBookOpen && play.isLocal) {
acDrawing::drawSpellBook(play, canvas, spinning);
} else if (!infoOpen && asPlayer.cooldown > 0) {
string spellbookText = "Cooldown - " + int(asPlayer.cooldown/70) + " seconds";
canvas.drawString(jjSubscreenWidth - jjGetStringWidth(spellbookText, STRING::SMALL, centeredText) / 2 - 4,
jjSubscreenHeight / SPELLBOOK_ORIGIN_TOP + 16, spellbookText, STRING::SMALL, centeredText);
} else {
acDrawing::drawSpellCastHints(canvas, play, asPlayer, jjSubscreenWidth - SPELL_CAST_HINT_DEFAULT_WIDTH,
jjSubscreenHeight / SPELLBOOK_ORIGIN_TOP + 16, SPELL_CAST_HINT_DEFAULT_WIDTH - 32);
}
if (!infoOpen) {
acDrawing::drawMana(asPlayer, canvas);
acDrawing::drawSelectedSpell(asPlayer, canvas);
if (showResources) acDrawing::drawResources(play, asPlayer, canvas, centeredText);
if (keyMenuState >= 1) acDrawing::drawKeyMenuTab(canvas);
return false;
}
return true;
}
void drawInfo(jjCANVAS@ canvas, Player@ asPlayer, jjTEXTAPPEARANCE centeredText) {
array<string> spellKeys = acInit::loadSpells();
acSpells::updateSpellDescriptions(spellKeys, asPlayer);
for (uint i = 0; i < spellKeys.length(); i++) {
string key = spellKeys[i];
Spell@ spell = cast<Spell@>(spells[key]);
int originX = i % 2 == 0 ? 0 : jjSubscreenWidth / 2;
int originY = SPELL_BOXES_INIT_Y + INFO_BOX_HEIGHT * int(floor(i / 2)) + infoScrollY;
acDrawingGeneral::drawBox(canvas, originX, originY, jjSubscreenWidth / 2, INFO_BOX_HEIGHT,
TEXT_BOX_BODY_COLOR, SPRITE::NORMAL, true, TEXT_BOX_BORDER_COLOR);
drawSpellIcon(asPlayer, canvas, originX + 32, originY + 16, spell.enumValue);
canvas.drawString(originX + 4, originY + 16, "" + spell.tier);
canvas.drawString(originX + 70, originY + 38, "||||" + spell.name);
canvas.drawString(originX + 270, originY + 16, "|Numpad", STRING::SMALL, centeredText);
canvas.drawString(originX + 270, originY + 40, "|" + spell.numpad, STRING::SMALL, centeredText);
canvas.drawString(originX + 344, originY + 16, "|||Mana", STRING::SMALL, centeredText);
drawManaIcon(canvas, originX + 386, originY + 16);
canvas.drawString(originX + 344, originY + 40, "|||" + spell.baseManaCost,
STRING::SMALL, centeredText);
canvas.drawString(originX + jjSubscreenWidth / 4, originY + 80,
acUtils::splitText(spell.description, jjSubscreenWidth / 2 - INFO_BOX_TEXT_MARGIN), STRING::SMALL, centeredText);
}
int spellsLength = spellKeys.length();
if (spellsLength% 2 == 1) {
spellsLength++;
int originX = jjSubscreenWidth / 2;
int originY = SPELL_BOXES_INIT_Y + INFO_BOX_HEIGHT * int(floor(spellKeys.length() / 2)) + infoScrollY;
acDrawingGeneral::drawBox(canvas, originX, originY, jjSubscreenWidth / 2, INFO_BOX_HEIGHT,
TEXT_BOX_BODY_COLOR, SPRITE::NORMAL, true, TEXT_BOX_BORDER_COLOR);
}
if (infoScrollY < SPELL_BOXES_INIT_Y) {
drawScaledArrow(canvas, jjSubscreenWidth / 2, 32, 196, 1);
}
if (acUtils::infoViewIsAboveBottom()) {
drawScaledArrow(canvas, jjSubscreenWidth / 2, jjSubscreenHeight - 32, 708, 1);
}
acDrawingGeneral::drawBox(canvas, 0, 0 + infoScrollY, jjSubscreenWidth, SPELL_BOXES_INIT_Y,
TEXT_BOX_BODY_COLOR, SPRITE::NORMAL, true, TEXT_BOX_BORDER_COLOR);
canvas.drawString(jjSubscreenWidth / 2, 16 + infoScrollY, "||||ACADEMY", STRING::SMALL, centeredText);
canvas.drawString(jjSubscreenWidth / 2, 48 + infoScrollY, acUtils::splitText(ACADEMY_INFO_TEXT, jjSubscreenWidth - 32), STRING::SMALL, centeredText);
canvas.drawString(jjSubscreenWidth / 2, SPELL_BOXES_INIT_Y - 12 + infoScrollY, "||||List of all available spells", STRING::SMALL, centeredText);
hintBoxY = SPELL_BOXES_INIT_Y + INFO_BOX_HEIGHT / 2 * spellsLength + infoScrollY;
acDrawingGeneral::drawBox(canvas, 0, hintBoxY, jjSubscreenWidth, HINT_BOX_HEIGHT,
TEXT_BOX_BODY_COLOR, SPRITE::NORMAL, true, TEXT_BOX_BORDER_COLOR);
canvas.drawString(jjSubscreenWidth / 2, hintBoxY + 64, acUtils::splitText(infoBoxHints[infoBoxHintPage],
jjSubscreenWidth / 2 - INFO_BOX_TEXT_MARGIN), STRING::SMALL, centeredText);
canvas.drawString(jjSubscreenWidth - 256, hintBoxY + HINT_BOX_HEIGHT - 8, "Click here for next hint..");
}
void drawKeyMenu(jjCANVAS@ canvas, jjTEXTAPPEARANCE centeredText) {
acDrawingGeneral::drawBox(canvas, jjSubscreenWidth / 4, jjSubscreenHeight / 4, jjSubscreenWidth / 2, jjSubscreenHeight / 2,
TEXT_BOX_BODY_COLOR, SPRITE::NORMAL, true, TEXT_BOX_BORDER_COLOR);
canvas.drawString(jjSubscreenWidth / 2, jjSubscreenHeight / 4 + 16,
"||||Key menu", STRING::SMALL, centeredText);
canvas.drawString(jjSubscreenWidth / 2, jjSubscreenHeight / 4 + 32,
"Left mouse click on a\nkey binding to change it.", STRING::SMALL, centeredText);
for (uint i = 0; i < keyBindings.length(); i++) {
if (selectionHotkey == int(i)) {
SPRITE::Mode mode = SPRITE::PALSHIFT;
jjTEXTAPPEARANCE appearance = jjTEXTAPPEARANCE(STRING::SPIN);
appearance.align = STRING::CENTER;
appearance.xAmp = 1;
appearance.yAmp = 0;
canvas.drawString(jjSubscreenWidth / 2, jjSubscreenHeight / 4 + 112 + i*16, keyBindings[i], STRING::SMALL, appearance, 0, mode, SELECTED_SPELL_COLOR);
} else {
canvas.drawString(jjSubscreenWidth / 2, jjSubscreenHeight / 4 + 112 + i*16, keyBindings[i], STRING::SMALL, centeredText);
}
}
if (hotkeyInUse) {
canvas.drawString(jjSubscreenWidth / 2, jjSubscreenHeight / 4 * 3 - 32, HOTKEY_IN_USE, STRING::SMALL, centeredText);
}
}
void drawKeyMenuTab(jjCANVAS@ canvas) {
string keyString = getNameByKeyCode(hotkeyKeyMenu) + "-Key menu";
acDrawingGeneral::drawBox(canvas, jjSubscreenWidth / KEY_MENU_TAB_LEFT, 0,
jjGetStringWidth(keyString, STRING::SMALL, jjTEXTAPPEARANCE()) + 8,
RESOURCE_BAR_HEIGHT, TEXT_BOX_BODY_COLOR, SPRITE::NORMAL, true, TEXT_BOX_BORDER_COLOR);
canvas.drawString(jjSubscreenWidth / KEY_MENU_TAB_LEFT + 4, 10, keyString);
}
void drawLayer4(jjPLAYER@ play, jjCANVAS@ canvas) {
jjTEXTAPPEARANCE centeredText();
centeredText.align = STRING::CENTER;
centeredText.pipe = STRING::SPECIALSIGN;
int elevatorTileX = isDuelLevel ? ELEVATOR_TILE_X_DUEL : ELEVATOR_TILE_X;
int elevatorTileY = isDuelLevel ? ELEVATOR_TILE_Y_DUEL : ELEVATOR_TILE_Y;
acDrawing::drawScaledArrow(canvas, elevatorTileX * TILE + 16, elevatorTileY * TILE + 16, 196, 0.7);
if (jjGameTicks % 5 == 0) {
jjPARTICLE@ particle = jjAddParticle(PARTICLE::PIXEL);
if (particle !is null) {
uint randomX = jjRandom() % (8*TILE);
particle.xPos = 60*TILE + randomX;
particle.yPos = 86*TILE;
particle.ySpeed = -7.45;
particle.pixel.color[1] = 34;
particle.pixel.size = 1;
}
}
for (uint i = 0; i < visualGems.length(); i++) {
VisualGem@ gem = visualGems[i];
gem.draw(canvas);
}
for (uint i = 0; i < gemMines.length(); i++) {
gemMines[i].draw(canvas);
}
}
void drawMagicMirrorAnimations() {
uint j = 0;
uint magicMirrorAnimationsLength = magicMirrorAnimations.length();
for (uint i = 0; i < magicMirrorAnimationsLength; i++) {
if (!magicMirrorAnimations[i].draw()) {
@magicMirrorAnimations[j] = magicMirrorAnimations[i];
j++;
}
}
magicMirrorAnimations.removeRange(j, magicMirrorAnimationsLength - j);
}
void drawMana(Player@ asPlayer, jjCANVAS@ canvas) {
string manaString = "|||" + asPlayer.mana + "/" + asPlayer.maxMana;
int stringWidth = jjGetStringWidth(manaString, STRING::SMALL, STRING::NORMAL);
drawManaIcon(canvas, jjSubscreenWidth - stringWidth - 16, jjSubscreenHeight / 8 + 18);
canvas.drawString(jjSubscreenWidth - stringWidth - 8, jjSubscreenHeight / 8 + 24, manaString);
}
void drawManaIcon(jjCANVAS@ canvas, int x, int y) {
canvas.drawResizedSprite(x, y, ANIM::PICKUPS, 22, 0, 0.7, 0.7, SPRITE::GEM, 12);
}
void drawResources(jjPLAYER@ play, Player@ asPlayer, jjCANVAS@ canvas, jjTEXTAPPEARANCE centeredText) {
acDrawingGeneral::drawBox(canvas, 0, jjSubscreenHeight - RESOURCE_BAR_HEIGHT, RESOURCE_BAR_WIDTH, RESOURCE_BAR_HEIGHT,
TEXT_BOX_BODY_COLOR, SPRITE::NORMAL, true, TEXT_BOX_BORDER_COLOR);
acDrawingGeneral::drawBox(canvas, RESOURCE_BAR_WIDTH, jjSubscreenHeight - RESOURCE_BAR_HEIGHT, RESOURCE_BAR_WIDTH, RESOURCE_BAR_HEIGHT,
TEXT_BOX_BODY_COLOR, SPRITE::NORMAL, true, TEXT_BOX_BORDER_COLOR);
canvas.drawResizedSprite(16, jjSubscreenHeight - 7, ANIM::PICKUPS, 34, 0, 0.3, 0.3, SPRITE::GEM, 3);
canvas.drawResizedSprite(RESOURCE_BAR_WIDTH + 16, jjSubscreenHeight - 7, ANIM::PICKUPS, 84, 0, 0.6, 0.6);
canvas.drawString(48, jjSubscreenHeight - 5, "" + play.gems[GEM::PURPLE], STRING::SMALL, centeredText);
if (asPlayer.activeSkills.length() < skills.length()) {
canvas.drawString(96, jjSubscreenHeight - 5,
"(" + secondarySkillCost + ")", STRING::SMALL, centeredText);
}
canvas.drawString(RESOURCE_BAR_WIDTH + 48, jjSubscreenHeight - 5, "" + play.coins, STRING::SMALL, centeredText);
string firstLearnableSpell = acUtils::getFirstLearnableSpell();
if (firstLearnableSpell.length() > 0) {
Spell@ spell = cast<Spell@>(spells[firstLearnableSpell]);
int spellPrice = acUtils::getSpellPriceByTier(spell.tier);
canvas.drawString(RESOURCE_BAR_WIDTH + 96, jjSubscreenHeight - 5,
"(" + spellPrice + ")", STRING::SMALL, centeredText);
}
}
void drawScaledArrow(jjCANVAS@ canvas, int x, int y, int angle, float scale) {
canvas.drawRotatedSprite(x, y, ANIM::FLAG, 0, 0, angle, scale, scale, SPRITE::SINGLECOLOR, 15);
}
void drawSelectedSpell(Player@ asPlayer, jjCANVAS@ canvas) {
int baseX = jjSubscreenWidth - 32;
int baseY = jjSubscreenHeight / 8 + 40;
canvas.drawResizedSprite(baseX, baseY, ANIM::BOLLPLAT, 0, 0, 1.2, 1.2, SPRITE::TRANSLUCENTCOLOR, 1);
SPELL selectedSpell = SPELL_NONE;
if (asPlayer.selectedSpellKey != "") {
selectedSpell = cast<Spell@>(spells[asPlayer.selectedSpellKey]).enumValue;
}
drawSpellIcon(asPlayer, canvas, baseX, baseY, selectedSpell, true);
}
void drawSkills(Player@ asPlayer, jjCANVAS@ canvas, jjTEXTAPPEARANCE centeredText) {
acDrawingGeneral::drawBox(canvas, jjSubscreenWidth / 8, jjSubscreenHeight / 4, jjSubscreenWidth / 4 * 3, jjSubscreenHeight / 2,
TEXT_BOX_BODY_COLOR, SPRITE::NORMAL, true, TEXT_BOX_BORDER_COLOR);
canvas.drawString(jjSubscreenWidth / 2, jjSubscreenHeight / 4 + 16,
"||||Skills", STRING::SMALL, centeredText);
canvas.drawString(jjSubscreenWidth / 2, jjSubscreenHeight / 4 + 32,
acUtils::splitText(SKILLS_TIP, jjSubscreenWidth / 4 * 3 - 64), STRING::SMALL, centeredText);
canvas.drawString(jjSubscreenWidth / 2, jjSubscreenHeight / 4 + 112,
"||||Active Secondary Skills", STRING::SMALL, centeredText);
if (asPlayer.activeSkills.length() == 0) {
canvas.drawString(jjSubscreenWidth / 2, jjSubscreenHeight / 4 + 128, acUtils::splitText(EMPTY_SKILLS, jjSubscreenWidth / 4 * 3 - 64), STRING::SMALL, centeredText);
}
for (uint i = 0; i < asPlayer.activeSkills.length(); i++) {
int index = skills.find(Skill(asPlayer.activeSkills[i]));
if (index >= 0) {
Skill@ skill = skills[index];
canvas.drawString(jjSubscreenWidth / 2, jjSubscreenHeight / 4 + i*16 + 128, skill.name + " (" + skill.description + ")", STRING::SMALL, centeredText);
}
}
}
void drawSpellBook(jjPLAYER@ play, jjCANVAS@ canvas, jjTEXTAPPEARANCE spinning) {
Player@ asPlayer = players[play.playerID];
array<Spell@> spellArray;
for (uint i = 0; i < ownSpells.length(); i++) {
spellArray.insertLast(cast<Spell@>(spells[ownSpells[i]]));
}
spellArray.sortAsc();
int spellBookWidth = TEXT_MARGIN_LEFT * 2 + jjGetStringWidth(
acSpells::getLongestSpellName(), STRING::SMALL, STRING::NORMAL) + 64;
int spellBookHeight = HEADER_MARGIN_TOP * 4 + (ownSpells.length() - 1) * ROW_SPACING;
int spellBookXOrigin = jjSubscreenWidth - spellBookWidth - SPELLBOOK_MARGIN_RIGHT;
int spellBookYOrigin = jjSubscreenHeight / SPELLBOOK_ORIGIN_TOP + 16;
if (ownSpells.length() == 0) {
spellBookHeight = TEXT_MARGIN_TOP * 2 + 3 * 16;
}
acDrawingGeneral::drawBox(canvas, spellBookXOrigin, spellBookYOrigin, spellBookWidth, spellBookHeight, SPELLBOOK_BODY_COLOR, SPRITE::TRANSLUCENT, true, SPELLBOOK_BORDER_COLOR);
canvas.drawResizedSprite(spellBookXOrigin + TEXT_MARGIN_LEFT + 16, spellBookYOrigin + HEADER_MARGIN_TOP, ANIM::PICKUPS, 22, 0, 0.7, 0.7, SPRITE::GEM, 12);
canvas.drawString(spellBookXOrigin + TEXT_MARGIN_LEFT, spellBookYOrigin + HEADER_MARGIN_TOP, " |Numpad |||||Spell");
if (ownSpells.length() == 0) {
jjTEXTAPPEARANCE withNewLine(STRING::NORMAL);
withNewLine.newline = STRING::SPECIALSIGN;
canvas.drawString(spellBookXOrigin + TEXT_MARGIN_LEFT + 48, spellBookYOrigin + TEXT_MARGIN_TOP, EMPTY_SPELLBOOK);
}
for (uint i = 0; i < spellArray.length(); i++) {
Spell@ spell = spellArray[i];
if (spellArray[i].key == asPlayer.selectedSpellKey) {
SPRITE::Mode mode = SPRITE::PALSHIFT;
jjTEXTAPPEARANCE appearance = jjTEXTAPPEARANCE(STRING::SPIN);
appearance.xAmp = 1;
appearance.yAmp = 0;
string spellString = "" + spell.baseManaCost + " " + spellArray[i].numpad + " " + spell.name;
canvas.drawString(spellBookXOrigin + TEXT_MARGIN_LEFT,
spellBookYOrigin + TEXT_MARGIN_TOP + i * ROW_SPACING,
spellString, STRING::SMALL, appearance, 0, mode, SELECTED_SPELL_COLOR);
} else {
jjTEXTAPPEARANCE appearance = jjTEXTAPPEARANCE();
appearance.pipe = STRING::SPECIALSIGN;
string spellString = "|||" + spell.baseManaCost + " ||||||" + spellArray[i].numpad + " |||||" + spell.name;
canvas.drawString(spellBookXOrigin + TEXT_MARGIN_LEFT,
spellBookYOrigin + TEXT_MARGIN_TOP + i * ROW_SPACING,
spellString, STRING::SMALL, appearance, 0);
}
}
drawSpellCastHints(canvas, play, asPlayer, spellBookXOrigin, spellBookYOrigin + spellBookHeight + HEADER_MARGIN_TOP, spellBookWidth - 64);
}
void drawSpellCastHints(jjCANVAS@ canvas, jjPLAYER@ play, Player@ asPlayer, int x, int y, int rowWidth) {
jjTEXTAPPEARANCE appearance = jjTEXTAPPEARANCE();
appearance.newline = STRING::SPECIALSIGN;
if (asPlayer.selectedSpellKey == "I" && activeWallsOfFire.length() >= MAX_ACTIVE_WALLS_OF_FIRE) {
string hint = "There are too many active walls of fire. Max: ||||" + MAX_ACTIVE_WALLS_OF_FIRE;
canvas.drawString(x, y, acUtils::splitText(hint, rowWidth), STRING::SMALL, appearance);
} else if (asPlayer.selectedSpellKey != "") {
Spell@ selectedSpell = cast<Spell@>(spells[asPlayer.selectedSpellKey]);
string hint = acSpells::canCastSpell(players[play.playerID], selectedSpell) ? selectedSpell.channelingTime == 0 ?
"Press fire to cast instantly" : "Hold fire to channel" : "Not enough mana to cast that spell";
canvas.drawString(x, y, acUtils::splitText(hint, rowWidth), STRING::SMALL, appearance);
}
}
void drawSpellIcon(Player@ asPlayer, jjCANVAS@ canvas, int baseX, int baseY, SPELL spellEnum,
bool darkenUncastableSpell = false) {
SPRITE::Mode spriteMode = SPRITE::NORMAL;
uint8 spriteParam = 0;
switch (spellEnum) {
case SPELL_MAGIC_ARROW:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::MENUPLAYER;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 0;
canvas.drawRotatedSprite(baseX + 12, baseY + 20, ANIM::FLAG, 0, 0, 425, 1, 1,
spriteMode, spriteParam);
break;
case SPELL_STONE_SKIN:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::SINGLEHUE;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 65;
canvas.drawRotatedSprite(baseX - 4, baseY + 16, ANIM::JAZZ, RABBIT::IDLE3, 0, 0, 0.7, 0.7,
spriteMode, spriteParam);
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::NORMAL;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 0;
canvas.drawRotatedSprite(baseX + 8, baseY + 28, ANIM::BIGROCK, 0, 0, 0, 0.3, 0.3,
spriteMode, spriteParam);
break;
case SPELL_BLESS:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::NORMAL;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 0;
canvas.drawRotatedSprite(baseX + 2, baseY + 2, ANIM::AMMO, 4, 0, 0, 1.5, 1.5,
spriteMode, spriteParam);
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::SINGLEHUE;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 80;
canvas.drawResizedSprite(baseX + 2, baseY + 20, ANIM::LORI, RABBIT::JUMPING3, 0, 0.8, 0.8,
spriteMode, spriteParam);
break;
case SPELL_BLOOD_LUST:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::SINGLECOLOR;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 24;
canvas.drawResizedSprite(baseX, baseY + 16, ANIM::AMMO, 2, 4, 1, 1,
spriteMode, spriteParam);
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::SINGLEHUE;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 24;
canvas.drawResizedSprite(baseX - 3, baseY + 18, ANIM::SPAZ2, 1, 25, 0.8, 0.8,
spriteMode, spriteParam);
break;
case SPELL_DISPEL:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::NORMAL;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 0;
canvas.drawResizedSprite(baseX + 2, baseY + 8, ANIM::AMMO, 82, 5, 0.8, 0.8,
spriteMode, spriteParam);
canvas.drawResizedSprite(baseX - 3, baseY + 19, ANIM::LORI, RABBIT::HURT, 7, 0.8, 0.8,
spriteMode, spriteParam);
break;
case SPELL_SLOW:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::NORMAL;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 0;
canvas.drawRotatedSprite(baseX, baseY + 4, ANIM::PICKUPS, 42, 0, 0, 0.7, 0.7,
spriteMode, spriteParam);
canvas.drawRotatedSprite(baseX, baseY + 18, ANIM::TURTLE, 0, 0, 0, 0.7, 0.7,
spriteMode, spriteParam);
break;
case SPELL_CURE:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::SINGLEHUE;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 32;
canvas.drawResizedSprite(baseX, baseY + 26, ANIM::PICKUPS, 78, 0, 1, 1,
spriteMode, spriteParam);
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::NORMAL;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 0;
canvas.drawResizedSprite(baseX + 2, baseY + 8, ANIM::AMMO, 8, 0, 0.8, 0.8,
spriteMode, spriteParam);
canvas.drawResizedSprite(baseX + 2, baseY + 2, ANIM::AMMO, 8, 0, 0.5, 0.5,
spriteMode, spriteParam);
break;
case SPELL_DISRUPTING_RAY:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::SINGLEHUE;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 10;
canvas.drawResizedSprite(baseX - 2, baseY + 20, ANIM::JAZZ, RABBIT::FALLLAND, 0, 0.8, 0.8,
spriteMode, spriteParam);
canvas.drawRotatedSprite(baseX + 6, baseY + 24, ANIM::AMMO, 30, 0, 511, 1, 1,
spriteMode, spriteParam);
break;
case SPELL_WEAKNESS:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::NORMAL;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 0;
canvas.drawRotatedSprite(baseX - 5, baseY + 9, ANIM::SPAZ, RABBIT::STATIONARYJUMPSTART, 0, 0, 0.8, 0.8,
spriteMode, spriteParam);
break;
case SPELL_ICE_BOLT:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::TINTED;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 35;
canvas.drawRotatedSprite(baseX - 2, baseY + 18, ANIM::AMMO, 11, 0, 540, 1, 1,
spriteMode, spriteParam);
break;
case SPELL_DEATH_RIPPLE:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::NORMAL;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 0;
canvas.drawRotatedSprite(baseX + 2, baseY + 16, ANIM::SKELETON, 0, 1, 0, 2, 2,
spriteMode, spriteParam);
canvas.drawRotatedSprite(baseX + 2, baseY + 16, ANIM::SKELETON, 0, 3, 0, 2, 2,
spriteMode, spriteParam);
canvas.drawRotatedSprite(baseX, baseY + 14, ANIM::SKELETON, 1, 6, 0, 1.2, 1.2,
spriteMode, spriteParam);
break;
case SPELL_PRECISION:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::NORMAL;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 0;
canvas.drawRotatedSprite(baseX, baseY + 17, ANIM::SONCSHIP, 7, 0, 0, 1.3, 1.3,
spriteMode, spriteParam);
break;
case SPELL_WALL_OF_FIRE:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::NORMAL;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 0;
canvas.drawResizedSprite(baseX + 2, baseY + 24, ANIM::AMMO, 13, 1, 1.8, 1.8,
spriteMode, spriteParam);
break;
case SPELL_FORGETFULNESS:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::NORMAL;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 0;
canvas.drawResizedSprite(baseX - 2, baseY + 18, ANIM::SPAZ, RABBIT::STONED, 0, 0.8, 0.8,
spriteMode, spriteParam);
canvas.drawString(baseX + 4, baseY + 14, "?", STRING::SMALL, jjTEXTAPPEARANCE(STRING::NORMAL), 0,
spriteMode, spriteParam);
break;
case SPELL_FROST_RING:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::TINTED;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 32;
canvas.drawRotatedSprite(baseX - 2, baseY + 16, ANIM::AMMO, 82, 3, 0, 1.2, 1.2,
spriteMode, spriteParam);
break;
case SPELL_FIREBALL:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::NORMAL;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 0;
canvas.drawRotatedSprite(baseX - 2, baseY + 16, ANIM::AMMO, 14, 1, 540, 1.2, 1.2,
spriteMode, spriteParam);
break;
case SPELL_FRENZY:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::SINGLEHUE;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 24;
canvas.drawResizedSprite(baseX, baseY + 14, ANIM::SPAZ, RABBIT::STATIONARYJUMP, 0, 0.8, 0.8,
spriteMode, spriteParam);
break;
case SPELL_CHAIN_LIGHTNING:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::NORMAL;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 0;
canvas.drawRotatedSprite(baseX, baseY + 2, ANIM::AMMO, 4, 0, 0, 1, 1,
spriteMode, spriteParam);
for (int i = 6; i < 28; i += 4) {
canvas.drawRotatedSprite(baseX, baseY + i, ANIM::AMMO, 4, 0, 0, 0.5, 0.5,
spriteMode, spriteParam);
}
canvas.drawRotatedSprite(baseX, baseY + 30, ANIM::AMMO, 4, 0, 0, 1, 1,
spriteMode, spriteParam);
break;
case SPELL_MAGIC_MIRROR:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::SINGLEHUE;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 128;
canvas.drawResizedSprite(baseX - 2, baseY + 16, ANIM::AMMO, 76, 0, 1.5, 1.5,
spriteMode, spriteParam);
break;
case SPELL_ARMAGEDDON:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::TINTED;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 24;
canvas.drawRotatedSprite(baseX + 1, baseY + 18, ANIM::ROCK, 0, 0, 0, 0.4, 0.4,
spriteMode, spriteParam);
break;
case SPELL_IMPLOSION:
spriteMode = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteModeUncastable : SPRITE::NORMAL;
spriteParam = isDrawUncastable(asPlayer, spellEnum, darkenUncastableSpell) ?
spriteParamUncastable : 0;
canvas.drawResizedSprite(baseX + 2, baseY + 16, ANIM::SPAZ, RABBIT::DIE, 1, 0.5, 0.5,
spriteMode, spriteParam);
break;
case SPELL_NONE:
default:
//Draw nothing
break;
}
}
void drawWallOfFire(WallOfFire@ wallOfFire) {
for (float y = wallOfFire.yOrigin; y > wallOfFire.yOrigin - wallOfFire.height*TILE; y -= 32) {
for (float x = wallOfFire.xOrigin; x < wallOfFire.xOrigin + WALL_OF_FIRE_WIDTH*TILE; x += 32) {
jjDrawResizedSprite(x, y, ANIM::AMMO, 13, wallOfFire.frame, 2.5, 2.5);
}
}
if (jjGameTicks % 10 == 0) {
if (wallOfFire.frame < 2) {
wallOfFire.frame = 2;
} else if (wallOfFire.frame < 3) {
wallOfFire.frame = 3;
} else {
wallOfFire.frame = 1;
}
}
jjTEXTAPPEARANCE centeredText();
centeredText.align = STRING::CENTER;
centeredText.pipe = STRING::SPECIALSIGN;
wallOfFire.channel = jjSampleLooped(wallOfFire.xOrigin + WALL_OF_FIRE_WIDTH*TILE/2, wallOfFire.yOrigin,
SOUND::COMMON_BURNIN, wallOfFire.channel);
jjDrawString(wallOfFire.xOrigin + WALL_OF_FIRE_WIDTH*TILE/2 - 20, wallOfFire.yOrigin + 32,
"||||" + int(wallOfFire.elapsed / SECOND), STRING::SMALL, centeredText, 0, SPRITE::PALSHIFT,
0, 1);
}
void drawWallOfFireTarget(jjPLAYER@ play) {
int direction = play.direction;
float xOrigin = play.xPos + direction * WALL_OF_FIRE_CASTING_RANGE;
float yOrigin = play.yPos + 16;
int height = acUtils::getWallOfFireHeightInTiles(xOrigin, yOrigin);
jjDrawRectangle(xOrigin - 16, yOrigin-height*TILE, WALL_OF_FIRE_WIDTH*TILE, height*TILE, AREA_OF_EFFECT_COLOR, SPRITE::TRANSLUCENT, 50, 1);
}
bool isDrawUncastable(Player@ asPlayer, SPELL spellEnum, bool darkenUncastableSpell) {
return darkenUncastableSpell && !acSpells::canCastSpell(asPlayer, spellEnum);
}
}
Jazz2Online © 1999-INFINITY (Site Credits). We have a Privacy Policy. Jazz Jackrabbit, Jazz Jackrabbit 2, Jazz Jackrabbit Advance and all related trademarks and media are ™ and © Epic Games. Lori Jackrabbit is © Dean Dodrill. J2O development powered by Loops of Fury and Chemical Beats.
Eat your lima beans, Johnny.