Files
2026-02-02 04:50:13 +01:00

342 lines
14 KiB
C++

/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "watchmaker/classes/do_mouse.h"
#include "watchmaker/t3d.h"
#include "watchmaker/globvar.h"
#include "watchmaker/message.h"
#include "watchmaker/ll/ll_mouse.h"
#include "watchmaker/define.h"
#include "watchmaker/3d/math/llmath.h"
#include "watchmaker/3d/geometry.h"
#include "watchmaker/classes/do_camera.h"
#include "watchmaker/schedule.h"
#include "watchmaker/classes/do_player.h"
#include "watchmaker/main.h"
#include "watchmaker/ll/ll_util.h"
#include "watchmaker/classes/do_dialog.h"
#include "watchmaker/classes/do_inv.h"
#include "watchmaker/walk/act.h"
#include "watchmaker/3d/animation.h"
#include "watchmaker/classes/do_string.h"
#include "watchmaker/classes/do_keyboard.h"
#include "watchmaker/ll/ll_diary.h"
#include "watchmaker/ll/ll_string.h"
#include "watchmaker/t2d/t2d.h"
#include "watchmaker/walk/walk.h"
#include "watchmaker/renderer.h"
namespace Watchmaker {
// locals
t3dV3F LastClickPos;
uint8 LastFloorHit;
void doMouseButton(WGame &game) {
uint8 cp;
Init &init = game.init;
Renderer &renderer = *game._renderer;
if (bT2DActive) {
doT2DMouse(game);
return ;
}
if (bSomeOneSpeak && !bNotSkippableSent) {
/*DebugLogWindow("skip");*/bSkipTalk = true;
return;
}
if (bDialogActive) {
UpdateDialogMenu(game, TheMessage->wparam1, TheMessage->wparam2, TheMessage->event);
return;
}
if ((bPlayerInAnim) || (bNotSkippableWalk) || (bMovingCamera)) return;
if (mHide) mHide = false;
if ((bClock33) || (CurObj == o33LANCETTAMSX) || (CurObj == o33LANCETTAHSX) || (CurObj == o33LANCETTAMDX) || (CurObj == o33LANCETTAHDX)) return;
CurInvObj = 0;
CurObj = 0;
// se sono su inventario
if (InvStatus & INV_ON) {
if ((InvStatus & INV_ON) && (InvStatus & INV_MODE1) && PlayerCanCall(game._gameVars)) {
if (CheckRect(renderer, game._gameRect._callOtherPlayerRect, TheMessage->wparam1, TheMessage->wparam2)) {
_vm->_messageSystem.doEvent(EventClass::MC_DIALOG, ME_DIALOGSTART, MP_DEFAULT, dRCALLOTHERPLAYER, 0, 0, nullptr, nullptr, nullptr);
return;
}
}
CurInvObj = WhatIcon(*game._renderer, TheMessage->wparam1, TheMessage->wparam2);
if ((CurInvObj == iNULL) && (InvStatus & INV_MODE2) && CheckRect(renderer, game._gameRect._bigIconRect, TheMessage->wparam1, TheMessage->wparam2))
CurInvObj = BigInvObj;
if (CurInvObj == iNULL) {
// se ho cliccato su icona grande
if (InvStatus & INV_MODE2) {
if (CheckRect(renderer, game._gameRect._inv1Up, TheMessage->wparam1, TheMessage->wparam2))
InventoryUp();
else if (CheckRect(renderer, game._gameRect._inv1Down, TheMessage->wparam1, TheMessage->wparam2))
InventoryDown();
else if (CheckRect(renderer, game._gameRect._closeInvRect, TheMessage->wparam1, TheMessage->wparam2)) {
if (InvStatus & INV_MODE4) {
CurPlayer ^= 1;
ChangePlayer(game, (uint8)((CurPlayer ^ 1) + ocDARRELL));
}
InvStatus = INV_OFF;
game._cameraMan->resetAngle();
game._cameraMan->GetCameraTarget(init, &t3dCurCamera->Target);
if (bFirstPerson)
game._renderer->setCurCameraViewport(CAMERA_FOV_1ST, bSuperView);
else
game._renderer->setCurCameraViewport(t3dCurCamera->Fov, bSuperView);
BigInvObj = iNULL;
} else if (CheckRect(renderer, game._gameRect._quitGameRect, TheMessage->wparam1, TheMessage->wparam2))
CloseSys(game);
else if (CheckRect(renderer, game._gameRect._invSaveRect, TheMessage->wparam1, TheMessage->wparam2) && !(InvStatus & INV_MODE4) && PlayerCanSave())
_vm->_messageSystem.doEvent(EventClass::MC_T2D, ME_T2DSTART, MP_DEFAULT, MPX_START_T2D_SAVE, 0, tOPTIONS, nullptr, nullptr, nullptr);
else if (CheckRect(renderer, game._gameRect._invLoadRect, TheMessage->wparam1, TheMessage->wparam2) && !(InvStatus & INV_MODE4))
_vm->_messageSystem.doEvent(EventClass::MC_T2D, ME_T2DSTART, MP_DEFAULT, MPX_START_T2D_LOAD, 0, tOPTIONS, nullptr, nullptr, nullptr);
else if (CheckRect(renderer, game._gameRect._invOptionsRect, TheMessage->wparam1, TheMessage->wparam2) && !(InvStatus & INV_MODE4))
_vm->_messageSystem.doEvent(EventClass::MC_T2D, ME_T2DSTART, MP_DEFAULT, MPX_START_T2D_OPTIONS, 0, tOPTIONS, nullptr, nullptr, nullptr);
else {
ClearUseWith();
if ((CheckRect(renderer, game._gameRect._playerInvRect, TheMessage->wparam1, TheMessage->wparam2)) || (InvStatus & INV_MODE4)) {
if (PlayerCanSwitch(game._gameVars, 0)) {
InvStatus ^= INV_MODE4;
CurPlayer ^= VICTORIA;
BigInvObj = iNULL;
return;
}
}
}
} else if (CheckRect(renderer, game._gameRect._inv1Up, TheMessage->wparam1, TheMessage->wparam2))
InventoryUp();
else if (CheckRect(renderer, game._gameRect._inv1Down, TheMessage->wparam1, TheMessage->wparam2))
InventoryDown();
else {
InvStatus = INV_OFF;
ClearUseWith();
}
return;
}
if ((BigInvObj != CurInvObj) && !(bUseWith & UW_ON)) {
t3dMatIdentity(&game.init._globals._invVars.BigIconM);
BigInvObj = CurInvObj;
}
if (TheMessage->event == ME_MRIGHT)
_vm->_messageSystem.doEvent(EventClass::MC_INVENTORY, ME_OPERATEICON, MP_DEFAULT, TheMessage->wparam1, TheMessage->wparam2, 0, &CurInvObj, nullptr, nullptr);
else if (bUseWith & UW_ON)
_vm->_messageSystem.doEvent(EventClass::MC_INVENTORY, ME_OPERATEICON, MP_DEFAULT, TheMessage->wparam1, TheMessage->wparam2, 0, &CurInvObj, nullptr, nullptr);
else
_vm->_messageSystem.doEvent(EventClass::MC_INVENTORY, ME_EXAMINEICON, MP_DEFAULT, TheMessage->wparam1, TheMessage->wparam2, 0, &CurInvObj, nullptr, nullptr);
//if( ( InvStatus & INV_MODE2 ) && CheckRect(BigIconRect,TheMessage->wparam1,TheMessage->wparam2) )
//CurInvObj = iNULL;
return;
} else if ((bUseWith & UW_ON) && (bUseWith & UW_USEDI) && CheckRect(renderer, game._gameRect._useIconRect, TheMessage->wparam1, TheMessage->wparam2)) {
ClearUseWith();
ClearText();
return;
}
// se sono su area gioco
cp = 0;
PlayerGotoPos[CurPlayer + ocDARRELL] = 0;
NextPortalObj = oNULL;
NextPortalAnim = aNULL;
// se gli ho gia' passato che oggetto deve trovare
if ((CurObj = TheMessage->lparam[0])) {
// se era per un passaggio di portale, cancella l'oggetto
if (CurObj == oNEXTPORTAL) CurObj = oNULL;
// Ripristina informazioni
bFastWalk = (uint8)TheMessage->lparam[2];
FloorHit = LastFloorHit;
t3dVectCopy(&mPos, &LastClickPos);
} else {
// Cerca l'oggetto su cui ho cliccato
CurObj = WhatObj(game, TheMessage->wparam1, TheMessage->wparam2, TheMessage->event);
// Se sono su albero e clicco fuori dal nido, simulo un cambio portale
if (bPlayerSuBasamento &&
(CurObj != oXT14ALBERO) && (CurObj != oXT14BASAMENTO) && (CurObj != oXT14NIDO_da_sopra_il_basamento) && (CurObj != oXT14OCCHIALI)) {
NextPortalObj = CurObj;
NextPortalAnim = a145;
}
// se non e' stato cliccato nessun oggetto e un oggetto era gia' selezionato dall'inventario il tasto
// destro del mouse elimina questa selezione (nd Fox)
if ((CurObj == oNULL) && (bUseWith) && (TheMessage->event == ME_MRIGHT)) {
ClearUseWith();
return;
}
// Salva informazioni
LastFloorHit = FloorHit;
t3dVectCopy(&LastClickPos, &mPos);
}
if (bFirstPerson && FromFirstPersonAnim && (!CurObj || (CurObj && (!(init.Obj[CurObj].flags & NOSWITCH))))) {
if (CurObj)
NextPortalObj = CurObj;
else
NextPortalObj = oNEXTPORTAL;
NextPortalAnim = FromFirstPersonAnim;
FromFirstPersonAnim = aNULL;
}
// Se ha cliccato in un altro portale e c'e' un'animazione di link
if ((NextPortalObj) && (NextPortalAnim)) {
// Prende luce di posizione dall'animazione
cp = init.Anim[NextPortalAnim].pos;
PlayerGotoPos[CurPlayer + ocDARRELL] = GetLightPosition(&mPos, cp);
// Simula un click per terra
CurObj = oNULL;
FloorHit = 1;
} else if ((CurObj) && !(NextPortalObj) && (init.Obj[CurObj].pos != 0)) {
// altrimenti prova a prendere la luce di posizione
cp = init.Obj[CurObj].pos;
PlayerGotoPos[CurPlayer + ocDARRELL] = GetLightPosition(&mPos, cp);
FloorHit = 1;
}
// Se deve prendere sempre un click col destro
if (init.Obj[CurObj].flags & FORCERIGHT) TheMessage->event = ME_MRIGHT;
// Cammina solo; nessuno oggetto o nessuna posizione o posizione diversa e non sono in closeup
if ((!CurObj) || ((PlayerGotoPos[CurPlayer + ocDARRELL]) && (PlayerGotoPos[CurPlayer + ocDARRELL] != PlayerPos[CurPlayer + ocDARRELL])) || (!PlayerGotoPos[CurPlayer + ocDARRELL])) {
CheckCharacterWithBounds(game, ocCURPLAYER, &mPos, cp, 10);
// Se ho cliccato in un altro portale dice di contiunare la camminata
if ((NextPortalObj) && (NextPortalAnim))
_vm->_messageSystem.doEvent(EventClass::MC_MOUSE, TheMessage->event, MP_WAIT_ANIM, 0, 0, 0, &NextPortalObj, nullptr, &bFastWalk);
else if (NextPortalObj)
_vm->_messageSystem.doEvent(EventClass::MC_MOUSE, TheMessage->event, MP_WAIT_PORTAL, 0, 0, 0, &NextPortalObj, nullptr, &bFastWalk);
// Se sono in prima torno in terza, a meno che l'oggetto non mi obblighi a restare in prima
if (bFirstPerson && !bNoFirstPersonSwitch && (!CurObj || (CurObj && (!(init.Obj[CurObj].flags & NOSWITCH) || (Player->Walk.Check & LONGPATH)))))
_vm->_messageSystem.doEvent(EventClass::MC_CAMERA, ME_CAMERA1TO3, MP_DEFAULT, 0, 0, 0, nullptr, nullptr, nullptr);
//? else if( bFirstPerson )
//? CharStop( ocCURPLAYER );
}
// Rimuove tutti gli eventi del personaggio
game._messageSystem.removeEvent(EventClass::MC_PLAYER, ME_ALL);
if (CurObj) { // se ho cliccato su un oggetto valido
if (TheMessage->event == ME_MLEFT) // se ho cliccato con sinistro
_vm->_messageSystem.doEvent(EventClass::MC_PLAYER, ME_PLAYERGOTOEXAMINE, MP_DEFAULT, TheMessage->wparam1, TheMessage->wparam2, bFirstPerson, &CurObj, nullptr, nullptr);
else if (TheMessage->event == ME_MRIGHT) { // se ho cliccato con destro
if ((init.Obj[CurObj].flags & USEWITH) && !(bUseWith)) { // se ho cliccato su un oggetto usacon
Player->Walk.NumSteps = 0; // Simula un PlayerStop
_vm->_messageSystem.doEvent(EventClass::MC_ACTION, ME_MOUSEOPERATE, MP_DEFAULT, TheMessage->wparam1, TheMessage->wparam2, bFirstPerson, &CurObj, nullptr, nullptr);
} else
_vm->_messageSystem.doEvent(EventClass::MC_PLAYER, ME_PLAYERGOTOACTION, MP_DEFAULT, TheMessage->wparam1, TheMessage->wparam2, bFirstPerson, &CurObj, nullptr, nullptr);
}
} else // se non ho cliccato su niente
_vm->_messageSystem.doEvent(EventClass::MC_PLAYER, ME_PLAYERGOTO, MP_DEFAULT, TheMessage->wparam1, TheMessage->wparam2, bFirstPerson, nullptr, &NextPortalAnim, nullptr);
}
void doMouseUpdate(WGame &game) {
Init &init = game.init;
Renderer &renderer = *game._renderer;
if (bT2DActive) {
doT2DMouse(game);
return ;
}
if (bDialogActive) {
UpdateDialogMenu(game, TheMessage->wparam1, TheMessage->wparam2, TheMessage->event);
return;
}
if (/*( mHide ) ||*/ (bSomeOneSpeak)) return;
if (!TheMessage->wparam1 && !TheMessage->wparam2) return;
if ((bPlayerInAnim) || (bNotSkippableWalk) || (mHide) || (bMovingCamera)) return;
CurObj = 0;
CurInvObj = 0;
//DebugFile("MM %d %d",TheMessage->wparam1, TheMessage->wparam2 );
// se sono su inventario
if (InvStatus & INV_ON) {
if ((bLPressed) && (InvStatus & INV_MODE2)) {
t3dM3X3F t;
t3dMatRot(&t, ((t3dF32)(TheMessage->lparam[1]) / (t3dF32)(game._gameRect._bigIconRect.y2 - game._gameRect._bigIconRect.y1))*T3D_PI * 2.0f,
((t3dF32)(TheMessage->lparam[0]) / (t3dF32)(game._gameRect._bigIconRect.x1 - game._gameRect._bigIconRect.x2))*T3D_PI * 2.0f, 0.0f);
t3dMatMul(&game.init._globals._invVars.BigIconM, &t, &game.init._globals._invVars.BigIconM);
CurInvObj = BigInvObj;
} else {
CurInvObj = WhatIcon(*game._renderer, TheMessage->wparam1, TheMessage->wparam2);
if ((CurInvObj == iNULL) && CheckRect(renderer, game._gameRect._bigIconRect, TheMessage->wparam1, TheMessage->wparam2))
CurInvObj = BigInvObj;
ShowInvObjName(init, CurInvObj);
}
return;
}
// se sono su area gioco
CurObj = WhatObj(game, TheMessage->wparam1, TheMessage->wparam2, TheMessage->event);
if ((bLPressed || bRPressed) && ((bClock33) || (CurObj == o33LANCETTAMSX) || (CurObj == o33LANCETTAHSX) || (CurObj == o33LANCETTAMDX) || (CurObj == o33LANCETTAHDX)))
doClock33(game, CurObj, &mPos);
else {
if (bClock33) {
if ((Comb33[0] == 7) && (Comb33[1] == 2) && (Comb33[2] == 9) && (Comb33[3] == 11) && IconInInv(init, i19FOGLIO1)) {
_vm->_messageSystem.doEvent(EventClass::MC_CAMERA, ME_CAMERA1TO3, MP_DEFAULT, 0, 0, 0, nullptr, nullptr, nullptr);
_vm->_messageSystem.doEvent(EventClass::MC_ANIM, ME_STARTANIM, MP_WAIT_CAMERA, a336, 0, 0, nullptr, nullptr, nullptr);
if (!(init.Obj[o33LANCETTAHSX].flags & EXTRA2)) {
IncCurTime(game, 15);
init.Obj[o33LANCETTAHSX].flags |= EXTRA2;
}
}
bClock33 = false;
}
ShowObjName(init, CurObj);
}
}
/* -----------------17/03/98 17.16-------------------
* doMouse
* --------------------------------------------------*/
void doMouse(WGame &game) {
//se ci sono i crediti ritorna
if (bTitoliCodaStatic || bTitoliCodaScrolling) return;
switch (TheMessage->event) {
case ME_MRIGHT:
case ME_MLEFT:
doMouseButton(game);
break;
case ME_MOUSEUPDATE :
doMouseUpdate(game);
break;
case ME_MOUSEHIDE :
if ((mCounter++ > 20) && !(mHide))
mHide = 1;
ClearText();
break;
case ME_MOUSEUNHIDE :
mHide = 0;
break;
}
}
} // End of namespace Watchmaker