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