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