Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
/* 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/>.
*
*/
#ifndef WATCHMAKER_LL_ANIM_H
#define WATCHMAKER_LL_ANIM_H
#include "watchmaker/types.h"
#include "watchmaker/work_dirs.h"
#include "watchmaker/globvar.h"
#include "watchmaker/game.h"
namespace Watchmaker {
void StopObjAnim(WGame &game, int32 obj);
bool CheckAndLoadMoglieSupervisoreModel(WorkDirs &workDirs, int32 c);
void StartAnim(WGame &game, int32 an);
void StopAnim(WGame &game, int32 an);
void PauseAnim(Init &init, int32 an);
void ContinueAnim(Init &init, int32 an);
void StopAllAnims(Init &init);
void StopPlayingGame(WGame &game);
void ProcessATF(WGame &game, int32 an, int32 atf);
void ProcessATFDO(WGame &game, int32 in);
void ProcessAnims(WGame &game);
} // End of namespace Watchmaker
#endif // WATCHMAKER_LL_ANIM_H

View File

@@ -0,0 +1,520 @@
/* 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/>.
*
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_strcat
#define FORBIDDEN_SYMBOL_EXCEPTION_strcpy
#include "watchmaker/game.h"
#include "watchmaker/ll/ll_diary.h"
#include "watchmaker/ll/ll_util.h"
#include "watchmaker/3d/geometry.h"
#include "watchmaker/ll/ll_mesh.h"
#include "watchmaker/windows_hacks.h"
#include "watchmaker/define.h"
#include "watchmaker/ll/ll_system.h"
#include "watchmaker/walk/act.h"
#include "watchmaker/ll/ll_anim.h"
#include "watchmaker/3d/animation.h"
namespace Watchmaker {
char bDiariesStoppedByTimeInc = 0;
void t3dLoadOutdoorLights(const char *pname, t3dBODY *b, int32 ora);
/* -----------------26/11/1999 16.19-----------------
* StartDiary
* --------------------------------------------------*/
void StartDiary(WGame &game, int32 room, t3dV3F *pos) {
struct SDiary *d, *l;
int32 tot_rand, cur_rand;
int32 i, j, ca;
t3dF32 acceptable_dist;
char special_flag;
uint8 cr;
Init &init = game.init;
if (t3dCurRoom) cr = (uint8)getRoomFromStr(init, t3dCurRoom->name);
else cr = rNULL;
if (bDisableDiary) return ;
// DebugLogFile( "Parto Diario per room %d", room );
for (i = 0, d = &init.Diary[0]; i < MAX_DIARIES; i++, d++) {
if ((d->room != room) || (t3dCurTime < d->startt) || (d->endt && (t3dCurTime >= d->endt))) continue;
if (d->item[d->cur].on) continue;
if ((Character[d->obj]) && (Character[d->obj]->Flags & T3D_CHARACTER_DIARYDISABLE)) continue;
if (init.Dialog[CurDialog].obj == d->obj) continue; //se e' attivo un dialogo e si cerca di far partire il diario del personaggio che sta' gia' parlando
for (j = 0, l = &init.Diary[0]; j < MAX_DIARIES; j++, l++)
if ((l->obj == d->obj) && (l->item[l->cur].on))
break;
if (j < MAX_DIARIES) continue;
if (cr != rNULL) {
//se un diario e' fuori ma l'omino e' dentro non lo faccio partire
if ((d->room == rXT) && (cr != rXT)) {
DebugLogWindow("Skippato diario %d in rXT: obj %d room %d", i, d->obj, d->room);
continue;
}
//se il diario e' nella r13 ma non siamo nella r13 skippo
if ((d->room == r13) && (cr != r13)) {
DebugLogWindow("Skippato diario %d in r13: obj %d room %d", i, d->obj, d->room);
continue;
}
}
// if( i==36)
// DebugLogFile("START36 d->startt %d, d->endt %d, d->obj %d",d->startt,d->endt,d->obj);
// DebugLogFile( "Diario valido num %d", i );
// da usare per quei personaggi che, tra un diario e il successivo, cambiano posizione (sempre nel caso che un dialogo/rtv abbia incrementato il tempo e fatto cosi' switchare il diario)
special_flag = 0;
if (bDiariesStoppedByTimeInc && (d->obj == ocSERVETTA)) special_flag = 1;
acceptable_dist = 40000.0f;
// la servetta ha bisogno di piu' spazio vista la disposizione delle luci di posizione dei dialoghi e dei background
if (d->obj == ocSERVETTA) acceptable_dist = 200000.0f;
// quando il sup non c'<27> noi possiamo rubare la foto e quindi il portafoto diventa vuoto. Quando lui torna dobbiamo fare in modo che il portafoto sia rovesciato
if ((d->obj == ocSUPERVISORE) && (d->room == r29) && (init.Obj[o29PORTAFOTOVUOTO].flags & ON) && (!(init.Obj[o29PORTAFOTOROVESCIATO].flags & ON))) {
init.Obj[o29PORTAFOTOVUOTO].flags &= ~ON;
UpdateObjMesh(init, o29PORTAFOTOVUOTO);
init.Obj[o29PORTAFOTOROVESCIATO].flags |= ON;
UpdateObjMesh(init, o29PORTAFOTOROVESCIATO);
}
// la domestica ha bisogno di piu' spazio in questa circostanza vista la disposizione delle luci di posizione dei dialoghi e dei background
if ((d->obj == ocDOMESTICA) && ((d->room == r22) || (d->room == r26) || (d->room == r28))) acceptable_dist = 200000.0f;
tot_rand = 0;
for (j = 0; j < MAX_ANIMS_PER_DIARY_ITEM; j++)
if ((special_flag) || (pos == nullptr) || ((d->item[j].anim[0]) && (CompareLightPosition((char *) init.Anim[d->item[j].anim[0]].RoomName.rawArray(), init.Anim[d->item[j].anim[0]].pos, pos, acceptable_dist))))
tot_rand += d->item[j].rand;
if (!tot_rand) continue;
game._rnd->setSeed((unsigned)t3dReadTime());
cur_rand = game._rnd->getRandomNumber(tot_rand - 1);
// DebugLogFile( "Random %d (%d)", cur_rand, tot_rand );
tot_rand = 0;
for (j = 0; j < MAX_ANIMS_PER_DIARY_ITEM; j++) {
if ((special_flag) || (pos == nullptr) || ((d->item[j].anim[0]) && (CompareLightPosition((char *) init.Anim[d->item[j].anim[0]].RoomName.rawArray(), init.Anim[d->item[j].anim[0]].pos, pos, acceptable_dist)))) {
tot_rand += d->item[j].rand;
// DebugLogFile( "%d: %d (%d)", j, cur_rand, tot_rand );
if (cur_rand < tot_rand)
break;
}
}
if (!(ca = d->item[j].anim[0]) || init.Anim[ca].active)
continue;
// DebugLogFile( "Parte anim %d char %d pos %d", ca, d->obj, Anim[ca].pos );
Character[d->obj]->Flags &= ~T3D_CHARACTER_HIDE;
d->cur = j;
d->item[d->cur].on = TRUE;
d->item[d->cur].cur = 0;
d->item[d->cur].loopc = 0;
if (d->end_hideobj) d->end_hideobj |= 0x8000; //se ha un oggetto assegnato setto anche il flag piu' alto
init.Anim[ca].flags |= ANIM_DIARY;
if ((d->item[d->cur].bnd < 255) && !(bPlayerSuBasamento && (d->room == rXT))) {
d->item[d->cur].saved_bnd = GetBndLevel((char *) init.Anim[ca].RoomName.rawArray());
SetBndLevel(game, (char *)init.Anim[ca].RoomName.rawArray(), d->item[d->cur].bnd);
} else d->item[d->cur].saved_bnd = 255;
if (d->obj) CharSetPosition(d->obj, init.Anim[ca].pos, (char *)init.Anim[ca].RoomName.rawArray());
StartAnim(game, ca);
}
bDiariesStoppedByTimeInc = 0;
// Fa partire animazione di stand dell'altro personaggio
i = (CurPlayer ^ 1);
if ((Character[i + ocDARRELL]->Flags & T3D_CHARACTER_HIDE) && (PlayerStand[i].cr == room)) {
Character[i + ocDARRELL]->Flags &= ~T3D_CHARACTER_HIDE;
// CharSetPosition( i+ocDARRELL, Anim[PlayerStand[i].an].pos, PlayerStand[i].RoomName );
CharSetPosition(i + ocDARRELL, PlayerStand[i].pos, PlayerStand[i].roomName.c_str());
StartAnim(game, PlayerStand[i].an);
}
}
/* -----------------26/11/1999 16.39-----------------
* StopDiary
* --------------------------------------------------*/
void StopDiary(WGame &game, int32 room, int32 obj, uint8 only_overtime) {
struct SDiary *d;
int32 i, an;
char is_overtime;
uint8 cr;
Init &init = game.init;
if (t3dCurRoom) cr = (uint8)getRoomFromStr(init, t3dCurRoom->name);
else cr = rNULL;
// DebugLogFile( "Finisco Diario per room %d", room );
for (i = 0, d = &init.Diary[0]; i < MAX_DIARIES; i++, d++) {
if (obj && (obj != d->obj)) continue;
if ((room > 0) && (d->room != room)) continue;
if ((room < 0) && (room == cr)) continue;
is_overtime = (t3dCurTime < d->startt) || ((d->endt != 0) && (t3dCurTime >= d->endt));
if (only_overtime && (!is_overtime)) continue;
if (is_overtime && (d->end_hideobj & 0x8000)) { //se ha il bit settato significa che aveva un oggetto da nascondere e il diario era stato lanciato almeno una volta
d->end_hideobj &= 0x7FFF; //rimuovo l'ultimo bit
DebugLogFile("!! EndAnim !! per obj %d (%s)", d->end_hideobj, Character[d->obj]->Mesh->name.c_str());
init.Obj[d->end_hideobj].flags &= ~ON;
UpdateObjMesh(init, d->end_hideobj);
d->end_hideobj = 0;
//caso particolare dello sportello del bagno
if ((d->room == r2M) && (d->obj == ocCUSTODE)) {
init.Obj[o2MOGGETTICUSTODE_TOHIDE].flags |= ON;
UpdateObjMesh(init, o2MOGGETTICUSTODE_TOHIDE);
}
//casi particolari delle porte dei diari della servetta
if (i == eSERVETTA1) {
init.Obj[o2CMEGABB_2R].flags &= ~ON;
UpdateObjMesh(init, o2CMEGABB_2R);
// stanze in cui la r2C e la r2R sono caricate
if ((cr == r2C) || (cr == r2F) || (cr == r15) || (cr == r2E) || (cr == r2R) || (cr == r2T) || (cr == r2S) || (cr == r31)) {
t3dResetMesh(LinkMeshToStr(init, "o2c-portacamere02"));
t3dResetMesh(LinkMeshToStr(init, "o2r-portacamere2c01"));
}
}
if (i == eSERVETTA2) {
init.Obj[o2CMEGABB_2S].flags &= ~ON;
UpdateObjMesh(init, o2CMEGABB_2S);
// stanze in cui la r2C e la r2R sono caricate
if ((cr == r2C) || (cr == r2F) || (cr == r15) || (cr == r2E) || (cr == r2R) || (cr == r2T) || (cr == r2S) || (cr == r31)) {
t3dResetMesh(LinkMeshToStr(init, "o2c-portacamere06"));
t3dResetMesh(LinkMeshToStr(init, "o2s-portacamere01"));
}
}
if (i == eSERVETTA4) {
init.Obj[o2PMEGABB_2D].flags &= ~ON;
UpdateObjMesh(init, o2PMEGABB_2D);
// stanze in cui la r2P e la r2D sono caricate
if ((cr == r27) || (cr == r2P) || (cr == r2D)) {
t3dResetMesh(LinkMeshToStr(init, "o2p-portasup"));
t3dResetMesh(LinkMeshToStr(init, "o2d-portasup"));
}
}
}//end_hideobj
// da mettere dopo "end_hideobj", perche' anche se il diario non e' attivo gli oggetti li devo spegnere lo stesso
if (!d->item[d->cur].on) continue;
an = d->item[d->cur].anim[d->item[d->cur].cur];
init.Anim[an].flags &= ~ANIM_DIARY;
StopAnim(game, an);
if ((d->item[d->cur].saved_bnd < 255)) {
if (!(bPlayerSuBasamento && (d->room == rXT)))
SetBndLevel(game, (char *)init.Anim[an].RoomName.rawArray(), d->item[d->cur].saved_bnd);
d->item[d->cur].saved_bnd = 255;
}
Character[d->obj]->Flags |= T3D_CHARACTER_HIDE;
// DebugLogWindow("%s HIDEEEEEEEE: Flags %d",Character[d->obj]->Mesh->Name,Character[d->obj]->Flags);
d->item[d->cur].on = FALSE;
d->item[d->cur].loopc = 0;
d->item[d->cur].cur = 0;
d->cur = 0;
}
// Termina animazione di stand dell'altro personaggio
if (!obj) {
i = (CurPlayer ^ 1);
if (!(Character[i + ocDARRELL]->Flags & T3D_CHARACTER_HIDE) && (PlayerStand[i].cr == room)) {
StopObjAnim(game, i + ocDARRELL);
Character[i + ocDARRELL]->Flags |= T3D_CHARACTER_HIDE;
}
}
}
/* -----------------26/11/1999 16.49-----------------
* ContinueDiary
* --------------------------------------------------*/
void ContinueDiary(WGame &game, int32 an) {
struct SDiary *d;
int32 i, ca;
Init &init = game.init;
// DebugLogFile( "Continuo Diario per anim %d", an );
for (i = 0, d = &init.Diary[0]; i < MAX_DIARIES; i++, d++) {
if ((!d->item[d->cur].on) || (d->item[d->cur].anim[d->item[d->cur].cur] != an)) continue;
d->item[d->cur].cur ++;
if (!(ca = d->item[d->cur].anim[d->item[d->cur].cur]) || init.Anim[ca].active) {
if ((!d->item[d->cur].loop) || !(ca = d->item[d->cur].anim[0]) || init.Anim[ca].active ||
((d->item[d->cur].loop > 0) && ((d->item[d->cur].loopc + 1) >= d->item[d->cur].loop))) {
if (!d->item[d->cur].anim[d->item[d->cur].cur])
d->item[d->cur].cur --; //altrimenti quando stoppo il tutto becca un item vuoto
StopDiary(game, d->room, d->obj, 0);
/* d->item[d->cur].on = FALSE;
d->item[d->cur].cur = 0;
d->item[d->cur].loopc = 0;
d->cur = 0;*/
if (Character[d->obj] && Character[d->obj]->Mesh)
StartDiary(game, d->room, &Character[d->obj]->Mesh->Trasl);
else
StartDiary(game, d->room, nullptr);
break;
} else {
if (d->item[d->cur].loop > 0) d->item[d->cur].loopc ++;
d->item[d->cur].cur = 0;
ca = d->item[d->cur].anim[d->item[d->cur].cur];
}
}
// DebugLogFile( "Parte anim %d char %d pos %d", ca, d->obj, Anim[ca].pos );
init.Anim[an].flags &= ~ANIM_DIARY;
init.Anim[ca].flags |= ANIM_DIARY;
CharSetPosition(d->obj, init.Anim[ca].pos, (char *)init.Anim[ca].RoomName.rawArray());
StartAnim(game, ca);
break;
}
}
/* -----------------29/05/00 16.57-------------------
* UpdateAllClocks
* --------------------------------------------------*/
void UpdateAllClocks(WGame &game) {
char str[255];
t3dMESH *mesh;
Init &init = game.init;
const char *ClockMeshes[] = {
"o21-a-ore01",
"o21-a-minuti01",
"o24-a-ore01",
"o24-a-minuti01",
"o2p-ore01",
"o2p-minuti01",
"o2s-ore01",
"o2s-minuti01",
nullptr
};
const char *ClockAnims[] = {
"r21-a-orologio-ore.a3d",
"r21-a-orologio-minuti.a3d",
"r24-a-orologio-ore.a3d",
"r24-a-orologio-minuti.a3d",
"r2p-orologio-ore.a3d",
"r2p-orologio-minuti.a3d",
"r2s-orologio-ore.a3d",
"r2s-orologio-minuti.a3d",
nullptr
};
const char *ClockMeshes24[] = {
"o48-lancettaore",
"o48-lancettaore01",
nullptr
};
const char *ClockAnims24[] = {
"r48-ore.a3d",
"r48-minuti.a3d",
nullptr
};
int32 i, l[2];
l[0] = (t3dCurTime / 100) % 12;
l[1] = (t3dCurTime % 100) / 5;
if (!l[0]) l[0] = 12;
if (!l[1]) l[1] = 12;
// DebugLogWindow("%d: %d %d",t3dCurTime,l[0],l[1]);
for (i = 0;; i++) {
if (ClockMeshes[i] == nullptr) break;
if ((mesh = LinkMeshToStr(init, ClockMeshes[i])) == nullptr) continue;
t3dSetSpecialAnimFrame(game, ClockAnims[i], mesh, l[i % 2]);
}
//orologio a 24ore (avanti di un'ora)
l[0] = ((t3dCurTime + 100) / 100) % 24;
l[1] = (t3dCurTime % 100) / 5;
if (!l[0]) l[0] = 24;
if (!l[1]) l[1] = 12;
for (i = 0;; i++) {
if (ClockMeshes24[i] == nullptr) break;
if ((mesh = LinkMeshToStr(init, ClockMeshes24[i])) == nullptr) continue;
t3dSetSpecialAnimFrame(game, ClockAnims24[i], mesh, l[i % 2]);
}
strcpy(str, game.workDirs._lightmapsDir.c_str());
strcat(str, "rxt.t3d");
if (t3dRxt)
t3dLoadOutdoorLights(str, t3dRxt, t3dCurTime);
}
/* -----------------22/05/00 10.03-------------------
* IncCurTime
* --------------------------------------------------*/
void IncCurTime(WGame &game, int32 inc) {
int32 h, m;
Init &init = game.init;
t3dCurTime += inc;
h = (t3dCurTime / 100);
m = (t3dCurTime % 100);
while (m >= 60) {
m -= 60;
h ++;
}
t3dCurTime = h * 100 + m;
UpdateAllClocks(game);
if (bDialogActive && (init.Dialog[CurDialog].obj == ocSERVETTA)) {
StopDiary(game, 0, init.Dialog[CurDialog].obj, 1);
bDiariesStoppedByTimeInc = 1;
}
// stoppo tutti i diari overtime di tutte le stanze esclusa la attuale
StopDiary(game, -1, 0, 1);
//la moglie del supervisore va in camera sua e non ci fa entrare in camera
if ((t3dCurTime >= 1700) && (t3dCurTime < 1720)) {
init.Obj[o2Pp2D].anim[CurPlayer] = a2P7;
init.Obj[o2Pp2D].anim[CurPlayer ^ 1] = a2P7;
init.Obj[o2Pp2D].pos = 2;
}
//il cuoco va a letto e noi non lo disturbiamo
if ((t3dCurTime >= 1430) && (t3dCurTime < 1450)) {
init.Obj[o2Cp2T].anim[CurPlayer] = a2C4_CUOCODORME;
init.Obj[o2Cp2T].anim[CurPlayer ^ 1] = a2C4_CUOCODORME;
}
//il cuoco si alza e ci lascia entrare nella r2t
if ((t3dCurTime >= 1715) && (t3dCurTime < 1735)) {
init.Obj[o2Cp2T].anim[CurPlayer] = a2C4;
init.Obj[o2Cp2T].anim[CurPlayer ^ 1] = a2C4;
}
//il supervisore ci da le foto
if ((t3dCurTime >= 1900) && !(init.Dialog[dR008].flags & DIALOG_DONE)) {
init.Obj[o2Qp29].anim[CurPlayer] = a2Q4b;
init.Obj[o2Qp29].anim[CurPlayer ^ 1] = a2Q4b;
}
//la domestica ci cazzia
if ((t3dCurTime >= 1715) && !(init.Dialog[dR015].flags & DIALOG_DONE)) {
init.Obj[o25p2Q].anim[CurPlayer] = a2513_DOM;
init.Obj[o25p2Q].anim[CurPlayer ^ 1] = a2513_DOM;
init.Obj[o25p24].anim[CurPlayer] = a2512_DOM;
init.Obj[o25p24].anim[CurPlayer ^ 1] = a2512_DOM;
init.Obj[oXT11p21].anim[CurPlayer] = a111_DOM;
init.Obj[oXT11p21].anim[CurPlayer ^ 1] = a111_DOM;
init.Obj[oXT1Ap22].anim[CurPlayer] = a1A4_DOM;
init.Obj[oXT1Ap22].anim[CurPlayer ^ 1] = a1A4_DOM;
}
}
/* -----------------22/05/00 10.03-------------------
* DecCurTime
* --------------------------------------------------*/
void DecCurTime(WGame &game, int32 dec) {
int32 h, m;
t3dCurTime -= dec;
h = (t3dCurTime / 100);
m = (t3dCurTime % 100);
while (m < 0) {
m += 60;
h --;
}
t3dCurTime = h * 100 + m;
UpdateAllClocks(game);
}
/* -----------------29/05/00 15.40-------------------
* SetCurTime
* --------------------------------------------------*/
void SetCurTime(WGame &game, int32 set) {
t3dCurTime = set;
UpdateAllClocks(game);
}
/* -----------------02/06/00 10.10-------------------
* WhichRoomChar
* --------------------------------------------------*/
int32 WhichRoomChar(Init &init, int32 ch) {
struct SDiary *d;
int32 i;
for (i = 0, d = &init.Diary[0]; i < MAX_DIARIES; i++, d++) {
if ((d->obj != ch) || (t3dCurTime < d->startt) || (d->endt && (t3dCurTime >= d->endt))) continue;
return d->room;
}
return rNULL;
}
/* -----------------02/06/00 10.26-------------------
* WhichAnimChar
* --------------------------------------------------*/
int32 WhichAnimChar(Init &init, int32 ch) {
struct SDiary *d;
int32 i;
for (i = 0, d = &init.Diary[0]; i < MAX_DIARIES; i++, d++) {
if ((d->obj != ch) || (t3dCurTime < d->startt) || (d->endt && (t3dCurTime >= d->endt))) continue;
if (!d->item[d->cur].on) continue;
return d->item[d->cur].anim[d->item[d->cur].cur];
}
return 0;
}
/* -----------------02/06/00 10.26-------------------
* WhichPosChar
* --------------------------------------------------*/
uint8 WhichPosChar(Init &init, int32 ch) {
struct SDiary *d;
int32 i;
for (i = 0, d = &init.Diary[0]; i < MAX_DIARIES; i++, d++) {
if ((d->obj != ch) || (t3dCurTime < d->startt) || (d->endt && (t3dCurTime >= d->endt))) continue;
if (!d->item[d->cur].on) continue;
return init.Anim[d->item[d->cur].anim[d->item[d->cur].cur]].pos;
}
return 0;
}
} // End of namespace Watchmaker

View File

@@ -0,0 +1,43 @@
/* 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/>.
*
*/
#ifndef WATCHMAKER_LL_DIARY_H
#define WATCHMAKER_LL_DIARY_H
#include "watchmaker/work_dirs.h"
#include "watchmaker/globvar.h"
#include "watchmaker/game.h"
namespace Watchmaker {
void UpdateAllClocks(WGame &game);
void StopDiary(WGame &game, int32 room, int32 obj, uint8 only_overtime);
void StartDiary(WGame &game, int32 room, t3dV3F *pos);
void IncCurTime(WGame &game, int32 inc);
void DecCurTime(WGame &game, int32 dec);
void SetCurTime(WGame &game, int32 set);
int32 WhichRoomChar(Init &init, int32 ch);
int32 WhichAnimChar(Init &init, int32 ch);
void ContinueDiary(WGame &game, int32 an);
} // End of namespace Watchmaker
#endif // WATCHMAKER_LL_DIARY_H

View File

@@ -0,0 +1,92 @@
/* 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/ll/ll_ffile.h"
#include "common/substream.h"
#include "watchmaker/ll/ll_system.h"
namespace Watchmaker {
const int MAX_NAME_LEN = 52;
struct FileEntry {
Common::String name;
int32 offset;
int32 time;
int32 date;
};
FastFile::FastFile(const char *path) : _path(path) {
auto stream = openFile(path);
assert(stream);
_numFiles = stream->readUint32LE();
_files = new FileEntry[_numFiles] {};
_totalSize = stream->size();
for (int i = 0; i < _numFiles; i++) {
char name[MAX_NAME_LEN] = {};
stream->read(name, MAX_NAME_LEN);
_files[i].name = name;
_files[i].offset = stream->readUint32LE();
_files[i].time = stream->readUint32LE();
_files[i].date = stream->readUint32LE();
for (auto it = _files[i].name.begin(); it != _files[i].name.end(); ++it) {
if (*it == '\\') {
*it = '/';
}
}
}
}
FastFile::~FastFile() {
delete[] _files;
}
Common::SharedPtr<Common::SeekableReadStream> FastFile::resolve(const char *filename) {
Common::String converted = filename;
int index = -1;
//HACK
if (converted.size() >= 2 && converted[0] == '.' && converted[1] == '/') {
converted = converted.substr(2, converted.size() - 2);
}
for (int i = 0; i < _numFiles; i++) {
if (_files[i].name.equalsIgnoreCase(converted)) {
index = i;
break;
}
}
if (index == -1) {
return nullptr;
}
const auto &entry = _files[index];
int size = 0;
if (index == _numFiles - 1) {
size = _totalSize - entry.offset;
} else {
size = _files[index + 1].offset - entry.offset;
}
auto stream = openFile(_path, entry.offset, size);
assert(stream);
return Common::SharedPtr<Common::SeekableReadStream>(stream);
}
} // End of namespace Watchmaker

View File

@@ -0,0 +1,47 @@
/* 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/>.
*
*/
#ifndef WATCHMAKER_LL_FFILE_H
#define WATCHMAKER_LL_FFILE_H
#include "common/ptr.h"
#include "common/stream.h"
namespace Watchmaker {
struct FileEntry;
class FastFile {
const char *_path = nullptr;
int _totalSize = 0;
public:
int _numFiles = 0;
FileEntry *_files = nullptr; // TODO: This could just be a Common::Array
FastFile(const char *path);
~FastFile();
Common::SharedPtr<Common::SeekableReadStream> resolve(const char *filename);
};
} // End of namespace Watchmaker
#endif // WATCHMAKER_LL_FFILE_H

View File

@@ -0,0 +1,881 @@
/* 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/ll/ll_mesh.h"
#include "watchmaker/types.h"
#include "watchmaker/t3d.h"
#include "watchmaker/3d/math/llmath.h"
#include "watchmaker/3d/geometry.h"
#include "watchmaker/windows_hacks.h"
#include "watchmaker/define.h"
#include "watchmaker/globvar.h"
#include "watchmaker/ll/ll_util.h"
#include "watchmaker/3d/animation.h"
#include "watchmaker/utils.h"
#include "watchmaker/ll/ll_mouse.h"
#include "watchmaker/walk/walkutil.h"
#include "watchmaker/walk/walk.h"
#include "watchmaker/ll/ll_system.h"
namespace Watchmaker {
// locals
struct t3dHEADMOVE {
t3dV3F OldPos, DestAng, CurAng;
};
t3dHEADMOVE HeadMove[T3D_MAX_CHARACTERS];
t3dF32 OldArrowLen, OldExplosionScale;
uint32 **SavedBodyLight;
uint8 LastLightChar, LastLightRoom;
/* -----------------14/04/99 18.24-------------------
* t3dUpdateArrow
* --------------------------------------------------*/
void t3dUpdateArrow(t3dMESH *m, t3dF32 len) {
uint32 i;
if (!m) return;
m->VBptr = m->VertexBuffer;
for (i = 0; i < m->NumVerts; i++)
if (fabs(m->VBptr[i].z) > 1.0f)
m->VBptr[i].z += (-len + OldArrowLen);
m->Flags |= T3D_MESH_UPDATEVB;
m->VBptr = nullptr;
OldArrowLen = len;
}
/* -----------------27/04/99 10.52-------------------
* t3dLightRoom
* --------------------------------------------------*/
void t3dLightRoom(Init &init, t3dBODY *b, t3dV3F *p, t3dF32 NearRange, t3dF32 FarRange, t3dF32 IperRange) {
uint32 i, j, k, rr, gg, bb, aa, cr, cb, cg, *sbl;
uint32 addr = 110;
uint32 addg = 95;
uint32 addb = 80;
t3dMESH *m;
t3dF32 dist;
t3dV3F tmp;
gVertex *gv;
if (!b || !p) return;
FarRange *= FarRange;
NearRange *= NearRange;
IperRange *= IperRange;
if (!SavedBodyLight) {
if (!(SavedBodyLight = (uint32 **)t3dMalloc(sizeof(uint32 *) * b->NumMeshes())))
return ;
m = &b->MeshTable[0];
for (j = 0; j < b->NumMeshes(); j++, m++) {
if (!m) continue;
if (!(SavedBodyLight[j] = (uint32 *)t3dMalloc(sizeof(uint32) * m->NumVerts * 4)))
continue;
gv = m->VBptr;
m->VBptr = m->VertexBuffer;
for (i = 0; i < m->NumVerts; i++, gv++) {
SavedBodyLight[j][i * 4 + 0] = RGBA_GETRED(gv->diffuse);
SavedBodyLight[j][i * 4 + 1] = RGBA_GETGREEN(gv->diffuse);
SavedBodyLight[j][i * 4 + 2] = RGBA_GETBLUE(gv->diffuse);
SavedBodyLight[j][i * 4 + 3] = RGBA_GETALPHA(gv->diffuse);
}
m->VBptr = nullptr;
}
}
LastLightRoom = (LastLightRoom + 1) > 3 ? 0 : LastLightRoom + 1;
m = &b->MeshTable[0];
for (j = 0; j < b->NumMeshes(); j++, m++) {
if (!m) continue;
if (m->name.equalsIgnoreCase("p50-cielo") || m->name.equalsIgnoreCase("p50-stelle") || m->name.equalsIgnoreCase("p50-luna")) continue;
if (!(m->Flags & T3D_MESH_VISIBLE) && !(m->Flags & T3D_MESH_HIDDEN)) {
m->Flags &= ~T3D_MESH_HIDDEN;
continue;
}
m->Flags &= ~T3D_MESH_HIDDEN;
// if( (j%4) != LastLightRoom ) continue;
sbl = (uint32 *)&SavedBodyLight[j][0];
for (k = 0; k < MAX_OBJ_MESHLINKS ; k++) {
if (((!init.Obj[oNEXTPORTAL].meshLinkIsEmpty(k)) && (m->name.equalsIgnoreCase(init.Obj[oNEXTPORTAL].getMeshLink(k)))) ||
m->name.equalsIgnoreCase("p50-sentierini01") || m->name.equalsIgnoreCase("p50-sentierini02") || m->name.equalsIgnoreCase("p50-sentierini03") ||
m->name.equalsIgnoreCase("p50-sentierini04") || m->name.equalsIgnoreCase("p50-sentierini05") || m->name.equalsIgnoreCase("p50-sentierini06")) {
tmp.x = m->Pos.x - p->x;
tmp.z = m->Pos.z - p->z;
gv = m->VBptr;
m->VBptr = m->VertexBuffer;
if ((dist = tmp.x * tmp.x + tmp.z * tmp.z) > (FarRange + m->Radius * m->Radius * 1.3f)) {
if ((bGolfMode == 0) || (bGolfMode == 1))
if (dist > (FarRange + m->Radius * m->Radius) * 2.5f) m->Flags |= T3D_MESH_HIDDEN;
for (i = 0; i < m->NumVerts; i++, gv++) {
rr = *sbl++;
gg = *sbl++;
bb = *sbl++;
aa = *sbl++;
gv->diffuse = RGBA_MAKE(rr, gg, bb, aa);
}
} else {
for (i = 0; i < m->NumVerts; i++, gv++) {
tmp.x = gv->x - p->x;
tmp.z = gv->z - p->z;
if ((dist = tmp.x * tmp.x + tmp.z * tmp.z) < IperRange) {
rr = *sbl++ + addr * 2;
gg = *sbl++ + addg * 2;
bb = *sbl++ + addb * 2;
} else if (dist < NearRange) {
rr = *sbl++ + addr;
gg = *sbl++ + addg;
bb = *sbl++ + addb;
} else if (dist < FarRange) {
dist = 1.0f - (dist - NearRange) / (FarRange - NearRange);
rr = *sbl++ + (uint32)((t3dF32)(addr) * dist);
gg = *sbl++ + (uint32)((t3dF32)(addg) * dist);
bb = *sbl++ + (uint32)((t3dF32)(addb) * dist);
} else {
rr = *sbl++;
gg = *sbl++;
bb = *sbl++;
}
aa = *sbl++;
if (rr > 255) rr = 255;
if (gg > 255) gg = 255;
if (bb > 255) bb = 255;
gv->diffuse = RGBA_MAKE(rr, gg, bb, aa);
}
}
m->Flags |= T3D_MESH_UPDATEVB;
m->VBptr = nullptr;
break;
}
}
if (k < MAX_OBJ_MESHLINKS) continue;
tmp.x = m->Pos.x - p->x + m->Trasl.x;
tmp.z = m->Pos.z - p->z + m->Trasl.z;
if ((dist = tmp.x * tmp.x + tmp.z * tmp.z) < IperRange) {
cr = addr * 2;
cg = addg * 2;
cb = addb * 2;
} else if (dist < NearRange) {
cr = addr;
cg = addg;
cb = addb;
} else if (dist < FarRange) {
dist = 1.0f - (dist - NearRange) / (FarRange - NearRange);
cr = (uint32)((t3dF32)(addr) * dist);
cg = (uint32)((t3dF32)(addg) * dist);
cb = (uint32)((t3dF32)(addb) * dist);
} else {
if ((bGolfMode == 0) || (bGolfMode == 1))
if (dist > (FarRange + m->Radius * m->Radius) * 2.5f) m->Flags |= T3D_MESH_HIDDEN;
cr = 0;
cg = 0;
cb = 0;
}
gv = m->VBptr;
m->VBptr = m->VertexBuffer;
for (i = 0; i < m->NumVerts; i++, gv++) {
rr = cr + *sbl++;
gg = cg + *sbl++;
bb = cb + *sbl++;
aa = *sbl++;
if (rr > 255) rr = 255;
if (gg > 255) gg = 255;
if (bb > 255) bb = 255;
gv->diffuse = RGBA_MAKE(rr, gg, bb, aa);
}
m->Flags |= T3D_MESH_UPDATEVB;
m->VBptr = nullptr;
}
}
/* -----------------27/04/99 15.35-------------------
* t3dLightChar
* --------------------------------------------------*/
void t3dLightChar(t3dMESH *mesh, t3dV3F *p) {
#if 0
int16 df;
uint32 j, rr, gg, bb, cr, cb, cg;
t3dF32 addr = 110 + 60;
t3dF32 addg = 95 + 75;
t3dF32 addb = 80 + 90;
t3dF32 nlight;
t3dV3F ppos, l, *normal;
gVertex *gv;
if (!mesh || !p) return;
t3dVectAdd(&ppos, &mesh->Trasl, &mesh->Pos);
gv = mesh->VBptr = mesh->VertexBuffer;
cr = (t3dU32)t3dCurRoom->AmbientLight.x + 20;
cg = (t3dU32)t3dCurRoom->AmbientLight.y + 20;
cb = (t3dU32)t3dCurRoom->AmbientLight.z + 20;
df = RGBA_MAKE(cr, cg, cb, 255);
for (j = 0; j < mesh->NumVerts; j++, gv++)
gv->diffuse = df;
t3dVectSub(&l, p, &ppos);
t3dVectTransformInv(&l, &l, &mesh->Matrix);
t3dVectNormalize(&l);
gv = mesh->VBptr;
for (j = 0; j < mesh->NumVerts; j++, gv++) {
normal = &mesh->NList[j]->n;
nlight = t3dVectDot(normal, &l);
// if( (nlight=t3dVectDot(normal,&l)) >= 0 )
{
rr = cr + t3dFloatToInt((addr * nlight));
gg = cg + t3dFloatToInt((addg * nlight));
bb = cb + t3dFloatToInt((addb * nlight));
if (rr > 255) rr = 255;
if (gg > 255) gg = 255;
if (bb > 255) bb = 255;
gv->diffuse = RGBA_MAKE(rr, gg, bb, 255);
}
}
mesh->Flags |= T3D_MESH_UPDATEVB;
mesh->VBptr = nullptr;
#endif
}
/* -----------------12/04/99 12.11-------------------
* t3dVectMeshInters
* --------------------------------------------------*/
uint8 t3dVectMeshInters(t3dMESH *m, t3dV3F start, t3dV3F end, t3dV3F *inters) {
t3dV3F v1, v2, v3;
if (!m) return 0;
if (!t3dVectPlaneIntersection(inters, start, end, m->BBoxNormal[3])) return 0;
m->VBptr = m->VertexBuffer;
for (uint32 j = 0; j < m->NumFaces(); j++) {
t3dFACE &f = m->FList[j];
if (!f.n) continue;
v1.x = m->VBptr[f.VertexIndex[0]].x;
v1.y = m->VBptr[f.VertexIndex[0]].y;
v1.z = m->VBptr[f.VertexIndex[0]].z;
v2.x = m->VBptr[f.VertexIndex[1]].x;
v2.y = m->VBptr[f.VertexIndex[1]].y;
v2.z = m->VBptr[f.VertexIndex[1]].z;
v3.x = m->VBptr[f.VertexIndex[2]].x;
v3.y = m->VBptr[f.VertexIndex[2]].y;
v3.z = m->VBptr[f.VertexIndex[2]].z;
if (t3dVectTriangleIntersection(inters, start, end, v1, v2, v3, *f.n)) {
m->VBptr = nullptr;
return 1;
}
}
m->VBptr = nullptr;
return 0;
}
/* -----------------19/05/00 12.43-------------------
* t3dMoveAndCheck1stCamera
* --------------------------------------------------*/
bool t3dMoveAndCheck1stCamera(t3dBODY *rr, t3dCAMERA *cc, t3dV3F *mm) {
t3dWALK *w;
t3dV3F tmp;
int32 i, j;
if (!Character[ocCURPLAYER]) return FALSE;
w = &Character[ocCURPLAYER]->Walk;
t3dVectAdd(&tmp, &cc->Source, mm);
// Controlla che non sia dentro un Bounding Box
for (i = 0; i < (int32)rr->NumMeshes(); i++) {
t3dMESH &mesh = rr->MeshTable[i];
if (!(mesh.Flags & T3D_MESH_HIDDEN)) {
// Se il punto di destinazione e' dentro il bound box (allargato dell'altezza del ginocchio)
for (j = 0; j < 6; j++)
if (t3dVectPlaneDistance(tmp, mesh.BBoxNormal[j]) < -KNEE_HEIGHT)
break;
if (j >= 6) {
// Prima controlla che non sia dentro i bounds
for (j = 0; j < w->PanelNum; j++) {
if (PointInside(ocCURPLAYER, j, (double)tmp.x, (double)tmp.z) != 0) {
warning("Inters %s", mesh.name.c_str()); // TODO: Debug
return FALSE;
}
}
warning("Saved by bounds"); // TODO: Debug
}
}
}
// evito che si entri nell'altro personaggio giocante
i = (CurPlayer ^ 1);
if (Character[i + ocDARRELL] && Character[i + ocDARRELL]->Mesh && t3dCurRoom->name.equalsIgnoreCase(PlayerStand[i].roomName)) { // Used to be stricmp
t3dF32 d = t3dVectDistance(&tmp, &Character[i + ocDARRELL]->Mesh->Trasl);
if (d < 435.f) return FALSE;
}
t3dVectAdd(&cc->Source, &cc->Source, mm);
t3dVectAdd(&cc->Target, &cc->Target, mm);
return TRUE;
}
/* -----------------03/05/99 15.24-------------------
* t3dClipToSurface
* --------------------------------------------------*/
uint8 t3dClipToSurface(Init &init, t3dV3F *pt) {
t3dV3F tmp, start, end;
int32 i;
t3dMESH *m;
t3dVectCopy(&start, pt);
start.y = 260000.0f;
t3dVectCopy(&end, pt);
end.y = -130000.0f;
for (i = 0; i < 6; i++) {
if ((m = LinkMeshToStr(init, init.Obj[oNEXTPORTAL].getMeshLink(i))) && (t3dVectMeshInters(m, start, end, &tmp))) {
pt->y = tmp.y;
return true;
}
}
return false;
}
/* -----------------03/05/99 16.44-------------------
* t3dUpdateExplosion
* --------------------------------------------------*/
void t3dUpdateExplosion(t3dMESH *m, t3dF32 scale) {
// t3dU32 i;
if (!m) return;
m->Matrix.M[0] = scale;
m->Matrix.M[4] = scale;
m->Matrix.M[8] = scale;
/* m->VBptr=m->VertexBuffer;
for (i=0; i<m->NumVerts; i++ )
{
m->VBptr[i].x *= (scale/OldExplosionScale);
m->VBptr[i].y *= (scale/OldExplosionScale);
m->VBptr[i].z *= (scale/OldExplosionScale);
}
m->Flags |= T3D_MESH_UPDATEVB;
m->VBptr = NULL;
*/
OldExplosionScale = scale;
}
/* -----------------03/09/98 17.42-------------------
* UpdateBoundingBox
* --------------------------------------------------*/
void UpdateBoundingBox(t3dMESH *mesh) {
t3dBONEANIM *db;
t3dBONE *bone;
t3dV3F Appov;
int32 i, frame;
if (!mesh || (mesh->Flags & T3D_MESH_NOBOUNDBOX))return;
// DebugFile("Update Bounding Box %s",mesh->Name);
if (mesh->Flags & T3D_MESH_DEFAULTANIM)
db = &mesh->DefaultAnim;
else
db = &mesh->Anim;
frame = mesh->CurFrame;
bone = db->BoneTable;
for (i = 0; i < db->NumBones; i++, bone++) {
if (!bone || !bone->Trasl || !bone->Matrix || (bone->ModVertices.size() > mesh->NumVerts)) continue;
if ((!bone->ModVertices.empty()) && !(mesh->Flags & T3D_MESH_CHARACTER)) {
for (i = 0; i < 8; i++) {
t3dVectSub(&Appov, &mesh->BBox[i].p, &bone->Trasl[1]);
t3dVectTransform(&Appov, &Appov, &bone->Matrix[1]);
t3dVectTransformInv(&Appov, &Appov, &bone->Matrix[frame]);
t3dVectAdd(&mesh->BBox[i].p, &Appov, &bone->Trasl[frame]);
}
t3dPlaneNormal(&mesh->BBoxNormal[0], &mesh->BBox[0].p, &mesh->BBox[2].p, &mesh->BBox[1].p); //front
t3dPlaneNormal(&mesh->BBoxNormal[1], &mesh->BBox[4].p, &mesh->BBox[5].p, &mesh->BBox[6].p); //back
t3dPlaneNormal(&mesh->BBoxNormal[2], &mesh->BBox[4].p, &mesh->BBox[0].p, &mesh->BBox[5].p); //Up
t3dPlaneNormal(&mesh->BBoxNormal[3], &mesh->BBox[6].p, &mesh->BBox[7].p, &mesh->BBox[2].p); //Down
t3dPlaneNormal(&mesh->BBoxNormal[4], &mesh->BBox[4].p, &mesh->BBox[6].p, &mesh->BBox[0].p); //Left
t3dPlaneNormal(&mesh->BBoxNormal[5], &mesh->BBox[5].p, &mesh->BBox[1].p, &mesh->BBox[7].p); //Right
return ;
}
}
}
/* -----------------08/06/00 14.51-------------------
* t3dSetSpecialAnimFrame
* --------------------------------------------------*/
bool t3dSetSpecialAnimFrame(WGame &game, const char *name, t3dMESH *mesh, int32 nf) {
if (!name || !mesh)
return false;
if (t3dLoadAnimation(game, name, mesh, T3D_MESH_DEFAULTANIM) <= 0)
return false;
mesh->Flags |= (T3D_MESH_ABS_ANIM | T3D_MESH_DEFAULTANIM);
FixupAnim(mesh, 0, "");
if (nf < 0) nf = mesh->DefaultAnim.NumFrames - 1;
mesh->CurFrame = nf;
mesh->LastFrame = -1;
mesh->BlendPercent = 255;
mesh->LastBlendPercent = 0;
return true;
}
void MeshModifiers::modifyMesh(WGame &game, t3dMESH *mesh) {
struct SMeshModifier *mm;
int16 i;
if (!mesh || (mesh->Flags & T3D_MESH_CHARACTER))
return;
// Check if there is a modifier for this mesh
mm = &MMList[0];
for (i = 0; i < MAX_MODIFIED_MESH; i++, mm++)
if ((!mm->meshName.empty()) && (mm->meshName.equalsIgnoreCase(mesh->name)))
break;
// If there are no modifiers for this mesh or they refer to a body
if ((i >= MAX_MODIFIED_MESH) || (mm->getFlags() & (MM_SET_BND_LEVEL | MM_SET_HALOES)))
return;
mm->modifyMesh(game, mesh);
}
void SMeshModifier::modifyMesh(WGame &game, t3dMESH *mesh) {
warning("MM %s: addflags %X, removeflags %X, anim |%s|", mesh->name.c_str(), this->AddFlags, this->RemoveFlags, this->animName.c_str());
// Update Flags
if (this->Flags & MM_REMOVE_FLAGS)
mesh->Flags &= ~this->RemoveFlags;
if (this->Flags & MM_ADD_FLAGS)
mesh->Flags |= this->AddFlags;
// Update Materials
if (this->Flags & MM_REMOVE_MAT_FLAGS)
mesh->FList[0].getMaterial()->Flags &= ~this->RemoveMatFlags;
if (this->Flags & MM_ADD_MAT_FLAGS)
mesh->FList[0].getMaterial()->Flags |= this->AddMatFlags;
if (this->Flags & MM_SET_MAT_FRAME)
mesh->setMovieFrame(this->MatFrame); // This did NOT check for existing face/material before setting before.
// Update Anim
if ((this->Flags & MM_ANIM_BLOCK) && (!this->animName.empty()) && (!mesh->CurFrame)) {
t3dSetSpecialAnimFrame(game, this->animName.c_str(), mesh, -1);
t3dCalcMeshBones(mesh, 1);
UpdateBoundingBox(mesh);
}
}
/* -----------------15/09/98 12.04-------------------
* AddMeshModifier
* --------------------------------------------------*/
void MeshModifiers::addMeshModifier(const Common::String &name, int16 com, void *p) {
struct SMeshModifier *mm;
int16 i;
warning("Not sure this is right"); // Used to check for nullptr, not 0 length.
if (name.empty() || !p)
return;
// DebugLogFile("AddMM |%s| %d",name,com);
// Check if a modifier already exists for this mesh
mm = &MMList[0];
for (i = 0; i < MAX_MODIFIED_MESH; i++, mm++)
if ((!mm->meshName.empty()) && mm->meshName.equalsIgnoreCase(name))
break;
// If it's a new modifier look for a free place
if (i >= MAX_MODIFIED_MESH) {
mm = &MMList[0];
for (i = 0; i < MAX_MODIFIED_MESH; i++, mm++)
if (mm->meshName.empty())
break;
if (i >= MAX_MODIFIED_MESH) {
warning("Troppi Mesh modifier per %s: MAX %d", name.c_str(), MAX_MODIFIED_MESH);
return;
}
*mm = SMeshModifier(name.c_str(), com, p);
} else {
mm->configure(name.c_str(), com, p);
}
}
SMeshModifier::SMeshModifier(Common::SeekableReadStream &stream) {
char stringBuffer[T3D_NAMELEN] = {};
stream.read(stringBuffer, T3D_NAMELEN);
meshName = stringBuffer;
Flags = stream.readSint32LE();
AddFlags = stream.readUint32LE();
RemoveFlags = stream.readUint32LE();
AddMatFlags = stream.readUint32LE();
RemoveMatFlags = stream.readUint32LE();
MatFrame = stream.readSint32LE();
BndLevel = stream.readUint16LE();
HaloesStatus = stream.readByte(); // TODO: Signed.
stream.read(stringBuffer, T3D_NAMELEN);
animName = stringBuffer;
}
SMeshModifier::SMeshModifier(const char *name, int16 com, void *p) {
configure(name, com, p);
}
void SMeshModifier::configure(const char *name, int16 com, void *p) {
this->Flags |= com;
switch (com) {
case MM_ADD_FLAGS:
Flags = *((uint32 *)p);
this->RemoveFlags &= ~Flags;
this->AddFlags |= Flags;
break;
case MM_REMOVE_FLAGS:
Flags = *((uint32 *)p);
this->AddFlags &= ~Flags;
this->RemoveFlags |= Flags;
break;
case MM_ADD_MAT_FLAGS:
Flags = *((uint32 *)p);
this->RemoveMatFlags &= ~Flags;
this->AddMatFlags |= Flags;
break;
case MM_REMOVE_MAT_FLAGS:
Flags = *((uint32 *)p);
this->AddMatFlags &= ~Flags;
this->RemoveMatFlags |= Flags;
break;
case MM_SET_MAT_FRAME:
this->MatFrame = *((int32 *)p);
break;
case MM_ANIM_BLOCK:
if (this->animName.empty())
this->animName = (char *)p;
else
this->animName.clear();
break;
case MM_SET_BND_LEVEL:
this->BndLevel = *((uint16 *)p);
break;
case MM_SET_HALOES:
this->HaloesStatus = *((int8 *)p);
break;
}
}
void MeshModifiers::applyAllMeshModifiers(WGame &game, t3dBODY *b) {
// Check if there is a modifier for this body
struct SMeshModifier *mm = &MMList[0];
for (int32 j = 0; j < MAX_MODIFIED_MESH; j++, mm++)
if ((!mm->meshName.empty()) && b->name.equalsIgnoreCase(mm->meshName)) {
if (mm->getFlags() & MM_SET_BND_LEVEL)
b->CurLevel = mm->getBndLevel();
if (mm->getFlags() & MM_SET_HALOES) {
for (auto &l : b->LightTable) {
if (!(l.Type & T3D_LIGHT_FLARE)) continue;
if (mm->getHaloesStatus() > 0)
l.Type |= T3D_LIGHT_LIGHTON;
else
l.Type &= ~T3D_LIGHT_LIGHTON;
}
}
}
for (int32 i = 0; i < (int32)b->NumMeshes(); i++) {
modifyMesh(game, &b->MeshTable[i]);
}
}
/* -----------------29/03/99 14.33-------------------
* HideRoomMeshes
* --------------------------------------------------*/
void HideRoomMeshes(Init &init, t3dBODY *body) {
int32 cr, c, a, b, i, j, k, h, skip;
t3dMESH *m;
if (!(cr = getRoomFromStr(init, body->name))) return;
// DebugFile("Hiding Room %s (%d)",body->Name,cr);
for (a = 0; a < MAX_OBJS_IN_ROOM; a++) {
if (!(c = init.Room[cr].objects[a])) continue;
if (init.Obj[c].flags & NOUPDATE) continue;
if (!(init.Obj[c].flags & ON) || (init.Obj[c].flags & HIDE)) {
for (b = 0; b < MAX_OBJ_MESHLINKS; b++) {
if (init.Obj[c].meshLinkIsEmpty(b)) continue;
m = nullptr;
const Common::String &str = init.Obj[c].getMeshLink(b);
for (h = 0; h < (uint16)body->NumMeshes(); h++) {
if (body->MeshTable[h].name.equalsIgnoreCase(str)) {
m = &body->MeshTable[h];
break;
}
}
if (m == nullptr) continue;
// DebugFile("CandidateObj '%s'",Obj[c].meshlink[b]);
skip = 0;
for (i = 0; i < MAX_OBJS_IN_ROOM; i++) {
if (!(k = init.Room[cr].objects[i]) || (k == c)) continue;
if (!(init.Obj[k].flags & ON) || (init.Obj[k].flags & HIDE)) continue;
for (j = 0; j < MAX_OBJ_MESHLINKS; j++) {
if (init.Obj[k].meshLinkIsEmpty(j)) continue;
if (!init.Obj[c].getMeshLink(b).equalsIgnoreCase(init.Obj[k].getMeshLink(j))) continue;
// DebugFile("Skipped for %d,%d",k,j);
skip ++;
break;
}
}
if (!skip && m) {
// DebugFile("Hiding Mesh %s",Obj[c].meshlink[b]);
m->Flags |= T3D_MESH_HIDDEN;
}
}
}
}
}
/* -----------------28/12/98 17.43-------------------
* UpdateCharHead
* --------------------------------------------------*/
void UpdateCharHead(int32 oc, t3dV3F *dir) {
t3dCHARACTER *Ch = Character[oc];
t3dMESH *mesh;
t3dHEADMOVE *t;
t3dBONE *bone;
t3dV3F tmp;
int32 i, cf;
t3dF32 s;
if (!Ch || !(mesh = Ch->Mesh) || mHide || !dir) return;
if ((bDialogActive) || (bT2DActive) || (InvStatus)) return;
if (oc == ocCURPLAYER) oc = ocDARRELL + CurPlayer;
t = &HeadMove[oc];
if ((Player->Mesh->CurFrame > ActionStart[aSTAND]) || !(Player->Mesh->Flags & T3D_MESH_DEFAULTANIM))
t3dVectFill(&t->DestAng, 0.0f);
else if (t->OldPos != *dir) {
t3dVectCopy(&tmp, &mesh->Trasl);
tmp.y = CurFloorY + EYES_HEIGHT;
t3dVectSub(&tmp, dir, &tmp);
t->DestAng.x = t3dVectAngle(&tmp, &Ch->Dir);
if (t->DestAng.x < -MAX_HEAD_ANGLE_X * 2) t->DestAng.x = -MAX_HEAD_ANGLE_X * 2;
if (t->DestAng.x > MAX_HEAD_ANGLE_X * 2) t->DestAng.x = MAX_HEAD_ANGLE_X * 2;
t->DestAng.y = -(t3dF32)asin((mPos.y - (CurFloorY + EYES_HEIGHT)) / t3dVectMod(&tmp)) * 180.0f / T3D_PI;
if (t->DestAng.y < -MAX_HEAD_ANGLE_Y / 2) t->DestAng.y = -MAX_HEAD_ANGLE_Y / 2;
if (t->DestAng.y > MAX_HEAD_ANGLE_Y / 2) t->DestAng.y = MAX_HEAD_ANGLE_Y / 2;
t->DestAng.z = 0.0f;
t3dVectCopy(&t->OldPos, dir);
}
if (t->DestAng != t->CurAng) {
Player->Mesh->LastFrame = 0;
if (Player->Mesh->Flags & T3D_MESH_DEFAULTANIM) {
if (Player->Mesh->CurFrame < ActionStart[aSTAND])
Player->Mesh->CurFrame = ActionStart[aSTAND];
cf = 1;
for (i = 1; i < Player->Mesh->DefaultAnim.NumBones; i++) {
if (!(bone = &Player->Mesh->DefaultAnim.BoneTable[i]) || !(bone->Trasl) || !(bone->Matrix))
continue;
t3dVectCopy(&bone->Trasl[cf], &bone->Trasl[Player->Mesh->CurFrame]);
t3dMatCopy(&bone->Matrix[cf], &bone->Matrix[Player->Mesh->CurFrame]);
}
bone = &Player->Mesh->DefaultAnim.BoneTable[12];
} else {
cf = Player->Mesh->CurFrame;
bone = &Player->Mesh->Anim.BoneTable[12];
}
if ((bone) && (bone->Trasl) && (bone->Matrix)) {
t3dVectSub(&tmp, &t->DestAng, &t->CurAng);
s = t3dVectMod(&tmp);
if (s > MAX_HEAD_SPEED) {
tmp.x *= (MAX_HEAD_SPEED / s);
tmp.y *= (MAX_HEAD_SPEED / s);
}
t->CurAng.x += tmp.x;
t->CurAng.y += tmp.y;
t->CurAng.z = 0.0f;
t3dMatRot(&bone->Matrix[cf], (t->CurAng.y * T3D_PI) / 180.0f, (t->CurAng.x * T3D_PI) / 180.0f, 0.0f);
bone->Matrix[cf].Flags &= ~T3D_MATRIX_IDENTITY;
// Player->Mesh->BlendPercent = 0;
Player->Mesh->CurFrame = cf;
}
}
// se siamo in un dialogo o RTV non gli faccio muovere la testolina
if (bDialogActive) {
t3dVectFill(&t->CurAng, 0.0f);
t3dVectFill(&t->DestAng, 0.0f);
t3dVectFill(&t->OldPos, 0.0f);
}
}
/* -----------------22/06/00 12.15-------------------
* ChangeMeshFlags
* --------------------------------------------------*/
void ChangeMeshFlags(t3dMESH *m, int8 add, uint32 newflags) {
if (!m) return;
if (add > 0) {
m->Flags |= newflags;
_vm->addMeshModifier(m->name, MM_ADD_FLAGS, &newflags);
} else {
m->Flags &= ~newflags;
_vm->addMeshModifier(m->name, MM_REMOVE_FLAGS, &newflags);
}
}
/* -----------------29/06/00 11.22-------------------
* ChangeHaloesStatus
* --------------------------------------------------*/
void ChangeHaloesStatus(t3dBODY *b, int8 op) {
if (b == nullptr) b = t3dCurRoom;
if (b == nullptr) return;
for (auto &l : b->LightTable) {
if (!(l.Type & T3D_LIGHT_FLARE)) continue;
if (op > 0)
l.Type |= T3D_LIGHT_LIGHTON;
else
l.Type &= ~T3D_LIGHT_LIGHTON;
}
_vm->addMeshModifier(b->name.c_str(), MM_SET_HALOES, &op);
}
/* -----------------01/06/00 11.12-------------------
* UpdateObjMesh
* --------------------------------------------------*/
void UpdateObjMesh(Init &init, int32 in) {
t3dMESH *m;
int32 a;
if (init.Obj[in].flags & NOUPDATE) return;
for (a = 0; a < MAX_OBJ_MESHLINKS; a++) {
m = LinkMeshToStr(init, init.Obj[in].getMeshLink(a));
if (m) {
if ((init.Obj[in].flags & ON) && !(init.Obj[in].flags & HIDE))
// m->Flags &= ~T3D_MESH_HIDDEN;
ChangeMeshFlags(m, -1, T3D_MESH_HIDDEN);
else
// m->Flags |= T3D_MESH_HIDDEN;
ChangeMeshFlags(m, +1, T3D_MESH_HIDDEN);
} else {
//se non la trova in memoria aggiunge solo il modifier alla lista
uint32 newflags;
newflags = T3D_MESH_HIDDEN;
if (!init.Obj[in].meshLinkIsEmpty(a)) {
if ((init.Obj[in].flags & ON) && !(init.Obj[in].flags & HIDE))
_vm->addMeshModifier(init.Obj[in].getMeshLink(a), MM_REMOVE_FLAGS, &newflags);
else
_vm->addMeshModifier(init.Obj[in].getMeshLink(a), MM_ADD_FLAGS, &newflags);
}
}
}//for
}
/* -----------------22/06/00 12.15-------------------
* SetMeshMaterialMovieFrame
* --------------------------------------------------*/
void SetMeshMaterialMovieFrame(t3dMESH *m, int8 op, int32 newframe) {
if (!m || m->FList.empty() || !m->FList[0].getMaterial()) return;
if (op == 0)
m->setMovieFrame(newframe);
else if (op > 0)
m->setMovieFrame(m->getMovieFrame() + newframe);
else if (op < 0)
m->setMovieFrame(m->getMovieFrame() - newframe);
newframe = m->getMovieFrame();
_vm->addMeshModifier(m->name, MM_SET_MAT_FRAME, &newframe);
}
/* -----------------22/06/00 12.15-------------------
* ChangeMeshMaterialFlags
* --------------------------------------------------*/
void ChangeMeshMaterialFlag(t3dMESH *m, int8 add, uint32 newflag) {
if (!m || m->hasFaceMaterial()) return;
if (add > 0) {
m->FList[0].getMaterial()->addProperty(newflag);
_vm->addMeshModifier(m->name, MM_ADD_MAT_FLAGS, &newflag);
} else {
m->FList[0].getMaterial()->clearFlag(newflag);
_vm->addMeshModifier(m->name, MM_REMOVE_MAT_FLAGS, &newflag);
}
}
/* -----------------20/04/99 15.29-------------------
* t3dProcessGolfSky
* --------------------------------------------------*/
void t3dProcessGolfSky(t3dMESH *gs) {
uint32 i;
t3dF32 GolfSkySpeed = 0.00009f;
gVertex *gv;
if (!gs) return ;
gv = gs->VertexBuffer;
for (i = 0; i < gs->NumVerts; i++, gv++) {
gv->u1 += GolfSkySpeed;
gv->v1 += GolfSkySpeed;
}
gs->Flags |= T3D_MESH_UPDATEVB;
gs->VBptr = NULL;
}
} // End of namespace Watchmaker

View File

@@ -0,0 +1,89 @@
/* 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/>.
*
*/
#ifndef WATCHMAKER_LL_MESH_H
#define WATCHMAKER_LL_MESH_H
#include "watchmaker/t3d.h"
#include "watchmaker/globvar.h"
#include "watchmaker/work_dirs.h"
namespace Watchmaker {
uint8 t3dClipToSurface(Init &init, t3dV3F *pt);
void t3dLightChar(t3dMESH *mesh, t3dV3F *p);
void t3dProcessGolfSky(t3dMESH *gs);
void HideRoomMeshes(Init &init, t3dBODY *body);
void t3dUpdateArrow(t3dMESH *m, t3dF32 len);
bool t3dSetSpecialAnimFrame(WGame &game, const char *name, t3dMESH *mesh, int32 nf);
void ChangeMeshFlags(t3dMESH *m, int8 add, uint32 newflags);
void UpdateObjMesh(Init &init, int32 in);
void UpdateBoundingBox(t3dMESH *mesh);
void UpdateCharHead(int32 oc, t3dV3F *dir);
void SetMeshMaterialMovieFrame(t3dMESH *m, int8 op, int32 newframe);
void ChangeMeshMaterialFlag(t3dMESH *m, int8 add, uint32 newflag);
void ChangeHaloesStatus(t3dBODY *b, int8 op);
uint8 t3dVectMeshInters(t3dMESH *m, t3dV3F start, t3dV3F end, t3dV3F *inters);
void t3dLightRoom(Init &init, t3dBODY *b, t3dV3F *p, t3dF32 NearRange, t3dF32 FarRange, t3dF32 IperRange);
void t3dUpdateExplosion(t3dMESH *m, t3dF32 scale);
bool t3dMoveAndCheck1stCamera(t3dBODY *rr, t3dCAMERA *cc, t3dV3F *mm);
// TODO: This could perhaps be PIMPLd, as we don't really need to expose the implementation.
struct SMeshModifier {
Common::String meshName;
private:
int32 Flags = 0;
uint32 AddFlags = 0;
uint32 RemoveFlags = 0;
uint32 AddMatFlags = 0;
uint32 RemoveMatFlags = 0;
int32 MatFrame = 0;
uint16 BndLevel = 0;
int8 HaloesStatus = 0;
public:
Common::String animName;
SMeshModifier() = default;
SMeshModifier(const char *name, int16 com, void *p);
SMeshModifier(Common::SeekableReadStream &stream);
void configure(const char *name, int16 com, void *p);
void modifyMesh(WGame &game, t3dMESH *mesh);
uint16 getBndLevel() const { return BndLevel; }
int32 getFlags() const { return Flags; }
int8 getHaloesStatus() const { return HaloesStatus; }
};
class MeshModifiers {
SMeshModifier MMList[MAX_MODIFIED_MESH] = {};
public:
MeshModifiers() = default;
MeshModifiers(Common::SeekableReadStream &stream) {
for (int i = 0; i < MAX_MODIFIED_MESH; i++) {
MMList[i] = SMeshModifier(stream);
}
}
void addMeshModifier(const Common::String &name, int16 com, void *p);
void applyAllMeshModifiers(WGame &game, t3dBODY *b);
void modifyMesh(WGame &game, t3dMESH *mesh);
};
} // End of namespace Watchmaker
#endif // WATCHMAKER_LL_MESH_H

View File

@@ -0,0 +1,129 @@
/* 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/ll/ll_mouse.h"
#include "watchmaker/utils.h"
#include "watchmaker/message.h"
#include "watchmaker/game.h"
#include "watchmaker/schedule.h"
#include "watchmaker/classes/do_camera.h"
#include "watchmaker/3d/geometry.h"
#include "watchmaker/renderer.h"
namespace Watchmaker {
int32 mPosy = 0, mPosx = 0, mMoveX = 0, mMoveY = 0, mMove = 0, mCounter = 0, mHotspotX = 0, mHotspotY = 0;
uint8 bLPressed = 0, bRPressed = 0, mHide = 1, bSkipped = 0;
uint8 bLPressedPrev = 0, bRPressedPrev = 0;
/* -----------------08/05/98 11.47-------------------
* ProcessMouse
* --------------------------------------------------*/
void ProcessMouse(WGame &game) {
t3dF32 diffx, diffy;
int32 fittedx, fittedy;
if (mMoveX || mMoveY) {
mHide = 0;
mCounter = 0;
game._messageSystem.removeEvent(EventClass::MC_MOUSE, ME_MOUSEUPDATE);
_vm->_messageSystem.doEvent(EventClass::MC_MOUSE, ME_MOUSEUPDATE, MP_DEFAULT, (int16)mPosx, (int16)mPosy, 0, &mMoveX, &mMoveY, NULL);
}
mMoveX = mMoveY = 0;
diffx = 0.0f;
diffy = 0.0f;
game._cameraMan->CamAngleX = 0.0f;
game._cameraMan->CamAngleY = 0.0f;
fittedx = 0;
fittedy = 0;
fittedx = game._renderer->rInvFitX(mPosx);
if (fittedx < (SCREEN_RES_X / 2)) {
if (fittedx < 50) {
diffx = - ((50.f - (t3dF32)fittedx) / 50.f);
}
if (fittedx < 5) diffx *= 1.4f;
} else {
if ((SCREEN_RES_X - fittedx) < 50) {
diffx = ((50.f - (t3dF32)(SCREEN_RES_X - fittedx)) / 50.f);
}
if ((SCREEN_RES_X - fittedx) < 5) diffx *= 1.4f;
}
fittedy = game._renderer->rInvFitY(mPosy);
if (fittedy < (SCREEN_RES_Y / 2)) {
if (fittedy < 50) {
diffy = - ((50.f - (t3dF32)fittedy) / 50.f);
}
if (fittedy < 5) diffy *= 1.4f;
} else {
if ((SCREEN_RES_Y - fittedy) < 50) {
diffy = ((50.f - (t3dF32)(SCREEN_RES_Y - fittedy)) / 50.f);
}
if ((SCREEN_RES_Y - fittedy) < 5) diffy *= 1.4f;
}
auto windowInfo = game._renderer->getScreenInfos();
if (mPosx > (int32)windowInfo.width) mPosx = windowInfo.width - 1;
else if (mPosx <= 0) mPosx = 1;
if (mPosy > (int32)windowInfo.height) mPosy = windowInfo.height - 1;
else if (mPosy <= 0) mPosy = 1;
game._cameraMan->MoveHeadAngles(diffx, diffy);
}
/* -----------------19/10/98 15.18-------------------
* DInputMouseGetCoords
* --------------------------------------------------*/
void HandleMouseChanges() {
// Mouse movement will have been accumulated prior to calling this function.
// Button flags may also have been changed, this function then applies the button changes.
//warning("L: %d %d R: %d %d", bLPressed, bLPressedPrev, bRPressed, bRPressedPrev);
// Button 0 pressed or released
if (bLPressed != bLPressedPrev) {
// se ha rilasciato e non ha mosso il mouse
if ((!bLPressed) && (!bSkipped) && ((mMove < 10) || (!(InvStatus & INV_MODE2) && !bFirstPerson && !bT2DActive))) {
_vm->_messageSystem.doEvent(EventClass::MC_MOUSE, ME_MLEFT, MP_DEFAULT, (int16)mPosx, (int16)mPosy, bRPressed, NULL, NULL, NULL);
bSkipped = FALSE;
} else if (bLPressed && (mMove >= 10) && (InvStatus & INV_MODE2) && (bSomeOneSpeak)) {
bSkipTalk = TRUE;
bSkipped = TRUE;
} else if (!bLPressed)
bSkipped = FALSE;
mMove = 0;
}
// Button 1 pressed or released
if (bRPressed != bRPressedPrev) {
if ((!bRPressed) && ((mMove < 10) || (!bFirstPerson && !bT2DActive)))
_vm->_messageSystem.doEvent(EventClass::MC_MOUSE, ME_MRIGHT, MP_DEFAULT, (int16)mPosx, (int16)mPosy, bLPressed, NULL, NULL, NULL);
mMove = 0;
}
bLPressedPrev = bLPressed;
bRPressedPrev = bRPressed;
}
} // End of namespace Watchmaker

View File

@@ -0,0 +1,39 @@
/* 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/>.
*
*/
#ifndef WATCHMAKER_LL_MOUSE_H
#define WATCHMAKER_LL_MOUSE_H
#include "watchmaker/types.h"
namespace Watchmaker {
class WGame;
// MOUSE form (llmouse.c)
extern int32 mPosy, mPosx, mMoveX, mMoveY, mMove, mCounter, mHotspotX, mHotspotY;
extern uint8 bLPressed, bRPressed, mHide;
void ProcessMouse(WGame &game);
void HandleMouseChanges();
} // End of namespace Watchmaker
#endif // WATCHMAKER_LL_MOUSE_H

View File

@@ -0,0 +1,433 @@
/* 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/ll/ll_regen.h"
#include "watchmaker/classes/do_camera.h"
#include "watchmaker/render.h"
#include "watchmaker/struct.h"
#include "watchmaker/sysdef.h"
#include "watchmaker/utils.h"
#include "watchmaker/t2d/t2d.h"
#include "watchmaker/extraLS.h"
#include "watchmaker/ll/ll_mouse.h"
#include "watchmaker/define.h"
#include "watchmaker/3d/geometry.h"
#include "watchmaker/3d/t3d_body.h"
#include "watchmaker/ll/ll_system.h"
#include "watchmaker/ll/ll_util.h"
#include "watchmaker/ll/ll_string.h"
#include "watchmaker/renderer.h"
// 2d-regen
#define MAX_PAINT_RECTS MAX_DD_BITMAPS+MAX_REND_TEXTS
#define MAX_UPDATE_RECTS MAX_DD_BITMAPS+MAX_REND_TEXTS
namespace Watchmaker {
struct SDDBitmap PaintRect[MAX_PAINT_RECTS];
struct SDDBitmap OldPaintRect[MAX_PAINT_RECTS];
// frame-rate
t3dF32 hi, lo, ofps;
#define WM_CUR_VERSION "The Watchmaker v0.92"
/* -----------------30/10/98 12.19-------------------
* IntersecateRect
* --------------------------------------------------*/
int32 IntersecateRect(int32 x1, int32 y1, int32 x2, int32 y2, int32 x3, int32 y3, int32 x4, int32 y4, SRect *r) {
if ((x1 <= x4) && (x2 >= x3) && (y1 <= y4) && (y2 >= y3)) {
if (x3 > x1)
r->x1 = 0;
else
r->x1 = x1 - x3;
if (x2 < x4)
r->x2 = x2 - x3;
else
r->x2 = x4 - x3;
if (y3 > y1)
r->y1 = 0;
else
r->y1 = y1 - y3;
if (y2 < y4)
r->y2 = y2 - y3;
else
r->y2 = y4 - y3;
if (!(r->x2 - r->x1) || !(r->y2 - r->y1))
return 0;
return 1;
} else
return 0;
}
/* -----------------30/10/98 11.41-------------------
* Regen
* --------------------------------------------------*/
void Regen(WGame &game) {
struct SRect UpdateRect[MAX_UPDATE_RECTS], *p;
struct SDDBitmap *n, *o;
struct SRect r, ext;
int32 a, b, upn;
uint8 found, refresh[MAX_PAINT_RECTS];
#ifdef DEBUG_REGEN
DebugFile("----- Nuovo Frame -----");
#endif
upn = 0;
memset(refresh, 0, sizeof(refresh));
for (uint32 i = 0; i < ARRAYSIZE(UpdateRect); i++) UpdateRect[i].reset();
// I take the Extends of what the engine drew
rGetExtends(&ext.x1, &ext.y1, &ext.x2, &ext.y2);
// 1 - Compare each element of PaintRect to all OlPaintRect elements
for (a = 0; a < MAX_PAINT_RECTS; a++) {
n = &PaintRect[a];
if (!(n->dx) || !(n->dy))
continue;
#ifdef DEBUG_REGEN
DebugFile("%d: Controllo rect %d '%s': %d,%d %d,%d", a, n->tnum, rGetBitmapName(n->tnum), n->px + n->ox, n->py + n->oy, n->dx, n->dy);
#endif
found = 0;
for (b = 0; b < MAX_PAINT_RECTS; b++) {
o = &OldPaintRect[b];
if (!(o->dx) || !(o->dy))
continue;
if ((n->tnum == o->tnum) && (n->px == o->px) && (n->py == o->py) && (n->ox == o->ox) && (n->oy == o->oy) && (n->dx == o->dx) && (n->dy == o->dy)) {
#ifdef DEBUG_REGEN
DebugFile("-> Gia' disegnato");
#endif
refresh[b] = 1;
found ++;
}
}
// if it's a new rectangle, compile UpdateRect
if (true || !found) { // HACK: Just always treat everything as new, since we're doing GL
#ifdef DEBUG_REGEN
DebugFile("-> Nuovo rettangolo");
#endif
UpdateRect[upn].x1 = n->px + n->ox;
UpdateRect[upn].y1 = n->py + n->oy;
UpdateRect[upn].x2 = n->px + n->ox + n->dx;
UpdateRect[upn].y2 = n->py + n->oy + n->dy;
upn ++;
}
}
// 2 - If there are any reactangles that need to be deleted, compile UpdateRect
for (a = 0; a < MAX_PAINT_RECTS; a++) {
n = &OldPaintRect[a];
if (!(n->dx) || !(n->dy))
continue;
if ((!refresh[a]) && (n->dx) && (n->dy)) {
#ifdef DEBUG_REGEN
DebugFile("Non viene piu' ridisegnato %d '%s': %d,%d %d,%d", n->tnum, rGetBitmapName(n->tnum), n->px + n->ox, n->py + n->oy, n->dx, n->dy);
#endif
UpdateRect[upn].x1 = n->px + n->ox;
UpdateRect[upn].y1 = n->py + n->oy;
UpdateRect[upn].x2 = n->px + n->ox + n->dx;
UpdateRect[upn].y2 = n->py + n->oy + n->dy;
upn ++;
}
}
// 3 - For all UpdateRects delete the ScreenBuffer and copy what's left
for (a = 0; a < upn; a++) {
p = &UpdateRect[a];
if (!(p->x2 - p->x1) || !(p->y2 - p->y1))
continue;
// Clear ScreenBuffer
game._renderer->clearBitmap(BACK_BUFFER, (p->x1), (p->y1), (p->x2 - p->x1), (p->y2 - p->y1), 0, 0, 0);
}
for (a = 0; a < upn; a++) {
p = &UpdateRect[a];
if (!(p->x2 - p->x1) || !(p->y2 - p->y1))
continue;
#ifdef DEBUG_REGEN
DebugFile("Ridisegno quello che sta sopra a %d,%d %d,%d", p->x1, p->y1, p->x2 - p->x1, p->y2 - p->y1);
#endif
found = 0;
for (b = 0; b < MAX_PAINT_RECTS; b++) {
n = &PaintRect[b];
if (!(n->dx) || !(n->dy))
continue;
// If it intersects, copies intersection only
if ((IntersecateRect(p->x1, p->y1, p->x2, p->y2, n->px + n->ox, n->py + n->oy, n->px + n->ox + n->dx, n->py + n->oy + n->dy, &r)) &&
(n->ox + r.x2 - r.x1) && (n->oy + r.y2 - r.y1)) {
#ifdef DEBUG_REGEN
DebugFile("Copio %d '%s': P %d,%d O %d,%d D %d,%d", n->tnum, rGetBitmapName(n->tnum), (n->px + n->ox + r.x1), (n->py + n->oy + r.y1), (n->ox + r.x1), (n->oy + r.y1), (r.x2 - r.x1), (r.y2 - r.y1));
// DebugLogWindow( "Copio %d '%s': P %d,%d O %d,%d D %d,%d", n->tnum, rGetBitmapName(n->tnum), (n->px+n->ox+r.x1), (n->py+n->oy+r.y1), (n->ox+r.x1), (n->oy+r.y1), (r.x2-r.x1), (r.y2-r.y1) );
#endif
rBlitter(game, BACK_BUFFER, n->tnum, (n->px + n->ox + r.x1), (n->py + n->oy + r.y1), (n->ox + r.x1), (n->oy + r.y1), (r.x2 - r.x1), (r.y2 - r.y1));
found ++;
}
}
if (!found) {
if (p) p->reset();
}
}
// 4 - Copy on screen only the UpdateRects by stretching them.
for (a = 0; a < MAX_PAINT_RECTS; a++) {
n = &PaintRect[a];
if (!(n->dx) || !(n->dy))
continue;
if ((n->px + n->ox) < ext.x1) ext.x1 = n->px + n->ox;
if ((n->py + n->oy) < ext.y1) ext.y1 = n->py + n->oy;
if ((n->px + n->ox + n->dx) > ext.x2) ext.x2 = n->px + n->ox + n->dx;
if ((n->py + n->oy + n->dy) > ext.y2) ext.y2 = n->py + n->oy + n->dy;
}
for (a = 0; a < upn; a++) {
p = &UpdateRect[a];
if (!(p->x2 - p->x1) || !(p->y2 - p->y1))
continue;
if (p->x1 < ext.x1) ext.x1 = p->x1;
if (p->y1 < ext.y1) ext.y1 = p->y1;
if (p->x2 > ext.x2) ext.x2 = p->x2;
if (p->y2 > ext.y2) ext.y2 = p->y2;
}
auto windowInfo = game._renderer->getScreenInfos();
if (ext.x1 < 0) ext.x1 = 0;
if (ext.y1 < 0) ext.y1 = 0;
if (ext.x2 > (int32)windowInfo.width) ext.x2 = windowInfo.width;
if (ext.y2 > (int32)windowInfo.height) ext.y2 = windowInfo.height;
#ifdef DEBUG_REGEN
DebugFile("Aggiorna video %d,%d %d,%d", ext.x1, ext.y1, ext.x2 - ext.x1, ext.y2 - ext.y1);
// DebugLogWindow( "Aggiorna video %d,%d %d,%d", ext.x1, ext.y1, ext.x2-ext.x1, ext.y2-ext.y1 );
#endif
rUpdateExtends(ext.x1, ext.y1, ext.x2, ext.y2);
game._renderer->blitScreenBuffer();
rResetExtends();
// 5 - Copy PaintRect to OldPaintRect
memcpy(OldPaintRect, PaintRect, sizeof(OldPaintRect));
// memset( OldPaintRect, 0, sizeof( OldPaintRect ) );
}
/* -----------------16/11/98 17.29-------------------
* ResetScreenBuffer
* --------------------------------------------------*/
void ResetScreenBuffer() {
for (uint i = 0; i < ARRAYSIZE(OldPaintRect); i++) OldPaintRect[i].reset();
if (!rClearBuffers(rCLEARSCREENBUFFER | rCLEARZBUFFER))
warning("Unable to clear screenbuffer");
}
/* -----------------30/10/98 16.18-------------------
* AfterRender
* --------------------------------------------------*/
void AfterRender(WGame &game) {
PaintT2D(*game._renderer);
PaintInventory(game);
PaintText(game);
}
/* -----------------31/10/98 15.56-------------------
* AddPaintRect
* --------------------------------------------------*/
void AddPaintRect(int32 tnum, int32 px, int32 py, int32 ox, int32 oy, int32 dx, int32 dy) {
int32 a;
for (a = 0; a < MAX_PAINT_RECTS; a++)
if (!PaintRect[a].tnum)
break;
// ce ne sono troppe
if (a >= MAX_PAINT_RECTS) {
warning("Too many PaintRects!");
return ;
}
PaintRect[a].tnum = tnum;
PaintRect[a].px = (px);
PaintRect[a].py = (py);
PaintRect[a].ox = (ox);
PaintRect[a].oy = (oy);
PaintRect[a].dx = (dx);
PaintRect[a].dy = (dy);
}
void Renderer::add2DStuff() {
// Insert pre-calculated images and texts
_2dStuff.writeBitmapListTo(PaintRect);
_2dStuff.garbageCollectPreRenderedText();
// Put mouse over everything
if ((!mHide) && (CurDialog <= dSUPERVISORE) && (!bTitoliCodaStatic) && (!bTitoliCodaScrolling)) {
int32 cmx = mPosx - mHotspotX;
int32 cmy = mPosy - mHotspotY;
if (cmx >= MousePointerLim.x2)
cmx = MousePointerLim.x2 - 1;
else if (cmx <= MousePointerLim.x1)
cmx = MousePointerLim.x1 + 1;
if (cmy >= MousePointerLim.y2)
cmy = MousePointerLim.y2 - 1;
else if (cmy <= MousePointerLim.y1)
cmy = MousePointerLim.y1 + 1;
// Draw the current mouse pointer
if (CurMousePointer > 0)
AddPaintRect(CurMousePointer, (cmx), (cmy), 0, 0, this->getBitmapDimX(CurMousePointer), this->getBitmapDimY(CurMousePointer));
}
Regen(*_game);
_2dStuff.clearBitmapList();
_2dStuff.clearTextList();
//check
CheckExtraLocalizationStrings(*this, 0);
}
/* -----------------27/10/98 17.14-------------------
* Add3DStuff
* --------------------------------------------------*/
void Add3DStuff(WGame &game) {
extern uint32 StatNumTris, StatNumVerts;
struct SD3DRect *p;
struct SD3DTriangle *t;
int32 a, y = 0;
// char *PauseAnimStr[] = { "", "(PAUSE)" };
if (bShowBoundingBox) {
t3dShowBoundingBox(t3dCurRoom);
for (a = ocCUOCO; a < ocCURPLAYER; a++)
if ((Character[a]) && (Character[a]->Body) && !(Character[a]->Flags & T3D_CHARACTER_HIDE))
t3dShowBoundingBox(Character[a]->Body);
}
if (bShowPanels && Player && Player->Walk.Panel)
t3dShowBounds(Player->Walk.Panel, Player->Walk.PanelNum);
else if (bShowPanels)
t3dShowBounds(t3dCurRoom->Panel[t3dCurRoom->CurLevel], t3dCurRoom->NumPanels[t3dCurRoom->CurLevel]);
//DisplayDDBitmap( TrecLogo, 800-10-rGetBitmapRealDimX(TrecLogo),0, 0,0, 0,0 );
if (bShowInfo) {
//display version
uint32 date = 0, time = 0, d = 0, m = 0, yy = 0, h = 0, min = 0;
t3dForceNOFastFile(1);
if (t3dGetFileDate(&date, &time, "wm.exe ")) {
d = date - (date / 100) * 100;
date /= 100;
m = date - (date / 100) * 100;
date /= 100;
yy = date;
time /= 100;
min = time - (time / 100) * 100;
time /= 100;
h = time;
} else {
d = m = yy = h = min = 0;
}
t3dForceNOFastFile(0);
DebugVideo(*game._renderer, 1, 600 - 20, "%s (%02d/%02d/%4d - %d.%d)", WM_CUR_VERSION, d, m, yy, h, min);
if (LoaderFlags & T3D_DEBUGMODE) {
auto windowInfo = game._renderer->getScreenInfos();
if (CurFps > 100.0f) CurFps = 100.0f;
if (AvgFps > 100.0f) AvgFps = 100.0f;
if (!AvgFps) AvgFps = CurFps;
if (AvgFps != ofps) {
ofps = AvgFps;
hi = 0.0f;
lo = 999.0f;
}
if (CurFps > hi) hi = CurFps;
if (CurFps < lo) lo = CurFps;
DisplayD3DRect(*game._renderer, 1, 1, (int32)((t3dF32)windowInfo.width * (CurFps / 101.0f)), 13, 78, 78, 78, 228);
DebugVideo(*game._renderer, 1, y += 16, "FPS: ( LOW %2d | AVG %2d | HI %2d ) TRI: %d VERT: %d", (int)lo, (int)AvgFps, (int)hi, StatNumTris, StatNumVerts);
// DebugVideo(1,y+=16,"(%d) CUR %f %s",(int)(1000.0f/CurFps),CurFps,PauseAnimStr[bPauseAllAnims]);
DebugVideo(*game._renderer, 1, y += 16, "%d,%d: %s (%d %d) %X", game._gameVars.getCurRoomId(), CurObj, ObjectUnderCursor, NextPortalObj, NextPortalAnim, game.init.Obj[CurObj].flags);
// DebugVideo(1,y+=16,"Player: %d %d %d %d",Player->Mesh->BlendPercent,Player->Mesh->CurFrame,Player->Mesh->LastFrame,Player->Walk.CurAction);
DebugVideo(*game._renderer, 1, y += 16, "DialogActive: %d AnimWaitText: %d PlayerInAnim: %d | %d", bDialogActive, bAnimWaitText, bPlayerInAnim, Player->Mesh->CurFrame);
DebugVideo(*game._renderer, 1, y += 16, "CurCamera %d CurTime %d (%f %f)", game._cameraMan->getCurCameraIndex() + 1, t3dCurTime, t3dCurCamera->Source.x, t3dCurCamera->Source.z);
// DebugVideo(1,y+=16,"xy(%f %f)",Character[1]->Mesh->Trasl.x,Character[1]->Mesh->Trasl.y);
// DebugVideo(1,y+=16,"xy(%f %f)",Character[2]->Dir.x,Character[2]->Dir.y);
DebugVideo(*game._renderer, 1, y += 16, "bPlayerSuBasamento %d", bPlayerSuBasamento);
DebugVideo(*game._renderer, 1, y += 16, "%f %f ", Player->Mesh->Trasl.y, Player->Pos.y);
// DebugVideo(1,y+=16,"CurP %d",CurPlayer);
// DebugVideo(1,y+=16,"InvStatus ON%d (1)%d (2)%d (3)%d (4)%d (5)%d",InvStatus&1,InvStatus&2,InvStatus&4,InvStatus&8,InvStatus&16,InvStatus&32);
DebugVideo(*game._renderer, 1, y += 16, "bMovingCamera%d", bMovingCamera);
// DebugVideo(1,y+=16,"1-%s",PlayerStand[0].RoomName);
// DebugVideo(1,y+=16,"2-%s",PlayerStand[1].RoomName);
/* if( Character[1]->CurRoom )
{
if( Character[1]->CurRoom->Name[0]=='\0' ) DebugVideo(1,y+=16,"1-NULLA");
else DebugVideo(1,y+=16,"1-%s",Character[1]->CurRoom->Name);
}
if( Character[2]->CurRoom )
{
if( Character[2]->CurRoom->Name[0]=='\0' ) DebugVideo(1,y+=16,"2-NULLA");
else DebugVideo(1,y+=16,"2-%s",Character[2]->CurRoom->Name);
}
*/
DebugVideo(*game._renderer, 1, windowInfo.height - 40, "%s", CurDebugString);
} else {
// extern t3dU8 t3dCurCameraIndex;
// DebugVideo(1,y+=16,"CurCamera %d CurTime %d",t3dCurCameraIndex+1,t3dCurTime);
// extern t3dU8 t3dCurCameraIndex;
// if( !AvgFps ) AvgFps = CurFps;
// if( AvgFps != ofps ) { ofps = AvgFps; hi = 0.0f; lo = 999.0f; }
// if( CurFps > hi ) hi = CurFps;
// if( CurFps < lo ) lo = CurFps;
// DebugVideo(1,y+=16,"mHide %d",mHide);
// DebugVideo(1,1,"FPS: %3d TRI: %d VERT: %d",(int)AvgFps,StatNumTris,StatNumVerts);
// DebugVideo(1,y+=16,"CurTime %d CurCamera %d",t3dCurTime,t3dCurCameraIndex+1);
// DebugVideo(1,y+=16,"CurDialog %d, obj %d",CurDialog,Dialog[CurDialog].obj);
// DebugVideo(1,y+=16,"%d,%d: %s (%d %d) %X",CurRoom,CurObj,ObjectUnderCursor,NextPortalObj,NextPortalAnim,Obj[CurObj].flags); //_remove
}
}
// Aggiunge i rettangoli D3D
for (a = 0, p = &D3DRectsList[0]; a < MAX_D3D_RECTS; a++, p++)
if (p->dx || p->dy)
t3dAddQuad((t3dF32)(p->px), (t3dF32)(p->py), (t3dF32)(p->px + p->dx), (t3dF32)(p->py),
(t3dF32)(p->px), (t3dF32)(p->py + p->dy), (t3dF32)(p->px + p->dx), (t3dF32)(p->py + p->dy),
p->r, p->g, p->b, p->a);
for (a = 0, p = &D3DRectsList[0]; a < MAX_D3D_RECTS; a++, p++)
p->dx = p->dy = 0;
// Aggiunge i triangoli D3D
for (a = 0, t = &D3DTrianglesList[0]; a < MAX_D3D_TRIANGLES; a++, t++)
if (t->x1 || t->y1 || t->x2 || t->y2)
t3dAddTriangle((t3dF32)(t->x1), (t3dF32)(t->y1), (t3dF32)(t->x2), (t3dF32)(t->y2),
(t3dF32)(t->x3), (t3dF32)(t->y3), t->r, t->g, t->b, t->a);
for (a = 0, t = &D3DTrianglesList[0]; a < MAX_D3D_TRIANGLES; a++, t++)
t->x1 = t->y1 = t->x2 = t->y2 = t->x3 = t->y3 = 0;
}
} // End of namespace Watchmaker

View File

@@ -0,0 +1,35 @@
/* 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/>.
*
*/
#ifndef WATCHMAKER_LL_REGEN_H
#define WATCHMAKER_LL_REGEN_H
namespace Watchmaker {
class WGame;
void ResetScreenBuffer();
void AfterRender(WGame &game);
void Add3DStuff(WGame &game);
} // End of namespace Watchmaker
#endif // WATCHMAKER_LL_REGEN_H

View File

@@ -0,0 +1,102 @@
/* 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/ll/ll_sound.h"
#include "watchmaker/windows_hacks.h"
namespace Watchmaker {
bool mInitMusicSystem() {
warning("STUBBED: mInitMusicSystem");
return true;
}
bool mCloseMusicSystem() {
warning("STUBBED: mCloseMusicSystem");
return true;
}
bool mLoadMusic(const char *FileName) {
warning("STUBBED: mLoadMusic");
return true;
}
bool mPlayMusic(const char *FileName) {
warning("STUBBED: mPlayMusic");
return true;
}
bool mStopMusic() {
warning("STUBBED: mStopMusic");
return true;
}
bool mRestoreMixerVolume() {
warning("STUBBED: mRestoreMixerVolume");
return true;
}
bool sSetListener(sListener *NewListener) {
warning("STUBBED: sSetListener");
return true;
}
bool sStartSound(sSound *CurSound, bool Reload) {
warning("STUBBED: sStartSound");
return true;
}
bool sStopSound(int32 index) {
warning("STUBBED: sStopSound");
return true;
}
bool sStopAllSounds() {
warning("STUBBED: sStopAllSounds");
return true;
}
bool sIsPlaying(sS32 lIndex) {
warning("STUBBED: sIsPlaying");
return true;
}
bool mSetAllVolume(unsigned char Volume) {
warning("STUBBED: mSetAllVolume");
return true;
}
bool sSetAllSoundsVolume(unsigned char Vol) {
warning("STUBBED: sSetAllSoundsVolume");
return true;
}
bool sSetAllSpeechVolume(unsigned char Vol) {
warning("STUBBED: sSetAllSpeechVolume");
return true;
}
bool sStartSoundDiffuse(sSound *CurSound) {
warning("STUBBED: sStartSoundDiffuse");
return true;
}
} // End of namespace Watchmaker

View File

@@ -0,0 +1,102 @@
/* 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/>.
*
*/
#ifndef WATCHMAKER_LL_SOUND_H
#define WATCHMAKER_LL_SOUND_H
#include "watchmaker/types.h"
namespace Watchmaker {
typedef float sF32;
typedef unsigned int sU32;
typedef signed int sS32;
typedef unsigned short sU16;
#define SOUND_NAME_LEN 100
#define SOUND_SPEECH 32
struct sV3F {
sF32 x, y, z;
};
struct sEnvironment {
sS32 lIndex; // room index (for retrieval)
sS32 lRoom; // room effect level at low frequencies
sS32 lRoomHF; // room effect high-frequency level re. low frequency level
sF32 flRoomRolloffFactor; // like DS3D flRolloffFactor but for room effect
sF32 flDecayTime; // reverberation decay time at low frequencies
sF32 flDecayHFRatio; // high-frequency to low-frequency decay time ratio
sS32 lReflections; // early reflections level relative to room effect
sF32 flReflectionsDelay; // initial reflection delay time
sS32 lReverb; // late reverberation level relative to room effect
sF32 flReverbDelay; // late reverberation delay time relative to initial reflection
sU32 dwEnvironment; // sets all listener properties ****
sF32 flEnvironmentSize; // environment size in meters
sF32 flEnvironmentDiffusion; // environment diffusion
sF32 flAirAbsorptionHF; // change in level per meter at 5 kHz
sU32 dwFlags; // modifies the behavior of properties
};
struct sSound {
char name[SOUND_NAME_LEN];
sS32 lIndex;
sU32 dwLooped;
sF32 flMaxDistance; // servono fl
sF32 flMinDistance; // servono fl
sV3F v3flPosition; // meshlink
sV3F v3flConeOrientation; // angolo con (0,0,-1)
sU32 dwConeInsideAngle; // servono int
sU32 dwConeOutsideAngle; // servono int
sS32 dwConeOutsideVolume; // servono int (negativo)
sU32 dwFlags; // flags
};
struct sListener {
sF32 flDistanceFactor; // non serve
sV3F v3flFrontOrientation; // vettore front camera
sV3F v3flTopOrientation; // vettore alto camera
sV3F v3flPosition; // quella della telecamera
sF32 flRolloff; // non serve
};
bool sSetListener(sListener *NewListener);
bool sStartSound(sSound *CurSound, bool Reload);
bool sStopSound(int32 index);
bool sStopAllSounds();
bool sIsPlaying(sS32 lIndex);
bool mInitMusicSystem();
bool mCloseMusicSystem();
bool mLoadMusic(const char *FileName);
bool mPlayMusic(const char *FileName);
bool mStopMusic();
bool mRestoreMixerVolume();
bool mSetAllVolume(unsigned char Volume);
bool sSetAllSoundsVolume(unsigned char Vol);
bool sSetAllSpeechVolume(unsigned char Vol);
bool sStartSoundDiffuse(sSound *CurSound);
} // End of namespace Watchmaker
#endif // WATCHMAKER_LL_SOUND_H

View File

@@ -0,0 +1,308 @@
/* 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/>.
*
*/
#define FORBIDDEN_SYMBOL_EXCEPTION_strcpy
#include "watchmaker/ll/ll_string.h"
#include "watchmaker/globvar.h"
#include "watchmaker/define.h"
#include "watchmaker/ll/ll_util.h"
#include "watchmaker/game.h"
#include "watchmaker/classes/do_player.h"
#include "watchmaker/classes/do_dialog.h"
#include "watchmaker/t2d/expr.h"
#include "watchmaker/renderer.h"
#include "watchmaker/3d/t3d_body.h"
namespace Watchmaker {
// locals
int32 LastTextTime;
int console_3_4_xoffs = 0;
/* -----------------17/03/98 17.48-------------------
* Text
* --------------------------------------------------*/
void Text(uint16 x, uint16 y, uint16 dx, char *text) {
if (!text) return;
LastTextTime = TheTime;
TheString.x = x;
TheString.y = y;
TheString.dx = dx;
strcpy(TheString.text, text);
}
/* -----------------17/03/98 17.48-------------------
* ClearText
* --------------------------------------------------*/
void ClearText() {
if (!(bUseWith & UW_ON)) {
TheString.x = 0;
TheString.y = 0;
TheString.dx = 0;
memset(TheString.text, 0, sizeof(TheString.text));
}
}
/*-----------------17/02/95 09.53-------------------
TextLen - calcola lunghezza str dal car 0 a num
--------------------------------------------------*/
uint16 TextLen(Fonts &fonts, char *sign, uint16 num) {
uint16 Len, b, c;
b = 0;
if (sign == nullptr)
return (0);
if (num == 0)
Len = strlen(sign);
else
Len = num;
for (c = 0; c < Len; c++)
b += (fonts.StandardFont.table[(uint16)((uint8)sign[c]) * 4 + 2]);
return (b);
}
/*-----------------14/05/95 12.12-------------------
CheckText - returns how many lines it will write
--------------------------------------------------*/
uint16 CheckText(Fonts &fonts, uint16 dx, char *sign) {
uint16 a, b;
uint16 CurInit;
uint16 LastSpace;
uint16 CurLine;
if (sign == NULL) return (0);
// Azzera tutto
memset(TextLines, 0, sizeof(TextLines));
a = 0;
LastSpace = 0;
CurInit = 0;
CurLine = 0;
// Caso piu' semplice: sta tutto su una riga
if (TextLen(fonts, sign, 0) <= dx) {
strcpy((char *)TextLines[CurLine], sign);
return (1);
}
while (a < strlen(sign)) {
a++;
if (sign[a] == ' ') {
if (TextLen(fonts, (char *)(sign + CurInit), (uint16)(a - CurInit)) <= dx)
LastSpace = a;
else if (TextLen(fonts, (char *)(sign + CurInit), (uint16)(LastSpace - CurInit)) <= dx) {
for (b = CurInit; b < LastSpace; b++)
TextLines[CurLine][b - CurInit] = sign[b];
TextLines[CurLine][b - CurInit] = '\0';
CurInit = LastSpace + 1;
a = CurInit;
CurLine++;
} else
return (0);
} else if (sign[a] == '\0') {
if (TextLen(fonts, (char *)(sign + CurInit), (uint16)(a - CurInit)) <= dx) {
for (b = CurInit; b < a; b++)
TextLines[CurLine][b - CurInit] = sign[b];
TextLines[CurLine][b - CurInit] = '\0';
CurLine++;
CurInit = a + 1;
return (CurLine);
} else if (TextLen(fonts, (char *)(sign + CurInit), (uint16)(LastSpace - CurInit)) <= dx) {
for (b = CurInit; b < LastSpace; b++)
TextLines[CurLine][b - CurInit] = sign[b];
TextLines[CurLine][b - CurInit] = '\0';
CurLine++;
CurInit = LastSpace + 1;
if (CurInit < strlen(sign)) {
for (b = CurInit; b < strlen(sign); b++)
TextLines[CurLine][b - CurInit] = sign[b];
TextLines[CurLine][b - CurInit] = '\0';
CurLine++;
}
return (CurLine);
} else
return (0);
}
}
return (0);
}
/* -----------------18/03/98 9.57--------------------
* PaintText
* --------------------------------------------------*/
void PaintText(WGame &game) {
uint16 lines, i;
int32 dx, obj;
FontColor color;
Init &init = game.init;
if (bTitoliCodaStatic || bTitoliCodaScrolling) return;
if (bDialogActive) {
obj = init.Anim[TimeAnim].obj;
if (obj == ocCURPLAYER)
Player->Mesh->ExpressionFrame = VisemaTimeRecon(TheTime - LastTextTime);
else if ((obj >= ocDARRELL) && (obj <= ocLASTCHAR) && (obj) && (Character[obj]->Mesh))
Character[obj]->Mesh->ExpressionFrame = VisemaTimeRecon(TheTime - LastTextTime);
}
lines = (uint16)CheckText(game._fonts, (uint16)game._renderer->rFitY((int32)TheString.dx), TheString.text);
for (i = 0; i < lines; i++) {
dx = (TheString.dx - (TextLen(game._fonts, TextLines[i], 0) * SCREEN_RES_X) / game._renderer->rFitX(SCREEN_RES_X)) / 2;
obj = init.Anim[TimeAnim].obj;
color = WHITE_FONT;
if ((obj >= ocCUOCO) && (obj <= ocCURPLAYER)) {
switch (obj) {
case ocNOTAIO:
case ocSUPERVISORE:
case ocCUOCO:
color = RED_FONT;
break;
case ocVALENCIA:
case ocCHIRURGO:
case ocGIARDINIERE:
color = GREEN_FONT;
break;
case ocKRENN:
case ocOROLOGIAIO:
case ocVICTORIA:
color = CYAN_FONT;
break;
case ocMOORE:
case ocMOOREBUCATO:
case ocDUKES:
case ocTRADUTTORE:
case ocCUSTODE:
color = MAGENTA_FONT;
break;
case ocCORONA:
case ocMOGLIESUPERVISORE:
case ocMOGLIE_KIMONO:
case ocSERVETTA:
color = YELLOW_FONT;
break;
case ocVECCHIO:
case ocCACCIATORE:
case ocCACCIATOREMALPRESO:
case ocDOMESTICA:
color = GRAY_FONT;
break;
case ocDARRELL:
case ocDARRELLALETTO:
case ocCURPLAYER:
default:
color = WHITE_FONT;
break;
}
}
game._renderer->_2dStuff.displayDDText(TextLines[i], FontKind::Standard, color, TheString.x + dx, TheString.y + i * 12, 0, 0, 0, 0);
}
}
/* -----------------06/04/98 10.34-------------------
* PaintInventory
* --------------------------------------------------*/
void PaintInventory(WGame &game) {
int32 a, ci;
Init &init = game.init;
Renderer &renderer = *game._renderer;
if ((InvStatus & INV_ON) || ((bT2DActive == tOPTIONS) && !bShowOnlyLoadWindow)) {
if (bT2DActive != tOPTIONS) {
DisplayD3DRect(renderer, 27, 77, 188, 490, 18, 25, 18, 128);
DisplayD3DRect(renderer, 13, 124, 14, 49, 18, 25, 18, 128);
DisplayD3DRect(renderer, 215, 472, 12, 50, 18, 25, 18, 128);
renderer._2dStuff.displayDDBitmap(Console1, 3, 73, 0, 0, 0, 0);
if (InvLen[CurPlayer] > MAX_SHOWN_ICONS) {
if (InvBase[CurPlayer] > 0)
renderer._2dStuff.displayDDBitmap(ConsoleFrecciaSu, 3 + 14, 73 + 66, 0, 0, 0, 0);
if (InvBase[CurPlayer] < (InvLen[CurPlayer] - MAX_SHOWN_ICONS))
renderer._2dStuff.displayDDBitmap(ConsoleFrecciaGiu, 3 + 206, 73 + 416, 0, 0, 0, 0);
}
}
if ((InvStatus & INV_MODE1) && PlayerCanCall(game._gameVars)) {
if (CurPlayer == VICTORIA)
renderer._2dStuff.displayDDBitmap(Console5, 22, 13, 0, 0, 0, 0);
else
renderer._2dStuff.displayDDBitmap(Console6, 22, 13, 0, 0, 0, 0);
}
if ((InvStatus & INV_MODE2) || (bT2DActive == tOPTIONS)) {
int ox;
if (bT2DActive == tOPTIONS) {
ox = 192;
console_3_4_xoffs = -94;
} else {
ox = 0;
console_3_4_xoffs = 0;
}
if (CurPlayer == DARRELL)
renderer._2dStuff.displayDDBitmap(Console3, 22 + console_3_4_xoffs, 13, ox, 0, 0, 0);
else
renderer._2dStuff.displayDDBitmap(Console4, 22 + console_3_4_xoffs, 13, ox, 0, 0, 0);
if (!PlayerCanSave())
renderer._2dStuff.displayDDBitmap(ConsoleNoSave, 227 + 22 + console_3_4_xoffs, 13, 0, 0, 0, 0);
if ((bT2DActive != tOPTIONS) && (!PlayerCanSwitch(game._gameVars, 0))) {
if (CurPlayer == DARRELL)
renderer._2dStuff.displayDDBitmap(ConsoleNoSwitchDar, 61 + 22 + console_3_4_xoffs, 13, 0, 0, 0, 0);
else
renderer._2dStuff.displayDDBitmap(ConsoleNoSwitchVic, 61 + 22 + console_3_4_xoffs, 13, 0, 0, 0, 0);
}
}
if (bT2DActive != tOPTIONS) {
for (a = 0; a < MAX_SHOWN_ICONS; a++) {
if ((ci = Inv[CurPlayer][InvBase[CurPlayer] + a])) {
if (CurInvObj == ci)
renderer._2dStuff.displayDDText(ObjName[init.InvObj[ci].name], FontKind::Standard, RED_FONT, INV_MARG_SX, INV_MARG_UP + ICON_DY * a, 0, 0, 0, 0);
else
renderer._2dStuff.displayDDText(ObjName[init.InvObj[ci].name], FontKind::Standard, WHITE_FONT, INV_MARG_SX, INV_MARG_UP + ICON_DY * a, 0, 0, 0, 0);
}
}
}
} else if ((bUseWith & UW_ON) && (bUseWith & UW_USEDI)) {
DisplayD3DRect(renderer, game._gameRect._useIconRect.x1 + 3, game._gameRect._useIconRect.y1 + 3, 63, 63, 22, 31, 22, 75);
renderer._2dStuff.displayDDBitmap(IconsPics[UseWith[USED]], game._gameRect._useIconRect.x1 + 3, game._gameRect._useIconRect.y1 + 3, 0, 0, 0, 0);
renderer._2dStuff.displayDDBitmap(Console2, game._gameRect._useIconRect.x1, game._gameRect._useIconRect.y1, 0, 0, 0, 0);
}
PaintDialog(game);
}
} // End of namespace Watchmaker

View File

@@ -0,0 +1,41 @@
/* 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/>.
*
*/
#ifndef WATCHMAKER_LL_STRING_H
#define WATCHMAKER_LL_STRING_H
#include "watchmaker/types.h"
#include "watchmaker/globvar.h"
namespace Watchmaker {
class WGame;
void ClearText();
void Text(uint16 x, uint16 y, uint16 dx, char *text);
class Fonts;
uint16 TextLen(Fonts &fonts, char *sign, uint16 num);
void PaintInventory(WGame &game);
void PaintText(WGame &game);
} // End of namespace Watchmaker
#endif // WATCHMAKER_LL_STRING_H

View File

@@ -0,0 +1,163 @@
/* 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 "common/substream.h"
#include "common/archive.h"
#include "watchmaker/ll/ll_system.h"
#include "watchmaker/types.h"
#include "watchmaker/utils.h"
#include "watchmaker/windows_hacks.h"
namespace Watchmaker {
char bUsingFastFile = 0;
char bForceNOFastFile = 0; // forza a non utilizzare il FastFile, nonostante questo sia attivo
char bForceNOFastFile_bUsingFastFile_backup = 0; //valore precedente la chiamata di ForceNOFastFile
//------------------------- Memory Functions -------------------------------
//..........................................................................
void *t3dMalloc(uint32 n) {
uint32 *res;
if (!(res = static_cast<uint32 *>(malloc(n))))
warning("t3dMalloc: Can't alloc %d bytes", n);
return (res);
}
void *t3dCalloc(uint32 n) {
uint32 *res;
if (!(res = static_cast<uint32 *>(calloc(n, 1))))
warning("t3dCalloc: Can't alloc %d bytes", n);
return (res);
}
void t3dFree(void *p) {
if (!p) return;
free(p);
}
//------------------------- Time Functions ---------------------------------
//..........................................................................
void t3dStartTime() {
warning("STUBBED t3dStartTime");
#if 0
timeGetDevCaps(&tc, sizeof(tc));
timeBeginPeriod(tc.wPeriodMin);
srand((unsigned)time(NULL));
#endif
}
void t3dEndTime() {
warning("STUBBED t3dEndTime");
#if 0
timeEndPeriod(tc.wPeriodMin);
#endif
}
uint32 t3dReadTime() {
return (timeGetTime());
}
//--------------------------------------------------------------------------
//------------------------- File I/O Functions -----------------------------
bool t3dFastFileInit(const char *name) {
warning("STUBBED t3dFastFileInit");
#if 0
bUsingFastFile = FastFileInit(name);
return (BOOL)(bUsingFastFile);
#endif
return false;
}
void t3dForceNOFastFile(char valore) {
if (valore) {
bForceNOFastFile_bUsingFastFile_backup = bUsingFastFile;
bUsingFastFile = 0;
} else bUsingFastFile = bForceNOFastFile_bUsingFastFile_backup;
}
int t3dAccessFile(char *name) {
error("STUBBED: t3dAccessFile\n");
#if 0
FILE *tempFile = nullptr;
if (bUsingFastFile) tempFile = (FILE *)FastFileOpen(name);
else tempFile = fopen(name, "rb");
if (tempFile == NULL)
return 0;
if (bUsingFastFile) FastFileClose((LPFILEHANDLE)tempFile);
else fclose(tempFile);
return 1;
#endif
return 0;
}
bool t3dGetFileDate(uint32 *date, uint32 *time, const char *name) {
warning("TODO: t3dGetFileDate is currently super-inefficient: %s", name);
*date = 0;
*time = 0;
return checkFileExists(name);
}
Common::Path adjustPath(const Common::String &path) {
Common::Path adjustedPath;
if (path.hasPrefix("./")) {
adjustedPath = Common::Path(path.substr(2, path.size()));
} else {
adjustedPath = Common::Path(path);
}
return adjustedPath;
}
bool checkFileExists(const Common::String &filename) {
Common::Path adjustedPath = adjustPath(filename);
return SearchMan.hasFile(adjustedPath);
}
Common::SharedPtr<Common::SeekableReadStream> openFile(const Common::String &filename, int offset, int size) {
Common::Path adjustedPath = adjustPath(filename);
Common::SeekableReadStream *file = SearchMan.createReadStreamForMember(adjustedPath);
if (offset != 0 || size != -1) {
if (size == -1) {
size = file->size();
}
assert(size <= file->size());
assert(offset >= 0 && offset <= file->size());
file = new Common::SeekableSubReadStream(file, offset, offset + size, DisposeAfterUse::YES);
}
return Common::SharedPtr<Common::SeekableReadStream>(file);
}
} // End of namespace Watchmaker

View File

@@ -0,0 +1,67 @@
/* 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/>.
*
*/
#ifndef WATCHMAKER_LL_SYSTEM_H
#define WATCHMAKER_LL_SYSTEM_H
#include "watchmaker/types.h"
#include "common/stream.h"
#include "common/ptr.h"
namespace Watchmaker {
//------------------------- Memory Functions -------------------------------
void *t3dMalloc(uint32 n);
void *t3dCalloc(uint32 n);
template<typename T>
T *t3dMalloc(uint32 num) {
return static_cast<T *>(t3dMalloc(sizeof(T) * num));
}
template<typename T>
T *t3dCalloc(uint32 num) {
// HACK: There are a few places where we actually access the first element even when zero-sized
// those need to be fixed, but for now, let's pad.
if (num == 0) {
num++;
}
return (T *)t3dCalloc(sizeof(T) * num);
}
void *t3dRealloc(void *p, uint32 additionalBytes);
void t3dFree(void *p);
//------------------------- Time Functions ---------------------------------
void t3dStartTime();
void t3dEndTime();
uint32 t3dReadTime();
bool t3dFastFileInit(const char *name);
void t3dForceNOFastFile(char valore);
int t3dAccessFile(char *name);
bool t3dGetFileDate(uint32 *date, uint32 *time, const char *name);
bool checkFileExists(const Common::String &filename);
Common::SeekableReadStream *resolveFile(const char *path);
Common::SharedPtr<Common::SeekableReadStream> openFile(const Common::String &filename, int offset = 0, int size = -1);
} // End of namespace Watchmaker
#endif // WATCHMAKER_LL_SYSTEM_H

View File

@@ -0,0 +1,679 @@
/* 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/ll/ll_util.h"
#include "watchmaker/ll/ll_anim.h"
#include "watchmaker/ll/ll_diary.h"
#include "watchmaker/ll/ll_mesh.h"
#include "watchmaker/ll/ll_regen.h"
#include "watchmaker/3d/animation.h"
#include "watchmaker/3d/geometry.h"
#include "watchmaker/3d/loader.h"
#include "watchmaker/3d/math/llmath.h"
#include "watchmaker/3d/t3d_mesh.h"
#include "watchmaker/classes/do_camera.h"
#include "watchmaker/classes/do_operate.h"
#include "watchmaker/classes/do_system.h"
#include "watchmaker/define.h"
#include "watchmaker/globvar.h"
#include "watchmaker/main.h"
#include "watchmaker/message.h"
#include "watchmaker/renderer.h"
#include "watchmaker/schedule.h"
#include "watchmaker/sysdef.h"
#include "watchmaker/t2d/t2d_internal.h"
#include "watchmaker/types.h"
#include "watchmaker/utils.h"
#include "watchmaker/walk/act.h"
#include "watchmaker/windows_hacks.h"
namespace Watchmaker {
/* -----------------17/03/98 16.19-------------------
* LinkObjToMesh
* --------------------------------------------------*/
uint16 LinkObjToMesh(WGame &game, t3dMESH *m, uint8 op) {
uint16 a, b, c, i;
t3dBODY *cr;
int16 n;
Init &init = game.init;
if (!m) return (oNULL);
NextPortalObj = oNULL;
// Controllo tra gli altri personaggi
for (c = ocCUOCO; c <= ocLASTCHAR; c++) {
for (b = 0; b < MAX_OBJ_MESHLINKS; b++)
if (Character[c] && Character[c]->Mesh)
if ((!init.Obj[c].meshLinkIsEmpty(b)) && (m->name.equalsIgnoreCase(init.Obj[c].getMeshLink(b))))
return (c);
}
// Controllo in stanza attuale
for (a = 0; a < MAX_OBJS_IN_ROOM; a++) {
if (!(c = game.getCurRoom().objects[a])) continue;
if ((init.Obj[c].flags & ON) && !(init.Obj[c].flags & HIDE) &&
(((bFirstPerson) && !(init.Obj[c].flags & HIDEIN1ST)) ||
(!(bFirstPerson) && !(init.Obj[c].flags & HIDEIN3RD)))) {
for (b = 0; b < MAX_OBJ_MESHLINKS; b++)
if ((!init.Obj[c].meshLinkIsEmpty(b)) && (m->name.equalsIgnoreCase(init.Obj[c].getMeshLink(b))))
for (i = 0; i < t3dCurRoom->NumMeshes(); i++)
if ((m->name.equalsIgnoreCase(t3dCurRoom->MeshTable[i].name)))
return (c);
}
}
// Se non trova controlla in portali vicino
for (i = 0; i < t3dCurRoom->NumMeshes(); i++) {
if ((cr = t3dCurRoom->MeshTable[i].PortalList) != nullptr) {
NextPortalAnim = aNULL;
n = getRoomFromStr(init, cr->name);
if ((op == ME_MRIGHT) || (op == ME_MLEFT)) {
for (a = 0; a < MAX_ANIMS_IN_ROOM; a++) {
b = game.getCurRoom().anims[a];
if ((b == aNULL) || !(init.Anim[b].flags & ANIM_PORTAL_LINK)) continue;
if (t3dCurRoom->MeshTable[i].name.equalsIgnoreCase((const char *)init.Anim[b].RoomName.rawArray())) {
NextPortalAnim = b;
break;
}
}
}
for (a = 0; a < MAX_OBJS_IN_ROOM; a++) {
if (!(c = init.Room[n].objects[a])) continue;
if ((init.Obj[c].flags & ON) && !(init.Obj[c].flags & HIDE) &&
(((bFirstPerson) && !(init.Obj[c].flags & HIDEIN1ST)) ||
(!(bFirstPerson) && !(init.Obj[c].flags & HIDEIN3RD)))) {
for (b = 0; b < MAX_OBJ_MESHLINKS; b++) {
if ((!init.Obj[c].meshLinkIsEmpty(b)) && m->name.equalsIgnoreCase(init.Obj[c].getMeshLink(b))) {
if ((op == ME_MRIGHT) || (op == ME_MLEFT))
NextPortalObj = c;
return (c);
}
}
}
}
if ((op == ME_MRIGHT) || (op == ME_MLEFT)) {
for (a = 0; a < cr->NumMeshes(); a++) {
if (m->name.equalsIgnoreCase(cr->MeshTable[a].name)) {
NextPortalObj = oNEXTPORTAL;
return (oNULL);
}
}
}
}
}
if ((op == ME_MRIGHT) || (op == ME_MLEFT))
NextPortalAnim = aNULL;
return (oNULL);
}
/* -----------------16/04/98 11.33-------------------
* WhatIObj
* --------------------------------------------------*/
int32 WhatObj(WGame &game, int32 mx, int32 my, uint8 op) {
t3dMESH *pm, *CurMesh;
t3dF32 minz;
int32 ret;
uint16 n;
op = ME_MRIGHT;
ret = 0;
CurMesh = nullptr;
FloorHit = 0;
minz = 999999999.9f;
for (n = 0; n < t3d_NumMeshesVisible; n++) { // Prima cerca in mesh associate
if (!(pm = t3d_VisibleMeshes[n])) continue;
if ((pm->BBoxAverageZ < minz) && ((pm->Flags & T3D_MESH_RAYBAN) || (LinkObjToMesh(game, pm, 0)))) {
minz = pm->BBoxAverageZ;
CurMesh = pm;
}
}
if (CurMesh == nullptr) { // Poi cerca nelle altre
for (n = 0; n < t3d_NumMeshesVisible; n++) {
if (!(pm = t3d_VisibleMeshes[n])) continue;
if (!(pm->Flags & T3D_MESH_NOBOUNDBOX) && (pm->BBoxAverageZ < minz)) {
minz = pm->BBoxAverageZ;
CurMesh = pm;
}
}
if (t3dCheckWithFloor() < minz)
FloorHit = 1;
}
memset(ObjectUnderCursor, 0, 400);
if (CurMesh || (FloorHit)) {
if (!FloorHit) {
Common::strlcpy(ObjectUnderCursor, CurMesh->name.c_str(), 400);
ret = LinkObjToMesh(game, CurMesh, op);
if (NextPortalObj)
snprintf(ObjectUnderCursor, 400, "NextPortalObj -> %s", CurMesh->name.c_str());
mPos.x = CurMesh->Intersection.x;
mPos.y = CurMesh->Intersection.y;
mPos.z = CurMesh->Intersection.z;
} else {
if (CurMesh)
snprintf(ObjectUnderCursor, 400, "Floor Hit -> %s", CurMesh->name.c_str());
else
Common::strlcpy(ObjectUnderCursor, "Floor Hit", 400);
LinkObjToMesh(game, CurMesh, op);
if (NextPortalObj)
snprintf(ObjectUnderCursor, 400, "NextPortalObj -> Floor Hit -> %s", CurMesh->name.c_str());
mPos.x = FloorHitCoords.x;
mPos.y = FloorHitCoords.y;
mPos.z = FloorHitCoords.z;
}
}
return (ret);
}
/* -----------------13/07/98 12.05-------------------
* getRoomFromStr
* --------------------------------------------------*/
int16 getRoomFromStr(Init &init, const Common::String &s) {
auto end = s.findLastOf(".-");
if (end == s.npos) {
end = s.size() - 1;
}
auto start = s.findLastOf("\\/");
if (start == s.npos) {
start = 0;
}
Common::String str = s.substr(start, end - start);
for (int a = 0; a < MAX_ROOMS; a++)
if (str.equalsIgnoreCase((const char *)init.Room[a].name))
return a;
return (0);
}
/* -----------------19/01/99 11.03-------------------
* CreateTooltipBitmap
* --------------------------------------------------*/
int32 CreateTooltipBitmap(Renderer &renderer, char *tooltip, FontColor color, uint8 r, uint8 g, uint8 b) {
int32 dimx, dimy, enlarge = 5;
char info[100];
if (!tooltip || !strcmp(tooltip, "")) return -1;
FontKind font = FontKind::Standard;
renderer._fonts->getTextDim(tooltip, font, &dimx, &dimy);
dimx += renderer.rFitX(enlarge * 2);
dimy += renderer.rFitY(enlarge * 2);
int32 surf = rCreateSurface(dimx, dimy, 0);
if (surf <= 0) return -1;
Common::strlcpy(info, "tooltip: ", 400);
strncat(info, tooltip, 15);
rSetBitmapName(surf, info);
renderer.clearBitmap(surf, 0, 0, dimx, dimy, 18, 18, 18); // Bordino nero
renderer.clearBitmap(surf, 1, 1, dimx - 2, dimy - 2, r, g, b); // Sfondo colorato
renderer.printText(tooltip, surf, font, color, (uint16)renderer.rFitX(enlarge), (uint16)renderer.rFitY(enlarge));
return surf;
}
/* -----------------27/10/98 15.31-------------------
* LoadDDBitmap
* --------------------------------------------------*/
int32 LoadDDBitmap(WGame &game, const char *n, uint8 flags) {
auto name = game.workDirs.join(game.workDirs._miscDir, n);
int rez = rLoadBitmapImage(game, name.c_str(), (uint8)(rBITMAPSURFACE | rSURFACEFLIP | flags));
if (rez <= 0) {
warning("Failed to load %s. Quitting ...", name.c_str());
CloseSys(game);
}
return (rez);
}
/* -----------------13/05/98 10.59-------------------
* LinkMeshToStr
* --------------------------------------------------*/
t3dMESH *LinkMeshToStr(Init &init, const Common::String &str) {
// TODO: Refactor the callsites:
return _vm->_roomManager->linkMeshToStr(init, str);
}
/* -----------------18/12/00 18.02-------------------
* UpdateRoomInfo
* --------------------------------------------------*/
void UpdateRoomInfo(WGame &game) {
uint8 cr;
if (!t3dCurRoom) return;
cr = (uint8)getRoomFromStr(game.init, t3dCurRoom->name);
if (!cr) return;
// se <20> diversa dalla precedente...
if (strcmp(RoomInfo.name, game.init.Room[cr].desc)) {
game._messageSystem.removeEvent_bparam(EventClass::MC_SYSTEM, ME_STARTEFFECT, EFFECT_ROOMINFO);
game._messageSystem.removeEvent_bparam(EventClass::MC_SYSTEM, ME_CONTINUEEFFECT, EFFECT_ROOMINFO);
game._messageSystem.removeEvent_bparam(EventClass::MC_SYSTEM, ME_STOPEFFECT, EFFECT_ROOMINFO);
_vm->_messageSystem.doEvent(EventClass::MC_SYSTEM, ME_STARTEFFECT, MP_DEFAULT, FRAME_PER_SECOND * 3, 0, EFFECT_ROOMINFO, nullptr, nullptr, nullptr);
}
}
/* -----------------13/10/98 15.00-------------------
* UpdateRoomVisibility
* --------------------------------------------------*/
void UpdateRoomVisibility(WGame &game) {
uint32 i, j;
t3dBODY *pr;
uint8 cr;
Init &init = game.init;
if (!t3dCurRoom) return;
// Leva il flag visibile a tutte le stanze
for (i = 0; i < MAX_ROOMS; i++) {
if (init.Room[i].flags & ROOM_VISIBLE)
init.Room[i].flags |= ROOM_OLDVISIBLE;
init.Room[i].flags &= ~ROOM_VISIBLE;
}
// Aggiunge room attuale
cr = (uint8)getRoomFromStr(init, t3dCurRoom->name);
if (!cr) {
init.Room[cr].flags |= ROOM_VISIBLE;
}
if (bShowRoomDescriptions)
UpdateRoomInfo(game);
// if( !( Room[cr].flags & ROOM_OLDVISIBLE ) )
// Event( EventClass::MC_SYSTEM, ME_STARTEFFECT, MP_DEFAULT, FRAME_PER_SECOND*3, 0, EFFECT_ROOMINFO, NULL, NULL, NULL );
// Prima volta che entra nella r45
if ((cr == r45) && !(init.Room[cr].flags & ROOM_VISITED))
init.Obj[o46SECONDODIAGRAMMA].flags |= EXTRA;
if (!(LoaderFlags & T3D_DEBUGMODE)) {
// Prima volta che entra nella r46
if ((cr == r46) && !(init.Room[cr].flags & ROOM_VISITED))
_vm->_messageSystem.doEvent(EventClass::MC_DIALOG, ME_DIALOGSTART, MP_DEFAULT, dR212, 0, 0, NULL, NULL, NULL);
// Prima volta che entra nella r47
if ((cr == r47) && !(init.Room[cr].flags & ROOM_VISITED))
_vm->_messageSystem.doEvent(EventClass::MC_DIALOG, ME_DIALOGSTART, MP_DEFAULT, dR471, 0, 0, NULL, NULL, NULL);
// Prima volta che entra nella r48
if ((cr == r48) && !(init.Room[cr].flags & ROOM_VISITED))
_vm->_messageSystem.doEvent(EventClass::MC_DIALOG, ME_DIALOGSTART, MP_DEFAULT, dR481, 0, 0, NULL, NULL, NULL);
}
#if 0
// Se ha cambiato stanza cambia anche l'environment
sSetEnvironment(init.Room[cr].env);
// Se ha cambiato stanza cambia anche la musica
if (!(LoaderFlags & T3D_NOMUSIC) && (init.Room[cr].music != nNULL))
PlayMusic(init.Room[cr].music, 3000, 3000);
#endif
init.Room[cr].flags |= ROOM_VISITED;
// Aggiorna oggetti speciali
UpdateSpecial(game, cr);
// Cerca nelle stanze visbili con ricorsione 2
for (i = 0; i < t3dCurRoom->NumMeshes(); i++) {
if (!(pr = t3dCurRoom->MeshTable[i].PortalList) || (t3dCurRoom->MeshTable[i].Flags & T3D_MESH_NOPORTALCHECK))
continue;
cr = (uint8)getRoomFromStr(init, pr->name);
if (!cr) {
init.Room[cr].flags |= ROOM_VISIBLE;
}
for (j = 0; j < pr->NumMeshes(); j++) {
if ((pr->MeshTable[j].PortalList) && !(pr->MeshTable[j].Flags & T3D_MESH_NOPORTALCHECK)) {
cr = (uint8)getRoomFromStr(init, pr->MeshTable[j].PortalList->name);
if (!cr) {
init.Room[cr].flags |= ROOM_VISIBLE;
}
}
}
}
// Accende le animazioni di background delle stanze che si vedono
// DebugFile("RoomVisibility %s",t3dCurRoom->Name);
for (i = 0; i < MAX_ROOMS; i++) {
if (init.Room[i].flags & ROOM_VISIBLE) {
// Aggiunge effetti di background
for (j = 0; j < MAX_SOUNDS_IN_ROOM; j++)
if ((init.Room[i].sounds[j]) && (init.Sound[init.Room[i].sounds[j]].flags & SOUND_ON)) {
//se la pompa non e' attivata non attivo nemmeno il suono
if ((init.Room[i].sounds[j] == wPOMPA) && (init.Obj[o2GOFF].flags & ON)) continue;
//di notte nella r1c la fontana e' spenta
if ((init.Room[i].sounds[j] == wFONTANA) &&
(((t3dCurTime >= 1300) && (t3dCurTime <= 1310)) || (t3dCurTime >= 1800))
) continue;
#if 0
StartSound(init.Room[i].sounds[j]);
#endif
}
// DebugFile("%d: %d %s",i,RoomVisibility[i],Room[RoomVisibility[i]].name);
for (j = 0; j < MAX_ANIMS_IN_ROOM; j++)
if ((init.Room[i].anims[j]) && (init.Anim[init.Room[i].anims[j]].flags & ANIM_ON))
if (!(init.Anim[init.Room[i].anims[j]].active)) {
if ((init.Anim[init.Room[i].anims[j]].obj != aNULL) && (Character[init.Anim[init.Room[i].anims[j]].obj])) {
Character[init.Anim[init.Room[i].anims[j]].obj]->Flags &= ~T3D_CHARACTER_HIDE;
CharSetPosition(init.Anim[init.Room[i].anims[j]].obj, init.Anim[init.Room[i].anims[j]].pos, (const char*)init.Anim[init.Room[i].anims[j]].RoomName.rawArray());
}
DebugLogWindow("Staring Bkg Anim %d | Obj %d Pos %d", init.Room[i].anims[j], init.Anim[init.Room[i].anims[j]].obj, init.Anim[init.Room[i].anims[j]].pos);
StartAnim(game, init.Room[i].anims[j]);
}
StartDiary(game, i, NULL);
}
// Spegne le animazioni delle stanze che non si vedono piu'
else if (init.Room[i].flags & ROOM_OLDVISIBLE) {
// Leva effetti di background
for (j = 0; j < MAX_SOUNDS_IN_ROOM; j++) {
#if 0
if ((init.Room[i].sounds[j]) && (init.Sound[init.Room[i].sounds[j]].flags & SOUND_ON))
StopSound(init.Room[i].sounds[j]);
#endif
}
// Se non e' piu' in vista
for (j = 0; j < MAX_ANIMS_IN_ROOM; j++)
if ((init.Room[i].anims[j]) && (init.Anim[init.Room[i].anims[j]].flags & ANIM_ON)) {
if (Character[init.Anim[init.Room[i].anims[j]].obj]) Character[init.Anim[init.Room[i].anims[j]].obj]->Flags |= T3D_CHARACTER_HIDE;
StopAnim(game, init.Room[i].anims[j]);
}
init.Room[i].flags &= ~ROOM_OLDVISIBLE;
StopDiary(game, i, 0, 0);
}
}
}
/* -----------------12/06/00 10.12-------------------
* SetBndLevel
* --------------------------------------------------*/
bool SetBndLevel(WGame &game, const char *roomname, int32 lev) {
t3dBODY *t = nullptr;
if (roomname && (roomname[0] != '\0')) {
_vm->_roomManager->getRoomIfLoaded(roomname);
} else t = t3dCurRoom;
if (!t) {
DebugLogFile("SETBND FAILED: %s, %d", roomname, lev);
return false;
}
if (lev >= t->NumLevels) {
DebugLogFile("!!!! BND Lev too high: %s max %d ask %d", t->name.c_str(), t->NumLevels, lev);
return false;
}
t->CurLevel = (int16)lev;
if (t == t3dCurRoom)
CurFloorY = t->PanelHeight[t->CurLevel];
_vm->addMeshModifier(t->name, MM_SET_BND_LEVEL, &lev);
UpdateRoomVisibility(game);
DebugLogFile("SETBND: %s, %d", t->name.c_str(), lev);
if (Player) {
Player->Walk.CurPanel = -1;
Player->Walk.OldPanel = -1;
}
return true;
}
/* -----------------17/12/00 17.59-------------------
* PrintLoading
* --------------------------------------------------*/
void PrintLoading() {
warning("STUBBED: PrintLoading");
#if 0
// Stampa la scritta loading
DisplayDDBitmap(LoadingImage, 800 - 103 - 4, 600 - 85 - 4, 0, 0, 0, 0);
Add2DStuff();
rShowFrame();
// rBlitSetStandardFont( StandardFont.Color[WHITE_FONT], StandardFont.Table );
// DebugQuick(10,-1,"Loading...");
// rBlitSetStandardFont( 0, NULL );
#endif
}
/* -----------------01/09/98 16.52--------------------
* ChangeRoom
* --------------------------------------------------*/
void ChangeRoom(WGame &game, Common::String n, uint8 pos, int32 an) {
t3dBODY *t;
int32 i, j, k;
if (n.equalsIgnoreCase("r21.t3d"))
n = "r21-a.t3d";
bFirstPerson = false;
if (t3dCurRoom && t3dCurRoom->name.equalsIgnoreCase(n)) {
game.UpdateAll();
if (pos) CharSetPosition(ocCURPLAYER, pos, nullptr);
if (an) StartAnim(game, an);
return ;
}
PrintLoading();
StopAllAnims(game.init);
// StopMusic();
// quando si cambia piano (e quindi si cancella quello attuale e si carica il nuovo) stoppo il diario in modo che
// se esso aveva delle modifiche da fare al piano corrente le fa subito, e non dopo quando il piano non e' piu' disponibile
StopDiary(game, 0, 0, 0);
// Prima lo cerca tra le stanze in memoria
t = _vm->_roomManager->getRoomIfLoaded(n);
// Se non lo trova tra le stanze in memoria
if (!t) {
t3dResetPipeline();
_vm->_roomManager->releaseLoadedFiles(T3D_STATIC_SET0);
for (i = 0; i < T3D_MAX_CHARACTERS; i++) {
if (Character[i]) {
for (j = 0; j < T3D_MAX_SHADOWBOX_PER_CHAR; j++) {
if (Character[i]->ShadowBox[j]) {
for (k = 0; k < MAX_SHADOWS_PER_LIGHT; k++) {
Character[i]->ShadowBox[j]->ShadowsList[k].ProjectiveTexture.clear();
}
}
}
Character[i]->Walk = t3dWALK();
}
}
rReleaseAllTextures(T3D_STATIC_SET0);
rReleaseAllBitmaps(T3D_STATIC_SET0);
// t3dFree( StandardFont.Table );
ReleasePreloadedAnims();
t3dReleaseParticles();
t3dCurRoom = nullptr;
if (!game.LoadAndSetup(n, 0)) CloseSys(game);
PortalCrossed = t3dCurRoom;
ResetScreenBuffer(); //resetto in modo che la scritta di loading non faccia casini
} else {
ResetScreenBuffer(); //resetto in modo che la scritta di loading non faccia casini
t3dResetPipeline();
t3dCurRoom = t;
PortalCrossed = t3dCurRoom;
t3dCurCamera = &t3dCurRoom->CameraTable[0];
t3dVectCopy(&t3dCurCamera->Target, &Player->Mesh->Trasl);
game._cameraMan->ResetCameraSource();
game._cameraMan->ResetCameraTarget();
CurFloorY = t3dCurRoom->PanelHeight[t3dCurRoom->CurLevel];
}
CameraTargetObj = 0;
CameraTargetBone = 0;
ForcedCamera = 0;
game.UpdateAll();
if (pos)
CharSetPosition(ocCURPLAYER, pos, nullptr);
game._cameraMan->ProcessCamera(game);
if (an)
StartAnim(game, an);
}
/* -----------------21/08/00 15.48-------------------
* GetBndLevel
* --------------------------------------------------*/
int32 GetBndLevel(char *roomname) {
t3dBODY *t = nullptr;
if (roomname && (roomname[0] != '\0')) {
t = _vm->_roomManager->getRoomIfLoaded(roomname);
} else t = t3dCurRoom;
if (!t) return FALSE;
return (int32)t->CurLevel;
}
/* -----------------23/10/98 18.17-------------------
* CheckRect
* --------------------------------------------------*/
bool CheckRect(Renderer &renderer, struct SRect p, int32 cmx, int32 cmy) {
return ((cmx >= renderer.rFitX(p.x1)) && (cmx < renderer.rFitX(p.x2)) && (cmy >= renderer.rFitY(p.y1)) && (cmy < renderer.rFitY(p.y2)));
}
/* -----------------03/05/99 17.31-------------------
* DisplayD3DTriangle
* --------------------------------------------------*/
void DisplayD3DTriangle(Renderer &renderer, int32 x1, int32 y1, int32 x2, int32 y2, int32 x3, int32 y3, uint8 r, uint8 g, uint8 b, uint8 al) {
int32 a;
for (a = 0; a < MAX_D3D_TRIANGLES; a++) {
if ((D3DTrianglesList[a].x1 == renderer.rFitX(x1)) && (D3DTrianglesList[a].y1 == renderer.rFitY(y1)) &&
(D3DTrianglesList[a].x2 == renderer.rFitX(x2)) && (D3DTrianglesList[a].y2 == renderer.rFitY(y2)) &&
(D3DTrianglesList[a].x3 == renderer.rFitX(x3)) && (D3DTrianglesList[a].y3 == renderer.rFitY(y3)))
break;
if (!D3DTrianglesList[a].x1 && !D3DTrianglesList[a].y1 && !D3DTrianglesList[a].x2 && !D3DTrianglesList[a].y2)
break;
}
if (a >= MAX_D3D_TRIANGLES) {
warning("Too many D3D Triangles!");
return ;
}
D3DTrianglesList[a].x1 = renderer.rFitX(x1);
D3DTrianglesList[a].y1 = renderer.rFitY(y1);
D3DTrianglesList[a].x2 = renderer.rFitX(x2);
D3DTrianglesList[a].y2 = renderer.rFitY(y2);
D3DTrianglesList[a].x3 = renderer.rFitX(x3);
D3DTrianglesList[a].y3 = renderer.rFitY(y3);
D3DTrianglesList[a].r = r;
D3DTrianglesList[a].g = g;
D3DTrianglesList[a].b = b;
D3DTrianglesList[a].a = al;
}
/* -----------------24/04/98 10.33-------------------
* DisplayD3DRect
* --------------------------------------------------*/
void DisplayD3DRect(Renderer &renderer, int32 px, int32 py, int32 dx, int32 dy, uint8 r, uint8 g, uint8 b, uint8 al) {
int32 a;
for (a = 0; a < MAX_D3D_RECTS; a++) {
if ((D3DRectsList[a].px == renderer.rFitX(px)) && (D3DRectsList[a].py == renderer.rFitY(py)) &&
(D3DRectsList[a].dx == renderer.rFitX(dx)) && (D3DRectsList[a].dy == renderer.rFitY(dy)))
break;
if (!D3DRectsList[a].dx && !D3DRectsList[a].dy)
break;
}
if (a >= MAX_D3D_RECTS) {
warning("Too many D3D Rects!");
return ;
}
D3DRectsList[a].px = renderer.rFitX(px);
D3DRectsList[a].py = renderer.rFitY(py);
D3DRectsList[a].dx = renderer.rFitX(px + dx) - renderer.rFitX(px);
D3DRectsList[a].dy = renderer.rFitY(py + dy) - renderer.rFitY(py);
D3DRectsList[a].r = r;
D3DRectsList[a].g = g;
D3DRectsList[a].b = b;
D3DRectsList[a].a = al;
}
/* -----------------15/01/99 18.15-------------------
* GetDDBitmapExtends
* --------------------------------------------------*/
void GetDDBitmapExtends(Renderer &renderer, struct SRect *r, struct SDDBitmap *b) {
if (!r || !b) return ;
r->x1 = b->px;
r->y1 = b->py;
// TODO: Somehow the original engine was able to handle this
// even though rGetBitmapRealDimX used b->tnum as index
// into gBitmapList, which becomes problematic when using
// the upper bits for flagging. For now let's mask out
// the high-bit.
uint32 mask = T2D_BM_OFF ^ 0xFFFFFFFF;
r->x2 = r->x1 + renderer.getBitmapRealDimX(b->tnum & mask);
r->y2 = r->y1 + renderer.getBitmapRealDimY(b->tnum & mask);
}
/* -----------------05/11/98 10.36-------------------
* DebugVideo
* --------------------------------------------------*/
void DebugVideo(Renderer &renderer, int32 px, int32 py, const char *format, ...) {
char str[500];
va_list args;
va_start(args, format);
vsnprintf(str, 500, format, args);
va_end(args);
renderer._2dStuff.displayDDText(str, FontKind::Standard, WHITE_FONT, px, py, 0, 0, 0, 0);
// rPrintText( str, 0, StandardFont.Color[WHITE_FONT], StandardFont.Table, px, py );
}
} // End of namespace Watchmaker

View File

@@ -0,0 +1,54 @@
/* 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/>.
*
*/
#ifndef WATCHMAKER_LL_UTIL_H
#define WATCHMAKER_LL_UTIL_H
#include "watchmaker/game.h"
#include "watchmaker/globvar.h"
#include "watchmaker/t3d.h"
#include "watchmaker/work_dirs.h"
#include "watchmaker/renderer.h"
namespace Watchmaker {
int32 LoadDDBitmap(WGame &game, const char *n, uint8 flags);
void LoadFont(WGame &game, struct SFont *f, const char *n);
void UpdateRoomVisibility(WGame &game);
t3dMESH *LinkMeshToStr(Init &init, const Common::String &str);
int16 getRoomFromStr(Init &init, const Common::String &s);
void ChangeRoom(WGame &game, Common::String n, uint8 pos, int32 an);
bool SetBndLevel(WGame &game, const char *roomname, int32 lev);
int32 GetBndLevel(char *roomname);
void GetDDBitmapExtends(Renderer &renderer, struct SRect *r, struct SDDBitmap *b);
void DisplayDDBitmap(Renderer &, int32 tnum, int32 px, int32 py, int32 ox, int32 oy, int32 dx, int32 dy);
void DisplayDDBitmap_NoFit(Renderer &renderer, int32 tnum, int32 px, int32 py, int32 ox, int32 oy, int32 dx, int32 dy);
void UpdateRoomInfo(WGame &game);
bool CheckRect(Renderer &renderer, struct SRect p, int32 cmx, int32 cmy);
void DisplayD3DTriangle(Renderer &, int32 x1, int32 y1, int32 x2, int32 y2, int32 x3, int32 y3, uint8 r, uint8 g, uint8 b, uint8 al);
void DisplayD3DRect(Renderer &, int32 px, int32 py, int32 dx, int32 dy, uint8 r, uint8 g, uint8 b, uint8 al);
int32 CreateTooltipBitmap(Renderer &renderer, char *tooltip, FontColor color, uint8 r, uint8 g, uint8 b);
int32 WhatObj(WGame &game, int32 mx, int32 my, uint8 op);
void DebugVideo(Renderer &renderer, int32 px, int32 py, const char *format, ...);
} // End of namespace Watchmaker
#endif // WATCHMAKER_LL_UTIL_H