PageRenderTime 48ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/engines/cge2/snail.cpp

http://github.com/scummvm/scummvm
C++ | 871 lines | 751 code | 80 blank | 40 comment | 217 complexity | 77772699f8cb32094ac7d38adc963667 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, GPL-2.0
  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. */
  22. /*
  23. * This code is based on original Sfinx source code
  24. * Copyright (c) 1994-1997 Janusz B. Wisniewski and L.K. Avalon
  25. */
  26. #include "cge2/snail.h"
  27. #include "cge2/fileio.h"
  28. #include "cge2/hero.h"
  29. #include "cge2/text.h"
  30. #include "cge2/sound.h"
  31. #include "cge2/events.h"
  32. namespace CGE2 {
  33. const char *CommandHandler::_commandText[] = {
  34. "NOP", "USE", "PAUSE", "INF", "CAVE", "SETX", "SETY", "SETZ", "ADD",
  35. "FLASH", "CYCLE", "CLEAR", "MOUSE", "MAP", "MIDI", ".DUMMY.", "WAIT",
  36. "HIDE", "ROOM", "SAY", "SOUND", "KILL", "RSEQ", "SEQ", "SEND", "SWAP",
  37. "KEEP", "GIVE", "GETPOS", "GOTO", "PORT", "NEXT", "NNEXT", "MTNEXT",
  38. "FTNEXT", "RNNEXT", "RMTNEXT", "RFTNEXT", "RMNEAR", "RMMTAKE", "RMFTAKE",
  39. "SETREF", "WALKTO", "REACH", "COVER", "UNCOVER", "EXEC", "GHOST",
  40. nullptr };
  41. CommandHandler::CommandHandler(CGE2Engine *vm, bool turbo)
  42. : _turbo(turbo), _textDelay(false), _timerExpiry(0), _talkEnable(true),
  43. _head(0), _tail(0), _commandList((Command *)malloc(sizeof(Command)* 256)),
  44. _vm(vm) {
  45. }
  46. CommandHandler::~CommandHandler() {
  47. free(_commandList);
  48. }
  49. void CommandHandler::runCommand() {
  50. if (!_turbo && _vm->_soundStat._wait) {
  51. if (*(_vm->_soundStat._wait))
  52. return;
  53. ++_vm->_soundStat._ref[0];
  54. if (_vm->_fx->exist(_vm->_soundStat._ref[1], _vm->_soundStat._ref[0])) {
  55. int16 oldRepeat = _vm->_sound->getRepeat();
  56. _vm->_sound->setRepeat(1);
  57. _vm->_sound->play(Audio::Mixer::kSpeechSoundType, _vm->_fx->load(_vm->_soundStat._ref[1], _vm->_soundStat._ref[0]), _vm->_sound->_smpinf._span);
  58. _vm->_sound->setRepeat(oldRepeat);
  59. return;
  60. }
  61. _vm->_soundStat._wait = nullptr;
  62. }
  63. uint8 tmpHead = _head;
  64. while (_tail != tmpHead) {
  65. Command tailCmd = _commandList[_tail];
  66. if (!_turbo) { // only for the slower one
  67. if (_vm->_waitRef)
  68. break;
  69. if (_timerExpiry) {
  70. // Delay in progress
  71. if (_timerExpiry > g_system->getMillis())
  72. // Delay not yet ended
  73. break;
  74. // Delay is finished
  75. _timerExpiry = 0;
  76. } else if (_textDelay) {
  77. if (_vm->_talk) {
  78. _vm->snKill((Sprite *)_vm->_talk);
  79. _vm->_talk = nullptr;
  80. }
  81. _textDelay = false;
  82. }
  83. if (_vm->_talk && tailCmd._commandType != kCmdPause)
  84. break;
  85. }
  86. ++_tail;
  87. _vm->_taken = false;
  88. Sprite *spr = nullptr;
  89. if (tailCmd._commandType > kCmdSpr)
  90. spr = (tailCmd._ref < 0) ? ((Sprite *)tailCmd._spritePtr) : _vm->locate(tailCmd._ref);
  91. Common::String sprStr;
  92. if (spr && *spr->_file && (tailCmd._commandType != kCmdGhost))
  93. // In case of kCmdGhost _spritePtr stores a pointer to a Bitmap, not to a Sprite...
  94. sprStr = Common::String(spr->_file);
  95. else
  96. sprStr = "None";
  97. if (sprStr.empty())
  98. sprStr = "None";
  99. debugC(1, kCGE2DebugOpcode, "Command: %s; Ref: %d; Val: %d; Sprite: %s;", getComStr(tailCmd._commandType), tailCmd._ref, tailCmd._val, sprStr.c_str());
  100. switch (tailCmd._commandType) {
  101. case kCmdUse:
  102. break;
  103. case kCmdPause:
  104. _timerExpiry = g_system->getMillis() + tailCmd._val * kCommandFrameDelay;
  105. if (_vm->_talk)
  106. _textDelay = true;
  107. break;
  108. case kCmdWait:
  109. if (spr && spr->active() && (spr->_scene == _vm->_now || spr->_scene == 0)) {
  110. _vm->_waitSeq = tailCmd._val;
  111. _vm->_waitRef = spr->_ref;
  112. }
  113. break;
  114. case kCmdHide:
  115. _vm->snHide(spr, tailCmd._val);
  116. break;
  117. case kCmdSay:
  118. _vm->snSay(spr, tailCmd._val);
  119. break;
  120. case kCmdInf:
  121. if (_talkEnable)
  122. _vm->inf(((tailCmd._val) >= 0) ? _vm->_text->getText(tailCmd._val) : (const char *)tailCmd._spritePtr);
  123. break;
  124. case kCmdCave:
  125. _vm->switchScene(tailCmd._val);
  126. break;
  127. case kCmdMidi:
  128. _vm->snMidi(tailCmd._val);
  129. break;
  130. case kCmdKill:
  131. _vm->snKill(spr);
  132. break;
  133. case kCmdSeq:
  134. _vm->snSeq(spr, tailCmd._val);
  135. break;
  136. case kCmdRSeq:
  137. _vm->snRSeq(spr, tailCmd._val);
  138. break;
  139. case kCmdSend:
  140. _vm->snSend(spr, tailCmd._val);
  141. break;
  142. case kCmdSwap:
  143. _vm->snSwap(spr, tailCmd._val);
  144. break;
  145. case kCmdCover:
  146. _vm->snCover(spr, tailCmd._val);
  147. break;
  148. case kCmdUncover:
  149. _vm->snUncover(spr, (tailCmd._val >= 0) ? _vm->locate(tailCmd._val) : ((Sprite *)tailCmd._spritePtr));
  150. break;
  151. case kCmdKeep:
  152. _vm->snKeep(spr, tailCmd._val);
  153. break;
  154. case kCmdGive:
  155. _vm->snGive(spr, tailCmd._val);
  156. break;
  157. case kCmdSetX:
  158. _vm->_point[tailCmd._val]->_x = tailCmd._ref;
  159. break;
  160. case kCmdSetY:
  161. _vm->_point[tailCmd._val]->_y = tailCmd._ref;
  162. break;
  163. case kCmdSetZ:
  164. _vm->_point[tailCmd._val]->_z = tailCmd._ref;
  165. break;
  166. case kCmdAdd:
  167. *(_vm->_point[tailCmd._ref]) = *(_vm->_point[tailCmd._ref]) + *(_vm->_point[tailCmd._val]);
  168. break;
  169. case kCmdGetPos:
  170. if (spr)
  171. *(_vm->_point[tailCmd._val]) = spr->_pos3D;
  172. break;
  173. case kCmdGoto:
  174. _vm->snGoto(spr, tailCmd._val);
  175. break;
  176. case kCmdPort:
  177. _vm->snPort(spr, tailCmd._val);
  178. break;
  179. case kCmdNext:
  180. break;
  181. case kCmdMouse:
  182. _vm->snMouse(tailCmd._val != 0);
  183. break;
  184. case kCmdNNext:
  185. _vm->snNNext(spr, kNear, tailCmd._val);
  186. break;
  187. case kCmdMTNext:
  188. _vm->snNNext(spr, kMTake, tailCmd._val);
  189. break;
  190. case kCmdFTNext:
  191. _vm->snNNext(spr, kFTake, tailCmd._val);
  192. break;
  193. case kCmdRNNext:
  194. _vm->snRNNext(spr, tailCmd._val);
  195. break;
  196. case kCmdRMTNext:
  197. _vm->snRMTNext(spr, tailCmd._val);
  198. break;
  199. case kCmdRFTNext:
  200. _vm->snRFTNext(spr, tailCmd._val);
  201. break;
  202. case kCmdRMNear:
  203. _vm->snRmNear(spr);
  204. break;
  205. case kCmdRMMTake:
  206. _vm->snRmMTake(spr);
  207. break;
  208. case kCmdRMFTake:
  209. _vm->snRmFTake(spr);
  210. break;
  211. case kCmdSetRef:
  212. _vm->snSetRef(spr, tailCmd._val);
  213. break;
  214. case kCmdFlash:
  215. _vm->snFlash(tailCmd._val != 0);
  216. break;
  217. case kCmdCycle:
  218. _vm->snCycle(tailCmd._val);
  219. break;
  220. case kCmdWalk:
  221. _vm->snWalk(spr, tailCmd._val);
  222. break;
  223. case kCmdReach:
  224. _vm->snReach(spr, tailCmd._val);
  225. break;
  226. case kCmdSound:
  227. _vm->snSound(spr, tailCmd._val);
  228. _vm->_sound->setRepeat(1);
  229. break;
  230. case kCmdMap:
  231. _vm->_heroTab[tailCmd._ref & 1]->_ptr->_ignoreMap = tailCmd._val == 0;
  232. break;
  233. case kCmdRoom:
  234. _vm->snRoom(spr, tailCmd._val);
  235. break;
  236. case kCmdExec:
  237. switch (tailCmd._cbType) {
  238. case kQGame:
  239. _vm->qGame();
  240. break;
  241. case kXScene:
  242. _vm->xScene();
  243. break;
  244. default:
  245. error("Unknown Callback Type in SNEXEC");
  246. break;
  247. }
  248. break;
  249. case kCmdGhost:
  250. _vm->snGhost((Bitmap *)tailCmd._spritePtr);
  251. break;
  252. case kCmdNop: // Do nothing.
  253. break;
  254. default:
  255. warning("Unhandled command");
  256. break;
  257. }
  258. if (_vm->_taken && spr)
  259. _vm->_spare->dispose(spr);
  260. if (!_turbo)
  261. break;
  262. }
  263. }
  264. void CGE2Engine::snKill(Sprite *spr) {
  265. if (spr) {
  266. if (spr->_flags._kept)
  267. releasePocket(spr);
  268. Sprite *nx = spr->_next;
  269. hide1(spr);
  270. _vga->_showQ->remove(spr);
  271. _eventManager->clearEvent(spr);
  272. if (spr->_flags._kill) {
  273. _spare->take(spr->_ref);
  274. delete spr;
  275. } else {
  276. spr->setScene(-1);
  277. _spare->dispose(spr);
  278. }
  279. if (nx && nx->_flags._slav)
  280. snKill(nx);
  281. }
  282. }
  283. void CGE2Engine::snHide(Sprite *spr, int val) {
  284. if (spr) {
  285. spr->_flags._hide = (val >= 0) ? (val != 0) : (!spr->_flags._hide);
  286. if (spr->_flags._shad)
  287. spr->_prev->_flags._hide = spr->_flags._hide;
  288. }
  289. }
  290. void CGE2Engine::snMidi(int val) {
  291. if (val < 0)
  292. _midiPlayer->killMidi();
  293. else if (_music)
  294. _midiPlayer->loadMidi(val);
  295. }
  296. void CGE2Engine::snSeq(Sprite *spr, int val) {
  297. if (spr) {
  298. if (isHero(spr) && (val == 0))
  299. ((Hero*)spr)->park();
  300. else
  301. spr->step(val);
  302. }
  303. }
  304. void CGE2Engine::snRSeq(Sprite *spr, int val) {
  305. if (spr)
  306. snSeq(spr, spr->_seqPtr + val);
  307. }
  308. void CGE2Engine::snSend(Sprite *spr, int val) {
  309. if (!spr)
  310. return;
  311. // Sending", spr->_file
  312. // from scene", spr->_scene
  313. // to scene", val
  314. bool was1 = (_vga->_showQ->locate(spr->_ref) != nullptr);
  315. bool val1 = (val == 0 || val == _now);
  316. spr->_scene = val;
  317. releasePocket(spr);
  318. if (val1 != was1) {
  319. if (was1) {
  320. // deactivating
  321. hide1(spr);
  322. spr->_flags._slav = false;
  323. if ((spr == _heroTab[_sex]->_ptr) && (_heroTab[!_sex]->_ptr->_scene == _now))
  324. switchHero(!_sex);
  325. _spare->dispose(spr);
  326. } else {
  327. // activating
  328. if (byte(spr->_ref) == 0)
  329. _bitmapPalette = _vga->_sysPal;
  330. _vga->_showQ->insert(spr);
  331. if (isHero(spr)) {
  332. V2D p = *_heroTab[spr->_ref & 1]->_posTab[val];
  333. spr->gotoxyz(V3D(p.x, 0, p.y));
  334. ((Hero*)spr)->setCurrent();
  335. }
  336. _taken = false;
  337. _bitmapPalette = nullptr;
  338. }
  339. }
  340. }
  341. void CGE2Engine::snSwap(Sprite *spr, int val) {
  342. bool tak = _taken;
  343. Sprite *xspr = locate(val);
  344. if (spr && xspr) {
  345. bool was1 = (_vga->_showQ->locate(spr->_ref) != nullptr);
  346. bool xwas1 = (_vga->_showQ->locate(val) != nullptr);
  347. int tmp = spr->_scene;
  348. spr->setScene(xspr->_scene);
  349. xspr->setScene(tmp);
  350. SWAP(spr->_pos2D, xspr->_pos2D);
  351. SWAP(spr->_pos3D, xspr->_pos3D);
  352. if (spr->_flags._kept)
  353. swapInPocket(spr, xspr);
  354. if (xwas1 != was1) {
  355. if (was1) {
  356. hide1(spr);
  357. _spare->dispose(spr);
  358. } else
  359. expandSprite(spr);
  360. if (xwas1) {
  361. hide1(xspr);
  362. _spare->dispose(xspr);
  363. } else {
  364. expandSprite(xspr);
  365. _taken = false;
  366. }
  367. }
  368. }
  369. if (_taken)
  370. _spare->dispose(xspr);
  371. _taken = tak;
  372. }
  373. void CGE2Engine::snCover(Sprite *spr, int val) {
  374. bool tak = _taken;
  375. Sprite *xspr = locate(val);
  376. if (spr && xspr) {
  377. spr->_flags._hide = true;
  378. xspr->setScene(spr->_scene);
  379. xspr->gotoxyz(spr->_pos3D);
  380. expandSprite(xspr);
  381. if ((xspr->_flags._shad = spr->_flags._shad) == true) {
  382. _vga->_showQ->insert(_vga->_showQ->remove(spr->_prev), xspr);
  383. spr->_flags._shad = false;
  384. }
  385. feedSnail(xspr, kNear, _heroTab[_sex]->_ptr);
  386. _taken = false;
  387. }
  388. if (_taken)
  389. _spare->dispose(xspr);
  390. _taken = tak;
  391. }
  392. void CGE2Engine::snUncover(Sprite *spr, Sprite *spr2) {
  393. if (spr && spr2) {
  394. spr->_flags._hide = false;
  395. spr->setScene(spr2->_scene);
  396. if ((spr->_flags._shad = spr2->_flags._shad) == true) {
  397. _vga->_showQ->insert(_vga->_showQ->remove(spr2->_prev), spr);
  398. spr2->_flags._shad = false;
  399. }
  400. spr->gotoxyz(spr2->_pos3D);
  401. snSend(spr2, -1);
  402. if (spr->_time == 0)
  403. ++spr->_time;
  404. }
  405. }
  406. void CGE2Engine::snKeep(Sprite *spr, int stp) {
  407. int sex = _sex;
  408. if (stp > 127) {
  409. _sex = stp & 1; // for another hero
  410. stp = -1;
  411. }
  412. HeroTab *ht = _heroTab[_sex];
  413. selectPocket(-1);
  414. int pp = ht->_pocPtr;
  415. if (spr && !spr->_flags._kept && ht->_pocket[pp] == nullptr) {
  416. V3D pos(14, -10, -1);
  417. int16 oldRepeat = _sound->getRepeat();
  418. _sound->setRepeat(1);
  419. snSound(ht->_ptr, 3);
  420. _sound->setRepeat(oldRepeat);
  421. if (_taken) {
  422. _vga->_showQ->insert(spr);
  423. _taken = false;
  424. }
  425. ht->_pocket[pp] = spr;
  426. spr->setScene(0);
  427. spr->_flags._kept = true;
  428. if (!_sex)
  429. pos._x += kScrWidth - 58;
  430. if (pp & 1)
  431. pos._x += 29;
  432. if (pp >> 1)
  433. pos._y -= 20;
  434. pos._y -= (spr->_siz.y / 2);
  435. spr->gotoxyz(pos);
  436. if (stp >= 0)
  437. spr->step(stp);
  438. }
  439. _sex = sex;
  440. selectPocket(-1);
  441. }
  442. void CGE2Engine::snGive(Sprite *spr, int val) {
  443. if (spr) {
  444. int p = findActivePocket(spr->_ref);
  445. if (p >= 0) {
  446. releasePocket(spr);
  447. spr->setScene(_now);
  448. if (val >= 0)
  449. spr->step(val);
  450. }
  451. }
  452. selectPocket(-1);
  453. }
  454. void CGE2Engine::snGoto(Sprite *spr, int val) {
  455. if (spr) {
  456. V3D eye = *_eye;
  457. if (spr->_scene > 0)
  458. setEye(*_eyeTab[spr->_scene]);
  459. spr->gotoxyz(*_point[val]);
  460. setEye(eye);
  461. }
  462. }
  463. void CGE2Engine::snPort(Sprite *spr, int port) {
  464. if (spr)
  465. spr->_flags._port = (port < 0) ? !spr->_flags._port : (port != 0);
  466. }
  467. void CGE2Engine::snMouse(bool on) {
  468. if (on)
  469. _mouse->on();
  470. else
  471. _mouse->off();
  472. }
  473. void CGE2Engine::snNNext(Sprite *spr, Action act, int val) {
  474. if (spr) {
  475. if (val > 255)
  476. val = spr->labVal(act, val >> 8);
  477. spr->_actionCtrl[act]._ptr = val;
  478. }
  479. }
  480. void CGE2Engine::snRNNext(Sprite *spr, int val) {
  481. if (spr)
  482. spr->_actionCtrl[kNear]._ptr += val;
  483. }
  484. void CGE2Engine::snRMTNext(Sprite *spr, int val) {
  485. if (spr)
  486. spr->_actionCtrl[kMTake]._ptr += val;
  487. }
  488. void CGE2Engine::snRFTNext(Sprite * spr, int val) {
  489. if (spr)
  490. spr->_actionCtrl[kFTake]._ptr += val;
  491. }
  492. void CGE2Engine::snRmNear(Sprite *spr) {
  493. if (spr)
  494. spr->_actionCtrl[kNear]._cnt = 0;
  495. }
  496. void CGE2Engine::snRmMTake(Sprite *spr) {
  497. if (spr)
  498. spr->_actionCtrl[kMTake]._cnt = 0;
  499. }
  500. void CGE2Engine::snRmFTake(Sprite *spr) {
  501. if (spr)
  502. spr->_actionCtrl[kFTake]._cnt = 0;
  503. }
  504. void CGE2Engine::snSetRef(Sprite *spr, int val) {
  505. if (spr)
  506. spr->_ref = val;
  507. }
  508. void CGE2Engine::snFlash(bool on) {
  509. if (on) {
  510. Dac *pal = (Dac *)malloc(sizeof(Dac) * kPalCount);
  511. if (pal) {
  512. memcpy(pal, _vga->_sysPal, kPalSize);
  513. for (int i = 0; i < kPalCount; i++) {
  514. int c;
  515. c = pal[i]._r << 1;
  516. pal[i]._r = (c < 64) ? c : 63;
  517. c = pal[i]._g << 1;
  518. pal[i]._g = (c < 64) ? c : 63;
  519. c = pal[i]._b << 1;
  520. pal[i]._b = (c < 64) ? c : 63;
  521. }
  522. _vga->setColors(pal, 64);
  523. }
  524. free(pal);
  525. } else
  526. _vga->setColors(_vga->_sysPal, 64);
  527. _dark = false;
  528. }
  529. void CGE2Engine::snCycle(int cnt) {
  530. _vga->_rot._len = cnt;
  531. }
  532. void CGE2Engine::snWalk(Sprite *spr, int val) {
  533. if (isHero(spr)) {
  534. if (val < kMaxPoint)
  535. ((Hero *)spr)->walkTo(*_point[val]);
  536. else {
  537. Sprite *s = _vga->_showQ->locate(val);
  538. if (s)
  539. ((Hero *)spr)->walkTo(s);
  540. }
  541. ((Hero *)spr)->_time = 1;
  542. }
  543. }
  544. void CGE2Engine::snReach(Sprite *spr, int val) {
  545. if (isHero(spr))
  546. ((Hero *)spr)->reach(val);
  547. }
  548. void CGE2Engine::snSound(Sprite *spr, int wav, Audio::Mixer::SoundType soundType) {
  549. if (wav == -1)
  550. _sound->stop();
  551. else {
  552. if (_sound->_smpinf._counter && wav < 20)
  553. return;
  554. if (_soundStat._wait && ((wav & 255) > 80))
  555. return;
  556. _soundStat._ref[1] = wav;
  557. _soundStat._ref[0] = !_fx->exist(_soundStat._ref[1]);
  558. _sound->play(soundType, _fx->load(_soundStat._ref[1], _soundStat._ref[0]),
  559. (spr) ? (spr->_pos2D.x / (kScrWidth / 16)) : 8);
  560. }
  561. }
  562. void CGE2Engine::snRoom(Sprite *spr, bool on) {
  563. if (!isHero(spr))
  564. return;
  565. int sex = spr->_ref & 1;
  566. Sprite **p = _heroTab[sex]->_pocket;
  567. if (on) {
  568. if (freePockets(sex) == 0 && p[kPocketMax] == nullptr) {
  569. SWAP(p[kPocketMax], p[kPocketMax - 1]);
  570. snHide(p[kPocketMax], 1);
  571. }
  572. } else if (p[kPocketMax]) {
  573. for (int i = 0; i < kPocketMax; i++) {
  574. if (p[i] == nullptr) {
  575. snHide(p[kPocketMax], 0);
  576. SWAP(p[kPocketMax], p[i]);
  577. break;
  578. }
  579. }
  580. }
  581. }
  582. void CGE2Engine::snGhost(Bitmap *bmp) {
  583. V2D p(this, bmp->_map & 0xFFFF, bmp->_map >> 16);
  584. bmp->hide(p);
  585. bmp->release();
  586. delete[] bmp->_b;
  587. bmp->_b = nullptr;
  588. delete bmp;
  589. bmp = nullptr;
  590. }
  591. void CGE2Engine::snSay(Sprite *spr, int val) {
  592. if (spr && spr->active() && _commandHandler->_talkEnable) {
  593. //-- mouth animation
  594. if (isHero(spr) && spr->seqTest(-1))
  595. ((Hero *)spr)->say();
  596. if (_sayCap)
  597. _text->say(_text->getText(val), spr);
  598. if (_sayVox) {
  599. int i = val;
  600. if (i < 256)
  601. i -= 100;
  602. int16 oldRepeat = _sound->getRepeat();
  603. _sound->setRepeat(1);
  604. snSound(spr, i, Audio::Mixer::kSpeechSoundType);
  605. _sound->setRepeat(oldRepeat);
  606. _soundStat._wait = &_sound->_smpinf._counter;
  607. }
  608. }
  609. }
  610. void CGE2Engine::hide1(Sprite *spr) {
  611. _commandHandlerTurbo->addCommand(kCmdGhost, -1, 0, spr->ghost());
  612. }
  613. void CGE2Engine::swapInPocket(Sprite *spr, Sprite *xspr) {
  614. for (int i = 0; i < 2; i++) {
  615. for (int j = 0; j < kPocketMax; j++) {
  616. Sprite *&poc = _heroTab[i]->_pocket[j];
  617. if (poc == spr) {
  618. spr->_flags._kept = false;
  619. poc = xspr;
  620. xspr->_flags._kept = true;
  621. xspr->_flags._port = false;
  622. return;
  623. }
  624. }
  625. }
  626. }
  627. Sprite *CGE2Engine::expandSprite(Sprite *spr) {
  628. if (spr)
  629. _vga->_showQ->insert(spr);
  630. return spr;
  631. }
  632. void CGE2Engine::qGame() {
  633. // Write out the user's progress
  634. saveGame(0, Common::String("Automatic Savegame"));
  635. busy(false);
  636. _vga->sunset();
  637. _endGame = true;
  638. }
  639. void CGE2Engine::xScene() {
  640. sceneDown();
  641. sceneUp(_req);
  642. }
  643. void CommandHandler::addCommand(CommandType com, int ref, int val, void *ptr) {
  644. if (ref == -2)
  645. ref = 142 - _vm->_sex;
  646. Command *headCmd = &_commandList[_head++];
  647. headCmd->_commandType = com;
  648. headCmd->_ref = ref;
  649. headCmd->_val = val;
  650. headCmd->_spritePtr = ptr;
  651. headCmd->_cbType = kNullCB;
  652. if (headCmd->_commandType == kCmdClear) {
  653. clear();
  654. }
  655. }
  656. void CommandHandler::addCallback(CommandType com, int ref, int val, CallbackType cbType) {
  657. Command *headCmd = &_commandList[_head++];
  658. headCmd->_commandType = com;
  659. headCmd->_ref = ref;
  660. headCmd->_val = val;
  661. headCmd->_spritePtr = nullptr;
  662. headCmd->_cbType = cbType;
  663. if (headCmd->_commandType == kCmdClear) {
  664. _tail = _head;
  665. _vm->killText();
  666. _timerExpiry = 0;
  667. }
  668. }
  669. void CommandHandler::insertCommand(CommandType com, int ref, int val, void *ptr) {
  670. if (ref == -2)
  671. ref = 142 - _vm->_sex;
  672. --_tail;
  673. Command *tailCmd = &_commandList[_tail];
  674. tailCmd->_commandType = com;
  675. tailCmd->_ref = ref;
  676. tailCmd->_val = val;
  677. tailCmd->_spritePtr = ptr;
  678. tailCmd->_cbType = kNullCB;
  679. if (com == kCmdClear) {
  680. _tail = _head;
  681. _vm->killText();
  682. _timerExpiry = 0;
  683. }
  684. }
  685. bool CommandHandler::idle() {
  686. return (!_vm->_waitRef && _head == _tail);
  687. }
  688. void CommandHandler::clear() {
  689. _tail = _head;
  690. _vm->killText();
  691. _timerExpiry = 0;
  692. }
  693. int CommandHandler::getComId(const char *com) {
  694. int i = _vm->takeEnum(_commandText, com);
  695. return (i < 0) ? i : i + kCmdCom0 + 1;
  696. }
  697. const char *CommandHandler::getComStr(CommandType cmdType) {
  698. return _commandText[cmdType - kCmdNop];
  699. }
  700. void CGE2Engine::feedSnail(Sprite *spr, Action snq, Hero *hero) {
  701. if (!spr || !spr->active())
  702. return;
  703. int cnt = spr->_actionCtrl[snq]._cnt;
  704. if (cnt) {
  705. byte ptr = spr->_actionCtrl[snq]._ptr;
  706. CommandHandler::Command *comtab = spr->snList(snq);
  707. CommandHandler::Command *c = &comtab[ptr];
  708. CommandHandler::Command *q = &comtab[cnt];
  709. if (hero != nullptr) {
  710. int pocFre = freePockets(hero->_ref & 1);
  711. int pocReq = 0;
  712. CommandHandler::Command *p = c;
  713. for (; p < q && p->_commandType != kCmdNext; p++) { // scan commands
  714. // drop from pocket?
  715. if ((p->_commandType == kCmdSend && p->_val != _now)
  716. || p->_commandType == kCmdGive) {
  717. int ref = p->_ref;
  718. if (ref < 0)
  719. ref = spr->_ref;
  720. if (findActivePocket(ref) >= 0)
  721. --pocReq;
  722. }
  723. // make/dispose additional room?
  724. if (p->_commandType == kCmdRoom) {
  725. if (p->_val == 0)
  726. ++pocReq;
  727. else
  728. --pocReq;
  729. }
  730. // put into pocket?
  731. if (p->_commandType == kCmdKeep)
  732. ++pocReq;
  733. // overloaded?
  734. if (pocReq > pocFre) {
  735. pocFul();
  736. return;
  737. }
  738. }
  739. }
  740. while (c < q) {
  741. if ((c->_val == -1) && (c->_commandType == kCmdWalk || c->_commandType == kCmdReach))
  742. c->_val = spr->_ref;
  743. if (c->_commandType == kCmdNext) {
  744. Sprite *s;
  745. switch (c->_ref) {
  746. case -2:
  747. s = hero;
  748. break;
  749. case -1:
  750. s = spr;
  751. break;
  752. default:
  753. s = _vga->_showQ->locate(c->_ref);
  754. break;
  755. }
  756. if (s && s->_actionCtrl[snq]._cnt) {
  757. int v;
  758. switch (c->_val) {
  759. case -1:
  760. v = int(c - comtab + 1);
  761. break;
  762. case -2:
  763. v = int(c - comtab);
  764. break;
  765. case -3:
  766. v = -1;
  767. break;
  768. default:
  769. v = c->_val;
  770. if ((v > 255) && s)
  771. v = s->labVal(snq, v >> 8);
  772. break;
  773. }
  774. if (v >= 0) {
  775. s->_actionCtrl[snq]._ptr = v;
  776. if (spr->_ref == 1537 && s->_actionCtrl[snq]._ptr == 26)
  777. {
  778. debug(1, "Carpet Clothes Horse Rehanging Workaround Triggered!");
  779. s->_actionCtrl[snq]._ptr = 8;
  780. }
  781. }
  782. }
  783. if (s == spr)
  784. break;
  785. }
  786. _commandHandler->addCommand(c->_commandType, c->_ref, c->_val, spr);
  787. ++c;
  788. }
  789. }
  790. }
  791. } // End of namespace CGE2.