/****************************************** THIRSTY NELLAN An 3D Animated Adventure Game for children Copyright (C) 2002 Geoffrey M. Draper This file is part of Thirsty Nellan. Thirsty Nellan 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. Thirsty Nellan 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 Thirsty Nellan; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA As a special exception, the copyright holder (Geoffrey M. Draper) gives permission to link this program with Qt non-commercial edition, and distribute the resulting executable, without including the source code for the Qt non-commercial edition in the source distribution. (This clause applies only to Windows and MacOS versions of the software.) ******************************************/ #include "myavatarsprite.h" #include "gamedata.h" #include extern GameData *gd; MyAvatarSprite::MyAvatarSprite( QCanvasPixmapArray *a, MyCanvas *can) : QCanvasSprite(a, can) { myCanvas = can; timer = new QTime(); setAnimated(true); setVelocity(0,0); move(550, 450); consecutiveCollisionCount = 0; } void MyAvatarSprite::advance(int stage) { if (stage == 1 && !gd->dialogVisible) { moveBy(xVelocity(), yVelocity()); //advance frame if (timer->elapsed() > 200) { if (xVelocity() != 0 || yVelocity() != 0) { switch(gd->avatarDir) { case 0: //front-left setFrame((frame()+1) % 2); break; case 1: //left setFrame(2 + ((frame()+1) % 4)); break; case 2: //front_right setFrame(6 + ((frame()+1) % 2)); break; case 3: //right setFrame(8 + ((frame()+1) % 4)); break; case 4: //back setFrame(12 + ((frame()+1) % 4)); break; } } timer->start(); } //allow avatar to move behind/in front of carrot-pile if (gd->currentRoom == gd->MILK_ROOM) { if (!gd->carrotsEaten) { if (y() < 450) { gd->carrotSprite->setZ(1); } else { gd->carrotSprite->setZ(-1); } } } collisionList = collisions(false); if (!collisionList.isEmpty()) { for (QCanvasItemList::Iterator it = collisionList.begin(); it != collisionList.end(); ++it) { if (collidesWith(*it)) { if (consecutiveCollisionCount++ > 10) { for (int i=0; iobjectData[i].location == gd->currentRoom) { if (gd->objectData[i].largeIcon == *it) { //cout << "collided with " << gd->objectData[i].name << endl; if (gd->currentObject == -1) { if (gd->objectData[i].isTreasure) { if (gd->objectData[i].pointsAwarded == 0) { QString filename = "images/squares/egg.png"; switch(i) { case gd->JEWEL: filename = "images/squares/jewel.png"; break; case gd->COIN: filename = "images/squares/coin.png"; break; case gd->VASE: filename = "images/squares/vase.png"; break; } gd->playSound("audio/N4treasures.WAV"); myCanvas->showInfoBox(filename, " Questo è uno dei quattro tesori \n" " nella Casa Incantata. Puoi ottenere \n" " dei punti dai tesori se li depositi \n" " nella Banca."); gd->score += 5; gd->objectData[i].pointsAwarded = 5; myCanvas->emitScoreChanged(); } } if (i == gd->COUPON) { gd->playSound("audio/Ncoupon.WAV"); myCanvas->showInfoBox("images/squares/coupon.png", " Cos'è questa? Una tessera per una \n" " tazza gratis! Se inserisci questa tessera\n" " in un distributore, potrai ricevere \n" " una bella tazza pulita."); } //pick up whatever you ran into myCanvas->emitInventoryItemAdded(i); } } } } } } } } else { consecutiveCollisionCount = 0; } //check to see if player is on the floor if (isInsidePerimeter(gd->roomData[gd->currentRoom].perimeter) && !isInsideDestination()) { //check to see if player is in a doorway for (int i=0; i < gd->roomData[gd->currentRoom].numPassages; i++) { if (isInsidePerimeter((gd->roomData[gd->currentRoom].passageway[i]).perimeter)) { setX(gd->roomData[gd->currentRoom].passageway[i].newPos->x()); setY(gd->roomData[gd->currentRoom].passageway[i].newPos->y()); gd->currentRoom = gd->roomData[gd->currentRoom].passageway[i].room; setVelocity(0,0); myCanvas->emitRoomChanged(); } } } else { moveBy(-xVelocity(), -yVelocity()); setVelocity(0,0); //HERE, check for pendingActions! switch (gd->pendingAction) { case gd->DO_NOTHING: default: break; case gd->TRYING_LOCKED_DOOR: gd->playSound("audio/nlockeddoor.WAV"); myCanvas->showInfoBox("images/squares/information.png", " Per quanto tu insista, la porta rimane \n" " chiusa. Forse può essere sbloccata \n" " solo dall'altra parte...?"); break; case gd->TRYING_LEFT_CHAIR: gd->playSound("audio/Nouch.WAV"); myCanvas->showInfoBox("images/squares/sitting_on_chair_1.png", " Ouch! Questa sedia è troppo dura! "); setFrame(0); break; case gd->TRYING_MIDDLE_CHAIR: gd->playSound("audio/Noomph.WAV"); myCanvas->showInfoBox("images/squares/sitting_on_chair_2.png", " Oomph! Questa sedia è troppo morbida! "); setFrame(0); break; case gd->TRYING_RIGHT_CHAIR: gd->playSound("audio/Nmagicchair.WAV"); myCanvas->showInfoBox("images/squares/sitting_on_chair_3.png", " Quando ti accomodi sulla sedia, cominci\n" " a sentirti confuso. La stanza comincia\n" " a ruotare attorno a te e improvvisamente tutto \n" " diventa molto buio..."); gd->currentRoom = gd->OFFICE; move(487, 456); setFrame(0); myCanvas->emitRoomChanged(); break; case gd->TRYING_OFFICE_CHAIR: gd->playSound("audio/nbacktogreenroom.WAV"); myCanvas->showInfoBox("images/squares/sitting_in_office.png", " Ti siedi sulla sedia, ovviamente aspettandoti\n" " di essere magicamente ritrasportato \n" " nella Stanza Verde."); gd->currentRoom = gd->GREEN_ROOM; move(539, 423); setFrame(6); myCanvas->emitRoomChanged(); break; case gd->FILLING_BOWL: gd->playSound("audio/Nfullmilk.WAV"); myCanvas->showInfoBox("images/squares/milk_pouring.png", " GLUG, GLUG, PLINK!\n" " La tua tazza è ora piena di \n" " buon latte fresco."); gd->objectData[gd->COLD_MILK].location = gd->MILK_ROOM; myCanvas->emitInventoryItemRemoved(gd->EMPTY_BOWL); gd->objectData[gd->EMPTY_BOWL].location = -2; break; case gd->DEPOSITING_COUPON: gd->playSound("audio/nbowlclank.WAV"); myCanvas->showInfoBox("images/squares/bowl.png", " La tessera scompare nella fessura e \n" " la macchina ammicca e ronza per \n" " qualche secondo.\n" " CLUNK! Una splendida tazza nuova \n" " cade nello scomparto del distributore."); gd->objectData[gd->EMPTY_BOWL].location = gd->STORE; myCanvas->emitInventoryItemRemoved(gd->COUPON); gd->objectData[gd->COUPON].location = -2; break; case gd->PICKING_UP_MAGAZINE: gd->playSound("audio/nmagazine.WAV"); myCanvas->showInfoBox("images/squares/magazine.png", " Ma guarda un po'! Hai trovato\n" " una copia originale del numero di \n" " Luglio/Agosto 1980 della rivista \n" " \"Recreational Computing\"! Ti sembra \n" " vagamente familiare, anche se è \n" " difficile capire il perché."); myCanvas->emitInventoryItemAdded(gd->MAGAZINE); break; case gd->FEEDING_NELLAN_WARM_MILK: gd->playSound("audio/NEwarmmilk.WAV"); cout << "you just fed Nellan some warm milk" << endl; myCanvas->showInfoBox("images/squares/nellan_hello.png", " Nella si beve con calma il latte\n" " e ti dice educatamente, \"Grazie per il latte. \n" " Peccato che fosse così caldo.\""); gd->objectData[gd->EMPTY_BOWL].location = gd->currentRoom; gd->objectData[gd->EMPTY_BOWL].largeIcon->move(290,460); gd->objectData[gd->EMPTY_BOWL].largeIcon->setZ(2); myCanvas->emitInventoryItemRemoved(gd->WARM_MILK); gd->objectData[gd->WARM_MILK].location = -2; break; case gd->FEEDING_NELLAN_COLD_MILK: gd->playSound("audio/NEcoldmilk.WAV"); cout << "you just fed Nellan some cold milk" << endl; myCanvas->showInfoBox("images/squares/nellan_hello.png", " Nella beve con foga il latte ripulendo con\n" " cura la tazza. Ora fa le fusa sonoramente.\n" " \"Grazie, amico mio, per avermi portato questo\n" " ottimo latte fresco. So che non è stato facile.\n" " Ti prego di accettare questo piccolo segno di \n" " ringraziamento.\" E spinge un bel vaso verso di te."); gd->objectData[gd->VASE].location = gd->currentRoom; myCanvas->emitInventoryItemRemoved(gd->COLD_MILK); gd->objectData[gd->COLD_MILK].location = -2; break; case gd->DEPOSITING_EGG: gd->playSound("audio/K_egg.WAV"); myCanvas->showInfoBox("images/squares/banker.png", " Il banchiere, Mr. Klinkoyn, sembra felice \n" " di vederti. \"Ah! Hai trovato il mio Uovo d'Oro! \n" " Grazie per avermelo restituito.\" "); gd->objectData[gd->EGG].location = -2;//gd->BANK; myCanvas->emitInventoryItemRemoved(gd->EGG); break; case gd->DEPOSITING_JEWEL: gd->playSound("audio/K_jewel.WAV"); myCanvas->showInfoBox("images/squares/banker.png", " Il banchiere, Mr. Klinkoyn, sembra felice \n" " di vederti. \"Come mi mancava questo Gioiello! Grazie\n" " per averlo ritrovato.\" "); gd->objectData[gd->JEWEL].location = -2;//gd->BANK; myCanvas->emitInventoryItemRemoved(gd->JEWEL); break; case gd->DEPOSITING_COIN: gd->playSound("audio/K_coin.WAV"); myCanvas->showInfoBox("images/squares/banker.png", " Il banchiere, Mr. Klinkoyn, sembra felice \n" " di vederti. \"Questa moneta apparteva alla mia \n" " famiglia da molto tempo. Sono contento che tu \n" " l'abbia ritrovata.\" "); gd->objectData[gd->COIN].location = -2;//gd->BANK; myCanvas->emitInventoryItemRemoved(gd->COIN); break; case gd->DEPOSITING_VASE: gd->playSound("audio/K_vace.WAV"); myCanvas->showInfoBox("images/squares/banker.png", " Il banchiere, Mr. Klinkoyn, sembra felice \n" " di vederti. \"Grazie per aver ritrovato questo \n" " vaso. L'avevo perso molto tempo fa!\" "); gd->objectData[gd->VASE].location = -2;//gd->BANK; myCanvas->emitInventoryItemRemoved(gd->VASE); break; } //check for an end-of-game condition switch (gd->pendingAction) { case gd->DEPOSITING_EGG: case gd->DEPOSITING_JEWEL: case gd->DEPOSITING_COIN: case gd->DEPOSITING_VASE: if (gd->score == 100) { gd->playSound("audio/won.WAV"); myCanvas->showInfoBox("images/squares/banker.png", " Congratulazioni!!! \n HAI VINTO!!! "); myCanvas->emitEndgame(); } break; } gd->pendingAction = gd->DO_NOTHING; } myCanvas->update(); } } bool MyAvatarSprite::isInsideDestination() { bool result = false; if ((gd->avatarDestination->x() - gd->stepValue < x()) && (x() < gd->avatarDestination->x() + gd->stepValue) && (gd->avatarDestination->y() - gd->stepValue < y()) && (y() < gd->avatarDestination->y() + gd->stepValue)) { result = true; gd->avatarDestination = new QPoint(-100,-100); } return result; } int MyAvatarSprite::isInsidePerimeter(QPointArray *p) { //adapted from http://astronomy.swin.edu.au/pbourke/geometry/insidepoly/ //by Randolph Franklin int i, j, c = 0; int npol = p->size(); int xx = (int)x(); int yy = (int)y(); QPoint *pi, *pj; //what, you expected this code to make SENSE ? for (i = 0, j = npol-1; i < npol; j = i++) { pi = new QPoint(p->point(i)); pj = new QPoint(p->point(j)); if ((((pi->y() <= yy) && (yy < pj->y() )) || ((pj->y() <= yy) && (yy < pi->y() ))) && (xx < (pj->x() - pi->x()) * (yy - pi->y() ) / (pj->y() - pi->y() ) + pi->x() )) c = !c; } return c; }