/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "fullpipe/fullpipe.h" #include "fullpipe/objectnames.h" #include "fullpipe/constants.h" #include "fullpipe/gameloader.h" #include "fullpipe/motion.h" #include "fullpipe/scenes.h" #include "fullpipe/statics.h" #include "fullpipe/interaction.h" #include "fullpipe/behavior.h" namespace Fullpipe { struct Hanger { StaticANIObject *ani; int field_4; int field_8; int phase; }; void scene09_setupGrit(Scene *sc) { if (g_vars->scene09_grit->_statics->_staticsId == ST_GRT9_GRIT) { if (!getGameLoaderInventory()->getCountItemsWithId(ANI_INV_COIN)) { if (g_fp->getObjectState(sO_CoinSlot_1) == g_fp->getObjectEnumState(sO_CoinSlot_1, sO_Empty) && (g_vars->swallowedEgg1->_value.intValue == ANI_INV_EGGBOOT || g_vars->swallowedEgg2->_value.intValue == ANI_INV_EGGBOOT || g_vars->swallowedEgg3->_value.intValue == ANI_INV_EGGBOOT)) { Scene *oldsc = g_fp->_currentScene; g_fp->_currentScene = sc; g_vars->scene09_grit->changeStatics2(ST_GRT9_NORM); g_fp->_currentScene = oldsc; } } } } void scene09_initScene(Scene *sc) { g_vars->scene09_flyingBall = 0; g_vars->scene09_numSwallenBalls = 0; g_vars->scene09_gulper = sc->getStaticANIObject1ById(ANI_GLOTATEL, -1); g_vars->scene09_spitter = sc->getStaticANIObject1ById(ANI_PLEVATEL, -1); g_vars->scene09_grit = sc->getStaticANIObject1ById(ANI_GRIT_9, -1); g_vars->scene09_gulperIsPresent = true; g_vars->scene09_dudeIsOnLadder = false; g_vars->scene09_interactingHanger = -1; g_vars->scene09_intHangerPhase = -1; g_vars->scene09_intHangerMaxPhase = -1000; g_vars->scene09_flyingBalls.clear(); for (uint i = 0; i < g_vars->scene09_hangers.size(); i++) delete g_vars->scene09_hangers[i]; g_vars->scene09_hangers.clear(); g_vars->scene09_numMovingHangers = 4; StaticANIObject *hanger = sc->getStaticANIObject1ById(ANI_VISUNCHIK, -1); Hanger *hng = new Hanger; hng->ani = hanger; hng->phase = 0; hng->field_4 = 0; hng->field_8 = 0; g_vars->scene09_hangers.push_back(hng); int x = 75; for (int i = 1; x < 300; i++, x += 75) { StaticANIObject *ani = new StaticANIObject(hanger); ani->show1(x + hanger->_ox, hanger->_oy, MV_VSN_CYCLE2, 0); sc->addStaticANIObject(ani, 1); hng = new Hanger; hng->ani = ani; hng->phase = 0; hng->field_4 = 0; hng->field_8 = 0; g_vars->scene09_hangers.push_back(hng); } g_vars->scene09_sceneBalls.clear(); StaticANIObject *newball1 = new StaticANIObject(sc->getStaticANIObject1ById(ANI_BALL9, -1)); newball1->setAlpha(0xc8); for (int i = 0; i < 4; i++) { StaticANIObject *newball = new StaticANIObject(newball1); newball->setAlpha(0xc8); g_vars->scene09_sceneBalls.push_back(newball); sc->addStaticANIObject(newball, 1); } delete newball1; g_fp->setObjectState(sO_RightStairs_9, g_fp->getObjectEnumState(sO_RightStairs_9, sO_IsClosed)); GameVar *eggvar = g_fp->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName(sO_GulpedEggs); g_vars->swallowedEgg1 = eggvar->getSubVarByName(sO_Egg1); g_vars->swallowedEgg2 = eggvar->getSubVarByName(sO_Egg2); g_vars->swallowedEgg3 = eggvar->getSubVarByName(sO_Egg3); scene09_setupGrit(sc); g_fp->initArcadeKeys("SC_9"); g_fp->lift_setButton(sO_Level1, ST_LBN_1N); g_fp->setArcadeOverlay(PIC_CSR_ARCADE4); } int sceneHandler09_updateScreenCallback() { int res = g_fp->drawArcadeOverlay(g_fp->_objectIdAtCursor == ANI_VISUNCHIK || g_vars->scene09_interactingHanger >= 0); if (!res) g_fp->_updateScreenCallback = 0; return res; } int scene09_updateCursor() { g_fp->updateCursorCommon(); if (g_vars->scene09_interactingHanger < 0) { if (g_fp->_objectIdAtCursor == ANI_VISUNCHIK) { if (g_fp->_cursorId == PIC_CSR_ITN) g_fp->_updateScreenCallback = sceneHandler09_updateScreenCallback; } else { if (g_fp->_objectIdAtCursor == PIC_SC9_LADDER_R && g_fp->_cursorId == PIC_CSR_ITN) g_fp->_cursorId = (g_vars->scene09_dudeY < 350) ? PIC_CSR_GOD : PIC_CSR_GOU; } } else { g_fp->_cursorId = PIC_CSR_ITN; } return g_fp->_cursorId; } void sceneHandler09_winArcade() { if (g_vars->scene09_gulper->_flags & 4) { g_vars->scene09_gulper->changeStatics2(ST_GLT_SIT); g_vars->scene09_gulper->startAnim(MV_GLT_FLYAWAY, 0, -1); g_fp->setObjectState(sO_Jug, g_fp->getObjectEnumState(sO_Jug, sO_Unblocked)); g_fp->setObjectState(sO_RightStairs_9, g_fp->getObjectEnumState(sO_RightStairs_9, sO_IsOpened)); g_vars->scene09_gulperIsPresent = false; } } void sceneHandler09_startAuntie() { MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_TTA9_GOL), 0, 1); mq->getExCommandByIndex(0)->_x = g_fp->_sceneRect.right + 30; mq->chain(0); } void sceneHandler09_spitterClick() { debugC(2, kDebugSceneLogic, "scene09: spitterClick"); if (g_vars->scene09_spitter->_flags & 4) { PicAniInfo info; g_vars->scene09_spitter->getPicAniInfo(info); g_vars->scene09_spitter->_messageQueueId = 0; g_vars->scene09_spitter->changeStatics2(ST_PLV_SIT); int x = g_vars->scene09_spitter->_ox - 10; int y = g_vars->scene09_spitter->_oy + 145; g_vars->scene09_spitter->setPicAniInfo(info); if (ABS(x - g_fp->_aniMan->_ox) > 1 || ABS(y - g_fp->_aniMan->_oy) > 1) { MessageQueue *mq = getCurrSceneSc2MotionController()->startMove(g_fp->_aniMan, x, y, 1, ST_MAN_UP); if (mq) { ExCommand *ex = new ExCommand(0, 17, MSG_SC9_PLVCLICK, 0, 0, 0, 1, 0, 0, 0); ex->_excFlags = 2; mq->addExCommandToEnd(ex); postExCommand(g_fp->_aniMan->_id, 2, x, y, 0, -1); } } else { if (!g_fp->_aniMan->_movement) { g_vars->scene09_spitter->changeStatics2(ST_PLV_SIT); g_vars->scene09_spitter->hide(); g_fp->_aniMan->startAnim(MV_MAN9_SHOOT, 0, -1); g_fp->stopAllSoundInstances(SND_9_006); } g_fp->_aniMan2 = 0; if (g_fp->_sceneRect.left < 800) g_fp->_currentScene->_x = 800 - g_fp->_sceneRect.left; } } } void sceneHandler09_eatBall() { debugC(2, kDebugSceneLogic, "scene09: eatBall"); if (g_vars->scene09_flyingBall) { g_vars->scene09_flyingBall->hide(); g_vars->scene09_flyingBalls.pop_back(); //g_vars->scene09_sceneBalls.pop_back(); g_vars->scene09_flyingBall = 0; g_vars->scene09_numSwallenBalls++; if (g_vars->scene09_numSwallenBalls >= 3) { MessageQueue *mq = g_vars->scene09_gulper->getMessageQueue(); if (mq) { ExCommand *ex = new ExCommand(ANI_GLOTATEL, 1, MV_GLT_FLYAWAY, 0, 0, 0, 1, 0, 0, 0); ex->_excFlags |= 2; mq->addExCommandToEnd(ex); } g_fp->setObjectState(sO_Jug, g_fp->getObjectEnumState(sO_Jug, sO_Unblocked)); g_fp->setObjectState(sO_RightStairs_9, g_fp->getObjectEnumState(sO_RightStairs_9, sO_IsOpened)); g_vars->scene09_gulperIsPresent = false; } } } void sceneHandler09_showBall() { debugC(2, kDebugSceneLogic, "scene09: showBall"); if (g_vars->scene09_sceneBalls.size()) { StaticANIObject *ani = g_vars->scene09_sceneBalls.front(); g_vars->scene09_sceneBalls.push_back(ani); g_vars->scene09_sceneBalls.remove_at(0); g_vars->scene09_flyingBalls.insert_at(0, ani); ani->show1(g_fp->_aniMan->_ox + 94, g_fp->_aniMan->_oy - 162, MV_BALL9_EXPLODE, 0); } } void sceneHandler09_cycleHangers() { for (int i = 0; i < g_vars->scene09_numMovingHangers; i++) { Movement *mov = g_vars->scene09_hangers[i]->ani->_movement; if (mov && mov->_id == MV_VSN_CYCLE2) { int idx; if (g_vars->scene09_hangers[i]->phase >= 0) idx = 18 - g_vars->scene09_hangers[i]->phase / 5; else idx = 18 - g_vars->scene09_hangers[i]->phase * 10 / 43; if (idx > 38) idx = 38; if (idx < 1) idx = 1; mov->setDynamicPhaseIndex(idx); } } } void sceneHandler09_limitHangerPhase() { for (int i = 0; i < g_vars->scene09_numMovingHangers; i++) { if (i != g_vars->scene09_interactingHanger) { g_vars->scene09_hangers[i]->phase += g_vars->scene09_hangers[i]->field_8; if (g_vars->scene09_hangers[i]->phase > 85) g_vars->scene09_hangers[i]->phase = 85; if (g_vars->scene09_hangers[i]->phase < -85) g_vars->scene09_hangers[i]->phase = -85; if (g_vars->scene09_hangers[i]->phase < 0) g_vars->scene09_hangers[i]->field_8++; if (g_vars->scene09_hangers[i]->phase > 0) g_vars->scene09_hangers[i]->field_8--; } } } void sceneHandler09_collideBall(uint num) { debugC(2, kDebugSceneLogic, "scene09: collideBall"); if (g_vars->scene09_gulperIsPresent) { g_vars->scene09_flyingBall = g_vars->scene09_flyingBalls[num]; if (g_vars->scene09_gulper) { g_vars->scene09_gulper->changeStatics2(ST_GLT_SIT); MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC9_EATBALL), 0, 0); mq->setFlags(mq->getFlags() | 1); if (!mq->chain(g_vars->scene09_gulper)) delete mq; } } } void sceneHandler09_ballExplode(uint num) { debugC(2, kDebugSceneLogic, "scene09: ballExplode(%d) of %d", num, g_vars->scene09_flyingBalls.size()); StaticANIObject *ball = g_vars->scene09_flyingBalls[num]; g_vars->scene09_flyingBalls.remove_at(num); MessageQueue *mq = new MessageQueue(g_fp->_currentScene->getMessageQueueById(QU_SC9_BALLEXPLODE), 0, 1); mq->setParamInt(-1, ball->_odelay); if (!mq->chain(ball)) delete mq; } void sceneHandler09_checkHangerCollide() { for (uint b = 0; b < g_vars->scene09_flyingBalls.size(); b++) { StaticANIObject *ball = g_vars->scene09_flyingBalls[b]; int newx = ball->_ox + 5; ball->setOXY(newx, ball->_oy); if (newx <= 1398 || g_vars->scene09_flyingBall) { if (g_vars->scene09_gulperIsPresent) goto LABEL_11; } else if (g_vars->scene09_gulperIsPresent) { sceneHandler09_collideBall(b); continue; } if (newx > 1600) { sceneHandler09_ballExplode(b); continue; } LABEL_11: bool hit; for (int i = 0; i < g_vars->scene09_numMovingHangers; i++) { for (int j = 0; j < 4; j++) { int x1 = newx + g_vars->scene09_hangerOffsets[j].x; int y1 = ball->_oy + g_vars->scene09_hangerOffsets[j].y; // Check 2 pixels to compensate cord width hit = g_vars->scene09_hangers[i]->ani->isPixelHitAtPos(x1, y1) && g_vars->scene09_hangers[i]->ani->isPixelHitAtPos(x1 + 10, y1); if (hit) { sceneHandler09_ballExplode(b); break; } } if (hit) break; } } } void sceneHandler09_hangerStartCycle() { StaticANIObject *ani = g_vars->scene09_hangers[g_vars->scene09_interactingHanger]->ani; if (ani->_movement) { ani->startAnim(MV_VSN_CYCLE2, 0, -1); g_vars->scene09_hangers[g_vars->scene09_interactingHanger]->field_8 = 0; g_vars->scene09_hangers[g_vars->scene09_interactingHanger]->phase = g_vars->scene09_intHangerPhase + (g_fp->_mouseScreenPos.y - g_vars->scene09_clickY) / 2; if (g_vars->scene09_intHangerMaxPhase != -1000 && g_vars->scene09_hangers[g_vars->scene09_interactingHanger]->phase != g_vars->scene09_intHangerMaxPhase) { ExCommand *ex = new ExCommand(0, 35, SND_9_019, 0, 0, 0, 1, 0, 0, 0); ex->_field_14 = 1; ex->_excFlags |= 2; ex->postMessage(); g_vars->scene09_intHangerMaxPhase = -1000; } } else { g_vars->scene09_interactingHanger = -1; } } void scene09_visCallback(int *phase) { // do nothing } int sceneHandler09(ExCommand *cmd) { if (cmd->_messageKind != 17) return 0; switch (cmd->_messageNum) { case MSG_CMN_WINARCADE: sceneHandler09_winArcade(); break; case MSG_SC9_STARTTIOTIA: sceneHandler09_startAuntie(); break; case MSG_SC9_FROMLADDER: getCurrSceneSc2MotionController()->activate(); getGameLoaderInteractionController()->enableFlag24(); g_vars->scene09_dudeIsOnLadder = false; break; case MSG_SC9_TOLADDER: getCurrSceneSc2MotionController()->deactivate(); getGameLoaderInteractionController()->disableFlag24(); g_vars->scene09_dudeIsOnLadder = true; break; case MSG_SC9_PLVCLICK: sceneHandler09_spitterClick(); break; case MSG_SC9_FLOWN: g_vars->scene09_gulperIsPresent = false; break; case MSG_SC9_EATBALL: sceneHandler09_eatBall(); break; case MSG_SC9_SHOWBALL: sceneHandler09_showBall(); break; case 367: if (g_fp->isDemo() && g_fp->getLanguage() == Common::RU_RUS) { g_fp->_needRestart = true; return 0; } break; case 33: { int res = 0; if (g_fp->_aniMan2) { int x = g_fp->_aniMan2->_ox; g_vars->scene09_dudeY = g_fp->_aniMan2->_oy; if (x < g_fp->_sceneRect.left + 200) g_fp->_currentScene->_x = x - g_fp->_sceneRect.left - 300; if (x > g_fp->_sceneRect.right - 200) g_fp->_currentScene->_x = x - g_fp->_sceneRect.right + 300; res = 1; g_fp->sceneAutoScrolling(); } else { if (g_fp->_aniMan->_movement && g_fp->_aniMan->_movement->_id != MV_MAN9_SHOOT) g_fp->_aniMan2 = g_fp->_aniMan; } sceneHandler09_cycleHangers(); sceneHandler09_limitHangerPhase(); sceneHandler09_checkHangerCollide(); if (g_vars->scene09_interactingHanger >= 0) sceneHandler09_hangerStartCycle(); g_fp->_behaviorManager->updateBehaviors(); g_fp->startSceneTrack(); return res; } case 30: if (g_vars->scene09_interactingHanger >= 0) { if (ABS(g_vars->scene09_hangers[g_vars->scene09_interactingHanger]->phase) < 15) { g_vars->scene09_hangers[g_vars->scene09_interactingHanger]->ani->_callback2 = 0; // Really NULL g_vars->scene09_hangers[g_vars->scene09_interactingHanger]->ani->changeStatics2(ST_VSN_NORMAL); } } g_vars->scene09_interactingHanger = -1; break; case 29: { StaticANIObject *ani = g_fp->_currentScene->getStaticANIObjectAtPos(g_fp->_sceneRect.left + cmd->_x, g_fp->_sceneRect.top + cmd->_y); if (ani) { if (ani->_id == ANI_PLEVATEL) { sceneHandler09_spitterClick(); break; } if (ani->_id == ANI_VISUNCHIK) { debugC(2, kDebugSceneLogic, "scene09: VISUNCHIK"); if (g_vars->scene09_numMovingHangers > 0) { int hng = 0; while (g_vars->scene09_hangers[hng]->ani != ani) { ++hng; if (hng >= g_vars->scene09_numMovingHangers) break; } g_vars->scene09_interactingHanger = hng; g_vars->scene09_intHangerPhase = g_vars->scene09_hangers[hng]->phase; g_vars->scene09_intHangerMaxPhase = g_vars->scene09_hangers[hng]->phase; g_vars->scene09_clickY = cmd->_y; if (!g_vars->scene09_hangers[hng]->ani->_movement || g_vars->scene09_hangers[hng]->ani->_movement->_id != MV_VSN_CYCLE2) { g_vars->scene09_hangers[hng]->ani->changeStatics2(ST_VSN_NORMAL); g_vars->scene09_hangers[hng]->ani->startAnim(MV_VSN_CYCLE2, 0, -1); g_vars->scene09_hangers[hng]->ani->_callback2 = scene09_visCallback; } ExCommand *ex = new ExCommand(0, 35, SND_9_018, 0, 0, 0, 1, 0, 0, 0); ex->_field_14 = 1; ex->_excFlags |= 2; ex->postMessage(); } break; } } if (g_vars->scene09_dudeIsOnLadder && g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY) == PIC_SC9_LADDER_R && !cmd->_param && !g_fp->_aniMan->_movement) { handleObjectInteraction(g_fp->_aniMan, g_fp->_currentScene->getPictureObjectById(PIC_SC9_LADDER_R, 0), 0); } if (!ani || !canInteractAny(g_fp->_aniMan, ani, cmd->_param)) { int picId = g_fp->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); PictureObject *pic = g_fp->_currentScene->getPictureObjectById(picId, 0); if (!pic || !canInteractAny(g_fp->_aniMan, pic, cmd->_param)) { if ((g_fp->_sceneRect.right - cmd->_sceneClickX < 47 && g_fp->_sceneRect.right < g_fp->_sceneWidth - 1) || (cmd->_sceneClickX - g_fp->_sceneRect.left < 47 && g_fp->_sceneRect.left > 0)) g_fp->processArcade(cmd); } } break; } } return 0; } } // End of namespace Fullpipe