Name | Author | Game Mode | Rating | |||||
---|---|---|---|---|---|---|---|---|
Diamondus Ultimate | DoubleGJ | Tileset conversion | 10 |
/* ===Demon Dash dialogue script v1.4===
Written by Violet CLM, minor adjustments by Gnegon Galek
Font in animation file is Kangaroo Court Rotalic
Version history:
v1.1: added scripted events support, use the following format in the same manner as top/bottom line:
finish: function() { jjPrint("hello world"); }
v1.2: sound effects added
v1.3: Mastah Yoman added to character pool, needs color palette entries 248-254 allocated for him, which are unused in every Nick Stadler tileset
v1.4: fixed a null pointer exception occuring when CurrentPopup is initiated by anything other than onFunction# (thx Speaktrap!)
---PUT IN LEVEL SCRIPT, MERGE WITH SAME FUNCTIONS IF NEEDED:---
void onLevelLoad() {
OrderTextAppearance.pipe = STRING::DISPLAYSIGN;
OrderTextAppearance.spacing -= 3;
uint8 i;
for (i = 0; i < 256; ++i)
if (jjAnimSets[ANIM::CUSTOM[i]] == 0) {
@OrderFontAnim = jjAnimations[jjAnimSets[ANIM::CUSTOM[i++]].load(0, "DD-Anims.j2a")];
break;
}
for (; i < 256; ++i)
if (jjAnimSets[ANIM::CUSTOM[i]] == 0) {
jjAnimSets[OrderPortraitSet = ANIM::CUSTOM[i]].load(1, "DD-Anims.j2a");
break;
}
}
bool onDrawScore(jjPLAYER@ play, jjCANVAS@ canvas) {
if (CurrentPopup !is null) {
CurrentPopup.Draw(canvas);
return !CurrentPopup.DrawHUD();
}
return false;
}
bool onDrawAmmo(jjPLAYER@ play, jjCANVAS@ canvas) { return CurrentPopup !is null && !CurrentPopup.DrawHUD(); }
bool onDrawHealth(jjPLAYER@ play, jjCANVAS@ canvas) { return CurrentPopup !is null && !CurrentPopup.DrawHUD(); }
bool onDrawLives(jjPLAYER@ play, jjCANVAS@ canvas) { return CurrentPopup !is null && !CurrentPopup.DrawHUD(); }
bool onDrawPlayerTimer(jjPLAYER@ play, jjCANVAS@ canvas) { return CurrentPopup !is null && !CurrentPopup.DrawHUD(); }
void onPlayer(jjPLAYER@ play) {
const bool inCutscene = CurrentPopup !is null;
jjCharacters[play.charCurr].canRun = !inCutscene; //block revving
if (inCutscene) {
play.timerPause();
play.invincibility = -15;
if (!CurrentPopup.Do())
@CurrentPopup = null;
PressingKeyToMakeCutsceneGoAway = true;
play.keyLeft = play.keyRight = play.keyDown = play.keyUp = play.keyRun = play.keyFire = play.keyJump = play.keySelect = false;
play.idle = 0;
} else {
if (play.keyFire || play.keySelect) {
if (PressingKeyToMakeCutsceneGoAway)
play.keySelect = play.keyFire = false;
} else
PressingKeyToMakeCutsceneGoAway = false;
play.timerResume();
}
}
---ADD TO ONLEVELLOAD IF LEVEL INCLUDES MASTAH YOMAN:---
jjPalette.color[248] = jjPALCOLOR(113, 255, 255);
jjPalette.color[249] = jjPALCOLOR(83, 237, 224);
jjPalette.color[250] = jjPALCOLOR(78, 219, 201);
jjPalette.color[251] = jjPALCOLOR(56, 176, 181);
jjPalette.color[252] = jjPALCOLOR(30, 133, 144);
jjPalette.color[253] = jjPALCOLOR(21, 99, 111);
jjPalette.color[254] = jjPALCOLOR(11, 67, 80);
---APPLY TO DESIRED DIALOGUE EVENT:---
@CurrentPopup = Conversation(array<Screen@> = {
Screen(top: Line("this is an example of the ORDERLOG system! press FIRE or SELECT to continue to the next screen.", left: Jazz, direction: -1)),
Screen(
top: Line("you can display multiple characters onscreen at once. any one of them can be given a speech box.", right: Lori, direction: 1, color: 88),
bottom: Line(left: Addie)
),
Screen(
top: Line("character corners are completely arbitrary, so are text box colors.", left: Eva, right: Jazz, direction: -1, color: 64),
bottom: Line(left: Devan, right: Eva)
),
Screen(bottom: Line("text can also appear at the bottom of the screen. text box tails can point to empty corners for characters who are just out of sight.", direction: 1)),
Screen(
top: Line("if textboxes appear on both the top and bottom of the screen, they fill up with letters simultaneously.", color: 24),
bottom: Line("wow TWO spazes! just like in multiplayer!", left: Spaz, right: Spaz, direction: -1, color: 48)
),
Screen(
top: Line("we sure are glad you came and played through this example level!", left: Jazz, right: Spaz, direction: -1),
bottom: Line("I'M not.", left: Eva, right: Devan, direction: 1, color: 80)
)
});
*/
#pragma require "DD-Anims.j2a"
const jjANIMATION@ OrderFontAnim;
ANIM::Set OrderPortraitSet;
enum Portrait { Devan, Eva, Jazz, Spaz, Addie, Lori, Bubba, Queen, Yoman, _LAST };
Popup@ CurrentPopup = null;
const uint8 FillColor = 15;
const uint8 StrokeColor = 71;
const array<uint8> MultiplyColors = {74, 42, 82, 90, 34, 50, 66};
const int LineSize = 17;
const int StrokeSize = 2;
const int FillSize = LineSize - StrokeSize * 2;
jjTEXTAPPEARANCE OrderTextAppearance(STRING::NORMAL);
abstract class Popup {
Popup(){}
bool Do() {
return true;
}
void Draw(jjCANVAS@ canvas) const { }
bool DrawHUD() const { return false; }
}
class Line {
string Text;
Portrait PLeft, PRight;
uint8 Color;
int TailDirection;
array<string> WrappedLines;
array<int> LinesX;
int Left, Top, Width, Height;
Line(const string &in text = "", Portrait left = Portrait::_LAST, Portrait right = Portrait::_LAST, uint8 color = 16, int direction = 0) { Text = text; PLeft = left; PRight = right; Color = color; TailDirection = direction; }
void Wrap(Portrait pLeft, Portrait pRight, bool isTop) {
const bool tooSmallForPortraits = jjSubscreenWidth < 640 || jjSubscreenHeight < 400;
Left = (tooSmallForPortraits || (pLeft == Portrait::_LAST && TailDirection >= 0)) ? 8 : 173;
Width = jjSubscreenWidth - ((tooSmallForPortraits || (pRight == Portrait::_LAST && TailDirection <= 0)) ? 8 : 173) - Left;
const int maxWidth = Width - 16;
WrappedLines.resize(0);
LinesX.resize(0);
if (Text.length != 0) {
string line = "";
const array<string> words = Text.split(" ");
for (uint wordID = 0; wordID < words.length; ++wordID) {
if (jjGetStringWidth(line + words[wordID], OrderFontAnim, OrderTextAppearance) >= maxWidth) {
WrappedLines.insertLast(line);
LinesX.insertLast(Left + (Width - jjGetStringWidth(line, OrderFontAnim, OrderTextAppearance)) / 2);
line = words[wordID] + " ";
} else
line += words[wordID] + " ";
}
WrappedLines.insertLast(line);
LinesX.insertLast(Left + (Width - jjGetStringWidth(line, OrderFontAnim, OrderTextAppearance)) / 2);
}
Height = WrappedLines.length * 20 + 16;
Top = (isTop ? (tooSmallForPortraits ? 30 : 60) : jjSubscreenHeight - (tooSmallForPortraits ? 30 : 60)) - Height / 2;
if (isTop) {
if (Top < 7)
Top = 7;
} else {
if (Top + Height > jjSubscreenHeight - 7)
Top = jjSubscreenHeight - 7 - Height;
}
}
}
class Screen {
array<Portrait> portraits(4, Portrait::_LAST);
array<Line@> boxes(2);
jjVOIDFUNC@ finishCallback;
Screen(Line@ top = null, Line@ bottom = null, jjVOIDFUNC@ finish = null) {
@boxes[0] = top;
@boxes[1] = bottom;
@finishCallback = finish;
if (top is null && bottom is null)
jjAlert("Please define at least one line!");
if (top !is null) {
portraits[0] = top.PLeft;
portraits[2] = top.PRight;
}
if (bottom !is null) {
portraits[1] = bottom.PLeft;
portraits[3] = bottom.PRight;
}
}
}
class Conversation : Popup {
bool LastSelect = true;
array<array<int>> PortraitX(4, array<int>(Portrait::_LAST, 180));
array<Portrait> PortraitPerCorner(4, Portrait::_LAST);
const array<Screen@>@ Screens;
uint ScreenID = 0;
uint CharactersToDraw;
uint MaxCharactersToDraw;
int LastSubscreenSize;
// string OriginalMusic = jjMusicFileName;
Conversation(const array<Screen@>@ screens) {
@Screens = screens;
if (Screens[ScreenID] !is null) StartScreen();
}
void StartScreen() {
const Screen@ screen = Screens[ScreenID];
for (int cornerID = 0; cornerID < 4; ++cornerID)
PortraitPerCorner[cornerID] = screen.portraits[cornerID];
CharactersToDraw = 0;
if (screen.boxes[0] is null)
MaxCharactersToDraw = screen.boxes[1].Text.length;
else if (screen.boxes[1] is null)
MaxCharactersToDraw = screen.boxes[0].Text.length;
else {
MaxCharactersToDraw = screen.boxes[0].Text.length;
if (screen.boxes[1].Text.length > MaxCharactersToDraw)
MaxCharactersToDraw = screen.boxes[1].Text.length;
}
WrapBoxes();
}
void WrapBoxes() {
LastSubscreenSize = jjSubscreenWidth | (jjSubscreenHeight << 16);
if (Screens[ScreenID].boxes[0] !is null)
Screens[ScreenID].boxes[0].Wrap(PortraitPerCorner[0], PortraitPerCorner[2], true);
if (Screens[ScreenID].boxes[1] !is null)
Screens[ScreenID].boxes[1].Wrap(PortraitPerCorner[1], PortraitPerCorner[3], false);
}
bool Do() {
if (Screens[ScreenID] is null)
return Finish();
if (LastSubscreenSize != jjSubscreenWidth | (jjSubscreenHeight << 16))
WrapBoxes();
for (int cornerID = 0; cornerID < 4; ++cornerID) {
array<int>@ corner = PortraitX[cornerID];
for (int portraitID = 0; portraitID < Portrait::_LAST; ++portraitID) {
if (PortraitPerCorner[cornerID] == portraitID) {
if (corner[portraitID] > 0)
corner[portraitID] -= 6;
} else {
if (corner[portraitID] < 180)
corner[portraitID] += 6;
}
}
if (CharactersToDraw < MaxCharactersToDraw)
jjSamplePriority(SOUND::MENUSOUNDS_TYPE);
}
if (jjKey[8]) //backspace
return Finish();
const bool pressingSelect = jjLocalPlayers[0].keyFire || jjLocalPlayers[0].keySelect || jjKey[1]; //left mouse button
if (!LastSelect && pressingSelect) {
playRandomMenuSample();
if (MaxCharactersToDraw > CharactersToDraw)
CharactersToDraw = MaxCharactersToDraw;
else {
if (Screens[ScreenID].finishCallback !is null)
Screens[ScreenID].finishCallback();
if (++ScreenID >= Screens.length)
return Finish();
else
if (Screens[ScreenID] !is null) StartScreen();
}
}
LastSelect = pressingSelect;
CharactersToDraw += 1;
return true;
}
bool Finish() const {
// jjMusicLoad(OriginalMusic);
return false;
}
void drawH(jjCANVAS@ canvas, int x, int y, int w) {
canvas.drawRectangle(x, y, w, LineSize, StrokeColor);
canvas.drawRectangle(x, y + StrokeSize, w, FillSize, FillColor);
}
void drawV(jjCANVAS@ canvas, int x, int y, int h) {
canvas.drawRectangle(x, y, LineSize, h, StrokeColor);
canvas.drawRectangle(x + StrokeSize, y, FillSize, h, FillColor);
}
void Draw(jjCANVAS@ canvas) const override {
const int width = jjSubscreenWidth;
const int height = jjSubscreenHeight;
int y = 37;
drawH(canvas, 0, y, width);
int x = (width - LineSize) / 2;
drawV(canvas, x, 0, y + StrokeSize);
canvas.drawRectangle(0,0, x,y, MultiplyColors[(ScreenID + 0) % 7],SPRITE::BLEND_MULTIPLY, 255);
canvas.drawRectangle(x+LineSize,0, width-x-LineSize,y, MultiplyColors[(ScreenID + 1) % 7],SPRITE::BLEND_MULTIPLY, 255);
y = height - 53;
drawH(canvas, 0, y, width);
x /= 2;
y += StrokeSize + FillSize;
drawV(canvas, x, y, height - y);
canvas.drawRectangle(0, y + StrokeSize, x, height - y - StrokeSize, MultiplyColors[(ScreenID + 2) % 7],SPRITE::BLEND_MULTIPLY, 255);
canvas.drawRectangle(x + LineSize, y + StrokeSize, x * 3 - x - LineSize, height - y - StrokeSize, MultiplyColors[(ScreenID + 3) % 7],SPRITE::BLEND_MULTIPLY, 255);
x *= 3;
drawV(canvas, x, y, height - y);
canvas.drawRectangle(x + LineSize, y + StrokeSize, width - x - LineSize, height - y - StrokeSize, MultiplyColors[(ScreenID + 4) % 7],SPRITE::BLEND_MULTIPLY, 255);
y = 37 + StrokeSize + FillSize;
drawV(canvas, 43, y, height - 53 - y + StrokeSize);
drawV(canvas, width - 43 - LineSize, y, height - 53 - y + StrokeSize);
canvas.drawRectangle(0, y + StrokeSize, 43, height - 53 - y - StrokeSize, MultiplyColors[(ScreenID + 5) % 7],SPRITE::BLEND_MULTIPLY, 255);
canvas.drawRectangle(width - 43, y + StrokeSize, 43, height - 53 - y - StrokeSize, MultiplyColors[(ScreenID + 6) % 7],SPRITE::BLEND_MULTIPLY, 255);
canvas.drawRectangle(43 + LineSize, 37 + LineSize, width - (43 + LineSize) * 2, height - 37 - 53 - LineSize, 0,SPRITE::SHADOW);
const bool tooSmallForPortraits = width < 640 || height < 400;
if (!tooSmallForPortraits) {
const array<array<int>> portraitLocations = {{0,100}, {0,height-92}, {width-1,100}, {width-1,height-92}};
for (int cornerID = 0; cornerID < 4; ++cornerID) {
const array<int>@ corner = PortraitX[cornerID];
for (int portraitID = 0; portraitID < Portrait::_LAST; ++portraitID) {
const int xOffset = corner[portraitID];
if (xOffset != 180)
canvas.drawSprite(portraitLocations[cornerID][0] + (cornerID >= 2 ? xOffset : -xOffset), portraitLocations[cornerID][1], OrderPortraitSet, portraitID, cornerID & 1, (cornerID >= 2) ? -1 : 1);
}
}
}
for (uint boxID = 0; boxID < 2; ++boxID) {
if (Screens[ScreenID] is null)
continue;
if (Screens[ScreenID].boxes[boxID] is null)
continue;
const Line@ box = Screens[ScreenID].boxes[boxID];
const array<int>@ xs = box.LinesX;
const array<string>@ lines = box.WrappedLines;
if (lines.length != 0) {
canvas.drawRectangle(box.Left, box.Top, box.Width, box.Height, box.Color + 7);
canvas.drawRectangle(box.Left + StrokeSize, box.Top + StrokeSize, box.Width - StrokeSize*2, box.Height - StrokeSize*2, box.Color);
if (box.TailDirection != 0 && !tooSmallForPortraits)
canvas.drawSprite(box.TailDirection < 0 ? 0 : width-1, boxID == 0 ? 80 : height - 82, OrderPortraitSet, Portrait::_LAST, 0, boxID == 0 ? -box.TailDirection : (-box.TailDirection ^ 0x40), SPRITE::SINGLEHUE, box.Color);
int charactersRemaining = CharactersToDraw;
y = box.Top + 16;
for (uint lineID = 0; lineID < lines.length && charactersRemaining > 0; ++lineID) {
canvas.drawString(xs[lineID],y, lines[lineID].substr(0, charactersRemaining), OrderFontAnim, OrderTextAppearance,0, SPRITE::ALPHAMAP,0);
charactersRemaining -= lines[lineID].length;
y += 20;
}
}
}
}
}
void playRandomMenuSample() {
switch(jjRandom()%7) {
case 0: jjSamplePriority(SOUND::MENUSOUNDS_SELECT0); break;
case 1: jjSamplePriority(SOUND::MENUSOUNDS_SELECT1); break;
case 2: jjSamplePriority(SOUND::MENUSOUNDS_SELECT2); break;
case 3: jjSamplePriority(SOUND::MENUSOUNDS_SELECT3); break;
case 4: jjSamplePriority(SOUND::MENUSOUNDS_SELECT4); break;
case 5: jjSamplePriority(SOUND::MENUSOUNDS_SELECT5); break;
case 6: jjSamplePriority(SOUND::MENUSOUNDS_SELECT6); break;
}
}
bool PressingKeyToMakeCutsceneGoAway = false;
bool IsLevelWhereRunningIsAllowed = jjDifficulty < 2;
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.