1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 * Copyright 2020 Google
22 *
23 */
24 #include "hadesch/hadesch.h"
25 #include "hadesch/video.h"
26 #include "hadesch/rooms/monster.h"
27 #include "common/translation.h"
28
29 namespace Hadesch {
30 enum {
31 kBackgroundZ = 10000,
32 kCyclopsZ = 500,
33 kZeusLightZ = 500,
34 kTyphoonZ = 500
35 };
36
37 static const char *kZeusLight = "V7100BJ0";
38 static const int kLightningCutoff = kVideoWidth / 2;
39
revitalisedSound()40 TranscribedSound revitalisedSound() {
41 return g_vm->getRnd().getRandomBit()
42 ? TranscribedSound::make("v7150wd0", "Your branch of life is revitalized")
43 : TranscribedSound::make("v7150we0", "You're back to full strength");
44 }
45
46 class MonsterHandler : public Handler {
47 public:
MonsterHandler()48 MonsterHandler() {
49 _playingShootingSound = false;
50 _countOfIntroLightning = 0;
51 _battleground = Common::SharedPtr<Battleground>(new Battleground());
52 _typhoon = Common::SharedPtr<Typhoon>(new Typhoon(_battleground));
53 _cyclops = Common::SharedPtr<Cyclops>(new Cyclops(_battleground));
54 _illusion = Common::SharedPtr<Illusion>(new Illusion(_battleground));
55 }
56
handleClick(const Common::String & name)57 void handleClick(const Common::String &name) override {
58 if (_battleground->_isInFight && _battleground->_monsterNum == kTyphoon) {
59 _typhoon->handleClick(_typhoon, name);
60 return;
61 }
62
63 if (_battleground->_isInFight && _battleground->_monsterNum == kIllusion) {
64 _illusion->handleClick(name);
65 return;
66 }
67 }
68
handleEvent(int eventId)69 void handleEvent(int eventId) override {
70 Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
71 Persistent *persistent = g_vm->getPersistent();
72
73 _typhoon->handleEvent(eventId);
74 _cyclops->handleEvent(eventId);
75 _illusion->handleEvent(eventId);
76
77 switch (eventId) {
78 case 524:
79 g_vm->getHeroBelt()->setBranchOfLifeFrame(0);
80 break;
81 case 526:
82 g_vm->getHeroBelt()->setThunderboltFrame(kLightning3);
83 break;
84
85 case 15351:
86 room->playAnimWithMusic(kZeusLight, "G0260MA0", kZeusLightZ,
87 PlayAnimParams::keepLastFrame().partial(0, 4),
88 15379); // 15379(anim), 15381(-1), 15359(sound)
89 break;
90 case 15352:
91 room->playVideo("V7190BA0", 0, 15386, Common::Point(0, 216));
92 break;
93 case 15353:
94 room->playAnim(kZeusLight, kZeusLightZ,
95 PlayAnimParams::disappear().partial(4, -1),
96 15358);
97 break;
98 case 15355:
99 room->playSpeech(TranscribedSound::make("V7100WC0",
100 "I'm giving you these thunderbolts to "
101 "use against Hades' monsters."),
102 15364);
103 g_vm->getHeroBelt()->setThunderboltFrame(kLightning2);
104 g_vm->addTimer(526, 5000);
105 break;
106 case 15356:
107 room->playVideo("V7180BB0", 0, 15361, Common::Point(0, 216));
108 break;
109 case 15357:
110 room->playSpeech(g_vm->getRnd().getRandomBit()
111 ? TranscribedSound::make("V7150WC0", "Get back in there. Here is another branch")
112 : TranscribedSound::make("V7150WB0", "Here's another branch. Keep going"),
113 15353);
114 break;
115 case 15358:
116 switch (_battleground->_monsterNum) {
117 case kCyclops:
118 room->playVideo("V7180BB0", 0, 15389, Common::Point(0, 216));
119 break;
120 case kTyphoon:
121 room->playVideo("V7210BB0", 0, 15387, Common::Point(0, 216));
122 break;
123 case kIllusion:
124 room->playVideo("V7220BR0", 0, 15382, Common::Point(0, 216));
125 break;
126 }
127 break;
128 case 15361:
129 g_vm->addTimer(15391, 100);
130 break;
131 case 15364:
132 room->playSpeech(TranscribedSound::make(
133 "V7100WD0",
134 "Ah, and this branch of life will let "
135 "you to remain in the underworld until "
136 "all of its leaves have fallen"),
137 15365);
138 _battleground->_leavesRemaining = 9;
139 g_vm->getHeroBelt()->setBranchOfLifeFrame(1);
140 g_vm->addTimer(524, 5000);
141 break;
142 case 15365:
143 room->playSpeech(TranscribedSound::make(
144 "V7100WE0",
145 "Use your thunderbolts and your hero powers "
146 "to battle the monsters of the underworld"), 15366);
147 _countOfIntroLightning = 0;
148 introLightning();
149 break;
150 case 15366:
151 room->playSpeech(TranscribedSound::make(
152 "V7100WF0",
153 "Move your mouse to aim and click to fire your thunderbolts. "
154 "And don't forget: you can now use your hero powers"),
155 15367);
156 break;
157 case 15367:
158 room->playSpeech(TranscribedSound::make(
159 "V7100WH0",
160 "And remember to keep an eye on your branch. "
161 "When the last leaf drops, you'll be "
162 "banished from the underworld"),
163 15368);
164 break;
165 case 15368:
166 room->playSpeech(TranscribedSound::make(
167 "V7100WI0",
168 "This is the ultimate test but I know you can do it"),
169 15369);
170 break;
171 case 15369:
172 room->playAnim(kZeusLight, kZeusLightZ,
173 PlayAnimParams::disappear().partial(4, -1),
174 15356);
175 break;
176 case 15370:
177 if (++_countOfIntroLightning < 4)
178 introLightning();
179 break;
180 case 15374:
181 room->playAnimWithMusic(kZeusLight, "G0260MA0", kZeusLightZ,
182 PlayAnimParams::keepLastFrame().partial(0, 4),
183 15375);
184 break;
185 case 15375:
186 room->playSpeech(revitalisedSound(), 15376);
187 replenishPowers();
188 break;
189 case 15376:
190 room->playAnim(kZeusLight, kZeusLightZ,
191 PlayAnimParams::disappear().partial(4, -1),
192 15377);
193 break;
194 case 15377:
195 room->playVideo("V7210BB0", 0, 15387, Common::Point(0, 216));
196 break;
197 case 15378:
198 handleEvent(15390);
199 break;
200 case 15379:
201 room->playSpeech(revitalisedSound(), 15380);
202 replenishPowers();
203 break;
204 case 15380:
205 room->playAnim(kZeusLight, kZeusLightZ,
206 PlayAnimParams::disappear().partial(4, -1),
207 15381);
208 break;
209 case 15381:
210 room->playVideo("V7220BR0", 0, 15388, Common::Point(0, 216));
211 break;
212 case 15382:
213 g_vm->addTimer(15392, 100);
214 break;
215 case 15383:
216 if (persistent->_quest == kRescuePhilQuest)
217 g_vm->moveToRoom(kHadesThroneRoom);
218 else {
219 _battleground->_level++;
220 _cyclops->enterCyclops(_battleground->_level);
221 }
222 break;
223 case 15386:
224 // unclear
225 room->playSpeech(
226 persistent->_gender == kMale
227 ? TranscribedSound::make(
228 "V7190WB0",
229 "One more word out of your goat-brain "
230 "and I'm gonna have your face for lambchops, alright? "
231 "This kid's gonna have to make it on his own, ok?")
232 : TranscribedSound::make(
233 "V7190WC0",
234 "One more word out of your goat-brain "
235 "and I'm gonna have your face for lambchops, ok? "
236 "This kid's gonna have to make it on her own."),
237 15374);
238 break;
239 case 15387:
240 room->playSpeech(
241 persistent->_gender == kMale
242 ? TranscribedSound::make(
243 "V7210WB0",
244 "Oh, you want to be a hero? "
245 "Well you're gonna die a hero's death. "
246 "Typhoon's gonna chew you up in little "
247 "pieces and spit you out like a meatgrinder, kid")
248 : TranscribedSound::make(
249 "V7210WC0",
250 "Oh, you want to be a heroine? "
251 "Well you're gonna die a gruesome death. "
252 "Typhoon's gonna chew you up in little "
253 "pieces and spit you out like a meatgrinder, little princess."),
254 15378);
255 break;
256 case 15388:
257 room->playSpeech(TranscribedSound::make(
258 "V7220WB1",
259 "You dare to think you can outwit me? "
260 "You, my little friend, will be ripped to shreads and slowly digested for eternity "
261 "inside a belly of a thousand hideous creatures. You will die a thousand agonizing "
262 "deaths as I now bring down upon you all the forces of Hades."),
263 15382);
264 break;
265 case 15389:
266 // unclear
267 room->playSpeech(TranscribedSound::make(
268 "V7180WB0",
269 "Hey, there. Hi, there. Hoi, there. "
270 "And welcome to my world. "
271 "You know what they say: \"My world - my rules\". "
272 "So here is the rule number one: No trespassing. "
273 "My bouncer will show you the way out. Have a nice day"),
274 15361);
275 break;
276 case 15390:
277 _typhoon->enterTyphoon(1);
278 break;
279 case 15391:
280 _cyclops->enterCyclops(1);
281 break;
282 case 15392:
283 _illusion->enterIllusion(1);
284 break;
285 case 15465:
286 _playingShootingSound = false;
287 break;
288 case kHitReceived:
289 _battleground->_leavesRemaining--;
290 if (_battleground->_leavesRemaining >= 0)
291 g_vm->getHeroBelt()->setBranchOfLifeFrame(10 - _battleground->_leavesRemaining);
292 if (_battleground->_leavesRemaining <= 0) {
293 _battleground->stopFight();
294 room->disableMouse();
295 room->playAnimWithMusic(kZeusLight, "G0260MA0", kZeusLightZ,
296 PlayAnimParams::keepLastFrame().partial(0, 4),
297 15357);
298 }
299 break;
300 }
301 }
302
prepareRoom()303 void prepareRoom() override {
304 Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
305 g_vm->getHeroBelt()->setColour(HeroBelt::kCold);
306 room->loadHotZones("Monster.HOT", false);
307 room->addStaticLayer("v7010pa0", kBackgroundZ, Common::Point(-10, -10)); // background
308 // event 15362+15363
309
310 room->disableMouse();
311 _battleground->_monsterNum = kCyclops;
312 room->playAnimWithMusic(kZeusLight, "G0260MA0", kZeusLightZ,
313 PlayAnimParams::keepLastFrame().partial(0, 4),
314 15355);
315 }
316
frameCallback()317 void frameCallback() override {
318 _battleground->tick();
319 _illusion->tick();
320 }
321
handleAbsoluteClick(Common::Point p)322 void handleAbsoluteClick(Common::Point p) override {
323 Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
324 if (!_battleground->_isInFight)
325 return;
326 _battleground->handleAbsoluteClick(p);
327
328 HeroPower hp = g_vm->getHeroBelt()->getSelectedStrength();
329 bool isStrong = hp == kPowerStrength;
330
331 if (p.x < kLightningCutoff) {
332 room->playAnim(isStrong ? "v7130ba2" : "v7130ba0", 300, PlayAnimParams::disappear(), EventHandlerWrapper(), p);
333 } else {
334 room->playAnim(isStrong ? "v7130ba3" : "v7130ba1", 300, PlayAnimParams::disappear(),
335 EventHandlerWrapper(), p - Common::Point(kLightningCutoff, 0));
336 }
337
338 if (!_playingShootingSound) {
339 switch (hp) {
340 case kPowerStealth:
341 room->playSFX("v7130ea0");
342 break;
343 case kPowerStrength:
344 room->playSFX("v7130eb0");
345 break;
346 case kPowerWisdom:
347 room->playSFX("v7130ec0");
348 break;
349 case kPowerNone:
350 room->playSFX("v7130ee0");
351 break;
352 }
353 _playingShootingSound = true;
354 g_vm->addTimer(15465, g_vm->getRnd().getRandomNumberRng(300, 600));
355 }
356
357 switch (_battleground->_monsterNum) {
358 case kCyclops:
359 _cyclops->handleClick(p);
360 break;
361 case kTyphoon:
362 break;
363 case kIllusion:
364 _illusion->handleAbsoluteClick(p);
365 break;
366 }
367 }
368
369 private:
replenishPowers()370 void replenishPowers() {
371 g_vm->getHeroBelt()->setThunderboltFrame(kLightning2);
372 g_vm->addTimer(526, 5000);
373 _battleground->_leavesRemaining = 9;
374 g_vm->getHeroBelt()->setBranchOfLifeFrame(1);
375 g_vm->addTimer(524, 5000);
376 }
377
introLightning()378 void introLightning() {
379 Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
380 Common::Point target = Common::Point(
381 g_vm->getRnd().getRandomNumberRng(150, 450),
382 g_vm->getRnd().getRandomNumberRng(50, 350));
383 if (target.x < kLightningCutoff) {
384 room->playAnim("v7130ba0", 300, PlayAnimParams::disappear(), 15370, target);
385 } else {
386 room->playAnim("v7130ba1", 300, PlayAnimParams::disappear(), 15370,
387 target - Common::Point(kLightningCutoff, 0));
388 }
389 room->playSFX("v7130eb0");
390 }
391
392 bool _playingShootingSound;
393 int _countOfIntroLightning;
394 Common::SharedPtr<Battleground> _battleground;
395 Common::SharedPtr<Typhoon> _typhoon;
396 Common::SharedPtr<Cyclops> _cyclops;
397 Common::SharedPtr<Illusion> _illusion;
398 };
399
makeMonsterHandler()400 Common::SharedPtr<Hadesch::Handler> makeMonsterHandler() {
401 return Common::SharedPtr<Hadesch::Handler>(new MonsterHandler());
402 }
403
404 }
405