1 /*
2  *  This file is part of Dune Legacy.
3  *
4  *  Dune Legacy is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  Dune Legacy is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with Dune Legacy.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include <Menu/MentatMenu.h>
19 
20 #include <globals.h>
21 
22 #include <FileClasses/GFXManager.h>
23 
24 #include <mmath.h>
25 
26 #include <algorithm>
27 
MentatMenu(int newHouse)28 MentatMenu::MentatMenu(int newHouse)
29  : MenuBase(), currentMentatTextIndex(-1), nextMentatTextSwitch(0)
30 {
31     nextSpecialAnimation = SDL_GetTicks() + getRandomInt(8000, 20000);
32 
33     Animation* anim;
34 
35     disableQuiting(true);
36     house = newHouse;
37 
38     // set up window
39     SDL_Texture *pBackground;
40     if(house == HOUSE_INVALID) {
41         pBackground = pGFXManager->getUIGraphic(UI_MentatBackgroundBene);
42     } else {
43         pBackground = pGFXManager->getUIGraphic(UI_MentatBackground,house);
44     }
45 
46     setBackground(pBackground, false);
47 
48     setCurrentPosition(calcAlignedDrawingRect(pBackground, HAlign::Center, VAlign::Center));
49 
50     setWindowWidget(&windowWidget);
51 
52     switch(house) {
53         case HOUSE_HARKONNEN: {
54             anim = pGFXManager->getAnimation(Anim_HarkonnenEyes);
55             eyesAnim.setAnimation(anim);
56             windowWidget.addWidget(&eyesAnim,Point(64,176),eyesAnim.getMinimumSize());
57 
58             anim = pGFXManager->getAnimation(Anim_HarkonnenMouth);
59             mouthAnim.setAnimation(anim);
60             windowWidget.addWidget(&mouthAnim,Point(64,208),mouthAnim.getMinimumSize());
61 
62             anim = pGFXManager->getAnimation(Anim_HarkonnenShoulder);
63             shoulderAnim.setAnimation(anim);
64             // don't add shoulderAnim, draw it in DrawSpecificStuff
65         } break;
66 
67         case HOUSE_ATREIDES: {
68             anim = pGFXManager->getAnimation(Anim_AtreidesEyes);
69             eyesAnim.setAnimation(anim);
70             windowWidget.addWidget(&eyesAnim,Point(80,160),eyesAnim.getMinimumSize());
71 
72             anim = pGFXManager->getAnimation(Anim_AtreidesMouth);
73             mouthAnim.setAnimation(anim);
74             windowWidget.addWidget(&mouthAnim,Point(80,192),mouthAnim.getMinimumSize());
75 
76             anim = pGFXManager->getAnimation(Anim_AtreidesBook);
77             specialAnim.setAnimation(anim);
78             windowWidget.addWidget(&specialAnim,Point(145,305),specialAnim.getMinimumSize());
79 
80             anim = pGFXManager->getAnimation(Anim_AtreidesShoulder);
81             shoulderAnim.setAnimation(anim);
82             // don't add shoulderAnim, draw it in DrawSpecificStuff
83         } break;
84 
85         case HOUSE_ORDOS: {
86             anim = pGFXManager->getAnimation(Anim_OrdosEyes);
87             eyesAnim.setAnimation(anim);
88             windowWidget.addWidget(&eyesAnim,Point(32,160),eyesAnim.getMinimumSize());
89 
90             anim = pGFXManager->getAnimation(Anim_OrdosMouth);
91             mouthAnim.setAnimation(anim);
92             windowWidget.addWidget(&mouthAnim,Point(32,192),mouthAnim.getMinimumSize());
93 
94             anim = pGFXManager->getAnimation(Anim_OrdosRing);
95             specialAnim.setAnimation(anim);
96             specialAnim.getAnimation()->setCurrentFrameNumber(specialAnim.getAnimation()->getNumberOfFrames()-1);
97             windowWidget.addWidget(&specialAnim,Point(178,289),specialAnim.getMinimumSize());
98 
99             anim = pGFXManager->getAnimation(Anim_OrdosShoulder);
100             shoulderAnim.setAnimation(anim);
101             // don't add shoulderAnim, draw it in DrawSpecificStuff
102         } break;
103 
104         case HOUSE_FREMEN: {
105             anim = pGFXManager->getAnimation(Anim_FremenEyes);
106             eyesAnim.setAnimation(anim);
107             windowWidget.addWidget(&eyesAnim,Point(80,160),eyesAnim.getMinimumSize());
108 
109             anim = pGFXManager->getAnimation(Anim_FremenMouth);
110             mouthAnim.setAnimation(anim);
111             windowWidget.addWidget(&mouthAnim,Point(80,192),mouthAnim.getMinimumSize());
112 
113             anim = pGFXManager->getAnimation(Anim_FremenBook);
114             specialAnim.setAnimation(anim);
115             windowWidget.addWidget(&specialAnim,Point(145,305),specialAnim.getMinimumSize());
116 
117             anim = pGFXManager->getAnimation(Anim_FremenShoulder);
118             shoulderAnim.setAnimation(anim);
119             // don't add shoulderAnim, draw it in DrawSpecificStuff
120         } break;
121 
122         case HOUSE_SARDAUKAR: {
123             anim = pGFXManager->getAnimation(Anim_SardaukarEyes);
124             eyesAnim.setAnimation(anim);
125             windowWidget.addWidget(&eyesAnim,Point(64,176),eyesAnim.getMinimumSize());
126 
127             anim = pGFXManager->getAnimation(Anim_SardaukarMouth);
128             mouthAnim.setAnimation(anim);
129             windowWidget.addWidget(&mouthAnim,Point(64,208),mouthAnim.getMinimumSize());
130 
131             anim = pGFXManager->getAnimation(Anim_SardaukarShoulder);
132             shoulderAnim.setAnimation(anim);
133             // don't add shoulderAnim, draw it in DrawSpecificStuff
134         } break;
135 
136         case HOUSE_MERCENARY: {
137             anim = pGFXManager->getAnimation(Anim_MercenaryEyes);
138             eyesAnim.setAnimation(anim);
139             windowWidget.addWidget(&eyesAnim,Point(32,160),eyesAnim.getMinimumSize());
140 
141             anim = pGFXManager->getAnimation(Anim_MercenaryMouth);
142             mouthAnim.setAnimation(anim);
143             windowWidget.addWidget(&mouthAnim,Point(32,192),mouthAnim.getMinimumSize());
144 
145             anim = pGFXManager->getAnimation(Anim_MercenaryRing);
146             specialAnim.setAnimation(anim);
147             specialAnim.getAnimation()->setCurrentFrameNumber(specialAnim.getAnimation()->getNumberOfFrames()-1);
148             windowWidget.addWidget(&specialAnim,Point(178,289),specialAnim.getMinimumSize());
149 
150             anim = pGFXManager->getAnimation(Anim_MercenaryShoulder);
151             shoulderAnim.setAnimation(anim);
152             // don't add shoulderAnim, draw it in DrawSpecificStuff
153         } break;
154 
155         default: {
156             // bene gese
157             anim = pGFXManager->getAnimation(Anim_BeneEyes);
158             eyesAnim.setAnimation(anim);
159             windowWidget.addWidget(&eyesAnim,Point(128,160),eyesAnim.getMinimumSize());
160 
161             anim = pGFXManager->getAnimation(Anim_BeneMouth);
162             mouthAnim.setAnimation(anim);
163             windowWidget.addWidget(&mouthAnim,Point(112,192),mouthAnim.getMinimumSize());
164         } break;
165     }
166 
167     textLabel.setTextColor(COLOR_WHITE, COLOR_TRANSPARENT);
168     textLabel.setAlignment((Alignment_Enum) (Alignment_Left | Alignment_Top));
169     textLabel.setVisible(false);
170 }
171 
~MentatMenu()172 MentatMenu::~MentatMenu() {
173 }
174 
update()175 void MentatMenu::update() {
176     // speedup blink of the eye
177     eyesAnim.getAnimation()->setFrameRate((eyesAnim.getAnimation()->getCurrentFrameNumber() == MentatEyesClosed) ? 4.0 : 0.5);
178 
179     if(SDL_GetTicks() > nextMentatTextSwitch) {
180         currentMentatTextIndex++;
181 
182         std::string text;
183         if(currentMentatTextIndex >= (int) mentatTexts.size()) {
184             onMentatTextFinished();
185             nextMentatTextSwitch = 0xFFFFFFFF;
186             text = "";
187         } else {
188             text = mentatTexts[currentMentatTextIndex];
189             if(text.empty()) {
190                 onMentatTextFinished();
191                 nextMentatTextSwitch = 0xFFFFFFFF;
192                 currentMentatTextIndex = mentatTexts.size();
193             } else {
194                 nextMentatTextSwitch = SDL_GetTicks() + text.length() * 75 + 1000;
195             }
196         }
197 
198         mouthAnim.getAnimation()->setNumLoops(text.empty() ? 0 : text.length()/25 + 1);
199 
200         textLabel.setText(text);
201         textLabel.setVisible(true);
202         textLabel.resize(620,240);
203     }
204 
205     if(specialAnim.getAnimation() != nullptr && specialAnim.getAnimation()->isFinished()) {
206         if(nextSpecialAnimation < SDL_GetTicks()) {
207             specialAnim.getAnimation()->setNumLoops(1);
208             nextSpecialAnimation = SDL_GetTicks() + getRandomInt(8000, 20000);
209         }
210     }
211 
212     const Point mouse(drawnMouseX - getPosition().x, drawnMouseY - getPosition().y);
213     bool bPressed = (SDL_GetMouseState(nullptr, nullptr) & SDL_BUTTON(SDL_BUTTON_LEFT));
214 
215     const Point eyesPos = windowWidget.getWidgetPosition(&eyesAnim);
216     const Point& eyesSize = eyesAnim.getSize();
217     const Point eyesCenter = eyesPos + eyesSize/2;
218     const Point mouseEyePos = mouse - eyesCenter;
219 
220     eyesAnim.getAnimation()->resetFrameOverride();
221 
222     if((mouseEyePos.x >= -eyesSize.x/2 - 30) && (mouseEyePos.x <= -eyesSize.x/2) && (mouseEyePos.y >= -eyesSize.y/2 - 20) && (mouseEyePos.y <= eyesSize.y/2)) {
223          eyesAnim.getAnimation()->setFrameOverride(MentatEyesLeft);
224     } else if((mouseEyePos.x <= eyesSize.x/2 + 30) && (mouseEyePos.x >= eyesSize.x/2) && (mouseEyePos.y >= -eyesSize.y/2 - 20) && (mouseEyePos.y <= eyesSize.y/2)) {
225          eyesAnim.getAnimation()->setFrameOverride(MentatEyesRight);
226     } else if((abs(mouseEyePos.x) < eyesSize.x) && (mouseEyePos.y >= -eyesSize.y/2 - 20) && (mouseEyePos.y <= eyesSize.y/2)) {
227          eyesAnim.getAnimation()->setFrameOverride(MentatEyesNormal);
228     } else if((abs(mouseEyePos.x) < eyesSize.x) && (mouseEyePos.y > eyesSize.y/2) && (mouseEyePos.y <= eyesSize.y/2 + 15)) {
229          eyesAnim.getAnimation()->setFrameOverride(MentatEyesDown);
230     }
231 
232     if(bPressed && (abs(mouseEyePos.x) <= eyesSize.x/2) && (abs(mouseEyePos.y) <= eyesSize.y/2)) {
233         eyesAnim.getAnimation()->setFrameOverride(MentatEyesClosed);
234     }
235 
236     const Point mouthPos = windowWidget.getWidgetPosition(&mouthAnim);
237     const Point& mouthSize = mouthAnim.getSize();
238     const Point mouthCenter = mouthPos + mouthSize/2;
239     const Point mouseMouthPos = mouse - mouthCenter;
240 
241     if(bPressed) {
242         if((abs(mouseMouthPos.x) <= mouthSize.x/2) && (abs(mouseMouthPos.y) <= mouthSize.y/2)) {
243             if(mouthAnim.getAnimation()->getCurrentFrameOverride() == INVALID_FRAME) {
244                 mouthAnim.getAnimation()->setFrameOverride(getRandomOf(4, MentatMouthOpen1, MentatMouthOpen2, MentatMouthOpen3, MentatMouthOpen4));
245             }
246         } else {
247             mouthAnim.getAnimation()->resetFrameOverride();
248         }
249     } else {
250         mouthAnim.getAnimation()->resetFrameOverride();
251     }
252 }
253 
drawSpecificStuff()254 void MentatMenu::drawSpecificStuff() {
255     Point shoulderPos;
256     switch(house) {
257         case HOUSE_HARKONNEN:
258         case HOUSE_SARDAUKAR: {
259             shoulderPos = Point(256,209) + getPosition();
260         } break;
261 
262         case HOUSE_ATREIDES:
263         case HOUSE_FREMEN: {
264             shoulderPos = Point(256,257) + getPosition();
265         } break;
266 
267         case HOUSE_ORDOS:
268         case HOUSE_MERCENARY: {
269             shoulderPos = Point(256,257) + getPosition();
270         } break;
271 
272         default: {
273             shoulderPos = Point(256,257) + getPosition();
274         } break;
275     }
276 
277     shoulderAnim.draw(shoulderPos);
278     textLabel.draw(Point(10,5) + getPosition());
279 }
280 
281 
282 
getMissionSpecificAnim(int missionnumber) const283 int MentatMenu::getMissionSpecificAnim(int missionnumber) const {
284 
285     static const int missionnumber2AnimID[] = { Anim_ConstructionYard,
286                                                 Anim_Harvester,
287                                                 Anim_Radar,
288                                                 Anim_Quad,
289                                                 Anim_Tank,
290                                                 Anim_RepairYard,
291                                                 Anim_HeavyFactory,
292                                                 Anim_IX,
293                                                 Anim_Palace,
294                                                 Anim_Sardaukar };
295 
296     if(missionnumber < 0 || missionnumber > 9) {
297         return missionnumber2AnimID[0];
298     } else {
299         return missionnumber2AnimID[missionnumber];
300     }
301 }
302