1 /** 2 * Copyright © Novelate 2020 3 * License: MIT (https://github.com/Novelate/NovelateEngine/blob/master/LICENSE) 4 * Author: Jacob Jensen (bausshf) 5 * Website: https://novelate.com/ 6 * ------ 7 * Novelate is a free and open-source visual novel engine and framework written in the D programming language. 8 * It can be used freely for both personal and commercial projects. 9 * ------ 10 * Module Description: 11 * This is the module for displaying the main menu. 12 */ 13 module novelate.mainmenu; 14 15 import std.conv : to; 16 17 import novelate.config; 18 import novelate.imagecomponent; 19 import novelate.animatedimage; 20 import novelate.media; 21 import novelate.label; 22 import novelate.colormanager; 23 import novelate.layer; 24 import novelate.external; 25 26 import novelate.core : getLayer, LayerType, changeScreen, Screen; 27 import novelate.state : exitGame, playScene; 28 29 package(novelate): 30 /// Shows the main menu. 31 void showMainMenu() 32 { 33 auto backgroundLayer = getLayer(LayerType.background); 34 35 { 36 auto oldBackground = cast(ImageComponent)backgroundLayer.getComponent("background"); 37 38 if (oldBackground) 39 { 40 backgroundLayer.addComponent(oldBackground, "background_old"); 41 backgroundLayer.removeComponent("background"); 42 oldBackground.fadeOut(20); 43 } 44 } 45 46 { 47 auto oldBackground = cast(AnimatedImage)backgroundLayer.getComponent("background"); 48 49 if (oldBackground) 50 { 51 backgroundLayer.addComponent(oldBackground, "background_old"); 52 backgroundLayer.removeComponent("background"); 53 oldBackground.fadeOut(20); 54 } 55 } 56 57 auto backgroundFrames = config.menuBackground; 58 59 if (backgroundFrames && backgroundFrames.frames && backgroundFrames.frames.length) 60 { 61 string[] backgroundImages = []; 62 63 auto frameSpeed = backgroundFrames.frames[0].nextFrameTime; 64 65 foreach (frame; backgroundFrames.frames) 66 { 67 backgroundImages ~= getMediaFile(frame.image).relativePath(backgroundLayer.width); 68 } 69 70 if (backgroundImages && backgroundImages.length) 71 { 72 auto image = new AnimatedImage(backgroundImages); 73 image.animationSpeed = frameSpeed; 74 image.fadeIn(20); 75 image.fadedIn = () 76 { 77 backgroundLayer.removeComponent("background_old"); 78 }; 79 image.fullScreen = true; 80 image.refresh(backgroundLayer.width, backgroundLayer.height); 81 82 backgroundLayer.addComponent(image, "background"); 83 } 84 } 85 86 auto frontLayer = getLayer(LayerType.front); 87 88 auto logoFrames = config.menuLogoImage; 89 90 if (logoFrames && logoFrames.frames && logoFrames.frames.length) 91 { 92 string[] logoImages = []; 93 94 auto frameSpeed = logoFrames.frames[0].nextFrameTime; 95 96 foreach (frame; logoFrames.frames) 97 { 98 logoImages ~= getMediaFile(frame.image).relativePath(frontLayer.width); 99 } 100 101 if (logoImages && logoImages.length) 102 { 103 auto image = new AnimatedImage(logoImages); 104 image.animationSpeed = frameSpeed; 105 image.fadeIn(20); 106 image.position = FloatVector(config.menuLogoImageX800, config.menuLogoImageY800); 107 108 frontLayer.addComponent(image, "logo"); 109 } 110 } 111 112 AltValue!(ptrdiff_t, string) menuBoxOffsetX; 113 AltValue!(ptrdiff_t, string) menuBoxOffsetY; 114 115 if (backgroundLayer.width == 800) 116 { 117 menuBoxOffsetX = config.menuBox_X800; 118 menuBoxOffsetY = config.menuBox_Y800; 119 } 120 else if (backgroundLayer.width == 1024) 121 { 122 menuBoxOffsetX = config.menuBox_X1024; 123 menuBoxOffsetY = config.menuBox_Y1024; 124 } 125 else if (backgroundLayer.width == 1280) 126 { 127 menuBoxOffsetX = config.menuBox_X1280; 128 menuBoxOffsetY = config.menuBox_Y1280; 129 } 130 131 ptrdiff_t offsetX = 0; 132 ptrdiff_t offsetY = 0; 133 134 if (menuBoxOffsetX.value2 && menuBoxOffsetX.value2.length) 135 { 136 switch (menuBoxOffsetX.value2) 137 { 138 case "C": 139 case "Center": 140 offsetX = (backgroundLayer.width / 2); 141 break; 142 143 default: break; 144 } 145 } 146 else 147 { 148 offsetX = menuBoxOffsetX.value1; 149 } 150 151 Label[] labels = []; 152 153 labels ~= createLabel(config.menuItem_Play.text, (b, ref s) 154 { 155 changeScreen(Screen.scene, [playScene]); 156 }, offsetX); 157 158 labels ~= createLabel(config.menuItem_Load.text, (b, ref s) 159 { 160 changeScreen(Screen.load); 161 }, offsetX); 162 163 labels ~= createLabel(config.menuItem_Save.text, (b, ref s) 164 { 165 changeScreen(Screen.save); 166 }, offsetX); 167 168 labels ~= createLabel(config.menuItem_About.text, (b, ref s) 169 { 170 changeScreen(Screen.about); 171 }, offsetX); 172 173 labels ~= createLabel(config.menuItem_Characters.text, (b, ref s) 174 { 175 changeScreen(Screen.characters); 176 }, offsetX); 177 178 labels ~= createLabel(config.menuItem_Exit.text, (b, ref s) 179 { 180 exitGame = true; 181 }, offsetX); 182 183 if (menuBoxOffsetY.value2 && menuBoxOffsetY.value2.length) 184 { 185 size_t totalHeight = 0; 186 187 foreach (label; labels) 188 { 189 totalHeight += label.height; 190 totalHeight += cast(size_t)(cast(double)label.fontSize * 0.5); 191 } 192 193 switch (menuBoxOffsetY.value2) 194 { 195 case "B": 196 case "Bottom": 197 totalHeight += cast(size_t)(cast(double)labels[0].fontSize * 1.5); 198 199 offsetY = (backgroundLayer.height - totalHeight); 200 break; 201 case "T": 202 case "Top": 203 offsetY = cast(ptrdiff_t)(cast(double)labels[0].fontSize * 1.5); 204 break; 205 206 case "C": 207 case "Center": 208 offsetY = cast(ptrdiff_t)((backgroundLayer.height / 2) - (totalHeight / 2)); 209 break; 210 211 default: break; 212 } 213 } 214 else 215 { 216 offsetY = menuBoxOffsetY.value1; 217 } 218 219 foreach (label; labels) 220 { 221 label.position = FloatVector(label.x, offsetY); 222 223 offsetY += label.height; 224 offsetY += cast(size_t)(cast(double)label.fontSize * 0.5); 225 getLayer(LayerType.dialogueBoxInteraction) 226 .addComponent(label, to!string(label.text)); 227 } 228 229 } 230 231 /** 232 * Creates a label for the menu. 233 * Params: 234 * text = The text of the label. 235 * mouseRelease = Handler for when the label is pressed. 236 * offsetX = The x offset of the label. 237 */ 238 private Label createLabel(string text, void delegate(MouseButton button, ref bool stopEvent) mouseRelease, ptrdiff_t offsetX) 239 { 240 auto label = new Label; 241 label.color = colorFromString(config.defaultDialogueColor); 242 label.fontSize = 48; 243 if (config.defaultFont && config.defaultFont.length) 244 { 245 label.fontName = config.defaultFont; 246 } 247 label.text = to!dstring(text); 248 label.position = FloatVector(offsetX - (label.width / 2), 50000); 249 label.mouseRelease = mouseRelease; 250 251 return label; 252 }