diff options
122 files changed, 12666 insertions, 3812 deletions
@@ -701,8 +701,8 @@ Special thanks to of Dreamweb and for their tremendous support. Janusz Wisniewski and Miroslaw Liminowicz from Laboratorium Komputerowe - Avalon for providing full source code for Soltys and letting us - redistribute the game. + Avalon for providing full source code for Soltys and Sfinx and letting us + redistribute the games. Jan Nedoma for providing the sources to the Wintermute-engine, and for his support while porting the engine to ScummVM. @@ -2,8 +2,10 @@ For a more comprehensive changelog of the latest experimental code, see: https://github.com/scummvm/scummvm/commits/ 1.8.0 (????-??-??) + New Games: + - Added support for Sfinx. -Broken Sword 1: + Broken Sword 1: - Fix speech endianness detection on big endian systems for the mac version (bug #6720). - Fix crash when reloading a game from the Main Menu while in the bull's diff --git a/config.guess b/config.guess index 43f0cdbcfd..6c32c8645c 100755 --- a/config.guess +++ b/config.guess @@ -1,14 +1,12 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -# 2011 Free Software Foundation, Inc. +# Copyright 1992-2014 Free Software Foundation, Inc. -timestamp='2011-10-01' +timestamp='2014-11-04' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# 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 @@ -17,26 +15,22 @@ timestamp='2011-10-01' # General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA -# 02110-1301, USA. +# along with this program; if not, see <http://www.gnu.org/licenses/>. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - - -# Originally written by Per Bothner. Please send patches (context -# diff format) to <config-patches@gnu.org> and include a ChangeLog -# entry. +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). # -# This script attempts to guess a canonical system name similar to -# config.sub. If it succeeds, it prints the system name on stdout, and -# exits with 0. Otherwise, it exits with 1. +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +# +# Please send patches to <config-patches@gnu.org>. + me=`echo "$0" | sed -e 's,.*/,,'` @@ -56,9 +50,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, -2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free -Software Foundation, Inc. +Copyright 1992-2014 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -140,12 +132,33 @@ UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown +case "${UNAME_SYSTEM}" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval $set_cc_for_build + cat <<-EOF > $dummy.c + #include <features.h> + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + ;; +esac + # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or - # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward @@ -202,6 +215,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} @@ -304,7 +321,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; - arm:riscos:*:*|arm:RISCOS:*:*) + arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) @@ -562,8 +579,9 @@ EOF else IBM_ARCH=powerpc fi - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi @@ -803,9 +821,15 @@ EOF i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; + *:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 @@ -851,15 +875,22 @@ EOF exit ;; *:GNU:*:*) # the GNU system - echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; @@ -871,59 +902,54 @@ EOF EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 - if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi - echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + if test "$?" = 0 ; then LIBC="gnulibc1" ; fi + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then - echo ${UNAME_MACHINE}-unknown-linux-gnueabi + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi else - echo ${UNAME_MACHINE}-unknown-linux-gnueabihf + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf fi fi exit ;; avr32*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) - echo cris-axis-linux-gnu + echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) - echo crisv32-axis-linux-gnu + echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; frv:Linux:*:*) - echo frv-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; hexagon:Linux:*:*) - echo hexagon-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) - LIBC=gnu - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #ifdef __dietlibc__ - LIBC=dietlibc - #endif -EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` - echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build @@ -942,54 +968,63 @@ EOF #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; - or32:Linux:*:*) - echo or32-unknown-linux-gnu + openrisc*:Linux:*:*) + echo or1k-unknown-linux-${LIBC} + exit ;; + or32:Linux:*:* | or1k*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) - echo sparc-unknown-linux-gnu + echo sparc-unknown-linux-${LIBC} exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-gnu + echo hppa64-unknown-linux-${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in - PA7*) echo hppa1.1-unknown-linux-gnu ;; - PA8*) echo hppa2.0-unknown-linux-gnu ;; - *) echo hppa-unknown-linux-gnu ;; + PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; + PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; + *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; ppc64:Linux:*:*) - echo powerpc64-unknown-linux-gnu + echo powerpc64-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) - echo powerpc-unknown-linux-gnu + echo powerpc-unknown-linux-${LIBC} + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-${LIBC} + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) - echo ${UNAME_MACHINE}-ibm-linux + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; tile*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) - echo ${UNAME_MACHINE}-dec-linux-gnu + echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) - echo x86_64-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; xtensa*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. @@ -1193,6 +1228,9 @@ EOF BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; @@ -1219,19 +1257,31 @@ EOF exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown - case $UNAME_PROCESSOR in - i386) - eval $set_cc_for_build - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then - if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null - then - UNAME_PROCESSOR="x86_64" - fi - fi ;; - unknown) UNAME_PROCESSOR=powerpc ;; - esac + eval $set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # Avoid executing cc on OS X 10.9, as it ships with a stub + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 + fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) @@ -1248,7 +1298,7 @@ EOF NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; - NSE-?:NONSTOP_KERNEL:*:*) + NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) @@ -1317,158 +1367,10 @@ EOF i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; -esac - -#echo '(No uname command or uname output not recognized.)' 1>&2 -#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 - -eval $set_cc_for_build -cat >$dummy.c <<EOF -#ifdef _SEQUENT_ -# include <sys/types.h> -# include <sys/utsname.h> -#endif -main () -{ -#if defined (sony) -#if defined (MIPSEB) - /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, - I don't know.... */ - printf ("mips-sony-bsd\n"); exit (0); -#else -#include <sys/param.h> - printf ("m68k-sony-newsos%s\n", -#ifdef NEWSOS4 - "4" -#else - "" -#endif - ); exit (0); -#endif -#endif - -#if defined (__arm) && defined (__acorn) && defined (__unix) - printf ("arm-acorn-riscix\n"); exit (0); -#endif - -#if defined (hp300) && !defined (hpux) - printf ("m68k-hp-bsd\n"); exit (0); -#endif - -#if defined (NeXT) -#if !defined (__ARCHITECTURE__) -#define __ARCHITECTURE__ "m68k" -#endif - int version; - version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; - if (version < 4) - printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); - else - printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); - exit (0); -#endif - -#if defined (MULTIMAX) || defined (n16) -#if defined (UMAXV) - printf ("ns32k-encore-sysv\n"); exit (0); -#else -#if defined (CMU) - printf ("ns32k-encore-mach\n"); exit (0); -#else - printf ("ns32k-encore-bsd\n"); exit (0); -#endif -#endif -#endif - -#if defined (__386BSD__) - printf ("i386-pc-bsd\n"); exit (0); -#endif - -#if defined (sequent) -#if defined (i386) - printf ("i386-sequent-dynix\n"); exit (0); -#endif -#if defined (ns32000) - printf ("ns32k-sequent-dynix\n"); exit (0); -#endif -#endif - -#if defined (_SEQUENT_) - struct utsname un; - - uname(&un); - - if (strncmp(un.version, "V2", 2) == 0) { - printf ("i386-sequent-ptx2\n"); exit (0); - } - if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ - printf ("i386-sequent-ptx1\n"); exit (0); - } - printf ("i386-sequent-ptx\n"); exit (0); - -#endif - -#if defined (vax) -# if !defined (ultrix) -# include <sys/param.h> -# if defined (BSD) -# if BSD == 43 - printf ("vax-dec-bsd4.3\n"); exit (0); -# else -# if BSD == 199006 - printf ("vax-dec-bsd4.3reno\n"); exit (0); -# else - printf ("vax-dec-bsd\n"); exit (0); -# endif -# endif -# else - printf ("vax-dec-bsd\n"); exit (0); -# endif -# else - printf ("vax-dec-ultrix\n"); exit (0); -# endif -#endif - -#if defined (alliant) && defined (i860) - printf ("i860-alliant-bsd\n"); exit (0); -#endif - - exit (1); -} -EOF - -$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && - { echo "$SYSTEM_NAME"; exit; } - -# Apollos put the system type in the environment. - -test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } - -# Convex versions that predate uname can use getsysinfo(1) - -if [ -x /usr/convex/getsysinfo ] -then - case `getsysinfo -f cpu_type` in - c1*) - echo c1-convex-bsd - exit ;; - c2*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit ;; - c34*) - echo c34-convex-bsd + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx exit ;; - c38*) - echo c38-convex-bsd - exit ;; - c4*) - echo c4-convex-bsd - exit ;; - esac -fi +esac cat >&2 <<EOF $0: unable to guess system type diff --git a/config.sub b/config.sub index 5b8736823d..7ffe373784 100755 --- a/config.sub +++ b/config.sub @@ -1,38 +1,31 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, -# 2011 Free Software Foundation, Inc. +# Copyright 1992-2014 Free Software Foundation, Inc. -timestamp='2011-10-08' +timestamp='2014-12-03' -# This file is (in principle) common to ALL GNU software. -# The presence of a machine in this file suggests that SOME GNU software -# can handle that machine. It does not imply ALL GNU software can. -# -# This file is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# This file 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. +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA -# 02110-1301, USA. +# along with this program; if not, see <http://www.gnu.org/licenses/>. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). -# Please send patches to <config-patches@gnu.org>. Submit a context -# diff and a properly formatted GNU ChangeLog entry. +# Please send patches to <config-patches@gnu.org>. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. @@ -75,9 +68,7 @@ Report bugs and patches to <config-patches@gnu.org>." version="\ GNU config.sub ($timestamp) -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, -2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free -Software Foundation, Inc. +Copyright 1992-2014 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -125,13 +116,17 @@ esac maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ - linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] @@ -154,7 +149,7 @@ case $os in -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ - -apple | -axis | -knuth | -cray | -microblaze) + -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; @@ -223,6 +218,12 @@ case $os in -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; -lynx*) os=-lynxos ;; @@ -247,13 +248,16 @@ case $basic_machine in # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ + | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ - | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ - | be32 | be64 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | be32 | be64 \ | bfin \ - | c4x | clipper \ + | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ @@ -261,10 +265,11 @@ case $basic_machine in | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ + | k1om \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ - | maxq | mb | microblaze | mcore | mep | metag \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ @@ -278,24 +283,27 @@ case $basic_machine in | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r6 | mipsisa32r6el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ - | nios | nios2 \ + | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ - | open8 \ - | or32 \ + | open8 | or1k | or1knd | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ - | rx \ + | riscv32 | riscv64 \ + | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ @@ -305,6 +313,7 @@ case $basic_machine in | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) @@ -319,8 +328,10 @@ case $basic_machine in c6x) basic_machine=tic6x-unknown ;; - m6811 | m68hc11 | m6812 | m68hc12 | picochip) - # Motorola 68HC11/12. + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown os=-none ;; @@ -333,7 +344,10 @@ case $basic_machine in strongarm | thumb | xscale) basic_machine=arm-unknown ;; - + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; xscaleeb) basic_machine=armeb-unknown ;; @@ -356,15 +370,16 @@ case $basic_machine in # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ + | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ - | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ - | clipper-* | craynv-* | cydra-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ @@ -373,11 +388,13 @@ case $basic_machine in | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ + | k1om-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ - | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ @@ -391,23 +408,27 @@ case $basic_machine in | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa32r6-* | mipsisa32r6el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64r6-* | mipsisa64r6el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ - | nios-* | nios2-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ + | or1k*-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ - | romp-* | rs6000-* | rx-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ @@ -420,6 +441,7 @@ case $basic_machine in | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ + | visium-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ @@ -719,7 +741,6 @@ case $basic_machine in i370-ibm* | ibm*) basic_machine=i370-ibm ;; -# I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 @@ -758,6 +779,9 @@ case $basic_machine in basic_machine=m68k-isi os=-sysv ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` + ;; m68knommu) basic_machine=m68k-unknown os=-linux @@ -777,11 +801,15 @@ case $basic_machine in basic_machine=ns32k-utek os=-sysv ;; - microblaze) + microblaze*) basic_machine=microblaze-xilinx ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; mingw32) - basic_machine=i386-pc + basic_machine=i686-pc os=-mingw32 ;; mingw32ce) @@ -809,6 +837,10 @@ case $basic_machine in basic_machine=powerpc-unknown os=-morphos ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; msdos) basic_machine=i386-pc os=-msdos @@ -816,6 +848,10 @@ case $basic_machine in ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; + msys) + basic_machine=i686-pc + os=-msys + ;; mvs) basic_machine=i370-ibm os=-mvs @@ -1004,7 +1040,11 @@ case $basic_machine in basic_machine=i586-unknown os=-pw32 ;; - rdos) + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) basic_machine=i386-pc os=-rdos ;; @@ -1331,29 +1371,29 @@ case $os in -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ - | -sym* | -kopensolaris* \ + | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -openbsd* | -solidbsd* \ + | -bitrig* | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ - | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -linux-gnu* | -linux-android* \ - | -linux-newlib* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) @@ -1477,9 +1517,6 @@ case $os in -aros*) os=-aros ;; - -kaos*) - os=-kaos - ;; -zvmoe) os=-zvmoe ;; @@ -1528,6 +1565,12 @@ case $basic_machine in c4x-* | tic4x-*) os=-coff ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; tic54x-*) os=-coff ;; @@ -1555,9 +1598,6 @@ case $basic_machine in ;; m68000-sun) os=-sunos3 - # This also exists in the configure program, but was not the - # default. - # os=-sunos4 ;; m68*-cisco) os=-aout diff --git a/devtools/create_translations/po_parser.cpp b/devtools/create_translations/po_parser.cpp index 7882502ca4..ecc3ba540c 100644 --- a/devtools/create_translations/po_parser.cpp +++ b/devtools/create_translations/po_parser.cpp @@ -332,6 +332,13 @@ PoMessageEntryList *parsePoFile(const char *file, PoMessageList& messages) { strcat(currentBuf, stripLine(line)); } } + if (currentBuf == msgstrBuf) { + // add last entry + if (*msgstrBuf != '\0' && !fuzzy) { + messages.insert(msgidBuf); + list->addMessageEntry(msgstrBuf, msgidBuf, msgctxtBuf); + } + } fclose(inFile); return list; diff --git a/devtools/credits.pl b/devtools/credits.pl index c8d9e538d8..1c2ece80ed 100755 --- a/devtools/credits.pl +++ b/devtools/credits.pl @@ -1267,7 +1267,7 @@ begin_credits("Credits"); add_paragraph( "Janusz Wiśniewski and Miroslaw Liminowicz from Laboratorium Komputerowe Avalon ". - "for providing full source code for Sołtys and letting us redistribute the game."); + "for providing full source code for Sołtys and Sfinx and letting us redistribute the games."); add_paragraph( "Jan Nedoma for providing the sources to the Wintermute-engine, and for his ". diff --git a/devtools/scumm-md5.txt b/devtools/scumm-md5.txt index eef50003d2..37d7e7a5e1 100644 --- a/devtools/scumm-md5.txt +++ b/devtools/scumm-md5.txt @@ -480,9 +480,9 @@ fbpack Fatty Bear's Fun Pack freddi Freddi Fish 1: The Case of the Missing Kelp Seeds d4cccb5af88f3e77f370896e9ba8c5f9 -1 All Windows HE 71 - - sev - c0039ad982999c92d0de81910d640fa0 -1 nl Windows HE 71 - - adutchguy + c0039ad982999c92d0de81910d640fa0 26159 nl Windows HE 71 - - adutchguy 68530d2e15f339fbbf3150b78b4d2ffb -1 en Mac HE 73 - - satz - 6d1baa1065ac5f7b210be8ebe4235e49 -1 nl Mac HE 73 - - daniel9 + 6d1baa1065ac5f7b210be8ebe4235e49 26384 nl Mac HE 73 - - daniel9 c782fbbe74a987c3df8ac73cd3e289ed -1 se Mac HE 73 - - Torbjörn Andersson 5ebb57234b2fe5c5dff641e00184ad81 -1 fr Windows HE 73 - - gist974 cf8ef3a1fb483c5c4b1c584d1167b2c4 -1 de Windows HE 73 - - Oncer @@ -561,7 +561,11 @@ freddi4 Freddi Fish 4: The Case of the Hogfish Rustlers of Briny Gulch fa84cb1018103a4ee4e5fa8041c1d0d1 13609 de Windows - Demo - George Kormendi ebd324dcf06a4c49e1ba5c231eee1060 -1 us All HE 99 Demo - sev 688328c5bdc4c8ec4145688dfa077bf2 -1 de All HE 99 Demo - Joachim Eberhard - 03d3b18ee3fd68114e2a687c871e38d5 -1 us Windows HE 99 Mini Game - eriktorbjorn + 03d3b18ee3fd68114e2a687c871e38d5 13609 us Windows HE 99 Mini Game - eriktorbjorn + 9340b552b0f2dffe6d4f3d13ebebe832 13609 nl Windows HE 99 Mini Game - Ben Castricum + c486e4cfa7bd6f8efcd0740f96f7dde3 13609 fr Windows HE 99 Mini Game - Ben Castricum + 7a2b6d8e8a645c9d534c8c4edc38a9c9 13609 it Windows HE 99 Mini Game - Ben Castricum + 09b0be55c16cd9e88b5080bf89ff281d 13609 de Windows HE 99 Mini Game - Ben Castricum 16effd200aa6b8abe9c569c3e578814d -1 nl All HE 99 Demo - joostp 499c958affc394f2a3868f1eb568c3ee -1 nl All HE 99 Demo - adutchguy 5fdb2ac2483908b065c6e77988338a54 -1 nl Windows HE 99 Demo - Ben @@ -622,6 +626,7 @@ farm Let's Explore the Farm with Buzzy a5c5388da9bf0e6662fdca8813a79d13 86962 en Windows - - - George Kormendi a85856675429fe88051744f755b72f93 -1 en Windows - - - Kirben a2386da005672cbd5136f4f27a626c5f 87061 nl Windows - - - George Kormendi + eeb606c2d2ec877a712a9f20c10bcdda 87034 nl Mac - - - Ben Castricum 5dda73606533d66a4c3f4f9ea6e842af 87061 ru Windows - - - sev 39fd6db10d0222d817025c4d3346e3b4 -1 en Mac - Demo - Joachim Eberhard @@ -685,7 +690,11 @@ pajama3 Pajama Sam 3: You Are What You Eat From Your Head to Your Feet a654fb60c3b67d6317a7894ffd9f25c5 -1 us All - Demo - sev a9f2f04b1ecaab9495b59befffe9bf88 -1 us All - Demo - sev 0c45eb4baff0c12c3d9dfa889c8070ab 13884 de All - Demo - Joachim Eberhard - 4fe6a2e8df3c4536b278fdd2fbcb181e -1 en Windows - Mini Game - Trekky + 4fe6a2e8df3c4536b278fdd2fbcb181e 13911 en Windows - Mini Game - Trekky + 24942a4200d99bdb4bdb78f9c7e07027 13911 nl Windows - Mini Game - Ben Castricum + faa89ab5e67ba4eebb4399f584f7490c 13911 fr Windows - Mini Game - Ben Castricum + d1a73e87564477c7c2dcc2b8f616ad0b 13911 it Windows - Mini Game - Ben Castricum + a8fcc3084ad5e3e569722755f205b1ef 13911 de Windows - Mini Game - Ben Castricum 679855cf61932f9bf995c8f3677380ed -1 fr Windows - Demo - Mevi c8c5baadcbfc8d0372ed4335abace8a7 -1 fr Windows - Demo - Mevi 784b499c98d07260a30952685758636b 13911 de Windows - Demo - George Kormendi @@ -722,6 +731,7 @@ puttrace Putt-Putt Enters the Race 62050da376483d8edcbd98cd26b6cb57 -1 ru Windows HE 99 - - sev 0ac41e2e3d2174e5a042a6b565328dba 13110 us All HE 98 Demo - sev + ee8cfeb76e55d43a01c25e0865a9db76 13135 nl Mac HE 98 Demo - Ben Castricum 6af2419fe3db5c2fdb091ae4e5833770 -1 nl All HE 98.5 Demo - Kirben 663743c03ae0c007f3d665cf631c0e6b 13135 de All HE 99 Demo - Joachim Eberhard aaa587701cde7e74692c68c1024b85eb -1 nl All HE 99 Demo - joostp @@ -811,7 +821,10 @@ PuttTime Putt-Putt Travels Through Time 59d5cfcc5e672a6e07baae01328b918b -1 fr All HE 90 Demo - Kirben fbb697d89d2beca87360a145f467bdae -1 de All HE 90 Demo - Joachim Eberhard 6b19d0e25cbf720d05822379b8b90ed9 -1 nl All HE 90 Demo - adutchguy - 0a6d7b81b850ed4a77811c60c9b5c555 -1 us Windows HE 99 Mini Game - eriktorbjorn + 0a6d7b81b850ed4a77811c60c9b5c555 18458 us Windows HE 99 Mini Game - eriktorbjorn + a71014c53a6d18c66ef2ea0ee42328e9 18458 nl Windows HE 99 Mini Game - Ben Castricum + 8dd4d590685c19bf651b5016e749ead2 18458 fr Windows HE 99 Mini Game - Ben Castricum + aef415cc5dc063e3668359c2657169f3 18458 de Windows HE 99 Mini Game - Ben Castricum 0ab19be9e2a3f6938226638b2a3744fe -1 us All HE 100 Demo - khalek balloon Putt-Putt and Pep's Balloon-O-Rama @@ -875,12 +888,16 @@ spyfox2 SPY Fox 2: Some Assembly Required bc4700bc0e12879f6d25d14d6be6cfdd -1 de All - - - Joachim Eberhard cea91e3dd47f2518ea418e41611aa77f -1 ru All - - - sev 9fd66fb3b04703bd50da4356e4202558 51295 en Mac - - - pix_climber - 71fe97c3108678cf604f14abe342341b -1 nl Windows - - - adutchguy + 71fe97c3108678cf604f14abe342341b 51286 nl All - - - adutchguy 1c792d28376d45e145cb916bca0400a2 -1 nl All - Demo - joostp 7222f260253f325c21fcfa68b5bfab67 -1 us All - Demo - Kirben 732845548b1d6c2da572cb6a1bf81b07 -1 de All - Demo - Joachim Eberhard - e62056ba675ad65d8854ab3c5ad4b3c0 -1 en Windows - Mini Game - Trekky + e62056ba675ad65d8854ab3c5ad4b3c0 14689 en Windows - Mini Game - Trekky + 22c7432dc97a821fcfccd480e93e3911 14689 nl Windows - Mini Game - Ben Castricum + 6b10c9977cad9de503642059359792b1 14689 fr Windows - Mini Game - Ben Castricum + 9684c161258d68e0d464d6cab7024b9c 14689 it Windows - Mini Game - Ben Castricum + 7f2578d8d33a9ff525488a2d9ba617e4 14689 de Windows - Mini Game - Ben Castricum 22de86b2f7ec6e5db745ed1123310b44 15832 fr Windows - Demo - George Kormendi 204453e33456c4faa26e276229fe5b76 14689 de Windows - Demo - George Kormendi 19bf6938a94698296bcb0c99c31c91a7 -1 gb Windows - Demo - eriktorbjorn diff --git a/engines/cge2/configure.engine b/engines/cge2/configure.engine index 6ccbfee088..79d091fec5 100644 --- a/engines/cge2/configure.engine +++ b/engines/cge2/configure.engine @@ -1,3 +1,3 @@ # This file is included from the main "configure" script # add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] -add_engine cge2 "CGE2" no +add_engine cge2 "CGE2" yes diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h index 3f08f17aff..f72e552fa6 100644 --- a/engines/scumm/detection_tables.h +++ b/engines/scumm/detection_tables.h @@ -664,6 +664,7 @@ static const GameFilenamePattern gameFilenamesTable[] = { { "dog", "Springparadijs", kGenHEMac, Common::NL_NLD, Common::kPlatformMacintosh, 0 }, { "farm", "farm", kGenHEPC, UNK_LANG, UNK, 0 }, + { "farm", "farm", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 }, { "farm", "farmdemo", kGenHEPC, UNK_LANG, UNK, 0 }, { "farm", "Farm Demo", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 }, @@ -855,7 +856,7 @@ static const GameFilenamePattern gameFilenamesTable[] = { { "putttime", "PuttTijd", kGenHEMac, Common::NL_NLD, Common::kPlatformMacintosh, 0 }, { "putttime", "Putt Time", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 }, { "putttime", "PuttTTT", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 }, - { "putttime", "PuttTTT", kGenHEPC, UNK_LANG, UNK, 0 }, + { "putttime", "PuttTTT", kGenHEPC, UNK_LANG, Common::kPlatformWindows, 0 }, { "putttime", "TIJDDEMO", kGenHEPC, Common::NL_NLD, Common::kPlatformWindows, 0 }, { "putttime", "TijdDemo", kGenHEMac, Common::NL_NLD, Common::kPlatformMacintosh, 0 }, { "putttime", "timedemo", kGenHEPC, UNK_LANG, UNK, 0 }, @@ -917,7 +918,7 @@ static const GameFilenamePattern gameFilenamesTable[] = { { "spyfox", "JR-Demo", kGenHEMac, Common::FR_FRA, Common::kPlatformMacintosh, 0 }, { "spyfox", "game", kGenHEIOS, Common::EN_ANY, Common::kPlatformIOS, 0 }, - { "spyfox2", "spyfox2", kGenHEPC, UNK_LANG, UNK, 0 }, + { "spyfox2", "spyfox2", kGenHEPC, UNK_LANG, Common::kPlatformWindows, 0 }, { "spyfox2", "sf2-demo", kGenHEPC, UNK_LANG, UNK, 0 }, { "spyfox2", "sf2demo", kGenHEPC, UNK_LANG, Common::kPlatformWindows, 0 }, { "spyfox2", "Sf2demo", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 }, diff --git a/engines/scumm/room.cpp b/engines/scumm/room.cpp index 3828629997..4b59e22408 100644 --- a/engines/scumm/room.cpp +++ b/engines/scumm/room.cpp @@ -614,6 +614,15 @@ void ScummEngine_v3old::setupRoomSubBlocks() { } } else { _roomWidth = READ_LE_UINT16(&(rmhd->old.width)); + + // WORKAROUND: Fix bad width value for room 64 (book of maps) in + // Indy3. A specific version of this game (DOS/EGA v1.0, according to + // scumm-md5.txt) has a wrong width of 1793 stored in the data files, + // which causes a strange situation in which the book view may scroll + // towards the right depending on Indy's position from the previous room. + // Fixes bug #6679. + if (_game.id == GID_INDY3 && _roomResource == 64 && _roomWidth == 1793) + _roomWidth = 320; _roomHeight = READ_LE_UINT16(&(rmhd->old.height)); } _numObjectsInRoom = roomptr[20]; diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h index 878b2eeef3..4a34894506 100644 --- a/engines/scumm/scumm-md5.h +++ b/engines/scumm/scumm-md5.h @@ -1,5 +1,5 @@ /* - This file was generated by the md5table tool on Sat Nov 01 11:52:16 2014 + This file was generated by the md5table tool on Sat Nov 29 19:54:41 2014 DO NOT EDIT MANUALLY! */ @@ -20,7 +20,7 @@ static const MD5Table md5table[] = { { "0354ee0d14cde1264ec762261c04c14a", "loom", "Steam", "Steam", 585728, Common::EN_ANY, Common::kPlatformWindows }, { "035deab53b47bc43abc763560d0f8d4b", "atlantis", "Floppy", "Demo", -1, Common::EN_ANY, Common::kPlatformDOS }, { "037385a953789190298494d92b89b3d0", "catalog", "HE 72", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, - { "03d3b18ee3fd68114e2a687c871e38d5", "freddi4", "HE 99", "Mini Game", -1, Common::EN_USA, Common::kPlatformWindows }, + { "03d3b18ee3fd68114e2a687c871e38d5", "freddi4", "HE 99", "Mini Game", 13609, Common::EN_USA, Common::kPlatformWindows }, { "0425954a9db5c340861672892c3e678d", "samnmax", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "04401d747f1a2c1c4b388daff71ed378", "ft", "", "", 535405461, Common::DE_DEU, Common::kPlatformMacintosh }, { "04687cdf7f975a89d2474929f7b80946", "indy3", "FM-TOWNS", "", 7552, Common::EN_ANY, Common::kPlatformFMTowns }, @@ -37,10 +37,11 @@ static const MD5Table md5table[] = { { "08656dd9698ddf1023ba9bf8a195e37b", "monkey", "VGA", "VGA", -1, Common::EN_ANY, Common::kPlatformDOS }, { "08cc5c3eedaf72ebe12734eee94f7fa2", "balloon", "HE 80", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "09820417db26687bb7fe0c83cc4c553b", "ft", "", "Version A", 19697, Common::EN_ANY, Common::kPlatformUnknown }, + { "09b0be55c16cd9e88b5080bf89ff281d", "freddi4", "HE 99", "Mini Game", 13609, Common::DE_DEU, Common::kPlatformWindows }, { "0a212fa35fa8421f31c1f3961272caf0", "monkey", "VGA", "VGA", -1, Common::DE_DEU, Common::kPlatformAmiga }, { "0a295b80f9a9edf818e8e161a0e83830", "freddi2", "HE 80", "", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "0a41311d462b6639fc45297b9044bf16", "monkey", "No AdLib", "EGA", -1, Common::ES_ESP, Common::kPlatformAtariST }, - { "0a6d7b81b850ed4a77811c60c9b5c555", "PuttTime", "HE 99", "Mini Game", -1, Common::EN_USA, Common::kPlatformWindows }, + { "0a6d7b81b850ed4a77811c60c9b5c555", "PuttTime", "HE 99", "Mini Game", 18458, Common::EN_USA, Common::kPlatformWindows }, { "0aa050f4ad79402fbe9c4f78fb8ac494", "loom", "PC-Engine", "", 6532, Common::EN_ANY, Common::kPlatformPCEngine }, { "0ab19be9e2a3f6938226638b2a3744fe", "PuttTime", "HE 100", "Demo", -1, Common::EN_USA, Common::kPlatformUnknown }, { "0ac41e2e3d2174e5a042a6b565328dba", "puttrace", "HE 98", "Demo", 13110, Common::EN_USA, Common::kPlatformUnknown }, @@ -114,10 +115,12 @@ static const MD5Table md5table[] = { { "21abe302e1b1e2b66d6f5c12e241ebfd", "freddicove", "unenc", "Unencrypted", -1, Common::RU_RUS, Common::kPlatformWindows }, { "2232b0b9411575b1f9961713ebc9de61", "balloon", "HE 80", "", -1, Common::NL_NLD, Common::kPlatformWindows }, { "225e18566e810c634bf7de63e7568e3e", "mustard", "", "", -1, Common::EN_USA, Common::kPlatformUnknown }, + { "22c7432dc97a821fcfccd480e93e3911", "spyfox2", "", "Mini Game", 14689, Common::NL_NLD, Common::kPlatformWindows }, { "22c9eb04455440131ffc157aeb8d40a8", "fbear", "HE 70", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, { "22de86b2f7ec6e5db745ed1123310b44", "spyfox2", "", "Demo", 15832, Common::FR_FRA, Common::kPlatformWindows }, { "22f4ea88a09da12df9308ba30bcb7d0f", "loom", "EGA", "EGA", -1, Common::EN_ANY, Common::kPlatformDOS }, { "23394c8d29cc63c61313959431a12476", "spyfox", "HE 100", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows }, + { "24942a4200d99bdb4bdb78f9c7e07027", "pajama3", "", "Mini Game", 13911, Common::NL_NLD, Common::kPlatformWindows }, { "254fede2f15dbb32a23760d601b01816", "zak", "V1", "", -1, Common::EN_ANY, Common::kPlatformC64 }, { "2723fea3dae0cb47768c424b145ae0e7", "tentacle", "Floppy", "Floppy", 7932, Common::EN_ANY, Common::kPlatformDOS }, { "27b2ef1653089fe5b897d9cc89ce784f", "balloon", "HE 80", "", -1, Common::RU_RUS, Common::kPlatformWindows }, @@ -230,7 +233,7 @@ static const MD5Table md5table[] = { { "4f580a021eee026f3b4589e17d130d78", "freddi4", "", "", -1, Common::UNK_LANG, Common::kPlatformUnknown }, { "4fa6870d9bc8c313b65d54b1da5a1891", "pajama", "", "", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "4fbbe9f64b8bc547503a379a301183ce", "tentacle", "", "CD", -1, Common::IT_ITA, Common::kPlatformUnknown }, - { "4fe6a2e8df3c4536b278fdd2fbcb181e", "pajama3", "", "Mini Game", -1, Common::EN_ANY, Common::kPlatformWindows }, + { "4fe6a2e8df3c4536b278fdd2fbcb181e", "pajama3", "", "Mini Game", 13911, Common::EN_ANY, Common::kPlatformWindows }, { "5057fb0e99e5aa29df1836329232f101", "freddi2", "HE 80", "", -1, Common::UNK_LANG, Common::kPlatformWindows }, { "507bb360688dc4180fdf0d7597352a69", "freddi", "HE 73", "", 26402, Common::SE_SWE, Common::kPlatformWindows }, { "50b831f11b8c4b83784cf81f4dcc69ea", "spyfox", "HE 101", "", -1, Common::EN_ANY, Common::kPlatformWii }, @@ -302,6 +305,7 @@ static const MD5Table md5table[] = { { "6a60d395b78b205c93a956100b1bf5ae", "pajama2", "HE 98.5", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "6a8133b63d46f6663fbcbb49d5a2edb1", "atlantis", "Steam", "Steam", 520548, Common::EN_ANY, Common::kPlatformMacintosh }, { "6af2419fe3db5c2fdb091ae4e5833770", "puttrace", "HE 98.5", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, + { "6b10c9977cad9de503642059359792b1", "spyfox2", "", "Mini Game", 14689, Common::FR_FRA, Common::kPlatformWindows }, { "6b19d0e25cbf720d05822379b8b90ed9", "PuttTime", "HE 90", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "6b257bb2827dd894b8109a50a1a18b5a", "freddicove", "HE 100", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "6b27dbcd8d5697d5c918eeca0f68ef6a", "puttrace", "HE CUP", "Preview", 3901484, Common::UNK_LANG, Common::kPlatformUnknown }, @@ -311,7 +315,7 @@ static const MD5Table md5table[] = { { "6bf70eee5de3d24d2403e0dd3d267e8a", "spyfox", "", "", 49221, Common::UNK_LANG, Common::kPlatformWindows }, { "6c2bff0e327f2962e809c2e1a82d7309", "monkey", "VGA", "VGA", -1, Common::EN_ANY, Common::kPlatformAmiga }, { "6c375c2236d99f56e6c2cf540e74e474", "farm", "", "Demo", 34333, Common::NL_NLD, Common::kPlatformWindows }, - { "6d1baa1065ac5f7b210be8ebe4235e49", "freddi", "HE 73", "", -1, Common::NL_NLD, Common::kPlatformMacintosh }, + { "6d1baa1065ac5f7b210be8ebe4235e49", "freddi", "HE 73", "", 26384, Common::NL_NLD, Common::kPlatformMacintosh }, { "6dead580b0ff14d5f7b33b4219f04159", "samnmax", "", "Demo", 16556335, Common::EN_ANY, Common::kPlatformMacintosh }, { "6df20c50c1ab19799de9be7ae7716881", "fbear", "HE 62", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "6e959d65358eedf9b68b81e304b97fa4", "tentacle", "", "CD", 7932, Common::DE_DEU, Common::kPlatformUnknown }, @@ -325,7 +329,7 @@ static const MD5Table md5table[] = { { "70b0719ac3a5b47ae233c561823d5b96", "puttzoo", "", "", -1, Common::NL_NLD, Common::kPlatformMacintosh }, { "71523b539491527d9860f4407faf0411", "monkey", "Demo", "EGA Demo", 7607, Common::EN_ANY, Common::kPlatformDOS }, { "71d384e7676c53d513ddd333eae1d82c", "Blues123time", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, - { "71fe97c3108678cf604f14abe342341b", "spyfox2", "", "", -1, Common::NL_NLD, Common::kPlatformWindows }, + { "71fe97c3108678cf604f14abe342341b", "spyfox2", "", "", 51286, Common::NL_NLD, Common::kPlatformUnknown }, { "7222f260253f325c21fcfa68b5bfab67", "spyfox2", "", "Demo", -1, Common::EN_USA, Common::kPlatformUnknown }, { "72ac6bc980d5101c2142189d746bd62f", "spyfox", "HE 99", "", -1, Common::RU_RUS, Common::kPlatformWindows }, { "732845548b1d6c2da572cb6a1bf81b07", "spyfox2", "", "Demo", -1, Common::DE_DEU, Common::kPlatformUnknown }, @@ -349,6 +353,7 @@ static const MD5Table md5table[] = { { "78c07ca088526d8d4446a4c2cb501203", "freddi3", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "7974365d3dc0f43a2748c975f91ff042", "monkey2", "", "", -1, Common::ES_ESP, Common::kPlatformDOS }, { "79b05f628586837e7166e82b2279bb50", "loom", "PC-Engine", "", -1, Common::JA_JPN, Common::kPlatformPCEngine }, + { "7a2b6d8e8a645c9d534c8c4edc38a9c9", "freddi4", "HE 99", "Mini Game", 13609, Common::IT_ITA, Common::kPlatformWindows }, { "7b4ee071eecadc2d8cd0c3509110825c", "puttzoo", "HE 100", "Remastered", -1, Common::EN_ANY, Common::kPlatformWindows }, { "7bad72e332a59f9fcc1d437f4edad32a", "puttcircus", "", "", -1, Common::RU_RUS, Common::kPlatformUnknown }, { "7c2e76087027eeee9c8f8985f93a1cc5", "freddi4", "", "Demo", 13584, Common::EN_ANY, Common::kPlatformUnknown }, @@ -358,6 +363,7 @@ static const MD5Table md5table[] = { { "7e151c17adf624f1966c8fc5827c95e9", "puttputt", "HE 61", "", -1, Common::EN_ANY, Common::kPlatform3DO }, { "7ea2da67ebabea4ac20cee9f4f9d2934", "airport", "", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "7edd665bbede7ea8b7233f8e650be6f8", "samnmax", "", "CD", -1, Common::FR_FRA, Common::kPlatformUnknown }, + { "7f2578d8d33a9ff525488a2d9ba617e4", "spyfox2", "", "Mini Game", 14689, Common::DE_DEU, Common::kPlatformWindows }, { "7f45ddd6dbfbf8f80c0c0efea4c295bc", "maniac", "V1", "V1", 1972, Common::EN_ANY, Common::kPlatformDOS }, { "7f945525abcd48015adf1632637a44a1", "pajama", "", "Demo", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "7fbcff27c323499beaedd605e1ebd47d", "indy3", "Steam", "Steam", 561152, Common::EN_ANY, Common::kPlatformWindows }, @@ -390,6 +396,7 @@ static const MD5Table md5table[] = { { "8afb3cf9f95abf208358e984f0c9e738", "funpack", "", "", -1, Common::EN_ANY, Common::kPlatform3DO }, { "8bdb0bf87b5e303dd35693afb9351215", "ft", "", "", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "8d479e36f35e80257dfc102cf4b8a912", "farm", "HE 72", "Demo", 34333, Common::EN_ANY, Common::kPlatformWindows }, + { "8dd4d590685c19bf651b5016e749ead2", "PuttTime", "HE 99", "Mini Game", 18458, Common::FR_FRA, Common::kPlatformWindows }, { "8de13897f0121c79d29a2377159f9ad0", "socks", "HE 99", "Updated", -1, Common::EN_ANY, Common::kPlatformWindows }, { "8e3241ddd6c8dadf64305e8740d45e13", "balloon", "HE 100", "Updated", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "8e4ee4db46954bfe2912e259a16fad82", "monkey2", "", "", -1, Common::FR_FRA, Common::kPlatformDOS }, @@ -411,11 +418,13 @@ static const MD5Table md5table[] = { { "92b078d9d6d9d751da9c26b8b3075779", "tentacle", "Floppy", "Floppy", -1, Common::FR_FRA, Common::kPlatformDOS }, { "92e7727e67f5cd979d8a1070e4eb8cb3", "puttzoo", "HE 98.5", "Updated", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "92fc0073a4cf259ff36070ecb8628ba8", "thinkerk", "", "", -1, Common::EN_USA, Common::kPlatformUnknown }, + { "9340b552b0f2dffe6d4f3d13ebebe832", "freddi4", "HE 99", "Mini Game", 13609, Common::NL_NLD, Common::kPlatformWindows }, { "94aaedbb8f26d71ed3ad6dd34490e29e", "tentacle", "Floppy", "Floppy", -1, Common::FR_FRA, Common::kPlatformDOS }, { "94db6519da85b8d08c976d8e9a858ea7", "baseball", "HE CUP", "Preview", 10044774, Common::UNK_LANG, Common::kPlatformUnknown }, { "95818b178d473c989ac753574e8892aa", "readtime", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "95b3806e043be08668c54c3ffe98650f", "BluesABCTime", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "95be99181bd0f10fef4872c2d4a771cb", "zak", "V1", "", -1, Common::DE_DEU, Common::kPlatformC64 }, + { "9684c161258d68e0d464d6cab7024b9c", "spyfox2", "", "Mini Game", 14689, Common::IT_ITA, Common::kPlatformWindows }, { "96a3069a3c63caa7329588ce1fef41ee", "spyozon", "", "", -1, Common::RU_RUS, Common::kPlatformUnknown }, { "9708cf716ed8bcc9ff3fcfc69413b746", "puttputt", "HE 62", "", -1, Common::EN_ANY, Common::kPlatformDOS }, { "9778341eefc6feb447ca07e7be21791c", "puttrace", "HE 99", "Demo", -1, Common::IT_ITA, Common::kPlatformWindows }, @@ -461,9 +470,11 @@ static const MD5Table md5table[] = { { "a59a438cb182124c30c4447d8ed469e9", "freddi", "HE 100", "", 34837, Common::NB_NOR, Common::kPlatformWii }, { "a5c5388da9bf0e6662fdca8813a79d13", "farm", "", "", 86962, Common::EN_ANY, Common::kPlatformWindows }, { "a654fb60c3b67d6317a7894ffd9f25c5", "pajama3", "", "Demo", -1, Common::EN_USA, Common::kPlatformUnknown }, + { "a71014c53a6d18c66ef2ea0ee42328e9", "PuttTime", "HE 99", "Mini Game", 18458, Common::NL_NLD, Common::kPlatformWindows }, { "a7cacad9c40c4dc9e1812abf6c8af9d5", "puttcircus", "", "Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "a85856675429fe88051744f755b72f93", "farm", "", "", -1, Common::EN_ANY, Common::kPlatformWindows }, { "a86f9c49355579c30d4a55b477c0d869", "baseball2001", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, + { "a8fcc3084ad5e3e569722755f205b1ef", "pajama3", "", "Mini Game", 13911, Common::DE_DEU, Common::kPlatformWindows }, { "a9543ef0d79bcb47cd76ec197ad0a967", "puttmoon", "", "", -1, Common::EN_ANY, Common::kPlatform3DO }, { "a99c39ba65b6086be28aef576da69595", "spyozon", "", "Demo", -1, Common::FR_FRA, Common::kPlatformWindows }, { "a9f2f04b1ecaab9495b59befffe9bf88", "pajama3", "", "Demo", -1, Common::EN_USA, Common::kPlatformUnknown }, @@ -480,6 +491,7 @@ static const MD5Table md5table[] = { { "acad97ab1c6fc2a5b2d98abf6db4a190", "tentacle", "Floppy", "Floppy", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "ae94f110a14ce71fc515d5b648827a8f", "tentacle", "Floppy", "Floppy", -1, Common::ES_ESP, Common::kPlatformDOS }, { "aeec382acef62e122bf0d5b14581cfa4", "zak", "V1", "", -1, Common::IT_ITA, Common::kPlatformC64 }, + { "aef415cc5dc063e3668359c2657169f3", "PuttTime", "HE 99", "Mini Game", 18458, Common::DE_DEU, Common::kPlatformWindows }, { "aefa244ea034b7cd2041f0a44be7d9ba", "pajama3", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh }, { "af2bd1a43b50b55915d87994e093203d", "freddi", "HE 99", "Updated", 34829, Common::DE_DEU, Common::kPlatformWindows }, { "b100abf7ff83146df50db78dbd5e9cfa", "freddicove", "HE 100", "", -1, Common::FR_FRA, Common::kPlatformUnknown }, @@ -507,7 +519,7 @@ static const MD5Table md5table[] = { { "be83e882b44f2767bc08d4f766ebc347", "maniac", "V2", "V2", -1, Common::DE_DEU, Common::kPlatformAtariST }, { "bf8b52fdd9a69c67f34e8e9fec72661c", "farm", "HE 71", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, { "bfdf584b01503f0762baded581f6a0a2", "SoccerMLS", "", "", -1, Common::EN_ANY, Common::kPlatformWindows }, - { "c0039ad982999c92d0de81910d640fa0", "freddi", "HE 71", "", -1, Common::NL_NLD, Common::kPlatformWindows }, + { "c0039ad982999c92d0de81910d640fa0", "freddi", "HE 71", "", 26159, Common::NL_NLD, Common::kPlatformWindows }, { "c13225cb1bbd3bc9fe578301696d8021", "monkey", "SEGA", "", -1, Common::EN_ANY, Common::kPlatformSegaCD }, { "c20848f53c2d48bfacdc840993843765", "freddi2", "HE 80", "Demo", -1, Common::NL_NLD, Common::kPlatformUnknown }, { "c225bec1b6c0798a2b8c89ac226dc793", "pajama", "HE 101", "", -1, Common::EN_ANY, Common::kPlatformWii }, @@ -518,6 +530,7 @@ static const MD5Table md5table[] = { { "c3b22fa4654bb580b20325ebf4174841", "puttzoo", "", "", -1, Common::NL_NLD, Common::kPlatformWindows }, { "c3df37df9d3b481b45f75283a9907c47", "loom", "EGA", "EGA", -1, Common::IT_ITA, Common::kPlatformDOS }, { "c4787c3e8b5e2dfda90850ee800af00f", "zak", "V2", "V2", -1, Common::FR_FRA, Common::kPlatformDOS }, + { "c486e4cfa7bd6f8efcd0740f96f7dde3", "freddi4", "HE 99", "Mini Game", 13609, Common::FR_FRA, Common::kPlatformWindows }, { "c4ffae9fac495475d6bc3343ccc8faf9", "Soccer2004", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "c5cc7cba02a2fbd539c4439e775b0536", "puttzoo", "HE 99", "Updated", 43470, Common::DE_DEU, Common::kPlatformWindows }, { "c5d10e190d4b4d59114b824f2fdbd00e", "loom", "FM-TOWNS", "", 7540, Common::EN_ANY, Common::kPlatformFMTowns }, @@ -557,6 +570,7 @@ static const MD5Table md5table[] = { { "d06fbe28818fef7bfc45c2cdf0c0849d", "zak", "V2", "V2", -1, Common::DE_DEU, Common::kPlatformDOS }, { "d0ad929def3e9cfe39dea55bd12098d4", "puttcircus", "", "", -1, Common::FR_FRA, Common::kPlatformWindows }, { "d0b531227a27c6662018d2bd05aac52a", "monkey", "VGA", "VGA", 8357, Common::DE_DEU, Common::kPlatformDOS }, + { "d1a73e87564477c7c2dcc2b8f616ad0b", "pajama3", "", "Mini Game", 13911, Common::IT_ITA, Common::kPlatformWindows }, { "d220d154aafbfa12bd6f3ab1b2dae420", "puttzoo", "", "Demo", -1, Common::DE_DEU, Common::kPlatformMacintosh }, { "d2cc8e31bce61e6cf2951249e10638fe", "basketball", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, { "d37c55388294b66e53e7ced3af88fa68", "freddi2", "HE 100", "Updated Demo", -1, Common::EN_ANY, Common::kPlatformUnknown }, @@ -604,7 +618,7 @@ static const MD5Table md5table[] = { { "e534d29afb3c6e0ee9dc3d53c5956714", "atlantis", "Floppy", "Floppy", -1, Common::DE_DEU, Common::kPlatformAmiga }, { "e5563c8358443c4352fcddf7402a5e0a", "pajama2", "HE 98.5", "", -1, Common::FR_FRA, Common::kPlatformWindows }, { "e5c112140ad6574997de033a8e2a2964", "readtime", "", "", -1, Common::EN_ANY, Common::kPlatformUnknown }, - { "e62056ba675ad65d8854ab3c5ad4b3c0", "spyfox2", "", "Mini Game", -1, Common::EN_ANY, Common::kPlatformWindows }, + { "e62056ba675ad65d8854ab3c5ad4b3c0", "spyfox2", "", "Mini Game", 14689, Common::EN_ANY, Common::kPlatformWindows }, { "e63a0b9249b5ca4cc4d3ac34305ae360", "freddi", "HE 99", "", -1, Common::NB_NOR, Common::kPlatformWindows }, { "e689bdf67f98b1d760ce4487ec0e8d06", "indy3", "EGA", "EGA", -1, Common::FR_FRA, Common::kPlatformAmiga }, { "e6cd81b25ab1453a8a6d3482118c391e", "pass", "", "", 7857, Common::EN_ANY, Common::kPlatformDOS }, @@ -626,7 +640,9 @@ static const MD5Table md5table[] = { { "edfdb24a499d92c59f824c52987c0eec", "atlantis", "Floppy", "Floppy", -1, Common::FR_FRA, Common::kPlatformDOS }, { "ee41f6afbc5b26fa475754b56fe92048", "puttputt", "HE 61", "", 8032, Common::JA_JPN, Common::kPlatform3DO }, { "ee785fe2569bc9965526e774f7ab86f1", "spyfox", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformMacintosh }, + { "ee8cfeb76e55d43a01c25e0865a9db76", "puttrace", "HE 98", "Demo", 13135, Common::NL_NLD, Common::kPlatformMacintosh }, { "eea4d9ac2fb6f145945a308e8866915b", "maniac", "C64", "", -1, Common::EN_ANY, Common::kPlatformC64 }, + { "eeb606c2d2ec877a712a9f20c10bcdda", "farm", "", "", 87034, Common::NL_NLD, Common::kPlatformMacintosh }, { "ef347474f3c7be3b29584eaa133cca05", "samnmax", "Floppy", "Floppy", -1, Common::FR_FRA, Common::kPlatformDOS }, { "ef71a322b6530ac45b1a070f7c0795f7", "moonbase", "Demo", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows }, { "ef74d9071d4e564b037cb44bd6774de7", "fbear", "HE 62", "", -1, Common::HE_ISR, Common::kPlatformDOS }, @@ -651,6 +667,7 @@ static const MD5Table md5table[] = { { "fa30c4a7a806629626269b6dcab59a15", "BluesBirthday", "HE CUP", "Preview", 7819264, Common::UNK_LANG, Common::kPlatformUnknown }, { "fa3cb1541f9d7cf99ccbae6249bc150c", "maniac", "NES", "", -1, Common::IT_ITA, Common::kPlatformNES }, { "fa84cb1018103a4ee4e5fa8041c1d0d1", "freddi4", "", "Demo", 13609, Common::DE_DEU, Common::kPlatformWindows }, + { "faa89ab5e67ba4eebb4399f584f7490c", "pajama3", "", "Mini Game", 13911, Common::FR_FRA, Common::kPlatformWindows }, { "fb66aa42de21675116346213f176a366", "monkey", "VGA", "VGA", -1, Common::IT_ITA, Common::kPlatformAmiga }, { "fbb697d89d2beca87360a145f467bdae", "PuttTime", "HE 90", "Demo", -1, Common::DE_DEU, Common::kPlatformUnknown }, { "fbbbb38a81fc9d6a61d509278390a290", "farm", "", "", -1, Common::EN_ANY, Common::kPlatformMacintosh }, diff --git a/engines/zvision/animation/meta_animation.cpp b/engines/zvision/animation/meta_animation.cpp new file mode 100644 index 0000000000..857a0dd688 --- /dev/null +++ b/engines/zvision/animation/meta_animation.cpp @@ -0,0 +1,132 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/animation/meta_animation.h" + +#include "zvision/zvision.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/animation/rlf_animation.h" +#include "zvision/video/zork_avi_decoder.h" + +#include "video/video_decoder.h" + +#include "graphics/surface.h" + +namespace ZVision { + +MetaAnimation::MetaAnimation(const Common::String &fileName, ZVision *engine) + : _fileType(RLF), + _curFrame(NULL) { + Common::String tmpFileName = fileName; + tmpFileName.toLowercase(); + if (tmpFileName.hasSuffix(".rlf")) { + _fileType = RLF; + Common::File *_file = engine->getSearchManager()->openFile(tmpFileName); + _animation.rlf = new RlfAnimation(_file, false); + _frmDelay = _animation.rlf->frameTime(); + } else if (tmpFileName.hasSuffix(".avi")) { + _fileType = AVI; + Common::File *_file = engine->getSearchManager()->openFile(tmpFileName); + _animation.avi = new ZorkAVIDecoder(); + _animation.avi->loadStream(_file); + _frmDelay = 1000.0 / _animation.avi->getDuration().framerate(); + } else { + warning("Unrecognized animation file type: %s", fileName.c_str()); + } +} + +MetaAnimation::~MetaAnimation() { + if (_fileType == RLF) { + delete _animation.rlf; + } else if (_fileType == AVI) { + delete _animation.avi; + } +} + +uint MetaAnimation::frameCount() { + if (_fileType == RLF) { + return _animation.rlf->frameCount(); + } else + return _animation.avi->getFrameCount(); + +} + +uint MetaAnimation::width() { + if (_fileType == RLF) { + return _animation.rlf->width(); + } else + return _animation.avi->getWidth(); +} +uint MetaAnimation::height() { + if (_fileType == RLF) { + return _animation.rlf->height(); + } else + return _animation.avi->getHeight(); +} +uint32 MetaAnimation::frameTime() { + return _frmDelay; +} + +void MetaAnimation::seekToFrame(int frameNumber) { + if (frameNumber >= (int)frameCount()) + frameNumber = frameCount() - 1; + + if (_fileType == RLF) { + _animation.rlf->seekToFrame(frameNumber); + } else + _animation.avi->seekToFrame(frameNumber); +} + +const Graphics::Surface *MetaAnimation::decodeNextFrame() { + if (_fileType == RLF) + _curFrame = _animation.rlf->decodeNextFrame(); + else + _curFrame = _animation.avi->decodeNextFrame(); + + return _curFrame; +} + +const Graphics::Surface *MetaAnimation::getFrameData(uint frameNumber) { + if (frameNumber >= frameCount()) + frameNumber = frameCount() - 1; + + if (_fileType == RLF) { + _curFrame = _animation.rlf->getFrameData(frameNumber); + return _curFrame; + } else { + _animation.avi->seekToFrame(frameNumber); + _curFrame = _animation.avi->decodeNextFrame(); + return _curFrame; + } +} + +bool MetaAnimation::endOfAnimation() { + if (_fileType == RLF) { + return _animation.rlf->endOfAnimation(); + } else + return _animation.avi->endOfVideo(); +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/animation_control.h b/engines/zvision/animation/meta_animation.h index bdb07d39ea..93b69587c4 100644 --- a/engines/zvision/scripting/controls/animation_control.h +++ b/engines/zvision/animation/meta_animation.h @@ -8,23 +8,25 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ -#ifndef ZVISION_ANIMATION_CONTROL_H -#define ZVISION_ANIMATION_CONTROL_H - -#include "zvision/scripting/control.h" +#ifndef ZVISION_METAANIM_NODE_H +#define ZVISION_METAANIM_NODE_H +#include "zvision/scripting/sidefx.h" +#include "zvision/zvision.h" +#include "common/rect.h" +#include "common/list.h" namespace Common { class String; @@ -43,10 +45,21 @@ namespace ZVision { class ZVision; class RlfAnimation; -class AnimationControl : public Control { +class MetaAnimation { public: - AnimationControl(ZVision *engine, uint32 controlKey, const Common::String &fileName); - ~AnimationControl(); + MetaAnimation(const Common::String &fileName, ZVision *engine); + ~MetaAnimation(); + + struct playnode { + Common::Rect pos; + int32 slot; + int32 start; + int32 stop; + int32 loop; + int32 _curFrame; + int32 _delay; + Graphics::Surface *_scaled; + }; private: enum FileType { @@ -55,31 +68,29 @@ private: }; private: - uint32 _animationKey; - union { RlfAnimation *rlf; Video::VideoDecoder *avi; } _animation; FileType _fileType; - uint _loopCount; - int32 _x; - int32 _y; - - uint _accumulatedTime; - uint _currentLoop; + int32 _frmDelay; - Graphics::Surface *_cachedFrame; - bool _cachedFrameNeedsDeletion; + const Graphics::Surface *_curFrame; public: - bool process(uint32 deltaTimeInMillis); - void setAnimationKey(uint32 animationKey) { _animationKey = animationKey; } - void setLoopCount(uint loopCount) { _loopCount = loopCount; } - void setXPos(int32 x) { _x = x; } - void setYPost(int32 y) { _y = y; } + uint frameCount(); + uint width(); + uint height(); + uint32 frameTime(); + + void seekToFrame(int frameNumber); + + const Graphics::Surface *decodeNextFrame(); + const Graphics::Surface *getFrameData(uint frameNumber); + + bool endOfAnimation(); }; } // End of namespace ZVision diff --git a/engines/zvision/animation/rlf_animation.cpp b/engines/zvision/animation/rlf_animation.cpp index 945461e7b2..d9b8fa3894 100644 --- a/engines/zvision/animation/rlf_animation.cpp +++ b/engines/zvision/animation/rlf_animation.cpp @@ -1,24 +1,24 @@ /* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ #include "common/scummsys.h" @@ -32,24 +32,28 @@ #include "graphics/colormasks.h" - namespace ZVision { RlfAnimation::RlfAnimation(const Common::String &fileName, bool stream) - : _stream(stream), - _lastFrameRead(0), - _frameCount(0), - _width(0), - _height(0), - _frameTime(0), - _frames(0), - _currentFrame(-1), - _frameBufferByteSize(0) { - if (!_file.open(fileName)) { + : _stream(stream), + _readStream(NULL), + _lastFrameRead(0), + _frameCount(0), + _width(0), + _height(0), + _frameTime(0), + _frames(0), + _nextFrame(0), + _frameBufferByteSize(0) { + + Common::File *_file = new Common::File; + if (!_file->open(fileName)) { warning("RLF animation file %s could not be opened", fileName.c_str()); return; } + _readStream = _file; + if (!readHeader()) { warning("%s is not a RLF animation file. Wrong magic number", fileName.c_str()); return; @@ -68,59 +72,90 @@ RlfAnimation::RlfAnimation(const Common::String &fileName, bool stream) } } +RlfAnimation::RlfAnimation(Common::SeekableReadStream *rstream, bool stream) + : _stream(stream), + _readStream(rstream), + _lastFrameRead(0), + _frameCount(0), + _width(0), + _height(0), + _frameTime(0), + _frames(0), + _nextFrame(0), + _frameBufferByteSize(0) { + + if (!readHeader()) { + warning("Stream is not a RLF animation. Wrong magic number"); + return; + } + + _currentFrameBuffer.create(_width, _height, Graphics::createPixelFormat<565>()); + _frameBufferByteSize = _width * _height * sizeof(uint16); + + if (!stream) { + _frames = new Frame[_frameCount]; + + // Read in each frame + for (uint i = 0; i < _frameCount; ++i) { + _frames[i] = readNextFrame(); + } + } +} + RlfAnimation::~RlfAnimation() { for (uint i = 0; i < _frameCount; ++i) { delete[] _frames[i].encodedData; } delete[] _frames; + delete _readStream; _currentFrameBuffer.free(); } bool RlfAnimation::readHeader() { - if (_file.readUint32BE() != MKTAG('F', 'E', 'L', 'R')) { + if (_readStream->readUint32BE() != MKTAG('F', 'E', 'L', 'R')) { return false; } // Read the header - _file.readUint32LE(); // Size1 - _file.readUint32LE(); // Unknown1 - _file.readUint32LE(); // Unknown2 - _frameCount = _file.readUint32LE(); // Frame count + _readStream->readUint32LE(); // Size1 + _readStream->readUint32LE(); // Unknown1 + _readStream->readUint32LE(); // Unknown2 + _frameCount = _readStream->readUint32LE(); // Frame count // Since we don't need any of the data, we can just seek right to the // entries we need rather than read in all the individual entries. - _file.seek(136, SEEK_CUR); + _readStream->seek(136, SEEK_CUR); //// Read CIN header - //_file.readUint32BE(); // Magic number FNIC - //_file.readUint32LE(); // Size2 - //_file.readUint32LE(); // Unknown3 - //_file.readUint32LE(); // Unknown4 - //_file.readUint32LE(); // Unknown5 - //_file.seek(0x18, SEEK_CUR); // VRLE - //_file.readUint32LE(); // LRVD - //_file.readUint32LE(); // Unknown6 - //_file.seek(0x18, SEEK_CUR); // HRLE - //_file.readUint32LE(); // ELHD - //_file.readUint32LE(); // Unknown7 - //_file.seek(0x18, SEEK_CUR); // HKEY - //_file.readUint32LE(); // ELRH + //_readStream->readUint32BE(); // Magic number FNIC + //_readStream->readUint32LE(); // Size2 + //_readStream->readUint32LE(); // Unknown3 + //_readStream->readUint32LE(); // Unknown4 + //_readStream->readUint32LE(); // Unknown5 + //_readStream->seek(0x18, SEEK_CUR); // VRLE + //_readStream->readUint32LE(); // LRVD + //_readStream->readUint32LE(); // Unknown6 + //_readStream->seek(0x18, SEEK_CUR); // HRLE + //_readStream->readUint32LE(); // ELHD + //_readStream->readUint32LE(); // Unknown7 + //_readStream->seek(0x18, SEEK_CUR); // HKEY + //_readStream->readUint32LE(); // ELRH //// Read MIN info header - //_file.readUint32BE(); // Magic number FNIM - //_file.readUint32LE(); // Size3 - //_file.readUint32LE(); // OEDV - //_file.readUint32LE(); // Unknown8 - //_file.readUint32LE(); // Unknown9 - //_file.readUint32LE(); // Unknown10 - _width = _file.readUint32LE(); // Width - _height = _file.readUint32LE(); // Height + //_readStream->readUint32BE(); // Magic number FNIM + //_readStream->readUint32LE(); // Size3 + //_readStream->readUint32LE(); // OEDV + //_readStream->readUint32LE(); // Unknown8 + //_readStream->readUint32LE(); // Unknown9 + //_readStream->readUint32LE(); // Unknown10 + _width = _readStream->readUint32LE(); // Width + _height = _readStream->readUint32LE(); // Height // Read time header - _file.readUint32BE(); // Magic number EMIT - _file.readUint32LE(); // Size4 - _file.readUint32LE(); // Unknown11 - _frameTime = _file.readUint32LE() / 10; // Frame time in microseconds + _readStream->readUint32BE(); // Magic number EMIT + _readStream->readUint32LE(); // Size4 + _readStream->readUint32LE(); // Unknown11 + _frameTime = _readStream->readUint32LE() / 10; // Frame time in microseconds return true; } @@ -128,17 +163,17 @@ bool RlfAnimation::readHeader() { RlfAnimation::Frame RlfAnimation::readNextFrame() { RlfAnimation::Frame frame; - _file.readUint32BE(); // Magic number MARF - uint32 size = _file.readUint32LE(); // Size - _file.readUint32LE(); // Unknown1 - _file.readUint32LE(); // Unknown2 - uint32 type = _file.readUint32BE(); // Either ELHD or ELRH - uint32 headerSize = _file.readUint32LE(); // Offset from the beginning of this frame to the frame data. Should always be 28 - _file.readUint32LE(); // Unknown3 + _readStream->readUint32BE(); // Magic number MARF + uint32 size = _readStream->readUint32LE(); // Size + _readStream->readUint32LE(); // Unknown1 + _readStream->readUint32LE(); // Unknown2 + uint32 type = _readStream->readUint32BE(); // Either ELHD or ELRH + uint32 headerSize = _readStream->readUint32LE(); // Offset from the beginning of this frame to the frame data. Should always be 28 + _readStream->readUint32LE(); // Unknown3 frame.encodedSize = size - headerSize; frame.encodedData = new int8[frame.encodedSize]; - _file.read(frame.encodedData, frame.encodedSize); + _readStream->read(frame.encodedData, frame.encodedSize); if (type == MKTAG('E', 'L', 'H', 'D')) { frame.type = Masked; @@ -157,26 +192,40 @@ void RlfAnimation::seekToFrame(int frameNumber) { assert(!_stream); assert(frameNumber < (int)_frameCount || frameNumber >= -1); - if (frameNumber == -1) { - _currentFrame = -1; + if (_nextFrame == frameNumber) + return; + + if (frameNumber < 0) { + _nextFrame = 0; return; } - int closestFrame = _currentFrame; - int distance = (int)frameNumber - _currentFrame; - for (uint i = 0; i < _completeFrames.size(); ++i) { - int newDistance = (int)frameNumber - (int)(_completeFrames[i]); - if (newDistance > 0 && (closestFrame == -1 || newDistance < distance)) { + int closestFrame = _nextFrame; + int distance = (int)frameNumber - _nextFrame; + + if (distance < 0) { + for (uint i = 0; i < _completeFrames.size(); ++i) { + if ((int)_completeFrames[i] > frameNumber) + break; closestFrame = _completeFrames[i]; - distance = newDistance; + } + } else { + for (uint i = 0; i < _completeFrames.size(); ++i) { + int newDistance = (int)frameNumber - (int)(_completeFrames[i]); + if (newDistance < 0) + break; + if (newDistance < distance) { + closestFrame = _completeFrames[i]; + distance = newDistance; + } } } - for (int i = closestFrame; i <= frameNumber; ++i) { + for (int i = closestFrame; i < frameNumber; ++i) { applyFrameToCurrent(i); } - _currentFrame = frameNumber; + _nextFrame = frameNumber; } const Graphics::Surface *RlfAnimation::getFrameData(uint frameNumber) { @@ -184,27 +233,27 @@ const Graphics::Surface *RlfAnimation::getFrameData(uint frameNumber) { assert(frameNumber < _frameCount); // Since this method is so expensive, first check to see if we can use - // getNextFrame() it's cheap. - if ((int)frameNumber == _currentFrame) { + // decodeNextFrame() it's cheap. + if ((int)frameNumber == _nextFrame - 1) { return &_currentFrameBuffer; - } else if (_currentFrame + 1 == (int)frameNumber) { - return getNextFrame(); + } else if (_nextFrame == (int)frameNumber) { + return decodeNextFrame(); } seekToFrame(frameNumber); - return &_currentFrameBuffer; + return decodeNextFrame(); } -const Graphics::Surface *RlfAnimation::getNextFrame() { - assert(_currentFrame + 1 < (int)_frameCount); +const Graphics::Surface *RlfAnimation::decodeNextFrame() { + assert(_nextFrame < (int)_frameCount); if (_stream) { applyFrameToCurrent(readNextFrame()); } else { - applyFrameToCurrent(_currentFrame + 1); + applyFrameToCurrent(_nextFrame); } - _currentFrame++; + _nextFrame++; return &_currentFrameBuffer; } @@ -227,6 +276,7 @@ void RlfAnimation::applyFrameToCurrent(const RlfAnimation::Frame &frame) { void RlfAnimation::decodeMaskedRunLengthEncoding(int8 *source, int8 *dest, uint32 sourceSize, uint32 destSize) const { uint32 sourceOffset = 0; uint32 destOffset = 0; + int16 numberOfCopy = 0; while (sourceOffset < sourceSize) { int8 numberOfSamples = source[sourceOffset]; @@ -235,9 +285,9 @@ void RlfAnimation::decodeMaskedRunLengthEncoding(int8 *source, int8 *dest, uint3 // If numberOfSamples is negative, the next abs(numberOfSamples) samples should // be copied directly from source to dest if (numberOfSamples < 0) { - numberOfSamples = ABS(numberOfSamples); + numberOfCopy = -numberOfSamples; - while (numberOfSamples > 0) { + while (numberOfCopy > 0) { if (sourceOffset + 1 >= sourceSize) { return; } else if (destOffset + 1 >= destSize) { @@ -252,11 +302,11 @@ void RlfAnimation::decodeMaskedRunLengthEncoding(int8 *source, int8 *dest, uint3 sourceOffset += 2; destOffset += 2; - numberOfSamples--; + numberOfCopy--; } - // If numberOfSamples is >= 0, move destOffset forward ((numberOfSamples * 2) + 2) - // This function assumes the dest buffer has been memset with 0's. + // If numberOfSamples is >= 0, move destOffset forward ((numberOfSamples * 2) + 2) + // This function assumes the dest buffer has been memset with 0's. } else { if (sourceOffset + 1 >= sourceSize) { return; @@ -273,6 +323,7 @@ void RlfAnimation::decodeMaskedRunLengthEncoding(int8 *source, int8 *dest, uint3 void RlfAnimation::decodeSimpleRunLengthEncoding(int8 *source, int8 *dest, uint32 sourceSize, uint32 destSize) const { uint32 sourceOffset = 0; uint32 destOffset = 0; + int16 numberOfCopy = 0; while (sourceOffset < sourceSize) { int8 numberOfSamples = source[sourceOffset]; @@ -281,9 +332,9 @@ void RlfAnimation::decodeSimpleRunLengthEncoding(int8 *source, int8 *dest, uint3 // If numberOfSamples is negative, the next abs(numberOfSamples) samples should // be copied directly from source to dest if (numberOfSamples < 0) { - numberOfSamples = ABS(numberOfSamples); + numberOfCopy = -numberOfSamples; - while (numberOfSamples > 0) { + while (numberOfCopy > 0) { if (sourceOffset + 1 >= sourceSize) { return; } else if (destOffset + 1 >= destSize) { @@ -298,11 +349,11 @@ void RlfAnimation::decodeSimpleRunLengthEncoding(int8 *source, int8 *dest, uint3 sourceOffset += 2; destOffset += 2; - numberOfSamples--; + numberOfCopy--; } - // If numberOfSamples is >= 0, copy one sample from source to the - // next (numberOfSamples + 2) dest spots + // If numberOfSamples is >= 0, copy one sample from source to the + // next (numberOfSamples + 2) dest spots } else { if (sourceOffset + 1 >= sourceSize) { return; @@ -313,8 +364,8 @@ void RlfAnimation::decodeSimpleRunLengthEncoding(int8 *source, int8 *dest, uint3 uint16 sampleColor = Graphics::RGBToColor<Graphics::ColorMasks<565> >(r, g, b); sourceOffset += 2; - numberOfSamples += 2; - while (numberOfSamples > 0) { + numberOfCopy = numberOfSamples + 2; + while (numberOfCopy > 0) { if (destOffset + 1 >= destSize) { debug(2, "Frame decoding overflow\n\tsourceOffset=%u\tsourceSize=%u\n\tdestOffset=%u\tdestSize=%u", sourceOffset, sourceSize, destOffset, destSize); return; @@ -322,7 +373,7 @@ void RlfAnimation::decodeSimpleRunLengthEncoding(int8 *source, int8 *dest, uint3 WRITE_UINT16(dest + destOffset, sampleColor); destOffset += 2; - numberOfSamples--; + numberOfCopy--; } } } diff --git a/engines/zvision/animation/rlf_animation.h b/engines/zvision/animation/rlf_animation.h index 4bb779301b..c8b2930676 100644 --- a/engines/zvision/animation/rlf_animation.h +++ b/engines/zvision/animation/rlf_animation.h @@ -27,7 +27,6 @@ #include "graphics/surface.h" - namespace Common { class String; } @@ -37,6 +36,7 @@ namespace ZVision { class RlfAnimation { public: RlfAnimation(const Common::String &fileName, bool stream = true); + RlfAnimation(Common::SeekableReadStream *rstream, bool stream); ~RlfAnimation(); private: @@ -52,7 +52,7 @@ private: }; private: - Common::File _file; + Common::SeekableReadStream *_readStream; bool _stream; uint _lastFrameRead; @@ -63,15 +63,23 @@ private: Frame *_frames; Common::Array<uint> _completeFrames; - int _currentFrame; + int _nextFrame; Graphics::Surface _currentFrameBuffer; uint32 _frameBufferByteSize; public: - uint frameCount() { return _frameCount; } - uint width() { return _width; } - uint height() { return _height; } - uint32 frameTime() { return _frameTime; } + uint frameCount() { + return _frameCount; + } + uint width() { + return _width; + } + uint height() { + return _height; + } + uint32 frameTime() { + return _frameTime; + } /** * Seeks to the frameNumber and updates the internal Surface with @@ -84,7 +92,7 @@ public: /** * Returns the pixel data of the frame specified. It will try to use - * getNextFrame() if possible. If not, it uses seekToFrame() to + * decodeNextFrame() if possible. If not, it uses seekToFrame() to * update the internal Surface and then returns a pointer to it. * This function requires _stream = false * @@ -93,18 +101,19 @@ public: */ const Graphics::Surface *getFrameData(uint frameNumber); /** - * Returns the pixel data of the next frame. It is up to the user to - * check if the next frame is valid before calling this. + * Returns the pixel data of current frame and go to next. It is up to the user to + * check if the current frame is valid before calling this. * IE. Use endOfAnimation() * * @return A pointer to the pixel data. Do NOT delete this. */ - const Graphics::Surface *getNextFrame(); - + const Graphics::Surface *decodeNextFrame(); /** * @return Is the currentFrame is the last frame in the animation? */ - bool endOfAnimation() { return _currentFrame == (int)_frameCount - 1; } + bool endOfAnimation() { + return _nextFrame == (int)_frameCount; + } private: /** diff --git a/engines/zvision/core/console.cpp b/engines/zvision/core/console.cpp index e610f34474..f8e28333f1 100644 --- a/engines/zvision/core/console.cpp +++ b/engines/zvision/core/console.cpp @@ -1,24 +1,24 @@ /* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ #include "common/scummsys.h" @@ -27,7 +27,7 @@ #include "zvision/zvision.h" #include "zvision/scripting/script_manager.h" #include "zvision/graphics/render_manager.h" -#include "zvision/strings/string_manager.h" +#include "zvision/text/string_manager.h" #include "zvision/video/zork_avi_decoder.h" #include "zvision/sound/zork_raw.h" #include "zvision/utility/utility.h" @@ -41,11 +41,9 @@ #include "audio/mixer.h" - namespace ZVision { Console::Console(ZVision *engine) : GUI::Debugger(), _engine(engine) { - registerCmd("loadimage", WRAP_METHOD(Console, cmdLoadImage)); registerCmd("loadvideo", WRAP_METHOD(Console, cmdLoadVideo)); registerCmd("loadsound", WRAP_METHOD(Console, cmdLoadSound)); registerCmd("raw2wav", WRAP_METHOD(Console, cmdRawToWav)); @@ -56,18 +54,6 @@ Console::Console(ZVision *engine) : GUI::Debugger(), _engine(engine) { registerCmd("changelocation", WRAP_METHOD(Console, cmdChangeLocation)); registerCmd("dumpfile", WRAP_METHOD(Console, cmdDumpFile)); registerCmd("parseallscrfiles", WRAP_METHOD(Console, cmdParseAllScrFiles)); - registerCmd("rendertext", WRAP_METHOD(Console, cmdRenderText)); -} - -bool Console::cmdLoadImage(int argc, const char **argv) { - if (argc == 4) - _engine->getRenderManager()->renderImageToScreen(argv[1], atoi(argv[2]), atoi(argv[3])); - else { - debugPrintf("Use loadimage <fileName> <destinationX> <destinationY> to load an image to the screen\n"); - return true; - } - - return true; } bool Console::cmdLoadVideo(int argc, const char **argv) { @@ -118,7 +104,42 @@ bool Console::cmdRawToWav(int argc, const char **argv) { return true; } - convertRawToWav(argv[1], _engine, argv[2]); + Common::File file; + if (!file.open(argv[1])) + return true; + + Audio::AudioStream *audioStream = makeRawZorkStream(argv[1], _engine); + + Common::DumpFile output; + output.open(argv[2]); + + output.writeUint32BE(MKTAG('R', 'I', 'F', 'F')); + output.writeUint32LE(file.size() * 2 + 36); + output.writeUint32BE(MKTAG('W', 'A', 'V', 'E')); + output.writeUint32BE(MKTAG('f', 'm', 't', ' ')); + output.writeUint32LE(16); + output.writeUint16LE(1); + uint16 numChannels; + if (audioStream->isStereo()) { + numChannels = 2; + output.writeUint16LE(2); + } else { + numChannels = 1; + output.writeUint16LE(1); + } + output.writeUint32LE(audioStream->getRate()); + output.writeUint32LE(audioStream->getRate() * numChannels * 2); + output.writeUint16LE(numChannels * 2); + output.writeUint16LE(16); + output.writeUint32BE(MKTAG('d', 'a', 't', 'a')); + output.writeUint32LE(file.size() * 2); + int16 *buffer = new int16[file.size()]; + audioStream->readBuffer(buffer, file.size()); + output.write(buffer, file.size() * 2); + + delete[] buffer; + + return true; } @@ -187,7 +208,22 @@ bool Console::cmdDumpFile(int argc, const char **argv) { return true; } - writeFileContentsToFile(argv[1], argv[1]); + Common::File f; + if (!f.open(argv[1])) { + return true; + } + + byte *buffer = new byte[f.size()]; + f.read(buffer, f.size()); + + Common::DumpFile dumpFile; + dumpFile.open(argv[1]); + + dumpFile.write(buffer, f.size()); + dumpFile.flush(); + dumpFile.close(); + + delete[] buffer; return true; } @@ -197,22 +233,9 @@ bool Console::cmdParseAllScrFiles(int argc, const char **argv) { SearchMan.listMatchingMembers(list, "*.scr"); for (Common::ArchiveMemberList::iterator iter = list.begin(); iter != list.end(); ++iter) { - _engine->getScriptManager()->parseScrFile((*iter)->getName()); } return true; } -bool Console::cmdRenderText(int argc, const char **argv) { - if (argc != 7) { - debugPrintf("Use rendertext <text> <fontNumber> <destX> <destY> <maxWidth> <1 or 0: wrap> to render text\n"); - return true; - } - - StringManager::TextStyle style = _engine->getStringManager()->getTextStyle(atoi(argv[2])); - _engine->getRenderManager()->renderTextToWorkingWindow(333, Common::String(argv[1]), style.font, atoi(argv[3]), atoi(argv[4]), style.color, atoi(argv[5]), -1, Graphics::kTextAlignLeft, atoi(argv[6]) == 0 ? false : true); - - return true; -} - } // End of namespace ZVision diff --git a/engines/zvision/core/console.h b/engines/zvision/core/console.h index 29523c57ee..994e05ba35 100644 --- a/engines/zvision/core/console.h +++ b/engines/zvision/core/console.h @@ -37,7 +37,6 @@ public: private: ZVision *_engine; - bool cmdLoadImage(int argc, const char **argv); bool cmdLoadVideo(int argc, const char **argv); bool cmdLoadSound(int argc, const char **argv); bool cmdRawToWav(int argc, const char **argv); @@ -48,7 +47,6 @@ private: bool cmdChangeLocation(int argc, const char **argv); bool cmdDumpFile(int argc, const char **argv); bool cmdParseAllScrFiles(int argc, const char **argv); - bool cmdRenderText(int argc, const char **argv); }; } // End of namespace ZVision diff --git a/engines/zvision/core/events.cpp b/engines/zvision/core/events.cpp index 83d6c17dec..52d71c92f6 100644 --- a/engines/zvision/core/events.cpp +++ b/engines/zvision/core/events.cpp @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -29,6 +29,8 @@ #include "zvision/graphics/render_manager.h" #include "zvision/scripting/script_manager.h" #include "zvision/animation/rlf_animation.h" +#include "zvision/core/menu.h" +#include "zvision/sound/zork_raw.h" #include "common/events.h" #include "common/system.h" @@ -36,29 +38,151 @@ #include "engines/util.h" - namespace ZVision { +void ZVision::shortKeys(Common::Event event) { + if (event.kbd.hasFlags(Common::KBD_CTRL)) { + switch (event.kbd.keycode) { + case Common::KEYCODE_s: + if (getMenuBarEnable() & menuBar_Save) + _scriptManager->changeLocation('g', 'j', 's', 'e', 0); + break; + case Common::KEYCODE_r: + if (getMenuBarEnable() & menuBar_Restore) + _scriptManager->changeLocation('g', 'j', 'r', 'e', 0); + break; + case Common::KEYCODE_p: + if (getMenuBarEnable() & menuBar_Settings) + _scriptManager->changeLocation('g', 'j', 'p', 'e', 0); + break; + case Common::KEYCODE_q: + if (getMenuBarEnable() & menuBar_Exit) + ifQuit(); + break; + default: + break; + } + } +} + +void ZVision::cheatCodes(uint8 key) { + pushKeyToCheatBuf(key); + + if (getGameId() == GID_GRANDINQUISITOR) { + if (checkCode("IMNOTDEAF")) { + // Unknown cheat + showDebugMsg(Common::String::format("IMNOTDEAF cheat or debug, not implemented")); + } + + if (checkCode("3100OPB")) { + showDebugMsg(Common::String::format("Current location: %c%c%c%c", + _scriptManager->getStateValue(StateKey_World), + _scriptManager->getStateValue(StateKey_Room), + _scriptManager->getStateValue(StateKey_Node), + _scriptManager->getStateValue(StateKey_View))); + } + + if (checkCode("KILLMENOW")) { + _scriptManager->changeLocation('g', 'j', 'd', 'e', 0); + _scriptManager->setStateValue(2201, 35); + } + + if (checkCode("MIKESPANTS")) { + _scriptManager->changeLocation('g', 'j', 't', 'm', 0); + } + + // There are 3 more cheats in script files: + // - "EAT ME": gjcr.scr + // - "WHOAMI": hp1e.scr + // - "HUISOK": uh1f.scr + } else if (getGameId() == GID_NEMESIS) { + if (checkCode("CHLOE")) { + _scriptManager->changeLocation('t', 'm', '2', 'g', 0); + _scriptManager->setStateValue(224, 1); + } + + if (checkCode("77MASSAVE")) { + showDebugMsg(Common::String::format("Current location: %c%c%c%c", + _scriptManager->getStateValue(StateKey_World), + _scriptManager->getStateValue(StateKey_Room), + _scriptManager->getStateValue(StateKey_Node), + _scriptManager->getStateValue(StateKey_View))); + } + + if (checkCode("IDKFA")) { + _scriptManager->changeLocation('t', 'w', '3', 'f', 0); + _scriptManager->setStateValue(249, 1); + } + + if (checkCode("309NEWDORMA")) { + _scriptManager->changeLocation('g', 'j', 'g', 'j', 0); + } + + if (checkCode("HELLOSAILOR")) { + Location loc = _scriptManager->getCurrentLocation(); + Audio::AudioStream *soundStream; + if (loc.world == 'v' && loc.room == 'b' && loc.node == '1' && loc.view == '0') { + soundStream = makeRawZorkStream("v000hpta.raw", this); + } else { + soundStream = makeRawZorkStream("v000hnta.raw", this); + } + Audio::SoundHandle handle; + _mixer->playStream(Audio::Mixer::kPlainSoundType, &handle, soundStream); + } + } + + if (checkCode("FRAME")) + showDebugMsg(Common::String::format("FPS: ???, not implemented")); + + if (checkCode("XYZZY")) + _scriptManager->setStateValue(StateKey_DebugCheats, 1 - _scriptManager->getStateValue(StateKey_DebugCheats)); + + if (checkCode("COMPUTERARCH")) + showDebugMsg(Common::String::format("COMPUTERARCH: var-viewer not implemented")); + + if (_scriptManager->getStateValue(StateKey_DebugCheats) == 1) + if (checkCode("GO????")) + _scriptManager->changeLocation(getBufferedKey(3), + getBufferedKey(2), + getBufferedKey(1), + getBufferedKey(0), 0); +} + void ZVision::processEvents() { while (_eventMan->pollEvent(_event)) { switch (_event.type) { case Common::EVENT_LBUTTONDOWN: - onMouseDown(_event.mouse); + _cursorManager->cursorDown(true); + _scriptManager->setStateValue(StateKey_LMouse, 1); + _menu->onMouseDown(_event.mouse); + _scriptManager->addEvent(_event); break; case Common::EVENT_LBUTTONUP: - onMouseUp(_event.mouse); + _cursorManager->cursorDown(false); + _scriptManager->setStateValue(StateKey_LMouse, 0); + _menu->onMouseUp(_event.mouse); + _scriptManager->addEvent(_event); break; case Common::EVENT_RBUTTONDOWN: - // TODO: Inventory logic + _cursorManager->cursorDown(true); + _scriptManager->setStateValue(StateKey_RMouse, 1); + + if (getGameId() == GID_NEMESIS) + _scriptManager->inventoryCycle(); + break; + + case Common::EVENT_RBUTTONUP: + _cursorManager->cursorDown(false); + _scriptManager->setStateValue(StateKey_RMouse, 0); break; case Common::EVENT_MOUSEMOVE: onMouseMove(_event.mouse); break; - case Common::EVENT_KEYDOWN: + case Common::EVENT_KEYDOWN: { switch (_event.kbd.keycode) { case Common::KEYCODE_d: if (_event.kbd.hasFlags(Common::KBD_CTRL)) { @@ -67,18 +191,52 @@ void ZVision::processEvents() { _console->onFrame(); } break; - case Common::KEYCODE_q: - if (_event.kbd.hasFlags(Common::KBD_CTRL)) - quitGame(); + + case Common::KEYCODE_LEFT: + case Common::KEYCODE_RIGHT: + if (_renderManager->getRenderTable()->getRenderState() == RenderTable::PANORAMA) + _kbdVelocity = (_event.kbd.keycode == Common::KEYCODE_LEFT ? + -_scriptManager->getStateValue(StateKey_KbdRotateSpeed) : + _scriptManager->getStateValue(StateKey_KbdRotateSpeed)) * 2; + break; + + case Common::KEYCODE_UP: + case Common::KEYCODE_DOWN: + if (_renderManager->getRenderTable()->getRenderState() == RenderTable::TILT) + _kbdVelocity = (_event.kbd.keycode == Common::KEYCODE_UP ? + -_scriptManager->getStateValue(StateKey_KbdRotateSpeed) : + _scriptManager->getStateValue(StateKey_KbdRotateSpeed)) * 2; break; + default: break; } - _scriptManager->onKeyDown(_event.kbd); - break; + uint8 vkKey = getZvisionKey(_event.kbd.keycode); + + _scriptManager->setStateValue(StateKey_KeyPress, vkKey); + + _scriptManager->addEvent(_event); + shortKeys(_event); + cheatCodes(vkKey); + } + break; case Common::EVENT_KEYUP: - _scriptManager->onKeyUp(_event.kbd); + _scriptManager->addEvent(_event); + switch (_event.kbd.keycode) { + case Common::KEYCODE_LEFT: + case Common::KEYCODE_RIGHT: + if (_renderManager->getRenderTable()->getRenderState() == RenderTable::PANORAMA) + _kbdVelocity = 0; + break; + case Common::KEYCODE_UP: + case Common::KEYCODE_DOWN: + if (_renderManager->getRenderTable()->getRenderState() == RenderTable::TILT) + _kbdVelocity = 0; + break; + default: + break; + } break; default: break; @@ -86,24 +244,11 @@ void ZVision::processEvents() { } } -void ZVision::onMouseDown(const Common::Point &pos) { - _cursorManager->cursorDown(true); - - Common::Point imageCoord(_renderManager->screenSpaceToImageSpace(pos)); - _scriptManager->onMouseDown(pos, imageCoord); -} - -void ZVision::onMouseUp(const Common::Point &pos) { - _cursorManager->cursorDown(false); - - Common::Point imageCoord(_renderManager->screenSpaceToImageSpace(pos)); - _scriptManager->onMouseUp(pos, imageCoord); -} - void ZVision::onMouseMove(const Common::Point &pos) { + _menu->onMouseMove(pos); Common::Point imageCoord(_renderManager->screenSpaceToImageSpace(pos)); - bool cursorWasChanged = _scriptManager->onMouseMove(pos, imageCoord); + bool cursorWasChanged = false; // Graph of the function governing rotation velocity: // @@ -136,51 +281,165 @@ void ZVision::onMouseMove(const Common::Point &pos) { // ^ if (_workingWindow.contains(pos)) { + cursorWasChanged = _scriptManager->onMouseMove(pos, imageCoord); + RenderTable::RenderState renderState = _renderManager->getRenderTable()->getRenderState(); if (renderState == RenderTable::PANORAMA) { if (pos.x >= _workingWindow.left && pos.x < _workingWindow.left + ROTATION_SCREEN_EDGE_OFFSET) { - // Linear function of distance to the left edge (y = -mx + b) - // We use fixed point math to get better accuracy - Common::Rational velocity = (Common::Rational(MAX_ROTATION_SPEED, ROTATION_SCREEN_EDGE_OFFSET) * (pos.x - _workingWindow.left)) - MAX_ROTATION_SPEED; - _renderManager->setBackgroundVelocity(velocity.toInt()); - _cursorManager->setLeftCursor(); + + int16 mspeed = _scriptManager->getStateValue(StateKey_RotateSpeed) >> 4; + if (mspeed <= 0) + mspeed = 400 >> 4; + _mouseVelocity = (((pos.x - (ROTATION_SCREEN_EDGE_OFFSET + _workingWindow.left)) << 7) / ROTATION_SCREEN_EDGE_OFFSET * mspeed) >> 7; + + _cursorManager->changeCursor(CursorIndex_Left); cursorWasChanged = true; } else if (pos.x <= _workingWindow.right && pos.x > _workingWindow.right - ROTATION_SCREEN_EDGE_OFFSET) { - // Linear function of distance to the right edge (y = mx) - // We use fixed point math to get better accuracy - Common::Rational velocity = Common::Rational(MAX_ROTATION_SPEED, ROTATION_SCREEN_EDGE_OFFSET) * (pos.x - _workingWindow.right + ROTATION_SCREEN_EDGE_OFFSET); - _renderManager->setBackgroundVelocity(velocity.toInt()); - _cursorManager->setRightCursor(); + + int16 mspeed = _scriptManager->getStateValue(StateKey_RotateSpeed) >> 4; + if (mspeed <= 0) + mspeed = 400 >> 4; + _mouseVelocity = (((pos.x - (_workingWindow.right - ROTATION_SCREEN_EDGE_OFFSET)) << 7) / ROTATION_SCREEN_EDGE_OFFSET * mspeed) >> 7; + + _cursorManager->changeCursor(CursorIndex_Right); cursorWasChanged = true; } else { - _renderManager->setBackgroundVelocity(0); + _mouseVelocity = 0; } } else if (renderState == RenderTable::TILT) { if (pos.y >= _workingWindow.top && pos.y < _workingWindow.top + ROTATION_SCREEN_EDGE_OFFSET) { - // Linear function of distance to top edge - // We use fixed point math to get better accuracy - Common::Rational velocity = (Common::Rational(MAX_ROTATION_SPEED, ROTATION_SCREEN_EDGE_OFFSET) * (pos.y - _workingWindow.top)) - MAX_ROTATION_SPEED; - _renderManager->setBackgroundVelocity(velocity.toInt()); - _cursorManager->setUpCursor(); + + int16 mspeed = _scriptManager->getStateValue(StateKey_RotateSpeed) >> 4; + if (mspeed <= 0) + mspeed = 400 >> 4; + _mouseVelocity = (((pos.y - (_workingWindow.top + ROTATION_SCREEN_EDGE_OFFSET)) << 7) / ROTATION_SCREEN_EDGE_OFFSET * mspeed) >> 7; + + _cursorManager->changeCursor(CursorIndex_UpArr); cursorWasChanged = true; } else if (pos.y <= _workingWindow.bottom && pos.y > _workingWindow.bottom - ROTATION_SCREEN_EDGE_OFFSET) { - // Linear function of distance to the bottom edge (y = mx) - // We use fixed point math to get better accuracy - Common::Rational velocity = Common::Rational(MAX_ROTATION_SPEED, ROTATION_SCREEN_EDGE_OFFSET) * (pos.y - _workingWindow.bottom + ROTATION_SCREEN_EDGE_OFFSET); - _renderManager->setBackgroundVelocity(velocity.toInt()); - _cursorManager->setDownCursor(); + + int16 mspeed = _scriptManager->getStateValue(StateKey_RotateSpeed) >> 4; + if (mspeed <= 0) + mspeed = 400 >> 4; + _mouseVelocity = (((pos.y - (_workingWindow.bottom - ROTATION_SCREEN_EDGE_OFFSET)) << 7) / ROTATION_SCREEN_EDGE_OFFSET * mspeed) >> 7; + + _cursorManager->changeCursor(CursorIndex_DownArr); cursorWasChanged = true; } else { - _renderManager->setBackgroundVelocity(0); + _mouseVelocity = 0; } + } else { + _mouseVelocity = 0; } } else { - _renderManager->setBackgroundVelocity(0); + _mouseVelocity = 0; } if (!cursorWasChanged) { - _cursorManager->revertToIdle(); + _cursorManager->changeCursor(CursorIndex_Idle); } } +uint8 ZVision::getZvisionKey(Common::KeyCode scummKeyCode) { + if (scummKeyCode >= Common::KEYCODE_a && scummKeyCode <= Common::KEYCODE_z) + return 0x41 + scummKeyCode - Common::KEYCODE_a; + if (scummKeyCode >= Common::KEYCODE_0 && scummKeyCode <= Common::KEYCODE_9) + return 0x30 + scummKeyCode - Common::KEYCODE_0; + if (scummKeyCode >= Common::KEYCODE_F1 && scummKeyCode <= Common::KEYCODE_F15) + return 0x70 + scummKeyCode - Common::KEYCODE_F1; + if (scummKeyCode >= Common::KEYCODE_KP0 && scummKeyCode <= Common::KEYCODE_KP9) + return 0x60 + scummKeyCode - Common::KEYCODE_KP0; + + switch (scummKeyCode) { + case Common::KEYCODE_BACKSPACE: + return 0x8; + case Common::KEYCODE_TAB: + return 0x9; + case Common::KEYCODE_CLEAR: + return 0xC; + case Common::KEYCODE_RETURN: + return 0xD; + case Common::KEYCODE_CAPSLOCK: + return 0x14; + case Common::KEYCODE_ESCAPE: + return 0x1B; + case Common::KEYCODE_SPACE: + return 0x20; + case Common::KEYCODE_PAGEUP: + return 0x21; + case Common::KEYCODE_PAGEDOWN: + return 0x22; + case Common::KEYCODE_END: + return 0x23; + case Common::KEYCODE_HOME: + return 0x24; + case Common::KEYCODE_LEFT: + return 0x25; + case Common::KEYCODE_UP: + return 0x26; + case Common::KEYCODE_RIGHT: + return 0x27; + case Common::KEYCODE_DOWN: + return 0x28; + case Common::KEYCODE_PRINT: + return 0x2A; + case Common::KEYCODE_INSERT: + return 0x2D; + case Common::KEYCODE_DELETE: + return 0x2E; + case Common::KEYCODE_HELP: + return 0x2F; + case Common::KEYCODE_KP_MULTIPLY: + return 0x6A; + case Common::KEYCODE_KP_PLUS: + return 0x6B; + case Common::KEYCODE_KP_MINUS: + return 0x6D; + case Common::KEYCODE_KP_PERIOD: + return 0x6E; + case Common::KEYCODE_KP_DIVIDE: + return 0x6F; + case Common::KEYCODE_NUMLOCK: + return 0x90; + case Common::KEYCODE_SCROLLOCK: + return 0x91; + case Common::KEYCODE_LSHIFT: + return 0xA0; + case Common::KEYCODE_RSHIFT: + return 0xA1; + case Common::KEYCODE_LCTRL: + return 0xA2; + case Common::KEYCODE_RCTRL: + return 0xA3; + case Common::KEYCODE_MENU: + return 0xA5; + case Common::KEYCODE_LEFTBRACKET: + return 0xDB; + case Common::KEYCODE_RIGHTBRACKET: + return 0xDD; + case Common::KEYCODE_SEMICOLON: + return 0xBA; + case Common::KEYCODE_BACKSLASH: + return 0xDC; + case Common::KEYCODE_QUOTE: + return 0xDE; + case Common::KEYCODE_SLASH: + return 0xBF; + case Common::KEYCODE_TILDE: + return 0xC0; + case Common::KEYCODE_COMMA: + return 0xBC; + case Common::KEYCODE_PERIOD: + return 0xBE; + case Common::KEYCODE_MINUS: + return 0xBD; + case Common::KEYCODE_PLUS: + return 0xBB; + default: + return 0; + } + + return 0; +} + } // End of namespace ZVision diff --git a/engines/zvision/core/menu.cpp b/engines/zvision/core/menu.cpp new file mode 100644 index 0000000000..c7898a4fbd --- /dev/null +++ b/engines/zvision/core/menu.cpp @@ -0,0 +1,761 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/core/menu.h" + +#include "zvision/graphics/render_manager.h" + +namespace ZVision { + +enum { + SLOT_START_SLOT = 151, + SLOT_SPELL_1 = 191, + SLOT_USER_CHOSE_THIS_SPELL = 205, + SLOT_REVERSED_SPELLBOOK = 206 +}; + +enum { + menu_MAIN_SAVE = 0, + menu_MAIN_REST = 1, + menu_MAIN_PREF = 2, + menu_MAIN_EXIT = 3 +}; + +MenuHandler::MenuHandler(ZVision *engine) { + _engine = engine; + menuBarFlag = 0xFFFF; +} + +MenuZGI::MenuZGI(ZVision *engine) : + MenuHandler(engine) { + menuMouseFocus = -1; + inmenu = false; + scrolled[0] = false; + scrolled[1] = false; + scrolled[2] = false; + scrollPos[0] = 0.0; + scrollPos[1] = 0.0; + scrollPos[2] = 0.0; + mouseOnItem = -1; + + char buf[24]; + for (int i = 1; i < 4; i++) { + sprintf(buf, "gmzau%2.2x1.tga", i); + _engine->getRenderManager()->readImageToSurface(buf, menuback[i - 1][0], false); + sprintf(buf, "gmzau%2.2x1.tga", i + 0x10); + _engine->getRenderManager()->readImageToSurface(buf, menuback[i - 1][1], false); + } + for (int i = 0; i < 4; i++) { + sprintf(buf, "gmzmu%2.2x1.tga", i); + _engine->getRenderManager()->readImageToSurface(buf, menubar[i][0], false); + sprintf(buf, "gmznu%2.2x1.tga", i); + _engine->getRenderManager()->readImageToSurface(buf, menubar[i][1], false); + } + + for (int i = 0; i < 50; i++) { + items[i][0] = NULL; + items[i][1] = NULL; + itemId[i] = 0; + } + + for (int i = 0; i < 12; i++) { + magic[i][0] = NULL; + magic[i][1] = NULL; + magicId[i] = 0; + } +} + +MenuZGI::~MenuZGI() { + for (int i = 0; i < 3; i++) { + menuback[i][0].free(); + menuback[i][1].free(); + } + for (int i = 0; i < 4; i++) { + menubar[i][0].free(); + menubar[i][1].free(); + } + for (int i = 0; i < 50; i++) { + if (items[i][0]) { + items[i][0]->free(); + delete items[i][0]; + } + if (items[i][1]) { + items[i][1]->free(); + delete items[i][1]; + } + } + for (int i = 0; i < 12; i++) { + if (magic[i][0]) { + magic[i][0]->free(); + delete magic[i][0]; + } + if (magic[i][1]) { + magic[i][1]->free(); + delete magic[i][1]; + } + } +} + +void MenuZGI::onMouseUp(const Common::Point &Pos) { + if (Pos.y < 40) { + switch (menuMouseFocus) { + case menu_ITEM: + if (menuBarFlag & menuBar_Items) { + int itemCount = _engine->getScriptManager()->getStateValue(StateKey_Inv_TotalSlots); + if (itemCount == 0) + itemCount = 20; + + for (int i = 0; i < itemCount; i++) { + int itemspace = (600 - 28) / itemCount; + + if (Common::Rect(scrollPos[menu_ITEM] + itemspace * i, 0, + scrollPos[menu_ITEM] + itemspace * i + 28, 32).contains(Pos)) { + int32 mouseItem = _engine->getScriptManager()->getStateValue(StateKey_InventoryItem); + if (mouseItem >= 0 && mouseItem < 0xE0) { + _engine->getScriptManager()->inventoryDrop(mouseItem); + _engine->getScriptManager()->inventoryAdd(_engine->getScriptManager()->getStateValue(SLOT_START_SLOT + i)); + _engine->getScriptManager()->setStateValue(SLOT_START_SLOT + i, mouseItem); + + redraw = true; + } + } + } + } + break; + + case menu_MAGIC: + if (menuBarFlag & menuBar_Magic) { + for (int i = 0; i < 12; i++) { + + uint itemnum = _engine->getScriptManager()->getStateValue(SLOT_SPELL_1 + i); + if (itemnum != 0) { + if (_engine->getScriptManager()->getStateValue(SLOT_REVERSED_SPELLBOOK) == 1) + itemnum = 0xEE + i; + else + itemnum = 0xE0 + i; + } + if (itemnum) + if (_engine->getScriptManager()->getStateValue(StateKey_InventoryItem) == 0 || _engine->getScriptManager()->getStateValue(StateKey_InventoryItem) >= 0xE0) + if (Common::Rect(668 + 47 * i - scrollPos[menu_MAGIC], 0, + 668 + 47 * i - scrollPos[menu_MAGIC] + 28, 32).contains(Pos)) + _engine->getScriptManager()->setStateValue(SLOT_USER_CHOSE_THIS_SPELL, itemnum); + } + + } + break; + + case menu_MAIN: + + // Exit + if (menuBarFlag & menuBar_Exit) + if (Common::Rect(320 + 135, + scrollPos[menu_MAIN], + 320 + 135 + 135, + scrollPos[menu_MAIN] + 32).contains(Pos)) { + _engine->ifQuit(); + } + + // Settings + if (menuBarFlag & menuBar_Settings) + if (Common::Rect(320 , + scrollPos[menu_MAIN], + 320 + 135, + scrollPos[menu_MAIN] + 32).contains(Pos)) { + _engine->getScriptManager()->changeLocation('g', 'j', 'p', 'e', 0); + } + + // Load + if (menuBarFlag & menuBar_Restore) + if (Common::Rect(320 - 135, + scrollPos[menu_MAIN], + 320, + scrollPos[menu_MAIN] + 32).contains(Pos)) { + _engine->getScriptManager()->changeLocation('g', 'j', 'r', 'e', 0); + } + + // Save + if (menuBarFlag & menuBar_Save) + if (Common::Rect(320 - 135 * 2, + scrollPos[menu_MAIN], + 320 - 135, + scrollPos[menu_MAIN] + 32).contains(Pos)) { + _engine->getScriptManager()->changeLocation('g', 'j', 's', 'e', 0); + } + break; + } + } +} + +void MenuZGI::onMouseMove(const Common::Point &Pos) { + if (Pos.y < 40) { + + if (!inmenu) + redraw = true; + inmenu = true; + switch (menuMouseFocus) { + case menu_ITEM: + if (menuBarFlag & menuBar_Items) { + int itemCount = _engine->getScriptManager()->getStateValue(StateKey_Inv_TotalSlots); + if (itemCount == 0) + itemCount = 20; + else if (itemCount > 50) + itemCount = 50; + + int lastItem = mouseOnItem; + + mouseOnItem = -1; + + for (int i = 0; i < itemCount; i++) { + int itemspace = (600 - 28) / itemCount; + + if (Common::Rect(scrollPos[menu_ITEM] + itemspace * i, 0, + scrollPos[menu_ITEM] + itemspace * i + 28, 32).contains(Pos)) { + mouseOnItem = i; + break; + } + } + + if (lastItem != mouseOnItem) + if (_engine->getScriptManager()->getStateValue(SLOT_START_SLOT + mouseOnItem) || + _engine->getScriptManager()->getStateValue(SLOT_START_SLOT + lastItem)) + redraw = true; + } + break; + + case menu_MAGIC: + if (menuBarFlag & menuBar_Magic) { + int lastItem = mouseOnItem; + mouseOnItem = -1; + for (int i = 0; i < 12; i++) { + if (Common::Rect(668 + 47 * i - scrollPos[menu_MAGIC], 0, + 668 + 47 * i - scrollPos[menu_MAGIC] + 28, 32).contains(Pos)) { + mouseOnItem = i; + break; + } + } + + if (lastItem != mouseOnItem) + if (_engine->getScriptManager()->getStateValue(SLOT_SPELL_1 + mouseOnItem) || + _engine->getScriptManager()->getStateValue(SLOT_SPELL_1 + lastItem)) + redraw = true; + + } + break; + + case menu_MAIN: { + int lastItem = mouseOnItem; + mouseOnItem = -1; + + // Exit + if (menuBarFlag & menuBar_Exit) + if (Common::Rect(320 + 135, + scrollPos[menu_MAIN], + 320 + 135 + 135, + scrollPos[menu_MAIN] + 32).contains(Pos)) { + mouseOnItem = menu_MAIN_EXIT; + } + + // Settings + if (menuBarFlag & menuBar_Settings) + if (Common::Rect(320 , + scrollPos[menu_MAIN], + 320 + 135, + scrollPos[menu_MAIN] + 32).contains(Pos)) { + mouseOnItem = menu_MAIN_PREF; + } + + // Load + if (menuBarFlag & menuBar_Restore) + if (Common::Rect(320 - 135, + scrollPos[menu_MAIN], + 320, + scrollPos[menu_MAIN] + 32).contains(Pos)) { + mouseOnItem = menu_MAIN_REST; + } + + // Save + if (menuBarFlag & menuBar_Save) + if (Common::Rect(320 - 135 * 2, + scrollPos[menu_MAIN], + 320 - 135, + scrollPos[menu_MAIN] + 32).contains(Pos)) { + mouseOnItem = menu_MAIN_SAVE; + } + + if (lastItem != mouseOnItem) + redraw = true; + } + break; + + default: + int cur_menu = menuMouseFocus; + if (Common::Rect(64, 0, 64 + 512, 8).contains(Pos)) { // Main + menuMouseFocus = menu_MAIN; + scrolled[menu_MAIN] = false; + scrollPos[menu_MAIN] = menuback[menu_MAIN][1].h - menuback[menu_MAIN][0].h; + _engine->getScriptManager()->setStateValue(StateKey_MenuState, 2); + } + + if (menuBarFlag & menuBar_Magic) + if (Common::Rect(640 - 28, 0, 640, 32).contains(Pos)) { // Magic + menuMouseFocus = menu_MAGIC; + scrolled[menu_MAGIC] = false; + scrollPos[menu_MAGIC] = 28; + _engine->getScriptManager()->setStateValue(StateKey_MenuState, 3); + } + + if (menuBarFlag & menuBar_Items) + if (Common::Rect(0, 0, 28, 32).contains(Pos)) { // Items + menuMouseFocus = menu_ITEM; + scrolled[menu_ITEM] = false; + scrollPos[menu_ITEM] = 28 - 600; + _engine->getScriptManager()->setStateValue(StateKey_MenuState, 1); + } + + if (cur_menu != menuMouseFocus) + clean = true; + + break; + } + } else { + if (inmenu) + clean = true; + inmenu = false; + if (_engine->getScriptManager()->getStateValue(StateKey_MenuState) != 0) + _engine->getScriptManager()->setStateValue(StateKey_MenuState, 0); + menuMouseFocus = -1; + } +} + +void MenuZGI::process(uint32 deltatime) { + if (clean) { + _engine->getRenderManager()->clearMenuSurface(); + clean = false; + } + switch (menuMouseFocus) { + case menu_ITEM: + if (menuBarFlag & menuBar_Items) + if (!scrolled[menu_ITEM]) { + redraw = true; + float scrl = 600.0 * (deltatime / 1000.0); + + if (scrl == 0) + scrl = 1.0; + + scrollPos [menu_ITEM] += scrl; + + if (scrollPos[menu_ITEM] >= 0) { + scrolled[menu_ITEM] = true; + scrollPos [menu_ITEM] = 0; + } + } + if (redraw) { + _engine->getRenderManager()->blitSurfaceToMenu(menuback[menu_ITEM][0], scrollPos[menu_ITEM], 0); + + int itemCount = _engine->getScriptManager()->getStateValue(StateKey_Inv_TotalSlots); + if (itemCount == 0) + itemCount = 20; + else if (itemCount > 50) + itemCount = 50; + + for (int i = 0; i < itemCount; i++) { + int itemspace = (600 - 28) / itemCount; + + bool inrect = false; + + if (mouseOnItem == i) + inrect = true; + + uint curItemId = _engine->getScriptManager()->getStateValue(SLOT_START_SLOT + i); + + if (curItemId != 0) { + if (itemId[i] != curItemId) { + char buf[16]; + sprintf(buf, "gmzwu%2.2x1.tga", curItemId); + items[i][0] = _engine->getRenderManager()->loadImage(buf, false); + sprintf(buf, "gmzxu%2.2x1.tga", curItemId); + items[i][1] = _engine->getRenderManager()->loadImage(buf, false); + itemId[i] = curItemId; + } + + if (inrect) + _engine->getRenderManager()->blitSurfaceToMenu(*items[i][1], scrollPos[menu_ITEM] + itemspace * i, 0, 0); + else + _engine->getRenderManager()->blitSurfaceToMenu(*items[i][0], scrollPos[menu_ITEM] + itemspace * i, 0, 0); + + } else { + if (items[i][0]) { + items[i][0]->free(); + delete items[i][0]; + items[i][0] = NULL; + } + if (items[i][1]) { + items[i][1]->free(); + delete items[i][1]; + items[i][1] = NULL; + } + itemId[i] = 0; + } + } + + redraw = false; + } + break; + + case menu_MAGIC: + if (menuBarFlag & menuBar_Magic) + if (!scrolled[menu_MAGIC]) { + redraw = true; + float scrl = 600.0 * (deltatime / 1000.0); + + if (scrl == 0) + scrl = 1.0; + + scrollPos [menu_MAGIC] += scrl; + + if (scrollPos[menu_MAGIC] >= 600) { + scrolled[menu_MAGIC] = true; + scrollPos [menu_MAGIC] = 600; + } + } + if (redraw) { + _engine->getRenderManager()->blitSurfaceToMenu(menuback[menu_MAGIC][0], 640 - scrollPos[menu_MAGIC], 0); + + for (int i = 0; i < 12; i++) { + bool inrect = false; + + if (mouseOnItem == i) + inrect = true; + + uint curItemId = _engine->getScriptManager()->getStateValue(SLOT_SPELL_1 + i); + if (curItemId) { + if (_engine->getScriptManager()->getStateValue(SLOT_REVERSED_SPELLBOOK) == 1) + curItemId = 0xEE + i; + else + curItemId = 0xE0 + i; + } + + if (curItemId != 0) { + if (itemId[i] != curItemId) { + char buf[16]; + sprintf(buf, "gmzwu%2.2x1.tga", curItemId); + magic[i][0] = _engine->getRenderManager()->loadImage(buf, false); + sprintf(buf, "gmzxu%2.2x1.tga", curItemId); + magic[i][1] = _engine->getRenderManager()->loadImage(buf, false); + magicId[i] = curItemId; + } + + if (inrect) + _engine->getRenderManager()->blitSurfaceToMenu(*magic[i][1], 668 + 47 * i - scrollPos[menu_MAGIC], 0, 0); + else + _engine->getRenderManager()->blitSurfaceToMenu(*magic[i][0], 668 + 47 * i - scrollPos[menu_MAGIC], 0, 0); + + } else { + if (magic[i][0]) { + magic[i][0]->free(); + delete magic[i][0]; + magic[i][0] = NULL; + } + if (magic[i][1]) { + magic[i][1]->free(); + delete magic[i][1]; + magic[i][1] = NULL; + } + magicId[i] = 0; + } + } + redraw = false; + } + break; + + case menu_MAIN: + if (!scrolled[menu_MAIN]) { + redraw = true; + float scrl = 32.0 * 2.0 * (deltatime / 1000.0); + + if (scrl == 0) + scrl = 1.0; + + scrollPos [menu_MAIN] += scrl; + + if (scrollPos[menu_MAIN] >= 0) { + scrolled[menu_MAIN] = true; + scrollPos [menu_MAIN] = 0; + } + } + if (redraw) { + _engine->getRenderManager()->blitSurfaceToMenu(menuback[menu_MAIN][0], 30, scrollPos[menu_MAIN]); + + if (menuBarFlag & menuBar_Exit) { + if (mouseOnItem == menu_MAIN_EXIT) + _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_EXIT][1], 320 + 135, scrollPos[menu_MAIN]); + else + _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_EXIT][0], 320 + 135, scrollPos[menu_MAIN]); + } + if (menuBarFlag & menuBar_Settings) { + if (mouseOnItem == menu_MAIN_PREF) + _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_PREF][1], 320, scrollPos[menu_MAIN]); + else + _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_PREF][0], 320, scrollPos[menu_MAIN]); + } + if (menuBarFlag & menuBar_Restore) { + if (mouseOnItem == menu_MAIN_REST) + _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_REST][1], 320 - 135, scrollPos[menu_MAIN]); + else + _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_REST][0], 320 - 135, scrollPos[menu_MAIN]); + } + if (menuBarFlag & menuBar_Save) { + if (mouseOnItem == menu_MAIN_SAVE) + _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_SAVE][1], 320 - 135 * 2, scrollPos[menu_MAIN]); + else + _engine->getRenderManager()->blitSurfaceToMenu(menubar[menu_MAIN_SAVE][0], 320 - 135 * 2, scrollPos[menu_MAIN]); + } + redraw = false; + } + break; + default: + if (redraw) { + if (inmenu) { + _engine->getRenderManager()->blitSurfaceToMenu(menuback[menu_MAIN][1], 30, 0); + + if (menuBarFlag & menuBar_Items) + _engine->getRenderManager()->blitSurfaceToMenu(menuback[menu_ITEM][1], 0, 0); + + if (menuBarFlag & menuBar_Magic) + _engine->getRenderManager()->blitSurfaceToMenu(menuback[menu_MAGIC][1], 640 - 28, 0); + } + redraw = false; + } + break; + } +} + +MenuNemesis::MenuNemesis(ZVision *engine) : + MenuHandler(engine) { + inmenu = false; + scrolled = false; + scrollPos = 0.0; + mouseOnItem = -1; + + char buf[24]; + for (int i = 0; i < 4; i++) + for (int j = 0; j < 6; j++) { + sprintf(buf, "butfrm%d%d.tga", i + 1, j); + _engine->getRenderManager()->readImageToSurface(buf, but[i][j], false); + } + + _engine->getRenderManager()->readImageToSurface("bar.tga", menubar, false); + + frm = 0; +} + +MenuNemesis::~MenuNemesis() { + for (int i = 0; i < 4; i++) + for (int j = 0; j < 6; j++) + but[i][j].free(); + + menubar.free(); +} + +static const int16 buts[4][2] = { {120 , 64}, {144, 184}, {128, 328}, {120, 456} }; + +void MenuNemesis::onMouseUp(const Common::Point &Pos) { + if (Pos.y < 40) { + // Exit + if (menuBarFlag & menuBar_Exit) + if (Common::Rect(buts[3][1], + scrollPos, + buts[3][0] + buts[3][1], + scrollPos + 32).contains(Pos)) { + _engine->ifQuit(); + frm = 5; + redraw = true; + } + + // Settings + if (menuBarFlag & menuBar_Settings) + if (Common::Rect(buts[2][1], + scrollPos, + buts[2][0] + buts[2][1], + scrollPos + 32).contains(Pos)) { + _engine->getScriptManager()->changeLocation('g', 'j', 'p', 'e', 0); + frm = 5; + redraw = true; + } + + // Load + if (menuBarFlag & menuBar_Restore) + if (Common::Rect(buts[1][1], + scrollPos, + buts[1][0] + buts[1][1], + scrollPos + 32).contains(Pos)) { + _engine->getScriptManager()->changeLocation('g', 'j', 'r', 'e', 0); + frm = 5; + redraw = true; + } + + // Save + if (menuBarFlag & menuBar_Save) + if (Common::Rect(buts[0][1], + scrollPos, + buts[0][0] + buts[0][1], + scrollPos + 32).contains(Pos)) { + _engine->getScriptManager()->changeLocation('g', 'j', 's', 'e', 0); + frm = 5; + redraw = true; + } + } +} + +void MenuNemesis::onMouseMove(const Common::Point &Pos) { + if (Pos.y < 40) { + + inmenu = true; + + if (_engine->getScriptManager()->getStateValue(StateKey_MenuState) != 2) + _engine->getScriptManager()->setStateValue(StateKey_MenuState, 2); + + int lastItem = mouseOnItem; + mouseOnItem = -1; + + // Exit + if (menuBarFlag & menuBar_Exit) + if (Common::Rect(buts[3][1], + scrollPos, + buts[3][0] + buts[3][1], + scrollPos + 32).contains(Pos)) { + mouseOnItem = menu_MAIN_EXIT; + } + + // Settings + if (menuBarFlag & menuBar_Settings) + if (Common::Rect(buts[2][1], + scrollPos, + buts[2][0] + buts[2][1], + scrollPos + 32).contains(Pos)) { + mouseOnItem = menu_MAIN_PREF; + } + + // Load + if (menuBarFlag & menuBar_Restore) + if (Common::Rect(buts[1][1], + scrollPos, + buts[1][0] + buts[1][1], + scrollPos + 32).contains(Pos)) { + mouseOnItem = menu_MAIN_REST; + } + + // Save + if (menuBarFlag & menuBar_Save) + if (Common::Rect(buts[0][1], + scrollPos, + buts[0][0] + buts[0][1], + scrollPos + 32).contains(Pos)) { + mouseOnItem = menu_MAIN_SAVE; + } + + if (lastItem != mouseOnItem) { + redraw = true; + frm = 0; + delay = 200; + } + } else { + inmenu = false; + if (_engine->getScriptManager()->getStateValue(StateKey_MenuState) != 0) + _engine->getScriptManager()->setStateValue(StateKey_MenuState, 0); + mouseOnItem = -1; + } +} + +void MenuNemesis::process(uint32 deltatime) { + if (inmenu) { + if (!scrolled) { + float scrl = 32.0 * 2.0 * (deltatime / 1000.0); + + if (scrl == 0) + scrl = 1.0; + + scrollPos += scrl; + redraw = true; + } + + if (scrollPos >= 0) { + scrolled = true; + scrollPos = 0; + } + + if (mouseOnItem != -1) { + delay -= deltatime; + if (delay <= 0 && frm < 4) { + delay = 200; + frm++; + redraw = true; + } + } + + if (redraw) { + _engine->getRenderManager()->blitSurfaceToMenu(menubar, 64, scrollPos); + + if (menuBarFlag & menuBar_Exit) + if (mouseOnItem == menu_MAIN_EXIT) + _engine->getRenderManager()->blitSurfaceToMenu(but[3][frm], buts[3][1], scrollPos); + + if (menuBarFlag & menuBar_Settings) + if (mouseOnItem == menu_MAIN_PREF) + _engine->getRenderManager()->blitSurfaceToMenu(but[2][frm], buts[2][1], scrollPos); + + if (menuBarFlag & menuBar_Restore) + if (mouseOnItem == menu_MAIN_REST) + _engine->getRenderManager()->blitSurfaceToMenu(but[1][frm], buts[1][1], scrollPos); + + if (menuBarFlag & menuBar_Save) + if (mouseOnItem == menu_MAIN_SAVE) + _engine->getRenderManager()->blitSurfaceToMenu(but[0][frm], buts[0][1], scrollPos); + + redraw = false; + } + } else { + scrolled = false; + if (scrollPos > -32) { + float scrl = 32.0 * 2.0 * (deltatime / 1000.0); + + if (scrl == 0) + scrl = 1.0; + + Common::Rect cl(64, 32 + scrollPos - scrl, 64 + 512, 32 + scrollPos + 1); + _engine->getRenderManager()->clearMenuSurface(cl); + + scrollPos -= scrl; + redraw = true; + } else + scrollPos = -32; + + if (redraw) { + _engine->getRenderManager()->blitSurfaceToMenu(menubar, 64, scrollPos); + redraw = false; + } + } +} + +} // End of namespace ZVision diff --git a/engines/zvision/core/menu.h b/engines/zvision/core/menu.h index 3ab6d4c2ec..ebe0bb50ac 100644 --- a/engines/zvision/core/menu.h +++ b/engines/zvision/core/menu.h @@ -23,6 +23,103 @@ #ifndef ZVISION_MENU_H #define ZVISION_MENU_H -// TODO: Implement MenuHandler +#include "graphics/surface.h" +#include "common/rect.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" + +namespace ZVision { + +enum menuBar { + menuBar_Exit = 0x1, + menuBar_Settings = 0x2, + menuBar_Restore = 0x4, + menuBar_Save = 0x8, + menuBar_Items = 0x100, + menuBar_Magic = 0x200 +}; + +class MenuHandler { +public: + MenuHandler(ZVision *engine); + virtual ~MenuHandler() {}; + virtual void onMouseMove(const Common::Point &Pos) {}; + virtual void onMouseDown(const Common::Point &Pos) {}; + virtual void onMouseUp(const Common::Point &Pos) {}; + virtual void process(uint32 deltaTimeInMillis) {}; + + void setEnable(uint16 flags) { + menuBarFlag = flags; + } + uint16 getEnable() { + return menuBarFlag; + } +protected: + uint16 menuBarFlag; + ZVision *_engine; +}; + +class MenuZGI: public MenuHandler { +public: + MenuZGI(ZVision *engine); + ~MenuZGI(); + void onMouseMove(const Common::Point &Pos); + void onMouseUp(const Common::Point &Pos); + void process(uint32 deltaTimeInMillis); +private: + Graphics::Surface menuback[3][2]; + Graphics::Surface menubar[4][2]; + Graphics::Surface *items[50][2]; + uint itemId[50]; + + Graphics::Surface *magic[12][2]; + uint magicId[12]; + + int menuMouseFocus; + bool inmenu; + + int mouseOnItem; + + bool scrolled[3]; + int16 scrollPos[3]; + + enum { + menu_ITEM = 0, + menu_MAGIC = 1, + menu_MAIN = 2 + }; + + bool clean; + bool redraw; + +}; + +class MenuNemesis: public MenuHandler { +public: + MenuNemesis(ZVision *engine); + ~MenuNemesis(); + void onMouseMove(const Common::Point &Pos); + void onMouseUp(const Common::Point &Pos); + void process(uint32 deltaTimeInMillis); +private: + Graphics::Surface but[4][6]; + Graphics::Surface menubar; + + bool inmenu; + + int mouseOnItem; + + bool scrolled; + int16 scrollPos; + + bool redraw; + + int frm; + int16 delay; + +}; + +} #endif diff --git a/engines/zvision/core/midi.cpp b/engines/zvision/core/midi.cpp new file mode 100644 index 0000000000..736be1311d --- /dev/null +++ b/engines/zvision/core/midi.cpp @@ -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 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/core/midi.h" + +namespace ZVision { + +MidiManager::MidiManager() { + MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB); + _driver = MidiDriver::createMidi(dev); + _driver->open(); +} + +MidiManager::~MidiManager() { + stop(); + _driver->close(); + delete _driver; +} + +void MidiManager::stop() { + for (int8 i = 0; i < 16; i++) + if (_playChannels[i].playing) + noteOff(i); +} + +void MidiManager::noteOn(int8 channel, int8 note, int8 velocity) { + assert(channel <= 15); + + _playChannels[channel].playing = true; + _playChannels[channel].note = note; + _driver->send(channel | (velocity << 16) | (note << 8) | 0x90); +} + +void MidiManager::noteOff(int8 channel) { + assert(channel <= 15); + + if (_playChannels[channel].playing) { + _playChannels[channel].playing = false; + _driver->send(channel | (_playChannels[channel].note << 8) | 0x80); + } +} + +int8 MidiManager::getFreeChannel() { + for (int8 i = 0; i < 16; i++) + if (!_playChannels[i].playing) + return i; + return -1; +} + +void MidiManager::setPan(int8 channel, int8 pan) { + assert(channel <= 15); + + _driver->send(channel | (pan << 16) | 0xAB0); +} + +void MidiManager::setVolume(int8 channel, int8 volume) { + assert(channel <= 15); + + _driver->send(channel | (volume << 16) | 0x7B0); +} + +void MidiManager::setProgram(int8 channel, int8 prog) { + assert(channel <= 15); + + _driver->send(channel | (prog << 8) | 0xC0); +} + +} // End of namespace ZVision diff --git a/engines/zvision/core/midi.h b/engines/zvision/core/midi.h new file mode 100644 index 0000000000..a3bac19636 --- /dev/null +++ b/engines/zvision/core/midi.h @@ -0,0 +1,59 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_MIDI_H +#define ZVISION_MIDI_H + +#include "audio/mididrv.h" + +namespace ZVision { + +class MidiManager { +public: + MidiManager(); + ~MidiManager(); + + void stop(); + void noteOn(int8 channel, int8 noteNumber, int8 velocity); + void noteOff(int8 channel); + void setPan(int8 channel, int8 pan); + void setVolume(int8 channel, int8 volume); + void setProgram(int8 channel, int8 prog); + + int8 getFreeChannel(); + +protected: + + struct chan { + bool playing; + int8 note; + + chan() : playing(false), note(0) {}; + }; + + MidiDriver *_driver; + chan _playChannels[16]; +}; + +} + +#endif diff --git a/engines/zvision/core/save_manager.cpp b/engines/zvision/core/save_manager.cpp index e10201e024..11d3dd391a 100644 --- a/engines/zvision/core/save_manager.cpp +++ b/engines/zvision/core/save_manager.cpp @@ -35,75 +35,67 @@ #include "gui/message.h" - namespace ZVision { const uint32 SaveManager::SAVEGAME_ID = MKTAG('Z', 'E', 'N', 'G'); void SaveManager::saveGame(uint slot, const Common::String &saveName) { // The games only support 20 slots - assert(slot <= 1 && slot <= 20); + //assert(slot <= 1 && slot <= 20); Common::SaveFileManager *saveFileManager = g_system->getSavefileManager(); Common::OutSaveFile *file = saveFileManager->openForSaving(_engine->generateSaveFileName(slot)); - // Write out the savegame header - file->writeUint32BE(SAVEGAME_ID); - - // Write version - file->writeByte(SAVE_VERSION); + writeSaveGameHeader(file, saveName); - // Write savegame name - file->writeString(saveName); - file->writeByte(0); + _engine->getScriptManager()->serialize(file); - // We can't call writeGameSaveData because the save menu is actually - // a room, so writeGameSaveData would save us in the save menu. - // However, an auto save is performed before each room change, so we - // can copy the data from there. We can guarantee that an auto save file will - // exist before this is called because the save menu can only be accessed - // after the first room (the main menu) has loaded. - Common::InSaveFile *autoSaveFile = saveFileManager->openForLoading(_engine->generateAutoSaveFileName()); + file->finalize(); + delete file; +} - // Skip over the header info - autoSaveFile->readSint32BE(); // SAVEGAME_ID - autoSaveFile->readByte(); // Version - autoSaveFile->seek(5, SEEK_CUR); // The string "auto" with terminating NULL +void SaveManager::saveGame(uint slot, const Common::String &saveName, Common::MemoryWriteStreamDynamic *stream) { + Common::SaveFileManager *saveFileManager = g_system->getSavefileManager(); + Common::OutSaveFile *file = saveFileManager->openForSaving(_engine->generateSaveFileName(slot)); - // Read the rest to a buffer - uint32 size = autoSaveFile->size() - autoSaveFile->pos(); - byte *buffer = new byte[size]; - autoSaveFile->read(buffer, size); + writeSaveGameHeader(file, saveName); - // Then write the buffer to the new file - file->write(buffer, size); + file->write(stream->getData(), stream->size()); - // Cleanup - delete[] buffer; file->finalize(); delete file; } +void SaveManager::saveGameBuffered(uint slot, const Common::String &saveName) { + if (_tempSave) { + saveGame(slot, saveName, _tempSave); + flushSaveBuffer(); + } +} + void SaveManager::autoSave() { Common::OutSaveFile *file = g_system->getSavefileManager()->openForSaving(_engine->generateAutoSaveFileName()); - // Write out the savegame header - file->writeUint32BE(SAVEGAME_ID); - - // Version - file->writeByte(SAVE_VERSION); - - file->writeString("auto"); - file->writeByte(0); + writeSaveGameHeader(file, "auto"); - writeSaveGameData(file); + _engine->getScriptManager()->serialize(file); // Cleanup file->finalize(); delete file; } -void SaveManager::writeSaveGameData(Common::OutSaveFile *file) { +void SaveManager::writeSaveGameHeader(Common::OutSaveFile *file, const Common::String &saveName) { + + file->writeUint32BE(SAVEGAME_ID); + + // Write version + file->writeByte(SAVE_VERSION); + + // Write savegame name + file->writeString(saveName); + file->writeByte(0); + // Create a thumbnail and save it Graphics::saveThumbnail(*file); @@ -115,28 +107,13 @@ void SaveManager::writeSaveGameData(Common::OutSaveFile *file) { file->writeSint16LE(td.tm_mday); file->writeSint16LE(td.tm_hour); file->writeSint16LE(td.tm_min); - - ScriptManager *scriptManager = _engine->getScriptManager(); - // Write out the current location - Location currentLocation = scriptManager->getCurrentLocation(); - file->writeByte(currentLocation.world); - file->writeByte(currentLocation.room); - file->writeByte(currentLocation.node); - file->writeByte(currentLocation.view); - file->writeUint32LE(currentLocation.offset); - - // Write out the current state table values - scriptManager->serializeStateTable(file); - - // Write out any controls needing to save state - scriptManager->serializeControls(file); } Common::Error SaveManager::loadGame(uint slot) { // The games only support 20 slots - assert(slot <= 1 && slot <= 20); + //assert(slot <= 1 && slot <= 20); - Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(_engine->generateSaveFileName(slot)); + Common::SeekableReadStream *saveFile = getSlotFile(slot); if (saveFile == 0) { return Common::kPathDoesNotExist; } @@ -147,27 +124,60 @@ Common::Error SaveManager::loadGame(uint slot) { return Common::kUnknownError; } - char world = (char)saveFile->readByte(); - char room = (char)saveFile->readByte(); - char node = (char)saveFile->readByte(); - char view = (char)saveFile->readByte(); - uint32 offset = (char)saveFile->readUint32LE(); - ScriptManager *scriptManager = _engine->getScriptManager(); // Update the state table values - scriptManager->deserializeStateTable(saveFile); + scriptManager->deserialize(saveFile); + + delete saveFile; + if (header.thumbnail) + delete header.thumbnail; + + return Common::kNoError; +} - // Load the room - scriptManager->changeLocation(world, room, node, view, offset); +Common::Error SaveManager::loadGame(const Common::String &saveName) { + Common::File *saveFile = _engine->getSearchManager()->openFile(saveName); + if (saveFile == NULL) { + saveFile = new Common::File; + if (!saveFile->open(saveName)) { + delete saveFile; + return Common::kPathDoesNotExist; + } + } - // Update the controls - scriptManager->deserializeControls(saveFile); + // Read the header + SaveGameHeader header; + if (!readSaveGameHeader(saveFile, header)) { + return Common::kUnknownError; + } + + ScriptManager *scriptManager = _engine->getScriptManager(); + // Update the state table values + scriptManager->deserialize(saveFile); + + delete saveFile; + if (header.thumbnail) + delete header.thumbnail; return Common::kNoError; } bool SaveManager::readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header) { - if (in->readUint32BE() != SAVEGAME_ID) { + uint32 tag = in->readUint32BE(); + // Check if it's original savegame than fill header structure + if (tag == MKTAG('Z', 'N', 'S', 'G')) { + header.saveYear = 0; + header.saveMonth = 0; + header.saveDay = 0; + header.saveHour = 0; + header.saveMinutes = 0; + header.saveName = "Original Save"; + header.thumbnail = NULL; + header.version = SAVE_ORIGINAL; + in->seek(-4, SEEK_CUR); + return true; + } + if (tag != SAVEGAME_ID) { warning("File is not a ZVision save file. Aborting load"); return false; } @@ -203,4 +213,45 @@ bool SaveManager::readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &hea return true; } +Common::SeekableReadStream *SaveManager::getSlotFile(uint slot) { + Common::SeekableReadStream *saveFile = g_system->getSavefileManager()->openForLoading(_engine->generateSaveFileName(slot)); + if (saveFile == NULL) { + // Try to load standard save file + Common::String filename; + if (_engine->getGameId() == GID_GRANDINQUISITOR) + filename = Common::String::format("inqsav%u.sav", slot); + else if (_engine->getGameId() == GID_NEMESIS) + filename = Common::String::format("nemsav%u.sav", slot); + + saveFile = _engine->getSearchManager()->openFile(filename); + if (saveFile == NULL) { + Common::File *tmpFile = new Common::File; + if (!tmpFile->open(filename)) { + delete tmpFile; + } else { + saveFile = tmpFile; + } + } + + } + + return saveFile; +} + +void SaveManager::prepareSaveBuffer() { + if (_tempSave) + delete _tempSave; + + _tempSave = new Common::MemoryWriteStreamDynamic; + + _engine->getScriptManager()->serialize(_tempSave); +} + +void SaveManager::flushSaveBuffer() { + if (_tempSave) + delete _tempSave; + + _tempSave = NULL; +} + } // End of namespace ZVision diff --git a/engines/zvision/core/save_manager.h b/engines/zvision/core/save_manager.h index 43fb0c0faf..5cd61c7aa9 100644 --- a/engines/zvision/core/save_manager.h +++ b/engines/zvision/core/save_manager.h @@ -24,6 +24,7 @@ #define ZVISION_SAVE_MANAGER_H #include "common/savefile.h" +#include "common/memstream.h" namespace Common { class String; @@ -47,16 +48,22 @@ struct SaveGameHeader { class SaveManager { public: - SaveManager(ZVision *engine) : _engine(engine) {} + SaveManager(ZVision *engine) : _engine(engine), _tempSave(NULL) {} + ~SaveManager() { + flushSaveBuffer(); + } private: ZVision *_engine; static const uint32 SAVEGAME_ID; enum { + SAVE_ORIGINAL = 0, SAVE_VERSION = 1 }; + Common::MemoryWriteStreamDynamic *_tempSave; + public: /** * Called every room change. Saves the state of the room just before @@ -73,6 +80,8 @@ public: * @param saveName The internal name for this save. This is NOT the name of the actual save file. */ void saveGame(uint slot, const Common::String &saveName); + void saveGame(uint slot, const Common::String &saveName, Common::MemoryWriteStreamDynamic *stream); + void saveGameBuffered(uint slot, const Common::String &saveName); /** * Loads the state data from the save file that slot references. Uses * ZVision::generateSaveFileName(slot) to get the save file name. @@ -80,10 +89,15 @@ public: * @param slot The save slot to load. Must be [1, 20] */ Common::Error loadGame(uint slot); + Common::Error loadGame(const Common::String &saveName); + + Common::SeekableReadStream *getSlotFile(uint slot); + bool readSaveGameHeader(Common::SeekableReadStream *in, SaveGameHeader &header); + void prepareSaveBuffer(); + void flushSaveBuffer(); private: - void writeSaveGameData(Common::OutSaveFile *file); - bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header); + void writeSaveGameHeader(Common::OutSaveFile *file, const Common::String &saveName); }; } // End of namespace ZVision diff --git a/engines/zvision/core/search_manager.cpp b/engines/zvision/core/search_manager.cpp new file mode 100644 index 0000000000..9c5d8fb323 --- /dev/null +++ b/engines/zvision/core/search_manager.cpp @@ -0,0 +1,273 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#include "common/debug.h" +#include "common/fs.h" +#include "common/stream.h" + +#include "zvision/core/search_manager.h" +#include "zvision/utility/zfs_archive.h" + +namespace ZVision { + +SearchManager::SearchManager(const Common::String &rootPath, int depth) { + _root = rootPath; + if (_root[_root.size() - 1] == '\\' || _root[_root.size() - 1] == '/') + _root.deleteLastChar(); + + Common::FSNode fsNode(_root); + + listDirRecursive(dirList, fsNode, depth); + + for (Common::List<Common::String>::iterator it = dirList.begin(); it != dirList.end();) + if (it->size() == _root.size()) + it = dirList.erase(it); + else if (it->size() > _root.size()) { + *it = Common::String(it->c_str() + _root.size() + 1); + it++; + } else + it++; +} + +SearchManager::~SearchManager() { + Common::List<Common::Archive *>::iterator it = archList.begin(); + while (it != archList.end()) { + delete *it; + it++; + } + + archList.clear(); +} + +void SearchManager::addPatch(const Common::String &src, const Common::String &dst) { + Common::String lowerCaseName = dst; + lowerCaseName.toLowercase(); + + SearchManager::MatchList::iterator it = files.find(lowerCaseName); + + if (it != files.end()) { + lowerCaseName = src; + lowerCaseName.toLowercase(); + files[lowerCaseName] = it->_value; + } +} + +void SearchManager::addFile(const Common::String &name, Common::Archive *arch) { + bool addArch = true; + Common::List<Common::Archive *>::iterator it = archList.begin(); + while (it != archList.end()) { + if (*it == arch) { + addArch = false; + break; + } + it++; + } + if (addArch) + archList.push_back(arch); + + Common::String lowerCaseName = name; + lowerCaseName.toLowercase(); + + SearchManager::Node nod; + nod.name = lowerCaseName; + nod.arch = arch; + + SearchManager::MatchList::iterator fit = files.find(lowerCaseName); + + if (fit == files.end()) { + files[lowerCaseName] = nod; + } else { + Common::SeekableReadStream *stream = fit->_value.arch->createReadStreamForMember(fit->_value.name); + if (stream) { + if (stream->size() < 10) + fit->_value.arch = arch; + delete stream; + } else { + files[lowerCaseName] = nod; + } + } +} + +Common::File *SearchManager::openFile(const Common::String &name) { + Common::String lowerCaseName = name; + lowerCaseName.toLowercase(); + + SearchManager::MatchList::iterator fit = files.find(lowerCaseName); + + if (fit != files.end()) { + Common::File *tmp = new Common::File(); + tmp->open(fit->_value.name, *fit->_value.arch); + return tmp; + } + return NULL; +} + +bool SearchManager::openFile(Common::File &file, const Common::String &name) { + Common::String lowerCaseName = name; + lowerCaseName.toLowercase(); + + SearchManager::MatchList::iterator fit = files.find(lowerCaseName); + + if (fit != files.end()) + return file.open(fit->_value.name, *fit->_value.arch); + return false; +} + +bool SearchManager::hasFile(const Common::String &name) { + Common::String lowerCaseName = name; + lowerCaseName.toLowercase(); + + SearchManager::MatchList::iterator fit = files.find(lowerCaseName); + + if (fit != files.end()) + return true; + return false; +} + +void SearchManager::loadZix(const Common::String &name) { + Common::File file; + file.open(name); + + Common::String line; + + while (!file.eos()) { + line = file.readLine(); + if (line.matchString("----------*", true)) + break; + } + + if (file.eos()) + return; + + Common::Array<Common::Archive *> archives; + + while (!file.eos()) { + line = file.readLine(); + line.trim(); + if (line.matchString("----------*", true)) + break; + else if (line.matchString("DIR:*", true)) { + Common::String path(line.c_str() + 5); + Common::Archive *arc; + char tempPath[128]; + strcpy(tempPath, path.c_str()); + for (uint i = 0; i < path.size(); i++) + if (tempPath[i] == '\\') + tempPath[i] = '/'; + + path = Common::String(tempPath); + if (path.size() && path[0] == '.') + path.deleteChar(0); + if (path.size() && path[0] == '/') + path.deleteChar(0); + + if (path.matchString("*.zfs", true)) + arc = new ZfsArchive(path); + else { + if (path.size()) { + if (path[path.size() - 1] == '\\' || path[path.size() - 1] == '/') + path.deleteLastChar(); + if (path.size()) + for (Common::List<Common::String>::iterator it = dirList.begin(); it != dirList.end(); ++it) + if (path.equalsIgnoreCase(*it)) { + path = *it; + break; + } + } + + path = Common::String::format("%s/%s", _root.c_str(), path.c_str()); + + arc = new Common::FSDirectory(path); + } + archives.push_back(arc); + } + } + + if (file.eos()) + return; + + while (!file.eos()) { + line = file.readLine(); + line.trim(); + uint dr = 0; + char buf[32]; + if (sscanf(line.c_str(), "%u %s", &dr, buf) == 2) { + if (dr <= archives.size() && dr > 0) { + addFile(Common::String(buf), archives[dr - 1]); + } + } + } +} + +void SearchManager::addDir(const Common::String &name) { + Common::String path; + for (Common::List<Common::String>::iterator it = dirList.begin(); it != dirList.end(); ++it) + if (name.equalsIgnoreCase(*it)) { + path = *it; + break; + } + + if (path.size() == 0) + return; + + path = Common::String::format("%s/%s", _root.c_str(), path.c_str()); + + Common::FSDirectory *dir = new Common::FSDirectory(path); + + Common::ArchiveMemberList list; + dir->listMatchingMembers(list, "*.zfs"); + + for (Common::ArchiveMemberList::iterator iter = list.begin(); iter != list.end(); ++iter) { + Common::String flname = (*iter)->getName(); + + ZfsArchive *zfs = new ZfsArchive(Common::String::format("%s/%s", name.c_str(), flname.c_str())); + + Common::ArchiveMemberList zfslist; + zfs->listMembers(zfslist); + + for (Common::ArchiveMemberList::iterator ziter = zfslist.begin(); ziter != zfslist.end(); ++ziter) { + Common::String zfsFileName = (*ziter)->getName(); + addFile(zfsFileName, zfs); + } + } + + list.clear(); + dir->listMembers(list); + + for (Common::ArchiveMemberList::iterator iter = list.begin(); iter != list.end(); ++iter) { + Common::String flname = (*iter)->getName(); + addFile(flname, dir); + } +} + +void SearchManager::listDirRecursive(Common::List<Common::String> &_list, const Common::FSNode &fsNode, int depth) { + Common::FSList fsList; + fsNode.getChildren(fsList); + + _list.push_back(fsNode.getPath()); + + if (depth > 1) + for (Common::FSList::const_iterator it = fsList.begin(); it != fsList.end(); ++it) + listDirRecursive(_list, *it, depth - 1); +} + +} // End of namespace ZVision diff --git a/engines/zvision/core/search_manager.h b/engines/zvision/core/search_manager.h new file mode 100644 index 0000000000..180102eac6 --- /dev/null +++ b/engines/zvision/core/search_manager.h @@ -0,0 +1,73 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_SEARCH_MANAGER_H +#define ZVISION_SEARCH_MANAGER_H + +#include "common/str.h" +#include "common/hash-str.h" +#include "common/hashmap.h" +#include "common/archive.h" +#include "common/file.h" +#include "common/list.h" + +namespace ZVision { + +class SearchManager { +public: + SearchManager(const Common::String &rootPath, int depth); + ~SearchManager(); + + void addFile(const Common::String &name, Common::Archive *arch); + void addDir(const Common::String &name); + void addPatch(const Common::String &src, const Common::String &dst); + + Common::File *openFile(const Common::String &name); + bool openFile(Common::File &file, const Common::String &name); + bool hasFile(const Common::String &name); + + void loadZix(const Common::String &name); + +private: + + void listDirRecursive(Common::List<Common::String> &dirList, const Common::FSNode &fsNode, int depth); + + struct Node { + Common::String name; + Common::Archive *arch; + }; + + Common::List<Common::String> dirList; + + typedef Common::HashMap<Common::String, Node, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> MatchList; + + Common::List<Common::Archive *> archList; + MatchList files; + + Common::String _root; + +private: +}; + +} + +#endif // ZVISION_SEARCH_MANAGER_H diff --git a/engines/zvision/cursors/cursor.cpp b/engines/zvision/cursors/cursor.cpp index 9b9b9a3f71..b07220df92 100644 --- a/engines/zvision/cursors/cursor.cpp +++ b/engines/zvision/cursors/cursor.cpp @@ -1,24 +1,24 @@ /* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ #include "common/scummsys.h" @@ -27,7 +27,6 @@ #include "common/str.h" #include "common/file.h" - namespace ZVision { ZorkCursor::ZorkCursor() @@ -38,10 +37,10 @@ ZorkCursor::ZorkCursor() } ZorkCursor::ZorkCursor(const Common::String &fileName) - : _width(0), - _height(0), - _hotspotX(0), - _hotspotY(0) { + : _width(0), + _height(0), + _hotspotX(0), + _hotspotY(0) { Common::File file; if (!file.open(fileName)) return; @@ -66,6 +65,35 @@ ZorkCursor::ZorkCursor(const Common::String &fileName) _surface.convertToInPlace(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)); } +ZorkCursor::ZorkCursor(ZVision *engine, const Common::String &fileName) + : _width(0), + _height(0), + _hotspotX(0), + _hotspotY(0) { + Common::File file; + if (!engine->getSearchManager()->openFile(file, fileName)) + return; + + uint32 magic = file.readUint32BE(); + if (magic != MKTAG('Z', 'C', 'R', '1')) { + warning("%s is not a Zork Cursor file", fileName.c_str()); + return; + } + + _hotspotX = file.readUint16LE(); + _hotspotY = file.readUint16LE(); + _width = file.readUint16LE(); + _height = file.readUint16LE(); + + uint dataSize = _width * _height * sizeof(uint16); + _surface.create(_width, _height, Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0)); + uint32 bytesRead = file.read(_surface.getPixels(), dataSize); + assert(bytesRead == dataSize); + + // Convert to RGB 565 + _surface.convertToInPlace(Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)); +} + ZorkCursor::ZorkCursor(const ZorkCursor &other) { _width = other._width; _height = other._height; diff --git a/engines/zvision/cursors/cursor.h b/engines/zvision/cursors/cursor.h index be9fae64da..0c1e99411f 100644 --- a/engines/zvision/cursors/cursor.h +++ b/engines/zvision/cursors/cursor.h @@ -24,7 +24,7 @@ #define ZVISION_CURSOR_H #include "graphics/surface.h" - +#include "zvision/zvision.h" namespace Common { class String; @@ -40,6 +40,7 @@ class ZorkCursor { public: ZorkCursor(); ZorkCursor(const Common::String &fileName); + ZorkCursor(ZVision *engine, const Common::String &fileName); ZorkCursor(const ZorkCursor &other); ~ZorkCursor(); @@ -53,12 +54,24 @@ private: public: ZorkCursor &operator=(const ZorkCursor &other); - uint16 getWidth() const { return _width; } - uint16 getHeight() const { return _height; } - uint16 getHotspotX() const { return _hotspotX; } - uint16 getHotspotY() const { return _hotspotY; } - byte getKeyColor() const { return 0; } - const byte *getSurface() const { return (const byte *)_surface.getPixels(); } + uint16 getWidth() const { + return _width; + } + uint16 getHeight() const { + return _height; + } + uint16 getHotspotX() const { + return _hotspotX; + } + uint16 getHotspotY() const { + return _hotspotY; + } + byte getKeyColor() const { + return 0; + } + const byte *getSurface() const { + return (const byte *)_surface.getPixels(); + } }; } // End of namespace ZVision diff --git a/engines/zvision/cursors/cursor_manager.cpp b/engines/zvision/cursors/cursor_manager.cpp index 7f70c8b4e3..33fb55515b 100644 --- a/engines/zvision/cursors/cursor_manager.cpp +++ b/engines/zvision/cursors/cursor_manager.cpp @@ -1,24 +1,24 @@ /* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ #include "common/scummsys.h" @@ -31,86 +31,76 @@ #include "graphics/pixelformat.h" #include "graphics/cursorman.h" - namespace ZVision { const char *CursorManager::_cursorNames[NUM_CURSORS] = { "active", "arrow", "backward", "downarrow", "forward", "handpt", "handpu", "hdown", "hleft", - "hright", "hup", "idle", "leftarrow", "rightarrow", "suggest_surround", "suggest_tilt", "turnaround", "zuparrow" }; + "hright", "hup", "idle", "leftarrow", "rightarrow", "suggest_surround", "suggest_tilt", "turnaround", "zuparrow" + }; const char *CursorManager::_zgiCursorFileNames[NUM_CURSORS] = { "g0gbc011.zcr", "g0gac001.zcr", "g0gac021.zcr", "g0gac031.zcr", "g0gac041.zcr", "g0gac051.zcr", "g0gac061.zcr", "g0gac071.zcr", "g0gac081.zcr", - "g0gac091.zcr", "g0gac101.zcr", "g0gac011.zcr", "g0gac111.zcr", "g0gac121.zcr", "g0gac131.zcr", "g0gac141.zcr", "g0gac151.zcr", "g0gac161.zcr" }; + "g0gac091.zcr", "g0gac101.zcr", "g0gac011.zcr", "g0gac111.zcr", "g0gac121.zcr", "g0gac131.zcr", "g0gac141.zcr", "g0gac151.zcr", "g0gac161.zcr" + }; const char *CursorManager::_zNemCursorFileNames[NUM_CURSORS] = { "00act", "arrow", "back", "down", "forw", "handpt", "handpu", "hdown", "hleft", - "hright", "hup", "00idle", "left", "right", "ssurr", "stilt", "turn", "up" }; - + "hright", "hup", "00idle", "left", "right", "ssurr", "stilt", "turn", "up" + }; CursorManager::CursorManager(ZVision *engine, const Graphics::PixelFormat *pixelFormat) - : _engine(engine), - _pixelFormat(pixelFormat), - _cursorIsPushed(false) { - // WARNING: The index IDLE_CURSOR_INDEX is hardcoded. If you change the order of _cursorNames/_zgiCursorFileNames/_zNemCursorFileNames, you HAVE to change the index accordingly - if (_engine->getGameId() == GID_NEMESIS) { - Common::String name(Common::String::format("%sa.zcr", _zNemCursorFileNames[IDLE_CURSOR_INDEX])); - _idleCursor = ZorkCursor(name); - } else if (_engine->getGameId() == GID_GRANDINQUISITOR) { - _idleCursor = ZorkCursor(_zgiCursorFileNames[IDLE_CURSOR_INDEX]); + : _engine(engine), + _pixelFormat(pixelFormat), + _cursorIsPushed(false), + _item(0), + _lastitem(0) { + for (int i = 0; i < NUM_CURSORS; i++) { + if (_engine->getGameId() == GID_NEMESIS) { + Common::String name; + name = Common::String::format("%sa.zcr", _zNemCursorFileNames[i]); + _cursors[i][0] = ZorkCursor(_engine, name); // Up cursor + name = Common::String::format("%sb.zcr", _zNemCursorFileNames[i]); + _cursors[i][1] = ZorkCursor(_engine, name); // Down cursor + } else if (_engine->getGameId() == GID_GRANDINQUISITOR) { + _cursors[i][0] = ZorkCursor(_engine, _zgiCursorFileNames[i]); // Up cursor + char buffer[25]; + strcpy(buffer, _zgiCursorFileNames[i]); + buffer[3] += 2; + _cursors[i][1] = ZorkCursor(_engine, buffer); // Down cursor + } } } -void CursorManager::initialize() { - revertToIdle(); - CursorMan.showMouse(true); -} - -void CursorManager::changeCursor(const Common::String &cursorName) { - changeCursor(cursorName, _cursorIsPushed); -} - -void CursorManager::changeCursor(const Common::String &cursorName, bool pushed) { - if (_currentCursor.equals(cursorName) && _cursorIsPushed == pushed) - return; - - if (_cursorIsPushed != pushed) - _cursorIsPushed = pushed; - - if (cursorName == "idle" && !pushed) { - CursorMan.replaceCursor(_idleCursor.getSurface(), _idleCursor.getWidth(), _idleCursor.getHeight(), _idleCursor.getHotspotX(), _idleCursor.getHotspotY(), _idleCursor.getKeyColor(), false, _pixelFormat); - return; - } - - for (int i = 0; i < NUM_CURSORS; ++i) { - if (_engine->getGameId() == GID_NEMESIS) { - if (cursorName.equals(_cursorNames[i])) { - _currentCursor = cursorName; - - // ZNem uses a/b at the end of the file to signify not pushed/pushed respectively - Common::String pushedFlag = pushed ? "b" : "a"; - Common::String name = Common::String::format("%s%s.zcr", _zNemCursorFileNames[i], pushedFlag.c_str()); - - changeCursor(ZorkCursor(name)); +void CursorManager::setItemID(int id) { + if (id != _item) { + if (id) { + Common::String file; + if (_engine->getGameId() == GID_NEMESIS) { + file = Common::String::format("%2.2d%s%c.zcr", id, "idle", 'a'); + _cursors[NUM_CURSORS][0] = ZorkCursor(_engine, file); + file = Common::String::format("%2.2d%s%c.zcr", id, "idle", 'b'); + _cursors[NUM_CURSORS][1] = ZorkCursor(_engine, file); + file = Common::String::format("%2.2d%s%c.zcr", id, "act", 'a'); + _cursors[NUM_CURSORS + 1][0] = ZorkCursor(_engine, file); + file = Common::String::format("%2.2d%s%c.zcr", id, "act", 'b'); + _cursors[NUM_CURSORS + 1][0] = ZorkCursor(_engine, file); + } else if (_engine->getGameId() == GID_GRANDINQUISITOR) { + file = Common::String::format("g0b%cc%2.2x1.zcr", 'a' , id); + _cursors[NUM_CURSORS][0] = ZorkCursor(_engine, file); + file = Common::String::format("g0b%cc%2.2x1.zcr", 'c' , id); + _cursors[NUM_CURSORS][1] = ZorkCursor(_engine, file); + file = Common::String::format("g0b%cc%2.2x1.zcr", 'b' , id); + _cursors[NUM_CURSORS + 1][0] = ZorkCursor(_engine, file); + file = Common::String::format("g0b%cc%2.2x1.zcr", 'd' , id); + _cursors[NUM_CURSORS + 1][1] = ZorkCursor(_engine, file); + } else return; - } - } else if (_engine->getGameId() == GID_GRANDINQUISITOR) { - if (cursorName.equals(_cursorNames[i])) { - _currentCursor = cursorName; - - if (!pushed) { - changeCursor(ZorkCursor(_zgiCursorFileNames[i])); - } else { - // ZGI flips not pushed/pushed between a/c and b/d - // It flips the 4th character of the name - char buffer[25]; - strcpy(buffer, _zgiCursorFileNames[i]); - buffer[3] += 2; - changeCursor(ZorkCursor(buffer)); - } - return; - } } + _item = id; + changeCursor(CursorIndex_Idle); } +} - // If we get here, something went wrong - warning("No cursor found for identifier %s", cursorName.c_str()); +void CursorManager::initialize() { + changeCursor(_cursors[CursorIndex_Idle][_cursorIsPushed]); + showMouse(true); } void CursorManager::changeCursor(const ZorkCursor &cursor) { @@ -122,31 +112,41 @@ void CursorManager::cursorDown(bool pushed) { return; _cursorIsPushed = pushed; - changeCursor(_currentCursor, pushed); -} -void CursorManager::setLeftCursor() { - changeCursor("leftarrow"); + changeCursor(_cursors[_currentCursor][_cursorIsPushed]); } -void CursorManager::setRightCursor() { - changeCursor("rightarrow"); -} +void CursorManager::changeCursor(int id) { + int _id = id; + + if (_item && + (_id == CursorIndex_Active || + _id == CursorIndex_Idle || + _id == CursorIndex_HandPu)) { -void CursorManager::setUpCursor() { - changeCursor("zuparrow"); + if (_id == CursorIndex_Idle) + _id = CursorIndex_ItemIdle; + else + _id = CursorIndex_ItemAct; + } + + if (_currentCursor != _id || + ((_id == CursorIndex_ItemAct || _id == CursorIndex_ItemIdle) && _lastitem != _item)) { + _currentCursor = _id; + _lastitem = _item; + changeCursor(_cursors[_currentCursor][_cursorIsPushed]); + } } -void CursorManager::setDownCursor() { - changeCursor("downarrow"); +int CursorManager::getCursorId(const Common::String &name) { + for (int i = 0; i < NUM_CURSORS; i++) + if (name.equals(_cursorNames[i])) + return i; + return CursorIndex_Idle; } -void CursorManager::revertToIdle() { - _currentCursor = "idle"; - if (!_cursorIsPushed) - CursorMan.replaceCursor(_idleCursor.getSurface(), _idleCursor.getWidth(), _idleCursor.getHeight(), _idleCursor.getHotspotX(), _idleCursor.getHotspotY(), _idleCursor.getKeyColor(), false, _pixelFormat); - else - changeCursor(_currentCursor, _cursorIsPushed); +void CursorManager::showMouse(bool vis) { + CursorMan.showMouse(vis); } } // End of namespace ZVision diff --git a/engines/zvision/cursors/cursor_manager.h b/engines/zvision/cursors/cursor_manager.h index 0576517f58..460f6fade6 100644 --- a/engines/zvision/cursors/cursor_manager.h +++ b/engines/zvision/cursors/cursor_manager.h @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -27,7 +27,6 @@ #include "common/str.h" - namespace Graphics { struct PixelFormat; } @@ -37,6 +36,21 @@ namespace ZVision { class ZVision; /** + * Mostly usable cursors + */ +enum CursorIndex { + CursorIndex_Active = 0, + CursorIndex_DownArr = 3, + CursorIndex_HandPu = 6, + CursorIndex_Idle = 11, + CursorIndex_Left = 12, + CursorIndex_Right = 13, + CursorIndex_UpArr = 17, + CursorIndex_ItemIdle = 18, + CursorIndex_ItemAct = 19 +}; + +/** * Class to manage cursor changes. The actual changes have to be done * through CursorMan. Otherwise the cursor will disappear after GMM * or debug console. @@ -47,17 +61,17 @@ public: CursorManager(ZVision *engine, const Graphics::PixelFormat *pixelFormat); private: - enum { - NUM_CURSORS = 18, - // WARNING: The index 11 is hardcoded. If you change the order of _cursorNames/_zgiCursorFileNames/_zNemCursorFileNames, you HAVE to change the index accordingly - IDLE_CURSOR_INDEX = 11 - }; + static const int NUM_CURSORS = 18; + + // 18 default cursors in up/down states, +2 for items idle/act cursors + ZorkCursor _cursors[NUM_CURSORS + 2][2]; ZVision *_engine; const Graphics::PixelFormat *_pixelFormat; - ZorkCursor _idleCursor; - Common::String _currentCursor; bool _cursorIsPushed; + int _item; + int _lastitem; + int _currentCursor; static const char *_cursorNames[]; static const char *_zgiCursorFileNames[]; @@ -68,19 +82,30 @@ public: void initialize(); /** - * Parses a cursor name into a cursor file then creates and shows that cursor. - * It will use the current _isCursorPushed state to choose the correct cursor + * Change cursor to specified cursor ID. If item setted to not 0 and cursor id idle/acrive/handpu change cursor to item. + * + * @param id Wanted cursor id. + */ + + void changeCursor(int id); + + /** + * Return founded id for string contains cursor name * - * @param cursorName The name of a cursor. This *HAS* to correspond to one of the entries in _cursorNames[] + * @param name Cursor name + * @return Id of cursor or idle cursor id if not found */ - void changeCursor(const Common::String &cursorName); + + int getCursorId(const Common::String &name); + /** - * Parses a cursor name into a cursor file then creates and shows that cursor. + * Load cursor for item by id, and try to change cursor to item cursor if it's not 0 * - * @param cursorName The name of a cursor. This *HAS* to correspond to one of the entries in _cursorNames[] - * @param pushed Should the cursor be pushed (true) or not pushed (false) (Another way to say it: down or up) + * @param id Item id or 0 for no item cursor */ - void changeCursor(const Common::String &cursorName, bool pushed); + + void setItemID(int id); + /** * Change the cursor to a certain push state. If the cursor is already in the specified push state, nothing will happen. * @@ -88,17 +113,12 @@ public: */ void cursorDown(bool pushed); - /** Set the cursor to 'Left Arrow'. It will retain the current _isCursorPushed state */ - void setLeftCursor(); - /** Set the cursor to 'Right Arrow'. It will retain the current _isCursorPushed state */ - void setRightCursor(); - /** Set the cursor to 'Up Arrow'. It will retain the current _isCursorPushed state */ - void setUpCursor(); - /** Set the cursor to 'Down Arrow'. It will retain the current _isCursorPushed state */ - void setDownCursor(); - - /** Set the cursor to 'Idle'. It will retain the current _isCursorPushed state */ - void revertToIdle(); + /** + * Show or hide mouse cursor. + * + * @param vis Should the cursor be showed (true) or hide (false) + */ + void showMouse(bool vis); private: /** diff --git a/engines/zvision/detection.cpp b/engines/zvision/detection.cpp index 9961db1215..4d210abe86 100644 --- a/engines/zvision/detection.cpp +++ b/engines/zvision/detection.cpp @@ -32,7 +32,6 @@ #include "common/str-array.h" #include "common/system.h" - namespace ZVision { uint32 ZVision::getFeatures() const { @@ -45,7 +44,6 @@ Common::Language ZVision::getLanguage() const { } // End of namespace ZVision - static const PlainGameDescriptor zVisionGames[] = { {"zvision", "ZVision Game"}, {"znemesis", "Zork Nemesis: The Forbidden Lands"}, @@ -53,7 +51,6 @@ static const PlainGameDescriptor zVisionGames[] = { {0, 0} }; - namespace ZVision { static const ZVisionGameDescription gameDescriptions[] = { @@ -73,10 +70,24 @@ static const ZVisionGameDescription gameDescriptions[] = { }, { - // Zork Grand Inquisitor English version + // Zork Nemesis English demo version + { + "znemesis", + "Demo", + AD_ENTRY1s("SCRIPTS.ZFS", "64f1e881394e9462305104f99513c833", 380539), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_DEMO, + GUIO1(GUIO_NONE) + }, + GID_NEMESIS + }, + + { + // Zork Grand Inquisitor English CD version { "zgi", - 0, + "CD", AD_ENTRY1s("SCRIPTS.ZFS", "81efd40ecc3d22531e211368b779f17f", 8336944), Common::EN_ANY, Common::kPlatformWindows, @@ -87,6 +98,34 @@ static const ZVisionGameDescription gameDescriptions[] = { }, { + // Zork Grand Inquisitor English demo version + { + "zgi", + "Demo", + AD_ENTRY1s("SCRIPTS.ZFS", "71a2494fd2fb999347deb13401e9b998", 304239), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_DEMO, + GUIO1(GUIO_NONE) + }, + GID_GRANDINQUISITOR + }, + + { + // Zork Grand Inquisitor English DVD version + { + "zgi", + "DVD", + AD_ENTRY1s("SCRIPTS.ZFS", "03157a3399513bfaaf8dc6d5ab798b36", 8433326), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_NO_FLAGS, + GUIO1(GUIO_NONE) + }, + GID_GRANDINQUISITOR + }, + + { AD_TABLE_END_MARKER, GID_NONE } @@ -106,6 +145,13 @@ static const ExtraGuiOption ZVisionExtraGuiOption = { false }; +static const ExtraGuiOption ZVisionExtraGuiOption2 = { + _s("Double FPS"), + _s("Halve the update delay"), + "doublefps", + false +}; + class ZVisionMetaEngine : public AdvancedMetaEngine { public: ZVisionMetaEngine() : AdvancedMetaEngine(ZVision::gameDescriptions, sizeof(ZVision::ZVisionGameDescription), zVisionGames) { @@ -133,22 +179,22 @@ public: bool ZVisionMetaEngine::hasFeature(MetaEngineFeature f) const { return false; - /* - (f == kSupportsListSaves) || - (f == kSupportsLoadingDuringStartup) || - (f == kSupportsDeleteSave) || - (f == kSavesSupportMetaInfo) || - (f == kSavesSupportThumbnail) || - (f == kSavesSupportCreationDate) || - (f == kSavesSupportPlayTime); - */ + /* + (f == kSupportsListSaves) || + (f == kSupportsLoadingDuringStartup) || + (f == kSupportsDeleteSave) || + (f == kSavesSupportMetaInfo) || + (f == kSavesSupportThumbnail) || + (f == kSavesSupportCreationDate) || + (f == kSavesSupportPlayTime); + */ } /*bool ZVision::ZVision::hasFeature(EngineFeature f) const { - return - (f == kSupportsRTL) || - (f == kSupportsLoadingDuringRuntime) || - (f == kSupportsSavingDuringRuntime); + return + (f == kSupportsRTL) || + (f == kSupportsLoadingDuringRuntime) || + (f == kSupportsSavingDuringRuntime); }*/ bool ZVisionMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { @@ -162,6 +208,7 @@ bool ZVisionMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADG const ExtraGuiOptions ZVisionMetaEngine::getExtraGuiOptions(const Common::String &target) const { ExtraGuiOptions options; options.push_back(ZVisionExtraGuiOption); + options.push_back(ZVisionExtraGuiOption2); return options; } @@ -173,23 +220,23 @@ SaveStateList ZVisionMetaEngine::listSaves(const char *target) const { Common::StringArray filenames; filenames = saveFileMan->listSavefiles(pattern.c_str()); - Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)*/ + Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)*/ SaveStateList saveList; -/* for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); file++) { - // Obtain the last 3 digits of the filename, since they correspond to the save slot - int slotNum = atoi(file->c_str() + file->size() - 3); - - if (slotNum >= 0 && slotNum <= 999) { - Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); - if (in) { - if (ZVision::ZVision::readSaveHeader(in, false, header) == ZVision::ZVision::kRSHENoError) { - saveList.push_back(SaveStateDescriptor(slotNum, header.description)); - } - delete in; - } - } - }*/ + /* for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); file++) { + // Obtain the last 3 digits of the filename, since they correspond to the save slot + int slotNum = atoi(file->c_str() + file->size() - 3); + + if (slotNum >= 0 && slotNum <= 999) { + Common::InSaveFile *in = saveFileMan->openForLoading(file->c_str()); + if (in) { + if (ZVision::ZVision::readSaveHeader(in, false, header) == ZVision::ZVision::kRSHENoError) { + saveList.push_back(SaveStateDescriptor(slotNum, header.description)); + } + delete in; + } + } + }*/ return saveList; } @@ -209,17 +256,17 @@ void ZVisionMetaEngine::removeSaveState(const char *target, int slot) const { Common::String pattern = target; pattern += ".???"; filenames = saveFileMan->listSavefiles(pattern.c_str()); - Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) + Common::sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..) for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) { - // Obtain the last 3 digits of the filename, since they correspond to the save slot - int slotNum = atoi(file->c_str() + file->size() - 3); - - // Rename every slot greater than the deleted slot, - if (slotNum > slot) { - saveFileMan->renameSavefile(file->c_str(), filename.c_str()); - filename = ZVision::ZVision::getSavegameFilename(target, ++slot); - } + // Obtain the last 3 digits of the filename, since they correspond to the save slot + int slotNum = atoi(file->c_str() + file->size() - 3); + + // Rename every slot greater than the deleted slot, + if (slotNum > slot) { + saveFileMan->renameSavefile(file->c_str(), filename.c_str()); + filename = ZVision::ZVision::getSavegameFilename(target, ++slot); + } } */ } @@ -230,34 +277,34 @@ SaveStateDescriptor ZVisionMetaEngine::querySaveMetaInfos(const char *target, in Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename.c_str()); if (in) { - ZVision::ZVision::SaveHeader header; - ZVision::ZVision::kReadSaveHeaderError error; + ZVision::ZVision::SaveHeader header; + ZVision::ZVision::kReadSaveHeaderError error; - error = ZVision::ZVision::readSaveHeader(in, true, header); - delete in; + error = ZVision::ZVision::readSaveHeader(in, true, header); + delete in; - if (error == ZVision::ZVision::kRSHENoError) { - SaveStateDescriptor desc(slot, header.description); + if (error == ZVision::ZVision::kRSHENoError) { + SaveStateDescriptor desc(slot, header.description); - desc.setThumbnail(header.thumbnail); + desc.setThumbnail(header.thumbnail); - if (header.version > 0) { - int day = (header.saveDate >> 24) & 0xFF; - int month = (header.saveDate >> 16) & 0xFF; - int year = header.saveDate & 0xFFFF; + if (header.version > 0) { + int day = (header.saveDate >> 24) & 0xFF; + int month = (header.saveDate >> 16) & 0xFF; + int year = header.saveDate & 0xFFFF; - desc.setSaveDate(year, month, day); + desc.setSaveDate(year, month, day); - int hour = (header.saveTime >> 16) & 0xFF; - int minutes = (header.saveTime >> 8) & 0xFF; + int hour = (header.saveTime >> 16) & 0xFF; + int minutes = (header.saveTime >> 8) & 0xFF; - desc.setSaveTime(hour, minutes); + desc.setSaveTime(hour, minutes); - desc.setPlayTime(header.playTime * 1000); - } + desc.setPlayTime(header.playTime * 1000); + } - return desc; - } + return desc; + } } */ @@ -265,7 +312,7 @@ SaveStateDescriptor ZVisionMetaEngine::querySaveMetaInfos(const char *target, in } #if PLUGIN_ENABLED_DYNAMIC(ZVISION) - REGISTER_PLUGIN_DYNAMIC(ZVISION, PLUGIN_TYPE_ENGINE, ZVisionMetaEngine); +REGISTER_PLUGIN_DYNAMIC(ZVISION, PLUGIN_TYPE_ENGINE, ZVisionMetaEngine); #else - REGISTER_PLUGIN_STATIC(ZVISION, PLUGIN_TYPE_ENGINE, ZVisionMetaEngine); +REGISTER_PLUGIN_STATIC(ZVISION, PLUGIN_TYPE_ENGINE, ZVisionMetaEngine); #endif diff --git a/engines/zvision/detection.h b/engines/zvision/detection.h index a788e710b7..f80cac79ec 100644 --- a/engines/zvision/detection.h +++ b/engines/zvision/detection.h @@ -25,7 +25,6 @@ #include "engines/advancedDetector.h" - namespace ZVision { enum ZVisionGameId { diff --git a/engines/zvision/fonts/truetype_font.cpp b/engines/zvision/fonts/truetype_font.cpp deleted file mode 100644 index 45eaeeb2b4..0000000000 --- a/engines/zvision/fonts/truetype_font.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#include "common/scummsys.h" - -#include "zvision/fonts/truetype_font.h" - -#include "zvision/zvision.h" -#include "zvision/graphics/render_manager.h" - -#include "common/debug.h" -#include "common/file.h" -#include "common/system.h" - -#include "graphics/font.h" -#include "graphics/fonts/ttf.h" -#include "graphics/surface.h" - - -namespace ZVision { - -TruetypeFont::TruetypeFont(ZVision *engine, int32 fontHeight) - : _fontHeight(fontHeight), - _font(0), - _lineHeight(0) { -} - -TruetypeFont::~TruetypeFont(void) { - delete _font; -} - -bool TruetypeFont::loadFile(const Common::String &filename) { - Common::File file; - - bool fileOpened = false; - if (!Common::File::exists(filename)) { - debug("TTF font file %s was not found. Reverting to arial.ttf", filename.c_str()); - fileOpened = file.open("arial.ttf"); - } else { - fileOpened = file.open(filename); - } - - if (!fileOpened) { - debug("TTF file could not be opened"); - return false; - } - - _font = Graphics::loadTTFFont(file, _fontHeight); - _lineHeight = _font->getFontHeight(); - - return true; -} - -Graphics::Surface *TruetypeFont::drawTextToSurface(const Common::String &text, uint16 textColor, int maxWidth, int maxHeight, Graphics::TextAlign align, bool wrap) { - if (text.equals("")) { - return nullptr; - } - - Graphics::Surface *surface = new Graphics::Surface(); - - if (!wrap) { - int width = MIN(_font->getStringWidth(text), maxWidth); - surface->create(width, _lineHeight, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)); - // TODO: Add better alpha support by getting the pixels from the backbuffer. - // However doing that requires some kind of caching system so future text doesn't try to use this text as it's alpha background. - surface->fillRect(Common::Rect(0, 0, surface->w, surface->h), 0); - - _font->drawString(surface, text, 0, 0, maxWidth, textColor, align); - return surface; - } - - Common::Array<Common::String> lines; - _font->wordWrapText(text, maxWidth, lines); - - while (maxHeight > 0 && (int)lines.size() * _lineHeight > maxHeight) { - lines.pop_back(); - } - if (lines.size() == 0) { - delete surface; - return nullptr; - } - - surface->create(maxWidth, lines.size() * _lineHeight, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)); - surface->fillRect(Common::Rect(0, 0, surface->w, surface->h), 0); - - int heightOffset = 0; - for (Common::Array<Common::String>::iterator it = lines.begin(); it != lines.end(); it++) { - _font->drawString(surface, *it, 0, 0 + heightOffset, maxWidth, textColor, align); - heightOffset += _lineHeight; - } - - return surface; -} - -} // End of namespace ZVision diff --git a/engines/zvision/graphics/effect.h b/engines/zvision/graphics/effect.h new file mode 100644 index 0000000000..c6653c6037 --- /dev/null +++ b/engines/zvision/graphics/effect.h @@ -0,0 +1,83 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef EFFECT_H_INCLUDED +#define EFFECT_H_INCLUDED + +#include "common/rect.h" +#include "common/list.h" +#include "graphics/surface.h" + +#include "zvision/zvision.h" + +namespace ZVision { + +class ZVision; + +class Effect { +public: + + Effect(ZVision *engine, uint32 key, Common::Rect region, bool ported) : _engine(engine), _key(key), _region(region), _ported(ported) { + _surface.create(_region.width(), _region.height(), _engine->_pixelFormat); + } + virtual ~Effect() {} + + uint32 getKey() { + return _key; + } + + Common::Rect getRegion() { + return _region; + } + + bool isPort() { + return _ported; + } + + virtual const Graphics::Surface *draw(const Graphics::Surface &srcSubRect) { + return &_surface; + } + + virtual void update() {} + +protected: + ZVision *_engine; + uint32 _key; + Common::Rect _region; + bool _ported; + Graphics::Surface _surface; + +// Static member functions +public: + +}; + +struct EffectMapUnit { + uint32 count; + bool inEffect; +}; + +typedef Common::List<EffectMapUnit> EffectMap; + +} // End of namespace ZVision + +#endif // EFFECT_H_INCLUDED diff --git a/engines/zvision/graphics/effects/fog.cpp b/engines/zvision/graphics/effects/fog.cpp new file mode 100644 index 0000000000..f59e82a4a0 --- /dev/null +++ b/engines/zvision/graphics/effects/fog.cpp @@ -0,0 +1,173 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/graphics/effects/fog.h" + +#include "zvision/zvision.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/scripting/script_manager.h" + +namespace ZVision { + +FogFx::FogFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, EffectMap *Map, const Common::String &clouds): + Effect(engine, key, region, ported) { + + _map = Map; + + _r = 0; + _g = 0; + _b = 0; + + _pos = 0; + + if (_engine->getSearchManager()->hasFile(clouds)) + _engine->getRenderManager()->readImageToSurface(clouds, _fog); + else + _engine->getRenderManager()->readImageToSurface("cloud.tga", _fog); + + _mp.resize(_fog.h); + for (int16 i = 0; i < _fog.h; i++) { + _mp[i].resize(_fog.w); + for (int16 j = 0; j < _fog.w; j++) + _mp[i][j] = true; + } + + for (uint8 i = 0; i < 32; i++) + _colorMap[i] = 0; +} + +FogFx::~FogFx() { + if (_map) + delete _map; + + for (uint16 i = 0; i < _mp.size(); i++) + _mp[i].clear(); + _mp.clear(); +} + +const Graphics::Surface *FogFx::draw(const Graphics::Surface &srcSubRect) { + _surface.copyFrom(srcSubRect); + EffectMap::iterator it = _map->begin(); + + uint32 cnt = 0; + + for (uint16 j = 0; j < _surface.h; j++) { + uint16 *lineBuf = (uint16 *)_surface.getBasePtr(0, j); + + for (uint16 i = 0; i < _surface.w; i++) { + if (it->inEffect) { + // Not 100% equivalent, but looks nice and not buggy + uint8 sr, sg, sb; + _engine->_pixelFormat.colorToRGB(lineBuf[i], sr, sg, sb); + uint16 fogColor = *(uint16 *)_fog.getBasePtr((i + _pos) % _fog.w, j); + uint8 dr, dg, db; + _engine->_pixelFormat.colorToRGB(_colorMap[fogColor & 0x1F], dr, dg, db); + uint16 fr = dr + sr; + if (fr > 255) + fr = 255; + uint16 fg = dg + sg; + if (fg > 255) + fg = 255; + uint16 fb = db + sb; + if (fb > 255) + fb = 255; + lineBuf[i] = _engine->_pixelFormat.RGBToColor(fr, fg, fb); + } + cnt++; + if (cnt >= it->count) { + it++; + cnt = 0; + } + if (it == _map->end()) + break; + } + if (it == _map->end()) + break; + } + + return &_surface; +} + +void FogFx::update() { + _pos += _engine->getScriptManager()->getStateValue(StateKey_EF9_Speed); + _pos %= _fog.w; + + uint8 dr = _engine->getScriptManager()->getStateValue(StateKey_EF9_R); + uint8 dg = _engine->getScriptManager()->getStateValue(StateKey_EF9_G); + uint8 db = _engine->getScriptManager()->getStateValue(StateKey_EF9_B); + dr = CLIP((int)dr, 0, 31); + dg = CLIP((int)dg, 0, 31); + db = CLIP((int)db, 0, 31); + + if (dr != _r || dg != _g || db != _b) { + if (_r > dr) + _r--; + else if (_r < dr) + _r++; + + if (_g > dg) + _g--; + else if (_g < dg) + _g++; + + if (_b > db) + _b--; + else if (_b < db) + _b++; + + // Not 100% equivalent, but looks nice and not buggy + + _colorMap[31] = _engine->_pixelFormat.RGBToColor(_r << 3, _g << 3, _b << 3); + + for (uint8 i = 0; i < 31; i++) { + float perc = (float)i / 31.0; + uint8 cr = (float)_r * perc; + uint8 cg = (float)_g * perc; + uint8 cb = (float)_b * perc; + _colorMap[i] = _engine->_pixelFormat.RGBToColor(cr << 3, cg << 3, cb << 3); + } + } + + for (uint16 j = 0; j < _fog.h; j++) { + uint16 *pix = (uint16 *)_fog.getBasePtr(0, j); + + for (uint16 i = 0; i < _fog.w; i++) { + if (_mp[j][i]) { + if ((pix[i] & 0x1F) == 0x1F) { + pix[i]--; + _mp[j][i] = false; + } else + pix[i]++; + } else { + if ((pix[i] & 0x1F) == 0) { + pix[i]++; + _mp[j][i] = true; + } else + pix[i]--; + } + } + } +} + +} // End of namespace ZVision diff --git a/engines/zvision/graphics/effects/fog.h b/engines/zvision/graphics/effects/fog.h new file mode 100644 index 0000000000..45d6f9596d --- /dev/null +++ b/engines/zvision/graphics/effects/fog.h @@ -0,0 +1,52 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_FOG_H +#define ZVISION_FOG_H + +#include "zvision/graphics/effect.h" + +namespace ZVision { + +class ZVision; + +class FogFx : public Effect { +public: + + FogFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, EffectMap *Map, const Common::String &clouds); + ~FogFx(); + + const Graphics::Surface *draw(const Graphics::Surface &srcSubRect); + + void update(); + +private: + EffectMap *_map; + Graphics::Surface _fog; + uint8 _r, _g, _b; + int32 _pos; + Common::Array< Common::Array< bool > > _mp; + uint16 _colorMap[32]; +}; +} // End of namespace ZVision + +#endif // ZVISION_FOG_H diff --git a/engines/zvision/graphics/effects/light.cpp b/engines/zvision/graphics/effects/light.cpp new file mode 100644 index 0000000000..00b3811d65 --- /dev/null +++ b/engines/zvision/graphics/effects/light.cpp @@ -0,0 +1,109 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/graphics/effects/light.h" + +#include "zvision/zvision.h" +#include "zvision/graphics/render_manager.h" + +namespace ZVision { + +LightFx::LightFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, EffectMap *Map, int8 delta, int8 minD, int8 maxD): + Effect(engine, key, region, ported) { + _map = Map; + _delta = delta; + _up = true; + _pos = 0; + + _minD = minD; + if (_minD < -delta) + _minD = -delta; + + _maxD = maxD; + if (_maxD > delta) + _maxD = delta; +} + +LightFx::~LightFx() { + if (_map) + delete _map; +} + +const Graphics::Surface *LightFx::draw(const Graphics::Surface &srcSubRect) { + _surface.copyFrom(srcSubRect); + EffectMap::iterator it = _map->begin(); + uint32 cnt = 0; + + uint32 dcolor = 0; + + if (_pos < 0) { + uint8 cc = ((-_pos) & 0x1F) << 3; + dcolor = _engine->_pixelFormat.RGBToColor(cc, cc, cc); + } else { + uint8 cc = (_pos & 0x1F) << 3; + dcolor = _engine->_pixelFormat.RGBToColor(cc, cc, cc); + } + + for (uint16 j = 0; j < _surface.h; j++) { + uint16 *lineBuf = (uint16 *)_surface.getBasePtr(0, j); + + for (uint16 i = 0; i < _surface.w; i++) { + if (it->inEffect) { + if (_pos < 0) { + lineBuf[i] -= dcolor; + } else { + lineBuf[i] += dcolor; + } + } + cnt++; + if (cnt >= it->count) { + it++; + cnt = 0; + } + if (it == _map->end()) + break; + } + if (it == _map->end()) + break; + } + + return &_surface; +} + +void LightFx::update() { + if (_up) + _pos++; + else + _pos--; + + if (_pos <= _minD) { + _up = !_up; + _pos = _minD; + } else if (_pos >= _maxD) { + _up = !_up; + _pos = _maxD; + } +} + +} // End of namespace ZVision diff --git a/engines/zvision/graphics/effects/light.h b/engines/zvision/graphics/effects/light.h new file mode 100644 index 0000000000..ae87d66cb3 --- /dev/null +++ b/engines/zvision/graphics/effects/light.h @@ -0,0 +1,53 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef LIGHTFX_H_INCLUDED +#define LIGHTFX_H_INCLUDED + +#include "zvision/graphics/effect.h" + +namespace ZVision { + +class ZVision; + +class LightFx : public Effect { +public: + + LightFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, EffectMap *Map, int8 delta, int8 minD = -127, int8 maxD = 127); + ~LightFx(); + + const Graphics::Surface *draw(const Graphics::Surface &srcSubRect); + + void update(); + +private: + EffectMap *_map; + int32 _delta; + bool _up; + int32 _pos; + + int8 _minD; + int8 _maxD; +}; +} // End of namespace ZVision + +#endif // LIGHTFX_H_INCLUDED diff --git a/engines/zvision/graphics/effects/wave.cpp b/engines/zvision/graphics/effects/wave.cpp new file mode 100644 index 0000000000..1b3aa040e8 --- /dev/null +++ b/engines/zvision/graphics/effects/wave.cpp @@ -0,0 +1,145 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/graphics/effects/wave.h" + +#include "zvision/zvision.h" +#include "zvision/graphics/render_manager.h" + +namespace ZVision { + +WaveFx::WaveFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, int16 frames, int16 centerX, int16 centerY, float ampl, float waveln, float spd): + Effect(engine, key, region, ported) { + + _frame = 0; + _frameCount = frames; + + _ampls.resize(_frameCount); + _halfWidth = _region.width() / 2; + _halfHeight = _region.height() / 2; + + int32 frmsize = _halfWidth * _halfHeight; + + float phase = 0; + + int16 quarterWidth = _halfWidth / 2; + int16 quarterHeight = _halfHeight / 2; + + for (int16 i = 0; i < _frameCount; i++) { + _ampls[i].resize(frmsize); + + for (int16 y = 0; y < _halfHeight; y++) + for (int16 x = 0; x < _halfWidth; x++) { + int16 dx = (x - quarterWidth); + int16 dy = (y - quarterHeight); + + _ampls[i][x + y * _halfWidth] = ampl * sin(sqrt(dx * dx / (float)centerX + dy * dy / (float)centerY) / (-waveln * 3.1415926) + phase); + } + phase += spd; + } +} + +WaveFx::~WaveFx() { + for (uint16 i = 0; i < _ampls.size(); i++) + _ampls[i].clear(); + _ampls.clear(); +} + +const Graphics::Surface *WaveFx::draw(const Graphics::Surface &srcSubRect) { + for (int16 y = 0; y < _halfHeight; y++) { + uint16 *abc = (uint16 *)_surface.getBasePtr(0, y); + uint16 *abc2 = (uint16 *)_surface.getBasePtr(0, _halfHeight + y); + uint16 *abc3 = (uint16 *)_surface.getBasePtr(_halfWidth, y); + uint16 *abc4 = (uint16 *)_surface.getBasePtr(_halfWidth, _halfHeight + y); + + for (int16 x = 0; x < _halfWidth; x++) { + int8 amnt = _ampls[_frame][x + _halfWidth * y]; + + int16 nX = x + amnt; + int16 nY = y + amnt; + + if (nX < 0) + nX = 0; + if (nX >= _region.width()) + nX = _region.width() - 1; + if (nY < 0) + nY = 0; + if (nY >= _region.height()) + nY = _region.height() - 1; + *abc = *(const uint16 *)srcSubRect.getBasePtr(nX, nY); + + nX = x + amnt + _halfWidth; + nY = y + amnt; + + if (nX < 0) + nX = 0; + if (nX >= _region.width()) + nX = _region.width() - 1; + if (nY < 0) + nY = 0; + if (nY >= _region.height()) + nY = _region.height() - 1; + *abc3 = *(const uint16 *)srcSubRect.getBasePtr(nX, nY); + + nX = x + amnt; + nY = y + amnt + _halfHeight; + + if (nX < 0) + nX = 0; + if (nX >= _region.width()) + nX = _region.width() - 1; + if (nY < 0) + nY = 0; + if (nY >= _region.height()) + nY = _region.height() - 1; + *abc2 = *(const uint16 *)srcSubRect.getBasePtr(nX, nY); + + nX = x + amnt + _halfWidth; + nY = y + amnt + _halfHeight; + + if (nX < 0) + nX = 0; + if (nX >= _region.width()) + nX = _region.width() - 1; + if (nY < 0) + nY = 0; + if (nY >= _region.height()) + nY = _region.height() - 1; + *abc4 = *(const uint16 *)srcSubRect.getBasePtr(nX, nY); + + abc++; + abc2++; + abc3++; + abc4++; + } + } + + return &_surface; +} + +void WaveFx::update() { + _frame = (_frame + 1) % _frameCount; +} + +} // End of namespace ZVision diff --git a/engines/zvision/graphics/effects/wave.h b/engines/zvision/graphics/effects/wave.h new file mode 100644 index 0000000000..2e813ed5b6 --- /dev/null +++ b/engines/zvision/graphics/effects/wave.h @@ -0,0 +1,51 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef WAVEFX_H_INCLUDED +#define WAVEFX_H_INCLUDED + +#include "common/array.h" +#include "zvision/graphics/effect.h" + +namespace ZVision { + +class ZVision; + +class WaveFx : public Effect { +public: + + WaveFx(ZVision *engine, uint32 key, Common::Rect region, bool ported, int16 frames, int16 centerX, int16 centerY, float ampl, float waveln, float spd); + ~WaveFx(); + + const Graphics::Surface *draw(const Graphics::Surface &srcSubRect); + + void update(); + +private: + int16 _frame; + int16 _frameCount; + int16 _halfWidth, _halfHeight; + Common::Array< Common::Array< int8 > > _ampls; +}; +} // End of namespace ZVision + +#endif // WAVEFX_H_INCLUDED diff --git a/engines/zvision/graphics/render_manager.cpp b/engines/zvision/graphics/render_manager.cpp index aed30ea12c..97d47e3920 100644 --- a/engines/zvision/graphics/render_manager.cpp +++ b/engines/zvision/graphics/render_manager.cpp @@ -1,28 +1,31 @@ /* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ #include "common/scummsys.h" +#include "zvision/zvision.h" #include "zvision/graphics/render_manager.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/text/text.h" #include "zvision/utility/lzss_read_stream.h" @@ -34,200 +37,223 @@ #include "image/tga.h" - namespace ZVision { -RenderManager::RenderManager(OSystem *system, uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow, const Graphics::PixelFormat pixelFormat) - : _system(system), - _workingWidth(workingWindow.width()), - _workingHeight(workingWindow.height()), - _screenCenterX(_workingWidth / 2), - _screenCenterY(_workingHeight / 2), - _workingWindow(workingWindow), - _pixelFormat(pixelFormat), - _backgroundWidth(0), - _backgroundHeight(0), - _backgroundInverseVelocity(0), - _backgroundOffset(0, 0), - _accumulatedVelocityMilliseconds(0), - _renderTable(_workingWidth, _workingHeight) { - - _workingWindowBuffer.create(_workingWidth, _workingHeight, _pixelFormat); - _backBuffer.create(windowWidth, windowHeight, pixelFormat); +RenderManager::RenderManager(ZVision *engine, uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow, const Graphics::PixelFormat pixelFormat) + : _engine(engine), + _system(engine->_system), + _wrkWidth(workingWindow.width()), + _wrkHeight(workingWindow.height()), + _screenCenterX(_wrkWidth / 2), + _screenCenterY(_wrkHeight / 2), + _workingWindow(workingWindow), + _pixelFormat(pixelFormat), + _bkgWidth(0), + _bkgHeight(0), + _bkgOff(0), + _renderTable(_wrkWidth, _wrkHeight) { + + _wrkWnd.create(_wrkWidth, _wrkHeight, _pixelFormat); + _effectWnd.create(_wrkWidth, _wrkHeight, _pixelFormat); + _outWnd.create(_wrkWidth, _wrkHeight, _pixelFormat); + _menuWnd.create(windowWidth, workingWindow.top, _pixelFormat); + _subWnd.create(windowWidth, windowHeight - workingWindow.bottom, _pixelFormat); + + _menuWndRect = Common::Rect(0, 0, windowWidth, workingWindow.top); + _subWndRect = Common::Rect(0, workingWindow.bottom, windowWidth, windowHeight); + + _subid = 0; } RenderManager::~RenderManager() { - _workingWindowBuffer.free(); - _currentBackground.free(); - _backBuffer.free(); - - for (AlphaEntryMap::iterator iter = _alphaDataEntries.begin(); iter != _alphaDataEntries.end(); ++iter) { - iter->_value.data->free(); - delete iter->_value.data; - } -} - -void RenderManager::update(uint deltaTimeInMillis) { - // An inverse velocity of 0 would be infinitely fast, so we'll let 0 mean no velocity. - if (_backgroundInverseVelocity != 0) { - _accumulatedVelocityMilliseconds += deltaTimeInMillis; - - uint absVelocity = uint(abs(_backgroundInverseVelocity)); - - int numberOfSteps = 0; - while (_accumulatedVelocityMilliseconds >= absVelocity) { - _accumulatedVelocityMilliseconds -= absVelocity; - numberOfSteps++; - } - - // Choose the direction of movement using the sign of the velocity - moveBackground(_backgroundInverseVelocity < 0 ? -numberOfSteps : numberOfSteps); - } + _curBkg.free(); + _wrkWnd.free(); + _effectWnd.free(); + _outWnd.free(); + _menuWnd.free(); + _subWnd.free(); } void RenderManager::renderBackbufferToScreen() { - if (!_workingWindowDirtyRect.isEmpty()) { - RenderTable::RenderState state = _renderTable.getRenderState(); - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - _renderTable.mutateImage((uint16 *)_workingWindowBuffer.getPixels(), (uint16 *)_backBuffer.getBasePtr(_workingWindow.left + _workingWindowDirtyRect.left, _workingWindow.top + _workingWindowDirtyRect.top), _backBuffer.w, _workingWindowDirtyRect); - } else { - _backBuffer.copyRectToSurface(_workingWindowBuffer.getBasePtr(_workingWindowDirtyRect.left, _workingWindowDirtyRect.top), _workingWindowBuffer.pitch, _workingWindow.left + _workingWindowDirtyRect.left, _workingWindow.top + _workingWindowDirtyRect.top, _workingWindowDirtyRect.width(), _workingWindowDirtyRect.height()); + Graphics::Surface *out = &_outWnd; + Graphics::Surface *in = &_wrkWnd; + Common::Rect outWndDirtyRect; + + if (!_effects.empty()) { + bool copied = false; + Common::Rect windRect(_wrkWidth, _wrkHeight); + for (effectsList::iterator it = _effects.begin(); it != _effects.end(); it++) { + Common::Rect rect = (*it)->getRegion(); + Common::Rect scrPlace = rect; + if ((*it)->isPort()) + scrPlace = bkgRectToScreen(scrPlace); + if (windRect.intersects(scrPlace)) { + if (!copied) { + copied = true; + _effectWnd.copyFrom(_wrkWnd); + in = &_effectWnd; + } + const Graphics::Surface *post; + if ((*it)->isPort()) + post = (*it)->draw(_curBkg.getSubArea(rect)); + else + post = (*it)->draw(_effectWnd.getSubArea(rect)); + blitSurfaceToSurface(*post, _effectWnd, scrPlace.left, scrPlace.top); + scrPlace.clip(windRect); + if (_wrkWndDirtyRect .isEmpty()) { + _wrkWndDirtyRect = scrPlace; + } else { + _wrkWndDirtyRect.extend(scrPlace); + } + } } + } - // Translate the working window dirty rect to screen coords - _workingWindowDirtyRect.translate(_workingWindow.left, _workingWindow.top); - // Then extend the backbuffer dirty rect to contain it - if (_backBufferDirtyRect.isEmpty()) { - _backBufferDirtyRect = _workingWindowDirtyRect; - } else { - _backBufferDirtyRect.extend(_workingWindowDirtyRect); + RenderTable::RenderState state = _renderTable.getRenderState(); + if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { + if (!_wrkWndDirtyRect.isEmpty()) { + _renderTable.mutateImage(&_outWnd, in); + out = &_outWnd; + outWndDirtyRect = Common::Rect(_wrkWidth, _wrkHeight); } - - // Clear the dirty rect - _workingWindowDirtyRect = Common::Rect(); + } else { + out = in; + outWndDirtyRect = _wrkWndDirtyRect; } - // TODO: Add menu rendering + if (!outWndDirtyRect.isEmpty()) { + _system->copyRectToScreen(out->getBasePtr(outWndDirtyRect.left, outWndDirtyRect.top), out->pitch, + outWndDirtyRect.left + _workingWindow.left, + outWndDirtyRect.top + _workingWindow.top, + outWndDirtyRect.width(), + outWndDirtyRect.height()); + } +} - // Render alpha entries - processAlphaEntries(); +void RenderManager::renderImageToBackground(const Common::String &fileName, int16 destX, int16 destY) { + Graphics::Surface surface; + readImageToSurface(fileName, surface); - if (!_backBufferDirtyRect.isEmpty()) { - _system->copyRectToScreen(_backBuffer.getBasePtr(_backBufferDirtyRect.left, _backBufferDirtyRect.top), _backBuffer.pitch, _backBufferDirtyRect.left, _backBufferDirtyRect.top, _backBufferDirtyRect.width(), _backBufferDirtyRect.height()); - _backBufferDirtyRect = Common::Rect(); - } + blitSurfaceToBkg(surface, destX, destY); + surface.free(); } -void RenderManager::processAlphaEntries() { - // TODO: Add dirty rectangling support. AKA only draw an entry if the _backbufferDirtyRect intersects/contains the entry Rect +void RenderManager::renderImageToBackground(const Common::String &fileName, int16 destX, int16 destY, uint32 keycolor) { + Graphics::Surface surface; + readImageToSurface(fileName, surface); - for (AlphaEntryMap::iterator iter = _alphaDataEntries.begin(); iter != _alphaDataEntries.end(); ++iter) { - uint32 destOffset = 0; - uint32 sourceOffset = 0; - uint16 *backbufferPtr = (uint16 *)_backBuffer.getBasePtr(iter->_value.destX + _workingWindow.left, iter->_value.destY + _workingWindow.top); - uint16 *entryPtr = (uint16 *)iter->_value.data->getPixels(); + blitSurfaceToBkg(surface, destX, destY, keycolor); + surface.free(); +} - for (int32 y = 0; y < iter->_value.height; ++y) { - for (int32 x = 0; x < iter->_value.width; ++x) { - uint16 color = entryPtr[sourceOffset + x]; - if (color != iter->_value.alphaColor) { - backbufferPtr[destOffset + x] = color; - } - } +void RenderManager::renderImageToBackground(const Common::String &fileName, int16 destX, int16 destY, int16 keyX, int16 keyY) { + Graphics::Surface surface; + readImageToSurface(fileName, surface); - destOffset += _backBuffer.w; - sourceOffset += iter->_value.width; - } + uint16 keycolor = *(uint16 *)surface.getBasePtr(keyX, keyY); - if (_backBufferDirtyRect.isEmpty()) { - _backBufferDirtyRect = Common::Rect(iter->_value.destX + _workingWindow.left, iter->_value.destY + _workingWindow.top, iter->_value.destX + _workingWindow.left + iter->_value.width, iter->_value.destY + _workingWindow.top + iter->_value.height); - } else { - _backBufferDirtyRect.extend(Common::Rect(iter->_value.destX + _workingWindow.left, iter->_value.destY + _workingWindow.top, iter->_value.destX + _workingWindow.left + iter->_value.width, iter->_value.destY + _workingWindow.top + iter->_value.height)); - } - } + blitSurfaceToBkg(surface, destX, destY, keycolor); + surface.free(); } -void RenderManager::clearWorkingWindowTo555Color(uint16 color) { - uint32 workingWindowSize = _workingWidth * _workingHeight; - byte r, g, b; - Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0).colorToRGB(color, r, g, b); - uint16 colorIn565 = _pixelFormat.RGBToColor(r, g, b); - uint16 *bufferPtr = (uint16 *)_workingWindowBuffer.getPixels(); +void RenderManager::readImageToSurface(const Common::String &fileName, Graphics::Surface &destination) { + Common::File file; - for (uint32 i = 0; i < workingWindowSize; ++i) { - bufferPtr[i] = colorIn565; + if (!_engine->getSearchManager()->openFile(file, fileName)) { + warning("Could not open file %s", fileName.c_str()); + return; } -} -void RenderManager::renderSubRectToScreen(Graphics::Surface &surface, int16 destinationX, int16 destinationY, bool wrap) { - int16 subRectX = 0; - int16 subRectY = 0; + // Read the magic number + // Some files are true TGA, while others are TGZ + uint32 fileType = file.readUint32BE(); - // Take care of negative destinations - if (destinationX < 0) { - subRectX = -destinationX; - destinationX = 0; - } else if (destinationX >= surface.w) { - // Take care of extreme positive destinations - destinationX -= surface.w; - } + uint32 imageWidth; + uint32 imageHeight; + Image::TGADecoder tga; + uint16 *buffer; + bool isTransposed = _renderTable.getRenderState() == RenderTable::PANORAMA; + // All ZVision images are in RGB 555 + Graphics::PixelFormat pixelFormat555 = Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0); + destination.format = pixelFormat555; - // Take care of negative destinations - if (destinationY < 0) { - subRectY = -destinationY; - destinationY = 0; - } else if (destinationY >= surface.h) { - // Take care of extreme positive destinations - destinationY -= surface.h; - } + bool isTGZ; + + // Check for TGZ files + if (fileType == MKTAG('T', 'G', 'Z', '\0')) { + isTGZ = true; - if (wrap) { - _backgroundWidth = surface.w; - _backgroundHeight = surface.h; + // TGZ files have a header and then Bitmap data that is compressed with LZSS + uint32 decompressedSize = file.readSint32LE(); + imageWidth = file.readSint32LE(); + imageHeight = file.readSint32LE(); - if (destinationX > 0) { - // Move destinationX to 0 - subRectX = surface.w - destinationX; - destinationX = 0; - } + LzssReadStream lzssStream(&file); + buffer = (uint16 *)(new uint16[decompressedSize]); + lzssStream.read(buffer, decompressedSize); + } else { + isTGZ = false; - if (destinationY > 0) { - // Move destinationY to 0 - subRectY = surface.h - destinationY; - destinationY = 0; + // Reset the cursor + file.seek(0); + + // Decode + if (!tga.loadStream(file)) { + warning("Error while reading TGA image"); + return; } + + Graphics::Surface tgaSurface = *(tga.getSurface()); + imageWidth = tgaSurface.w; + imageHeight = tgaSurface.h; + + buffer = (uint16 *)tgaSurface.getPixels(); } - // Clip subRect to working window bounds - Common::Rect subRect(subRectX, subRectY, subRectX + _workingWidth, subRectY + _workingHeight); + // Flip the width and height if transposed + if (isTransposed) { + uint16 temp = imageHeight; + imageHeight = imageWidth; + imageWidth = temp; + } - if (!wrap) { - // Clip to image bounds - subRect.clip(surface.w, surface.h); + // If the destination internal buffer is the same size as what we're copying into it, + // there is no need to free() and re-create + if (imageWidth != destination.w || imageHeight != destination.h) { + destination.create(imageWidth, imageHeight, pixelFormat555); } - // Check destRect for validity - if (!subRect.isValidRect() || subRect.isEmpty()) - return; + // If transposed, 'un-transpose' the data while copying it to the destination + // Otherwise, just do a simple copy + if (isTransposed) { + uint16 *dest = (uint16 *)destination.getPixels(); - copyRectToWorkingWindow((const uint16 *)surface.getBasePtr(subRect.left, subRect.top), destinationX, destinationY, surface.w, subRect.width(), subRect.height()); -} + for (uint32 y = 0; y < imageHeight; ++y) { + uint32 columnIndex = y * imageWidth; -void RenderManager::renderImageToScreen(const Common::String &fileName, int16 destinationX, int16 destinationY, bool wrap) { - Graphics::Surface surface; - readImageToSurface(fileName, surface); + for (uint32 x = 0; x < imageWidth; ++x) { + dest[columnIndex + x] = buffer[x * imageHeight + y]; + } + } + } else { + memcpy(destination.getPixels(), buffer, imageWidth * imageHeight * _pixelFormat.bytesPerPixel); + } - renderSubRectToScreen(surface, destinationX, destinationY, wrap); -} + // Cleanup + if (isTGZ) { + delete[] buffer; + } else { + tga.destroy(); + } -void RenderManager::renderImageToScreen(Graphics::Surface &surface, int16 destinationX, int16 destinationY, bool wrap) { - renderSubRectToScreen(surface, destinationX, destinationY, wrap); + // Convert in place to RGB 565 from RGB 555 + destination.convertToInPlace(_pixelFormat); } -void RenderManager::readImageToSurface(const Common::String &fileName, Graphics::Surface &destination) { +void RenderManager::readImageToSurface(const Common::String &fileName, Graphics::Surface &destination, bool transposed) { Common::File file; - if (!file.open(fileName)) { + if (!_engine->getSearchManager()->openFile(file, fileName)) { warning("Could not open file %s", fileName.c_str()); return; } @@ -240,7 +266,6 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics: uint32 imageHeight; Image::TGADecoder tga; uint16 *buffer; - bool isTransposed = _renderTable.getRenderState() == RenderTable::PANORAMA; // All ZVision images are in RGB 555 Graphics::PixelFormat pixelFormat555 = Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0); destination.format = pixelFormat555; @@ -279,7 +304,7 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics: } // Flip the width and height if transposed - if (isTransposed) { + if (transposed) { uint16 temp = imageHeight; imageHeight = imageWidth; imageWidth = temp; @@ -293,7 +318,7 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics: // If transposed, 'un-transpose' the data while copying it to the destination // Otherwise, just do a simple copy - if (isTransposed) { + if (transposed) { uint16 *dest = (uint16 *)destination.getPixels(); for (uint32 y = 0; y < imageHeight; ++y) { @@ -318,209 +343,724 @@ void RenderManager::readImageToSurface(const Common::String &fileName, Graphics: destination.convertToInPlace(_pixelFormat); } -void RenderManager::copyRectToWorkingWindow(const uint16 *buffer, int32 destX, int32 destY, int32 imageWidth, int32 width, int32 height) { - uint32 destOffset = 0; - uint32 sourceOffset = 0; - uint16 *workingWindowBufferPtr = (uint16 *)_workingWindowBuffer.getBasePtr(destX, destY); +const Common::Point RenderManager::screenSpaceToImageSpace(const Common::Point &point) { + if (_workingWindow.contains(point)) { + // Convert from screen space to working window space + Common::Point newPoint(point - Common::Point(_workingWindow.left, _workingWindow.top)); + + RenderTable::RenderState state = _renderTable.getRenderState(); + if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { + newPoint = _renderTable.convertWarpedCoordToFlatCoord(newPoint); + } - for (int32 y = 0; y < height; ++y) { - for (int32 x = 0; x < width; ++x) { - workingWindowBufferPtr[destOffset + x] = buffer[sourceOffset + x]; + if (state == RenderTable::PANORAMA) { + newPoint += (Common::Point(_bkgOff - _screenCenterX, 0)); + } else if (state == RenderTable::TILT) { + newPoint += (Common::Point(0, _bkgOff - _screenCenterY)); } - destOffset += _workingWidth; - sourceOffset += imageWidth; - } + if (_bkgWidth) + newPoint.x %= _bkgWidth; + if (_bkgHeight) + newPoint.y %= _bkgHeight; - if (_workingWindowDirtyRect.isEmpty()) { - _workingWindowDirtyRect = Common::Rect(destX, destY, destX + width, destY + height); + if (newPoint.x < 0) + newPoint.x += _bkgWidth; + if (newPoint.y < 0) + newPoint.y += _bkgHeight; + + return newPoint; } else { - _workingWindowDirtyRect.extend(Common::Rect(destX, destY, destX + width, destY + height)); + return Common::Point(0, 0); } +} + +RenderTable *RenderManager::getRenderTable() { + return &_renderTable; +} + +void RenderManager::setBackgroundImage(const Common::String &fileName) { + readImageToSurface(fileName, _curBkg); + _bkgWidth = _curBkg.w; + _bkgHeight = _curBkg.h; + _bkgDirtyRect = Common::Rect(_bkgWidth, _bkgHeight); +} + +void RenderManager::setBackgroundPosition(int offset) { + RenderTable::RenderState state = _renderTable.getRenderState(); + if (state == RenderTable::TILT || state == RenderTable::PANORAMA) + if (_bkgOff != offset) + _bkgDirtyRect = Common::Rect(_bkgWidth, _bkgHeight); + _bkgOff = offset; + + _engine->getScriptManager()->setStateValue(StateKey_ViewPos, offset); +} + +uint32 RenderManager::getCurrentBackgroundOffset() { + RenderTable::RenderState state = _renderTable.getRenderState(); - // TODO: Remove this from release. It's here to make sure code that uses this function clips their destinations correctly - assert(_workingWindowDirtyRect.width() <= _workingWidth && _workingWindowDirtyRect.height() <= _workingHeight); + if (state == RenderTable::PANORAMA) { + return _bkgOff; + } else if (state == RenderTable::TILT) { + return _bkgOff; + } else { + return 0; + } } -void RenderManager::copyRectToWorkingWindow(const uint16 *buffer, int32 destX, int32 destY, int32 imageWidth, int32 width, int32 height, int16 alphaColor, uint32 idNumber) { - AlphaDataEntry entry; - entry.alphaColor = alphaColor; - entry.data = new Graphics::Surface(); - entry.data->create(width, height, _pixelFormat); - entry.destX = destX; - entry.destY = destY; - entry.width = width; - entry.height = height; +Graphics::Surface *RenderManager::tranposeSurface(const Graphics::Surface *surface) { + Graphics::Surface *tranposedSurface = new Graphics::Surface(); + tranposedSurface->create(surface->h, surface->w, surface->format); + + const uint16 *source = (const uint16 *)surface->getPixels(); + uint16 *dest = (uint16 *)tranposedSurface->getPixels(); - uint32 sourceOffset = 0; - uint32 destOffset = 0; - uint16 *surfacePtr = (uint16 *)entry.data->getPixels(); + for (uint32 y = 0; y < tranposedSurface->h; ++y) { + uint32 columnIndex = y * tranposedSurface->w; - for (int32 y = 0; y < height; ++y) { - for (int32 x = 0; x < width; ++x) { - surfacePtr[destOffset + x] = buffer[sourceOffset + x]; + for (uint32 x = 0; x < tranposedSurface->w; ++x) { + dest[columnIndex + x] = source[x * surface->w + y]; } + } + + return tranposedSurface; +} + +void RenderManager::scaleBuffer(const void *src, void *dst, uint32 srcWidth, uint32 srcHeight, byte bytesPerPixel, uint32 dstWidth, uint32 dstHeight) { + assert(bytesPerPixel == 1 || bytesPerPixel == 2); + + const float xscale = (float)srcWidth / (float)dstWidth; + const float yscale = (float)srcHeight / (float)dstHeight; - destOffset += width; - sourceOffset += imageWidth; + if (bytesPerPixel == 1) { + const byte *srcPtr = (const byte *)src; + byte *dstPtr = (byte *)dst; + for (uint32 y = 0; y < dstHeight; ++y) { + for (uint32 x = 0; x < dstWidth; ++x) { + *dstPtr = srcPtr[(int)(x * xscale) + (int)(y * yscale) * srcWidth]; + dstPtr++; + } + } + } else if (bytesPerPixel == 2) { + const uint16 *srcPtr = (const uint16 *)src; + uint16 *dstPtr = (uint16 *)dst; + for (uint32 y = 0; y < dstHeight; ++y) { + for (uint32 x = 0; x < dstWidth; ++x) { + *dstPtr = srcPtr[(int)(x * xscale) + (int)(y * yscale) * srcWidth]; + dstPtr++; + } + } } +} + +void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Common::Rect &_srcRect , Graphics::Surface &dst, int _x, int _y) { + + if (src.format != dst.format) + return; + + Common::Rect srcRect = _srcRect; + if (srcRect.isEmpty()) + srcRect = Common::Rect(src.w, src.h); + srcRect.clip(src.w, src.h); + Common::Rect dstRect = Common::Rect(-_x + srcRect.left , -_y + srcRect.top, -_x + srcRect.left + dst.w, -_y + srcRect.top + dst.h); + srcRect.clip(dstRect); + + if (srcRect.isEmpty() || !srcRect.isValidRect()) + return; + + // Copy srcRect from src surface to dst surface + const byte *srcBuffer = (const byte *)src.getBasePtr(srcRect.left, srcRect.top); - _alphaDataEntries[idNumber] = entry; + int xx = _x; + int yy = _y; + + if (xx < 0) + xx = 0; + if (yy < 0) + yy = 0; + + if (_x >= dst.w || _y >= dst.h) + return; + + byte *dstBuffer = (byte *)dst.getBasePtr(xx, yy); + + int32 w = srcRect.width(); + int32 h = srcRect.height(); + + for (int32 y = 0; y < h; y++) { + memcpy(dstBuffer, srcBuffer, w * src.format.bytesPerPixel); + srcBuffer += src.pitch; + dstBuffer += dst.pitch; + } } -Common::Rect RenderManager::renderTextToWorkingWindow(uint32 idNumber, const Common::String &text, TruetypeFont *font, int destX, int destY, uint16 textColor, int maxWidth, int maxHeight, Graphics::TextAlign align, bool wrap) { - AlphaDataEntry entry; - entry.alphaColor = 0; - entry.destX = destX; - entry.destY = destY; +void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, const Common::Rect &_srcRect , Graphics::Surface &dst, int _x, int _y, uint32 colorkey) { + + if (src.format != dst.format) + return; + + Common::Rect srcRect = _srcRect; + if (srcRect.isEmpty()) + srcRect = Common::Rect(src.w, src.h); + srcRect.clip(src.w, src.h); + Common::Rect dstRect = Common::Rect(-_x + srcRect.left , -_y + srcRect.top, -_x + srcRect.left + dst.w, -_y + srcRect.top + dst.h); + srcRect.clip(dstRect); + + if (srcRect.isEmpty() || !srcRect.isValidRect()) + return; + + uint32 _keycolor = colorkey & ((1 << (src.format.bytesPerPixel << 3)) - 1); + + // Copy srcRect from src surface to dst surface + const byte *srcBuffer = (const byte *)src.getBasePtr(srcRect.left, srcRect.top); + + int xx = _x; + int yy = _y; + + if (xx < 0) + xx = 0; + if (yy < 0) + yy = 0; + + if (_x >= dst.w || _y >= dst.h) + return; + + byte *dstBuffer = (byte *)dst.getBasePtr(xx, yy); + + int32 w = srcRect.width(); + int32 h = srcRect.height(); + + for (int32 y = 0; y < h; y++) { + switch (src.format.bytesPerPixel) { + case 1: { + const uint *srcTemp = (const uint *)srcBuffer; + uint *dstTemp = (uint *)dstBuffer; + for (int32 x = 0; x < w; x++) { + if (*srcTemp != _keycolor) + *dstTemp = *srcTemp; + srcTemp++; + dstTemp++; + } + } + break; + + case 2: { + const uint16 *srcTemp = (const uint16 *)srcBuffer; + uint16 *dstTemp = (uint16 *)dstBuffer; + for (int32 x = 0; x < w; x++) { + if (*srcTemp != _keycolor) + *dstTemp = *srcTemp; + srcTemp++; + dstTemp++; + } + } + break; + + case 4: { + const uint32 *srcTemp = (const uint32 *)srcBuffer; + uint32 *dstTemp = (uint32 *)dstBuffer; + for (int32 x = 0; x < w; x++) { + if (*srcTemp != _keycolor) + *dstTemp = *srcTemp; + srcTemp++; + dstTemp++; + } + } + break; + + default: + break; + } + srcBuffer += src.pitch; + dstBuffer += dst.pitch; + } +} - // Draw the text to the working window - entry.data = font->drawTextToSurface(text, textColor, maxWidth, maxHeight, align, wrap); - entry.width = entry.data->w; - entry.height = entry.data->h; +void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, Graphics::Surface &dst, int x, int y) { + Common::Rect empt; + blitSurfaceToSurface(src, empt, dst, x, y); +} - _alphaDataEntries[idNumber] = entry; +void RenderManager::blitSurfaceToSurface(const Graphics::Surface &src, Graphics::Surface &dst, int x, int y, uint32 colorkey) { + Common::Rect empt; + blitSurfaceToSurface(src, empt, dst, x, y, colorkey); +} - return Common::Rect(destX, destY, destX + entry.width, destY + entry.height); +void RenderManager::blitSurfaceToBkg(const Graphics::Surface &src, int x, int y) { + Common::Rect empt; + blitSurfaceToSurface(src, empt, _curBkg, x, y); + Common::Rect dirty(src.w, src.h); + dirty.translate(x, y); + if (_bkgDirtyRect.isEmpty()) + _bkgDirtyRect = dirty; + else + _bkgDirtyRect.extend(dirty); } -const Common::Point RenderManager::screenSpaceToImageSpace(const Common::Point &point) { - // Convert from screen space to working window space - Common::Point newPoint(point - Common::Point(_workingWindow.left, _workingWindow.top)); +void RenderManager::blitSurfaceToBkg(const Graphics::Surface &src, int x, int y, uint32 colorkey) { + Common::Rect empt; + blitSurfaceToSurface(src, empt, _curBkg, x, y, colorkey); + Common::Rect dirty(src.w, src.h); + dirty.translate(x, y); + if (_bkgDirtyRect.isEmpty()) + _bkgDirtyRect = dirty; + else + _bkgDirtyRect.extend(dirty); +} - RenderTable::RenderState state = _renderTable.getRenderState(); - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - newPoint = _renderTable.convertWarpedCoordToFlatCoord(newPoint); +void RenderManager::blitSurfaceToBkgScaled(const Graphics::Surface &src, const Common::Rect &_dstRect) { + if (src.w == _dstRect.width() && src.h == _dstRect.height()) + blitSurfaceToBkg(src, _dstRect.left, _dstRect.top); + else { + Graphics::Surface *tmp = new Graphics::Surface; + tmp->create(_dstRect.width(), _dstRect.height(), src.format); + scaleBuffer(src.getPixels(), tmp->getPixels(), src.w, src.h, src.format.bytesPerPixel, _dstRect.width(), _dstRect.height()); + blitSurfaceToBkg(*tmp, _dstRect.left, _dstRect.top); + tmp->free(); + delete tmp; } +} - if (state == RenderTable::PANORAMA) { - newPoint -= (Common::Point(_screenCenterX, 0) - _backgroundOffset); - } else if (state == RenderTable::TILT) { - newPoint -= (Common::Point(0, _screenCenterY) - _backgroundOffset); +void RenderManager::blitSurfaceToBkgScaled(const Graphics::Surface &src, const Common::Rect &_dstRect, uint32 colorkey) { + if (src.w == _dstRect.width() && src.h == _dstRect.height()) + blitSurfaceToBkg(src, _dstRect.left, _dstRect.top, colorkey); + else { + Graphics::Surface *tmp = new Graphics::Surface; + tmp->create(_dstRect.width(), _dstRect.height(), src.format); + scaleBuffer(src.getPixels(), tmp->getPixels(), src.w, src.h, src.format.bytesPerPixel, _dstRect.width(), _dstRect.height()); + blitSurfaceToBkg(*tmp, _dstRect.left, _dstRect.top, colorkey); + tmp->free(); + delete tmp; } +} + +void RenderManager::blitSurfaceToMenu(const Graphics::Surface &src, int x, int y) { + Common::Rect empt; + blitSurfaceToSurface(src, empt, _menuWnd, x, y); + Common::Rect dirty(src.w, src.h); + dirty.translate(x, y); + if (_menuWndDirtyRect.isEmpty()) + _menuWndDirtyRect = dirty; + else + _menuWndDirtyRect.extend(dirty); +} + +void RenderManager::blitSurfaceToMenu(const Graphics::Surface &src, int x, int y, uint32 colorkey) { + Common::Rect empt; + blitSurfaceToSurface(src, empt, _menuWnd, x, y, colorkey); + Common::Rect dirty(src.w, src.h); + dirty.translate(x, y); + if (_menuWndDirtyRect.isEmpty()) + _menuWndDirtyRect = dirty; + else + _menuWndDirtyRect.extend(dirty); +} + +Graphics::Surface *RenderManager::getBkgRect(Common::Rect &rect) { + Common::Rect dst = rect; + dst.clip(_bkgWidth, _bkgHeight); + + if (dst.isEmpty() || !dst.isValidRect()) + return NULL; + + Graphics::Surface *srf = new Graphics::Surface; + srf->create(dst.width(), dst.height(), _curBkg.format); + + srf->copyRectToSurface(_curBkg, 0, 0, Common::Rect(dst)); + + return srf; +} + +Graphics::Surface *RenderManager::loadImage(Common::String &file) { + Graphics::Surface *tmp = new Graphics::Surface; + readImageToSurface(file, *tmp); + return tmp; +} - if (newPoint.x < 0) - newPoint.x += _backgroundWidth; - else if (newPoint.x >= _backgroundWidth) - newPoint.x -= _backgroundWidth; - if (newPoint.y < 0) - newPoint.y += _backgroundHeight; - else if (newPoint.y >= _backgroundHeight) - newPoint.y -= _backgroundHeight; +Graphics::Surface *RenderManager::loadImage(const char *file) { + Common::String str = Common::String(file); + return loadImage(str); +} - return newPoint; +Graphics::Surface *RenderManager::loadImage(Common::String &file, bool transposed) { + Graphics::Surface *tmp = new Graphics::Surface; + readImageToSurface(file, *tmp, transposed); + return tmp; } -const Common::Point RenderManager::imageSpaceToWorkingWindowSpace(const Common::Point &point) { - Common::Point newPoint(point); +Graphics::Surface *RenderManager::loadImage(const char *file, bool transposed) { + Common::String str = Common::String(file); + return loadImage(str, transposed); +} +void RenderManager::prepareBkg() { + _bkgDirtyRect.clip(_bkgWidth, _bkgHeight); RenderTable::RenderState state = _renderTable.getRenderState(); + if (state == RenderTable::PANORAMA) { - newPoint += (Common::Point(_screenCenterX, 0) - _backgroundOffset); + Common::Rect viewPort(_wrkWidth, _wrkHeight); + viewPort.translate(-(_screenCenterX - _bkgOff), 0); + Common::Rect drawRect = _bkgDirtyRect; + drawRect.clip(viewPort); + + if (!drawRect.isEmpty()) + blitSurfaceToSurface(_curBkg, drawRect, _wrkWnd, _screenCenterX - _bkgOff + drawRect.left, drawRect.top); + + _wrkWndDirtyRect = _bkgDirtyRect; + _wrkWndDirtyRect.translate(_screenCenterX - _bkgOff, 0); + + if (_bkgOff < _screenCenterX) { + viewPort.moveTo(-(_screenCenterX - (_bkgOff + _bkgWidth)), 0); + drawRect = _bkgDirtyRect; + drawRect.clip(viewPort); + + if (!drawRect.isEmpty()) + blitSurfaceToSurface(_curBkg, drawRect, _wrkWnd, _screenCenterX - (_bkgOff + _bkgWidth) + drawRect.left, drawRect.top); + + Common::Rect tmp = _bkgDirtyRect; + tmp.translate(_screenCenterX - (_bkgOff + _bkgWidth), 0); + if (!tmp.isEmpty()) + _wrkWndDirtyRect.extend(tmp); + + } else if (_bkgWidth - _bkgOff < _screenCenterX) { + viewPort.moveTo(-(_screenCenterX + _bkgWidth - _bkgOff), 0); + drawRect = _bkgDirtyRect; + drawRect.clip(viewPort); + + if (!drawRect.isEmpty()) + blitSurfaceToSurface(_curBkg, drawRect, _wrkWnd, _screenCenterX + _bkgWidth - _bkgOff + drawRect.left, drawRect.top); + + Common::Rect tmp = _bkgDirtyRect; + tmp.translate(_screenCenterX + _bkgWidth - _bkgOff, 0); + if (!tmp.isEmpty()) + _wrkWndDirtyRect.extend(tmp); + + } } else if (state == RenderTable::TILT) { - newPoint += (Common::Point(0, _screenCenterY) - _backgroundOffset); + Common::Rect viewPort(_wrkWidth, _wrkHeight); + viewPort.translate(0, -(_screenCenterY - _bkgOff)); + Common::Rect drawRect = _bkgDirtyRect; + drawRect.clip(viewPort); + if (!drawRect.isEmpty()) + blitSurfaceToSurface(_curBkg, drawRect, _wrkWnd, drawRect.left, _screenCenterY - _bkgOff + drawRect.top); + + _wrkWndDirtyRect = _bkgDirtyRect; + _wrkWndDirtyRect.translate(0, _screenCenterY - _bkgOff); + + } else { + if (!_bkgDirtyRect.isEmpty()) + blitSurfaceToSurface(_curBkg, _bkgDirtyRect, _wrkWnd, _bkgDirtyRect.left, _bkgDirtyRect.top); + _wrkWndDirtyRect = _bkgDirtyRect; } - return newPoint; + _bkgDirtyRect = Common::Rect(); + + _wrkWndDirtyRect.clip(_wrkWidth, _wrkHeight); +} + +void RenderManager::clearMenuSurface() { + _menuWndDirtyRect = Common::Rect(0, 0, _menuWnd.w, _menuWnd.h); + _menuWnd.fillRect(_menuWndDirtyRect, 0); } -bool RenderManager::clipRectToWorkingWindow(Common::Rect &rect) { - if (!_workingWindow.contains(rect)) { - return false; +void RenderManager::clearMenuSurface(const Common::Rect &r) { + if (_menuWndDirtyRect.isEmpty()) + _menuWndDirtyRect = r; + else + _menuWndDirtyRect.extend(r); + _menuWnd.fillRect(r, 0); +} + +void RenderManager::renderMenuToScreen() { + if (!_menuWndDirtyRect.isEmpty()) { + _menuWndDirtyRect.clip(Common::Rect(_menuWnd.w, _menuWnd.h)); + if (!_menuWndDirtyRect.isEmpty()) + _system->copyRectToScreen(_menuWnd.getBasePtr(_menuWndDirtyRect.left, _menuWndDirtyRect.top), _menuWnd.pitch, + _menuWndDirtyRect.left + _menuWndRect.left, + _menuWndDirtyRect.top + _menuWndRect.top, + _menuWndDirtyRect.width(), + _menuWndDirtyRect.height()); + _menuWndDirtyRect = Common::Rect(); } +} + +uint16 RenderManager::createSubArea(const Common::Rect &area) { + _subid++; + + oneSub sub; + sub.redraw = false; + sub.timer = -1; + sub.todelete = false; + sub.r = area; - // We can't clip against the actual working window rect because it's in screen space - // But rect is in working window space - rect.clip(_workingWidth, _workingHeight); - return true; + _subsList[_subid] = sub; + + return _subid; } -RenderTable *RenderManager::getRenderTable() { - return &_renderTable; +uint16 RenderManager::createSubArea() { + _subid++; + + oneSub sub; + sub.redraw = false; + sub.timer = -1; + sub.todelete = false; + sub.r = Common::Rect(_subWndRect.left, _subWndRect.top, _subWndRect.right, _subWndRect.bottom); + sub.r.translate(-_workingWindow.left, -_workingWindow.top); + + _subsList[_subid] = sub; + + return _subid; } -void RenderManager::setBackgroundImage(const Common::String &fileName) { - readImageToSurface(fileName, _currentBackground); +void RenderManager::deleteSubArea(uint16 id) { + if (_subsList.contains(id)) + _subsList[id].todelete = true; +} - moveBackground(0); +void RenderManager::deleteSubArea(uint16 id, int16 delay) { + if (_subsList.contains(id)) + _subsList[id].timer = delay; } -void RenderManager::setBackgroundPosition(int offset) { - RenderTable::RenderState state = _renderTable.getRenderState(); - if (state == RenderTable::TILT) { - _backgroundOffset.x = 0; - _backgroundOffset.y = offset; - } else if (state == RenderTable::PANORAMA) { - _backgroundOffset.x = offset; - _backgroundOffset.y = 0; - } else { - _backgroundOffset.x = 0; - _backgroundOffset.y = 0; +void RenderManager::updateSubArea(uint16 id, const Common::String &txt) { + if (_subsList.contains(id)) { + oneSub *sub = &_subsList[id]; + sub->txt = txt; + sub->redraw = true; } } -void RenderManager::setBackgroundVelocity(int velocity) { - // setBackgroundVelocity(0) will be called quite often, so make sure - // _backgroundInverseVelocity isn't already 0 to prevent an extraneous assignment - if (velocity == 0) { - if (_backgroundInverseVelocity != 0) { - _backgroundInverseVelocity = 0; +void RenderManager::processSubs(uint16 deltatime) { + bool redraw = false; + for (subMap::iterator it = _subsList.begin(); it != _subsList.end(); it++) { + if (it->_value.timer != -1) { + it->_value.timer -= deltatime; + if (it->_value.timer <= 0) + it->_value.todelete = true; + } + if (it->_value.todelete) { + _subsList.erase(it); + redraw = true; + } else if (it->_value.redraw) { + redraw = true; } - } else { - _backgroundInverseVelocity = 1000 / velocity; } -} -void RenderManager::moveBackground(int offset) { - RenderTable::RenderState state = _renderTable.getRenderState(); - if (state == RenderTable::TILT) { - _backgroundOffset += Common::Point(0, offset); + if (redraw) { + _subWnd.fillRect(Common::Rect(_subWnd.w, _subWnd.h), 0); + + for (subMap::iterator it = _subsList.begin(); it != _subsList.end(); it++) { + oneSub *sub = &it->_value; + if (sub->txt.size()) { + Graphics::Surface *rndr = new Graphics::Surface(); + rndr->create(sub->r.width(), sub->r.height(), _pixelFormat); + _engine->getTextRenderer()->drawTxtInOneLine(sub->txt, *rndr); + blitSurfaceToSurface(*rndr, _subWnd, sub->r.left - _subWndRect.left + _workingWindow.left, sub->r.top - _subWndRect.top + _workingWindow.top); + rndr->free(); + delete rndr; + } + sub->redraw = false; + } - _backgroundOffset.y = CLIP<int16>(_backgroundOffset.y, _screenCenterY, (int16)_backgroundHeight - _screenCenterY); + _system->copyRectToScreen(_subWnd.getPixels(), _subWnd.pitch, + _subWndRect.left, + _subWndRect.top, + _subWnd.w, + _subWnd.h); + } +} - renderImageToScreen(_currentBackground, 0, _screenCenterY - _backgroundOffset.y, true); - } else if (state == RenderTable::PANORAMA) { - _backgroundOffset += Common::Point(offset, 0); +Common::Point RenderManager::getBkgSize() { + return Common::Point(_bkgWidth, _bkgHeight); +} - if (_backgroundOffset.x <= -_backgroundWidth) - _backgroundOffset.x += _backgroundWidth; - else if (_backgroundOffset.x >= _backgroundWidth) - _backgroundOffset.x -= _backgroundWidth; +void RenderManager::addEffect(Effect *_effect) { + _effects.push_back(_effect); +} - renderImageToScreen(_currentBackground, _screenCenterX - _backgroundOffset.x, 0, true); - } else { - renderImageToScreen(_currentBackground, 0, 0); +void RenderManager::deleteEffect(uint32 ID) { + for (effectsList::iterator it = _effects.begin(); it != _effects.end(); it++) { + if ((*it)->getKey() == ID) { + delete *it; + it = _effects.erase(it); + } } } -uint32 RenderManager::getCurrentBackgroundOffset() { +Common::Rect RenderManager::bkgRectToScreen(const Common::Rect &src) { + Common::Rect tmp = src; RenderTable::RenderState state = _renderTable.getRenderState(); if (state == RenderTable::PANORAMA) { - return _backgroundOffset.x; + if (_bkgOff < _screenCenterX) { + Common::Rect rScreen(_screenCenterX + _bkgOff, _wrkHeight); + Common::Rect lScreen(_wrkWidth - rScreen.width(), _wrkHeight); + lScreen.translate(_bkgWidth - lScreen.width(), 0); + lScreen.clip(src); + rScreen.clip(src); + if (rScreen.width() < lScreen.width()) { + tmp.translate(_screenCenterX - _bkgOff - _bkgWidth, 0); + } else { + tmp.translate(_screenCenterX - _bkgOff, 0); + } + } else if (_bkgWidth - _bkgOff < _screenCenterX) { + Common::Rect rScreen(_screenCenterX - (_bkgWidth - _bkgOff), _wrkHeight); + Common::Rect lScreen(_wrkWidth - rScreen.width(), _wrkHeight); + lScreen.translate(_bkgWidth - lScreen.width(), 0); + lScreen.clip(src); + rScreen.clip(src); + if (lScreen.width() < rScreen.width()) { + tmp.translate(_screenCenterX + (_bkgWidth - _bkgOff), 0); + } else { + tmp.translate(_screenCenterX - _bkgOff, 0); + } + } else { + tmp.translate(_screenCenterX - _bkgOff, 0); + } } else if (state == RenderTable::TILT) { - return _backgroundOffset.y; - } else { - return 0; + tmp.translate(0, (_screenCenterY - _bkgOff)); } + + return tmp; } -Graphics::Surface *RenderManager::tranposeSurface(const Graphics::Surface *surface) { - Graphics::Surface *tranposedSurface = new Graphics::Surface(); - tranposedSurface->create(surface->h, surface->w, surface->format); +EffectMap *RenderManager::makeEffectMap(const Common::Point &xy, int16 depth, const Common::Rect &rect, int8 *_minComp, int8 *_maxComp) { + Common::Rect bkgRect(_bkgWidth, _bkgHeight); + if (!bkgRect.contains(xy)) + return NULL; + + if (!bkgRect.intersects(rect)) + return NULL; + + uint16 color = *(uint16 *)_curBkg.getBasePtr(xy.x, xy.y); + uint8 stC1, stC2, stC3; + _curBkg.format.colorToRGB(color, stC1, stC2, stC3); + EffectMap *newMap = new EffectMap; + + EffectMapUnit unit; + unit.count = 0; + unit.inEffect = false; + + int16 w = rect.width(); + int16 h = rect.height(); + + bool first = true; + + uint8 minComp = MIN(MIN(stC1, stC2), stC3); + uint8 maxComp = MAX(MAX(stC1, stC2), stC3); + + uint8 depth8 = depth << 3; + + for (int16 j = 0; j < h; j++) { + uint16 *pix = (uint16 *)_curBkg.getBasePtr(rect.left, rect.top + j); + for (int16 i = 0; i < w; i++) { + uint16 curClr = pix[i]; + uint8 cC1, cC2, cC3; + _curBkg.format.colorToRGB(curClr, cC1, cC2, cC3); + + bool use = false; + + if (curClr == color) + use = true; + else if (curClr > color) { + if ((cC1 - stC1 < depth8) && + (cC2 - stC2 < depth8) && + (cC3 - stC3 < depth8)) + use = true; + } else { /* if (curClr < color) */ + if ((stC1 - cC1 < depth8) && + (stC2 - cC2 < depth8) && + (stC3 - cC3 < depth8)) + use = true; + } - const uint16 *source = (const uint16 *)surface->getPixels(); - uint16 *dest = (uint16 *)tranposedSurface->getPixels(); + if (first) { + unit.inEffect = use; + first = false; + } - for (uint32 y = 0; y < tranposedSurface->h; ++y) { - uint32 columnIndex = y * tranposedSurface->w; + if (use) { + uint8 cMinComp = MIN(MIN(cC1, cC2), cC3); + uint8 cMaxComp = MAX(MAX(cC1, cC2), cC3); + if (cMinComp < minComp) + minComp = cMinComp; + if (cMaxComp > maxComp) + maxComp = cMaxComp; + } - for (uint32 x = 0; x < tranposedSurface->w; ++x) { - dest[columnIndex + x] = source[x * surface->w + y]; + if (unit.inEffect == use) + unit.count++; + else { + newMap->push_back(unit); + unit.count = 1; + unit.inEffect = use; + } } } + newMap->push_back(unit); - return tranposedSurface; + if (_minComp) { + if (minComp - depth8 < 0) + *_minComp = -(minComp >> 3); + else + *_minComp = -depth; + } + if (_maxComp) { + if ((int16)maxComp + (int16)depth8 > 255) + *_maxComp = (255 - maxComp) >> 3; + else + *_maxComp = depth; + } + + return newMap; +} + +EffectMap *RenderManager::makeEffectMap(const Graphics::Surface &surf, uint16 transp) { + EffectMapUnit unit; + unit.count = 0; + unit.inEffect = false; + + int16 w = surf.w; + int16 h = surf.h; + + EffectMap *newMap = new EffectMap; + + bool first = true; + + for (int16 j = 0; j < h; j++) { + const uint16 *pix = (const uint16 *)surf.getBasePtr(0, j); + for (int16 i = 0; i < w; i++) { + bool use = false; + if (pix[i] != transp) + use = true; + + if (first) { + unit.inEffect = use; + first = false; + } + + if (unit.inEffect == use) + unit.count++; + else { + newMap->push_back(unit); + unit.count = 1; + unit.inEffect = use; + } + } + } + newMap->push_back(unit); + + return newMap; +} + +void RenderManager::markDirty() { + _bkgDirtyRect = Common::Rect(_bkgWidth, _bkgHeight); +} + +void RenderManager::bkgFill(uint8 r, uint8 g, uint8 b) { + _curBkg.fillRect(Common::Rect(_curBkg.w, _curBkg.h), _curBkg.format.RGBToColor(r, g, b)); + markDirty(); } } // End of namespace ZVision diff --git a/engines/zvision/graphics/render_manager.h b/engines/zvision/graphics/render_manager.h index 9feff4c030..879a8643ce 100644 --- a/engines/zvision/graphics/render_manager.h +++ b/engines/zvision/graphics/render_manager.h @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -24,13 +24,14 @@ #define ZVISION_RENDER_MANAGER_H #include "zvision/graphics/render_table.h" -#include "zvision/fonts/truetype_font.h" +#include "zvision/graphics/truetype_font.h" #include "common/rect.h" #include "common/hashmap.h" #include "graphics/surface.h" +#include "effect.h" class OSystem; @@ -47,43 +48,53 @@ namespace ZVision { class RenderManager { public: - RenderManager(OSystem *system, uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow, const Graphics::PixelFormat pixelFormat); + RenderManager(ZVision *engine, uint32 windowWidth, uint32 windowHeight, const Common::Rect workingWindow, const Graphics::PixelFormat pixelFormat); ~RenderManager(); private: - struct AlphaDataEntry { - Graphics::Surface *data; - uint16 alphaColor; - uint16 destX; - uint16 destY; - uint16 width; - uint16 height; + struct oneSub { + Common::Rect r; + Common::String txt; + int16 timer; + bool todelete; + bool redraw; }; - typedef Common::HashMap<uint32, AlphaDataEntry> AlphaEntryMap; + typedef Common::HashMap<uint16, oneSub> subMap; + typedef Common::List<Effect *> effectsList; private: + ZVision *_engine; OSystem *_system; const Graphics::PixelFormat _pixelFormat; - // A buffer the exact same size as the workingWindow - // This buffer stores everything un-warped, then does a warp at the end of the frame - Graphics::Surface _workingWindowBuffer; - // A buffer representing the entire screen. Any graphical updates are first done with this buffer - // before actually being blitted to the screen - Graphics::Surface _backBuffer; - // A list of Alpha Entries that need to be blitted to the backbuffer - AlphaEntryMap _alphaDataEntries; + // A buffer for blitting background image to working window + Graphics::Surface _wrkWnd; + + Common::Rect _wrkWndDirtyRect; + + // A buffer for mutate image by tilt or panorama renderers + Graphics::Surface _outWnd; - // A rectangle representing the portion of the working window where the pixels have been changed since last frame - Common::Rect _workingWindowDirtyRect; - // A rectangle representing the portion of the backbuffer where the pixels have been changed since last frame - Common::Rect _backBufferDirtyRect; + Common::Rect _bkgDirtyRect; + + // A buffer for subtitles + Graphics::Surface _subWnd; + + Common::Rect _subWndDirtyRect; + + // A buffer for menu drawing + Graphics::Surface _menuWnd; + + Common::Rect _menuWndDirtyRect; + + // A buffer used for apply graphics effects + Graphics::Surface _effectWnd; /** Width of the working window. Saved to prevent extraneous calls to _workingWindow.width() */ - const int _workingWidth; + const int _wrkWidth; /** Height of the working window. Saved to prevent extraneous calls to _workingWindow.height() */ - const int _workingHeight; + const int _wrkHeight; /** Center of the screen in the x direction */ const int _screenCenterX; /** Center of the screen in the y direction */ @@ -95,33 +106,36 @@ private: * edges of this Rectangle */ const Common::Rect _workingWindow; + + // Recatangle for subtitles area + Common::Rect _subWndRect; + + // Recatangle for menu area + Common::Rect _menuWndRect; + /** Used to warp the background image */ RenderTable _renderTable; - Graphics::Surface _currentBackground; + // A buffer for background image + Graphics::Surface _curBkg; /** The (x1,y1) coordinates of the subRectangle of the background that is currently displayed on the screen */ - Common::Point _backgroundOffset; + int16 _bkgOff; /** The width of the current background image */ - uint16 _backgroundWidth; + uint16 _bkgWidth; /** The height of the current background image */ - uint16 _backgroundHeight; + uint16 _bkgHeight; - /** - * The "velocity" at which the background image is panning. We actually store the inverse of velocity (ms/pixel instead of pixels/ms) - * because it allows you to accumulate whole pixels 'steps' instead of rounding pixels every frame - */ - int _backgroundInverseVelocity; - /** Holds any 'leftover' milliseconds between frames */ - uint _accumulatedVelocityMilliseconds; + // Internal subtitles counter + uint16 _subid; + + // Subtitle list + subMap _subsList; + + // Visual effects list + effectsList _effects; public: void initialize(); - /** - * Rotates the background image in accordance to the current _backgroundInverseVelocity - * - * @param deltaTimeInMillis The amount of time that has passed since the last frame - */ - void update(uint deltaTimeInMillis); /** * Renders the current state of the backbuffer to the screen @@ -129,89 +143,34 @@ public: void renderBackbufferToScreen(); /** - * Renders all AlphaEntries to the backbuffer - */ - void processAlphaEntries(); - /** - * Clears the AlphaEntry list - */ - void clearAlphaEntries() { _alphaDataEntries.clear(); } - /** - * Removes a specific AlphaEntry from the list - * - * @param idNumber The id number identifing the AlphaEntry - */ - void removeAlphaEntry(uint32 idNumber) { _alphaDataEntries.erase(idNumber); } - - /** - * Copies a sub-rectangle of a buffer to the working window - * - * @param buffer The pixel data to copy to the working window - * @param destX The X destination in the working window where the subRect of data should be put - * @param destY The Y destination in the working window where the subRect of data should be put - * @param imageWidth The width of the source image - * @param width The width of the sub rectangle - * @param height The height of the sub rectangle - */ - void copyRectToWorkingWindow(const uint16 *buffer, int32 destX, int32 destY, int32 imageWidth, int32 width, int32 height); - /** - * Copies a sub-rectangle of a buffer to the working window with binary alpha support. - * - * @param buffer The pixel data to copy to the working window - * @param destX The X destination in the working window where the subRect of data should be put - * @param destY The Y destination in the working window where the subRect of data should be put - * @param imageWidth The width of the source image - * @param width The width of the sub rectangle - * @param height The height of the sub rectangle - * @param alphaColor The color to interpret as meaning 'transparent' - * @param idNumber A unique identifier for the data being copied over. - */ - void copyRectToWorkingWindow(const uint16 *buffer, int32 destX, int32 destY, int32 imageWidth, int32 width, int32 height, int16 alphaColor, uint32 idNumber); - - /** - * Renders the supplied text to the working window + * Blits the image or a portion of the image to the background. * - * @param idNumber A unique identifier for the text - * @param text The text to be rendered - * @param font The font to use to render the text - * @param destX The X destination in the working window where the text should be rendered - * @param destY The Y destination in the working window where the text should be rendered - * @param textColor The color to render the text with (in RBG 565) - * @param maxWidth The max width the text should take up. - * @param maxHeight The max height the text should take up. - * @param align The alignment of the text within the bounds of maxWidth - * @param wrap If true, any words extending past maxWidth will wrap to a new line. If false, ellipses will be rendered to show that the text didn't fit - * @return A rectangle representing where the text was drawn in the working window - */ - Common::Rect renderTextToWorkingWindow(uint32 idNumber, const Common::String &text, TruetypeFont *font, int destX, int destY, uint16 textColor, int maxWidth, int maxHeight = -1, Graphics::TextAlign align = Graphics::kTextAlignLeft, bool wrap = true); - - /** - * Fills the entire workingWindow with the specified color. Internally, the color - * will be converted to RGB 565 and then blitted. - * - * @param color The color to fill the working window with. (In RGB 555) + * @param fileName Name of the image file + * @param destinationX X position where the image should be put. Coords are in working window space, not screen space! + * @param destinationY Y position where the image should be put. Coords are in working window space, not screen space! */ - void clearWorkingWindowTo555Color(uint16 color); + void renderImageToBackground(const Common::String &fileName, int16 destinationX, int16 destinationY); /** - * Blits the image or a portion of the image to the backbuffer. Actual screen updates won't happen until the end of the frame. - * The image will be clipped to fit inside the working window. Coords are in working window space, not screen space! + * Blits the image or a portion of the image to the background. * - * @param fileName Name of the image file - * @param destinationX X position where the image should be put. Coords are in working window space, not screen space! - * @param destinationY Y position where the image should be put. Coords are in working window space, not screen space! + * @param fileName Name of the image file + * @param destX X position where the image should be put. Coords are in working window space, not screen space! + * @param destY Y position where the image should be put. Coords are in working window space, not screen space! + * @param colorkey Transparent color */ - void renderImageToScreen(const Common::String &fileName, int16 destinationX, int16 destinationY, bool wrap = false); + void renderImageToBackground(const Common::String &fileName, int16 destX, int16 destY, uint32 colorkey); /** - * Blits the image or a portion of the image to the backbuffer. Actual screen updates won't happen until the end of the frame. - * The image will be clipped to fit inside the working window. Coords are in working window space, not screen space! + * Blits the image or a portion of the image to the background. * - * @param stream Surface to read the image data from - * @param destinationX X position where the image should be put. Coords are in working window space, not screen space! - * @param destinationY Y position where the image should be put. Coords are in working window space, not screen space! + * @param fileName Name of the image file + * @param destX X position where the image should be put. Coords are in working window space, not screen space! + * @param destY Y position where the image should be put. Coords are in working window space, not screen space! + * @param keyX X position of transparent color + * @param keyY Y position of transparent color */ - void renderImageToScreen(Graphics::Surface &surface, int16 destinationX, int16 destinationY, bool wrap = false); + void renderImageToBackground(const Common::String &fileName, int16 destX, int16 destY, int16 keyX, int16 keyY); /** * Sets the current background image to be used by the RenderManager and immediately @@ -234,41 +193,18 @@ public: void setBackgroundPosition(int offset); /** - * Set the background scroll velocity. Negative velocities correspond to left / up scrolling and - * positive velocities correspond to right / down scrolling - * - * @param velocity Velocity - */ - void setBackgroundVelocity(int velocity); - - /** * Converts a point in screen coordinate space to image coordinate space * * @param point Point in screen coordinate space * @return Point in image coordinate space */ const Common::Point screenSpaceToImageSpace(const Common::Point &point); - /** - * Converts a point in image coordinate space to ***PRE-WARP*** - * working window coordinate space - * - * @param point Point in image coordinate space - * @return Point in PRE-WARP working window coordinate space - */ - const Common::Point imageSpaceToWorkingWindowSpace(const Common::Point &point); - - /** - * Clip a rectangle to the working window. If it returns false, the original rect - * is not inside the working window. - * - * @param rect The rectangle to clip against the working window - * @return Is rect at least partially inside the working window (true) or completely outside (false) - */ - bool clipRectToWorkingWindow(Common::Rect &rect); + // Return pointer of RenderTable object RenderTable *getRenderTable(); + + // Return current background offset uint32 getCurrentBackgroundOffset(); - const Graphics::Surface *getBackBuffer() { return &_backBuffer; } /** * Creates a copy of surface and transposes the data. @@ -281,21 +217,64 @@ public: */ static Graphics::Surface *tranposeSurface(const Graphics::Surface *surface); -private: - /** - * Renders a subRectangle of an image to the backbuffer. The destinationRect and SubRect - * will be clipped to image bound and to working window bounds - * - * @param buffer Pointer to (0, 0) of the image data - * @param imageWidth The width of the original image (not of the subRectangle) - * @param imageHeight The width of the original image (not of the subRectangle) - * @param horizontalPitch The horizontal pitch of the original image - * @param destinationX The x coordinate (in working window space) of where to put the final image - * @param destinationY The y coordinate (in working window space) of where to put the final image - * @param subRectangle A rectangle representing the part of the image that should be rendered - * @param wrap Should the image wrap (tile) if it doesn't completely fill the screen? - */ - void renderSubRectToScreen(Graphics::Surface &surface, int16 destinationX, int16 destinationY, bool wrap); + // Scale buffer (nearest) + void scaleBuffer(const void *src, void *dst, uint32 srcWidth, uint32 srcHeight, byte bytesPerPixel, uint32 dstWidth, uint32 dstHeight); + + // Blitting surface-to-surface methods + void blitSurfaceToSurface(const Graphics::Surface &src, const Common::Rect &_srcRect , Graphics::Surface &dst, int x, int y); + void blitSurfaceToSurface(const Graphics::Surface &src, const Common::Rect &_srcRect , Graphics::Surface &dst, int _x, int _y, uint32 colorkey); + void blitSurfaceToSurface(const Graphics::Surface &src, Graphics::Surface &dst, int x, int y); + void blitSurfaceToSurface(const Graphics::Surface &src, Graphics::Surface &dst, int x, int y, uint32 colorkey); + + // Blitting surface-to-background methods + void blitSurfaceToBkg(const Graphics::Surface &src, int x, int y); + void blitSurfaceToBkg(const Graphics::Surface &src, int x, int y, uint32 colorkey); + + // Blitting surface-to-background methods with scale + void blitSurfaceToBkgScaled(const Graphics::Surface &src, const Common::Rect &_dstRect); + void blitSurfaceToBkgScaled(const Graphics::Surface &src, const Common::Rect &_dstRect, uint32 colorkey); + + // Blitting surface-to-menu methods + void blitSurfaceToMenu(const Graphics::Surface &src, int x, int y); + void blitSurfaceToMenu(const Graphics::Surface &src, int x, int y, uint32 colorkey); + + // Subtitles methods + + // Create subtitle area and return ID + uint16 createSubArea(const Common::Rect &area); + uint16 createSubArea(); + + // Delete subtitle by ID + void deleteSubArea(uint16 id); + void deleteSubArea(uint16 id, int16 delay); + + // Update subtitle area + void updateSubArea(uint16 id, const Common::String &txt); + + // Processing subtitles + void processSubs(uint16 deltatime); + + // Return background size + Common::Point getBkgSize(); + + // Return portion of background as new surface + Graphics::Surface *getBkgRect(Common::Rect &rect); + + // Load image into new surface + Graphics::Surface *loadImage(const char *file); + Graphics::Surface *loadImage(Common::String &file); + Graphics::Surface *loadImage(const char *file, bool transposed); + Graphics::Surface *loadImage(Common::String &file, bool transposed); + + // Clear whole/area of menu surface + void clearMenuSurface(); + void clearMenuSurface(const Common::Rect &r); + + // Copy menu buffer to screen + void renderMenuToScreen(); + + // Copy needed portion of background surface to workingWindow surface + void prepareBkg(); /** * Reads an image file pixel data into a Surface buffer. In the process @@ -310,17 +289,43 @@ private: void readImageToSurface(const Common::String &fileName, Graphics::Surface &destination); /** - * Move the background image by an offset. If we are currently in Panorama mode, - * the offset will correspond to a horizontal motion. If we are currently in Tilt mode, - * the offset will correspond to a vertical motion. This function should not be called - * if we are in Flat mode. - * - * The RenderManager will take care of wrapping the image. - * Ex: If the image has width 1400px, it is legal to offset 1500px. + * Reads an image file pixel data into a Surface buffer. In the process + * it converts the pixel data from RGB 555 to RGB 565. Also, if the image + * is transposed, it will un-transpose the pixel data. The function will + * call destination::create() if the dimensions of destination do not match + * up with the dimensions of the image. * - * @param offset The amount to move the background + * @param fileName The name of a .tga file + * @param destination A reference to the Surface to store the pixel data in + * @param transposed Transpose flag */ - void moveBackground(int offset); + void readImageToSurface(const Common::String &fileName, Graphics::Surface &destination, bool transposed); + + // Add visual effect to effects list + void addEffect(Effect *_effect); + + // Delete effect(s) by ID (ID equal to slot of action:region that create this effect) + void deleteEffect(uint32 ID); + + // Create "mask" for effects - (color +/- depth) will be selected as not transparent. Like color selection + // xy - base color + // depth - +/- of base color + // rect - rectangle where select pixels + // minD - if not NULL will recieve real bottom border of depth + // maxD - if not NULL will recieve real top border of depth + EffectMap *makeEffectMap(const Common::Point &xy, int16 depth, const Common::Rect &rect, int8 *minD, int8 *maxD); + + // Create "mask" for effects by simple transparent color + EffectMap *makeEffectMap(const Graphics::Surface &surf, uint16 transp); + + // Return background rectangle in screen coordinates + Common::Rect bkgRectToScreen(const Common::Rect &src); + + // Mark whole background surface as dirty + void markDirty(); + + // Fille background surface by color + void bkgFill(uint8 r, uint8 g, uint8 b); }; } // End of namespace ZVision diff --git a/engines/zvision/graphics/render_table.cpp b/engines/zvision/graphics/render_table.cpp index 49b934dc37..54faecfa8b 100644 --- a/engines/zvision/graphics/render_table.cpp +++ b/engines/zvision/graphics/render_table.cpp @@ -21,20 +21,16 @@ */ #include "common/scummsys.h" - #include "zvision/graphics/render_table.h" - #include "common/rect.h" - #include "graphics/colormasks.h" - namespace ZVision { RenderTable::RenderTable(uint numColumns, uint numRows) - : _numRows(numRows), - _numColumns(numColumns), - _renderState(FLAT) { + : _numRows(numRows), + _numColumns(numColumns), + _renderState(FLAT) { assert(numRows != 0 && numColumns != 0); _internalBuffer = new Common::Point[numRows * numColumns]; @@ -52,10 +48,11 @@ void RenderTable::setRenderState(RenderState newState) { _panoramaOptions.fieldOfView = 27.0f; _panoramaOptions.linearScale = 0.55f; _panoramaOptions.reverse = false; + _panoramaOptions.zeroPoint = 0; break; case TILT: _tiltOptions.fieldOfView = 27.0f; - _tiltOptions.linearScale = 0.55f; + _tiltOptions.linearScale = 0.65f; _tiltOptions.reverse = false; break; case FLAT: @@ -97,12 +94,12 @@ uint16 mixTwoRGB(uint16 colorOne, uint16 colorTwo, float percentColorOne) { uint16 returnColor = (byte(rFinal + 0.5f) << Graphics::ColorMasks<555>::kRedShift) | (byte(gFinal + 0.5f) << Graphics::ColorMasks<555>::kGreenShift) | - (byte(bFinal + 0.5f) << Graphics::ColorMasks<555>::kBlueShift); + (byte(bFinal + 0.5f) << Graphics::ColorMasks<555>::kBlueShift); return returnColor; } -void RenderTable::mutateImage(uint16 *sourceBuffer, uint16* destBuffer, uint32 destWidth, const Common::Rect &subRect) { +void RenderTable::mutateImage(uint16 *sourceBuffer, uint16 *destBuffer, uint32 destWidth, const Common::Rect &subRect) { uint32 destOffset = 0; for (int16 y = subRect.top; y < subRect.bottom; ++y) { @@ -123,6 +120,28 @@ void RenderTable::mutateImage(uint16 *sourceBuffer, uint16* destBuffer, uint32 d } } +void RenderTable::mutateImage(Graphics::Surface *dstBuf, Graphics::Surface *srcBuf) { + uint32 destOffset = 0; + + uint16 *sourceBuffer = (uint16 *)srcBuf->getPixels(); + uint16 *destBuffer = (uint16 *)dstBuf->getPixels(); + + for (int16 y = 0; y < srcBuf->h; ++y) { + uint32 sourceOffset = y * _numColumns; + + for (int16 x = 0; x < srcBuf->w; ++x) { + uint32 index = sourceOffset + x; + + // RenderTable only stores offsets from the original coordinates + uint32 sourceYIndex = y + _internalBuffer[index].y; + uint32 sourceXIndex = x + _internalBuffer[index].x; + + destBuffer[destOffset] = sourceBuffer[sourceYIndex * _numColumns + sourceXIndex]; + destOffset++; + } + } +} + void RenderTable::generateRenderTable() { switch (_renderState) { case ZVision::RenderTable::PANORAMA: @@ -177,6 +196,7 @@ void RenderTable::generateTiltLookupTable() { float fovInRadians = (_tiltOptions.fieldOfView * M_PI / 180.0f); float cylinderRadius = halfWidth / tan(fovInRadians); + _tiltOptions.gap = cylinderRadius * atan2((float)(halfHeight / cylinderRadius), 1.0f) * _tiltOptions.linearScale; for (uint y = 0; y < _numRows; ++y) { @@ -221,6 +241,18 @@ void RenderTable::setPanoramaReverse(bool reverse) { _panoramaOptions.reverse = reverse; } +bool RenderTable::getPanoramaReverse() { + return _panoramaOptions.reverse; +} + +void RenderTable::setPanoramaZeroPoint(uint16 point) { + _panoramaOptions.zeroPoint = point; +} + +uint16 RenderTable::getPanoramaZeroPoint() { + return _panoramaOptions.zeroPoint; +} + void RenderTable::setTiltFoV(float fov) { assert(fov > 0.0f); @@ -237,4 +269,26 @@ void RenderTable::setTiltReverse(bool reverse) { _tiltOptions.reverse = reverse; } +float RenderTable::getTiltGap() { + return _tiltOptions.gap; +} + +float RenderTable::getAngle() { + if (_renderState == TILT) + return _tiltOptions.fieldOfView; + else if (_renderState == PANORAMA) + return _panoramaOptions.fieldOfView; + else + return 1.0; +} + +float RenderTable::getLinscale() { + if (_renderState == TILT) + return _tiltOptions.linearScale; + else if (_renderState == PANORAMA) + return _panoramaOptions.linearScale; + else + return 1.0; +} + } // End of namespace ZVision diff --git a/engines/zvision/graphics/render_table.h b/engines/zvision/graphics/render_table.h index f066187ad1..7455d9ba39 100644 --- a/engines/zvision/graphics/render_table.h +++ b/engines/zvision/graphics/render_table.h @@ -24,7 +24,7 @@ #define ZVISION_RENDER_TABLE_H #include "common/rect.h" - +#include "graphics/surface.h" namespace ZVision { @@ -49,6 +49,7 @@ private: float fieldOfView; float linearScale; bool reverse; + uint16 zeroPoint; } _panoramaOptions; // TODO: See if tilt and panorama need to have separate options @@ -56,25 +57,36 @@ private: float fieldOfView; float linearScale; bool reverse; + float gap; } _tiltOptions; public: - RenderState getRenderState() { return _renderState; } + RenderState getRenderState() { + return _renderState; + } void setRenderState(RenderState newState); const Common::Point convertWarpedCoordToFlatCoord(const Common::Point &point); - void mutateImage(uint16 *sourceBuffer, uint16* destBuffer, uint32 destWidth, const Common::Rect &subRect); + void mutateImage(uint16 *sourceBuffer, uint16 *destBuffer, uint32 destWidth, const Common::Rect &subRect); + void mutateImage(Graphics::Surface *dstBuf, Graphics::Surface *srcBuf); void generateRenderTable(); void setPanoramaFoV(float fov); void setPanoramaScale(float scale); void setPanoramaReverse(bool reverse); + void setPanoramaZeroPoint(uint16 point); + uint16 getPanoramaZeroPoint(); + bool getPanoramaReverse(); void setTiltFoV(float fov); void setTiltScale(float scale); void setTiltReverse(bool reverse); + float getTiltGap(); + float getAngle(); + float getLinscale(); + private: void generatePanoramaLookupTable(); void generateTiltLookupTable(); diff --git a/engines/zvision/graphics/subtitles.cpp b/engines/zvision/graphics/subtitles.cpp new file mode 100644 index 0000000000..784721562a --- /dev/null +++ b/engines/zvision/graphics/subtitles.cpp @@ -0,0 +1,108 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "zvision/graphics/render_manager.h" +#include "zvision/graphics/subtitles.h" +#include "zvision/core/search_manager.h" +#include "zvision/text/text.h" + +namespace ZVision { + +Subtitle::Subtitle(ZVision *engine, const Common::String &subname) : + _engine(engine), + _areaId(-1), + _subId(-1) { + Common::File file; + if (_engine->getSearchManager()->openFile(file, subname)) { + while (!file.eos()) { + Common::String str = file.readLine(); + if (str.lastChar() == '~') + str.deleteLastChar(); + + if (str.matchString("*Initialization*", true)) { + // Not used + } else if (str.matchString("*Rectangle*", true)) { + int32 x1, y1, x2, y2; + sscanf(str.c_str(), "%*[^:]:%d %d %d %d", &x1, &y1, &x2, &y2); + Common::Rect rct = Common::Rect(x1, y1, x2, y2); + _areaId = _engine->getRenderManager()->createSubArea(rct); + } else if (str.matchString("*TextFile*", true)) { + char filename[64]; + sscanf(str.c_str(), "%*[^:]:%s", filename); + Common::File txt; + if (_engine->getSearchManager()->openFile(txt, filename)) { + while (!txt.eos()) { + Common::String txtline = readWideLine(txt); + sub curSubtitle; + curSubtitle.start = -1; + curSubtitle.stop = -1; + curSubtitle.subStr = txtline; + + _subs.push_back(curSubtitle); + } + txt.close(); + } + } else { + int32 st; + int32 en; + int32 sb; + if (sscanf(str.c_str(), "%*[^:]:(%d,%d)=%d", &st, &en, &sb) == 3) { + if (sb <= (int32)_subs.size()) { + _subs[sb].start = st; + _subs[sb].stop = en; + } + } + } + } + } +} + +Subtitle::~Subtitle() { + if (_areaId != -1) + _engine->getRenderManager()->deleteSubArea(_areaId); + + _subs.clear(); +} + +void Subtitle::process(int32 time) { + int16 j = -1; + for (uint16 i = 0; i < _subs.size(); i++) + if (time >= _subs[i].start && time <= _subs[i].stop) { + j = i; + break; + } + + if (j == -1 && _subId != -1) { + if (_areaId != -1) + _engine->getRenderManager()->updateSubArea(_areaId, ""); + _subId = -1; + } + + if (j != -1 && j != _subId) { + if (_subs[j].subStr.size()) + if (_areaId != -1) + _engine->getRenderManager()->updateSubArea(_areaId, _subs[j].subStr); + _subId = j; + } +} + +} // End of namespace ZVision diff --git a/engines/zvision/subtitles/subtitles.h b/engines/zvision/graphics/subtitles.h index 776ddd3a97..c3da6583a4 100644 --- a/engines/zvision/subtitles/subtitles.h +++ b/engines/zvision/graphics/subtitles.h @@ -23,6 +23,32 @@ #ifndef ZVISION_SUBTITLES_H #define ZVISION_SUBTITLES_H -// TODO: Implement Subtitles +#include "zvision/zvision.h" + +namespace ZVision { + +class ZVision; + +class Subtitle { +public: + Subtitle(ZVision *engine, const Common::String &subname); + ~Subtitle(); + + void process(int32 time); +private: + ZVision *_engine; + int32 _areaId; + int16 _subId; + + struct sub { + int start; + int stop; + Common::String subStr; + }; + + Common::Array<sub> _subs; +}; + +} #endif diff --git a/engines/zvision/graphics/truetype_font.cpp b/engines/zvision/graphics/truetype_font.cpp new file mode 100644 index 0000000000..1a0e92087c --- /dev/null +++ b/engines/zvision/graphics/truetype_font.cpp @@ -0,0 +1,341 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" +#include "common/config-manager.h" +#include "common/debug.h" +#include "common/file.h" +#include "common/system.h" +#include "common/unzip.h" +#include "graphics/font.h" +#include "graphics/fonts/ttf.h" +#include "graphics/surface.h" + +#include "zvision/zvision.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/graphics/truetype_font.h" + +namespace ZVision { + +TruetypeFont::TruetypeFont(ZVision *engine, int32 fontHeight) + : _engine(engine), + _fontHeight(fontHeight), + _font(0), + _lineHeight(0), + _maxCharWidth(0), + _maxCharHeight(0) { +} + +TruetypeFont::~TruetypeFont(void) { + delete _font; +} + +bool TruetypeFont::loadFile(const Common::String &filename) { + Common::File file; + + bool fileOpened = false; + if (!Common::File::exists(filename)) { + debug("TTF font file %s was not found. Reverting to arial.ttf", filename.c_str()); + fileOpened = file.open("arial.ttf"); + } else { + fileOpened = file.open(filename); + } + + if (!fileOpened) { + debug("TTF file could not be opened"); + return false; + } + + _font = Graphics::loadTTFFont(file, _fontHeight); + _lineHeight = _font->getFontHeight(); + + return true; +} + +Graphics::Surface *TruetypeFont::drawTextToSurface(const Common::String &text, uint16 textColor, int maxWidth, int maxHeight, Graphics::TextAlign align, bool wrap) { + if (text.equals("")) { + return nullptr; + } + + Graphics::Surface *surface = new Graphics::Surface(); + + if (!wrap) { + int width = MIN(_font->getStringWidth(text), maxWidth); + surface->create(width, _lineHeight, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)); + // TODO: Add better alpha support by getting the pixels from the backbuffer. + // However doing that requires some kind of caching system so future text doesn't try to use this text as it's alpha background. + surface->fillRect(Common::Rect(0, 0, surface->w, surface->h), 0); + + _font->drawString(surface, text, 0, 0, maxWidth, textColor, align); + return surface; + } + + Common::Array<Common::String> lines; + _font->wordWrapText(text, maxWidth, lines); + + while (maxHeight > 0 && (int)lines.size() * _lineHeight > maxHeight) { + lines.pop_back(); + } + if (lines.size() == 0) { + delete surface; + return nullptr; + } + + surface->create(maxWidth, lines.size() * _lineHeight, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0)); + surface->fillRect(Common::Rect(0, 0, surface->w, surface->h), 0); + + int heightOffset = 0; + for (Common::Array<Common::String>::iterator it = lines.begin(); it != lines.end(); it++) { + _font->drawString(surface, *it, 0, 0 + heightOffset, maxWidth, textColor, align); + heightOffset += _lineHeight; + } + + return surface; +} + +StyledTTFont::StyledTTFont(ZVision *engine) { + _engine = engine; + _style = 0; + _font = NULL; + _lineHeight = 0; +} + +StyledTTFont::~StyledTTFont() { + if (_font) + delete _font; +} + +bool StyledTTFont::loadFont(const Common::String &fontName, int32 point, uint style) { + _style = style; + return loadFont(fontName, point); +} + +bool StyledTTFont::loadFont(const Common::String &fontName, int32 point) { + Common::String newFontName; + if (fontName.matchString("*times new roman*", true) || fontName.matchString("*times*", true)) { + if ((_style & (STTF_BOLD | STTF_ITALIC)) == (STTF_BOLD | STTF_ITALIC)) + newFontName = "timesbi.ttf"; + else if (_style & STTF_BOLD) + newFontName = "timesbd.ttf"; + else if (_style & STTF_ITALIC) + newFontName = "timesi.ttf"; + else + newFontName = "times.ttf"; + + } else if (fontName.matchString("*courier new*", true) || fontName.matchString("*courier*", true) || fontName.matchString("*ZorkDeath*", true)) { + if ((_style & (STTF_BOLD | STTF_ITALIC)) == (STTF_BOLD | STTF_ITALIC)) + newFontName = "courbi.ttf"; + else if (_style & STTF_BOLD) + newFontName = "courbd.ttf"; + else if (_style & STTF_ITALIC) + newFontName = "couri.ttf"; + else + newFontName = "cour.ttf"; + + } else if (fontName.matchString("*century schoolbook*", true)) { + if ((_style & (STTF_BOLD | STTF_ITALIC)) == (STTF_BOLD | STTF_ITALIC)) + newFontName = "censcbkbi.ttf"; + else if (_style & STTF_BOLD) + newFontName = "censcbkbd.ttf"; + else if (_style & STTF_ITALIC) + newFontName = "censcbki.ttf"; + else + newFontName = "censcbk.ttf"; + + } else if (fontName.matchString("*garamond*", true)) { + if ((_style & (STTF_BOLD | STTF_ITALIC)) == (STTF_BOLD | STTF_ITALIC)) + newFontName = "garabi.ttf"; + else if (_style & STTF_BOLD) + newFontName = "garabd.ttf"; + else if (_style & STTF_ITALIC) + newFontName = "garai.ttf"; + else + newFontName = "gara.ttf"; + + } else if (fontName.matchString("*arial*", true) || fontName.matchString("*ZorkNormal*", true)) { + if ((_style & (STTF_BOLD | STTF_ITALIC)) == (STTF_BOLD | STTF_ITALIC)) + newFontName = "arialbi.ttf"; + else if (_style & STTF_BOLD) + newFontName = "arialbd.ttf"; + else if (_style & STTF_ITALIC) + newFontName = "ariali.ttf"; + else + newFontName = "arial.ttf"; + + } else { + debug("Could not identify font: %s. Reverting to Arial", fontName.c_str()); + newFontName = "arial.ttf"; + } + + bool sharp = (_style & STTF_SHARP) == STTF_SHARP; + + Common::File *file = _engine->getSearchManager()->openFile(newFontName); + + if (!file) { + Common::SeekableReadStream *themeFile = nullptr; + if (ConfMan.hasKey("themepath")) { + Common::FSNode themePath(ConfMan.get("themepath")); + if (themePath.exists()) { + Common::FSNode scummModern = themePath.getChild("scummmodern.zip"); + if (scummModern.exists()) { + themeFile = scummModern.createReadStream(); + } + } + } + if (!themeFile) { // Fallback : Search for ScummModern.zip in SearchMan. + themeFile = SearchMan.createReadStreamForMember("scummmodern.zip"); + } + if (themeFile) { + Common::Archive *themeArchive = Common::makeZipArchive(themeFile); + if (themeArchive->hasFile("FreeSans.ttf")) { + Common::SeekableReadStream *stream = nullptr; + stream = themeArchive->createReadStreamForMember("FreeSans.ttf"); + Graphics::Font *_newFont = Graphics::loadTTFFont(*stream, point, 60, (sharp ? Graphics::kTTFRenderModeMonochrome : Graphics::kTTFRenderModeNormal)); // 66 dpi for 640 x 480 on 14" display + if (_newFont) { + if (!_font) + delete _font; + _font = _newFont; + } + if (stream) + delete stream; + } + delete themeArchive; + themeArchive = nullptr; + } + } else { + Graphics::Font *_newFont = Graphics::loadTTFFont(*file, point, 60, (sharp ? Graphics::kTTFRenderModeMonochrome : Graphics::kTTFRenderModeNormal)); // 66 dpi for 640 x 480 on 14" display + if (_newFont) { + if (!_font) + delete _font; + _font = _newFont; + } + delete file; + } + + _fntName = fontName; + _lineHeight = point; + + if (_font) + return true; + return false; +} + +void StyledTTFont::setStyle(uint newStyle) { + if ((_style & (STTF_BOLD | STTF_ITALIC | STTF_SHARP)) != (newStyle & (STTF_BOLD | STTF_ITALIC | STTF_SHARP))) { + _style = newStyle; + loadFont(_fntName, _lineHeight); + } else { + _style = newStyle; + } +} + +int StyledTTFont::getFontHeight() { + if (_font) + return _font->getFontHeight(); + return 0; +} + +int StyledTTFont::getMaxCharWidth() { + if (_font) + return _font->getMaxCharWidth(); + return 0; +} + +int StyledTTFont::getCharWidth(byte chr) { + if (_font) + return _font->getCharWidth(chr); + return 0; +} + +int StyledTTFont::getKerningOffset(byte left, byte right) { + if (_font) + return _font->getKerningOffset(left, right); + return 0; +} + +void StyledTTFont::drawChar(Graphics::Surface *dst, byte chr, int x, int y, uint32 color) { + if (_font) { + _font->drawChar(dst, chr, x, y, color); + if (_style & STTF_UNDERLINE) { + int16 pos = floor(_font->getFontHeight() * 0.87); + int thk = MAX((int)(_font->getFontHeight() * 0.05), 1); + dst->fillRect(Common::Rect(x, y + pos, x + _font->getCharWidth(chr), y + pos + thk), color); + } + if (_style & STTF_STRIKEOUT) { + int16 pos = floor(_font->getFontHeight() * 0.60); + int thk = MAX((int)(_font->getFontHeight() * 0.05), 1); + dst->fillRect(Common::Rect(x, y + pos, x + _font->getCharWidth(chr), y + pos + thk), color); + } + } +} + +void StyledTTFont::drawString(Graphics::Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, Graphics::TextAlign align) { + if (_font) { + _font->drawString(dst, str, x, y, w, color, align); + if (_style & STTF_UNDERLINE) { + int16 pos = floor(_font->getFontHeight() * 0.87); + int16 wd = MIN(_font->getStringWidth(str), w); + int16 stX = x; + if (align == Graphics::kTextAlignCenter) + stX += (w - wd) / 2; + else if (align == Graphics::kTextAlignRight) + stX += (w - wd); + + int thk = MAX((int)(_font->getFontHeight() * 0.05), 1); + + dst->fillRect(Common::Rect(stX, y + pos, stX + wd, y + pos + thk), color); + } + if (_style & STTF_STRIKEOUT) { + int16 pos = floor(_font->getFontHeight() * 0.60); + int16 wd = MIN(_font->getStringWidth(str), w); + int16 stX = x; + if (align == Graphics::kTextAlignCenter) + stX += (w - wd) / 2; + else if (align == Graphics::kTextAlignRight) + stX += (w - wd); + + int thk = MAX((int)(_font->getFontHeight() * 0.05), 1); + + dst->fillRect(Common::Rect(stX, y + pos, stX + wd, y + pos + thk), color); + } + } +} + +int StyledTTFont::getStringWidth(const Common::String &str) { + if (_font) + return _font->getStringWidth(str); + return 0; +} + +Graphics::Surface *StyledTTFont::renderSolidText(const Common::String &str, uint32 color) { + Graphics::Surface *tmp = new Graphics::Surface; + if (_font) { + int16 w = _font->getStringWidth(str); + if (w && w < 1024) { + tmp->create(w, _font->getFontHeight(), _engine->_pixelFormat); + drawString(tmp, str, 0, 0, w, color); + } + } + return tmp; +} + +} // End of namespace ZVision diff --git a/engines/zvision/fonts/truetype_font.h b/engines/zvision/graphics/truetype_font.h index 64f53a2c3b..30ef1c73a3 100644 --- a/engines/zvision/fonts/truetype_font.h +++ b/engines/zvision/graphics/truetype_font.h @@ -28,7 +28,6 @@ #include "graphics/font.h" #include "graphics/pixelformat.h" - namespace Graphics { struct Surface; } @@ -43,12 +42,12 @@ public: ~TruetypeFont(); private: -// ZVision *_engine; + ZVision *_engine; Graphics::Font *_font; int _lineHeight; -// size_t _maxCharWidth; -// size_t _maxCharHeight; + size_t _maxCharWidth; + size_t _maxCharHeight; public: int32 _fontHeight; @@ -76,6 +75,49 @@ public: Graphics::Surface *drawTextToSurface(const Common::String &text, uint16 textColor, int maxWidth, int maxHeight, Graphics::TextAlign align, bool wrap); }; +// Styled TTF +class StyledTTFont { +public: + StyledTTFont(ZVision *engine); + ~StyledTTFont(); + + enum { + STTF_BOLD = 1, + STTF_ITALIC = 2, + STTF_UNDERLINE = 4, + STTF_STRIKEOUT = 8, + STTF_SHARP = 16 + }; + +private: + ZVision *_engine; + Graphics::Font *_font; + int _lineHeight; + uint _style; + Common::String _fntName; + +public: + bool loadFont(const Common::String &fontName, int32 point); + bool loadFont(const Common::String &fontName, int32 point, uint style); + void setStyle(uint newStyle); + + int getFontHeight(); + int getMaxCharWidth(); + int getCharWidth(byte chr); + int getKerningOffset(byte left, byte right); + + void drawChar(Graphics::Surface *dst, byte chr, int x, int y, uint32 color); + + void drawString(Graphics::Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, Graphics::TextAlign align = Graphics::kTextAlignLeft); + int getStringWidth(const Common::String &str); + + Graphics::Surface *renderSolidText(const Common::String &str, uint32 color); + + bool isLoaded() { + return _font != NULL; + }; +}; + } // End of namespace ZVision #endif diff --git a/engines/zvision/module.mk b/engines/zvision/module.mk index 2e298f24c6..045eb5264a 100644 --- a/engines/zvision/module.mk +++ b/engines/zvision/module.mk @@ -1,32 +1,53 @@ MODULE := engines/zvision MODULE_OBJS := \ + animation/meta_animation.o \ animation/rlf_animation.o \ - archives/zfs_archive.o \ core/console.o \ core/events.o \ + core/menu.o \ + core/midi.o \ core/save_manager.o \ - cursors/cursor.o \ + core/search_manager.o \ cursors/cursor_manager.o \ + cursors/cursor.o \ detection.o \ - fonts/truetype_font.o \ + graphics/effects/fog.o \ + graphics/effects/light.o \ + graphics/effects/wave.o \ graphics/render_manager.o \ graphics/render_table.o \ + graphics/subtitles.o \ + graphics/truetype_font.o \ scripting/actions.o \ scripting/control.o \ - scripting/controls/animation_control.o \ + scripting/controls/fist_control.o \ + scripting/controls/hotmov_control.o \ scripting/controls/input_control.o \ scripting/controls/lever_control.o \ + scripting/controls/paint_control.o \ scripting/controls/push_toggle_control.o \ - scripting/controls/timer_node.o \ + scripting/controls/safe_control.o \ + scripting/controls/save_control.o \ + scripting/controls/slot_control.o \ + scripting/controls/titler_control.o \ + scripting/inventory.o \ scripting/scr_file_handling.o \ scripting/script_manager.o \ + scripting/sidefx/animation_node.o \ + scripting/sidefx/distort_node.o \ + scripting/sidefx/music_node.o \ + scripting/sidefx/region_node.o \ + scripting/sidefx/syncsound_node.o \ + scripting/sidefx/timer_node.o \ + scripting/sidefx/ttytext_node.o \ sound/zork_raw.o \ - strings/string_manager.o \ + text/string_manager.o \ + text/text.o \ utility/clock.o \ utility/lzss_read_stream.o \ - utility/single_value_container.o \ utility/utility.o \ + utility/zfs_archive.o \ video/video.o \ video/zork_avi_decoder.o \ zvision.o diff --git a/engines/zvision/scripting/actions.cpp b/engines/zvision/scripting/actions.cpp index 219f418b13..c8c82063f7 100644 --- a/engines/zvision/scripting/actions.cpp +++ b/engines/zvision/scripting/actions.cpp @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -29,372 +29,972 @@ #include "zvision/graphics/render_manager.h" #include "zvision/sound/zork_raw.h" #include "zvision/video/zork_avi_decoder.h" -#include "zvision/scripting/controls/timer_node.h" -#include "zvision/scripting/controls/animation_control.h" +#include "zvision/scripting/sidefx/timer_node.h" +#include "zvision/scripting/sidefx/music_node.h" +#include "zvision/scripting/sidefx/syncsound_node.h" +#include "zvision/scripting/sidefx/animation_node.h" +#include "zvision/scripting/sidefx/distort_node.h" +#include "zvision/scripting/sidefx/ttytext_node.h" +#include "zvision/scripting/sidefx/region_node.h" +#include "zvision/scripting/controls/titler_control.h" +#include "zvision/graphics/render_table.h" +#include "zvision/graphics/effect.h" +#include "zvision/graphics/effects/fog.h" +#include "zvision/graphics/effects/light.h" +#include "zvision/graphics/effects/wave.h" +#include "zvision/core/save_manager.h" +#include "zvision/cursors/cursor_manager.h" #include "common/file.h" #include "audio/decoders/wave.h" - namespace ZVision { ////////////////////////////////////////////////////////////////////////////// // ActionAdd ////////////////////////////////////////////////////////////////////////////// -ActionAdd::ActionAdd(const Common::String &line) { - sscanf(line.c_str(), "%*[^(](%u,%u)", &_key, &_value); +ActionAdd::ActionAdd(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%u,%d", &_key, &_value); } -bool ActionAdd::execute(ZVision *engine) { - engine->getScriptManager()->addToStateValue(_key, _value); +bool ActionAdd::execute() { + _engine->getScriptManager()->setStateValue(_key, _engine->getScriptManager()->getStateValue(_key) + _value); return true; } - ////////////////////////////////////////////////////////////////////////////// // ActionAssign ////////////////////////////////////////////////////////////////////////////// -ActionAssign::ActionAssign(const Common::String &line) { - sscanf(line.c_str(), "%*[^(](%u, %u)", &_key, &_value); +ActionAssign::ActionAssign(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char buf[64]; + memset(buf, 0, 64); + sscanf(line.c_str(), "%u, %s", &_key, buf); + _value = new ValueSlot(_engine->getScriptManager(), buf); } -bool ActionAssign::execute(ZVision *engine) { - engine->getScriptManager()->setStateValue(_key, _value); - return true; +ActionAssign::~ActionAssign() { + if (_value) + delete _value; } +bool ActionAssign::execute() { + _engine->getScriptManager()->setStateValue(_key, _value->getValue()); + return true; +} ////////////////////////////////////////////////////////////////////////////// // ActionAttenuate ////////////////////////////////////////////////////////////////////////////// -ActionAttenuate::ActionAttenuate(const Common::String &line) { - sscanf(line.c_str(), "%*[^(](%u, %d)", &_key, &_attenuation); +ActionAttenuate::ActionAttenuate(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%u, %d", &_key, &_attenuation); } -bool ActionAttenuate::execute(ZVision *engine) { - // TODO: Implement +bool ActionAttenuate::execute() { + SideFX *fx = _engine->getScriptManager()->getSideFX(_key); + if (fx && fx->getType() == SideFX::SIDEFX_AUDIO) { + MusicNode *mus = (MusicNode *)fx; + mus->setVolume(255 - (abs(_attenuation) >> 7)); + } return true; } - ////////////////////////////////////////////////////////////////////////////// // ActionChangeLocation ////////////////////////////////////////////////////////////////////////////// -ActionChangeLocation::ActionChangeLocation(const Common::String &line) { - sscanf(line.c_str(), "%*[^(](%c,%c,%c%c,%u)", &_world, &_room, &_node, &_view, &_offset); +ActionChangeLocation::ActionChangeLocation(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%c, %c, %c%c, %u", &_world, &_room, &_node, &_view, &_offset); } -bool ActionChangeLocation::execute(ZVision *engine) { +bool ActionChangeLocation::execute() { // We can't directly call ScriptManager::ChangeLocationIntern() because doing so clears all the Puzzles, and thus would corrupt the current puzzle checking - engine->getScriptManager()->changeLocation(_world, _room, _node, _view, _offset); + _engine->getScriptManager()->changeLocation(_world, _room, _node, _view, _offset); // Tell the puzzle system to stop checking any more puzzles return false; } - ////////////////////////////////////////////////////////////////////////////// // ActionCrossfade ////////////////////////////////////////////////////////////////////////////// -ActionCrossfade::ActionCrossfade(const Common::String &line) { +ActionCrossfade::ActionCrossfade(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { sscanf(line.c_str(), - "%*[^(](%u %u %u %u %u %u %u)", - &_keyOne, &_keyTwo, &_oneStartVolume, &_twoStartVolume, &_oneEndVolume, &_twoEndVolume, &_timeInMillis); + "%u %u %d %d %d %d %d", + &_keyOne, &_keyTwo, &_oneStartVolume, &_twoStartVolume, &_oneEndVolume, &_twoEndVolume, &_timeInMillis); +} + +bool ActionCrossfade::execute() { + if (_keyOne) { + SideFX *fx = _engine->getScriptManager()->getSideFX(_keyOne); + if (fx && fx->getType() == SideFX::SIDEFX_AUDIO) { + MusicNode *mus = (MusicNode *)fx; + if (_oneStartVolume >= 0) + mus->setVolume((_oneStartVolume * 255) / 100); + + mus->setFade(_timeInMillis, (_oneEndVolume * 255) / 100); + } + } + + if (_keyTwo) { + SideFX *fx = _engine->getScriptManager()->getSideFX(_keyTwo); + if (fx && fx->getType() == SideFX::SIDEFX_AUDIO) { + MusicNode *mus = (MusicNode *)fx; + if (_twoStartVolume >= 0) + mus->setVolume((_twoStartVolume * 255) / 100); + + mus->setFade(_timeInMillis, (_twoEndVolume * 255) / 100); + } + } + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// ActionCursor +////////////////////////////////////////////////////////////////////////////// + +ActionCursor::ActionCursor(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + Common::String up = line; + up.toUppercase(); + _action = 0; + + if (up[0] == 'B') + _action = 2; + else if (up[0] == 'I') + _action = 3; + else if (up[0] == 'U') + _action = 0; + else if (up[0] == 'H') + _action = 1; } -bool ActionCrossfade::execute(ZVision *engine) { - // TODO: Implement +bool ActionCursor::execute() { + switch (_action) { + case 1: + _engine->getCursorManager()->showMouse(false); + break; + default: + _engine->getCursorManager()->showMouse(true); + break; + } return true; } +////////////////////////////////////////////////////////////////////////////// +// ActionDelayRender +////////////////////////////////////////////////////////////////////////////// + +ActionDelayRender::ActionDelayRender(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%u", &_framesToDelay); +} + +bool ActionDelayRender::execute() { + _engine->setRenderDelay(_framesToDelay); + return true; +} ////////////////////////////////////////////////////////////////////////////// // ActionDisableControl ////////////////////////////////////////////////////////////////////////////// -ActionDisableControl::ActionDisableControl(const Common::String &line) { - sscanf(line.c_str(), "%*[^(](%u)", &_key); +ActionDisableControl::ActionDisableControl(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%u", &_key); +} + +bool ActionDisableControl::execute() { + _engine->getScriptManager()->setStateFlag(_key, Puzzle::DISABLED); + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// ActionDisableVenus +////////////////////////////////////////////////////////////////////////////// + +ActionDisableVenus::ActionDisableVenus(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%d", &_key); +} + +bool ActionDisableVenus::execute() { + _engine->getScriptManager()->setStateValue(_key, 0); + + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// ActionDisplayMessage +////////////////////////////////////////////////////////////////////////////// + +ActionDisplayMessage::ActionDisplayMessage(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%hd %hd", &_control, &_msgid); +} + +bool ActionDisplayMessage::execute() { + Control *ctrl = _engine->getScriptManager()->getControl(_control); + if (ctrl && ctrl->getType() == Control::CONTROL_TITLER) { + TitlerControl *titler = (TitlerControl *)ctrl; + titler->setString(_msgid); + } + return true; } -bool ActionDisableControl::execute(ZVision *engine) { - debug("Disabling control %u", _key); +////////////////////////////////////////////////////////////////////////////// +// ActionDissolve +////////////////////////////////////////////////////////////////////////////// - ScriptManager *scriptManager = engine->getScriptManager(); - scriptManager->setStateFlags(_key, scriptManager->getStateFlags(_key) | ScriptManager::DISABLED); +ActionDissolve::ActionDissolve(ZVision *engine) : + ResultAction(engine, 0) { +} +bool ActionDissolve::execute() { + // Cause black screen flick + // _engine->getRenderManager()->bkgFill(0, 0, 0); return true; } +////////////////////////////////////////////////////////////////////////////// +// ActionDistort +////////////////////////////////////////////////////////////////////////////// + +ActionDistort::ActionDistort(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%hd %hd %f %f %f %f", &_distSlot, &_speed, &_startAngle, &_endAngle, &_startLineScale, &_endLineScale); +} + +ActionDistort::~ActionDistort() { + _engine->getScriptManager()->killSideFx(_distSlot); +} + +bool ActionDistort::execute() { + if (_engine->getScriptManager()->getSideFX(_distSlot)) + return true; + + _engine->getScriptManager()->addSideFX(new DistortNode(_engine, _distSlot, _speed, _startAngle, _endAngle, _startLineScale, _endLineScale)); + + return true; +} ////////////////////////////////////////////////////////////////////////////// // ActionEnableControl ////////////////////////////////////////////////////////////////////////////// -ActionEnableControl::ActionEnableControl(const Common::String &line) { - sscanf(line.c_str(), "%*[^(](%u)", &_key); +ActionEnableControl::ActionEnableControl(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%u", &_key); +} + +bool ActionEnableControl::execute() { + _engine->getScriptManager()->unsetStateFlag(_key, Puzzle::DISABLED); + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// ActionFlushMouseEvents +////////////////////////////////////////////////////////////////////////////// + +ActionFlushMouseEvents::ActionFlushMouseEvents(ZVision *engine, int32 slotkey) : + ResultAction(engine, slotkey) { } -bool ActionEnableControl::execute(ZVision *engine) { - debug("Enabling control %u", _key); +bool ActionFlushMouseEvents::execute() { + _engine->getScriptManager()->flushEvent(Common::EVENT_LBUTTONUP); + _engine->getScriptManager()->flushEvent(Common::EVENT_LBUTTONDOWN); + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// ActionInventory +////////////////////////////////////////////////////////////////////////////// + +ActionInventory::ActionInventory(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char buf[25]; + sscanf(line.c_str(), "%25s %d", buf, &_key); + + if (strcmp(buf, "add") == 0) { + _type = 0; + } else if (strcmp(buf, "addi") == 0) { + _type = 1; + } else if (strcmp(buf, "drop") == 0) { + _type = 2; + } else if (strcmp(buf, "dropi") == 0) { + _type = 3; + } else if (strcmp(buf, "cycle") == 0) { + _type = 4; + } - ScriptManager *scriptManager = engine->getScriptManager(); - scriptManager->setStateFlags(_key, scriptManager->getStateFlags(_key) & ~ScriptManager::DISABLED); +} + +bool ActionInventory::execute() { + switch (_type) { + case 0: // add + _engine->getScriptManager()->inventoryAdd(_key); + break; + case 1: // addi + _engine->getScriptManager()->inventoryAdd(_engine->getScriptManager()->getStateValue(_key)); + break; + case 2: // drop + if (_key >= 0) + _engine->getScriptManager()->inventoryDrop(_key); + else + _engine->getScriptManager()->inventoryDrop(_engine->getScriptManager()->getStateValue(StateKey_InventoryItem)); + break; + case 3: // dropi + _engine->getScriptManager()->inventoryDrop(_engine->getScriptManager()->getStateValue(_key)); + break; + case 4: // cycle + _engine->getScriptManager()->inventoryCycle(); + break; + default: + break; + } + return true; +} +////////////////////////////////////////////////////////////////////////////// +// ActionKill +////////////////////////////////////////////////////////////////////////////// + +ActionKill::ActionKill(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + _key = 0; + _type = 0; + char keytype[25]; + sscanf(line.c_str(), "%25s", keytype); + if (keytype[0] == '"') { + if (!scumm_stricmp(keytype, "\"ANIM\"")) + _type = SideFX::SIDEFX_ANIM; + else if (!scumm_stricmp(keytype, "\"AUDIO\"")) + _type = SideFX::SIDEFX_AUDIO; + else if (!scumm_stricmp(keytype, "\"DISTORT\"")) + _type = SideFX::SIDEFX_DISTORT; + else if (!scumm_stricmp(keytype, "\"PANTRACK\"")) + _type = SideFX::SIDEFX_PANTRACK; + else if (!scumm_stricmp(keytype, "\"REGION\"")) + _type = SideFX::SIDEFX_REGION; + else if (!scumm_stricmp(keytype, "\"TIMER\"")) + _type = SideFX::SIDEFX_TIMER; + else if (!scumm_stricmp(keytype, "\"TTYTEXT\"")) + _type = SideFX::SIDEFX_TTYTXT; + else if (!scumm_stricmp(keytype, "\"ALL\"")) + _type = SideFX::SIDEFX_ALL; + } else + _key = atoi(keytype); +} + +bool ActionKill::execute() { + if (_type) + _engine->getScriptManager()->killSideFxType((SideFX::SideFXType)_type); + else + _engine->getScriptManager()->killSideFx(_key); return true; } +////////////////////////////////////////////////////////////////////////////// +// ActionMenuBarEnable +////////////////////////////////////////////////////////////////////////////// + +ActionMenuBarEnable::ActionMenuBarEnable(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%hu", &_menus); +} + +bool ActionMenuBarEnable::execute() { + _engine->menuBarEnable(_menus); + return true; +} ////////////////////////////////////////////////////////////////////////////// // ActionMusic ////////////////////////////////////////////////////////////////////////////// -ActionMusic::ActionMusic(const Common::String &line) : _volume(255) { +ActionMusic::ActionMusic(ZVision *engine, int32 slotkey, const Common::String &line, bool global) : + ResultAction(engine, slotkey), + _volume(255), + _universe(global) { uint type; - char fileNameBuffer[26]; + char fileNameBuffer[25]; uint loop; uint volume = 255; - sscanf(line.c_str(), "%*[^:]:%*[^:]:%u(%u %25s %u %u)", &_key, &type, fileNameBuffer, &loop, &volume); + sscanf(line.c_str(), "%u %25s %u %u", &type, fileNameBuffer, &loop, &volume); // type 4 are midi sound effect files if (type == 4) { - _soundType = Audio::Mixer::kSFXSoundType; - _fileName = Common::String::format("midi/%s/%u.wav", fileNameBuffer, loop); - _loop = false; + _midi = true; + int note; + int prog; + sscanf(line.c_str(), "%u %d %d %u", &type, &prog, ¬e, &volume); + _volume = volume; + _note = note; + _prog = prog; } else { - // TODO: See what the other types are so we can specify the correct Mixer::SoundType. In the meantime use kPlainSoundType - _soundType = Audio::Mixer::kPlainSoundType; + _midi = false; _fileName = Common::String(fileNameBuffer); _loop = loop == 1 ? true : false; - } - // Volume is optional. If it doesn't appear, assume full volume - if (volume != 255) { - // Volume in the script files is mapped to [0, 100], but the ScummVM mixer uses [0, 255] - _volume = volume * 255 / 100; + // Volume is optional. If it doesn't appear, assume full volume + if (volume != 255) { + // Volume in the script files is mapped to [0, 100], but the ScummVM mixer uses [0, 255] + _volume = volume * 255 / 100; + } } } -bool ActionMusic::execute(ZVision *engine) { - Audio::RewindableAudioStream *audioStream; +ActionMusic::~ActionMusic() { + if (!_universe) + _engine->getScriptManager()->killSideFx(_slotKey); +} + +bool ActionMusic::execute() { + if (_engine->getScriptManager()->getSideFX(_slotKey)) + return true; - if (_fileName.contains(".wav")) { - Common::File *file = new Common::File(); - if (file->open(_fileName)) { - audioStream = Audio::makeWAVStream(file, DisposeAfterUse::YES); - } else { - warning("Unable to open %s", _fileName.c_str()); - return false; - } + if (_midi) { + _engine->getScriptManager()->addSideFX(new MusicMidiNode(_engine, _slotKey, _prog, _note, _volume)); } else { - audioStream = makeRawZorkStream(_fileName, engine); - } + if (!_engine->getSearchManager()->hasFile(_fileName)) + return true; - if (_loop) { - Audio::LoopingAudioStream *loopingAudioStream = new Audio::LoopingAudioStream(audioStream, 0, DisposeAfterUse::YES); - engine->_mixer->playStream(_soundType, 0, loopingAudioStream, -1, _volume); - } else { - engine->_mixer->playStream(_soundType, 0, audioStream, -1, _volume); + _engine->getScriptManager()->addSideFX(new MusicNode(_engine, _slotKey, _fileName, _loop, _volume)); } return true; } +////////////////////////////////////////////////////////////////////////////// +// ActionPanTrack +////////////////////////////////////////////////////////////////////////////// + +ActionPanTrack::ActionPanTrack(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey), + _pos(0), + _musicSlot(0) { + + sscanf(line.c_str(), "%u %d", &_musicSlot, &_pos); +} + +ActionPanTrack::~ActionPanTrack() { + _engine->getScriptManager()->killSideFx(_slotKey); +} + +bool ActionPanTrack::execute() { + if (_engine->getScriptManager()->getSideFX(_slotKey)) + return true; + + _engine->getScriptManager()->addSideFX(new PanTrackNode(_engine, _slotKey, _musicSlot, _pos)); + + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// ActionPreferences +////////////////////////////////////////////////////////////////////////////// + +ActionPreferences::ActionPreferences(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + if (line.compareToIgnoreCase("save") == 0) + _save = true; + else + _save = false; +} + +bool ActionPreferences::execute() { + if (_save) + _engine->saveSettings(); + else + _engine->loadSettings(); + + return true; +} ////////////////////////////////////////////////////////////////////////////// // ActionPreloadAnimation ////////////////////////////////////////////////////////////////////////////// -ActionPreloadAnimation::ActionPreloadAnimation(const Common::String &line) { - char fileName[26]; +ActionPreloadAnimation::ActionPreloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char fileName[25]; // The two %*u are always 0 and dont seem to have a use - sscanf(line.c_str(), "%*[^:]:%*[^:]:%u(%25s %*u %*u %u %u)", &_key, fileName, &_mask, &_framerate); + sscanf(line.c_str(), "%25s %*u %*u %d %d", fileName, &_mask, &_framerate); + + if (_mask > 0) { + byte r, g, b; + Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0).colorToRGB(_mask, r, g, b); + _mask = _engine->_pixelFormat.RGBToColor(r, g, b); + } _fileName = Common::String(fileName); } -bool ActionPreloadAnimation::execute(ZVision *engine) { - // TODO: We ignore the mask and framerate atm. Mask refers to a key color used for binary alpha. We assume the framerate is the default framerate embedded in the videos - - // TODO: Check if the Control already exists +ActionPreloadAnimation::~ActionPreloadAnimation() { + _engine->getScriptManager()->deleteSideFx(_slotKey); +} - // Create the control, but disable it until PlayPreload is called - ScriptManager *scriptManager = engine->getScriptManager(); - scriptManager->addControl(new AnimationControl(engine, _key, _fileName)); - scriptManager->setStateFlags(_key, scriptManager->getStateFlags(_key) | ScriptManager::DISABLED); +bool ActionPreloadAnimation::execute() { + AnimationNode *nod = (AnimationNode *)_engine->getScriptManager()->getSideFX(_slotKey); + if (!nod) { + nod = new AnimationNode(_engine, _slotKey, _fileName, _mask, _framerate, false); + _engine->getScriptManager()->addSideFX(nod); + } else + nod->stop(); + _engine->getScriptManager()->setStateValue(_slotKey, 2); return true; } +////////////////////////////////////////////////////////////////////////////// +// ActionUnloadAnimation +////////////////////////////////////////////////////////////////////////////// + +ActionUnloadAnimation::ActionUnloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + + sscanf(line.c_str(), "%u", &_key); +} + +bool ActionUnloadAnimation::execute() { + AnimationNode *nod = (AnimationNode *)_engine->getScriptManager()->getSideFX(_key); + + if (nod && nod->getType() == SideFX::SIDEFX_ANIM) + _engine->getScriptManager()->deleteSideFx(_key); + + return true; +} ////////////////////////////////////////////////////////////////////////////// // ActionPlayAnimation ////////////////////////////////////////////////////////////////////////////// -ActionPlayAnimation::ActionPlayAnimation(const Common::String &line) { - char fileName[26]; +ActionPlayAnimation::ActionPlayAnimation(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char fileName[25]; // The two %*u are always 0 and dont seem to have a use sscanf(line.c_str(), - "%*[^:]:%*[^:]:%u(%25s %u %u %u %u %u %u %u %*u %*u %u %u)", - &_key, fileName, &_x, &_y, &_width, &_height, &_start, &_end, &_loopCount, &_mask, &_framerate); + "%25s %u %u %u %u %u %u %d %*u %*u %d %d", + fileName, &_x, &_y, &_x2, &_y2, &_start, &_end, &_loopCount, &_mask, &_framerate); + + if (_mask > 0) { + byte r, g, b; + Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0).colorToRGB(_mask, r, g, b); + _mask = _engine->_pixelFormat.RGBToColor(r, g, b); + } _fileName = Common::String(fileName); } -bool ActionPlayAnimation::execute(ZVision *engine) { - // TODO: Implement - return true; +ActionPlayAnimation::~ActionPlayAnimation() { + _engine->getScriptManager()->deleteSideFx(_slotKey); } +bool ActionPlayAnimation::execute() { + AnimationNode *nod = (AnimationNode *)_engine->getScriptManager()->getSideFX(_slotKey); + + if (!nod) { + nod = new AnimationNode(_engine, _slotKey, _fileName, _mask, _framerate); + _engine->getScriptManager()->addSideFX(nod); + } else + nod->stop(); + + if (nod) + nod->addPlayNode(_slotKey, _x, _y, _x2, _y2, _start, _end, _loopCount); + + return true; +} ////////////////////////////////////////////////////////////////////////////// // ActionPlayPreloadAnimation ////////////////////////////////////////////////////////////////////////////// -ActionPlayPreloadAnimation::ActionPlayPreloadAnimation(const Common::String &line) { +ActionPlayPreloadAnimation::ActionPlayPreloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { sscanf(line.c_str(), - "%*[^:]:%*[^:]:%u(%u %u %u %u %u %u %u %u)", - &_animationKey, &_controlKey, &_x1, &_y1, &_x2, &_y2, &_startFrame, &_endFrame, &_loopCount); + "%u %u %u %u %u %u %u %u", + &_controlKey, &_x1, &_y1, &_x2, &_y2, &_startFrame, &_endFrame, &_loopCount); } -bool ActionPlayPreloadAnimation::execute(ZVision *engine) { - // Find the control - AnimationControl *control = (AnimationControl *)engine->getScriptManager()->getControl(_controlKey); - - // Set the needed values within the control - control->setAnimationKey(_animationKey); - control->setLoopCount(_loopCount); - control->setXPos(_x1); - control->setYPost(_y1); +bool ActionPlayPreloadAnimation::execute() { + AnimationNode *nod = (AnimationNode *)_engine->getScriptManager()->getSideFX(_controlKey); - // Enable the control. ScriptManager will take care of the rest - control->enable(); + if (nod) + nod->addPlayNode(_slotKey, _x1, _y1, _x2, _y2, _startFrame, _endFrame, _loopCount); return true; } - ////////////////////////////////////////////////////////////////////////////// // ActionQuit ////////////////////////////////////////////////////////////////////////////// -bool ActionQuit::execute(ZVision *engine) { - engine->quitGame(); +bool ActionQuit::execute() { + _engine->quitGame(); return true; } +////////////////////////////////////////////////////////////////////////////// +// ActionRegion +////////////////////////////////////////////////////////////////////////////// + +ActionRegion::ActionRegion(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + + char art[64]; + char custom[64]; + + int32 x1, x2, y1, y2; + + sscanf(line.c_str(), "%s %d %d %d %d %hu %hu %hu %hu %s", art, &x1, &y1, &x2, &y2, &_delay, &_type, &_unk1, &_unk2, custom); + _art = Common::String(art); + _custom = Common::String(custom); + _rect = Common::Rect(x1, y1, x2 + 1, y2 + 1); +} + +ActionRegion::~ActionRegion() { + _engine->getScriptManager()->killSideFx(_slotKey); +} + +bool ActionRegion::execute() { + if (_engine->getScriptManager()->getSideFX(_slotKey)) + return true; + + Effect *effct = NULL; + switch (_type) { + case 0: { + uint16 centerX, centerY, frames; + double amplitude, waveln, speed; + sscanf(_custom.c_str(), "%hu,%hu,%hu,%lf,%lf,%lf,", ¢erX, ¢erY, &frames, &litude, &waveln, &speed); + effct = new WaveFx(_engine, _slotKey, _rect, _unk1, frames, centerX, centerY, amplitude, waveln, speed); + } + break; + case 1: { + uint16 aX, aY, aD; + if (_engine->getRenderManager()->getRenderTable()->getRenderState() == RenderTable::PANORAMA) + sscanf(_art.c_str(), "useart[%hu,%hu,%hu]", &aY, &aX, &aD); + else + sscanf(_art.c_str(), "useart[%hu,%hu,%hu]", &aX, &aY, &aD); + int8 minD; + int8 maxD; + EffectMap *_map = _engine->getRenderManager()->makeEffectMap(Common::Point(aX, aY), aD, _rect, &minD, &maxD); + effct = new LightFx(_engine, _slotKey, _rect, _unk1, _map, atoi(_custom.c_str()), minD, maxD); + } + break; + case 9: { + int16 dum1; + int32 dum2; + char buf[64]; + sscanf(_custom.c_str(), "%hd,%d,%s", &dum1, &dum2, buf); + Graphics::Surface tempMask; + _engine->getRenderManager()->readImageToSurface(_art, tempMask); + if (_rect.width() != tempMask.w) + _rect.setWidth(tempMask.w); + if (_rect.height() != tempMask.h) + _rect.setHeight(tempMask.h); + + EffectMap *_map = _engine->getRenderManager()->makeEffectMap(tempMask, 0); + effct = new FogFx(_engine, _slotKey, _rect, _unk1, _map, Common::String(buf)); + } + break; + default: + break; + } + + if (effct) { + _engine->getScriptManager()->addSideFX(new RegionNode(_engine, _slotKey, effct, _delay)); + _engine->getRenderManager()->addEffect(effct); + } + + return true; +} ////////////////////////////////////////////////////////////////////////////// // ActionRandom ////////////////////////////////////////////////////////////////////////////// -ActionRandom::ActionRandom(const Common::String &line) { - sscanf(line.c_str(), "%*[^:]:%*[^:]:%u, %u)", &_key, &_max); +ActionRandom::ActionRandom(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char maxBuffer[64]; + memset(maxBuffer, 0, 64); + sscanf(line.c_str(), "%s", maxBuffer); + _max = new ValueSlot(_engine->getScriptManager(), maxBuffer); } -bool ActionRandom::execute(ZVision *engine) { - uint randNumber = engine->getRandomSource()->getRandomNumber(_max); - engine->getScriptManager()->setStateValue(_key, randNumber); +ActionRandom::~ActionRandom() { + if (_max) + delete _max; +} + +bool ActionRandom::execute() { + uint randNumber = _engine->getRandomSource()->getRandomNumber(_max->getValue()); + _engine->getScriptManager()->setStateValue(_slotKey, randNumber); return true; } +////////////////////////////////////////////////////////////////////////////// +// ActionRestoreGame +////////////////////////////////////////////////////////////////////////////// + +ActionRestoreGame::ActionRestoreGame(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char buf[128]; + sscanf(line.c_str(), "%s", buf); + _fileName = Common::String(buf); +} + +bool ActionRestoreGame::execute() { + _engine->getSaveManager()->loadGame(_fileName); + return false; +} + +////////////////////////////////////////////////////////////////////////////// +// ActionRotateTo +////////////////////////////////////////////////////////////////////////////// + +ActionRotateTo::ActionRotateTo(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%d, %d", &_toPos, &_time); +} + +bool ActionRotateTo::execute() { + _engine->rotateTo(_toPos, _time); + + return true; +} ////////////////////////////////////////////////////////////////////////////// // ActionSetPartialScreen ////////////////////////////////////////////////////////////////////////////// -ActionSetPartialScreen::ActionSetPartialScreen(const Common::String &line) { - char fileName[26]; - uint color; +ActionSetPartialScreen::ActionSetPartialScreen(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char fileName[25]; + int color; - sscanf(line.c_str(), "%*[^(](%u %u %25s %*u %u)", &_x, &_y, fileName, &color); + sscanf(line.c_str(), "%u %u %25s %*u %d", &_x, &_y, fileName, &color); _fileName = Common::String(fileName); - if (color > 0xFFFF) { + if (color >= 0) { + byte r, g, b; + Graphics::PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0).colorToRGB(color, r, g, b); + _backgroundColor = _engine->_pixelFormat.RGBToColor(r, g, b); + } else { + _backgroundColor = color; + } + + if (color > 65535) { warning("Background color for ActionSetPartialScreen is bigger than a uint16"); } - _backgroundColor = color; } -bool ActionSetPartialScreen::execute(ZVision *engine) { - RenderManager *renderManager = engine->getRenderManager(); +bool ActionSetPartialScreen::execute() { + RenderManager *renderManager = _engine->getRenderManager(); - if (_backgroundColor > 0) { - renderManager->clearWorkingWindowTo555Color(_backgroundColor); + if (_engine->getGameId() == GID_NEMESIS) { + if (_backgroundColor) + renderManager->renderImageToBackground(_fileName, _x, _y, 0, 0); + else + renderManager->renderImageToBackground(_fileName, _x, _y); + } else { + if (_backgroundColor >= 0) + renderManager->renderImageToBackground(_fileName, _x, _y, _backgroundColor); + else if (_backgroundColor == -2) + renderManager->renderImageToBackground(_fileName, _x, _y, 0, 0); + else + renderManager->renderImageToBackground(_fileName, _x, _y); } - renderManager->renderImageToScreen(_fileName, _x, _y); return true; } - ////////////////////////////////////////////////////////////////////////////// // ActionSetScreen ////////////////////////////////////////////////////////////////////////////// -ActionSetScreen::ActionSetScreen(const Common::String &line) { - char fileName[26]; - sscanf(line.c_str(), "%*[^(](%25[^)])", fileName); +ActionSetScreen::ActionSetScreen(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char fileName[25]; + sscanf(line.c_str(), "%25s", fileName); _fileName = Common::String(fileName); } -bool ActionSetScreen::execute(ZVision *engine) { - engine->getRenderManager()->setBackgroundImage(_fileName); +bool ActionSetScreen::execute() { + _engine->getRenderManager()->setBackgroundImage(_fileName); + + return true; +} + +////////////////////////////////////////////////////////////////////////////// +// ActionSetVenus +////////////////////////////////////////////////////////////////////////////// + +ActionSetVenus::ActionSetVenus(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + sscanf(line.c_str(), "%d", &_key); +} + +bool ActionSetVenus::execute() { + if (_engine->getScriptManager()->getStateValue(_key)) + _engine->getScriptManager()->setStateValue(StateKey_Venus, _key); return true; } +////////////////////////////////////////////////////////////////////////////// +// ActionStop +////////////////////////////////////////////////////////////////////////////// + +ActionStop::ActionStop(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + _key = 0; + sscanf(line.c_str(), "%u", &_key); +} + +bool ActionStop::execute() { + _engine->getScriptManager()->stopSideFx(_key); + return true; +} ////////////////////////////////////////////////////////////////////////////// // ActionStreamVideo ////////////////////////////////////////////////////////////////////////////// -ActionStreamVideo::ActionStreamVideo(const Common::String &line) { - char fileName[26]; - uint skippable; +ActionStreamVideo::ActionStreamVideo(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char fileName[25]; + uint skipline; //skipline - render video with skip every second line, not skippable. - sscanf(line.c_str(), "%*[^(](%25s %u %u %u %u %u %u)", fileName, &_x1, &_y1, &_x2, &_y2, &_flags, &skippable); + sscanf(line.c_str(), "%25s %u %u %u %u %u %u", fileName, &_x1, &_y1, &_x2, &_y2, &_flags, &skipline); _fileName = Common::String(fileName); - _skippable = (skippable == 0) ? false : true; + _skippable = true; } -bool ActionStreamVideo::execute(ZVision *engine) { +bool ActionStreamVideo::execute() { ZorkAVIDecoder decoder; - if (!decoder.loadFile(_fileName)) { - return true; - } + Common::File *_file = _engine->getSearchManager()->openFile(_fileName); + + if (_file) { + if (!decoder.loadStream(_file)) { + return true; + } + + _engine->getCursorManager()->showMouse(false); + + Common::Rect destRect = Common::Rect(_x1, _y1, _x2 + 1, _y2 + 1); + + Common::String subname = _fileName; + subname.setChar('s', subname.size() - 3); + subname.setChar('u', subname.size() - 2); + subname.setChar('b', subname.size() - 1); + + Subtitle *sub = NULL; + + if (_engine->getSearchManager()->hasFile(subname)) + sub = new Subtitle(_engine, subname); - Common::Rect destRect; - if ((_flags & DIFFERENT_DIMENSIONS) == DIFFERENT_DIMENSIONS) { - destRect = Common::Rect(_x1, _y1, _x2, _y2); + _engine->playVideo(decoder, destRect, _skippable, sub); + + _engine->getCursorManager()->showMouse(true); + + if (sub) + delete sub; } - engine->playVideo(decoder, destRect, _skippable); return true; } +////////////////////////////////////////////////////////////////////////////// +// ActionSyncSound +////////////////////////////////////////////////////////////////////////////// + +ActionSyncSound::ActionSyncSound(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char fileName[25]; + int notUsed; + + sscanf(line.c_str(), "%d %d %25s", &_syncto, ¬Used, fileName); + + _fileName = Common::String(fileName); +} + +bool ActionSyncSound::execute() { + SideFX *fx = _engine->getScriptManager()->getSideFX(_syncto); + if (!fx) + return true; + + if (!(fx->getType() & SideFX::SIDEFX_ANIM)) + return true; + + AnimationNode *animnode = (AnimationNode *)fx; + if (animnode->getFrameDelay() > 200) // Hack for fix incorrect framedelay in some animpreload + animnode->setNewFrameDelay(66); // ~15fps + + _engine->getScriptManager()->addSideFX(new SyncSoundNode(_engine, _slotKey, _fileName, _syncto)); + return true; +} ////////////////////////////////////////////////////////////////////////////// // ActionTimer ////////////////////////////////////////////////////////////////////////////// -ActionTimer::ActionTimer(const Common::String &line) { - sscanf(line.c_str(), "%*[^:]:%*[^:]:%u(%u)", &_key, &_time); +ActionTimer::ActionTimer(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char timeBuffer[64]; + memset(timeBuffer, 0, 64); + sscanf(line.c_str(), "%s", timeBuffer); + _time = new ValueSlot(_engine->getScriptManager(), timeBuffer); +} + +ActionTimer::~ActionTimer() { + if (_time) + delete _time; + _engine->getScriptManager()->killSideFx(_slotKey); +} + +bool ActionTimer::execute() { + if (_engine->getScriptManager()->getSideFX(_slotKey)) + return true; + _engine->getScriptManager()->addSideFX(new TimerNode(_engine, _slotKey, _time->getValue())); + return true; } -bool ActionTimer::execute(ZVision *engine) { - engine->getScriptManager()->addControl(new TimerNode(engine, _key, _time)); +////////////////////////////////////////////////////////////////////////////// +// ActionTtyText +////////////////////////////////////////////////////////////////////////////// + +ActionTtyText::ActionTtyText(ZVision *engine, int32 slotkey, const Common::String &line) : + ResultAction(engine, slotkey) { + char filename[64]; + int32 x1, y1, x2, y2; + sscanf(line.c_str(), "%d %d %d %d %s %u", &x1, &y1, &x2, &y2, filename, &_delay); + _r = Common::Rect(x1, y1, x2, y2); + _filename = Common::String(filename); +} + +ActionTtyText::~ActionTtyText() { + _engine->getScriptManager()->killSideFx(_slotKey); +} + +bool ActionTtyText::execute() { + if (_engine->getScriptManager()->getSideFX(_slotKey)) + return true; + _engine->getScriptManager()->addSideFX(new ttyTextNode(_engine, _slotKey, _filename, _r, _delay)); return true; } diff --git a/engines/zvision/scripting/actions.h b/engines/zvision/scripting/actions.h index 01457d21cc..f9e4ee8167 100644 --- a/engines/zvision/scripting/actions.h +++ b/engines/zvision/scripting/actions.h @@ -24,14 +24,15 @@ #define ZVISION_ACTIONS_H #include "common/str.h" +#include "common/rect.h" #include "audio/mixer.h" - namespace ZVision { // Forward declaration of ZVision. This file is included before ZVision is declared class ZVision; +class ValueSlot; /** * The base class that represents any action that a Puzzle can take. @@ -39,6 +40,7 @@ class ZVision; */ class ResultAction { public: + ResultAction(ZVision *engine, int32 slotkey) : _engine(engine), _slotKey(slotkey) {} virtual ~ResultAction() {} /** * This is called by the script system whenever a Puzzle's criteria are found to be true. @@ -48,75 +50,47 @@ public: * @param engine A pointer to the base engine so the ResultAction can access all the necessary methods * @return Should the script system continue to test any remaining puzzles (true) or immediately break and go on to the next frame (false) */ - virtual bool execute(ZVision *engine) = 0; -}; - - -// The different types of actions -// DEBUG, -// DISABLE_CONTROL, -// DISABLE_VENUS, -// DISPLAY_MESSAGE, -// DISSOLVE, -// DISTORT, -// ENABLE_CONTROL, -// FLUSH_MOUSE_EVENTS, -// INVENTORY, -// KILL, -// MENU_BAR_ENABLE, -// MUSIC, -// PAN_TRACK, -// PLAY_PRELOAD, -// PREFERENCES, -// QUIT, -// RANDOM, -// REGION, -// RESTORE_GAME, -// ROTATE_TO, -// SAVE_GAME, -// SET_PARTIAL_SCREEN, -// SET_SCREEN, -// SET_VENUS, -// STOP, -// STREAM_VIDEO, -// SYNC_SOUND, -// TTY_TEXT, -// UNIVERSE_MUSIC, + virtual bool execute() = 0; +protected: + ZVision *_engine; + int32 _slotKey; +}; class ActionAdd : public ResultAction { public: - ActionAdd(const Common::String &line); - bool execute(ZVision *engine); + ActionAdd(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: uint32 _key; - uint _value; + int _value; }; class ActionAssign : public ResultAction { public: - ActionAssign(const Common::String &line); - bool execute(ZVision *engine); + ActionAssign(ZVision *engine, int32 slotkey, const Common::String &line); + ~ActionAssign(); + bool execute(); private: uint32 _key; - uint _value; + ValueSlot *_value; }; class ActionAttenuate : public ResultAction { public: - ActionAttenuate(const Common::String &line); - bool execute(ZVision *engine); + ActionAttenuate(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: uint32 _key; - int _attenuation; + int32 _attenuation; }; class ActionChangeLocation : public ResultAction { public: - ActionChangeLocation(const Common::String &line); - bool execute(ZVision *engine); + ActionChangeLocation(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: char _world; @@ -128,41 +102,49 @@ private: class ActionCrossfade : public ResultAction { public: - ActionCrossfade(const Common::String &line); - bool execute(ZVision *engine); + ActionCrossfade(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: uint32 _keyOne; uint32 _keyTwo; - uint _oneStartVolume; - uint _twoStartVolume; - uint _oneEndVolume; - uint _twoEndVolume; - uint _timeInMillis; + int32 _oneStartVolume; + int32 _twoStartVolume; + int32 _oneEndVolume; + int32 _twoEndVolume; + int32 _timeInMillis; +}; + +class ActionCursor : public ResultAction { +public: + ActionCursor(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); + +private: + uint8 _action; }; class ActionDebug : public ResultAction { public: - ActionDebug(const Common::String &line); - bool execute(ZVision *engine); + ActionDebug(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: }; class ActionDelayRender : public ResultAction { public: - ActionDelayRender(const Common::String &line); - bool execute(ZVision *engine); + ActionDelayRender(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: - // TODO: Check if this should actually be frames or if it should be milliseconds/seconds - uint32 framesToDelay; + uint32 _framesToDelay; }; class ActionDisableControl : public ResultAction { public: - ActionDisableControl(const Common::String &line); - bool execute(ZVision *engine); + ActionDisableControl(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: uint32 _key; @@ -170,79 +152,138 @@ private: class ActionDisableVenus : public ResultAction { public: - ActionDisableVenus(const Common::String &line); - bool execute(ZVision *engine); + ActionDisableVenus(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: + int32 _key; }; class ActionDisplayMessage : public ResultAction { public: - ActionDisplayMessage(const Common::String &line); - bool execute(ZVision *engine); + ActionDisplayMessage(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: + int16 _control; + int16 _msgid; }; class ActionDissolve : public ResultAction { public: - ActionDissolve(); - bool execute(ZVision *engine); + ActionDissolve(ZVision *engine); + bool execute(); }; class ActionDistort : public ResultAction { public: - ActionDistort(const Common::String &line); - bool execute(ZVision *engine); + ActionDistort(ZVision *engine, int32 slotkey, const Common::String &line); + ~ActionDistort(); + bool execute(); private: + int16 _distSlot; + int16 _speed; + float _startAngle; + float _endAngle; + float _startLineScale; + float _endLineScale; }; class ActionEnableControl : public ResultAction { public: - ActionEnableControl(const Common::String &line); - bool execute(ZVision *engine); + ActionEnableControl(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); + +private: + uint32 _key; +}; + +class ActionFlushMouseEvents : public ResultAction { +public: + ActionFlushMouseEvents(ZVision *engine, int32 slotkey); + bool execute(); +}; + +class ActionInventory : public ResultAction { +public: + ActionInventory(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); +private: + uint8 _type; + int32 _key; +}; + +class ActionKill : public ResultAction { +public: + ActionKill(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: uint32 _key; + uint32 _type; +}; + +class ActionMenuBarEnable : public ResultAction { +public: + ActionMenuBarEnable(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); +private: + uint16 _menus; }; class ActionMusic : public ResultAction { public: - ActionMusic(const Common::String &line); - bool execute(ZVision *engine); + ActionMusic(ZVision *engine, int32 slotkey, const Common::String &line, bool global); + ~ActionMusic(); + bool execute(); private: uint32 _key; - Audio::Mixer::SoundType _soundType; Common::String _fileName; bool _loop; byte _volume; + bool _universe; + bool _midi; + int8 _note; + int8 _prog; +}; + +class ActionPanTrack : public ResultAction { +public: + ActionPanTrack(ZVision *engine, int32 slotkey, const Common::String &line); + ~ActionPanTrack(); + bool execute(); + +private: + int32 _pos; + uint32 _musicSlot; }; class ActionPlayAnimation : public ResultAction { public: - ActionPlayAnimation(const Common::String &line); - bool execute(ZVision *engine); + ActionPlayAnimation(ZVision *engine, int32 slotkey, const Common::String &line); + ~ActionPlayAnimation(); + bool execute(); private: uint32 _key; Common::String _fileName; uint32 _x; uint32 _y; - uint32 _width; - uint32 _height; + uint32 _x2; + uint32 _y2; uint32 _start; uint32 _end; - uint _mask; - uint _framerate; - uint _loopCount; + int32 _mask; + int32 _framerate; + int32 _loopCount; }; class ActionPlayPreloadAnimation : public ResultAction { public: - ActionPlayPreloadAnimation(const Common::String &line); - bool execute(ZVision *engine); + ActionPlayPreloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: uint32 _animationKey; @@ -258,64 +299,130 @@ private: class ActionPreloadAnimation : public ResultAction { public: - ActionPreloadAnimation(const Common::String &line); - bool execute(ZVision *engine); + ActionPreloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line); + ~ActionPreloadAnimation(); + bool execute(); private: uint32 _key; Common::String _fileName; - uint _mask; - uint _framerate; + int32 _mask; + int32 _framerate; +}; + +class ActionPreferences : public ResultAction { +public: + ActionPreferences(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); + +private: + bool _save; }; class ActionQuit : public ResultAction { public: - ActionQuit() {} - bool execute(ZVision *engine); + ActionQuit(ZVision *engine, int32 slotkey) : ResultAction(engine, slotkey) {} + bool execute(); +}; + +class ActionRegion : public ResultAction { +public: + ActionRegion(ZVision *engine, int32 slotkey, const Common::String &line); + ~ActionRegion(); + bool execute(); + +private: + Common::String _art; + Common::String _custom; + Common::Rect _rect; + uint16 _delay; + uint16 _type; + uint16 _unk1; + uint16 _unk2; }; // TODO: See if this exists in ZGI. It doesn't in ZNem class ActionUnloadAnimation : public ResultAction { public: - ActionUnloadAnimation(const Common::String &line); - bool execute(ZVision *engine); + ActionUnloadAnimation(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); +private: + uint32 _key; }; class ActionRandom : public ResultAction { public: - ActionRandom(const Common::String &line); - bool execute(ZVision *engine); + ActionRandom(ZVision *engine, int32 slotkey, const Common::String &line); + ~ActionRandom(); + bool execute(); private: uint32 _key; - uint _max; + ValueSlot *_max; +}; + +class ActionRestoreGame : public ResultAction { +public: + ActionRestoreGame(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); + +private: + Common::String _fileName; +}; + +class ActionRotateTo : public ResultAction { +public: + ActionRotateTo(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); + +private: + int32 _toPos; + int32 _time; }; class ActionSetPartialScreen : public ResultAction { public: - ActionSetPartialScreen(const Common::String &line); - bool execute(ZVision *engine); + ActionSetPartialScreen(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: uint _x; uint _y; Common::String _fileName; - uint16 _backgroundColor; + int32 _backgroundColor; }; class ActionSetScreen : public ResultAction { public: - ActionSetScreen(const Common::String &line); - bool execute(ZVision *engine); + ActionSetScreen(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: Common::String _fileName; }; +class ActionSetVenus : public ResultAction { +public: + ActionSetVenus(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); + +private: + int32 _key; +}; + +class ActionStop : public ResultAction { +public: + ActionStop(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); + +private: + uint32 _key; +}; + class ActionStreamVideo : public ResultAction { public: - ActionStreamVideo(const Common::String &line); - bool execute(ZVision *engine); + ActionStreamVideo(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: enum { @@ -331,16 +438,37 @@ private: bool _skippable; }; -class ActionTimer : public ResultAction { +class ActionSyncSound : public ResultAction { public: - ActionTimer(const Common::String &line); - bool execute(ZVision *engine); + ActionSyncSound(ZVision *engine, int32 slotkey, const Common::String &line); + bool execute(); private: + int _syncto; + Common::String _fileName; +}; + +class ActionTimer : public ResultAction { +public: + ActionTimer(ZVision *engine, int32 slotkey, const Common::String &line); + ~ActionTimer(); + bool execute(); +private: uint32 _key; - uint _time; + ValueSlot *_time; }; +class ActionTtyText : public ResultAction { +public: + ActionTtyText(ZVision *engine, int32 slotkey, const Common::String &line); + ~ActionTtyText(); + bool execute(); + +private: + Common::String _filename; + uint32 _delay; + Common::Rect _r; +}; } // End of namespace ZVision #endif diff --git a/engines/zvision/scripting/control.cpp b/engines/zvision/scripting/control.cpp index 2343c83c56..5469106928 100644 --- a/engines/zvision/scripting/control.cpp +++ b/engines/zvision/scripting/control.cpp @@ -23,6 +23,7 @@ #include "common/scummsys.h" #include "zvision/scripting/control.h" +#include "zvision/scripting/script_manager.h" #include "zvision/zvision.h" #include "zvision/graphics/render_manager.h" @@ -30,27 +31,8 @@ #include "common/stream.h" - namespace ZVision { -void Control::enable() { - if (!_enabled) { - _enabled = true; - return; - } - - debug("Control %u is already enabled", _key); -} - -void Control::disable() { - if (_enabled) { - _enabled = false; - return; - } - - debug("Control %u is already disabled", _key); -} - void Control::parseFlatControl(ZVision *engine) { engine->getRenderManager()->getRenderTable()->setRenderState(RenderTable::FLAT); } @@ -79,7 +61,9 @@ void Control::parsePanoramaControl(ZVision *engine, Common::SeekableReadStream & renderTable->setPanoramaReverse(true); } } else if (line.matchString("zeropoint*", true)) { - // TODO: Implement + uint point; + sscanf(line.c_str(), "zeropoint(%u)", &point); + renderTable->setPanoramaZeroPoint(point); } line = stream.readLine(); @@ -121,4 +105,34 @@ void Control::parseTiltControl(ZVision *engine, Common::SeekableReadStream &stre renderTable->generateRenderTable(); } +void Control::getParams(const Common::String &inputStr, Common::String ¶meter, Common::String &values) { + const char *chrs = inputStr.c_str(); + uint lbr; + + for (lbr = 0; lbr < inputStr.size(); lbr++) + if (chrs[lbr] == '(') + break; + + if (lbr >= inputStr.size()) + return; + + uint rbr; + + for (rbr = lbr + 1; rbr < inputStr.size(); rbr++) + if (chrs[rbr] == ')') + break; + + if (rbr >= inputStr.size()) + return; + + parameter = Common::String(chrs, chrs + lbr); + values = Common::String(chrs + lbr + 1, chrs + rbr); +} + +void Control::setVenus() { + if (_venusId >= 0) + if (_engine->getScriptManager()->getStateValue(_venusId) > 0) + _engine->getScriptManager()->setStateValue(StateKey_Venus, _venusId); +} + } // End of namespace ZVision diff --git a/engines/zvision/scripting/control.h b/engines/zvision/scripting/control.h index ffeacb273d..803d0cf1ce 100644 --- a/engines/zvision/scripting/control.h +++ b/engines/zvision/scripting/control.h @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -24,7 +24,7 @@ #define ZVISION_CONTROL_H #include "common/keyboard.h" - +#include "common/str.h" namespace Common { class SeekableReadStream; @@ -38,14 +38,32 @@ class ZVision; class Control { public: - Control() : _engine(0), _key(0), _enabled(false) {} - Control(ZVision *engine, uint32 key) : _engine(engine), _key(key), _enabled(false) {} + + enum ControlType { + CONTROL_UNKNOW, + CONTROL_INPUT, + CONTROL_PUSHTGL, + CONTROL_SLOT, + CONTROL_LEVER, + CONTROL_SAVE, + CONTROL_SAFE, + CONTROL_FIST, + CONTROL_TITLER, + CONTROL_HOTMOV, + CONTROL_PAINT + }; + + Control(ZVision *engine, uint32 key, ControlType type) : _engine(engine), _key(key), _type(type), _venusId(-1) {} virtual ~Control() {} - uint32 getKey() { return _key; } + uint32 getKey() { + return _key; + } + + ControlType getType() { + return _type; + } - virtual void enable(); - virtual void disable(); virtual void focus() {} virtual void unfocus() {} /** @@ -54,14 +72,18 @@ public: * @param screenSpacePos The position of the mouse in screen space * @param backgroundImageSpacePos The position of the mouse in background image space */ - virtual void onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) {} + virtual bool onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + return false; + } /** * Called when LeftMouse is lifted. Default is NOP. * * @param screenSpacePos The position of the mouse in screen space * @param backgroundImageSpacePos The position of the mouse in background image space */ - virtual void onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) {} + virtual bool onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + return false; + } /** * Called on every MouseMove. Default is NOP. * @@ -69,78 +91,52 @@ public: * @param backgroundImageSpacePos The position of the mouse in background image space * @return Was the cursor changed? */ - virtual bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { return false; } + virtual bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + return false; + } /** * Called when a key is pressed. Default is NOP. * * @param keycode The key that was pressed */ - virtual void onKeyDown(Common::KeyState keyState) {} + virtual bool onKeyDown(Common::KeyState keyState) { + return false; + } /** * Called when a key is released. Default is NOP. * * @param keycode The key that was pressed */ - virtual void onKeyUp(Common::KeyState keyState) {} + virtual bool onKeyUp(Common::KeyState keyState) { + return false; + } /** * Processes the node given the deltaTime since last frame. Default is NOP. * * @param deltaTimeInMillis The number of milliseconds that have passed since last frame * @return If true, the node can be deleted after process() finishes */ - virtual bool process(uint32 deltaTimeInMillis) { return false; } - /** - * Serialize a Control for save game use. This should only be used if a Control needs - * to save values that would be different from initialization. AKA a TimerNode needs to - * store the amount of time left on the timer. Any Controls overriding this *MUST* write - * their key as the first data outputted. The default implementation is NOP. - * - * NOTE: If this method is overridden, you MUST also override deserialize() - * and needsSerialization() - * - * @param stream Stream to write any needed data to - */ - virtual void serialize(Common::WriteStream *stream) {} - /** - * De-serialize data from a save game stream. This should only be implemented if the - * Control also implements serialize(). The calling method assumes the size of the - * data read from the stream exactly equals that written in serialize(). The default - * implementation is NOP. - * - * NOTE: If this method is overridden, you MUST also override serialize() - * and needsSerialization() - * - * @param stream Save game file stream - */ - virtual void deserialize(Common::SeekableReadStream *stream) {} - /** - * If a Control overrides serialize() and deserialize(), this should return true - * - * @return Does the Control need save game serialization? - */ - virtual inline bool needsSerialization() { return false; } + virtual bool process(uint32 deltaTimeInMillis) { + return false; + } + + void setVenus(); protected: - ZVision * _engine; + ZVision *_engine; uint32 _key; - bool _enabled; + int32 _venusId; + void getParams(const Common::String &inputStr, Common::String ¶meter, Common::String &values); // Static member functions public: static void parseFlatControl(ZVision *engine); static void parsePanoramaControl(ZVision *engine, Common::SeekableReadStream &stream); static void parseTiltControl(ZVision *engine, Common::SeekableReadStream &stream); +private: + ControlType _type; }; -// TODO: Implement InputControl -// TODO: Implement SaveControl -// TODO: Implement SlotControl -// TODO: Implement SafeControl -// TODO: Implement FistControl -// TODO: Implement HotMovieControl -// TODO: Implement PaintControl -// TODO: Implement TilterControl - } // End of namespace ZVision #endif diff --git a/engines/zvision/scripting/controls/animation_control.cpp b/engines/zvision/scripting/controls/animation_control.cpp deleted file mode 100644 index e351e81d25..0000000000 --- a/engines/zvision/scripting/controls/animation_control.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#include "common/scummsys.h" - -#include "zvision/scripting/controls/animation_control.h" - -#include "zvision/zvision.h" -#include "zvision/graphics/render_manager.h" -#include "zvision/scripting/script_manager.h" -#include "zvision/animation/rlf_animation.h" -#include "zvision/video/zork_avi_decoder.h" - -#include "video/video_decoder.h" - -#include "graphics/surface.h" - - -namespace ZVision { - -AnimationControl::AnimationControl(ZVision *engine, uint32 controlKey, const Common::String &fileName) - : Control(engine, controlKey), - _fileType(RLF), - _loopCount(1), - _currentLoop(0), - _accumulatedTime(0), - _cachedFrame(0), - _cachedFrameNeedsDeletion(false) { - if (fileName.hasSuffix(".rlf")) { - _fileType = RLF; - _animation.rlf = new RlfAnimation(fileName, false); - } else if (fileName.hasSuffix(".avi")) { - _fileType = AVI; - _animation.avi = new ZorkAVIDecoder(); - _animation.avi->loadFile(fileName); - } else { - warning("Unrecognized animation file type: %s", fileName.c_str()); - } - - _cachedFrame = new Graphics::Surface(); -} - -AnimationControl::~AnimationControl() { - if (_fileType == RLF) { - delete _animation.rlf; - } else if (_fileType == AVI) { - delete _animation.avi; - } - - _cachedFrame->free(); - delete _cachedFrame; -} - -bool AnimationControl::process(uint32 deltaTimeInMillis) { - if (!_enabled) { - return false; - } - - bool finished = false; - - if (_fileType == RLF) { - _accumulatedTime += deltaTimeInMillis; - - uint32 frameTime = _animation.rlf->frameTime(); - if (_accumulatedTime >= frameTime) { - while (_accumulatedTime >= frameTime) { - _accumulatedTime -= frameTime; - - // Make sure the frame is inside the working window - // If it's not, then just return - - RenderManager *renderManager = _engine->getRenderManager(); - Common::Point workingWindowPoint = renderManager->imageSpaceToWorkingWindowSpace(Common::Point(_x, _y)); - Common::Rect subRect(workingWindowPoint.x, workingWindowPoint.y, workingWindowPoint.x + _animation.rlf->width(), workingWindowPoint.y + _animation.rlf->height()); - - // If the clip returns false, it means the animation is outside the working window - if (!renderManager->clipRectToWorkingWindow(subRect)) { - return false; - } - - const Graphics::Surface *frame = _animation.rlf->getNextFrame(); - - // Animation frames for PANORAMAs are transposed, so un-transpose them - RenderTable::RenderState state = renderManager->getRenderTable()->getRenderState(); - if (state == RenderTable::PANORAMA) { - Graphics::Surface *tranposedFrame = RenderManager::tranposeSurface(frame); - - renderManager->copyRectToWorkingWindow((uint16 *)tranposedFrame->getBasePtr(tranposedFrame->w - subRect.width(), tranposedFrame->h - subRect.height()), subRect.left, subRect.top, _animation.rlf->width(), subRect.width(), subRect.height()); - - // If the background can move, we need to cache the last frame so it can be rendered during background movement - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - if (_cachedFrameNeedsDeletion) { - _cachedFrame->free(); - delete _cachedFrame; - _cachedFrameNeedsDeletion = false; - } - _cachedFrame = tranposedFrame; - _cachedFrameNeedsDeletion = true; - } else { - // Cleanup - tranposedFrame->free(); - delete tranposedFrame; - } - } else { - renderManager->copyRectToWorkingWindow((const uint16 *)frame->getBasePtr(frame->w - subRect.width(), frame->h - subRect.height()), subRect.left, subRect.top, _animation.rlf->width(), subRect.width(), subRect.height()); - - // If the background can move, we need to cache the last frame so it can be rendered during background movement - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - if (_cachedFrameNeedsDeletion) { - _cachedFrame->free(); - delete _cachedFrame; - _cachedFrameNeedsDeletion = false; - } - _cachedFrame->copyFrom(*frame); - } - } - - // Check if we should continue looping - if (_animation.rlf->endOfAnimation()) { - _animation.rlf->seekToFrame(-1); - if (_loopCount > 0) { - _currentLoop++; - if (_currentLoop >= _loopCount) { - finished = true; - } - } - } - } - } else { - // If the background can move, we have to keep rendering animation frames, otherwise the animation flickers during background movement - RenderManager *renderManager = _engine->getRenderManager(); - RenderTable::RenderState state = renderManager->getRenderTable()->getRenderState(); - - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - Common::Point workingWindowPoint = renderManager->imageSpaceToWorkingWindowSpace(Common::Point(_x, _y)); - Common::Rect subRect(workingWindowPoint.x, workingWindowPoint.y, workingWindowPoint.x + _cachedFrame->w, workingWindowPoint.y + _cachedFrame->h); - - // If the clip returns false, it means the animation is outside the working window - if (!renderManager->clipRectToWorkingWindow(subRect)) { - return false; - } - - renderManager->copyRectToWorkingWindow((uint16 *)_cachedFrame->getBasePtr(_cachedFrame->w - subRect.width(), _cachedFrame->h - subRect.height()), subRect.left, subRect.top, _cachedFrame->w, subRect.width(), subRect.height()); - } - } - } else if (_fileType == AVI) { - if (!_animation.avi->isPlaying()) { - _animation.avi->start(); - } - - if (_animation.avi->needsUpdate()) { - const Graphics::Surface *frame = _animation.avi->decodeNextFrame(); - - if (frame) { - // Make sure the frame is inside the working window - // If it's not, then just return - - RenderManager *renderManager = _engine->getRenderManager(); - Common::Point workingWindowPoint = renderManager->imageSpaceToWorkingWindowSpace(Common::Point(_x, _y)); - Common::Rect subRect(workingWindowPoint.x, workingWindowPoint.y, workingWindowPoint.x + frame->w, workingWindowPoint.y + frame->h); - - // If the clip returns false, it means the animation is outside the working window - if (!renderManager->clipRectToWorkingWindow(subRect)) { - return false; - } - - // Animation frames for PANORAMAs are transposed, so un-transpose them - RenderTable::RenderState state = renderManager->getRenderTable()->getRenderState(); - if (state == RenderTable::PANORAMA) { - Graphics::Surface *tranposedFrame = RenderManager::tranposeSurface(frame); - - renderManager->copyRectToWorkingWindow((uint16 *)tranposedFrame->getBasePtr(tranposedFrame->w - subRect.width(), tranposedFrame->h - subRect.height()), subRect.left, subRect.top, frame->w, subRect.width(), subRect.height()); - - // If the background can move, we need to cache the last frame so it can be rendered during background movement - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - if (_cachedFrameNeedsDeletion) { - _cachedFrame->free(); - delete _cachedFrame; - _cachedFrameNeedsDeletion = false; - } - _cachedFrame = tranposedFrame; - _cachedFrameNeedsDeletion = true; - } else { - // Cleanup - tranposedFrame->free(); - delete tranposedFrame; - } - } else { - renderManager->copyRectToWorkingWindow((const uint16 *)frame->getBasePtr(frame->w - subRect.width(), frame->h - subRect.height()), subRect.left, subRect.top, frame->w, subRect.width(), subRect.height()); - - // If the background can move, we need to cache the last frame so it can be rendered during background movement - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - if (_cachedFrameNeedsDeletion) { - _cachedFrame->free(); - delete _cachedFrame; - _cachedFrameNeedsDeletion = false; - } - _cachedFrame->copyFrom(*frame); - } - } - } else { - // If the background can move, we have to keep rendering animation frames, otherwise the animation flickers during background movement - RenderManager *renderManager = _engine->getRenderManager(); - RenderTable::RenderState state = renderManager->getRenderTable()->getRenderState(); - - if (state == RenderTable::PANORAMA || state == RenderTable::TILT) { - Common::Point workingWindowPoint = renderManager->imageSpaceToWorkingWindowSpace(Common::Point(_x, _y)); - Common::Rect subRect(workingWindowPoint.x, workingWindowPoint.y, workingWindowPoint.x + _cachedFrame->w, workingWindowPoint.y + _cachedFrame->h); - - // If the clip returns false, it means the animation is outside the working window - if (!renderManager->clipRectToWorkingWindow(subRect)) { - return false; - } - - renderManager->copyRectToWorkingWindow((uint16 *)_cachedFrame->getBasePtr(_cachedFrame->w - subRect.width(), _cachedFrame->h - subRect.height()), subRect.left, subRect.top, _cachedFrame->w, subRect.width(), subRect.height()); - } - } - } - - // Check if we should continue looping - if (_animation.avi->endOfVideo()) { - _animation.avi->rewind(); - if (_loopCount > 0) { - _currentLoop++; - if (_currentLoop >= _loopCount) { - _animation.avi->stop(); - finished = true; - } - } - } - } - - // If we're done, set _animation key = 2 (Why 2? I don't know. It's just the value that they used) - // Then disable the control. DON'T delete it. It can be re-used - if (finished) { - _engine->getScriptManager()->setStateValue(_animationKey, 2); - disable(); - _currentLoop = 0; - } - - return false; -} - -} // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/fist_control.cpp b/engines/zvision/scripting/controls/fist_control.cpp new file mode 100644 index 0000000000..dd6a7f11a9 --- /dev/null +++ b/engines/zvision/scripting/controls/fist_control.cpp @@ -0,0 +1,319 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/controls/fist_control.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/cursors/cursor_manager.h" +#include "zvision/animation/meta_animation.h" +#include "zvision/utility/utility.h" + +#include "common/stream.h" +#include "common/file.h" +#include "common/system.h" + +#include "graphics/surface.h" + +namespace ZVision { + +FistControl::FistControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) + : Control(engine, key, CONTROL_FIST) { + _cursor = CursorIndex_Idle; + _animation = NULL; + _soundKey = 0; + _fiststatus = 0; + _order = 0; + _fistnum = 0; + + _frameCur = -1; + _frameEnd = -1; + _frameTime = 0; + _lastRenderedFrame = -1; + _animationId = 0; + + clearFistArray(_fistsUp); + clearFistArray(_fistsDwn); + + _numEntries = 0; + _entries.clear(); + + _anmRect = Common::Rect(); + + // Loop until we find the closing brace + Common::String line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + Common::String param; + Common::String values; + getParams(line, param, values); + + while (!stream.eos() && !line.contains('}')) { + if (param.matchString("sound_key", true)) { + _soundKey = atoi(values.c_str()); + } else if (param.matchString("cursor", true)) { + _cursor = _engine->getCursorManager()->getCursorId(values); + } else if (param.matchString("descfile", true)) { + readDescFile(values); + } else if (param.matchString("animation_id", true)) { + _animationId = atoi(values.c_str()); + } else if (param.matchString("venus_id", true)) { + _venusId = atoi(values.c_str()); + } + + line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + getParams(line, param, values); + } +} + +FistControl::~FistControl() { + if (_animation) + delete _animation; + + clearFistArray(_fistsUp); + clearFistArray(_fistsDwn); + _entries.clear(); +} + +void FistControl::renderFrame(uint frameNumber) { + if ((int32)frameNumber == _lastRenderedFrame) + return; + + _lastRenderedFrame = frameNumber; + + const Graphics::Surface *frameData; + + if (_animation) { + frameData = _animation->getFrameData(frameNumber); + if (frameData) + _engine->getRenderManager()->blitSurfaceToBkgScaled(*frameData, _anmRect); + } +} + +bool FistControl::process(uint32 deltaTimeInMillis) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_frameCur >= 0 && _frameEnd >= 0) + if (_frameCur <= _frameEnd) { + _frameTime -= deltaTimeInMillis; + + if (_frameTime <= 0) { + _frameTime = _animation->frameTime(); + + renderFrame(_frameCur); + + _frameCur++; + + if (_frameCur > _frameEnd) + _engine->getScriptManager()->setStateValue(_animationId, 2); + } + } + + return false; +} + +bool FistControl::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (mouseIn(screenSpacePos, backgroundImageSpacePos) >= 0) { + _engine->getCursorManager()->changeCursor(_cursor); + return true; + } + + return false; +} + +bool FistControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + int fistNumber = mouseIn(screenSpacePos, backgroundImageSpacePos); + + if (fistNumber >= 0) { + setVenus(); + + uint32 oldStatus = _fiststatus; + _fiststatus ^= (1 << fistNumber); + + for (int i = 0; i < _numEntries; i++) + if (_entries[i]._bitsStrt == oldStatus && _entries[i]._bitsEnd == _fiststatus) { + _frameCur = _entries[i]._anmStrt; + _frameEnd = _entries[i]._anmEnd; + _frameTime = 0; + + _engine->getScriptManager()->setStateValue(_animationId, 1); + _engine->getScriptManager()->setStateValue(_soundKey, _entries[i]._sound); + break; + } + + _engine->getScriptManager()->setStateValue(_key, _fiststatus); + } + + return false; +} + +void FistControl::readDescFile(const Common::String &fileName) { + Common::File file; + if (!_engine->getSearchManager()->openFile(file, fileName)) { + warning("Desc file %s could could be opened", fileName.c_str()); + return; + } + + Common::String line; + Common::String param; + Common::String values; + + while (!file.eos()) { + line = file.readLine(); + getFistParams(line, param, values); + + if (param.matchString("animation_id", true)) { + // Not used + } else if (param.matchString("animation", true)) { + _animation = new MetaAnimation(values, _engine); + } else if (param.matchString("anim_rect", true)) { + int left, top, right, bottom; + sscanf(values.c_str(), "%d %d %d %d", &left, &top, &right, &bottom); + _anmRect = Common::Rect(left, top, right, bottom); + } else if (param.matchString("num_fingers", true)) { + sscanf(values.c_str(), "%d", &_fistnum); + _fistsUp.resize(_fistnum); + _fistsDwn.resize(_fistnum); + } else if (param.matchString("entries", true)) { + sscanf(values.c_str(), "%d", &_numEntries); + _entries.resize(_numEntries); + } else if (param.matchString("eval_order_ascending", true)) { + sscanf(values.c_str(), "%d", &_order); + } else if (param.matchString("up_hs_num_*", true)) { + int fist, num; + num = atoi(values.c_str()); + + sscanf(param.c_str(), "up_hs_num_%d", &fist); + _fistsUp[fist].resize(num); + } else if (param.matchString("up_hs_*", true)) { + int16 fist, box, x1, y1, x2, y2; + sscanf(param.c_str(), "up_hs_%hd_%hd", &fist, &box); + sscanf(values.c_str(), "%hd %hd %hd %hd", &x1, &y1, &x2, &y2); + (_fistsUp[fist])[box] = Common::Rect(x1, y1, x2, y2); + } else if (param.matchString("down_hs_num_*", true)) { + int fist, num; + num = atoi(values.c_str()); + + sscanf(param.c_str(), "down_hs_num_%d", &fist); + _fistsDwn[fist].resize(num); + } else if (param.matchString("down_hs_*", true)) { + int16 fist, box, x1, y1, x2, y2; + sscanf(param.c_str(), "down_hs_%hd_%hd", &fist, &box); + sscanf(values.c_str(), "%hd %hd %hd %hd", &x1, &y1, &x2, &y2); + (_fistsDwn[fist])[box] = Common::Rect(x1, y1, x2, y2); + } else { + int entry, start, end, sound; + char bitsStart[33]; + char bitsEnd[33]; + entry = atoi(param.c_str()); + if (sscanf(values.c_str(), "%s %s %d %d (%d)", bitsStart, bitsEnd, &start, &end, &sound) == 5) { + _entries[entry]._bitsStrt = readBits(bitsStart); + _entries[entry]._bitsEnd = readBits(bitsEnd); + _entries[entry]._anmStrt = start; + _entries[entry]._anmEnd = end; + _entries[entry]._sound = sound; + } + } + } + file.close(); +} + +void FistControl::clearFistArray(Common::Array< Common::Array<Common::Rect> > &arr) { + for (uint i = 0; i < arr.size(); i++) + arr[i].clear(); + + arr.clear(); +} + +uint32 FistControl::readBits(const char *str) { + uint32 bfield = 0; + int len = strlen(str); + for (int i = 0; i < len; i++) + if (str[i] != '0') + bfield |= (1 << i); + return bfield; +} + +int FistControl::mouseIn(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_order) { + for (int i = 0; i < _fistnum; i++) { + if (((_fiststatus >> i) & 1) == 1) { + for (uint j = 0; j < _fistsDwn[i].size(); j++) + if ((_fistsDwn[i])[j].contains(backgroundImageSpacePos)) + return i; + } else { + for (uint j = 0; j < _fistsUp[i].size(); j++) + if ((_fistsUp[i])[j].contains(backgroundImageSpacePos)) + return i; + } + } + } else { + for (int i = _fistnum - 1; i >= 0; i--) { + if (((_fiststatus >> i) & 1) == 1) { + for (uint j = 0; j < _fistsDwn[i].size(); j++) + if ((_fistsDwn[i])[j].contains(backgroundImageSpacePos)) + return i; + } else { + for (uint j = 0; j < _fistsUp[i].size(); j++) + if ((_fistsUp[i])[j].contains(backgroundImageSpacePos)) + return i; + } + } + } + return -1; +} + +void FistControl::getFistParams(const Common::String &inputStr, Common::String ¶meter, Common::String &values) { + const char *chrs = inputStr.c_str(); + uint lbr; + + for (lbr = 0; lbr < inputStr.size(); lbr++) + if (chrs[lbr] == ':') + break; + + if (lbr >= inputStr.size()) + return; + + uint rbr; + + for (rbr = lbr + 1; rbr < inputStr.size(); rbr++) + if (chrs[rbr] == '~') + break; + + if (rbr >= inputStr.size()) + return; + + parameter = Common::String(chrs, chrs + lbr); + values = Common::String(chrs + lbr + 1, chrs + rbr); +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/fist_control.h b/engines/zvision/scripting/controls/fist_control.h new file mode 100644 index 0000000000..cb765c429a --- /dev/null +++ b/engines/zvision/scripting/controls/fist_control.h @@ -0,0 +1,86 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_FIST_CONTROL_H +#define ZVISION_FIST_CONTROL_H + +#include "zvision/scripting/control.h" + +#include "common/array.h" +#include "common/rect.h" + +namespace ZVision { + +class MetaAnimation; + +class FistControl : public Control { +public: + FistControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream); + ~FistControl(); + +private: + uint32 _fiststatus; + int _fistnum; + int16 _cursor; + int _order; + + Common::Array< Common::Array<Common::Rect> > _fistsUp; + Common::Array< Common::Array<Common::Rect> > _fistsDwn; + + int32 _numEntries; + + struct entries { + uint32 _bitsStrt; + uint32 _bitsEnd; + int32 _anmStrt; + int32 _anmEnd; + int32 _sound; + }; + + Common::Array<entries> _entries; + + MetaAnimation *_animation; + Common::Rect _anmRect; + int32 _soundKey; + int32 _frameCur; + int32 _frameEnd; + int32 _frameTime; + int32 _lastRenderedFrame; + int32 _animationId; + +public: + bool onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool process(uint32 deltaTimeInMillis); + +private: + void renderFrame(uint frameNumber); + void readDescFile(const Common::String &fileName); + void clearFistArray(Common::Array< Common::Array<Common::Rect> > &arr); + uint32 readBits(const char *str); + int mouseIn(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + void getFistParams(const Common::String &inputStr, Common::String ¶meter, Common::String &values); +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/controls/hotmov_control.cpp b/engines/zvision/scripting/controls/hotmov_control.cpp new file mode 100644 index 0000000000..68861dc221 --- /dev/null +++ b/engines/zvision/scripting/controls/hotmov_control.cpp @@ -0,0 +1,200 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/controls/hotmov_control.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/cursors/cursor_manager.h" +#include "zvision/animation/meta_animation.h" +#include "zvision/utility/utility.h" + +#include "common/stream.h" +#include "common/file.h" +#include "common/system.h" + +#include "graphics/surface.h" + +namespace ZVision { + +HotMovControl::HotMovControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) + : Control(engine, key, CONTROL_HOTMOV) { + _animation = NULL; + _cycle = 0; + _curFrame = -1; + _lastRenderedFrame = -1; + _frames.clear(); + _frameTime = 0; + _cyclesCount = 0; + _framesCount = 0; + + _engine->getScriptManager()->setStateValue(_key, 0); + + // Loop until we find the closing brace + Common::String line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + Common::String param; + Common::String values; + getParams(line, param, values); + + while (!stream.eos() && !line.contains('}')) { + if (param.matchString("hs_frame_list", true)) { + readHsFile(values); + } else if (param.matchString("rectangle", true)) { + int x; + int y; + int width; + int height; + + sscanf(values.c_str(), "%d %d %d %d", &x, &y, &width, &height); + + _rectangle = Common::Rect(x, y, width, height); + } else if (param.matchString("num_frames", true)) { + _framesCount = atoi(values.c_str()); + } else if (param.matchString("num_cycles", true)) { + _cyclesCount = atoi(values.c_str()); + } else if (param.matchString("animation", true)) { + char filename[64]; + sscanf(values.c_str(), "%s", filename); + values = Common::String(filename); + _animation = new MetaAnimation(values, _engine); + } else if (param.matchString("venus_id", true)) { + _venusId = atoi(values.c_str()); + } + + line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + getParams(line, param, values); + } +} + +HotMovControl::~HotMovControl() { + if (_animation) + delete _animation; + + _frames.clear(); +} + +void HotMovControl::renderFrame(uint frameNumber) { + if ((int)frameNumber == _lastRenderedFrame) + return; + + _lastRenderedFrame = frameNumber; + + const Graphics::Surface *frameData; + + if (_animation) { + frameData = _animation->getFrameData(frameNumber); + if (frameData) + _engine->getRenderManager()->blitSurfaceToBkgScaled(*frameData, _rectangle); + } +} + +bool HotMovControl::process(uint32 deltaTimeInMillis) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_cycle < _cyclesCount) { + _frameTime -= deltaTimeInMillis; + + if (_frameTime <= 0) { + _curFrame++; + if (_curFrame >= _framesCount) { + _curFrame = 0; + _cycle++; + } + if (_cycle != _cyclesCount) + renderFrame(_curFrame); + else + _engine->getScriptManager()->setStateValue(_key, 2); + + _frameTime = _animation->frameTime(); + } + } + + return false; +} + +bool HotMovControl::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_cycle < _cyclesCount) { + if (_frames[_curFrame].contains(backgroundImageSpacePos)) { + _engine->getCursorManager()->changeCursor(CursorIndex_Active); + return true; + } + } + + return false; +} + +bool HotMovControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_cycle < _cyclesCount) { + if (_frames[_curFrame].contains(backgroundImageSpacePos)) { + setVenus(); + _engine->getScriptManager()->setStateValue(_key, 1); + return true; + } + } + + return false; +} + +void HotMovControl::readHsFile(const Common::String &fileName) { + if (_framesCount == 0) + return; + + Common::File file; + if (!_engine->getSearchManager()->openFile(file, fileName)) { + warning("HS file %s could could be opened", fileName.c_str()); + return; + } + + Common::String line; + + _frames.resize(_framesCount); + + while (!file.eos()) { + line = file.readLine(); + + int frame; + int x; + int y; + int width; + int height; + + sscanf(line.c_str(), "%d:%d %d %d %d~", &frame, &x, &y, &width, &height); + + if (frame >= 0 && frame < _framesCount) + _frames[frame] = Common::Rect(x, y, width, height); + } + file.close(); +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/hotmov_control.h b/engines/zvision/scripting/controls/hotmov_control.h new file mode 100644 index 0000000000..86600d65dc --- /dev/null +++ b/engines/zvision/scripting/controls/hotmov_control.h @@ -0,0 +1,62 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_HOTMOV_CONTROL_H +#define ZVISION_HOTMOV_CONTROL_H + +#include "zvision/scripting/control.h" + +#include "common/array.h" +#include "common/rect.h" + +namespace ZVision { + +class MetaAnimation; + +class HotMovControl : public Control { +public: + HotMovControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream); + ~HotMovControl(); + +private: + int32 _framesCount; + int32 _frameTime; + int32 _curFrame; + int32 _lastRenderedFrame; + int32 _cycle; + int32 _cyclesCount; + MetaAnimation *_animation; + Common::Rect _rectangle; + Common::Array<Common::Rect> _frames; +public: + bool onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool process(uint32 deltaTimeInMillis); + +private: + void renderFrame(uint frameNumber); + void readHsFile(const Common::String &fileName); +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/controls/input_control.cpp b/engines/zvision/scripting/controls/input_control.cpp index a35548d02e..c541693ec3 100644 --- a/engines/zvision/scripting/controls/input_control.cpp +++ b/engines/zvision/scripting/controls/input_control.cpp @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -23,10 +23,11 @@ #include "common/scummsys.h" #include "zvision/scripting/controls/input_control.h" +#include "zvision/cursors/cursor_manager.h" #include "zvision/zvision.h" #include "zvision/scripting/script_manager.h" -#include "zvision/strings/string_manager.h" +#include "zvision/text/string_manager.h" #include "zvision/graphics/render_manager.h" #include "zvision/utility/utility.h" @@ -34,109 +35,221 @@ #include "common/stream.h" #include "common/rect.h" - namespace ZVision { InputControl::InputControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) - : Control(engine, key), - _nextTabstop(0), - _focused(false), - _textChanged(false), - _cursorOffset(0) { + : Control(engine, key, CONTROL_INPUT), + _nextTabstop(0), + _focused(false), + _textChanged(false), + _cursorOffset(0), + _enterPressed(false), + _readOnly(false), + _txtWidth(0), + _animation(NULL) { // Loop until we find the closing brace Common::String line = stream.readLine(); trimCommentsAndWhiteSpace(&line); + Common::String param; + Common::String values; + getParams(line, param, values); while (!stream.eos() && !line.contains('}')) { - if (line.matchString("*rectangle*", true)) { + if (param.matchString("rectangle", true)) { int x1; int y1; int x2; int y2; - sscanf(line.c_str(), "%*[^(](%d %d %d %d)", &x1, &y1, &x2, &y2); + sscanf(values.c_str(), "%d %d %d %d", &x1, &y1, &x2, &y2); _textRectangle = Common::Rect(x1, y1, x2, y2); - } else if (line.matchString("*aux_hotspot*", true)) { + } else if (param.matchString("aux_hotspot", true)) { int x1; int y1; int x2; int y2; - sscanf(line.c_str(), "%*[^(](%d %d %d %d)", &x1, &y1, &x2, &y2); + sscanf(values.c_str(), "%d %d %d %d", &x1, &y1, &x2, &y2); _headerRectangle = Common::Rect(x1, y1, x2, y2); - } else if (line.matchString("*string_init*", true)) { + } else if (param.matchString("string_init", true)) { uint fontFormatNumber; - sscanf(line.c_str(), "%*[^(](%u)", &fontFormatNumber); + sscanf(values.c_str(), "%u", &fontFormatNumber); - _textStyle = _engine->getStringManager()->getTextStyle(fontFormatNumber); - } else if (line.matchString("*next_tabstop*", true)) { - sscanf(line.c_str(), "%*[^(](%u)", &_nextTabstop); - } else if (line.matchString("*cursor_animation*", true)) { - char fileName[26]; + _stringInit.readAllStyle(_engine->getStringManager()->getTextLine(fontFormatNumber)); + } else if (param.matchString("chooser_init_string", true)) { + uint fontFormatNumber; - sscanf(line.c_str(), "%*[^(](%25s %*u)", fileName); + sscanf(values.c_str(), "%u", &fontFormatNumber); - _cursorAnimationFileName = Common::String(fileName); - } else if (line.matchString("*cursor_dimensions*", true)) { + _stringChooserInit.readAllStyle(_engine->getStringManager()->getTextLine(fontFormatNumber)); + } else if (param.matchString("next_tabstop", true)) { + sscanf(values.c_str(), "%u", &_nextTabstop); + } else if (param.matchString("cursor_dimensions", true)) { // Ignore, use the dimensions in the animation file - } else if (line.matchString("*cursor_animation_frames*", true)) { + } else if (param.matchString("cursor_animation_frames", true)) { // Ignore, use the frame count in the animation file - } else if (line.matchString("*focus*", true)) { + } else if (param.matchString("cursor_animation", true)) { + char fileName[25]; + + sscanf(values.c_str(), "%25s %*u", fileName); + + _animation = new MetaAnimation(fileName, _engine); + _frame = -1; + _frameDelay = 0; + } else if (param.matchString("focus", true)) { _focused = true; + _engine->getScriptManager()->setFocusControlKey(_key); + } else if (param.matchString("venus_id", true)) { + _venusId = atoi(values.c_str()); } line = stream.readLine(); trimCommentsAndWhiteSpace(&line); + getParams(line, param, values); + } +} + +bool InputControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_textRectangle.contains(backgroundImageSpacePos)) { + if (!_readOnly) { + // Save + _engine->getScriptManager()->focusControl(_key); + setVenus(); + } else { + // Restore + if (_currentInputText.size()) { + setVenus(); + _enterPressed = true; + } + } } + return false; } -void InputControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - _engine->getScriptManager()->focusControl(_key); +bool InputControl::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_textRectangle.contains(backgroundImageSpacePos)) { + if (!_readOnly) { + // Save + _engine->getCursorManager()->changeCursor(CursorIndex_Active); + return true; + } else { + // Restore + if (_currentInputText.size()) { + _engine->getCursorManager()->changeCursor(CursorIndex_Active); + _engine->getScriptManager()->focusControl(_key); + return true; + } + } + } + return false; } -void InputControl::onKeyDown(Common::KeyState keyState) { +bool InputControl::onKeyDown(Common::KeyState keyState) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + if (!_focused) { - return; + return false; } if (keyState.keycode == Common::KEYCODE_BACKSPACE) { - _currentInputText.deleteLastChar(); + if (!_readOnly) { + _currentInputText.deleteLastChar(); + _textChanged = true; + } + } else if (keyState.keycode == Common::KEYCODE_RETURN) { + _enterPressed = true; } else if (keyState.keycode == Common::KEYCODE_TAB) { - _focused = false; + unfocus(); // Focus the next input control _engine->getScriptManager()->focusControl(_nextTabstop); + // Don't process this event for other controls + return true; } else { - // Otherwise, append the new character to the end of the current text - - uint16 asciiValue = keyState.ascii; - // We only care about text values - if (asciiValue >= 32 && asciiValue <= 126) { - _currentInputText += (char)asciiValue; - _textChanged = true; + if (!_readOnly) { + // Otherwise, append the new character to the end of the current text + uint16 asciiValue = keyState.ascii; + // We only care about text values + if (asciiValue >= 32 && asciiValue <= 126) { + _currentInputText += (char)asciiValue; + _textChanged = true; + } } } + return false; } bool InputControl::process(uint32 deltaTimeInMillis) { - if (!_focused) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) return false; - } // First see if we need to render the text if (_textChanged) { // Blit the text using the RenderManager - Common::Rect destRect = _engine->getRenderManager()->renderTextToWorkingWindow(_key, _currentInputText, _textStyle.font, _textRectangle.left, _textRectangle.top, _textStyle.color, _textRectangle.width()); - _cursorOffset = destRect.left - _textRectangle.left; + Graphics::Surface txt; + txt.create(_textRectangle.width(), _textRectangle.height(), _engine->_pixelFormat); + + if (!_readOnly || !_focused) + _txtWidth = _engine->getTextRenderer()->drawTxt(_currentInputText, _stringInit, txt); + else + _txtWidth = _engine->getTextRenderer()->drawTxt(_currentInputText, _stringChooserInit, txt); + + _engine->getRenderManager()->blitSurfaceToBkg(txt, _textRectangle.left, _textRectangle.top); + + txt.free(); } - // Render the next frame of the animation - // TODO: Implement animation handling + if (_animation && !_readOnly && _focused) { + bool needDraw = true;// = _textChanged; + _frameDelay -= deltaTimeInMillis; + if (_frameDelay <= 0) { + _frame = (_frame + 1) % _animation->frameCount(); + _frameDelay = _animation->frameTime(); + needDraw = true; + } + if (needDraw) { + const Graphics::Surface *srf = _animation->getFrameData(_frame); + uint32 xx = _textRectangle.left + _txtWidth; + if (xx >= _textRectangle.left + (_textRectangle.width() - _animation->width())) + xx = _textRectangle.left + _textRectangle.width() - _animation->width(); + _engine->getRenderManager()->blitSurfaceToBkg(*srf, xx, _textRectangle.top); + } + } + + _textChanged = false; + return false; +} + +bool InputControl::enterPress() { + if (_enterPressed) { + _enterPressed = false; + return true; + } return false; } +void InputControl::setText(const Common::String &_str) { + _currentInputText = _str; + _textChanged = true; +} + +const Common::String InputControl::getText() { + return _currentInputText; +} + +void InputControl::setReadOnly(bool readonly) { + _readOnly = readonly; +} + } // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/input_control.h b/engines/zvision/scripting/controls/input_control.h index 32432438bb..410caf6d49 100644 --- a/engines/zvision/scripting/controls/input_control.h +++ b/engines/zvision/scripting/controls/input_control.h @@ -24,11 +24,12 @@ #define ZVISION_INPUT_CONTROL_H #include "zvision/scripting/control.h" -#include "zvision/strings/string_manager.h" +#include "zvision/animation/meta_animation.h" +#include "zvision/text/text.h" +#include "zvision/text/string_manager.h" #include "common/rect.h" - namespace ZVision { class InputControl : public Control { @@ -38,21 +39,39 @@ public: private: Common::Rect _textRectangle; Common::Rect _headerRectangle; - StringManager::TextStyle _textStyle; + cTxtStyle _stringInit; + cTxtStyle _stringChooserInit; uint32 _nextTabstop; - Common::String _cursorAnimationFileName; bool _focused; Common::String _currentInputText; bool _textChanged; uint _cursorOffset; + bool _enterPressed; + bool _readOnly; + + int16 _txtWidth; + MetaAnimation *_animation; + int32 _frameDelay; + int16 _frame; public: - void focus() { _focused = true; } - void unfocus() { _focused = false; } - void onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); - void onKeyDown(Common::KeyState keyState); + void focus() { + _focused = true; + _textChanged = true; + } + void unfocus() { + _focused = false; + _textChanged = true; + } + bool onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool onKeyDown(Common::KeyState keyState); bool process(uint32 deltaTimeInMillis); + void setText(const Common::String &_str); + const Common::String getText(); + bool enterPress(); + void setReadOnly(bool); }; } // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/lever_control.cpp b/engines/zvision/scripting/controls/lever_control.cpp index c029a2a7a1..12b07d7584 100644 --- a/engines/zvision/scripting/controls/lever_control.cpp +++ b/engines/zvision/scripting/controls/lever_control.cpp @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -28,8 +28,7 @@ #include "zvision/scripting/script_manager.h" #include "zvision/graphics/render_manager.h" #include "zvision/cursors/cursor_manager.h" -#include "zvision/animation/rlf_animation.h" -#include "zvision/video/zork_avi_decoder.h" +#include "zvision/animation/meta_animation.h" #include "zvision/utility/utility.h" #include "common/stream.h" @@ -39,118 +38,116 @@ #include "graphics/surface.h" - namespace ZVision { LeverControl::LeverControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) - : Control(engine, key), - _frameInfo(0), - _frameCount(0), - _startFrame(0), - _currentFrame(0), - _lastRenderedFrame(0), - _mouseIsCaptured(false), - _isReturning(false), - _accumulatedTime(0), - _returnRoutesCurrentFrame(0) { + : Control(engine, key, CONTROL_LEVER), + _frameInfo(0), + _frameCount(0), + _startFrame(0), + _currentFrame(0), + _lastRenderedFrame(0), + _mouseIsCaptured(false), + _isReturning(false), + _accumulatedTime(0), + _returnRoutesCurrentFrame(0) { // Loop until we find the closing brace Common::String line = stream.readLine(); trimCommentsAndWhiteSpace(&line); + Common::String param; + Common::String values; + getParams(line, param, values); + while (!stream.eos() && !line.contains('}')) { - if (line.matchString("*descfile*", true)) { + if (param.matchString("descfile", true)) { char levFileName[25]; - sscanf(line.c_str(), "%*[^(](%25[^)])", levFileName); + sscanf(values.c_str(), "%25s", levFileName); parseLevFile(levFileName); - } else if (line.matchString("*cursor*", true)) { + } else if (param.matchString("cursor", true)) { char cursorName[25]; - sscanf(line.c_str(), "%*[^(](%25[^)])", cursorName); + sscanf(values.c_str(), "%25s", cursorName); - _cursorName = Common::String(cursorName); + _cursor = _engine->getCursorManager()->getCursorId(Common::String(cursorName)); } line = stream.readLine(); trimCommentsAndWhiteSpace(&line); + getParams(line, param, values); } renderFrame(_currentFrame); } LeverControl::~LeverControl() { - if (_fileType == AVI) { - delete _animation.avi; - } else if (_fileType == RLF) { - delete _animation.rlf; - } + if (_animation) + delete _animation; delete[] _frameInfo; } void LeverControl::parseLevFile(const Common::String &fileName) { Common::File file; - if (!file.open(fileName)) { + if (!_engine->getSearchManager()->openFile(file, fileName)) { warning("LEV file %s could could be opened", fileName.c_str()); return; } - Common::String line = file.readLine(); + Common::String line; + Common::String param; + Common::String values; while (!file.eos()) { - if (line.matchString("*animation_id*", true)) { + line = file.readLine(); + getLevParams(line, param, values); + + if (param.matchString("animation_id", true)) { // Not used - } else if (line.matchString("*filename*", true)) { - char fileNameBuffer[25]; - sscanf(line.c_str(), "%*[^:]:%25[^~]~", fileNameBuffer); - - Common::String animationFileName(fileNameBuffer); - - if (animationFileName.hasSuffix(".avi")) { - _animation.avi = new ZorkAVIDecoder(); - _animation.avi->loadFile(animationFileName); - _fileType = AVI; - } else if (animationFileName.hasSuffix(".rlf")) { - _animation.rlf = new RlfAnimation(animationFileName, false); - _fileType = RLF; - } - } else if (line.matchString("*skipcolor*", true)) { + } else if (param.matchString("filename", true)) { + _animation = new MetaAnimation(values, _engine); + } else if (param.matchString("skipcolor", true)) { // Not used - } else if (line.matchString("*anim_coords*", true)) { + } else if (param.matchString("anim_coords", true)) { int left, top, right, bottom; - sscanf(line.c_str(), "%*[^:]:%d %d %d %d~", &left, &top, &right, &bottom); + sscanf(values.c_str(), "%d %d %d %d", &left, &top, &right, &bottom); _animationCoords.left = left; _animationCoords.top = top; _animationCoords.right = right; _animationCoords.bottom = bottom; - } else if (line.matchString("*mirrored*", true)) { + } else if (param.matchString("mirrored", true)) { uint mirrored; - sscanf(line.c_str(), "%*[^:]:%u~", &mirrored); + sscanf(values.c_str(), "%u", &mirrored); _mirrored = mirrored == 0 ? false : true; - } else if (line.matchString("*frames*", true)) { - sscanf(line.c_str(), "%*[^:]:%u~", &_frameCount); + } else if (param.matchString("frames", true)) { + sscanf(values.c_str(), "%u", &_frameCount); _frameInfo = new FrameInfo[_frameCount]; - } else if (line.matchString("*elsewhere*", true)) { + } else if (param.matchString("elsewhere", true)) { // Not used - } else if (line.matchString("*out_of_control*", true)) { + } else if (param.matchString("out_of_control", true)) { // Not used - } else if (line.matchString("*start_pos*", true)) { - sscanf(line.c_str(), "%*[^:]:%u~", &_startFrame); + } else if (param.matchString("start_pos", true)) { + sscanf(values.c_str(), "%u", &_startFrame); _currentFrame = _startFrame; - } else if (line.matchString("*hotspot_deltas*", true)) { + } else if (param.matchString("hotspot_deltas", true)) { uint x; uint y; - sscanf(line.c_str(), "%*[^:]:%u %u~", &x, &y); + sscanf(values.c_str(), "%u %u", &x, &y); _hotspotDelta.x = x; _hotspotDelta.y = y; + } else if (param.matchString("venus_id", true)) { + _venusId = atoi(values.c_str()); } else { uint frameNumber; uint x, y; + line.toLowercase(); + if (sscanf(line.c_str(), "%u:%u %u", &frameNumber, &x, &y) == 3) { _frameInfo[frameNumber].hotspot.left = x; _frameInfo[frameNumber].hotspot.top = y; @@ -158,13 +155,13 @@ void LeverControl::parseLevFile(const Common::String &fileName) { _frameInfo[frameNumber].hotspot.bottom = y + _hotspotDelta.y; } - Common::StringTokenizer tokenizer(line, " ^=()"); + Common::StringTokenizer tokenizer(line, " ^=()~"); tokenizer.nextToken(); tokenizer.nextToken(); Common::String token = tokenizer.nextToken(); while (!tokenizer.empty()) { - if (token == "D") { + if (token == "d") { token = tokenizer.nextToken(); uint angle; @@ -172,7 +169,7 @@ void LeverControl::parseLevFile(const Common::String &fileName) { sscanf(token.c_str(), "%u,%u", &toFrame, &angle); _frameInfo[frameNumber].directions.push_back(Direction(angle, toFrame)); - } else if (token.hasPrefix("P")) { + } else if (token.hasPrefix("p")) { // Format: P(<from> to <to>) tokenizer.nextToken(); tokenizer.nextToken(); @@ -186,25 +183,25 @@ void LeverControl::parseLevFile(const Common::String &fileName) { } } - line = file.readLine(); + // Don't read lines in this place because last will not be parsed. } } -void LeverControl::onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - if (!_enabled) { - return; - } +bool LeverControl::onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; if (_frameInfo[_currentFrame].hotspot.contains(backgroundImageSpacePos)) { + setVenus(); _mouseIsCaptured = true; _lastMousePos = backgroundImageSpacePos; } + return false; } -void LeverControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - if (!_enabled) { - return; - } +bool LeverControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; if (_mouseIsCaptured) { _mouseIsCaptured = false; @@ -214,12 +211,12 @@ void LeverControl::onMouseUp(const Common::Point &screenSpacePos, const Common:: _returnRoutesCurrentProgress = _frameInfo[_currentFrame].returnRoute.begin(); _returnRoutesCurrentFrame = _currentFrame; } + return false; } bool LeverControl::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - if (!_enabled) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) return false; - } bool cursorWasChanged = false; @@ -240,7 +237,7 @@ bool LeverControl::onMouseMove(const Common::Point &screenSpacePos, const Common } } } else if (_frameInfo[_currentFrame].hotspot.contains(backgroundImageSpacePos)) { - _engine->getCursorManager()->changeCursor(_cursorName); + _engine->getCursorManager()->changeCursor(_cursor); cursorWasChanged = true; } @@ -248,9 +245,8 @@ bool LeverControl::onMouseMove(const Common::Point &screenSpacePos, const Common } bool LeverControl::process(uint32 deltaTimeInMillis) { - if (!_enabled) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) return false; - } if (_isReturning) { _accumulatedTime += deltaTimeInMillis; @@ -301,7 +297,7 @@ int LeverControl::calculateVectorAngle(const Common::Point &pointOne, const Comm // Calculate the angle using arctan // Then convert to degrees. (180 / 3.14159 = 57.2958) - int angle = int(atan((float)yDist / (float)xDist) * 57); + int angle = int(atan((float)yDist / (float)abs(xDist)) * 57); // Calculate what quadrant pointTwo is in uint quadrant = ((yDist > 0 ? 1 : 0) << 1) | (xDist < 0 ? 1 : 0); @@ -350,16 +346,16 @@ int LeverControl::calculateVectorAngle(const Common::Point &pointOne, const Comm // Convert the local angles to unit circle angles switch (quadrant) { case 0: - angle = 180 + angle; + angle = -angle; break; case 1: - // Do nothing + angle = angle + 180; break; case 2: - angle = 180 + angle; + angle = 360 - angle; break; case 3: - angle = 360 + angle; + angle = 180 + angle; break; } @@ -377,26 +373,35 @@ void LeverControl::renderFrame(uint frameNumber) { _lastRenderedFrame = frameNumber; } - const uint16 *frameData = 0; - int x = _animationCoords.left; - int y = _animationCoords.top; - int width = 0; - int height = 0; - - if (_fileType == RLF) { - // getFrameData() will automatically optimize to getNextFrame() / getPreviousFrame() if it can - frameData = (const uint16 *)_animation.rlf->getFrameData(frameNumber)->getPixels(); - width = _animation.rlf->width(); // Use the animation width instead of _animationCoords.width() - height = _animation.rlf->height(); // Use the animation height instead of _animationCoords.height() - } else if (_fileType == AVI) { - _animation.avi->seekToFrame(frameNumber); - const Graphics::Surface *surface = _animation.avi->decodeNextFrame(); - frameData = (const uint16 *)surface->getPixels(); - width = surface->w; - height = surface->h; - } + const Graphics::Surface *frameData; + + frameData = _animation->getFrameData(frameNumber); + if (frameData) + _engine->getRenderManager()->blitSurfaceToBkgScaled(*frameData, _animationCoords); +} + +void LeverControl::getLevParams(const Common::String &inputStr, Common::String ¶meter, Common::String &values) { + const char *chrs = inputStr.c_str(); + uint lbr; + + for (lbr = 0; lbr < inputStr.size(); lbr++) + if (chrs[lbr] == ':') + break; + + if (lbr >= inputStr.size()) + return; + + uint rbr; + + for (rbr = lbr + 1; rbr < inputStr.size(); rbr++) + if (chrs[rbr] == '~') + break; + + if (rbr >= inputStr.size()) + return; - _engine->getRenderManager()->copyRectToWorkingWindow(frameData, x, y, width, width, height); + parameter = Common::String(chrs, chrs + lbr); + values = Common::String(chrs + lbr + 1, chrs + rbr); } } // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/lever_control.h b/engines/zvision/scripting/controls/lever_control.h index 49e4fd3806..37d4d3bd8d 100644 --- a/engines/zvision/scripting/controls/lever_control.h +++ b/engines/zvision/scripting/controls/lever_control.h @@ -28,11 +28,10 @@ #include "common/list.h" #include "common/rect.h" - namespace ZVision { class ZorkAVIDecoder; -class RlfAnimation; +class MetaAnimation; class LeverControl : public Control { public: @@ -40,10 +39,6 @@ public: ~LeverControl(); private: - enum FileType { - RLF = 1, - AVI = 2 - }; struct Direction { Direction(uint a, uint t) : angle(a), toFrame(t) {} @@ -64,13 +59,9 @@ private: }; private: - union { - RlfAnimation *rlf; - ZorkAVIDecoder *avi; - } _animation; - FileType _fileType; + MetaAnimation *_animation; - Common::String _cursorName; + int _cursor; Common::Rect _animationCoords; bool _mirrored; uint _frameCount; @@ -88,8 +79,8 @@ private: uint32 _accumulatedTime; public: - void onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); - void onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); bool process(uint32 deltaTimeInMillis); @@ -120,6 +111,7 @@ private: */ static int calculateVectorAngle(const Common::Point &pointOne, const Common::Point &pointTwo); void renderFrame(uint frameNumber); + void getLevParams(const Common::String &inputStr, Common::String ¶meter, Common::String &values); }; } // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/paint_control.cpp b/engines/zvision/scripting/controls/paint_control.cpp new file mode 100644 index 0000000000..9bad6f2c58 --- /dev/null +++ b/engines/zvision/scripting/controls/paint_control.cpp @@ -0,0 +1,214 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/controls/paint_control.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/cursors/cursor_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/utility/utility.h" + +namespace ZVision { + +PaintControl::PaintControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) + : Control(engine, key, CONTROL_PAINT) { + + _cursor = CursorIndex_Active; + _paint = NULL; + _bkg = NULL; + _brush = NULL; + _colorKey = 0; + _mouseDown = false; + + // Loop until we find the closing brace + Common::String line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + Common::String param; + Common::String values; + getParams(line, param, values); + + while (!stream.eos() && !line.contains('}')) { + if (param.matchString("rectangle", true)) { + int x; + int y; + int width; + int height; + + sscanf(values.c_str(), "%d %d %d %d", &x, &y, &width, &height); + + _rectangle = Common::Rect(x, y, width + x, height + y); + } else if (param.matchString("cursor", true)) { + _cursor = _engine->getCursorManager()->getCursorId(values); + } else if (param.matchString("brush_file", true)) { + _brush = _engine->getRenderManager()->loadImage(values, false); + } else if (param.matchString("venus_id", true)) { + _venusId = atoi(values.c_str()); + } else if (param.matchString("paint_file", true)) { + _paint = _engine->getRenderManager()->loadImage(values, false); + } else if (param.matchString("eligible_objects", true)) { + char buf[256]; + memset(buf, 0, 256); + strcpy(buf, values.c_str()); + + char *curpos = buf; + char *strend = buf + strlen(buf); + while (true) { + char *st = curpos; + + if (st >= strend) + break; + + while (*curpos != ' ' && curpos < strend) + curpos++; + + *curpos = 0; + curpos++; + + int obj = atoi(st); + + _eligibleObjects.push_back(obj); + } + } + + line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + getParams(line, param, values); + } + + if (_paint) { + _colorKey = _paint->format.RGBToColor(255, 0, 255); + _bkg = new Graphics::Surface; + _bkg->create(_rectangle.width(), _rectangle.height(), _paint->format); + _bkg->fillRect(Common::Rect(_rectangle.width(), _rectangle.height()), _colorKey); + + Graphics::Surface *tmp = new Graphics::Surface; + tmp->create(_rectangle.width(), _rectangle.height(), _paint->format); + _engine->getRenderManager()->blitSurfaceToSurface(*_paint, _rectangle, *tmp, 0, 0); + _paint->free(); + delete _paint; + _paint = tmp; + } +} + +PaintControl::~PaintControl() { + // Clear the state value back to 0 + //_engine->getScriptManager()->setStateValue(_key, 0); + if (_paint) + delete _paint; + if (_brush) + delete _brush; + if (_bkg) + delete _bkg; +} + +bool PaintControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + _mouseDown = false; + + return false; +} + +bool PaintControl::onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_rectangle.contains(backgroundImageSpacePos)) { + int mouseItem = _engine->getScriptManager()->getStateValue(StateKey_InventoryItem); + + if (eligeblity(mouseItem)) { + setVenus(); + _mouseDown = true; + } + } + + return false; +} + +bool PaintControl::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_rectangle.contains(backgroundImageSpacePos)) { + int mouseItem = _engine->getScriptManager()->getStateValue(StateKey_InventoryItem); + + if (eligeblity(mouseItem)) { + _engine->getCursorManager()->changeCursor(_cursor); + + if (_mouseDown) { + Common::Rect bkgRect = paint(backgroundImageSpacePos); + if (!bkgRect.isEmpty()) { + Common::Rect imgRect = bkgRect; + imgRect.translate(-_rectangle.left, -_rectangle.top); + + Graphics::Surface imgUpdate = _bkg->getSubArea(imgRect); + + _engine->getRenderManager()->blitSurfaceToBkg(imgUpdate, bkgRect.left, bkgRect.top, _colorKey); + } + } + return true; + } + } + + return false; +} + +bool PaintControl::eligeblity(int itemId) { + for (Common::List<int>::iterator it = _eligibleObjects.begin(); it != _eligibleObjects.end(); it++) + if (*it == itemId) + return true; + return false; +} + +Common::Rect PaintControl::paint(const Common::Point &point) { + Common::Rect paintRect = Common::Rect(_brush->w, _brush->h); + paintRect.moveTo(point); + paintRect.clip(_rectangle); + + if (!paintRect.isEmpty()) { + Common::Rect brushRect = paintRect; + brushRect.translate(-point.x, -point.y); + + Common::Rect bkgRect = paintRect; + bkgRect.translate(-_rectangle.left, -_rectangle.top); + + for (int yy = 0; yy < brushRect.height(); yy++) { + uint16 *mask = (uint16 *)_brush->getBasePtr(brushRect.left, brushRect.top + yy); + uint16 *from = (uint16 *)_paint->getBasePtr(bkgRect.left, bkgRect.top + yy); + uint16 *to = (uint16 *)_bkg->getBasePtr(bkgRect.left, bkgRect.top + yy); + for (int xx = 0; xx < brushRect.width(); xx++) { + if (*mask != 0) + *(to + xx) = *(from + xx); + + mask++; + } + } + + } + return paintRect; +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/paint_control.h b/engines/zvision/scripting/controls/paint_control.h new file mode 100644 index 0000000000..8097290ac2 --- /dev/null +++ b/engines/zvision/scripting/controls/paint_control.h @@ -0,0 +1,91 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_PAINT_CONTROL_H +#define ZVISION_PAINT_CONTROL_H + +#include "zvision/scripting/control.h" + +#include "graphics/surface.h" + +#include "common/rect.h" +#include "common/list.h" + +namespace ZVision { + +class PaintControl : public Control { +public: + PaintControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream); + ~PaintControl(); + + /** + * @param screenSpacePos The position of the mouse in screen space + * @param backgroundImageSpacePos The position of the mouse in background image space + */ + bool onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + + /** + * @param screenSpacePos The position of the mouse in screen space + * @param backgroundImageSpacePos The position of the mouse in background image space + */ + bool onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + /** + * Called on every MouseMove. Tests if the mouse is inside _hotspot, and if so, sets the cursor. + * + * @param engine The base engine + * @param screenSpacePos The position of the mouse in screen space + * @param backgroundImageSpacePos The position of the mouse in background image space + * @return Was the cursor changed? + */ + bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + + bool process(uint32 deltaTimeInMillis) { + return false; + }; + +private: + /** + * The area that will trigger the event + * This is in image space coordinates, NOT screen space + */ + + uint32 _colorKey; + + Graphics::Surface *_paint; + Graphics::Surface *_bkg; + Graphics::Surface *_brush; + + Common::List<int> _eligibleObjects; + + int _cursor; + Common::Rect _rectangle; + + bool _mouseDown; + + bool eligeblity(int itemId); + Common::Rect paint(const Common::Point &point); + +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/controls/push_toggle_control.cpp b/engines/zvision/scripting/controls/push_toggle_control.cpp index a96c95b377..c5ec070899 100644 --- a/engines/zvision/scripting/controls/push_toggle_control.cpp +++ b/engines/zvision/scripting/controls/push_toggle_control.cpp @@ -31,68 +31,117 @@ #include "common/stream.h" - namespace ZVision { PushToggleControl::PushToggleControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) - : Control(engine, key) { + : Control(engine, key, CONTROL_PUSHTGL), + _countTo(2), + _event(Common::EVENT_LBUTTONUP) { + + _hotspots.clear(); + // Loop until we find the closing brace Common::String line = stream.readLine(); trimCommentsAndWhiteSpace(&line); + Common::String param; + Common::String values; + getParams(line, param, values); while (!stream.eos() && !line.contains('}')) { - if (line.matchString("*_hotspot*", true)) { + if (param.matchString("*_hotspot", true)) { uint x; uint y; uint width; uint height; - sscanf(line.c_str(), "%*[^(](%u,%u,%u,%u)", &x, &y, &width, &height); - - _hotspot = Common::Rect(x, y, x + width, y + height); - } else if (line.matchString("cursor*", true)) { - char nameBuffer[25]; - - sscanf(line.c_str(), "%*[^(](%25[^)])", nameBuffer); - - _hoverCursor = Common::String(nameBuffer); + sscanf(values.c_str(), "%u,%u,%u,%u", &x, &y, &width, &height); + + _hotspots.push_back(Common::Rect(x, y, x + width + 1, y + height + 1)); + } else if (param.matchString("cursor", true)) { + _cursor = _engine->getCursorManager()->getCursorId(values); + } else if (param.matchString("animation", true)) { + // Not used + } else if (param.matchString("sound", true)) { + // Not used + } else if (param.matchString("count_to", true)) { + sscanf(values.c_str(), "%u", &_countTo); + } else if (param.matchString("mouse_event", true)) { + if (values.equalsIgnoreCase("up")) { + _event = Common::EVENT_LBUTTONUP; + } else if (values.equalsIgnoreCase("down")) { + _event = Common::EVENT_LBUTTONDOWN; + } else if (values.equalsIgnoreCase("double")) { + // Not used + } + } else if (param.matchString("venus_id", true)) { + _venusId = atoi(values.c_str()); } line = stream.readLine(); trimCommentsAndWhiteSpace(&line); + getParams(line, param, values); } - if (_hotspot.isEmpty() || _hoverCursor.empty()) { - warning("Push_toggle cursor %u was parsed incorrectly", key); + if (_hotspots.size() == 0) { + warning("Push_toggle %u was parsed incorrectly", key); } } PushToggleControl::~PushToggleControl() { - // Clear the state value back to 0 - _engine->getScriptManager()->setStateValue(_key, 0); + _hotspots.clear(); } -void PushToggleControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - if (!_enabled) { - return; +bool PushToggleControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_event != Common::EVENT_LBUTTONUP) + return false; + + if (contain(backgroundImageSpacePos)) { + setVenus(); + int32 val = _engine->getScriptManager()->getStateValue(_key); + val = (val + 1) % _countTo; + _engine->getScriptManager()->setStateValue(_key, val); + return true; } + return false; +} + +bool PushToggleControl::onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; - if (_hotspot.contains(backgroundImageSpacePos)) { - _engine->getScriptManager()->setStateValue(_key, 1); + if (_event != Common::EVENT_LBUTTONDOWN) + return false; + + if (contain(backgroundImageSpacePos)) { + setVenus(); + int32 val = _engine->getScriptManager()->getStateValue(_key); + val = (val + 1) % _countTo; + _engine->getScriptManager()->setStateValue(_key, val); + return true; } + return false; } bool PushToggleControl::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - if (!_enabled) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) return false; - } - if (_hotspot.contains(backgroundImageSpacePos)) { - _engine->getCursorManager()->changeCursor(_hoverCursor); + if (contain(backgroundImageSpacePos)) { + _engine->getCursorManager()->changeCursor(_cursor); return true; } return false; } +bool PushToggleControl::contain(const Common::Point &point) { + for (uint i = 0; i < _hotspots.size(); i++) + if (_hotspots[i].contains(point)) + return true; + return false; +} + } // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/push_toggle_control.h b/engines/zvision/scripting/controls/push_toggle_control.h index 3854fc2005..9444c77cb6 100644 --- a/engines/zvision/scripting/controls/push_toggle_control.h +++ b/engines/zvision/scripting/controls/push_toggle_control.h @@ -26,7 +26,8 @@ #include "zvision/scripting/control.h" #include "common/rect.h" - +#include "common/events.h" +#include "common/array.h" namespace ZVision { @@ -36,12 +37,19 @@ public: ~PushToggleControl(); /** + * Called when LeftMouse is pushed. Default is NOP. + * + * @param screenSpacePos The position of the mouse in screen space + * @param backgroundImageSpacePos The position of the mouse in background image space + */ + bool onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + /** * Called when LeftMouse is lifted. Calls ScriptManager::setStateValue(_key, 1); * * @param screenSpacePos The position of the mouse in screen space * @param backgroundImageSpacePos The position of the mouse in background image space */ - void onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); /** * Called on every MouseMove. Tests if the mouse is inside _hotspot, and if so, sets the cursor. * @@ -57,9 +65,15 @@ private: * The area that will trigger the event * This is in image space coordinates, NOT screen space */ - Common::Rect _hotspot; + Common::Array<Common::Rect> _hotspots; /** The cursor to use when hovering over _hotspot */ - Common::String _hoverCursor; + int _cursor; + /** Button maximal values count */ + uint _countTo; + + Common::EventType _event; + + bool contain(const Common::Point &point); }; } // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/safe_control.cpp b/engines/zvision/scripting/controls/safe_control.cpp new file mode 100644 index 0000000000..3ad5d3a8ae --- /dev/null +++ b/engines/zvision/scripting/controls/safe_control.cpp @@ -0,0 +1,204 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/controls/safe_control.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/cursors/cursor_manager.h" +#include "zvision/animation/meta_animation.h" +#include "zvision/utility/utility.h" + +#include "common/stream.h" +#include "common/file.h" +#include "common/tokenizer.h" +#include "common/system.h" + +#include "graphics/surface.h" + +namespace ZVision { + +SafeControl::SafeControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) + : Control(engine, key, CONTROL_SAFE) { + _statesCount = 0; + _curState = 0; + _animation = NULL; + _innerRaduis = 0; + _innerRadiusSqr = 0; + _outerRadius = 0; + _outerRadiusSqr = 0; + _zeroPointer = 0; + _startPointer = 0; + _curFrame = -1; + _targetFrame = 0; + _frameTime = 0; + _lastRenderedFrame = -1; + + // Loop until we find the closing brace + Common::String line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + Common::String param; + Common::String values; + getParams(line, param, values); + + while (!stream.eos() && !line.contains('}')) { + if (param.matchString("animation", true)) { + _animation = new MetaAnimation(values, _engine); + } else if (param.matchString("rectangle", true)) { + int x; + int y; + int width; + int height; + + sscanf(values.c_str(), "%d %d %d %d", &x, &y, &width, &height); + + _rectangle = Common::Rect(x, y, width, height); + } else if (param.matchString("num_states", true)) { + _statesCount = atoi(values.c_str()); + } else if (param.matchString("center", true)) { + int x; + int y; + + sscanf(values.c_str(), "%d %d", &x, &y); + _center = Common::Point(x, y); + } else if (param.matchString("dial_inner_radius", true)) { + _innerRaduis = atoi(values.c_str()); + _innerRadiusSqr = _innerRaduis * _innerRaduis; + } else if (param.matchString("radius", true)) { + _outerRadius = atoi(values.c_str()); + _outerRadiusSqr = _outerRadius * _outerRadius; + } else if (param.matchString("zero_radians_offset", true)) { + _zeroPointer = atoi(values.c_str()); + } else if (param.matchString("pointer_offset", true)) { + _startPointer = atoi(values.c_str()); + _curState = _startPointer; + } else if (param.matchString("cursor", true)) { + // Not used + } else if (param.matchString("mirrored", true)) { + // Not used + } else if (param.matchString("venus_id", true)) { + _venusId = atoi(values.c_str()); + } + + line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + getParams(line, param, values); + } + renderFrame(_curState); +} + +SafeControl::~SafeControl() { + if (_animation) + delete _animation; + +} + +void SafeControl::renderFrame(uint frameNumber) { + if (frameNumber == 0) { + _lastRenderedFrame = frameNumber; + } else if ((int16)frameNumber < _lastRenderedFrame) { + _lastRenderedFrame = frameNumber; + frameNumber = (_statesCount * 2) - frameNumber; + } else { + _lastRenderedFrame = frameNumber; + } + + const Graphics::Surface *frameData; + int x = _rectangle.left; + int y = _rectangle.top; + + frameData = _animation->getFrameData(frameNumber); + if (frameData) + _engine->getRenderManager()->blitSurfaceToBkg(*frameData, x, y); +} + +bool SafeControl::process(uint32 deltaTimeInMillis) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_curFrame != _targetFrame) { + _frameTime -= deltaTimeInMillis; + + if (_frameTime <= 0) { + if (_curFrame < _targetFrame) { + _curFrame++; + renderFrame(_curFrame); + } else if (_curFrame > _targetFrame) { + _curFrame--; + renderFrame(_curFrame); + } + _frameTime = _animation->frameTime(); + } + } + return false; +} + +bool SafeControl::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_rectangle.contains(backgroundImageSpacePos)) { + int32 mR = backgroundImageSpacePos.sqrDist(_center); + if (mR <= _outerRadiusSqr && mR >= _innerRadiusSqr) { + _engine->getCursorManager()->changeCursor(CursorIndex_Active); + return true; + } + } + return false; +} + +bool SafeControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_rectangle.contains(backgroundImageSpacePos)) { + int32 mR = backgroundImageSpacePos.sqrDist(_center); + if (mR <= _outerRadiusSqr && mR >= _innerRadiusSqr) { + setVenus(); + + Common::Point tmp = backgroundImageSpacePos - _center; + + float dd = atan2((float)tmp.x, (float)tmp.y) * 57.29578; + + int16 dp_state = 360 / _statesCount; + + int16 m_state = (_statesCount - ((((int16)dd + 540) % 360) / dp_state)) % _statesCount; + + int16 tmp2 = (m_state + _curState - _zeroPointer + _statesCount - 1) % _statesCount; + + _curFrame = (_curState + _statesCount - _startPointer) % _statesCount; + + _curState = (_statesCount * 2 + tmp2) % _statesCount; + + _targetFrame = (_curState + _statesCount - _startPointer) % _statesCount; + + _engine->getScriptManager()->setStateValue(_key, _curState); + return true; + } + } + return false; +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/safe_control.h b/engines/zvision/scripting/controls/safe_control.h new file mode 100644 index 0000000000..e32ca97b70 --- /dev/null +++ b/engines/zvision/scripting/controls/safe_control.h @@ -0,0 +1,70 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_SAFE_CONTROL_H +#define ZVISION_SAFE_CONTROL_H + +#include "zvision/scripting/control.h" + +#include "common/list.h" +#include "common/rect.h" + +namespace ZVision { + +class ZorkAVIDecoder; +class MetaAnimation; + +class SafeControl : public Control { +public: + SafeControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream); + ~SafeControl(); + +private: + int16 _statesCount; + int16 _curState; + MetaAnimation *_animation; + Common::Point _center; + Common::Rect _rectangle; + int16 _innerRaduis; + int32 _innerRadiusSqr; + int16 _outerRadius; + int32 _outerRadiusSqr; + int16 _zeroPointer; + int16 _startPointer; + int16 _curFrame; + int16 _targetFrame; + int32 _frameTime; + + int16 _lastRenderedFrame; + +public: + bool onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + bool process(uint32 deltaTimeInMillis); + +private: + void renderFrame(uint frameNumber); +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/controls/save_control.cpp b/engines/zvision/scripting/controls/save_control.cpp new file mode 100644 index 0000000000..ad01257e6b --- /dev/null +++ b/engines/zvision/scripting/controls/save_control.cpp @@ -0,0 +1,122 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/controls/input_control.h" +#include "zvision/scripting/controls/save_control.h" +#include "zvision/utility/utility.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/text/string_manager.h" + +#include "zvision/core/save_manager.h" + +#include "common/str.h" +#include "common/stream.h" + +namespace ZVision { + +SaveControl::SaveControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) + : Control(engine, key, CONTROL_SAVE), + _saveControl(false) { + // Loop until we find the closing brace + Common::String line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + Common::String param; + Common::String values; + getParams(line, param, values); + + while (!stream.eos() && !line.contains('}')) { + if (param.matchString("savebox", true)) { + int saveId; + int inputId; + + sscanf(values.c_str(), "%d %d", &saveId, &inputId); + saveElement elmnt; + elmnt.inputKey = inputId; + elmnt.saveId = saveId; + elmnt.exist = false; + _inputs.push_back(elmnt); + } else if (param.matchString("control_type", true)) { + if (values.contains("save")) + _saveControl = true; + else + _saveControl = false; + } + + line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + getParams(line, param, values); + } + + for (saveElmntList::iterator iter = _inputs.begin(); iter != _inputs.end(); ++iter) { + Control *ctrl = _engine->getScriptManager()->getControl(iter->inputKey); + if (ctrl && ctrl->getType() == Control::CONTROL_INPUT) { + InputControl *inp = (InputControl *)ctrl; + inp->setReadOnly(!_saveControl); + Common::SeekableReadStream *save = _engine->getSaveManager()->getSlotFile(iter->saveId); + if (save) { + SaveGameHeader header; + _engine->getSaveManager()->readSaveGameHeader(save, header); + delete save; + inp->setText(header.saveName); + iter->exist = true; + } + } + } +} + +bool SaveControl::process(uint32 deltaTimeInMillis) { + for (saveElmntList::iterator iter = _inputs.begin(); iter != _inputs.end(); ++iter) { + Control *ctrl = _engine->getScriptManager()->getControl(iter->inputKey); + if (ctrl && ctrl->getType() == Control::CONTROL_INPUT) { + InputControl *inp = (InputControl *)ctrl; + if (inp->enterPress()) { + if (_saveControl) { + if (inp->getText().size() > 0) { + bool toSave = true; + if (iter->exist) + if (!_engine->askQuestion(_engine->getStringManager()->getTextLine(StringManager::ZVISION_STR_SAVEEXIST))) + toSave = false; + + if (toSave) { + _engine->getSaveManager()->saveGameBuffered(iter->saveId, inp->getText()); + _engine->delayedMessage(_engine->getStringManager()->getTextLine(StringManager::ZVISION_STR_SAVED), 2000); + _engine->getScriptManager()->changeLocation(_engine->getScriptManager()->getLastMenuLocation()); + } + } else { + _engine->timedMessage(_engine->getStringManager()->getTextLine(StringManager::ZVISION_STR_SAVEEMPTY), 2000); + } + } else { + _engine->getSaveManager()->loadGame(iter->saveId); + return true; + } + break; + } + } + } + return false; +} + +} // End of namespace ZVision diff --git a/engines/zvision/inventory/inventory_manager.h b/engines/zvision/scripting/controls/save_control.h index f9d2ff294a..cdc50eb54d 100644 --- a/engines/zvision/inventory/inventory_manager.h +++ b/engines/zvision/scripting/controls/save_control.h @@ -20,9 +20,36 @@ * */ -#ifndef ZVISION_INVENTORY_MANAGER_H -#define ZVISION_INVENTORY_MANAGER_H +#ifndef ZVISION_SAVE_CONTROL_H +#define ZVISION_SAVE_CONTROL_H -// TODO: Implement InventoryManager +#include "zvision/scripting/control.h" + +#include "common/list.h" + +namespace ZVision { + +class SaveControl : public Control { +public: + SaveControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream); + +private: + struct saveElement { + int saveId; + int inputKey; + bool exist; + }; + typedef Common::List<saveElement> saveElmntList; + saveElmntList _inputs; + + bool _saveControl; + +public: + + bool process(uint32 deltaTimeInMillis); + +}; + +} // End of namespace ZVision #endif diff --git a/engines/zvision/scripting/controls/slot_control.cpp b/engines/zvision/scripting/controls/slot_control.cpp new file mode 100644 index 0000000000..1d83b44392 --- /dev/null +++ b/engines/zvision/scripting/controls/slot_control.cpp @@ -0,0 +1,218 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/controls/slot_control.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/cursors/cursor_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/utility/utility.h" + +#include "common/stream.h" + +namespace ZVision { + +SlotControl::SlotControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) + : Control(engine, key, CONTROL_SLOT) { + + _renderedItem = 0; + _bkg = NULL; + + // Loop until we find the closing brace + Common::String line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + Common::String param; + Common::String values; + getParams(line, param, values); + + while (!stream.eos() && !line.contains('}')) { + if (param.matchString("hotspot", true)) { + int x; + int y; + int width; + int height; + + sscanf(values.c_str(), "%d %d %d %d", &x, &y, &width, &height); + + _hotspot = Common::Rect(x, y, width, height); + } else if (param.matchString("rectangle", true)) { + int x; + int y; + int width; + int height; + + sscanf(values.c_str(), "%d %d %d %d", &x, &y, &width, &height); + + _rectangle = Common::Rect(x, y, width, height); + } else if (param.matchString("cursor", true)) { + _cursor = _engine->getCursorManager()->getCursorId(values); + } else if (param.matchString("distance_id", true)) { + sscanf(values.c_str(), "%c", &_distanceId); + } else if (param.matchString("venus_id", true)) { + _venusId = atoi(values.c_str()); + } else if (param.matchString("eligible_objects", true)) { + char buf[256]; + memset(buf, 0, 256); + strcpy(buf, values.c_str()); + + char *curpos = buf; + char *strend = buf + strlen(buf); + while (true) { + char *st = curpos; + + if (st >= strend) + break; + + while (*curpos != ' ' && curpos < strend) + curpos++; + + *curpos = 0; + curpos++; + + int obj = atoi(st); + + _eligibleObjects.push_back(obj); + } + } + + line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + getParams(line, param, values); + } + + if (_hotspot.isEmpty() || _rectangle.isEmpty()) { + warning("Slot %u was parsed incorrectly", key); + } +} + +SlotControl::~SlotControl() { + // Clear the state value back to 0 + //_engine->getScriptManager()->setStateValue(_key, 0); + + if (_bkg) + delete _bkg; +} + +bool SlotControl::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_hotspot.contains(backgroundImageSpacePos)) { + setVenus(); + + int item = _engine->getScriptManager()->getStateValue(_key); + int mouseItem = _engine->getScriptManager()->getStateValue(StateKey_InventoryItem); + if (item != 0) { + if (mouseItem != 0) { + if (eligeblity(mouseItem)) { + _engine->getScriptManager()->inventoryDrop(mouseItem); + _engine->getScriptManager()->inventoryAdd(item); + _engine->getScriptManager()->setStateValue(_key, mouseItem); + } + } else { + _engine->getScriptManager()->inventoryAdd(item); + _engine->getScriptManager()->setStateValue(_key, 0); + } + } else if (mouseItem == 0) { + if (eligeblity(0)) { + _engine->getScriptManager()->inventoryDrop(0); + _engine->getScriptManager()->setStateValue(_key, 0); + } + } else if (eligeblity(mouseItem)) { + _engine->getScriptManager()->setStateValue(_key, mouseItem); + _engine->getScriptManager()->inventoryDrop(mouseItem); + } + } + return false; +} + +bool SlotControl::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_hotspot.contains(backgroundImageSpacePos)) { + _engine->getCursorManager()->changeCursor(_cursor); + return true; + } + + return false; +} + +bool SlotControl::process(uint32 deltaTimeInMillis) { + if (_engine->getScriptManager()->getStateFlag(_key) & Puzzle::DISABLED) + return false; + + if (_engine->canRender()) { + int curItem = _engine->getScriptManager()->getStateValue(_key); + if (curItem != _renderedItem) { + if (_renderedItem != 0 && curItem == 0) { + _engine->getRenderManager()->blitSurfaceToBkg(*_bkg, _rectangle.left, _rectangle.top); + _renderedItem = curItem; + } else { + if (_renderedItem == 0) { + if (_bkg) + delete _bkg; + + _bkg = _engine->getRenderManager()->getBkgRect(_rectangle); + } else { + _engine->getRenderManager()->blitSurfaceToBkg(*_bkg, _rectangle.left, _rectangle.top); + } + + char buf[16]; + if (_engine->getGameId() == GID_NEMESIS) + sprintf(buf, "%d%cobj.tga", curItem, _distanceId); + else + sprintf(buf, "g0z%cu%2.2x1.tga", _distanceId, curItem); + + Graphics::Surface *srf = _engine->getRenderManager()->loadImage(buf); + + int16 drawx = _rectangle.left; + int16 drawy = _rectangle.top; + + if (_rectangle.width() > srf->w) + drawx = _rectangle.left + (_rectangle.width() - srf->w) / 2; + + if (_rectangle.height() > srf->h) + drawy = _rectangle.top + (_rectangle.height() - srf->h) / 2; + + _engine->getRenderManager()->blitSurfaceToBkg(*srf, drawx, drawy, 0); + + delete srf; + + _renderedItem = curItem; + } + } + } + return false; +} + +bool SlotControl::eligeblity(int itemId) { + for (Common::List<int>::iterator it = _eligibleObjects.begin(); it != _eligibleObjects.end(); it++) + if (*it == itemId) + return true; + return false; +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/slot_control.h b/engines/zvision/scripting/controls/slot_control.h new file mode 100644 index 0000000000..e776d99311 --- /dev/null +++ b/engines/zvision/scripting/controls/slot_control.h @@ -0,0 +1,84 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_SLOT_CONTROL_H +#define ZVISION_SLOT_CONTROL_H + +#include "zvision/scripting/control.h" + +#include "graphics/surface.h" + +#include "common/rect.h" +#include "common/list.h" + +namespace ZVision { + +class SlotControl : public Control { +public: + SlotControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream); + ~SlotControl(); + + /** + * Called when LeftMouse is lifted. Calls ScriptManager::setStateValue(_key, 1); + * + * @param screenSpacePos The position of the mouse in screen space + * @param backgroundImageSpacePos The position of the mouse in background image space + */ + bool onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + /** + * Called on every MouseMove. Tests if the mouse is inside _hotspot, and if so, sets the cursor. + * + * @param engine The base engine + * @param screenSpacePos The position of the mouse in screen space + * @param backgroundImageSpacePos The position of the mouse in background image space + * @return Was the cursor changed? + */ + bool onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos); + + bool process(uint32 deltaTimeInMillis); + +private: + /** + * The area that will trigger the event + * This is in image space coordinates, NOT screen space + */ + Common::Rect _rectangle; + Common::Rect _hotspot; + + int _cursor; + char _distanceId; + + int _renderedItem; + + Common::List<int> _eligibleObjects; + + bool eligeblity(int itemId); + + Graphics::Surface *_bkg; + + /** The cursor to use when hovering over _hotspot */ + Common::String _hoverCursor; +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/controls/titler_control.cpp b/engines/zvision/scripting/controls/titler_control.cpp new file mode 100644 index 0000000000..f0126bebc2 --- /dev/null +++ b/engines/zvision/scripting/controls/titler_control.cpp @@ -0,0 +1,107 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/controls/titler_control.h" + +#include "zvision/zvision.h" +#include "zvision/text/text.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/utility/utility.h" + +#include "common/stream.h" + +namespace ZVision { + +TitlerControl::TitlerControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream) + : Control(engine, key, CONTROL_TITLER) { + + _surface = NULL; + _curString = -1; + + // Loop until we find the closing brace + Common::String line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + Common::String param; + Common::String values; + getParams(line, param, values); + + while (!stream.eos() && !line.contains('}')) { + if (param.matchString("string_resource_file", true)) { + readStringsFile(values); + } else if (param.matchString("rectangle", true)) { + int x; + int y; + int x2; + int y2; + + sscanf(values.c_str(), "%d %d %d %d", &x, &y, &x2, &y2); + + _rectangle = Common::Rect(x, y, x2, y2); + } + + line = stream.readLine(); + trimCommentsAndWhiteSpace(&line); + getParams(line, param, values); + } + + if (!_rectangle.isEmpty()) { + _surface = new Graphics::Surface; + _surface->create(_rectangle.width(), _rectangle.height(), _engine->_pixelFormat); + _surface->fillRect(Common::Rect(_surface->w, _surface->h), 0); + } +} + +TitlerControl::~TitlerControl() { + if (_surface) + delete _surface; +} + +void TitlerControl::setString(int strLine) { + if (strLine != _curString && strLine >= 0 && strLine < (int)_strings.size()) { + _surface->fillRect(Common::Rect(_surface->w, _surface->h), 0); + _engine->getTextRenderer()->drawTxtInOneLine(_strings[strLine], *_surface); + _engine->getRenderManager()->blitSurfaceToBkg(*_surface, _rectangle.left, _rectangle.top); + _curString = strLine; + } +} + +void TitlerControl::readStringsFile(const Common::String &fileName) { + Common::File file; + if (!_engine->getSearchManager()->openFile(file, fileName)) { + warning("String_resource_file %s could could be opened", fileName.c_str()); + return; + } + + _strings.clear(); + + while (!file.eos()) { + + Common::String line = readWideLine(file); + _strings.push_back(line); + } + file.close(); +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/controls/titler_control.h b/engines/zvision/scripting/controls/titler_control.h new file mode 100644 index 0000000000..075e47c9e9 --- /dev/null +++ b/engines/zvision/scripting/controls/titler_control.h @@ -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 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_TITLER_CONTROL_H +#define ZVISION_TITLER_CONTROL_H + +#include "zvision/scripting/control.h" + +#include "graphics/surface.h" + +#include "common/rect.h" +#include "common/array.h" + +namespace ZVision { + +class TitlerControl : public Control { +public: + TitlerControl(ZVision *engine, uint32 key, Common::SeekableReadStream &stream); + ~TitlerControl(); + + void setString(int strLine); + +private: + + Common::Array< Common::String > _strings; + Common::Rect _rectangle; + int16 _curString; + Graphics::Surface *_surface; + + void readStringsFile(const Common::String &fileName); +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/inventory.cpp b/engines/zvision/scripting/inventory.cpp new file mode 100644 index 0000000000..76d43b200b --- /dev/null +++ b/engines/zvision/scripting/inventory.cpp @@ -0,0 +1,122 @@ +/* ScummVM - Graphic Adventure Engine +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ + +#include "common/scummsys.h" + +#include "zvision/scripting/script_manager.h" + +namespace ZVision { + +int8 ScriptManager::inventoryGetCount() { + return getStateValue(StateKey_Inv_Cnt_Slot); +} + +void ScriptManager::inventorySetCount(int8 cnt) { + setStateValue(StateKey_Inv_Cnt_Slot, cnt); +} + +int16 ScriptManager::inventoryGetItem(int8 id) { + if (id < 49 && id >= 0) + return getStateValue(StateKey_Inv_1_Slot + id); + return -1; +} + +void ScriptManager::inventorySetItem(int8 id, int16 item) { + if (id < 49 && id >= 0) + setStateValue(StateKey_Inv_1_Slot + id, item); +} + +void ScriptManager::inventoryAdd(int16 item) { + int8 cnt = inventoryGetCount(); + + if (cnt < 49) { + bool notExist = true; + + if (cnt == 0) { + inventorySetItem(0, 0); + inventorySetCount(1); // we needed empty item for cycle code + cnt = 1; + } + + for (int8 cur = 0; cur < cnt; cur++) + if (inventoryGetItem(cur) == item) { + notExist = false; + break; + } + + if (notExist) { + for (int8 i = cnt; i > 0; i--) + inventorySetItem(i, inventoryGetItem(i - 1)); + + inventorySetItem(0, item); + + setStateValue(StateKey_InventoryItem, item); + + inventorySetCount(cnt + 1); + } + } +} + +void ScriptManager::inventoryDrop(int16 item) { + int8 itemCount = inventoryGetCount(); + + // if items in inventory > 0 + if (itemCount != 0) { + int8 index = 0; + + // finding needed item + while (index < itemCount) { + if (inventoryGetItem(index) == item) + break; + + index++; + } + + // if item in the inventory + if (itemCount != index) { + // shift all items left with rewrite founded item + for (int8 v = index; v < itemCount - 1 ; v++) + inventorySetItem(v, inventoryGetItem(v + 1)); + + // del last item + inventorySetItem(itemCount - 1, 0); + inventorySetCount(inventoryGetCount() - 1); + + setStateValue(StateKey_InventoryItem, inventoryGetItem(0)); + } + } +} +void ScriptManager::inventoryCycle() { + int8 itemCount = inventoryGetCount(); + int8 curItem = inventoryGetItem(0); + if (itemCount > 1) { + for (int8 i = 0; i < itemCount - 1; i++) + inventorySetItem(i, inventoryGetItem(i + 1)); + + inventorySetItem(itemCount - 1, curItem); + + setStateValue(StateKey_InventoryItem, inventoryGetItem(0)); + + } +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/puzzle.h b/engines/zvision/scripting/puzzle.h index ee9ce521c9..4123880835 100644 --- a/engines/zvision/scripting/puzzle.h +++ b/engines/zvision/scripting/puzzle.h @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -28,7 +28,6 @@ #include "common/list.h" #include "common/ptr.h" - namespace ZVision { struct Puzzle { @@ -63,10 +62,17 @@ struct Puzzle { bool argumentIsAKey; }; + enum StateFlags { + ONCE_PER_INST = 0x01, + DISABLED = 0x02, + DO_ME_NOW = 0x04 + }; + uint32 key; Common::List<Common::List <CriteriaEntry> > criteriaList; // This has to be list of pointers because ResultAction is abstract Common::List<ResultAction *> resultActions; + bool addedBySetState; }; } // End of namespace ZVision diff --git a/engines/zvision/scripting/scr_file_handling.cpp b/engines/zvision/scripting/scr_file_handling.cpp index 416bac00f3..f97eed6b75 100644 --- a/engines/zvision/scripting/scr_file_handling.cpp +++ b/engines/zvision/scripting/scr_file_handling.cpp @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -22,6 +22,7 @@ #include "common/scummsys.h" +#include "zvision/zvision.h" #include "zvision/scripting/script_manager.h" #include "zvision/utility/utility.h" @@ -29,22 +30,29 @@ #include "zvision/scripting/actions.h" #include "zvision/scripting/controls/push_toggle_control.h" #include "zvision/scripting/controls/lever_control.h" +#include "zvision/scripting/controls/slot_control.h" +#include "zvision/scripting/controls/save_control.h" +#include "zvision/scripting/controls/input_control.h" +#include "zvision/scripting/controls/safe_control.h" +#include "zvision/scripting/controls/hotmov_control.h" +#include "zvision/scripting/controls/fist_control.h" +#include "zvision/scripting/controls/paint_control.h" +#include "zvision/scripting/controls/titler_control.h" #include "common/textconsole.h" #include "common/file.h" #include "common/tokenizer.h" - namespace ZVision { -void ScriptManager::parseScrFile(const Common::String &fileName, bool isGlobal) { +void ScriptManager::parseScrFile(const Common::String &fileName, ScriptScope &scope) { Common::File file; - if (!file.open(fileName)) { + if (!_engine->getSearchManager()->openFile(file, fileName)) { warning("Script file not found: %s", fileName.c_str()); return; } - while(!file.eos()) { + while (!file.eos()) { Common::String line = file.readLine(); if (file.err()) { warning("Error parsing scr file: %s", fileName.c_str()); @@ -57,18 +65,19 @@ void ScriptManager::parseScrFile(const Common::String &fileName, bool isGlobal) if (line.matchString("puzzle:*", true)) { Puzzle *puzzle = new Puzzle(); - sscanf(line.c_str(),"puzzle:%u",&(puzzle->key)); - + sscanf(line.c_str(), "puzzle:%u", &(puzzle->key)); + if (getStateFlag(puzzle->key) & Puzzle::ONCE_PER_INST) + setStateValue(puzzle->key, 0); parsePuzzle(puzzle, file); - if (isGlobal) { - _globalPuzzles.push_back(puzzle); - } else { - _activePuzzles.push_back(puzzle); - } + scope.puzzles.push_back(puzzle); + } else if (line.matchString("control:*", true)) { - parseControl(line, file); + Control *ctrl = parseControl(line, file); + if (ctrl) + scope.controls.push_back(ctrl); } } + scope.procCount = 0; } void ScriptManager::parsePuzzle(Puzzle *puzzle, Common::SeekableReadStream &stream) { @@ -81,12 +90,14 @@ void ScriptManager::parsePuzzle(Puzzle *puzzle, Common::SeekableReadStream &stre } else if (line.matchString("results {", true)) { parseResults(stream, puzzle->resultActions); } else if (line.matchString("flags {", true)) { - setStateFlags(puzzle->key, parseFlags(stream)); + setStateFlag(puzzle->key, parseFlags(stream)); } line = stream.readLine(); trimCommentsAndWhiteSpace(&line); } + + puzzle->addedBySetState = 0; } bool ScriptManager::parseCriteria(Common::SeekableReadStream &stream, Common::List<Common::List<Puzzle::CriteriaEntry> > &criteriaList) const { @@ -148,103 +159,148 @@ void ScriptManager::parseResults(Common::SeekableReadStream &stream, Common::Lis // Loop until we find the closing brace Common::String line = stream.readLine(); trimCommentsAndWhiteSpace(&line); + line.toLowercase(); // TODO: Re-order the if-then statements in order of highest occurrence while (!stream.eos() && !line.contains('}')) { if (line.empty()) { line = stream.readLine(); trimCommentsAndWhiteSpace(&line); - + line.toLowercase(); continue; } - // Parse for the action type - if (line.matchString("*:add*", true)) { - actionList.push_back(new ActionAdd(line)); - } else if (line.matchString("*:animplay*", true)) { - actionList.push_back(new ActionPlayAnimation(line)); - } else if (line.matchString("*:animpreload*", true)) { - actionList.push_back(new ActionPreloadAnimation(line)); - } else if (line.matchString("*:animunload*", true)) { - //actionList.push_back(new ActionUnloadAnimation(line)); - } else if (line.matchString("*:attenuate*", true)) { - // TODO: Implement ActionAttenuate - } else if (line.matchString("*:assign*", true)) { - actionList.push_back(new ActionAssign(line)); - } else if (line.matchString("*:change_location*", true)) { - actionList.push_back(new ActionChangeLocation(line)); - } else if (line.matchString("*:crossfade*", true)) { - // TODO: Implement ActionCrossfade - } else if (line.matchString("*:debug*", true)) { - // TODO: Implement ActionDebug - } else if (line.matchString("*:delay_render*", true)) { - // TODO: Implement ActionDelayRender - } else if (line.matchString("*:disable_control*", true)) { - actionList.push_back(new ActionDisableControl(line)); - } else if (line.matchString("*:disable_venus*", true)) { - // TODO: Implement ActionDisableVenus - } else if (line.matchString("*:display_message*", true)) { - // TODO: Implement ActionDisplayMessage - } else if (line.matchString("*:dissolve*", true)) { - // TODO: Implement ActionDissolve - } else if (line.matchString("*:distort*", true)) { - // TODO: Implement ActionDistort - } else if (line.matchString("*:enable_control*", true)) { - actionList.push_back(new ActionEnableControl(line)); - } else if (line.matchString("*:flush_mouse_events*", true)) { - // TODO: Implement ActionFlushMouseEvents - } else if (line.matchString("*:inventory*", true)) { - // TODO: Implement ActionInventory - } else if (line.matchString("*:kill*", true)) { - // TODO: Implement ActionKill - } else if (line.matchString("*:menu_bar_enable*", true)) { - // TODO: Implement ActionMenuBarEnable - } else if (line.matchString("*:music*", true)) { - actionList.push_back(new ActionMusic(line)); - } else if (line.matchString("*:pan_track*", true)) { - // TODO: Implement ActionPanTrack - } else if (line.matchString("*:playpreload*", true)) { - actionList.push_back(new ActionPlayPreloadAnimation(line)); - } else if (line.matchString("*:preferences*", true)) { - // TODO: Implement ActionPreferences - } else if (line.matchString("*:quit*", true)) { - actionList.push_back(new ActionQuit()); - } else if (line.matchString("*:random*", true)) { - actionList.push_back(new ActionRandom(line)); - } else if (line.matchString("*:region*", true)) { - // TODO: Implement ActionRegion - } else if (line.matchString("*:restore_game*", true)) { - // TODO: Implement ActionRestoreGame - } else if (line.matchString("*:rotate_to*", true)) { - // TODO: Implement ActionRotateTo - } else if (line.matchString("*:save_game*", true)) { - // TODO: Implement ActionSaveGame - } else if (line.matchString("*:set_partial_screen*", true)) { - actionList.push_back(new ActionSetPartialScreen(line)); - } else if (line.matchString("*:set_screen*", true)) { - actionList.push_back(new ActionSetScreen(line)); - } else if (line.matchString("*:set_venus*", true)) { - // TODO: Implement ActionSetVenus - } else if (line.matchString("*:stop*", true)) { - // TODO: Implement ActionStop - } else if (line.matchString("*:streamvideo*", true)) { - actionList.push_back(new ActionStreamVideo(line)); - } else if (line.matchString("*:syncsound*", true)) { - // TODO: Implement ActionSyncSound - } else if (line.matchString("*:timer*", true)) { - actionList.push_back(new ActionTimer(line)); - } else if (line.matchString("*:ttytext*", true)) { - // TODO: Implement ActionTTYText - } else if (line.matchString("*:universe_music*", true)) { - // TODO: Implement ActionUniverseMusic - } else if (line.matchString("*:copy_file*", true)) { - // Not used. Purposely left empty - } else { - warning("Unhandled result action type: %s", line.c_str()); + const char *chrs = line.c_str(); + uint pos; + for (pos = 0; pos < line.size(); pos++) + if (chrs[pos] == ':') + break; + + if (pos < line.size()) { + + uint startpos = pos + 1; + + for (pos = startpos; pos < line.size(); pos++) + if (chrs[pos] == ':' || chrs[pos] == '(') + break; + + if (pos < line.size()) { + int32 slot = 11; + Common::String args = ""; + Common::String act(chrs + startpos, chrs + pos); + + startpos = pos + 1; + + if (chrs[pos] == ':') { + for (pos = startpos; pos < line.size(); pos++) + if (chrs[pos] == '(') + break; + Common::String strSlot(chrs + startpos, chrs + pos); + slot = atoi(strSlot.c_str()); + + startpos = pos + 1; + } + + if (pos < line.size()) { + for (pos = startpos; pos < line.size(); pos++) + if (chrs[pos] == ')') + break; + + args = Common::String(chrs + startpos, chrs + pos); + } + + // Parse for the action type + if (act.matchString("add", true)) { + actionList.push_back(new ActionAdd(_engine, slot, args)); + } else if (act.matchString("animplay", true)) { + actionList.push_back(new ActionPlayAnimation(_engine, slot, args)); + } else if (act.matchString("animpreload", true)) { + actionList.push_back(new ActionPreloadAnimation(_engine, slot, args)); + } else if (act.matchString("animunload", true)) { + actionList.push_back(new ActionUnloadAnimation(_engine, slot, args)); + } else if (act.matchString("attenuate", true)) { + actionList.push_back(new ActionAttenuate(_engine, slot, args)); + } else if (act.matchString("assign", true)) { + actionList.push_back(new ActionAssign(_engine, slot, args)); + } else if (act.matchString("change_location", true)) { + actionList.push_back(new ActionChangeLocation(_engine, slot, args)); + } else if (act.matchString("crossfade", true)) { + actionList.push_back(new ActionCrossfade(_engine, slot, args)); + } else if (act.matchString("cursor", true)) { + actionList.push_back(new ActionCursor(_engine, slot, args)); + } else if (act.matchString("debug", true)) { + // Not used. Purposely left empty + } else if (act.matchString("delay_render", true)) { + actionList.push_back(new ActionDelayRender(_engine, slot, args)); + } else if (act.matchString("disable_control", true)) { + actionList.push_back(new ActionDisableControl(_engine, slot, args)); + } else if (act.matchString("disable_venus", true)) { + actionList.push_back(new ActionDisableVenus(_engine, slot, args)); + } else if (act.matchString("display_message", true)) { + actionList.push_back(new ActionDisplayMessage(_engine, slot, args)); + } else if (act.matchString("dissolve", true)) { + actionList.push_back(new ActionDissolve(_engine)); + } else if (act.matchString("distort", true)) { + actionList.push_back(new ActionDistort(_engine, slot, args)); + } else if (act.matchString("enable_control", true)) { + actionList.push_back(new ActionEnableControl(_engine, slot, args)); + } else if (act.matchString("flush_mouse_events", true)) { + actionList.push_back(new ActionFlushMouseEvents(_engine, slot)); + } else if (act.matchString("inventory", true)) { + actionList.push_back(new ActionInventory(_engine, slot, args)); + } else if (act.matchString("kill", true)) { + actionList.push_back(new ActionKill(_engine, slot, args)); + } else if (act.matchString("menu_bar_enable", true)) { + actionList.push_back(new ActionMenuBarEnable(_engine, slot, args)); + } else if (act.matchString("music", true)) { + actionList.push_back(new ActionMusic(_engine, slot, args, false)); + } else if (act.matchString("pan_track", true)) { + actionList.push_back(new ActionPanTrack(_engine, slot, args)); + } else if (act.matchString("playpreload", true)) { + actionList.push_back(new ActionPlayPreloadAnimation(_engine, slot, args)); + } else if (act.matchString("preferences", true)) { + actionList.push_back(new ActionPreferences(_engine, slot, args)); + } else if (act.matchString("quit", true)) { + actionList.push_back(new ActionQuit(_engine, slot)); + } else if (act.matchString("random", true)) { + actionList.push_back(new ActionRandom(_engine, slot, args)); + } else if (act.matchString("region", true)) { + actionList.push_back(new ActionRegion(_engine, slot, args)); + } else if (act.matchString("restore_game", true)) { + actionList.push_back(new ActionRestoreGame(_engine, slot, args)); + } else if (act.matchString("rotate_to", true)) { + actionList.push_back(new ActionRotateTo(_engine, slot, args)); + } else if (act.matchString("save_game", true)) { + // Not used. Purposely left empty + } else if (act.matchString("set_partial_screen", true)) { + actionList.push_back(new ActionSetPartialScreen(_engine, slot, args)); + } else if (act.matchString("set_screen", true)) { + actionList.push_back(new ActionSetScreen(_engine, slot, args)); + } else if (act.matchString("set_venus", true)) { + actionList.push_back(new ActionSetVenus(_engine, slot, args)); + } else if (act.matchString("stop", true)) { + actionList.push_back(new ActionStop(_engine, slot, args)); + } else if (act.matchString("streamvideo", true)) { + actionList.push_back(new ActionStreamVideo(_engine, slot, args)); + } else if (act.matchString("syncsound", true)) { + actionList.push_back(new ActionSyncSound(_engine, slot, args)); + } else if (act.matchString("timer", true)) { + actionList.push_back(new ActionTimer(_engine, slot, args)); + } else if (act.matchString("ttytext", true)) { + actionList.push_back(new ActionTtyText(_engine, slot, args)); + } else if (act.matchString("universe_music", true)) { + actionList.push_back(new ActionMusic(_engine, slot, args, true)); + } else if (act.matchString("copy_file", true)) { + // Not used. Purposely left empty + } else { + warning("Unhandled result action type: %s", line.c_str()); + } + } } line = stream.readLine(); trimCommentsAndWhiteSpace(&line); + line.toLowercase(); } return; @@ -259,11 +315,11 @@ uint ScriptManager::parseFlags(Common::SeekableReadStream &stream) const { while (!stream.eos() && !line.contains('}')) { if (line.matchString("ONCE_PER_INST", true)) { - flags |= ONCE_PER_INST; + flags |= Puzzle::ONCE_PER_INST; } else if (line.matchString("DO_ME_NOW", true)) { - flags |= DO_ME_NOW; + flags |= Puzzle::DO_ME_NOW; } else if (line.matchString("DISABLED", true)) { - flags |= DISABLED; + flags |= Puzzle::DISABLED; } line = stream.readLine(); @@ -273,7 +329,7 @@ uint ScriptManager::parseFlags(Common::SeekableReadStream &stream) const { return flags; } -void ScriptManager::parseControl(Common::String &line, Common::SeekableReadStream &stream) { +Control *ScriptManager::parseControl(Common::String &line, Common::SeekableReadStream &stream) { uint32 key; char controlTypeBuffer[20]; @@ -282,21 +338,36 @@ void ScriptManager::parseControl(Common::String &line, Common::SeekableReadStrea Common::String controlType(controlTypeBuffer); if (controlType.equalsIgnoreCase("push_toggle")) { - _activeControls.push_back(new PushToggleControl(_engine, key, stream)); - return; + return new PushToggleControl(_engine, key, stream); } else if (controlType.equalsIgnoreCase("flat")) { Control::parseFlatControl(_engine); - return; + return NULL; } else if (controlType.equalsIgnoreCase("pana")) { Control::parsePanoramaControl(_engine, stream); - return; + return NULL; } else if (controlType.equalsIgnoreCase("tilt")) { Control::parseTiltControl(_engine, stream); - return; + return NULL; } else if (controlType.equalsIgnoreCase("lever")) { - _activeControls.push_back(new LeverControl(_engine, key, stream)); - return; + return new LeverControl(_engine, key, stream); + } else if (controlType.equalsIgnoreCase("slot")) { + return new SlotControl(_engine, key, stream); + } else if (controlType.equalsIgnoreCase("input")) { + return new InputControl(_engine, key, stream); + } else if (controlType.equalsIgnoreCase("save")) { + return new SaveControl(_engine, key, stream); + } else if (controlType.equalsIgnoreCase("safe")) { + return new SafeControl(_engine, key, stream); + } else if (controlType.equalsIgnoreCase("hotmovie")) { + return new HotMovControl(_engine, key, stream); + } else if (controlType.equalsIgnoreCase("fist")) { + return new FistControl(_engine, key, stream); + } else if (controlType.equalsIgnoreCase("paint")) { + return new PaintControl(_engine, key, stream); + } else if (controlType.equalsIgnoreCase("titler")) { + return new TitlerControl(_engine, key, stream); } + return NULL; } } // End of namespace ZVision diff --git a/engines/zvision/scripting/script_manager.cpp b/engines/zvision/scripting/script_manager.cpp index da82308051..7904817156 100644 --- a/engines/zvision/scripting/script_manager.cpp +++ b/engines/zvision/scripting/script_manager.cpp @@ -1,24 +1,24 @@ /* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ +* +* ScummVM is the legal property of its developers, whose names +* are too numerous to list here. Please refer to the COPYRIGHT +* file distributed with this source distribution. +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. + +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. + +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +* +*/ #include "common/scummsys.h" @@ -30,168 +30,232 @@ #include "zvision/core/save_manager.h" #include "zvision/scripting/actions.h" #include "zvision/utility/utility.h" +#include "zvision/scripting/sidefx/timer_node.h" #include "common/algorithm.h" #include "common/hashmap.h" #include "common/debug.h" #include "common/stream.h" - namespace ZVision { ScriptManager::ScriptManager(ZVision *engine) : _engine(engine), - _currentlyFocusedControl(0) { + _currentlyFocusedControl(0), + _activeControls(NULL) { } ScriptManager::~ScriptManager() { - for (PuzzleList::iterator iter = _activePuzzles.begin(); iter != _activePuzzles.end(); ++iter) { - delete (*iter); - } - for (PuzzleList::iterator iter = _globalPuzzles.begin(); iter != _globalPuzzles.end(); ++iter) { - delete (*iter); - } - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - delete (*iter); - } + cleanScriptScope(universe); + cleanScriptScope(world); + cleanScriptScope(room); + cleanScriptScope(nodeview); + _controlEvents.clear(); } void ScriptManager::initialize() { - parseScrFile("universe.scr", true); + cleanScriptScope(universe); + cleanScriptScope(world); + cleanScriptScope(room); + cleanScriptScope(nodeview); + + _currentLocation.node = 0; + _currentLocation.world = 0; + _currentLocation.room = 0; + _currentLocation.view = 0; + + parseScrFile("universe.scr", universe); changeLocation('g', 'a', 'r', 'y', 0); + + _controlEvents.clear(); } void ScriptManager::update(uint deltaTimeMillis) { + if (_currentLocation.node != _nextLocation.node || + _currentLocation.room != _nextLocation.room || + _currentLocation.view != _nextLocation.view || + _currentLocation.world != _nextLocation.world) + ChangeLocationReal(); + updateNodes(deltaTimeMillis); - checkPuzzleCriteria(); + if (! execScope(nodeview)) + return; + if (! execScope(room)) + return; + if (! execScope(world)) + return; + if (! execScope(universe)) + return; + updateControls(deltaTimeMillis); } -void ScriptManager::createReferenceTable() { - // Iterate through each local Puzzle - for (PuzzleList::iterator activePuzzleIter = _activePuzzles.begin(); activePuzzleIter != _activePuzzles.end(); ++activePuzzleIter) { - Puzzle *puzzlePtr = (*activePuzzleIter); - - // Iterate through each CriteriaEntry and add a reference from the criteria key to the Puzzle - for (Common::List<Common::List<Puzzle::CriteriaEntry> >::iterator criteriaIter = (*activePuzzleIter)->criteriaList.begin(); criteriaIter != (*activePuzzleIter)->criteriaList.end(); ++criteriaIter) { - for (Common::List<Puzzle::CriteriaEntry>::iterator entryIter = criteriaIter->begin(); entryIter != criteriaIter->end(); ++entryIter) { - _referenceTable[entryIter->key].push_back(puzzlePtr); - - // If the argument is a key, add a reference to it as well - if (entryIter->argumentIsAKey) { - _referenceTable[entryIter->argument].push_back(puzzlePtr); - } - } - } +bool ScriptManager::execScope(ScriptScope &scope) { + // Swap queues + PuzzleList *tmp = scope.execQueue; + scope.execQueue = scope.scopeQueue; + scope.scopeQueue = tmp; + scope.scopeQueue->clear(); + + for (PuzzleList::iterator PuzzleIter = scope.puzzles.begin(); PuzzleIter != scope.puzzles.end(); ++PuzzleIter) + (*PuzzleIter)->addedBySetState = 0; + + if (scope.procCount < 2 || getStateValue(StateKey_ExecScopeStyle)) { + for (PuzzleList::iterator PuzzleIter = scope.puzzles.begin(); PuzzleIter != scope.puzzles.end(); ++PuzzleIter) + if (!checkPuzzleCriteria(*PuzzleIter, scope.procCount)) + return false; + } else { + for (PuzzleList::iterator PuzzleIter = scope.execQueue->begin(); PuzzleIter != scope.execQueue->end(); ++PuzzleIter) + if (!checkPuzzleCriteria(*PuzzleIter, scope.procCount)) + return false; } - // Iterate through each global Puzzle - for (PuzzleList::iterator globalPuzzleIter = _globalPuzzles.begin(); globalPuzzleIter != _globalPuzzles.end(); ++globalPuzzleIter) { - Puzzle *puzzlePtr = (*globalPuzzleIter); + if (scope.procCount < 2) { + scope.procCount++; + } + return true; +} - // Iterate through each CriteriaEntry and add a reference from the criteria key to the Puzzle - for (Common::List<Common::List<Puzzle::CriteriaEntry> >::iterator criteriaIter = (*globalPuzzleIter)->criteriaList.begin(); criteriaIter != (*globalPuzzleIter)->criteriaList.end(); ++criteriaIter) { - for (Common::List<Puzzle::CriteriaEntry>::iterator entryIter = criteriaIter->begin(); entryIter != criteriaIter->end(); ++entryIter) { - _referenceTable[entryIter->key].push_back(puzzlePtr); - - // If the argument is a key, add a reference to it as well - if (entryIter->argumentIsAKey) { - _referenceTable[entryIter->argument].push_back(puzzlePtr); - } - } - } +void ScriptManager::referenceTableAddPuzzle(uint32 key, PuzzleRef ref) { + if (_referenceTable.contains(key)) { + Common::Array<PuzzleRef> *arr = &_referenceTable[key]; + for (uint32 i = 0; i < arr->size(); i++) + if ((*arr)[i].puz == ref.puz) + return; } - // Remove duplicate entries - for (PuzzleMap::iterator referenceTableIter = _referenceTable.begin(); referenceTableIter != _referenceTable.end(); ++referenceTableIter) { - removeDuplicateEntries(referenceTableIter->_value); + _referenceTable[key].push_back(ref); +} + +void ScriptManager::addPuzzlesToReferenceTable(ScriptScope &scope) { + // Iterate through each local Puzzle + for (PuzzleList::iterator PuzzleIter = scope.puzzles.begin(); PuzzleIter != scope.puzzles.end(); ++PuzzleIter) { + Puzzle *puzzlePtr = (*PuzzleIter); + + PuzzleRef ref; + ref.scope = &scope; + ref.puz = puzzlePtr; + + referenceTableAddPuzzle(puzzlePtr->key, ref); + + // Iterate through each CriteriaEntry and add a reference from the criteria key to the Puzzle + for (Common::List<Common::List<Puzzle::CriteriaEntry> >::iterator criteriaIter = (*PuzzleIter)->criteriaList.begin(); criteriaIter != (*PuzzleIter)->criteriaList.end(); ++criteriaIter) + for (Common::List<Puzzle::CriteriaEntry>::iterator entryIter = criteriaIter->begin(); entryIter != criteriaIter->end(); ++entryIter) + referenceTableAddPuzzle(entryIter->key, ref); } } void ScriptManager::updateNodes(uint deltaTimeMillis) { // If process() returns true, it means the node can be deleted - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end();) { + for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end();) { if ((*iter)->process(deltaTimeMillis)) { - delete (*iter); + delete(*iter); // Remove the node - iter = _activeControls.erase(iter); + iter = _activeSideFx.erase(iter); } else { ++iter; } } } -void ScriptManager::checkPuzzleCriteria() { - while (!_puzzlesToCheck.empty()) { - Puzzle *puzzle = _puzzlesToCheck.pop(); - - // Check if the puzzle is already finished - // Also check that the puzzle isn't disabled - if (getStateValue(puzzle->key) == 1 && (getStateFlags(puzzle->key) & DISABLED) == 0) { - continue; +void ScriptManager::updateControls(uint deltaTimeMillis) { + if (!_activeControls) + return; + + // Process only one event + if (!_controlEvents.empty()) { + Common::Event _event = _controlEvents.front(); + Common::Point imageCoord; + switch (_event.type) { + case Common::EVENT_LBUTTONDOWN: + imageCoord = _engine->getRenderManager()->screenSpaceToImageSpace(_event.mouse); + onMouseDown(_event.mouse, imageCoord); + break; + case Common::EVENT_LBUTTONUP: + imageCoord = _engine->getRenderManager()->screenSpaceToImageSpace(_event.mouse); + onMouseUp(_event.mouse, imageCoord); + break; + case Common::EVENT_KEYDOWN: + onKeyDown(_event.kbd); + break; + case Common::EVENT_KEYUP: + onKeyUp(_event.kbd); + break; + default: + break; } + _controlEvents.pop_front(); + } - // Check each Criteria - - bool criteriaMet = false; - for (Common::List<Common::List<Puzzle::CriteriaEntry> >::iterator criteriaIter = puzzle->criteriaList.begin(); criteriaIter != puzzle->criteriaList.end(); ++criteriaIter) { - criteriaMet = false; - - for (Common::List<Puzzle::CriteriaEntry>::iterator entryIter = criteriaIter->begin(); entryIter != criteriaIter->end(); ++entryIter) { - // Get the value to compare against - uint argumentValue; - if (entryIter->argumentIsAKey) - argumentValue = getStateValue(entryIter->argument); - else - argumentValue = entryIter->argument; - - // Do the comparison - switch (entryIter->criteriaOperator) { - case Puzzle::EQUAL_TO: - criteriaMet = getStateValue(entryIter->key) == argumentValue; - break; - case Puzzle::NOT_EQUAL_TO: - criteriaMet = getStateValue(entryIter->key) != argumentValue; - break; - case Puzzle::GREATER_THAN: - criteriaMet = getStateValue(entryIter->key) > argumentValue; - break; - case Puzzle::LESS_THAN: - criteriaMet = getStateValue(entryIter->key) < argumentValue; - break; - } - - // If one check returns false, don't keep checking - if (!criteriaMet) { - break; - } + for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); iter++) + if ((*iter)->process(deltaTimeMillis)) + break; +} + +bool ScriptManager::checkPuzzleCriteria(Puzzle *puzzle, uint counter) { + // Check if the puzzle is already finished + // Also check that the puzzle isn't disabled + if (getStateValue(puzzle->key) == 1 || (getStateFlag(puzzle->key) & Puzzle::DISABLED) == Puzzle::DISABLED) { + return true; + } + + // Check each Criteria + if (counter == 0 && (getStateFlag(puzzle->key) & Puzzle::DO_ME_NOW) == 0) + return true; + + bool criteriaMet = false; + for (Common::List<Common::List<Puzzle::CriteriaEntry> >::iterator criteriaIter = puzzle->criteriaList.begin(); criteriaIter != puzzle->criteriaList.end(); ++criteriaIter) { + criteriaMet = false; + + for (Common::List<Puzzle::CriteriaEntry>::iterator entryIter = criteriaIter->begin(); entryIter != criteriaIter->end(); ++entryIter) { + // Get the value to compare against + int argumentValue; + if (entryIter->argumentIsAKey) + argumentValue = getStateValue(entryIter->argument); + else + argumentValue = entryIter->argument; + + // Do the comparison + switch (entryIter->criteriaOperator) { + case Puzzle::EQUAL_TO: + criteriaMet = getStateValue(entryIter->key) == argumentValue; + break; + case Puzzle::NOT_EQUAL_TO: + criteriaMet = getStateValue(entryIter->key) != argumentValue; + break; + case Puzzle::GREATER_THAN: + criteriaMet = getStateValue(entryIter->key) > argumentValue; + break; + case Puzzle::LESS_THAN: + criteriaMet = getStateValue(entryIter->key) < argumentValue; + break; } - // If any of the Criteria are *fully* met, then execute the results - if (criteriaMet) { + // If one check returns false, don't keep checking + if (!criteriaMet) { break; } } - // criteriaList can be empty. Aka, the puzzle should be executed immediately - if (puzzle->criteriaList.empty() || criteriaMet) { - debug(1, "Puzzle %u criteria passed. Executing its ResultActions", puzzle->key); + // If any of the Criteria are *fully* met, then execute the results + if (criteriaMet) { + break; + } + } - // Set the puzzle as completed - setStateValue(puzzle->key, 1); + // criteriaList can be empty. Aka, the puzzle should be executed immediately + if (puzzle->criteriaList.empty() || criteriaMet) { + debug(1, "Puzzle %u criteria passed. Executing its ResultActions", puzzle->key); - bool shouldContinue = true; - for (Common::List<ResultAction *>::iterator resultIter = puzzle->resultActions.begin(); resultIter != puzzle->resultActions.end(); ++resultIter) { - shouldContinue = shouldContinue && (*resultIter)->execute(_engine); - if (!shouldContinue) { - break; - } - } + // Set the puzzle as completed + setStateValue(puzzle->key, 1); - if (!shouldContinue) { - break; - } + for (Common::List<ResultAction *>::iterator resultIter = puzzle->resultActions.begin(); resultIter != puzzle->resultActions.end(); ++resultIter) { + if (!(*resultIter)->execute()) + return false; } } + + return true; } void ScriptManager::cleanStateTable() { @@ -205,60 +269,102 @@ void ScriptManager::cleanStateTable() { } } -uint ScriptManager::getStateValue(uint32 key) { +void ScriptManager::cleanScriptScope(ScriptScope &scope) { + scope.privQueueOne.clear(); + scope.privQueueTwo.clear(); + scope.scopeQueue = &scope.privQueueOne; + scope.execQueue = &scope.privQueueTwo; + for (PuzzleList::iterator iter = scope.puzzles.begin(); iter != scope.puzzles.end(); ++iter) + delete(*iter); + + scope.puzzles.clear(); + + for (ControlList::iterator iter = scope.controls.begin(); iter != scope.controls.end(); ++iter) + delete(*iter); + + scope.controls.clear(); + + scope.procCount = 0; +} + +int ScriptManager::getStateValue(uint32 key) { if (_globalState.contains(key)) return _globalState[key]; else return 0; } -void ScriptManager::setStateValue(uint32 key, uint value) { - _globalState[key] = value; - +void ScriptManager::queuePuzzles(uint32 key) { if (_referenceTable.contains(key)) { - for (Common::Array<Puzzle *>::iterator iter = _referenceTable[key].begin(); iter != _referenceTable[key].end(); ++iter) { - _puzzlesToCheck.push((*iter)); - } + Common::Array<PuzzleRef> *arr = &_referenceTable[key]; + for (int32 i = arr->size() - 1; i >= 0; i--) + if (!(*arr)[i].puz->addedBySetState) { + (*arr)[i].scope->scopeQueue->push_back((*arr)[i].puz); + (*arr)[i].puz->addedBySetState = true; + } } } -uint ScriptManager::getStateFlags(uint32 key) { +void ScriptManager::setStateValue(uint32 key, int value) { + if (value == 0) + _globalState.erase(key); + else + _globalState[key] = value; + + queuePuzzles(key); +} + +void ScriptManager::setStateValueSilent(uint32 key, int value) { + if (value == 0) + _globalState.erase(key); + else + _globalState[key] = value; +} + +uint ScriptManager::getStateFlag(uint32 key) { if (_globalStateFlags.contains(key)) return _globalStateFlags[key]; else return 0; } -void ScriptManager::setStateFlags(uint32 key, uint flags) { - _globalStateFlags[key] = flags; +void ScriptManager::setStateFlag(uint32 key, uint value) { + queuePuzzles(key); - if (_referenceTable.contains(key)) { - for (Common::Array<Puzzle *>::iterator iter = _referenceTable[key].begin(); iter != _referenceTable[key].end(); ++iter) { - _puzzlesToCheck.push((*iter)); - } - } + _globalStateFlags[key] |= value; } -void ScriptManager::addToStateValue(uint32 key, uint valueToAdd) { - _globalState[key] += valueToAdd; +void ScriptManager::setStateFlagSilent(uint32 key, uint value) { + if (value == 0) + _globalStateFlags.erase(key); + else + _globalStateFlags[key] = value; } -void ScriptManager::addControl(Control *control) { - _activeControls.push_back(control); -} +void ScriptManager::unsetStateFlag(uint32 key, uint value) { + queuePuzzles(key); -Control *ScriptManager::getControl(uint32 key) { - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - if ((*iter)->getKey() == key) { - return (*iter); - } + if (_globalStateFlags.contains(key)) { + _globalStateFlags[key] &= ~value; + + if (_globalStateFlags[key] == 0) + _globalStateFlags.erase(key); } +} +Control *ScriptManager::getControl(uint32 key) { + for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) + if ((*iter)->getKey() == key) + return *iter; return nullptr; } void ScriptManager::focusControl(uint32 key) { - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { + if (!_activeControls) + return; + if (_currentlyFocusedControl == key) + return; + for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) { uint32 controlKey = (*iter)->getKey(); if (controlKey == key) { @@ -271,167 +377,372 @@ void ScriptManager::focusControl(uint32 key) { _currentlyFocusedControl = key; } +void ScriptManager::setFocusControlKey(uint32 key) { + _currentlyFocusedControl = key; +} + +void ScriptManager::addSideFX(SideFX *fx) { + _activeSideFx.push_back(fx); +} + +SideFX *ScriptManager::getSideFX(uint32 key) { + for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter) { + if ((*iter)->getKey() == key) { + return (*iter); + } + } + + return nullptr; +} + +void ScriptManager::deleteSideFx(uint32 key) { + for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter) { + if ((*iter)->getKey() == key) { + delete(*iter); + _activeSideFx.erase(iter); + break; + } + } +} + +void ScriptManager::stopSideFx(uint32 key) { + for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter) { + if ((*iter)->getKey() == key) { + bool ret = (*iter)->stop(); + if (ret) { + delete(*iter); + _activeSideFx.erase(iter); + } + break; + } + } +} + +void ScriptManager::killSideFx(uint32 key) { + for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter) { + if ((*iter)->getKey() == key) { + (*iter)->kill(); + delete(*iter); + _activeSideFx.erase(iter); + break; + } + } +} + +void ScriptManager::killSideFxType(SideFX::SideFXType type) { + for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end();) { + if ((*iter)->getType() & type) { + (*iter)->kill(); + delete(*iter); + iter = _activeSideFx.erase(iter); + } else { + ++iter; + } + } +} + void ScriptManager::onMouseDown(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - (*iter)->onMouseDown(screenSpacePos, backgroundImageSpacePos); + if (!_activeControls) + return; + for (ControlList::iterator iter = _activeControls->reverse_begin(); iter != _activeControls->end(); iter--) { + if ((*iter)->onMouseDown(screenSpacePos, backgroundImageSpacePos)) + return; } } void ScriptManager::onMouseUp(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - (*iter)->onMouseUp(screenSpacePos, backgroundImageSpacePos); + if (!_activeControls) + return; + for (ControlList::iterator iter = _activeControls->reverse_begin(); iter != _activeControls->end(); iter--) { + if ((*iter)->onMouseUp(screenSpacePos, backgroundImageSpacePos)) + return; } } bool ScriptManager::onMouseMove(const Common::Point &screenSpacePos, const Common::Point &backgroundImageSpacePos) { - bool cursorWasChanged = false; - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - cursorWasChanged = cursorWasChanged || (*iter)->onMouseMove(screenSpacePos, backgroundImageSpacePos); + if (!_activeControls) + return false; + + for (ControlList::iterator iter = _activeControls->reverse_begin(); iter != _activeControls->end(); iter--) { + if ((*iter)->onMouseMove(screenSpacePos, backgroundImageSpacePos)) + return true; } - return cursorWasChanged; + return false; } void ScriptManager::onKeyDown(Common::KeyState keyState) { - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - (*iter)->onKeyDown(keyState); + if (!_activeControls) + return; + for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) { + if ((*iter)->onKeyDown(keyState)) + return; } } void ScriptManager::onKeyUp(Common::KeyState keyState) { - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - (*iter)->onKeyUp(keyState); + if (!_activeControls) + return; + for (ControlList::iterator iter = _activeControls->begin(); iter != _activeControls->end(); ++iter) { + if ((*iter)->onKeyUp(keyState)) + return; } } -void ScriptManager::changeLocation(char world, char room, char node, char view, uint32 offset) { - assert(world != 0); - debug(1, "Changing location to: %c %c %c %c %u", world, room, node, view, offset); +void ScriptManager::changeLocation(const Location &_newLocation) { + changeLocation(_newLocation.world, _newLocation.room, _newLocation.node, _newLocation.view, _newLocation.offset); +} - // Auto save - _engine->getSaveManager()->autoSave(); +void ScriptManager::changeLocation(char _world, char _room, char _node, char _view, uint32 offset) { + _nextLocation.world = _world; + _nextLocation.room = _room; + _nextLocation.node = _node; + _nextLocation.view = _view; + _nextLocation.offset = offset; + // If next location 0000 - it's indicate to go to previous location. + if (_nextLocation.world == '0' && _nextLocation.room == '0' && _nextLocation.node == '0' && _nextLocation.view == '0') { + if (getStateValue(StateKey_World) != 'g' || getStateValue(StateKey_Room) != 'j') { + _nextLocation.world = getStateValue(StateKey_LastWorld); + _nextLocation.room = getStateValue(StateKey_LastRoom); + _nextLocation.node = getStateValue(StateKey_LastNode); + _nextLocation.view = getStateValue(StateKey_LastView); + _nextLocation.offset = getStateValue(StateKey_LastViewPos); + } else { + _nextLocation.world = getStateValue(StateKey_Menu_LastWorld); + _nextLocation.room = getStateValue(StateKey_Menu_LastRoom); + _nextLocation.node = getStateValue(StateKey_Menu_LastNode); + _nextLocation.view = getStateValue(StateKey_Menu_LastView); + _nextLocation.offset = getStateValue(StateKey_Menu_LastViewPos); + } + } +} - // Clear all the containers - _referenceTable.clear(); - _puzzlesToCheck.clear(); - for (PuzzleList::iterator iter = _activePuzzles.begin(); iter != _activePuzzles.end(); ++iter) { - delete (*iter); +void ScriptManager::ChangeLocationReal() { + assert(_nextLocation.world != 0); + debug(1, "Changing location to: %c %c %c %c %u", _nextLocation.world, _nextLocation.room, _nextLocation.node, _nextLocation.view, _nextLocation.offset); + + _engine->setRenderDelay(2); + + if (getStateValue(StateKey_World) != 'g' || getStateValue(StateKey_Room) != 'j') { + if (_nextLocation.world != 'g' || _nextLocation.room != 'j') { + setStateValue(StateKey_LastWorld, getStateValue(StateKey_World)); + setStateValue(StateKey_LastRoom, getStateValue(StateKey_Room)); + setStateValue(StateKey_LastNode, getStateValue(StateKey_Node)); + setStateValue(StateKey_LastView, getStateValue(StateKey_View)); + setStateValue(StateKey_LastViewPos, getStateValue(StateKey_ViewPos)); + } else { + setStateValue(StateKey_Menu_LastWorld, getStateValue(StateKey_World)); + setStateValue(StateKey_Menu_LastRoom, getStateValue(StateKey_Room)); + setStateValue(StateKey_Menu_LastNode, getStateValue(StateKey_Node)); + setStateValue(StateKey_Menu_LastView, getStateValue(StateKey_View)); + setStateValue(StateKey_Menu_LastViewPos, getStateValue(StateKey_ViewPos)); + } } - _activePuzzles.clear(); - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - delete (*iter); + + if (_nextLocation.world == 'g' && _nextLocation.room == 'j') { + if (_nextLocation.node == 's' && _nextLocation.view == 'e' && + _currentLocation.world != 'g' && _currentLocation.room != 'j') + _engine->getSaveManager()->prepareSaveBuffer(); + } else { + if (_currentLocation.world == 'g' && _currentLocation.room == 'j') + _engine->getSaveManager()->flushSaveBuffer(); + else { + // Auto save + //_engine->getSaveManager()->autoSave(); + } } - _activeControls.clear(); - // Revert to the idle cursor - _engine->getCursorManager()->revertToIdle(); + setStateValue(StateKey_World, _nextLocation.world); + setStateValue(StateKey_Room, _nextLocation.room); + setStateValue(StateKey_Node, _nextLocation.node); + setStateValue(StateKey_View, _nextLocation.view); + setStateValue(StateKey_ViewPos, _nextLocation.offset); - // Reset the background velocity - _engine->getRenderManager()->setBackgroundVelocity(0); + _referenceTable.clear(); + addPuzzlesToReferenceTable(universe); - // Remove any alphaEntries - _engine->getRenderManager()->clearAlphaEntries(); + _engine->menuBarEnable(0xFFFF); - // Clean the global state table - cleanStateTable(); + if (_nextLocation.world != _currentLocation.world) { + cleanScriptScope(nodeview); + cleanScriptScope(room); + cleanScriptScope(world); - // Parse into puzzles and controls - Common::String fileName = Common::String::format("%c%c%c%c.scr", world, room, node, view); - parseScrFile(fileName); + Common::String fileName = Common::String::format("%c%c%c%c.scr", _nextLocation.world, _nextLocation.room, _nextLocation.node, _nextLocation.view); + parseScrFile(fileName, nodeview); + addPuzzlesToReferenceTable(nodeview); - // Change the background position - _engine->getRenderManager()->setBackgroundPosition(offset); + fileName = Common::String::format("%c%c.scr", _nextLocation.world, _nextLocation.room); + parseScrFile(fileName, room); + addPuzzlesToReferenceTable(room); - // Enable all the controls - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - (*iter)->enable(); - } + fileName = Common::String::format("%c.scr", _nextLocation.world); + parseScrFile(fileName, world); + addPuzzlesToReferenceTable(world); + } else if (_nextLocation.room != _currentLocation.room) { + cleanScriptScope(nodeview); + cleanScriptScope(room); - // Add all the local puzzles to the queue to be checked - for (PuzzleList::iterator iter = _activePuzzles.begin(); iter != _activePuzzles.end(); ++iter) { - // Reset any Puzzles that have the flag ONCE_PER_INST - if ((getStateFlags((*iter)->key) & ONCE_PER_INST) == ONCE_PER_INST) { - setStateValue((*iter)->key, 0); - } + addPuzzlesToReferenceTable(world); - _puzzlesToCheck.push((*iter)); - } + Common::String fileName = Common::String::format("%c%c%c%c.scr", _nextLocation.world, _nextLocation.room, _nextLocation.node, _nextLocation.view); + parseScrFile(fileName, nodeview); + addPuzzlesToReferenceTable(nodeview); - // Add all the global puzzles to the queue to be checked - for (PuzzleList::iterator iter = _globalPuzzles.begin(); iter != _globalPuzzles.end(); ++iter) { - // Reset any Puzzles that have the flag ONCE_PER_INST - if ((getStateFlags((*iter)->key) & ONCE_PER_INST) == ONCE_PER_INST) { - setStateValue((*iter)->key, 0); - } + fileName = Common::String::format("%c%c.scr", _nextLocation.world, _nextLocation.room); + parseScrFile(fileName, room); + addPuzzlesToReferenceTable(room); - _puzzlesToCheck.push((*iter)); + } else if (_nextLocation.node != _currentLocation.node || _nextLocation.view != _currentLocation.view) { + cleanScriptScope(nodeview); + + addPuzzlesToReferenceTable(room); + addPuzzlesToReferenceTable(world); + + Common::String fileName = Common::String::format("%c%c%c%c.scr", _nextLocation.world, _nextLocation.room, _nextLocation.node, _nextLocation.view); + parseScrFile(fileName, nodeview); + addPuzzlesToReferenceTable(nodeview); } - // Create the puzzle reference table - createReferenceTable(); + _activeControls = &nodeview.controls; - // Update _currentLocation - _currentLocation.world = world; - _currentLocation.room = room; - _currentLocation.node = node; - _currentLocation.view = view; - _currentLocation.offset = offset; + // Revert to the idle cursor + _engine->getCursorManager()->changeCursor(CursorIndex_Idle); + + // Change the background position + _engine->getRenderManager()->setBackgroundPosition(_nextLocation.offset); + + if (_currentLocation.world == 0 && _currentLocation.room == 0 && _currentLocation.node == 0 && _currentLocation.view == 0) { + _currentLocation = _nextLocation; + execScope(world); + execScope(room); + execScope(nodeview); + } else if (_nextLocation.world != _currentLocation.world) { + _currentLocation = _nextLocation; + execScope(room); + execScope(nodeview); + } else if (_nextLocation.room != _currentLocation.room) { + _currentLocation = _nextLocation; + execScope(room); + execScope(nodeview); + } else if (_nextLocation.node != _currentLocation.node || _nextLocation.view != _currentLocation.view) { + _currentLocation = _nextLocation; + execScope(nodeview); + } + + _engine->checkBorders(); } -void ScriptManager::serializeStateTable(Common::WriteStream *stream) { - // Write the number of state value entries - stream->writeUint32LE(_globalState.size()); +void ScriptManager::serialize(Common::WriteStream *stream) { + stream->writeUint32BE(MKTAG('Z', 'N', 'S', 'G')); + stream->writeUint32LE(4); + stream->writeUint32LE(0); + stream->writeUint32BE(MKTAG('L', 'O', 'C', ' ')); + stream->writeUint32LE(8); + stream->writeByte(getStateValue(StateKey_World)); + stream->writeByte(getStateValue(StateKey_Room)); + stream->writeByte(getStateValue(StateKey_Node)); + stream->writeByte(getStateValue(StateKey_View)); + stream->writeUint32LE(getStateValue(StateKey_ViewPos)); + + for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); ++iter) + (*iter)->serialize(stream); + + stream->writeUint32BE(MKTAG('F', 'L', 'A', 'G')); - for (StateMap::iterator iter = _globalState.begin(); iter != _globalState.end(); ++iter) { - // Write out the key/value pair - stream->writeUint32LE(iter->_key); - stream->writeUint32LE(iter->_value); - } + int32 slots = 20000; + if (_engine->getGameId() == GID_NEMESIS) + slots = 30000; + + stream->writeUint32LE(slots * 2); + + for (int32 i = 0; i < slots; i++) + stream->writeUint16LE(getStateFlag(i)); + + stream->writeUint32BE(MKTAG('P', 'U', 'Z', 'Z')); + + stream->writeUint32LE(slots * 2); + + for (int32 i = 0; i < slots; i++) + stream->writeSint16LE(getStateValue(i)); } -void ScriptManager::deserializeStateTable(Common::SeekableReadStream *stream) { +void ScriptManager::deserialize(Common::SeekableReadStream *stream) { // Clear out the current table values _globalState.clear(); + _globalStateFlags.clear(); - // Read the number of key/value pairs - uint32 numberOfPairs = stream->readUint32LE(); + cleanScriptScope(nodeview); + cleanScriptScope(room); + cleanScriptScope(world); - for (uint32 i = 0; i < numberOfPairs; ++i) { - uint32 key = stream->readUint32LE(); - uint32 value = stream->readUint32LE(); - // Directly access the state table so we don't trigger Puzzle checks - _globalState[key] = value; - } -} + _currentLocation.node = 0; + _currentLocation.world = 0; + _currentLocation.room = 0; + _currentLocation.view = 0; -void ScriptManager::serializeControls(Common::WriteStream *stream) { - // Count how many controls need to save their data - // Because WriteStream isn't seekable - uint32 numberOfControlsNeedingSerialization = 0; - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - if ((*iter)->needsSerialization()) { - numberOfControlsNeedingSerialization++; - } - } - stream->writeUint32LE(numberOfControlsNeedingSerialization); + for (SideFXList::iterator iter = _activeSideFx.begin(); iter != _activeSideFx.end(); iter++) + delete(*iter); - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - (*iter)->serialize(stream); + _activeSideFx.clear(); + + _referenceTable.clear(); + + if (stream->readUint32BE() != MKTAG('Z', 'N', 'S', 'G') || stream->readUint32LE() != 4) { + changeLocation('g', 'a', 'r', 'y', 0); + return; } -} -void ScriptManager::deserializeControls(Common::SeekableReadStream *stream) { - uint32 numberOfControls = stream->readUint32LE(); + stream->seek(4, SEEK_CUR); - for (uint32 i = 0; i < numberOfControls; ++i) { - uint32 key = stream->readUint32LE(); - for (ControlList::iterator iter = _activeControls.begin(); iter != _activeControls.end(); ++iter) { - if ((*iter)->getKey() == key) { - (*iter)->deserialize(stream); - break; - } + if (stream->readUint32BE() != MKTAG('L', 'O', 'C', ' ') || stream->readUint32LE() != 8) { + changeLocation('g', 'a', 'r', 'y', 0); + return; + } + + Location nextLocation; + + nextLocation.world = stream->readByte(); + nextLocation.room = stream->readByte(); + nextLocation.node = stream->readByte(); + nextLocation.view = stream->readByte(); + nextLocation.offset = stream->readUint32LE() & 0x0000FFFF; + + while (stream->pos() < stream->size()) { + uint32 tag = stream->readUint32BE(); + uint32 tagSize = stream->readUint32LE(); + switch (tag) { + case MKTAG('T', 'I', 'M', 'R'): { + uint32 key = stream->readUint32LE(); + uint32 time = stream->readUint32LE(); + if (_engine->getGameId() == GID_GRANDINQUISITOR) + time /= 100; + else if (_engine->getGameId() == GID_NEMESIS) + time /= 1000; + addSideFX(new TimerNode(_engine, key, time)); + } + break; + case MKTAG('F', 'L', 'A', 'G'): + for (uint32 i = 0; i < tagSize / 2; i++) + setStateFlagSilent(i, stream->readUint16LE()); + break; + case MKTAG('P', 'U', 'Z', 'Z'): + for (uint32 i = 0; i < tagSize / 2; i++) + setStateValueSilent(i, stream->readUint16LE()); + break; + default: + stream->seek(tagSize, SEEK_CUR); } } + + _nextLocation = nextLocation; + + ChangeLocationReal(); + + _engine->setRenderDelay(10); + setStateValue(StateKey_RestoreFlag, 1); + + _engine->loadSettings(); } Location ScriptManager::getCurrentLocation() const { @@ -441,4 +752,64 @@ Location ScriptManager::getCurrentLocation() const { return location; } +Location ScriptManager::getLastLocation() { + Location location; + location.world = getStateValue(StateKey_LastWorld); + location.room = getStateValue(StateKey_LastRoom); + location.node = getStateValue(StateKey_LastNode); + location.view = getStateValue(StateKey_LastView); + location.offset = getStateValue(StateKey_LastViewPos); + + return location; +} + +Location ScriptManager::getLastMenuLocation() { + Location location; + location.world = getStateValue(StateKey_Menu_LastWorld); + location.room = getStateValue(StateKey_Menu_LastRoom); + location.node = getStateValue(StateKey_Menu_LastNode); + location.view = getStateValue(StateKey_Menu_LastView); + location.offset = getStateValue(StateKey_Menu_LastViewPos); + + return location; +} + +void ScriptManager::addEvent(Common::Event event) { + _controlEvents.push_back(event); +} + +void ScriptManager::flushEvent(Common::EventType type) { + EventList::iterator it = _controlEvents.begin(); + while (it != _controlEvents.end()) { + + if ((*it).type == type) + it = _controlEvents.erase(it); + else + it++; + } +} + +ValueSlot::ValueSlot(ScriptManager *scriptManager, const char *slotValue): + _scriptManager(scriptManager) { + value = 0; + slot = false; + const char *isSlot = strstr(slotValue, "["); + if (isSlot) { + slot = true; + value = atoi(isSlot + 1); + } else { + slot = false; + value = atoi(slotValue); + } +} +int16 ValueSlot::getValue() { + if (slot) { + if (value >= 0) + return _scriptManager->getStateValue(value); + else + return 0; + } else + return value; +} + } // End of namespace ZVision diff --git a/engines/zvision/scripting/script_manager.h b/engines/zvision/scripting/script_manager.h index 4d1b1f359b..89b961634b 100644 --- a/engines/zvision/scripting/script_manager.h +++ b/engines/zvision/scripting/script_manager.h @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -25,10 +25,11 @@ #include "zvision/scripting/puzzle.h" #include "zvision/scripting/control.h" +#include "zvision/scripting/sidefx.h" #include "common/hashmap.h" #include "common/queue.h" - +#include "common/events.h" namespace Common { class String; @@ -39,6 +40,63 @@ namespace ZVision { class ZVision; +enum StateKey { + StateKey_World = 3, + StateKey_Room = 4, + StateKey_Node = 5, + StateKey_View = 6, + StateKey_ViewPos = 7, + StateKey_KeyPress = 8, + StateKey_InventoryItem = 9, + StateKey_LMouse = 10, + StateKey_NotSet = 11, // This key doesn't set + StateKey_Rounds = 12, + StateKey_Venus = 13, + StateKey_RMouse = 18, + StateKey_MenuState = 19, + StateKey_RestoreFlag = 20, + StateKey_Quitting = 39, + StateKey_LastWorld = 40, + StateKey_LastRoom = 41, + StateKey_LastNode = 42, + StateKey_LastView = 43, + StateKey_LastViewPos = 44, + StateKey_Menu_LastWorld = 45, + StateKey_Menu_LastRoom = 46, + StateKey_Menu_LastNode = 47, + StateKey_Menu_LastView = 48, + StateKey_Menu_LastViewPos = 49, + StateKey_KbdRotateSpeed = 50, + StateKey_Subtitles = 51, + StateKey_StreamSkipKey = 52, + StateKey_RotateSpeed = 53, + StateKey_Volume = 56, + StateKey_Qsound = 57, + StateKey_VenusEnable = 58, + StateKey_HighQuality = 59, + StateKey_VideoLineSkip = 65, + StateKey_Platform = 66, + StateKey_InstallLevel = 67, + StateKey_CountryCode = 68, + StateKey_CPU = 69, + StateKey_MovieCursor = 70, + StateKey_NoTurnAnim = 71, + StateKey_WIN958 = 72, + StateKey_ShowErrorDlg = 73, + StateKey_DebugCheats = 74, + StateKey_JapanFonts = 75, + StateKey_ExecScopeStyle = 76, + StateKey_Brightness = 77, + StateKey_EF9_R = 91, + StateKey_EF9_G = 92, + StateKey_EF9_B = 93, + StateKey_EF9_Speed = 94, + StateKey_Inv_Cnt_Slot = 100, + StateKey_Inv_1_Slot = 101, + StateKey_Inv_49_Slot = 149, + StateKey_Inv_TotalSlots = 150 +}; + struct Location { Location() : world('g'), room('a'), node('r'), view('y'), offset(0) {} @@ -49,68 +107,99 @@ struct Location { uint32 offset; }; -typedef Common::HashMap<uint32, Common::Array<Puzzle *> > PuzzleMap; typedef Common::List<Puzzle *> PuzzleList; typedef Common::Queue<Puzzle *> PuzzleQueue; typedef Common::List<Control *> ControlList; -typedef Common::HashMap<uint32, uint32> StateMap; -typedef Common::HashMap<uint32, uint> StateFlagMap; +typedef Common::HashMap<uint32, int32> StateMap; +typedef Common::List<SideFX *> SideFXList; +typedef Common::List<Common::Event> EventList; class ScriptManager { public: ScriptManager(ZVision *engine); ~ScriptManager(); -public: - enum StateFlags { - ONCE_PER_INST = 0x01, - DO_ME_NOW = 0x02, // Somewhat useless flag since anything that needs to be done immediately has no criteria - DISABLED = 0x04 - }; - private: ZVision *_engine; + + struct ScriptScope { + uint32 procCount; + + PuzzleList *scopeQueue; // For adding puzzles to queue + PuzzleList *execQueue; // Switch to it when execute + PuzzleList privQueueOne; + PuzzleList privQueueTwo; + + PuzzleList puzzles; + ControlList controls; + }; + + struct PuzzleRef { + Puzzle *puz; + ScriptScope *scope; + }; + + typedef Common::HashMap<uint32, Common::Array<PuzzleRef> > PuzzleMap; + /** * Holds the global state variable. Do NOT directly modify this. Use the accessors and * mutators getStateValue() and setStateValue(). This ensures that Puzzles that reference a * particular state key are checked after the key is modified. */ StateMap _globalState; - /** - * Holds the flags for the global states. This is used to enable/disable puzzles and/or - * controls as well as which puzzles should are allowed to be re-executed - */ - StateFlagMap _globalStateFlags; + /** Holds execute flags */ + StateMap _globalStateFlags; /** References _globalState keys to Puzzles */ PuzzleMap _referenceTable; - /** Holds the Puzzles that should be checked this frame */ - PuzzleQueue _puzzlesToCheck; - /** Holds the currently active puzzles */ - PuzzleList _activePuzzles; - /** Holds the global puzzles */ - PuzzleList _globalPuzzles; /** Holds the currently active controls */ - ControlList _activeControls; + ControlList *_activeControls; + + EventList _controlEvents; + + ScriptScope universe; + ScriptScope world; + ScriptScope room; + ScriptScope nodeview; + + /** Holds the currently active timers, musics, other */ + SideFXList _activeSideFx; Location _currentLocation; + Location _nextLocation; uint32 _currentlyFocusedControl; public: void initialize(); void update(uint deltaTimeMillis); + void queuePuzzles(uint32 key); - uint getStateValue(uint32 key); - void setStateValue(uint32 key, uint value); - void addToStateValue(uint32 key, uint valueToAdd); + int getStateValue(uint32 key); + void setStateValue(uint32 key, int value); - uint getStateFlags(uint32 key); - void setStateFlags(uint32 key, uint flags); + uint getStateFlag(uint32 key); + void setStateFlag(uint32 key, uint value); + void unsetStateFlag(uint32 key, uint value); void addControl(Control *control); Control *getControl(uint32 key); + void enableControl(uint32 key); + void disableControl(uint32 key); + void focusControl(uint32 key); + // Only change focus control without call focus/unfocus. + void setFocusControlKey(uint32 key); + + void addSideFX(SideFX *fx); + SideFX *getSideFX(uint32 key); + void deleteSideFx(uint32 key); + void stopSideFx(uint32 key); + void killSideFx(uint32 key); + void killSideFxType(SideFX::SideFXType type); + + void addEvent(Common::Event); + void flushEvent(Common::EventType type); /** * Called when LeftMouse is pushed. @@ -147,30 +236,51 @@ public: */ void onKeyUp(Common::KeyState keyState); + /** Mark next location */ void changeLocation(char world, char room, char node, char view, uint32 offset); + void changeLocation(const Location &_newLocation); - void serializeStateTable(Common::WriteStream *stream); - void deserializeStateTable(Common::SeekableReadStream *stream); - void serializeControls(Common::WriteStream *stream); - void deserializeControls(Common::SeekableReadStream *stream); + void serialize(Common::WriteStream *stream); + void deserialize(Common::SeekableReadStream *stream); Location getCurrentLocation() const; + Location getLastLocation(); + Location getLastMenuLocation(); private: - void createReferenceTable(); + void referenceTableAddPuzzle(uint32 key, PuzzleRef ref); + void addPuzzlesToReferenceTable(ScriptScope &scope); void updateNodes(uint deltaTimeMillis); - void checkPuzzleCriteria(); + void updateControls(uint deltaTimeMillis); + bool checkPuzzleCriteria(Puzzle *puzzle, uint counter); void cleanStateTable(); + void cleanScriptScope(ScriptScope &scope); + bool execScope(ScriptScope &scope); + + /** Perform change location */ + void ChangeLocationReal(); + + int8 inventoryGetCount(); + void inventorySetCount(int8 cnt); + int16 inventoryGetItem(int8 id); + void inventorySetItem(int8 id, int16 item); + + void setStateFlagSilent(uint32 key, uint value); + void setStateValueSilent(uint32 key, int value); -// TODO: Make this private. It was only made public so Console::cmdParseAllScrFiles() could use it public: + void inventoryAdd(int16 item); + void inventoryDrop(int16 item); + void inventoryCycle(); + + // TODO: Make this private. It was only made public so Console::cmdParseAllScrFiles() could use it /** * Parses a script file into triggers and events * * @param fileName Name of the .scr file * @param isGlobal Are the puzzles included in the file global (true). AKA, the won't be purged during location changes */ - void parseScrFile(const Common::String &fileName, bool isGlobal = false); + void parseScrFile(const Common::String &fileName, ScriptScope &scope); private: /** @@ -216,9 +326,18 @@ private: * @param line The line initially read * @param stream Scr file stream */ - void parseControl(Common::String &line, Common::SeekableReadStream &stream); + Control *parseControl(Common::String &line, Common::SeekableReadStream &stream); }; +class ValueSlot { +public: + ValueSlot(ScriptManager *scriptManager, const char *slotValue); + int16 getValue(); +private: + int16 value; + bool slot; + ScriptManager *_scriptManager; +}; } // End of namespace ZVision diff --git a/engines/zvision/scripting/sidefx.h b/engines/zvision/scripting/sidefx.h new file mode 100644 index 0000000000..5bb14f0cdd --- /dev/null +++ b/engines/zvision/scripting/sidefx.h @@ -0,0 +1,114 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef SIDEFX_H_INCLUDED +#define SIDEFX_H_INCLUDED + +namespace Common { +class SeekableReadStream; +struct Point; +class WriteStream; +} + +namespace ZVision { + +class ZVision; + +class SideFX { +public: + + enum SideFXType { + SIDEFX_ANIM = 1, + SIDEFX_AUDIO = 2, + SIDEFX_DISTORT = 4, + SIDEFX_PANTRACK = 8, + SIDEFX_REGION = 16, + SIDEFX_TIMER = 32, + SIDEFX_TTYTXT = 64, + SIDEFX_UNK = 128, + SIDEFX_ALL = 255 + }; + + SideFX() : _engine(0), _key(0), _type(SIDEFX_UNK) {} + SideFX(ZVision *engine, uint32 key, SideFXType type) : _engine(engine), _key(key), _type(type) {} + virtual ~SideFX() {} + + uint32 getKey() { + return _key; + } + SideFXType getType() { + return _type; + } + + virtual bool process(uint32 deltaTimeInMillis) { + return false; + } + /** + * Serialize a SideFX for save game use. This should only be used if a SideFX needs + * to save values that would be different from initialization. AKA a TimerNode needs to + * store the amount of time left on the timer. Any Controls overriding this *MUST* write + * their key as the first data outputted. The default implementation is NOP. + * + * NOTE: If this method is overridden, you MUST also override deserialize() + * and needsSerialization() + * + * @param stream Stream to write any needed data to + */ + virtual void serialize(Common::WriteStream *stream) {} + /** + * De-serialize data from a save game stream. This should only be implemented if the + * SideFX also implements serialize(). The calling method assumes the size of the + * data read from the stream exactly equals that written in serialize(). The default + * implementation is NOP. + * + * NOTE: If this method is overridden, you MUST also override serialize() + * and needsSerialization() + * + * @param stream Save game file stream + */ + virtual void deserialize(Common::SeekableReadStream *stream) {} + /** + * If a SideFX overrides serialize() and deserialize(), this should return true + * + * @return Does the SideFX need save game serialization? + */ + virtual inline bool needsSerialization() { + return false; + } + + virtual bool stop() { + return true; + } + virtual void kill() {} + +protected: + ZVision *_engine; + uint32 _key; + SideFXType _type; + +// Static member functions +public: + +}; +} // End of namespace ZVision + +#endif // SIDEFX_H_INCLUDED diff --git a/engines/zvision/scripting/sidefx/animation_node.cpp b/engines/zvision/scripting/sidefx/animation_node.cpp new file mode 100644 index 0000000000..549aacba7f --- /dev/null +++ b/engines/zvision/scripting/sidefx/animation_node.cpp @@ -0,0 +1,204 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/sidefx/animation_node.h" + +#include "zvision/zvision.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/animation/meta_animation.h" + +#include "graphics/surface.h" + +namespace ZVision { + +AnimationNode::AnimationNode(ZVision *engine, uint32 controlKey, const Common::String &fileName, int32 mask, int32 frate, bool DisposeAfterUse) + : SideFX(engine, controlKey, SIDEFX_ANIM), + _DisposeAfterUse(DisposeAfterUse), + _mask(mask), + _animation(NULL) { + + _animation = new MetaAnimation(fileName, engine); + _frmDelay = _animation->frameTime(); + + if (frate > 0) + _frmDelay = 1000.0 / frate; +} + +AnimationNode::~AnimationNode() { + if (_animation) + delete _animation; + + _engine->getScriptManager()->setStateValue(_key, 2); + + PlayNodes::iterator it = _playList.begin(); + if (it != _playList.end()) { + _engine->getScriptManager()->setStateValue((*it).slot, 2); + + if ((*it)._scaled) + delete(*it)._scaled; + } + + _playList.clear(); +} + +bool AnimationNode::process(uint32 deltaTimeInMillis) { + PlayNodes::iterator it = _playList.begin(); + if (it != _playList.end()) { + playnode *nod = &(*it); + + nod->_delay -= deltaTimeInMillis; + if (nod->_delay <= 0) { + nod->_delay += _frmDelay; + + const Graphics::Surface *frame = NULL; + + if (nod->_curFrame == -1) { // Start of new playlist node + nod->_curFrame = nod->start; + + _animation->seekToFrame(nod->_curFrame); + frame = _animation->decodeNextFrame(); + + nod->_delay = _frmDelay; + if (nod->slot) + _engine->getScriptManager()->setStateValue(nod->slot, 1); + } else { + nod->_curFrame++; + + if (nod->_curFrame > nod->stop) { + nod->loop--; + + if (nod->loop == 0) { + if (nod->slot >= 0) + _engine->getScriptManager()->setStateValue(nod->slot, 2); + if (nod->_scaled) + delete nod->_scaled; + _playList.erase(it); + return _DisposeAfterUse; + } + + nod->_curFrame = nod->start; + _animation->seekToFrame(nod->_curFrame); + } + + frame = _animation->decodeNextFrame(); + } + + if (frame) { + + uint32 dstw; + uint32 dsth; + if (_engine->getRenderManager()->getRenderTable()->getRenderState() == RenderTable::PANORAMA) { + dstw = nod->pos.height(); + dsth = nod->pos.width(); + } else { + dstw = nod->pos.width(); + dsth = nod->pos.height(); + } + + if (frame->w != dstw || frame->h != dsth) { + if (nod->_scaled) + if (nod->_scaled->w != dstw || nod->_scaled->h != dsth) { + delete nod->_scaled; + nod->_scaled = NULL; + } + + if (!nod->_scaled) { + nod->_scaled = new Graphics::Surface; + nod->_scaled->create(dstw, dsth, frame->format); + } + + _engine->getRenderManager()->scaleBuffer(frame->getPixels(), nod->_scaled->getPixels(), frame->w, frame->h, frame->format.bytesPerPixel, dstw, dsth); + frame = nod->_scaled; + } + + if (_engine->getRenderManager()->getRenderTable()->getRenderState() == RenderTable::PANORAMA) { + Graphics::Surface *transposed = RenderManager::tranposeSurface(frame); + if (_mask > 0) + _engine->getRenderManager()->blitSurfaceToBkg(*transposed, nod->pos.left, nod->pos.top, _mask); + else + _engine->getRenderManager()->blitSurfaceToBkg(*transposed, nod->pos.left, nod->pos.top); + delete transposed; + } else { + if (_mask > 0) + _engine->getRenderManager()->blitSurfaceToBkg(*frame, nod->pos.left, nod->pos.top, _mask); + else + _engine->getRenderManager()->blitSurfaceToBkg(*frame, nod->pos.left, nod->pos.top); + } + } + } + } + + return false; +} + +void AnimationNode::addPlayNode(int32 slot, int x, int y, int x2, int y2, int startFrame, int endFrame, int loops) { + playnode nod; + nod.loop = loops; + nod.pos = Common::Rect(x, y, x2 + 1, y2 + 1); + nod.start = startFrame; + nod.stop = endFrame; + + if (nod.stop >= (int)_animation->frameCount()) + nod.stop = _animation->frameCount() - 1; + + nod.slot = slot; + nod._curFrame = -1; + nod._delay = 0; + nod._scaled = NULL; + _playList.push_back(nod); +} + +bool AnimationNode::stop() { + PlayNodes::iterator it = _playList.begin(); + if (it != _playList.end()) { + _engine->getScriptManager()->setStateValue((*it).slot, 2); + if ((*it)._scaled) + delete(*it)._scaled; + } + + _playList.clear(); + + // We don't need to delete, it's may be reused + return false; +} + +void AnimationNode::setNewFrameDelay(int32 newDelay) { + if (newDelay > 0) { + PlayNodes::iterator it = _playList.begin(); + if (it != _playList.end()) { + playnode *nod = &(*it); + float percent = (float)nod->_delay / (float)_frmDelay; + nod->_delay = percent * newDelay; // Scale to new max + } + + _frmDelay = newDelay; + } +} + +int32 AnimationNode::getFrameDelay() { + return _frmDelay; +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/sidefx/animation_node.h b/engines/zvision/scripting/sidefx/animation_node.h new file mode 100644 index 0000000000..94428d2542 --- /dev/null +++ b/engines/zvision/scripting/sidefx/animation_node.h @@ -0,0 +1,83 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_ANIMATION_NODE_H +#define ZVISION_ANIMATION_NODE_H + +#include "zvision/scripting/sidefx.h" +#include "common/rect.h" +#include "common/list.h" + +namespace Common { +class String; +} + +namespace Graphics { +struct Surface; +} + +namespace ZVision { + +class ZVision; +class MetaAnimation; + +class AnimationNode : public SideFX { +public: + AnimationNode(ZVision *engine, uint32 controlKey, const Common::String &fileName, int32 mask, int32 frate, bool DisposeAfterUse = true); + ~AnimationNode(); + + struct playnode { + Common::Rect pos; + int32 slot; + int32 start; + int32 stop; + int32 loop; + int32 _curFrame; + int32 _delay; + Graphics::Surface *_scaled; + }; + +private: + typedef Common::List<playnode> PlayNodes; + + PlayNodes _playList; + + int32 _mask; + bool _DisposeAfterUse; + + MetaAnimation *_animation; + int32 _frmDelay; + +public: + bool process(uint32 deltaTimeInMillis); + + void addPlayNode(int32 slot, int x, int y, int x2, int y2, int startFrame, int endFrame, int loops = 1); + + bool stop(); + + void setNewFrameDelay(int32 newDelay); + int32 getFrameDelay(); +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/sidefx/distort_node.cpp b/engines/zvision/scripting/sidefx/distort_node.cpp new file mode 100644 index 0000000000..0d5c8b1ed5 --- /dev/null +++ b/engines/zvision/scripting/sidefx/distort_node.cpp @@ -0,0 +1,105 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/sidefx/distort_node.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/graphics/render_table.h" + +#include "common/stream.h" + +namespace ZVision { + +DistortNode::DistortNode(ZVision *engine, uint32 key, int16 speed, float startAngle, float endAngle, float startLineScale, float endLineScale) + : SideFX(engine, key, SIDEFX_DISTORT) { + + _angle = _engine->getRenderManager()->getRenderTable()->getAngle(); + _linScale = _engine->getRenderManager()->getRenderTable()->getLinscale(); + + _speed = speed; + _incr = true; + _startAngle = startAngle; + _endAngle = endAngle; + _startLineScale = startLineScale; + _endLineScale = endLineScale; + + _curFrame = 1.0; + + _diffAngle = endAngle - startAngle; + _diffLinScale = endLineScale - startLineScale; + + _frmSpeed = (float)speed / 15.0; + _frames = ceil((5.0 - _frmSpeed * 2.0) / _frmSpeed); + if (_frames <= 0) + _frames = 1; + + if (_key != StateKey_NotSet) + _engine->getScriptManager()->setStateValue(_key, 1); +} + +DistortNode::~DistortNode() { + setParams(_angle, _linScale); +} + +bool DistortNode::process(uint32 deltaTimeInMillis) { + + float updTime = deltaTimeInMillis / (1000.0 / 60.0); + + if (_incr) + _curFrame += updTime; + else + _curFrame -= updTime; + + if (_curFrame < 1.0) { + _curFrame = 1.0; + _incr = true; + } else if (_curFrame > _frames) { + _curFrame = _frames; + _incr = false; + } + + float diff = (1.0 / (5.0 - (_curFrame * _frmSpeed))) / (5.0 - _frmSpeed); + setParams(_startAngle + diff * _diffAngle, _startLineScale + diff * _diffLinScale); + + return false; +} + +void DistortNode::setParams(float angl, float linScale) { + RenderTable *table = _engine->getRenderManager()->getRenderTable(); + if (table->getRenderState() == RenderTable::PANORAMA) { + table->setPanoramaFoV(angl); + table->setPanoramaScale(linScale); + table->generateRenderTable(); + _engine->getRenderManager()->markDirty(); + } else if (table->getRenderState() == RenderTable::TILT) { + table->setTiltFoV(angl); + table->setTiltScale(linScale); + table->generateRenderTable(); + _engine->getRenderManager()->markDirty(); + } +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/sidefx/distort_node.h b/engines/zvision/scripting/sidefx/distort_node.h new file mode 100644 index 0000000000..787a69bdde --- /dev/null +++ b/engines/zvision/scripting/sidefx/distort_node.h @@ -0,0 +1,63 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_DISTORT_NODE_H +#define ZVISION_DISTORT_NODE_H + +#include "zvision/scripting/sidefx.h" + +namespace ZVision { + +class ZVision; + +class DistortNode : public SideFX { +public: + DistortNode(ZVision *engine, uint32 key, int16 speed, float startAngle, float endAngle, float startLineScale, float endLineScale); + ~DistortNode(); + + bool process(uint32 deltaTimeInMillis); + +private: + int16 _speed; + float _startAngle; + float _endAngle; + float _startLineScale; + float _endLineScale; + + float _frmSpeed; + float _diffAngle; + float _diffLinScale; + bool _incr; + int16 _frames; + + float _curFrame; + + float _angle; + float _linScale; + +private: + void setParams(float angl, float linScale); +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/sidefx/music_node.cpp b/engines/zvision/scripting/sidefx/music_node.cpp new file mode 100644 index 0000000000..a76d3b4e8d --- /dev/null +++ b/engines/zvision/scripting/sidefx/music_node.cpp @@ -0,0 +1,238 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/sidefx/music_node.h" + +#include "zvision/zvision.h" +#include "zvision/core/midi.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/sound/zork_raw.h" + +#include "common/stream.h" +#include "common/file.h" +#include "audio/decoders/wave.h" + +namespace ZVision { + +MusicNode::MusicNode(ZVision *engine, uint32 key, Common::String &filename, bool loop, int8 volume) + : MusicNodeBASE(engine, key, SIDEFX_AUDIO) { + _loop = loop; + _volume = volume; + _crossfade = false; + _crossfadeTarget = 0; + _crossfadeTime = 0; + _attenuate = 0; + _pantrack = false; + _pantrackPosition = 0; + _sub = NULL; + + Audio::RewindableAudioStream *audioStream = NULL; + + if (filename.contains(".wav")) { + Common::File *file = new Common::File(); + if (_engine->getSearchManager()->openFile(*file, filename)) { + audioStream = Audio::makeWAVStream(file, DisposeAfterUse::YES); + } + } else { + audioStream = makeRawZorkStream(filename, _engine); + } + + _stereo = audioStream->isStereo(); + + if (_loop) { + Audio::LoopingAudioStream *loopingAudioStream = new Audio::LoopingAudioStream(audioStream, 0, DisposeAfterUse::YES); + _engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, loopingAudioStream, -1, _volume); + } else { + _engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, audioStream, -1, _volume); + } + + if (_key != StateKey_NotSet) + _engine->getScriptManager()->setStateValue(_key, 1); + + Common::String subname = filename; + subname.setChar('s', subname.size() - 3); + subname.setChar('u', subname.size() - 2); + subname.setChar('b', subname.size() - 1); + + if (_engine->getSearchManager()->hasFile(subname)) + _sub = new Subtitle(_engine, subname); +} + +MusicNode::~MusicNode() { + _engine->_mixer->stopHandle(_handle); + if (_key != StateKey_NotSet) + _engine->getScriptManager()->setStateValue(_key, 2); + if (_sub) + delete _sub; + debug(1, "MusicNode: %d destroyed\n", _key); +} + +void MusicNode::setPanTrack(int16 pos) { + if (!_stereo) { + _pantrack = true; + _pantrackPosition = pos; + setVolume(_volume); + } +} + +void MusicNode::unsetPanTrack() { + _pantrack = false; + setVolume(_volume); +} + +void MusicNode::setFade(int32 time, uint8 target) { + _crossfadeTarget = target; + _crossfadeTime = time; + _crossfade = true; +} + +bool MusicNode::process(uint32 deltaTimeInMillis) { + if (! _engine->_mixer->isSoundHandleActive(_handle)) + return stop(); + else { + uint8 _newvol = _volume; + + if (_crossfade) { + if (_crossfadeTime > 0) { + if ((int32)deltaTimeInMillis > _crossfadeTime) + deltaTimeInMillis = _crossfadeTime; + _newvol += floor(((float)(_crossfadeTarget - _newvol) / (float)_crossfadeTime)) * (float)deltaTimeInMillis; + _crossfadeTime -= deltaTimeInMillis; + } else { + _crossfade = false; + _newvol = _crossfadeTarget; + } + } + + if (_pantrack || _volume != _newvol) + setVolume(_newvol); + + if (_sub) + _sub->process(_engine->_mixer->getSoundElapsedTime(_handle) / 100); + } + return false; +} + +void MusicNode::setVolume(uint8 newVolume) { + if (_pantrack) { + int curX = _engine->getScriptManager()->getStateValue(StateKey_ViewPos); + curX -= _pantrackPosition; + int32 _width = _engine->getRenderManager()->getBkgSize().x; + if (curX < (-_width) / 2) + curX += _width; + else if (curX >= _width / 2) + curX -= _width; + + float norm = (float)curX / ((float)_width / 2.0); + float lvl = fabs(norm); + if (lvl > 0.5) + lvl = (lvl - 0.5) * 1.7; + else + lvl = 1.0; + + float bal = sin(-norm * 3.1415926) * 127.0; + + if (_engine->_mixer->isSoundHandleActive(_handle)) { + _engine->_mixer->setChannelBalance(_handle, bal); + _engine->_mixer->setChannelVolume(_handle, newVolume * lvl); + } + } else { + if (_engine->_mixer->isSoundHandleActive(_handle)) { + _engine->_mixer->setChannelBalance(_handle, 0); + _engine->_mixer->setChannelVolume(_handle, newVolume); + } + } + + _volume = newVolume; +} + +PanTrackNode::PanTrackNode(ZVision *engine, uint32 key, uint32 slot, int16 pos) + : SideFX(engine, key, SIDEFX_PANTRACK) { + _slot = slot; + + SideFX *fx = _engine->getScriptManager()->getSideFX(slot); + if (fx && fx->getType() == SIDEFX_AUDIO) { + MusicNodeBASE *mus = (MusicNodeBASE *)fx; + mus->setPanTrack(pos); + } +} + +PanTrackNode::~PanTrackNode() { + SideFX *fx = _engine->getScriptManager()->getSideFX(_slot); + if (fx && fx->getType() == SIDEFX_AUDIO) { + MusicNodeBASE *mus = (MusicNodeBASE *)fx; + mus->unsetPanTrack(); + } +} + +MusicMidiNode::MusicMidiNode(ZVision *engine, uint32 key, int8 program, int8 note, int8 volume) + : MusicNodeBASE(engine, key, SIDEFX_AUDIO) { + _volume = volume; + _prog = program; + _noteNumber = note; + _pan = 0; + + _chan = _engine->getMidiManager()->getFreeChannel(); + + if (_chan >= 0) { + _engine->getMidiManager()->setVolume(_chan, _volume); + _engine->getMidiManager()->setPan(_chan, _pan); + _engine->getMidiManager()->setProgram(_chan, _prog); + _engine->getMidiManager()->noteOn(_chan, _noteNumber, _volume); + } + + if (_key != StateKey_NotSet) + _engine->getScriptManager()->setStateValue(_key, 1); +} + +MusicMidiNode::~MusicMidiNode() { + if (_chan >= 0) { + _engine->getMidiManager()->noteOff(_chan); + } + if (_key != StateKey_NotSet) + _engine->getScriptManager()->setStateValue(_key, 2); +} + +void MusicMidiNode::setPanTrack(int16 pos) { +} + +void MusicMidiNode::unsetPanTrack() { +} + +void MusicMidiNode::setFade(int32 time, uint8 target) { +} + +bool MusicMidiNode::process(uint32 deltaTimeInMillis) { + return false; +} + +void MusicMidiNode::setVolume(uint8 newVolume) { + if (_chan >= 0) { + _engine->getMidiManager()->setVolume(_chan, newVolume); + } + _volume = newVolume; +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/sidefx/music_node.h b/engines/zvision/scripting/sidefx/music_node.h new file mode 100644 index 0000000000..c89345f0d0 --- /dev/null +++ b/engines/zvision/scripting/sidefx/music_node.h @@ -0,0 +1,135 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_MUSIC_NODE_H +#define ZVISION_MUSIC_NODE_H + +#include "audio/mixer.h" +#include "zvision/scripting/sidefx.h" +#include "zvision/graphics/subtitles.h" + +namespace Common { +class String; +} + +namespace ZVision { + +class MusicNodeBASE : public SideFX { +public: + MusicNodeBASE(ZVision *engine, uint32 key, SideFXType type) : SideFX(engine, key, type) {} + ~MusicNodeBASE() {} + + /** + * Decrement the timer by the delta time. If the timer is finished, set the status + * in _globalState and let this node be deleted + * + * @param deltaTimeInMillis The number of milliseconds that have passed since last frame + * @return If true, the node can be deleted after process() finishes + */ + virtual bool process(uint32 deltaTimeInMillis) = 0; + + virtual void setVolume(uint8 volume) = 0; + + virtual void setPanTrack(int16 pos) = 0; + virtual void unsetPanTrack() = 0; + + virtual void setFade(int32 time, uint8 target) = 0; +}; + +class MusicNode : public MusicNodeBASE { +public: + MusicNode(ZVision *engine, uint32 key, Common::String &file, bool loop, int8 volume); + ~MusicNode(); + + /** + * Decrement the timer by the delta time. If the timer is finished, set the status + * in _globalState and let this node be deleted + * + * @param deltaTimeInMillis The number of milliseconds that have passed since last frame + * @return If true, the node can be deleted after process() finishes + */ + bool process(uint32 deltaTimeInMillis); + + void setVolume(uint8 volume); + + void setPanTrack(int16 pos); + void unsetPanTrack(); + + void setFade(int32 time, uint8 target); + +private: + int32 _timeLeft; + bool _pantrack; + int32 _pantrackPosition; + int32 _attenuate; + uint8 _volume; + bool _loop; + bool _crossfade; + uint8 _crossfadeTarget; + int32 _crossfadeTime; + bool _stereo; + Audio::SoundHandle _handle; + Subtitle *_sub; +}; + +class MusicMidiNode : public MusicNodeBASE { +public: + MusicMidiNode(ZVision *engine, uint32 key, int8 program, int8 note, int8 volume); + ~MusicMidiNode(); + + /** + * Decrement the timer by the delta time. If the timer is finished, set the status + * in _globalState and let this node be deleted + * + * @param deltaTimeInMillis The number of milliseconds that have passed since last frame + * @return If true, the node can be deleted after process() finishes + */ + bool process(uint32 deltaTimeInMillis); + + void setVolume(uint8 volume); + + void setPanTrack(int16 pos); + void unsetPanTrack(); + + void setFade(int32 time, uint8 target); + +private: + int8 _chan; + int8 _noteNumber; + int8 _velocity; + int8 _pan; + int8 _volume; + int8 _prog; +}; + +class PanTrackNode : public SideFX { +public: + PanTrackNode(ZVision *engine, uint32 key, uint32 slot, int16 pos); + ~PanTrackNode(); + +private: + uint32 _slot; +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/sidefx/region_node.cpp b/engines/zvision/scripting/sidefx/region_node.cpp new file mode 100644 index 0000000000..de613d8af2 --- /dev/null +++ b/engines/zvision/scripting/sidefx/region_node.cpp @@ -0,0 +1,56 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/sidefx/region_node.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/graphics/render_manager.h" + +namespace ZVision { + +RegionNode::RegionNode(ZVision *engine, uint32 key, Effect *effect, uint32 delay) + : SideFX(engine, key, SIDEFX_REGION) { + _effect = effect; + _delay = delay; + _timeLeft = 0; +} + +RegionNode::~RegionNode() { + _engine->getRenderManager()->deleteEffect(_key); +} + +bool RegionNode::process(uint32 deltaTimeInMillis) { + _timeLeft -= deltaTimeInMillis; + + if (_timeLeft <= 0) { + _timeLeft = _delay; + if (_effect) + _effect->update(); + } + + return false; +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/sidefx/region_node.h b/engines/zvision/scripting/sidefx/region_node.h new file mode 100644 index 0000000000..ec716b6e3e --- /dev/null +++ b/engines/zvision/scripting/sidefx/region_node.h @@ -0,0 +1,57 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_REGION_NODE_H +#define ZVISION_REGION_NODE_H + +#include "graphics/surface.h" + +#include "zvision/scripting/sidefx.h" +#include "zvision/graphics/effect.h" + +namespace ZVision { + +class ZVision; + +class RegionNode : public SideFX { +public: + RegionNode(ZVision *engine, uint32 key, Effect *effect, uint32 delay); + ~RegionNode(); + + /** + * Decrement the timer by the delta time. If the timer is finished, set the status + * in _globalState and let this node be deleted + * + * @param deltaTimeInMillis The number of milliseconds that have passed since last frame + * @return If true, the node can be deleted after process() finishes + */ + bool process(uint32 deltaTimeInMillis); + +private: + int32 _timeLeft; + uint32 _delay; + Effect *_effect; +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/sidefx/syncsound_node.cpp b/engines/zvision/scripting/sidefx/syncsound_node.cpp new file mode 100644 index 0000000000..c1f139694b --- /dev/null +++ b/engines/zvision/scripting/sidefx/syncsound_node.cpp @@ -0,0 +1,85 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/sidefx/syncsound_node.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/sound/zork_raw.h" + +#include "common/stream.h" +#include "common/file.h" +#include "audio/decoders/wave.h" + +namespace ZVision { + +SyncSoundNode::SyncSoundNode(ZVision *engine, uint32 key, Common::String &filename, int32 syncto) + : SideFX(engine, key, SIDEFX_AUDIO) { + _syncto = syncto; + _sub = NULL; + + Audio::RewindableAudioStream *audioStream = NULL; + + if (filename.contains(".wav")) { + Common::File *file = new Common::File(); + if (_engine->getSearchManager()->openFile(*file, filename)) { + audioStream = Audio::makeWAVStream(file, DisposeAfterUse::YES); + } + } else { + audioStream = makeRawZorkStream(filename, _engine); + } + + _engine->_mixer->playStream(Audio::Mixer::kPlainSoundType, &_handle, audioStream); + + Common::String subname = filename; + subname.setChar('s', subname.size() - 3); + subname.setChar('u', subname.size() - 2); + subname.setChar('b', subname.size() - 1); + + if (_engine->getSearchManager()->hasFile(subname)) + _sub = new Subtitle(_engine, subname); +} + +SyncSoundNode::~SyncSoundNode() { + _engine->_mixer->stopHandle(_handle); + if (_sub) + delete _sub; +} + +bool SyncSoundNode::process(uint32 deltaTimeInMillis) { + if (! _engine->_mixer->isSoundHandleActive(_handle)) + return stop(); + else { + + if (_engine->getScriptManager()->getSideFX(_syncto) == NULL) + return stop(); + + if (_sub) + _sub->process(_engine->_mixer->getSoundElapsedTime(_handle) / 100); + } + return false; +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/sidefx/syncsound_node.h b/engines/zvision/scripting/sidefx/syncsound_node.h new file mode 100644 index 0000000000..7cd02a8aef --- /dev/null +++ b/engines/zvision/scripting/sidefx/syncsound_node.h @@ -0,0 +1,56 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_SYNCSOUND_NODE_H +#define ZVISION_SYNCSOUND_NODE_H + +#include "audio/mixer.h" +#include "zvision/scripting/sidefx.h" +#include "zvision/graphics/subtitles.h" + +namespace Common { +class String; +} + +namespace ZVision { +class SyncSoundNode : public SideFX { +public: + SyncSoundNode(ZVision *engine, uint32 key, Common::String &file, int32 syncto); + ~SyncSoundNode(); + + /** + * Decrement the timer by the delta time. If the timer is finished, set the status + * in _globalState and let this node be deleted + * + * @param deltaTimeInMillis The number of milliseconds that have passed since last frame + * @return If true, the node can be deleted after process() finishes + */ + bool process(uint32 deltaTimeInMillis); +private: + int32 _syncto; + Audio::SoundHandle _handle; + Subtitle *_sub; +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/scripting/controls/timer_node.cpp b/engines/zvision/scripting/sidefx/timer_node.cpp index 6f88b056a1..abf2c90b04 100644 --- a/engines/zvision/scripting/controls/timer_node.cpp +++ b/engines/zvision/scripting/sidefx/timer_node.cpp @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -22,46 +22,52 @@ #include "common/scummsys.h" -#include "zvision/scripting/controls/timer_node.h" +#include "zvision/scripting/sidefx/timer_node.h" #include "zvision/zvision.h" #include "zvision/scripting/script_manager.h" #include "common/stream.h" - namespace ZVision { TimerNode::TimerNode(ZVision *engine, uint32 key, uint timeInSeconds) - : Control(engine, key) { - if (_engine->getGameId() == GID_NEMESIS) { + : SideFX(engine, key, SIDEFX_TIMER) { + if (_engine->getGameId() == GID_NEMESIS) _timeLeft = timeInSeconds * 1000; - } else if (_engine->getGameId() == GID_GRANDINQUISITOR) { + else if (_engine->getGameId() == GID_GRANDINQUISITOR) _timeLeft = timeInSeconds * 100; - } - _engine->getScriptManager()->setStateValue(_key, 1); + if (_key != StateKey_NotSet) + _engine->getScriptManager()->setStateValue(_key, 1); } TimerNode::~TimerNode() { - if (_timeLeft <= 0) + if (_key != StateKey_NotSet) _engine->getScriptManager()->setStateValue(_key, 2); - else - _engine->getScriptManager()->setStateValue(_key, _timeLeft); // If timer was stopped by stop or kill + int32 timeLeft = _timeLeft / (_engine->getGameId() == GID_NEMESIS ? 1000 : 100); + if (timeLeft > 0) + _engine->getScriptManager()->setStateValue(_key, timeLeft); // If timer was stopped by stop or kill } bool TimerNode::process(uint32 deltaTimeInMillis) { _timeLeft -= deltaTimeInMillis; - if (_timeLeft <= 0) { - // Let the destructor reset the state value - return true; - } + if (_timeLeft <= 0) + return stop(); return false; } +bool TimerNode::stop() { + if (_key != StateKey_NotSet) + _engine->getScriptManager()->setStateValue(_key, 2); + return true; +} + void TimerNode::serialize(Common::WriteStream *stream) { + stream->writeUint32BE(MKTAG('T', 'I', 'M', 'R')); + stream->writeUint32LE(8); // size stream->writeUint32LE(_key); stream->writeUint32LE(_timeLeft); } diff --git a/engines/zvision/scripting/controls/timer_node.h b/engines/zvision/scripting/sidefx/timer_node.h index 48b5fad1e9..7a26aff251 100644 --- a/engines/zvision/scripting/controls/timer_node.h +++ b/engines/zvision/scripting/sidefx/timer_node.h @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -23,13 +23,13 @@ #ifndef ZVISION_TIMER_NODE_H #define ZVISION_TIMER_NODE_H -#include "zvision/scripting/control.h" +#include "zvision/scripting/sidefx.h" namespace ZVision { class ZVision; -class TimerNode : public Control { +class TimerNode : public SideFX { public: TimerNode(ZVision *engine, uint32 key, uint timeInSeconds); ~TimerNode(); @@ -44,7 +44,11 @@ public: bool process(uint32 deltaTimeInMillis); void serialize(Common::WriteStream *stream); void deserialize(Common::SeekableReadStream *stream); - inline bool needsSerialization() { return true; } + inline bool needsSerialization() { + return true; + } + + bool stop(); private: int32 _timeLeft; diff --git a/engines/zvision/scripting/sidefx/ttytext_node.cpp b/engines/zvision/scripting/sidefx/ttytext_node.cpp new file mode 100644 index 0000000000..1fb7c10792 --- /dev/null +++ b/engines/zvision/scripting/sidefx/ttytext_node.cpp @@ -0,0 +1,174 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" + +#include "zvision/scripting/sidefx/ttytext_node.h" + +#include "zvision/zvision.h" +#include "zvision/scripting/script_manager.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/text/text.h" + +#include "common/stream.h" +#include "common/file.h" + +namespace ZVision { + +ttyTextNode::ttyTextNode(ZVision *engine, uint32 key, const Common::String &file, const Common::Rect &r, int32 delay) : + SideFX(engine, key, SIDEFX_TTYTXT), + _fnt(engine) { + _delay = delay; + _r = r; + _txtpos = 0; + _nexttime = 0; + _dx = 0; + _dy = 0; + + Common::File *infile = _engine->getSearchManager()->openFile(file); + if (infile) { + while (!infile->eos()) { + Common::String asciiLine = readWideLine(*infile); + if (asciiLine.empty()) { + continue; + } + _txtbuf += asciiLine; + } + + delete infile; + } + _img.create(_r.width(), _r.height(), _engine->_pixelFormat); + _style.sharp = true; + _style.readAllStyle(_txtbuf); + _style.setFont(_fnt); + _engine->getScriptManager()->setStateValue(_key, 1); +} + +ttyTextNode::~ttyTextNode() { + _engine->getScriptManager()->setStateValue(_key, 2); + _img.free(); +} + +bool ttyTextNode::process(uint32 deltaTimeInMillis) { + _nexttime -= deltaTimeInMillis; + + if (_nexttime < 0) { + if (_txtpos < _txtbuf.size()) { + if (_txtbuf[_txtpos] == '<') { + int32 strt = _txtpos; + int32 endt = 0; + int16 ret = 0; + while (_txtbuf[_txtpos] != '>' && _txtpos < _txtbuf.size()) + _txtpos++; + endt = _txtpos; + if (strt != -1) + if ((endt - strt - 1) > 0) + ret = _style.parseStyle(_txtbuf.c_str() + strt + 1, endt - strt - 1); + + if (ret & (TXT_RET_FNTCHG | TXT_RET_FNTSTL | TXT_RET_NEWLN)) { + if (ret & TXT_RET_FNTCHG) + _style.setFont(_fnt); + if (ret & TXT_RET_FNTSTL) + _style.setFontStyle(_fnt); + + if (ret & TXT_RET_NEWLN) + newline(); + } + + if (ret & TXT_RET_HASSTBOX) { + Common::String buf; + buf.format("%d", _style.statebox); + + for (uint8 j = 0; j < buf.size(); j++) + outchar(buf[j]); + } + + _txtpos++; + } else { + int8 charsz = getUtf8CharSize(_txtbuf[_txtpos]); + + uint16 chr = readUtf8Char(_txtbuf.c_str() + _txtpos); + + if (chr == ' ') { + uint32 i = _txtpos + charsz; + uint16 width = _fnt.getCharWidth(chr); + + while (i < _txtbuf.size() && _txtbuf[i] != ' ' && _txtbuf[i] != '<') { + + int8 chsz = getUtf8CharSize(_txtbuf[i]); + uint16 uchr = readUtf8Char(_txtbuf.c_str() + _txtpos); + + width += _fnt.getCharWidth(uchr); + + i += chsz; + } + + if (_dx + width > _r.width()) + newline(); + else + outchar(chr); + } else + outchar(chr); + + _txtpos += charsz; + } + _nexttime = _delay; + _engine->getRenderManager()->blitSurfaceToBkg(_img, _r.left, _r.top); + } else + return stop(); + } + + return false; +} + +void ttyTextNode::scroll() { + int32 scrl = 0; + while (_dy - scrl > _r.height() - _fnt.getFontHeight()) + scrl += _fnt.getFontHeight(); + int8 *pixels = (int8 *)_img.getPixels(); + for (uint16 h = scrl; h < _img.h; h++) + memcpy(pixels + _img.pitch * (h - scrl), pixels + _img.pitch * h, _img.pitch); + + _img.fillRect(Common::Rect(0, _img.h - scrl, _img.w, _img.h), 0); + _dy -= scrl; +} + +void ttyTextNode::newline() { + _dy += _fnt.getFontHeight(); + _dx = 0; +} + +void ttyTextNode::outchar(uint16 chr) { + uint32 clr = _engine->_pixelFormat.RGBToColor(_style.red, _style.green, _style.blue); + + if (_dx + _fnt.getCharWidth(chr) > _r.width()) + newline(); + + if (_dy + _fnt.getFontHeight() >= _r.height()) + scroll(); + + _fnt.drawChar(&_img, chr, _dx, _dy, clr); + + _dx += _fnt.getCharWidth(chr); +} + +} // End of namespace ZVision diff --git a/engines/zvision/scripting/sidefx/ttytext_node.h b/engines/zvision/scripting/sidefx/ttytext_node.h new file mode 100644 index 0000000000..b6cbed3e34 --- /dev/null +++ b/engines/zvision/scripting/sidefx/ttytext_node.h @@ -0,0 +1,73 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef ZVISION_TTYTEXT_NODE_H +#define ZVISION_TTYTEXT_NODE_H + +#include "common/rect.h" +#include "graphics/surface.h" + +#include "zvision/scripting/sidefx.h" +#include "zvision/text/text.h" +#include "zvision/graphics/truetype_font.h" + +namespace Common { +class String; +} + +namespace ZVision { +class ttyTextNode : public SideFX { +public: + ttyTextNode(ZVision *engine, uint32 key, const Common::String &file, const Common::Rect &r, int32 delay); + ~ttyTextNode(); + + /** + * Decrement the timer by the delta time. If the timer is finished, set the status + * in _globalState and let this node be deleted + * + * @param deltaTimeInMillis The number of milliseconds that have passed since last frame + * @return If true, the node can be deleted after process() finishes + */ + bool process(uint32 deltaTimeInMillis); +private: + Common::Rect _r; + + cTxtStyle _style; + StyledTTFont _fnt; + Common::String _txtbuf; + uint32 _txtpos; + + int32 _delay; + int32 _nexttime; + Graphics::Surface _img; + int16 _dx; + int16 _dy; +private: + + void newline(); + void scroll(); + void outchar(uint16 chr); +}; + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/sound/zork_raw.cpp b/engines/zvision/sound/zork_raw.cpp index edee1fd16e..c26c33a392 100644 --- a/engines/zvision/sound/zork_raw.cpp +++ b/engines/zvision/sound/zork_raw.cpp @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -21,85 +21,79 @@ */ #include "common/scummsys.h" - -#include "zvision/sound/zork_raw.h" - -#include "zvision/zvision.h" -#include "zvision/detection.h" -#include "zvision/utility/utility.h" - #include "common/file.h" #include "common/str.h" #include "common/stream.h" #include "common/memstream.h" #include "common/bufferedstream.h" #include "common/util.h" - +#include "common/tokenizer.h" #include "audio/audiostream.h" #include "audio/decoders/raw.h" +#include "zvision/sound/zork_raw.h" +#include "zvision/zvision.h" +#include "zvision/detection.h" +#include "zvision/utility/utility.h" namespace ZVision { -const int16 RawZorkStream::_stepAdjustmentTable[8] = {-1, -1, -1, 1, 4, 7, 10, 12}; - -const int32 RawZorkStream::_amplitudeLookupTable[89] = {0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, - 0x0010, 0x0011, 0x0013, 0x0015, 0x0017, 0x0019, 0x001C, 0x001F, - 0x0022, 0x0025, 0x0029, 0x002D, 0x0032, 0x0037, 0x003C, 0x0042, - 0x0049, 0x0050, 0x0058, 0x0061, 0x006B, 0x0076, 0x0082, 0x008F, - 0x009D, 0x00AD, 0x00BE, 0x00D1, 0x00E6, 0x00FD, 0x0117, 0x0133, - 0x0151, 0x0173, 0x0198, 0x01C1, 0x01EE, 0x0220, 0x0256, 0x0292, - 0x02D4, 0x031C, 0x036C, 0x03C3, 0x0424, 0x048E, 0x0502, 0x0583, - 0x0610, 0x06AB, 0x0756, 0x0812, 0x08E0, 0x09C3, 0x0ABD, 0x0BD0, - 0x0CFF, 0x0E4C, 0x0FBA, 0x114C, 0x1307, 0x14EE, 0x1706, 0x1954, - 0x1BDC, 0x1EA5, 0x21B6, 0x2515, 0x28CA, 0x2CDF, 0x315B, 0x364B, - 0x3BB9, 0x41B2, 0x4844, 0x4F7E, 0x5771, 0x602F, 0x69CE, 0x7462, 0x7FFF}; - -const SoundParams RawZorkStream::_zNemSoundParamLookupTable[6] = {{'6', 0x2B11, false, false}, - {'a', 0x5622, false, true}, - {'b', 0x5622, true, true}, - {'n', 0x2B11, false, true}, - {'s', 0x5622, false, true}, - {'t', 0x5622, true, true} -}; - -const SoundParams RawZorkStream::_zgiSoundParamLookupTable[5] = {{'a',0x5622, false, false}, - {'k',0x2B11, true, true}, - {'p',0x5622, false, true}, - {'q',0x5622, true, true}, - {'u',0xAC44, true, true} -}; - -RawZorkStream::RawZorkStream(uint32 rate, bool stereo, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream) - : _rate(rate), - _stereo(0), - _stream(stream, disposeStream), - _endOfData(false) { +const int16 RawChunkStream::_stepAdjustmentTable[8] = { -1, -1, -1, 1, 4, 7, 10, 12}; + +const int32 RawChunkStream::_amplitudeLookupTable[89] = {0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, + 0x0010, 0x0011, 0x0013, 0x0015, 0x0017, 0x0019, 0x001C, 0x001F, + 0x0022, 0x0025, 0x0029, 0x002D, 0x0032, 0x0037, 0x003C, 0x0042, + 0x0049, 0x0050, 0x0058, 0x0061, 0x006B, 0x0076, 0x0082, 0x008F, + 0x009D, 0x00AD, 0x00BE, 0x00D1, 0x00E6, 0x00FD, 0x0117, 0x0133, + 0x0151, 0x0173, 0x0198, 0x01C1, 0x01EE, 0x0220, 0x0256, 0x0292, + 0x02D4, 0x031C, 0x036C, 0x03C3, 0x0424, 0x048E, 0x0502, 0x0583, + 0x0610, 0x06AB, 0x0756, 0x0812, 0x08E0, 0x09C3, 0x0ABD, 0x0BD0, + 0x0CFF, 0x0E4C, 0x0FBA, 0x114C, 0x1307, 0x14EE, 0x1706, 0x1954, + 0x1BDC, 0x1EA5, 0x21B6, 0x2515, 0x28CA, 0x2CDF, 0x315B, 0x364B, + 0x3BB9, 0x41B2, 0x4844, 0x4F7E, 0x5771, 0x602F, 0x69CE, 0x7462, 0x7FFF + }; + +RawChunkStream::RawChunkStream(bool stereo) { if (stereo) _stereo = 1; + else + _stereo = 0; + + init(); +} +void RawChunkStream::init() { _lastSample[0].index = 0; _lastSample[0].sample = 0; _lastSample[1].index = 0; _lastSample[1].sample = 0; +} - // Calculate the total playtime of the stream - if (stereo) - _playtime = Audio::Timestamp(0, _stream->size() / 2, rate); - else - _playtime = Audio::Timestamp(0, _stream->size(), rate); +RawChunkStream::RawChunk RawChunkStream::readNextChunk(Common::SeekableReadStream *stream) { + RawChunk tmp; + tmp.size = 0; + tmp.data = NULL; + + if (stream && (stream->size() == 0 || stream->eos())) + return tmp; + + tmp.size = (stream->size() - stream->pos()) * 2; + tmp.data = (int16 *)calloc(tmp.size, 1); + + readBuffer(tmp.data, stream, stream->size() - stream->pos()); + + return tmp; } -int RawZorkStream::readBuffer(int16 *buffer, const int numSamples) { - int bytesRead = 0; +int RawChunkStream::readBuffer(int16 *buffer, Common::SeekableReadStream *stream, const int numSamples) { + int32 bytesRead = 0; // 0: Left, 1: Right uint channel = 0; while (bytesRead < numSamples) { - byte encodedSample = _stream->readByte(); - if (_stream->eos()) { - _endOfData = true; + byte encodedSample = stream->readByte(); + if (stream->eos()) { return bytesRead; } bytesRead++; @@ -140,6 +134,91 @@ int RawZorkStream::readBuffer(int16 *buffer, const int numSamples) { // Increment and wrap the channel channel = (channel + 1) & _stereo; } + return bytesRead; +} + +const SoundParams RawZorkStream::_zNemSoundParamLookupTable[32] = {{'0', 0x1F40, false, false, false}, + {'1', 0x1F40, true, false, false}, + {'2', 0x1F40, false, false, true}, + {'3', 0x1F40, true, false, true}, + {'4', 0x2B11, false, false, false}, + {'5', 0x2B11, true, false, false}, + {'6', 0x2B11, false, false, true}, + {'7', 0x2B11, true, false, true}, + {'8', 0x5622, false, false, false}, + {'9', 0x5622, true, false, false}, + {'a', 0x5622, false, false, true}, + {'b', 0x5622, true, false, true}, + {'c', 0xAC44, false, false, false}, + {'d', 0xAC44, true, false, false}, + {'e', 0xAC44, false, false, true}, + {'f', 0xAC44, true, false, true}, + {'g', 0x1F40, false, true, false}, + {'h', 0x1F40, true, true, false}, + {'j', 0x1F40, false, true, true}, + {'k', 0x1F40, true, true, true}, + {'l', 0x2B11, false, true, false}, + {'m', 0x2B11, true, true, false}, + {'n', 0x2B11, false, true, true}, + {'p', 0x2B11, true, true, true}, + {'q', 0x5622, false, true, false}, + {'r', 0x5622, true, true, false}, + {'s', 0x5622, false, true, true}, + {'t', 0x5622, true, true, true}, + {'u', 0xAC44, false, true, false}, + {'v', 0xAC44, true, true, false}, + {'w', 0xAC44, false, true, true}, + {'x', 0xAC44, true, true, true} +}; + +const SoundParams RawZorkStream::_zgiSoundParamLookupTable[24] = {{'4', 0x2B11, false, false, false}, + {'5', 0x2B11, true, false, false}, + {'6', 0x2B11, false, false, true}, + {'7', 0x2B11, true, false, true}, + {'8', 0x5622, false, false, false}, + {'9', 0x5622, true, false, false}, + {'a', 0x5622, false, false, true}, + {'b', 0x5622, true, false, true}, + {'c', 0xAC44, false, false, false}, + {'d', 0xAC44, true, false, false}, + {'e', 0xAC44, false, false, true}, + {'f', 0xAC44, true, false, true}, + {'g', 0x2B11, false, true, false}, + {'h', 0x2B11, true, true, false}, + {'j', 0x2B11, false, true, true}, + {'k', 0x2B11, true, true, true}, + {'m', 0x5622, false, true, false}, + {'n', 0x5622, true, true, false}, + {'p', 0x5622, false, true, true}, + {'q', 0x5622, true, true, true}, + {'r', 0xAC44, false, true, false}, + {'s', 0xAC44, true, true, false}, + {'t', 0xAC44, false, true, true}, + {'u', 0xAC44, true, true, true} +}; + +RawZorkStream::RawZorkStream(uint32 rate, bool stereo, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream) + : _rate(rate), + _stereo(0), + _stream(stream, disposeStream), + _endOfData(false), + _streamReader(stereo) { + if (stereo) + _stereo = 1; + + // Calculate the total playtime of the stream + if (stereo) + _playtime = Audio::Timestamp(0, _stream->size() / 2, rate); + else + _playtime = Audio::Timestamp(0, _stream->size(), rate); +} + +int RawZorkStream::readBuffer(int16 *buffer, const int numSamples) { + + int32 bytesRead = _streamReader.readBuffer(buffer, _stream.get(), numSamples); + + if (_stream->eos()) + _endOfData = true; return bytesRead; } @@ -148,18 +227,15 @@ bool RawZorkStream::rewind() { _stream->seek(0, 0); _stream->clearErr(); _endOfData = false; - _lastSample[0].index = 0; - _lastSample[0].sample = 0; - _lastSample[1].index = 0; - _lastSample[1].sample = 0; + _streamReader.init(); return true; } Audio::RewindableAudioStream *makeRawZorkStream(Common::SeekableReadStream *stream, - int rate, - bool stereo, - DisposeAfterUse::Flag disposeAfterUse) { + int rate, + bool stereo, + DisposeAfterUse::Flag disposeAfterUse) { if (stereo) assert(stream->size() % 2 == 0); @@ -167,46 +243,45 @@ Audio::RewindableAudioStream *makeRawZorkStream(Common::SeekableReadStream *stre } Audio::RewindableAudioStream *makeRawZorkStream(const byte *buffer, uint32 size, - int rate, - bool stereo, - DisposeAfterUse::Flag disposeAfterUse) { + int rate, + bool stereo, + DisposeAfterUse::Flag disposeAfterUse) { return makeRawZorkStream(new Common::MemoryReadStream(buffer, size, disposeAfterUse), rate, stereo, DisposeAfterUse::YES); } Audio::RewindableAudioStream *makeRawZorkStream(const Common::String &filePath, ZVision *engine) { Common::File *file = new Common::File(); - assert(file->open(filePath)); + assert(engine->getSearchManager()->openFile(*file, filePath)); + + // Get the file name + Common::StringTokenizer tokenizer(filePath, "/\\"); + Common::String fileName; + while (!tokenizer.empty()) { + fileName = tokenizer.nextToken(); + } - Common::String fileName = getFileName(filePath); fileName.toLowercase(); - SoundParams soundParams = { ' ', 0, false, false }; - bool foundParams = false; - char fileIdentifier = (engine->getGameId() == GID_NEMESIS) ? fileName[6] : fileName[7]; + SoundParams soundParams = {}; if (engine->getGameId() == GID_NEMESIS) { - for (uint i = 0; i < ARRAYSIZE(RawZorkStream::_zNemSoundParamLookupTable); ++i) { - if (RawZorkStream::_zNemSoundParamLookupTable[i].identifier == fileIdentifier) { + for (int i = 0; i < 32; ++i) { + if (RawZorkStream::_zNemSoundParamLookupTable[i].identifier == (fileName[6])) soundParams = RawZorkStream::_zNemSoundParamLookupTable[i]; - foundParams = true; - } } } else if (engine->getGameId() == GID_GRANDINQUISITOR) { - for (uint i = 0; i < ARRAYSIZE(RawZorkStream::_zgiSoundParamLookupTable); ++i) { - if (RawZorkStream::_zgiSoundParamLookupTable[i].identifier == fileIdentifier) { + for (int i = 0; i < 24; ++i) { + if (RawZorkStream::_zgiSoundParamLookupTable[i].identifier == (fileName[7])) soundParams = RawZorkStream::_zgiSoundParamLookupTable[i]; - foundParams = true; - } } } - if (!foundParams) - error("Unable to find sound params for file '%s'. File identifier is '%c'", filePath.c_str(), fileIdentifier); - if (soundParams.packed) { return makeRawZorkStream(wrapBufferedSeekableReadStream(file, 2048, DisposeAfterUse::YES), soundParams.rate, soundParams.stereo, DisposeAfterUse::YES); } else { byte flags = 0; + if (soundParams.bits16) + flags |= Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN; if (soundParams.stereo) flags |= Audio::FLAG_STEREO; diff --git a/engines/zvision/sound/zork_raw.h b/engines/zvision/sound/zork_raw.h index ef98e3e1ef..0b408d818c 100644 --- a/engines/zvision/sound/zork_raw.h +++ b/engines/zvision/sound/zork_raw.h @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -25,7 +25,6 @@ #include "audio/audiostream.h" - namespace Common { class SeekableReadStream; } @@ -39,27 +38,19 @@ struct SoundParams { uint32 rate; bool stereo; bool packed; + bool bits16; }; /** - * This is a stream, which allows for playing raw ADPCM data from a stream. + * This is a ADPCM stream-reader, this class holds context for multi-chunk reading and no buffers. */ -class RawZorkStream : public Audio::RewindableAudioStream { +class RawChunkStream { public: - RawZorkStream(uint32 rate, bool stereo, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream); + RawChunkStream(bool stereo); - ~RawZorkStream() { + ~RawChunkStream() { } - -public: - static const SoundParams _zNemSoundParamLookupTable[6]; - static const SoundParams _zgiSoundParamLookupTable[5]; - private: - const int _rate; // Sample rate of stream - Audio::Timestamp _playtime; // Calculated total play time - Common::DisposablePtr<Common::SeekableReadStream> _stream; // Stream to read data from - bool _endOfData; // Whether the stream end has been reached uint _stereo; /** @@ -75,13 +66,58 @@ private: static const int32 _amplitudeLookupTable[89]; public: + + struct RawChunk { + int16 *data; + uint32 size; + }; + + void init(); + //Read next audio portion in new stream (needed for avi), return structure with buffer + RawChunk readNextChunk(Common::SeekableReadStream *stream); + //Read numSamples from stream to buffer + int readBuffer(int16 *buffer, Common::SeekableReadStream *stream, const int numSamples); +}; + +/** + * This is a stream, which allows for playing raw ADPCM data from a stream. + */ +class RawZorkStream : public Audio::RewindableAudioStream { +public: + RawZorkStream(uint32 rate, bool stereo, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream); + + ~RawZorkStream() { + } + +public: + static const SoundParams _zNemSoundParamLookupTable[32]; + static const SoundParams _zgiSoundParamLookupTable[24]; + +private: + const int _rate; // Sample rate of stream + Audio::Timestamp _playtime; // Calculated total play time + Common::DisposablePtr<Common::SeekableReadStream> _stream; // Stream to read data from + bool _endOfData; // Whether the stream end has been reached + uint _stereo; + + RawChunkStream _streamReader; + +public: int readBuffer(int16 *buffer, const int numSamples); - bool isStereo() const { return true; } - bool endOfData() const { return _endOfData; } + bool isStereo() const { + return _stereo; + } + bool endOfData() const { + return _endOfData; + } - int getRate() const { return _rate; } - Audio::Timestamp getLength() const { return _playtime; } + int getRate() const { + return _rate; + } + Audio::Timestamp getLength() const { + return _playtime; + } bool rewind(); }; @@ -96,9 +132,9 @@ public: * @return The new SeekableAudioStream (or 0 on failure). */ Audio::RewindableAudioStream *makeRawZorkStream(const byte *buffer, uint32 size, - int rate, - bool stereo, - DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES); + int rate, + bool stereo, + DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES); /** * Creates an audio stream, which plays from the given stream. @@ -109,9 +145,9 @@ Audio::RewindableAudioStream *makeRawZorkStream(const byte *buffer, uint32 size, * @return The new SeekableAudioStream (or 0 on failure). */ Audio::RewindableAudioStream *makeRawZorkStream(Common::SeekableReadStream *stream, - int rate, - bool stereo, - DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES); + int rate, + bool stereo, + DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES); Audio::RewindableAudioStream *makeRawZorkStream(const Common::String &filePath, ZVision *engine); diff --git a/engines/zvision/strings/string_manager.cpp b/engines/zvision/text/string_manager.cpp index 22331d8a24..1a04c67988 100644 --- a/engines/zvision/strings/string_manager.cpp +++ b/engines/zvision/text/string_manager.cpp @@ -21,18 +21,16 @@ */ #include "common/scummsys.h" - -#include "zvision/strings/string_manager.h" - -#include "zvision/fonts/truetype_font.h" - #include "common/file.h" #include "common/tokenizer.h" #include "common/debug.h" - #include "graphics/fontman.h" #include "graphics/colormasks.h" +#include "zvision/zvision.h" +#include "zvision/core/search_manager.h" +#include "zvision/text/string_manager.h" +#include "zvision/graphics/truetype_font.h" namespace ZVision { @@ -49,10 +47,25 @@ StringManager::~StringManager() { void StringManager::initialize(ZVisionGameId gameId) { if (gameId == GID_NEMESIS) { // TODO: Check this hardcoded filename against all versions of Nemesis - parseStrFile("nemesis.str"); + loadStrFile("nemesis.str"); } else if (gameId == GID_GRANDINQUISITOR) { // TODO: Check this hardcoded filename against all versions of Grand Inquisitor - parseStrFile("inquis.str"); + loadStrFile("inquis.str"); + } +} + +void StringManager::loadStrFile(const Common::String &fileName) { + Common::File file; + if (!_engine->getSearchManager()->openFile(file, fileName)) { + warning("%s does not exist. String parsing failed", fileName.c_str()); + return; + } + uint lineNumber = 0; + while (!file.eos()) { + _lines[lineNumber] = readWideLine(file); + + lineNumber++; + assert(lineNumber <= NUM_TEXT_LINES); } } @@ -252,4 +265,8 @@ StringManager::TextStyle StringManager::getTextStyle(uint stringNumber) { return _inGameText[stringNumber].fragments.front().style; } +const Common::String StringManager::getTextLine(uint stringNumber) { + return _lines[stringNumber]; +} + } // End of namespace ZVision diff --git a/engines/zvision/strings/string_manager.h b/engines/zvision/text/string_manager.h index af8324b890..8d6fbe67a6 100644 --- a/engines/zvision/strings/string_manager.h +++ b/engines/zvision/text/string_manager.h @@ -24,8 +24,7 @@ #define ZVISION_STRING_MANAGER_H #include "zvision/detection.h" -#include "zvision/fonts/truetype_font.h" - +#include "zvision/graphics/truetype_font.h" namespace Graphics { class FontManager; @@ -52,6 +51,13 @@ public: Common::String text; }; + enum { + ZVISION_STR_SAVEEXIST = 23, + ZVISION_STR_SAVED = 4, + ZVISION_STR_SAVEEMPTY = 21, + ZVISION_STR_EXITPROMT = 6 + }; + private: struct InGameText { Common::List<TextFragment> fragments; @@ -63,6 +69,8 @@ private: private: ZVision *_engine; + Common::String _lines[NUM_TEXT_LINES]; + InGameText _inGameText[NUM_TEXT_LINES]; Common::HashMap<Common::String, TruetypeFont *> _fonts; @@ -71,8 +79,10 @@ private: public: void initialize(ZVisionGameId gameId); StringManager::TextStyle getTextStyle(uint stringNumber); + const Common::String getTextLine(uint stringNumber); private: + void loadStrFile(const Common::String &fileName); void parseStrFile(const Common::String &fileName); void parseTag(const Common::String &tagString, uint lineNumber); diff --git a/engines/zvision/text/text.cpp b/engines/zvision/text/text.cpp new file mode 100644 index 0000000000..0ccca214d7 --- /dev/null +++ b/engines/zvision/text/text.cpp @@ -0,0 +1,544 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/scummsys.h" +#include "common/file.h" +#include "common/tokenizer.h" +#include "common/debug.h" +#include "common/rect.h" +#include "graphics/fontman.h" +#include "graphics/colormasks.h" +#include "graphics/surface.h" +#include "graphics/font.h" +#include "graphics/fonts/ttf.h" + +#include "zvision/text/text.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/graphics/truetype_font.h" +#include "zvision/scripting/script_manager.h" + +namespace ZVision { + +cTxtStyle::cTxtStyle() { + fontname = "Arial"; + blue = 255; + green = 255; + red = 255; + bold = false; + escapement = 0; + italic = false; + justify = TXT_JUSTIFY_LEFT; + newline = false; + size = 12; + skipcolor = false; + strikeout = false; + underline = false; + statebox = 0; + sharp = false; +} + +txtReturn cTxtStyle::parseStyle(const Common::String &strin, int16 ln) { + Common::String buf = Common::String(strin.c_str(), ln); + + int8 retval = TXT_RET_NOTHING; + + Common::StringTokenizer tokenizer(buf, " "); + Common::String token; + + while (!tokenizer.empty()) { + token = tokenizer.nextToken(); + + if (token.matchString("font", true)) { + token = tokenizer.nextToken(); + if (token[0] == '"') { + Common::String _tmp = Common::String(token.c_str() + 1); + + while (token.lastChar() != '"' && !tokenizer.empty()) { + token = tokenizer.nextToken(); + _tmp += " " + token; + } + + if (_tmp.lastChar() == '"') + _tmp.deleteLastChar(); + + fontname = _tmp; + } else { + if (!tokenizer.empty()) + fontname = token; + } + retval |= TXT_RET_FNTCHG; + + } else if (token.matchString("blue", true)) { + if (!tokenizer.empty()) { + token = tokenizer.nextToken(); + int32 tmp = atoi(token.c_str()); + if (blue != tmp) { + blue = tmp; + retval |= TXT_RET_FNTSTL; + } + } + } else if (token.matchString("red", true)) { + if (!tokenizer.empty()) { + token = tokenizer.nextToken(); + int32 tmp = atoi(token.c_str()); + if (red != tmp) { + red = tmp; + retval |= TXT_RET_FNTSTL; + } + } + } else if (token.matchString("green", true)) { + if (!tokenizer.empty()) { + token = tokenizer.nextToken(); + int32 tmp = atoi(token.c_str()); + if (green != tmp) { + green = tmp; + retval |= TXT_RET_FNTSTL; + } + } + } else if (token.matchString("newline", true)) { + if ((retval & TXT_RET_NEWLN) == 0) + newline = 0; + + newline++; + retval |= TXT_RET_NEWLN; + } else if (token.matchString("point", true)) { + if (!tokenizer.empty()) { + token = tokenizer.nextToken(); + int32 tmp = atoi(token.c_str()); + if (size != tmp) { + size = tmp; + retval |= TXT_RET_FNTCHG; + } + } + } else if (token.matchString("escapement", true)) { + if (!tokenizer.empty()) { + token = tokenizer.nextToken(); + int32 tmp = atoi(token.c_str()); + escapement = tmp; + } + } else if (token.matchString("italic", true)) { + if (!tokenizer.empty()) { + token = tokenizer.nextToken(); + if (token.matchString("on", true)) { + if (italic != true) { + italic = true; + retval |= TXT_RET_FNTSTL; + } + } else if (token.matchString("off", true)) { + if (italic != false) { + italic = false; + retval |= TXT_RET_FNTSTL; + } + } + } + } else if (token.matchString("underline", true)) { + if (!tokenizer.empty()) { + token = tokenizer.nextToken(); + if (token.matchString("on", true)) { + if (underline != true) { + underline = true; + retval |= TXT_RET_FNTSTL; + } + } else if (token.matchString("off", true)) { + if (underline != false) { + underline = false; + retval |= TXT_RET_FNTSTL; + } + } + } + } else if (token.matchString("strikeout", true)) { + if (!tokenizer.empty()) { + token = tokenizer.nextToken(); + if (token.matchString("on", true)) { + if (strikeout != true) { + strikeout = true; + retval |= TXT_RET_FNTSTL; + } + } else if (token.matchString("off", true)) { + if (strikeout != false) { + strikeout = false; + retval |= TXT_RET_FNTSTL; + } + } + } + } else if (token.matchString("bold", true)) { + if (!tokenizer.empty()) { + token = tokenizer.nextToken(); + if (token.matchString("on", true)) { + if (bold != true) { + bold = true; + retval |= TXT_RET_FNTSTL; + } + } else if (token.matchString("off", true)) { + if (bold != false) { + bold = false; + retval |= TXT_RET_FNTSTL; + } + } + } + } else if (token.matchString("skipcolor", true)) { + if (!tokenizer.empty()) { + token = tokenizer.nextToken(); + if (token.matchString("on", true)) { + skipcolor = true; + } else if (token.matchString("off", true)) { + skipcolor = false; + } + } + } else if (token.matchString("image", true)) { + // Not used + } else if (token.matchString("statebox", true)) { + if (!tokenizer.empty()) { + token = tokenizer.nextToken(); + statebox = atoi(token.c_str()); + retval |= TXT_RET_HASSTBOX; + } + } else if (token.matchString("justify", true)) { + if (!tokenizer.empty()) { + token = tokenizer.nextToken(); + if (token.matchString("center", true)) + justify = TXT_JUSTIFY_CENTER; + else if (token.matchString("left", true)) + justify = TXT_JUSTIFY_LEFT; + else if (token.matchString("right", true)) + justify = TXT_JUSTIFY_RIGHT; + } + } + } + return (txtReturn)retval; +} + +void cTxtStyle::readAllStyle(const Common::String &txt) { + int16 startTextPosition = -1; + int16 endTextPosition = -1; + + for (uint16 i = 0; i < txt.size(); i++) { + if (txt[i] == '<') + startTextPosition = i; + else if (txt[i] == '>') { + endTextPosition = i; + if (startTextPosition != -1) + if ((endTextPosition - startTextPosition - 1) > 0) + parseStyle(Common::String(txt.c_str() + startTextPosition + 1), endTextPosition - startTextPosition - 1); + } + + } +} + +void cTxtStyle::setFontStyle(StyledTTFont &font) { + uint tempStyle = 0; + + if (bold) + tempStyle |= StyledTTFont::STTF_BOLD; + + if (italic) + tempStyle |= StyledTTFont::STTF_ITALIC; + + if (underline) + tempStyle |= StyledTTFont::STTF_UNDERLINE; + + if (strikeout) + tempStyle |= StyledTTFont::STTF_STRIKEOUT; + + if (sharp) + tempStyle |= StyledTTFont::STTF_SHARP; + + font.setStyle(tempStyle); +} + +void cTxtStyle::setFont(StyledTTFont &font) { + uint tempStyle = 0; + + if (bold) + tempStyle |= StyledTTFont::STTF_BOLD; + + if (italic) + tempStyle |= StyledTTFont::STTF_ITALIC; + + if (underline) + tempStyle |= StyledTTFont::STTF_UNDERLINE; + + if (strikeout) + tempStyle |= StyledTTFont::STTF_STRIKEOUT; + + if (sharp) + tempStyle |= StyledTTFont::STTF_SHARP; + + font.loadFont(fontname, size, tempStyle); +} + +Graphics::Surface *TextRenderer::render(StyledTTFont &fnt, const Common::String &txt, cTxtStyle &style) { + style.setFontStyle(fnt); + uint32 clr = _engine->_pixelFormat.RGBToColor(style.red, style.green, style.blue); + return fnt.renderSolidText(txt, clr); +} + +void TextRenderer::drawTxtWithJustify(const Common::String &txt, StyledTTFont &fnt, uint32 color, Graphics::Surface &dst, int lineY, txtJustify justify) { + if (justify == TXT_JUSTIFY_LEFT) + fnt.drawString(&dst, txt, 0, lineY, dst.w, color, Graphics::kTextAlignLeft); + else if (justify == TXT_JUSTIFY_CENTER) + fnt.drawString(&dst, txt, 0, lineY, dst.w, color, Graphics::kTextAlignCenter); + else if (justify == TXT_JUSTIFY_RIGHT) + fnt.drawString(&dst, txt, 0, lineY, dst.w, color, Graphics::kTextAlignRight); +} + +int32 TextRenderer::drawTxt(const Common::String &txt, cTxtStyle &fontStyle, Graphics::Surface &dst) { + StyledTTFont font(_engine); + fontStyle.setFont(font); + + dst.fillRect(Common::Rect(dst.w, dst.h), 0); + + uint32 clr = _engine->_pixelFormat.RGBToColor(fontStyle.red, fontStyle.green, fontStyle.blue); + + int16 w; + + w = font.getStringWidth(txt); + + drawTxtWithJustify(txt, font, clr, dst, 0, fontStyle.justify); + + return w; +} + +void TextRenderer::drawTxtInOneLine(const Common::String &text, Graphics::Surface &dst) { + const int16 TXT_CFG_TEXTURES_LINES = 256; // For now I don't want remake it + const int TXT_CFG_TEXTURES_PER_LINE = 6; + cTxtStyle style, style2; + int16 startTextPosition = -1; + int16 endTextPosition = -1; + int16 i = 0; + int16 dx = 0, dy = 0; + int16 textPixelWidth; + int16 textPosition = 0; + Common::String buf; + Common::String buf2; + + Graphics::Surface *TxtSurfaces[TXT_CFG_TEXTURES_LINES][TXT_CFG_TEXTURES_PER_LINE]; + int16 currentline = 0, currentlineitm = 0; + + int TxtJustify[TXT_CFG_TEXTURES_LINES]; + int TxtPoint[TXT_CFG_TEXTURES_LINES]; + + for (int16 k = 0; k < TXT_CFG_TEXTURES_LINES; k++) { + TxtPoint[k] = 0; + for (int j = 0; j < TXT_CFG_TEXTURES_PER_LINE; j++) + TxtSurfaces[k][j] = NULL; + } + + int16 stringlen = text.size(); + + StyledTTFont font(_engine); + + style.setFont(font); + + int16 prevbufspace = 0, prevtxtspace = 0; + + while (i < stringlen) { + TxtJustify[currentline] = style.justify; + if (text[i] == '<') { + int16 ret = 0; + + startTextPosition = i; + while (i < stringlen && text[i] != '>') + i++; + endTextPosition = i; + if (startTextPosition != -1) + if ((endTextPosition - startTextPosition - 1) > 0) { + style2 = style; + ret = style.parseStyle(Common::String(text.c_str() + startTextPosition + 1), endTextPosition - startTextPosition - 1); + } + + if (ret & (TXT_RET_FNTCHG | TXT_RET_FNTSTL | TXT_RET_NEWLN)) { + if (buf.size() > 0) { + textPixelWidth = font.getStringWidth(buf); + + TxtSurfaces[currentline][currentlineitm] = render(font, buf, style2); + TxtPoint[currentline] = MAX(font.getFontHeight(), TxtPoint[currentline]); + + currentlineitm++; + + buf.clear(); + prevbufspace = 0; + textPosition = 0; + dx += textPixelWidth; + + } + if (ret & TXT_RET_FNTCHG) { + style.setFont(font); + } + if (ret & TXT_RET_FNTSTL) + style.setFontStyle(font); + + if (ret & TXT_RET_NEWLN) { + currentline++; + currentlineitm = 0; + dx = 0; + } + } + + if (ret & TXT_RET_HASSTBOX) { + Common::String buf3; + buf3.format("%d", _engine->getScriptManager()->getStateValue(style.statebox)); + buf += buf3; + textPosition += buf3.size(); + } + + } else { + + buf += text[i]; + textPosition++; + + if (text[i] == ' ') { + prevbufspace = textPosition - 1; + prevtxtspace = i; + } + + if (font.isLoaded()) { + textPixelWidth = font.getStringWidth(buf); + if (textPixelWidth + dx > dst.w) { + if (prevbufspace == 0) { + prevtxtspace = i; + prevbufspace = textPosition - 1; + } + buf2 = Common::String(buf.c_str(), prevbufspace + 1); + + if (buf2.size() > 0) { + TxtSurfaces[currentline][currentlineitm] = render(font, buf2, style); + TxtPoint[currentline] = MAX(font.getFontHeight(), TxtPoint[currentline]); + } + + buf.clear(); + i = prevtxtspace; + prevbufspace = 0; + textPosition = 0; + currentline++; + currentlineitm = 0; + dx = 0; + } + } + } + i++; + } + + if (buf.size() > 0) { + TxtSurfaces[currentline][currentlineitm] = render(font, buf, style); + TxtPoint[currentline] = MAX(font.getFontHeight(), TxtPoint[currentline]); + } + + dy = 0; + for (i = 0; i <= currentline; i++) { + int16 j = 0; + int16 width = 0; + while (TxtSurfaces[i][j] != NULL) { + width += TxtSurfaces[i][j]->w; + j++; + } + dx = 0; + for (int32 jj = 0; jj < j; jj++) { + if (TxtJustify[i] == TXT_JUSTIFY_LEFT) + _engine->getRenderManager()->blitSurfaceToSurface(*TxtSurfaces[i][jj], dst, dx, dy + TxtPoint[i] - TxtSurfaces[i][jj]->h, 0); + + else if (TxtJustify[i] == TXT_JUSTIFY_CENTER) + _engine->getRenderManager()->blitSurfaceToSurface(*TxtSurfaces[i][jj], dst, ((dst.w - width) / 2) + dx, dy + TxtPoint[i] - TxtSurfaces[i][jj]->h, 0); + + else if (TxtJustify[i] == TXT_JUSTIFY_RIGHT) + _engine->getRenderManager()->blitSurfaceToSurface(*TxtSurfaces[i][jj], dst, dst.w - width + dx, dy + TxtPoint[i] - TxtSurfaces[i][jj]->h, 0); + + dx += TxtSurfaces[i][jj]->w; + } + + dy += TxtPoint[i]; + } + + for (i = 0; i < TXT_CFG_TEXTURES_LINES; i++) + for (int32 j = 0; j < TXT_CFG_TEXTURES_PER_LINE; j++) + if (TxtSurfaces[i][j] != NULL) { + TxtSurfaces[i][j]->free(); + delete TxtSurfaces[i][j]; + } +} + +Common::String readWideLine(Common::SeekableReadStream &stream) { + Common::String asciiString; + + while (!stream.eos()) { + uint32 value = stream.readUint16LE(); + // Check for CRLF + if (value == 0x0A0D) { + // Read in the extra NULL char + stream.readByte(); // \0 + // End of the line. Break + break; + } + + // Crush each octet pair to a UTF-8 sequence + if (value < 0x80) { + asciiString += (char)(value & 0x7F); + } else if (value >= 0x80 && value < 0x800) { + asciiString += (char)(0xC0 | ((value >> 6) & 0x1F)); + asciiString += (char)(0x80 | (value & 0x3F)); + } else if (value >= 0x800 && value < 0x10000) { + asciiString += (char)(0xE0 | ((value >> 12) & 0xF)); + asciiString += (char)(0x80 | ((value >> 6) & 0x3F)); + asciiString += (char)(0x80 | (value & 0x3F)); + } else if (value >= 0x10000 && value < 0x200000) { + asciiString += (char)(0xF0); + asciiString += (char)(0x80 | ((value >> 12) & 0x3F)); + asciiString += (char)(0x80 | ((value >> 6) & 0x3F)); + asciiString += (char)(0x80 | (value & 0x3F)); + } + } + + return asciiString; +} + +int8 getUtf8CharSize(char chr) { + if ((chr & 0x80) == 0) + return 1; + else if ((chr & 0xE0) == 0xC0) + return 2; + else if ((chr & 0xF0) == 0xE0) + return 3; + else if ((chr & 0xF8) == 0xF0) + return 4; + else if ((chr & 0xFC) == 0xF8) + return 5; + else if ((chr & 0xFE) == 0xFC) + return 6; + + return 1; +} + +uint16 readUtf8Char(const char *chr) { + uint16 result = 0; + if ((chr[0] & 0x80) == 0) + result = chr[0]; + else if ((chr[0] & 0xE0) == 0xC0) + result = ((chr[0] & 0x1F) << 6) | (chr[1] & 0x3F); + else if ((chr[0] & 0xF0) == 0xE0) + result = ((chr[0] & 0x0F) << 12) | ((chr[1] & 0x3F) << 6) | (chr[2] & 0x3F); + else + result = chr[0]; + + return result; +} + +} // End of namespace ZVision diff --git a/engines/zvision/text/text.h b/engines/zvision/text/text.h new file mode 100644 index 0000000000..01c3fd760c --- /dev/null +++ b/engines/zvision/text/text.h @@ -0,0 +1,99 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * + */ + +#ifndef ZVISION_TEXT_H +#define ZVISION_TEXT_H + +#include "zvision/detection.h" +#include "zvision/graphics/truetype_font.h" +#include "zvision/zvision.h" + +namespace Graphics { +class FontManager; +} + +namespace ZVision { + +class ZVision; + +enum txtJustify { + TXT_JUSTIFY_CENTER = 0, + TXT_JUSTIFY_LEFT = 1, + TXT_JUSTIFY_RIGHT = 2 +}; + +enum txtReturn { + TXT_RET_NOTHING = 0x0, + TXT_RET_FNTCHG = 0x1, + TXT_RET_FNTSTL = 0x2, + TXT_RET_NEWLN = 0x4, + TXT_RET_HASSTBOX = 0x8 +}; + +class cTxtStyle { +public: + cTxtStyle(); + txtReturn parseStyle(const Common::String &strin, int16 len); + void readAllStyle(const Common::String &txt); + void setFontStyle(StyledTTFont &font); + void setFont(StyledTTFont &font); + +public: + Common::String fontname; + txtJustify justify; // 0 - center, 1-left, 2-right + int16 size; + uint8 red; // 0-255 + uint8 green; // 0-255 + uint8 blue; // 0-255 + int8 newline; + int8 escapement; + bool italic; + bool bold; + bool underline; + bool strikeout; + bool skipcolor; + int32 statebox; + bool sharp; + // char image ?? +}; + +class TextRenderer { +public: + TextRenderer(ZVision *engine): _engine(engine) {}; + + void drawTxtWithJustify(const Common::String &txt, StyledTTFont &fnt, uint32 color, Graphics::Surface &dst, int lineY, txtJustify justify); + int32 drawTxt(const Common::String &txt, cTxtStyle &fontStyle, Graphics::Surface &dst); + Graphics::Surface *render(StyledTTFont &fnt, const Common::String &txt, cTxtStyle &style); + void drawTxtInOneLine(const Common::String &txt, Graphics::Surface &dst); + +private: + ZVision *_engine; +}; + +Common::String readWideLine(Common::SeekableReadStream &stream); +int8 getUtf8CharSize(char chr); +uint16 readUtf8Char(const char *chr); + +} // End of namespace ZVision + +#endif diff --git a/engines/zvision/utility/clock.cpp b/engines/zvision/utility/clock.cpp index 45ab23ab65..0e800a2031 100644 --- a/engines/zvision/utility/clock.cpp +++ b/engines/zvision/utility/clock.cpp @@ -26,7 +26,6 @@ #include "common/system.h" - namespace ZVision { Clock::Clock(OSystem *system) diff --git a/engines/zvision/utility/clock.h b/engines/zvision/utility/clock.h index 6ae0f86161..9a50116a8c 100644 --- a/engines/zvision/utility/clock.h +++ b/engines/zvision/utility/clock.h @@ -52,13 +52,17 @@ public: * * @return Delta time since the last frame (in milliseconds) */ - uint32 getDeltaTime() const { return _deltaTime; } + uint32 getDeltaTime() const { + return _deltaTime; + } /** * Get the time from the program starting to the last update() call * * @return Time from program start to last update() call (in milliseconds) */ - uint32 getLastMeasuredTime() { return _lastTime; } + uint32 getLastMeasuredTime() { + return _lastTime; + } /** * Pause the clock. Any future delta times will take this pause into account. diff --git a/engines/zvision/utility/lzss_read_stream.cpp b/engines/zvision/utility/lzss_read_stream.cpp index e094188ef6..bbe6e35f76 100644 --- a/engines/zvision/utility/lzss_read_stream.cpp +++ b/engines/zvision/utility/lzss_read_stream.cpp @@ -24,14 +24,13 @@ #include "zvision/utility/lzss_read_stream.h" - namespace ZVision { LzssReadStream::LzssReadStream(Common::SeekableReadStream *source) - : _source(source), - // It's convention to set the starting cursor position to blockSize - 16 - _windowCursor(0x0FEE), - _eosFlag(false) { + : _source(source), + // It's convention to set the starting cursor position to blockSize - 16 + _windowCursor(0x0FEE), + _eosFlag(false) { // Clear the window to null memset(_window, 0, BLOCK_SIZE); } @@ -69,9 +68,9 @@ uint32 LzssReadStream::decompressBytes(byte *destination, uint32 numberOfBytes) } uint16 length = (high & 0xF) + 2; - uint16 offset = low | ((high & 0xF0)<<4); + uint16 offset = low | ((high & 0xF0) << 4); - for(int j = 0; j <= length; ++j) { + for (int j = 0; j <= length; ++j) { byte temp = _window[(offset + j) & 0xFFF]; _window[_windowCursor] = temp; destination[destinationCursor++] = temp; diff --git a/engines/zvision/utility/lzss_read_stream.h b/engines/zvision/utility/lzss_read_stream.h index b51cf3905f..1420621f13 100644 --- a/engines/zvision/utility/lzss_read_stream.h +++ b/engines/zvision/utility/lzss_read_stream.h @@ -26,7 +26,6 @@ #include "common/stream.h" #include "common/array.h" - namespace Common { class SeekableReadStream; } @@ -64,7 +63,7 @@ private: * * @param numberOfBytes How many bytes to decompress. This is a count of source bytes, not destination bytes */ - uint32 decompressBytes(byte* destination, uint32 numberOfBytes); + uint32 decompressBytes(byte *destination, uint32 numberOfBytes); }; } diff --git a/engines/zvision/utility/single_value_container.cpp b/engines/zvision/utility/single_value_container.cpp deleted file mode 100644 index e609474285..0000000000 --- a/engines/zvision/utility/single_value_container.cpp +++ /dev/null @@ -1,348 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#include "common/scummsys.h" - -#include "zvision/utility/single_value_container.h" - -#include "common/textconsole.h" -#include "common/str.h" - - -namespace ZVision { - -SingleValueContainer::SingleValueContainer(ValueType type) : _objectType(type) { } - -SingleValueContainer::SingleValueContainer(bool value) : _objectType(BOOL) { - _value.boolVal = value; -} - -SingleValueContainer::SingleValueContainer(byte value) : _objectType(BYTE) { - _value.byteVal = value; -} - -SingleValueContainer::SingleValueContainer(int16 value) : _objectType(INT16) { - _value.int16Val = value; -} - -SingleValueContainer::SingleValueContainer(uint16 value) : _objectType(UINT16) { - _value.uint16Val = value; -} - -SingleValueContainer::SingleValueContainer(int32 value) : _objectType(INT32) { - _value.int32Val = value; -} - -SingleValueContainer::SingleValueContainer(uint32 value) : _objectType(UINT32) { - _value.uint32Val = value; -} - -SingleValueContainer::SingleValueContainer(float value) : _objectType(FLOAT) { - _value.floatVal = value; -} - -SingleValueContainer::SingleValueContainer(double value) : _objectType(DOUBLE) { - _value.doubleVal = value; -} - -SingleValueContainer::SingleValueContainer(Common::String value) : _objectType(BYTE) { - _value.stringVal = new char[value.size() + 1]; - memcpy(_value.stringVal, value.c_str(), value.size() + 1); -} - -SingleValueContainer::SingleValueContainer(const SingleValueContainer &other) { - _objectType = other._objectType; - - switch (_objectType) { - case BOOL: - _value.boolVal = other._value.boolVal; - break; - case BYTE: - _value.byteVal = other._value.byteVal; - break; - case INT16: - _value.int16Val = other._value.int16Val; - break; - case UINT16: - _value.uint16Val = other._value.uint16Val; - break; - case INT32: - _value.int32Val = other._value.int32Val; - break; - case UINT32: - _value.uint32Val = other._value.uint32Val; - break; - case FLOAT: - _value.floatVal = other._value.floatVal; - break; - case DOUBLE: - _value.doubleVal = other._value.doubleVal; - break; - case STRING: - uint32 length = strlen(other._value.stringVal); - _value.stringVal = new char[length + 1]; - memcpy(_value.stringVal, other._value.stringVal, length + 1); - break; - } -} - -SingleValueContainer::~SingleValueContainer() { - deleteCharPointer(); -} - -void SingleValueContainer::deleteCharPointer() { - if (_objectType == STRING) - delete[] _value.stringVal; -} - - -SingleValueContainer &SingleValueContainer::operator=(const bool &rhs) { - if (_objectType == BOOL) { - _value.boolVal = rhs; - return *this; - } - - deleteCharPointer(); - _objectType = BOOL; - _value.boolVal = rhs; - - return *this; -} - -SingleValueContainer &SingleValueContainer::operator=(const byte &rhs) { - if (_objectType == BYTE) { - _value.byteVal = rhs; - return *this; - } - - deleteCharPointer(); - _objectType = BYTE; - _value.byteVal = rhs; - - return *this; -} - -SingleValueContainer &SingleValueContainer::operator=(const int16 &rhs) { - if (_objectType == INT16) { - _value.int16Val = rhs; - return *this; - } - - deleteCharPointer(); - _objectType = INT16; - _value.int16Val = rhs; - - return *this; -} - -SingleValueContainer &SingleValueContainer::operator=(const uint16 &rhs) { - if (_objectType == UINT16) { - _value.uint16Val = rhs; - return *this; - } - - deleteCharPointer(); - _objectType = UINT16; - _value.uint16Val = rhs; - - return *this; -} - -SingleValueContainer &SingleValueContainer::operator=(const int32 &rhs) { - if (_objectType == INT32) { - _value.int32Val = rhs; - return *this; - } - - deleteCharPointer(); - _objectType = INT32; - _value.int32Val = rhs; - - return *this; -} - -SingleValueContainer &SingleValueContainer::operator=(const uint32 &rhs) { - if (_objectType == UINT32) { - _value.uint32Val = rhs; - return *this; - } - - deleteCharPointer(); - _objectType = UINT32; - _value.uint32Val = rhs; - - return *this; -} - -SingleValueContainer &SingleValueContainer::operator=(const float &rhs) { - if (_objectType == FLOAT) { - _value.floatVal = rhs; - return *this; - } - - deleteCharPointer(); - _objectType = FLOAT; - _value.floatVal = rhs; - - return *this; -} - -SingleValueContainer &SingleValueContainer::operator=(const double &rhs) { - if (_objectType == DOUBLE) { - _value.doubleVal = rhs; - return *this; - } - - deleteCharPointer(); - _objectType = DOUBLE; - _value.doubleVal = rhs; - - return *this; -} - -SingleValueContainer &SingleValueContainer::operator=(const Common::String &rhs) { - if (_objectType != STRING) { - _objectType = STRING; - _value.stringVal = new char[rhs.size() + 1]; - memcpy(_value.stringVal, rhs.c_str(), rhs.size() + 1); - - return *this; - } - - uint32 length = strlen(_value.stringVal); - if (length <= rhs.size() + 1) { - memcpy(_value.stringVal, rhs.c_str(), rhs.size() + 1); - } else { - delete[] _value.stringVal; - _value.stringVal = new char[rhs.size() + 1]; - memcpy(_value.stringVal, rhs.c_str(), rhs.size() + 1); - } - - return *this; -} - -SingleValueContainer &SingleValueContainer::operator=(const SingleValueContainer &rhs) { - switch (_objectType) { - case BOOL: - return operator=(rhs._value.boolVal); - case BYTE: - return operator=(rhs._value.byteVal); - case INT16: - return operator=(rhs._value.int16Val); - case UINT16: - return operator=(rhs._value.uint16Val); - case INT32: - return operator=(rhs._value.int32Val); - case UINT32: - return operator=(rhs._value.uint32Val); - case FLOAT: - return operator=(rhs._value.floatVal); - case DOUBLE: - return operator=(rhs._value.doubleVal); - case STRING: - uint32 length = strlen(rhs._value.stringVal); - - _value.stringVal = new char[length + 1]; - memcpy(_value.stringVal, rhs._value.stringVal, length + 1); - - return *this; - } - - return *this; -} - - -bool SingleValueContainer::getBoolValue(bool *returnValue) const { - if (_objectType != BOOL) { - warning("'Object' is not storing a bool."); - return false; - } - - *returnValue = _value.boolVal; - return true; -} - -bool SingleValueContainer::getByteValue(byte *returnValue) const { - if (_objectType != BYTE) - warning("'Object' is not storing a byte."); - - *returnValue = _value.byteVal; - return true; -} - -bool SingleValueContainer::getInt16Value(int16 *returnValue) const { - if (_objectType != INT16) - warning("'Object' is not storing an int16."); - - *returnValue = _value.int16Val; - return true; -} - -bool SingleValueContainer::getUInt16Value(uint16 *returnValue) const { - if (_objectType != UINT16) - warning("'Object' is not storing a uint16."); - - *returnValue = _value.uint16Val; - return true; -} - -bool SingleValueContainer::getInt32Value(int32 *returnValue) const { - if (_objectType != INT32) - warning("'Object' is not storing an int32."); - - *returnValue = _value.int32Val; - return true; -} - -bool SingleValueContainer::getUInt32Value(uint32 *returnValue) const { - if (_objectType != UINT32) - warning("'Object' is not storing a uint32."); - - *returnValue = _value.uint32Val; - return true; -} - -bool SingleValueContainer::getFloatValue(float *returnValue) const { - if (_objectType != FLOAT) - warning("'Object' is not storing a float."); - - *returnValue = _value.floatVal; - return true; -} - -bool SingleValueContainer::getDoubleValue(double *returnValue) const { - if (_objectType != DOUBLE) - warning("'Object' is not storing a double."); - - *returnValue = _value.doubleVal; - return true; -} - -bool SingleValueContainer::getStringValue(Common::String *returnValue) const { - if (_objectType != STRING) - warning("'Object' is not storing a Common::String."); - - *returnValue = _value.stringVal; - return true; -} - -} // End of namespace ZVision diff --git a/engines/zvision/utility/single_value_container.h b/engines/zvision/utility/single_value_container.h deleted file mode 100644 index 951383661a..0000000000 --- a/engines/zvision/utility/single_value_container.h +++ /dev/null @@ -1,183 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#ifndef ZVISION_SINGLE_VALUE_CONTAINER_H -#define ZVISION_SINGLE_VALUE_CONTAINER_H - -namespace Common { -class String; -} - -namespace ZVision { - -/** - * A generic single value storage class. It is useful for storing different - * value types in a single List, Hashmap, etc. - */ -class SingleValueContainer { -public: - enum ValueType { - BOOL, - BYTE, - INT16, - UINT16, - INT32, - UINT32, - FLOAT, - DOUBLE, - STRING - }; - - // Constructors - explicit SingleValueContainer(ValueType type); - explicit SingleValueContainer(bool value); - explicit SingleValueContainer(byte value); - explicit SingleValueContainer(int16 value); - explicit SingleValueContainer(uint16 value); - explicit SingleValueContainer(int32 value); - explicit SingleValueContainer(uint32 value); - explicit SingleValueContainer(float value); - explicit SingleValueContainer(double value); - explicit SingleValueContainer(Common::String value); - - // Copy constructor - explicit SingleValueContainer(const SingleValueContainer& other); - - // Destructor - ~SingleValueContainer(); - -private: - ValueType _objectType; - - union { - bool boolVal; - byte byteVal; - int16 int16Val; - uint16 uint16Val; - int32 int32Val; - uint32 uint32Val; - float floatVal; - double doubleVal; - char *stringVal; - } _value; - -public: - SingleValueContainer &operator=(const bool &rhs); - SingleValueContainer &operator=(const byte &rhs); - SingleValueContainer &operator=(const int16 &rhs); - SingleValueContainer &operator=(const uint16 &rhs); - SingleValueContainer &operator=(const int32 &rhs); - SingleValueContainer &operator=(const uint32 &rhs); - SingleValueContainer &operator=(const float &rhs); - SingleValueContainer &operator=(const double &rhs); - SingleValueContainer &operator=(const Common::String &rhs); - - SingleValueContainer& operator=(const SingleValueContainer &rhs); - - /** - * Retrieve a bool from the container. If the container is not storing a - * bool, this will return false and display a warning(). - * - * @param returnValue Pointer to where you want the value stored - * @return Value indicating whether the value assignment was successful - */ - bool getBoolValue(bool *returnValue) const; - /** - * Retrieve a byte from the container. If the container is not storing a - * byte, this will return false and display a warning(). - * - * @param returnValue Pointer to where you want the value stored - * @return Value indicating whether the value assignment was successful - */ - bool getByteValue(byte *returnValue) const; - /** - * Retrieve an int16 from the container. If the container is not storing an - * int16, this will return false and display a warning(). - * - * @param returnValue Pointer to where you want the value stored - * @return Value indicating whether the value assignment was successful - */ - bool getInt16Value(int16 *returnValue) const; - /** - * Retrieve a uint16 from the container. If the container is not storing a - * uint16, this will return false and display a warning(). - * - * @param returnValue Pointer to where you want the value stored - * @return Value indicating whether the value assignment was successful - */ - bool getUInt16Value(uint16 *returnValue) const; - /** - * Retrieve an int32 from the container. If the container is not storing an - * int32, this will return false and display a warning(). - * - * @param returnValue Pointer to where you want the value stored - * @return Value indicating whether the value assignment was successful - */ - bool getInt32Value(int32 *returnValue) const; - /** - * Retrieve a uint32 from the container. If the container is not storing a - * uint32, this will return false and display a warning(). - * - * @param returnValue Pointer to where you want the value stored - * @return Value indicating whether the value assignment was successful - */ - bool getUInt32Value(uint32 *returnValue) const; - /** - * Retrieve a float from the container. If the container is not storing a - * float, this will return false and display a warning(). - * - * @param returnValue Pointer to where you want the value stored - * @return Value indicating whether the value assignment was successful - */ - bool getFloatValue(float *returnValue) const; - /** - * Retrieve a double from the container. If the container is not storing a - * double, this will return false and display a warning(). - * - * @param returnValue Pointer to where you want the value stored - * @return Value indicating whether the value assignment was successful - */ - bool getDoubleValue(double *returnValue) const; - /** - * Retrieve a String from the container. If the container is not storing a - * string, this will return false and display a warning(). - * - * Caution: Strings are internally stored as char[]. getStringValue uses - * Common::String::operator=(char *) to do the assigment, which uses both - * strlen() AND memmove(). - * - * @param returnValue Pointer to where you want the value stored - * @return Value indicating whether the value assignment was successful - */ - bool getStringValue(Common::String *returnValue) const; - -private: - /** - * Helper method for destruction and assignment. It checks to see - * if the char pointer is being used, and if so calls delete on it - */ - void deleteCharPointer(); -}; - -} // End of namespace ZVision - -#endif diff --git a/engines/zvision/utility/utility.cpp b/engines/zvision/utility/utility.cpp index 2079d23733..2388fe826e 100644 --- a/engines/zvision/utility/utility.cpp +++ b/engines/zvision/utility/utility.cpp @@ -30,28 +30,8 @@ #include "common/tokenizer.h" #include "common/file.h" - namespace ZVision { -void writeFileContentsToFile(const Common::String &sourceFile, const Common::String &destFile) { - Common::File f; - if (!f.open(sourceFile)) { - return; - } - - byte* buffer = new byte[f.size()]; - f.read(buffer, f.size()); - - Common::DumpFile dumpFile; - dumpFile.open(destFile); - - dumpFile.write(buffer, f.size()); - dumpFile.flush(); - dumpFile.close(); - - delete[] buffer; -} - void trimCommentsAndWhiteSpace(Common::String *string) { for (int i = string->size() - 1; i >= 0; i--) { if ((*string)[i] == '#') { @@ -63,10 +43,10 @@ void trimCommentsAndWhiteSpace(Common::String *string) { } void tryToDumpLine(const Common::String &key, - Common::String &line, - Common::HashMap<Common::String, byte> *count, - Common::HashMap<Common::String, bool> *fileAlreadyUsed, - Common::DumpFile &output) { + Common::String &line, + Common::HashMap<Common::String, byte> *count, + Common::HashMap<Common::String, bool> *fileAlreadyUsed, + Common::DumpFile &output) { const byte numberOfExamplesPerType = 8; if ((*count)[key] < numberOfExamplesPerType && !(*fileAlreadyUsed)[key]) { @@ -77,161 +57,4 @@ void tryToDumpLine(const Common::String &key, } } -void dumpEveryResultAction(const Common::String &destFile) { - Common::HashMap<Common::String, byte> count; - Common::HashMap<Common::String, bool> fileAlreadyUsed; - - Common::DumpFile output; - output.open(destFile); - - // Find scr files - Common::ArchiveMemberList list; - SearchMan.listMatchingMembers(list, "*.scr"); - - for (Common::ArchiveMemberList::iterator iter = list.begin(); iter != list.end(); ++iter) { - Common::SeekableReadStream *stream = (*iter)->createReadStream(); - - Common::String line = stream->readLine(); - trimCommentsAndWhiteSpace(&line); - - while (!stream->eos()) { - if (line.matchString("*:add*", true)) { - tryToDumpLine("add", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:animplay*", true)) { - tryToDumpLine("animplay", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:animpreload*", true)) { - tryToDumpLine("animpreload", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:animunload*", true)) { - tryToDumpLine("animunload", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:attenuate*", true)) { - tryToDumpLine("attenuate", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:assign*", true)) { - tryToDumpLine("assign", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:change_location*", true)) { - tryToDumpLine("change_location", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:crossfade*", true) && !fileAlreadyUsed["add"]) { - tryToDumpLine("crossfade", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:debug*", true)) { - tryToDumpLine("debug", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:delay_render*", true)) { - tryToDumpLine("delay_render", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:disable_control*", true)) { - tryToDumpLine("disable_control", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:disable_venus*", true)) { - tryToDumpLine("disable_venus", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:display_message*", true)) { - tryToDumpLine("display_message", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:dissolve*", true)) { - tryToDumpLine("dissolve", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:distort*", true)) { - tryToDumpLine("distort", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:enable_control*", true)) { - tryToDumpLine("enable_control", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:flush_mouse_events*", true)) { - tryToDumpLine("flush_mouse_events", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:inventory*", true)) { - tryToDumpLine("inventory", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:kill*", true)) { - tryToDumpLine("kill", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:menu_bar_enable*", true)) { - tryToDumpLine("menu_bar_enable", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:music*", true)) { - tryToDumpLine("music", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:pan_track*", true)) { - tryToDumpLine("pan_track", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:playpreload*", true)) { - tryToDumpLine("playpreload", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:preferences*", true)) { - tryToDumpLine("preferences", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:quit*", true)) { - tryToDumpLine("quit", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:random*", true)) { - tryToDumpLine("random", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:region*", true)) { - tryToDumpLine("region", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:restore_game*", true)) { - tryToDumpLine("restore_game", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:rotate_to*", true)) { - tryToDumpLine("rotate_to", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:save_game*", true)) { - tryToDumpLine("save_game", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:set_partial_screen*", true)) { - tryToDumpLine("set_partial_screen", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:set_screen*", true)) { - tryToDumpLine("set_screen", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:set_venus*", true)) { - tryToDumpLine("set_venus", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:stop*", true)) { - tryToDumpLine("stop", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:streamvideo*", true)) { - tryToDumpLine("streamvideo", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:syncsound*", true)) { - tryToDumpLine("syncsound", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:timer*", true)) { - tryToDumpLine("timer", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:ttytext*", true)) { - tryToDumpLine("ttytext", line, &count, &fileAlreadyUsed, output); - } else if (line.matchString("*:universe_music*", true)) { - tryToDumpLine("universe_music", line, &count, &fileAlreadyUsed, output); - } - - line = stream->readLine(); - trimCommentsAndWhiteSpace(&line); - } - - for (Common::HashMap<Common::String, bool>::iterator fileUsedIter = fileAlreadyUsed.begin(); fileUsedIter != fileAlreadyUsed.end(); ++fileUsedIter) { - fileUsedIter->_value = false; - } - } - - output.close(); -} - -Common::String getFileName(const Common::String &fullPath) { - Common::StringTokenizer tokenizer(fullPath, "/\\"); - Common::String token; - while (!tokenizer.empty()) { - token = tokenizer.nextToken(); - } - - return token; -} - -void convertRawToWav(const Common::String &inputFile, ZVision *engine, const Common::String &outputFile) { - Common::File file; - if (!file.open(inputFile)) - return; - - Audio::AudioStream *audioStream = makeRawZorkStream(inputFile, engine); - - Common::DumpFile output; - output.open(outputFile); - - output.writeUint32BE(MKTAG('R', 'I', 'F', 'F')); - output.writeUint32LE(file.size() * 2 + 36); - output.writeUint32BE(MKTAG('W', 'A', 'V', 'E')); - output.writeUint32BE(MKTAG('f', 'm', 't', ' ')); - output.writeUint32LE(16); - output.writeUint16LE(1); - uint16 numChannels; - if (audioStream->isStereo()) { - numChannels = 2; - output.writeUint16LE(2); - } else { - numChannels = 1; - output.writeUint16LE(1); - } - output.writeUint32LE(audioStream->getRate()); - output.writeUint32LE(audioStream->getRate() * numChannels * 2); - output.writeUint16LE(numChannels * 2); - output.writeUint16LE(16); - output.writeUint32BE(MKTAG('d', 'a', 't', 'a')); - output.writeUint32LE(file.size() * 2); - int16 *buffer = new int16[file.size()]; - audioStream->readBuffer(buffer, file.size()); - output.write(buffer, file.size() * 2); - - delete[] buffer; -} - } // End of namespace ZVision diff --git a/engines/zvision/utility/utility.h b/engines/zvision/utility/utility.h index 063d4c0663..0ca26b968d 100644 --- a/engines/zvision/utility/utility.h +++ b/engines/zvision/utility/utility.h @@ -25,7 +25,6 @@ #include "common/array.h" - namespace Common { class String; } @@ -35,15 +34,6 @@ namespace ZVision { class ZVision; /** - * Opens the sourceFile utilizing Common::File (aka SearchMan) and writes the - * contents to destFile. destFile is created in the working directory - * - * @param sourceFile The 'file' you want the contents of - * @param destFile The name of the file where the content will be written to - */ -void writeFileContentsToFile(const Common::String &sourceFile, const Common::String &destFile); - -/** * Removes any line comments using '#' as a sequence start. * Then removes any trailing and leading 'whitespace' using String::trim() * Note: String::trim uses isspace() to determine what is whitespace and what is not. @@ -52,63 +42,6 @@ void writeFileContentsToFile(const Common::String &sourceFile, const Common::Str */ void trimCommentsAndWhiteSpace(Common::String *string); -/** - * Searches through all the .scr files and dumps 'numberOfExamplesPerType' examples of each type of ResultAction - * ZVision::initialize() must have been called before this function can be used. - * - * @param destFile Where to write the examples - */ -void dumpEveryResultAction(const Common::String &destFile); - -/** - * Removes all duplicate entries from container. Relative order will be preserved. - * - * @param container The Array to remove duplicate entries from - */ -template<class T> -void removeDuplicateEntries(Common::Array<T> &container) { - // Length of modified array - uint newLength = 1; - uint j; - - for(uint i = 1; i < container.size(); i++) { - for(j = 0; j < newLength; j++) { - if (container[i] == container[j]) { - break; - } - } - - // If none of the values in index[0..j] of container are the same as array[i], - // then copy the current value to corresponding new position in array - if (j == newLength) { - container[newLength++] = container[i]; - } - } - - // Actually remove the unneeded space - while (container.size() < newLength) { - container.pop_back(); - } -} - -/** - * Gets the name of the file (including extension). Forward or back slashes - * are interpreted as directory changes - * - * @param fullPath A full or partial path to the file. Ex: folderOne/folderTwo/file.txt - * @return The name of the file without any preceding directories. Ex: file.txt - */ -Common::String getFileName(const Common::String &fullPath); - -/** - * Converts a ZVision .RAW file to a .WAV - * The .WAV will be created in the working directory and will overwrite any existing file - * - * @param inputFile The path to the input .RAW file - * @param outputFile The name of the output .WAV file - */ -void convertRawToWav(const Common::String &inputFile, ZVision *engine, const Common::String &outputFile); - } // End of namespace ZVision #endif diff --git a/engines/zvision/archives/zfs_archive.cpp b/engines/zvision/utility/zfs_archive.cpp index d18cc9966b..13b0168e1c 100644 --- a/engines/zvision/archives/zfs_archive.cpp +++ b/engines/zvision/utility/zfs_archive.cpp @@ -21,13 +21,12 @@ */ #include "common/scummsys.h" - -#include "zvision/archives/zfs_archive.h" - #include "common/memstream.h" #include "common/debug.h" #include "common/file.h" +#include "zvision/utility/zfs_archive.h" + namespace ZVision { ZfsArchive::ZfsArchive(const Common::String &fileName) : _fileName(fileName) { @@ -52,7 +51,7 @@ ZfsArchive::ZfsArchive(const Common::String &fileName, Common::SeekableReadStrea ZfsArchive::~ZfsArchive() { debug(1, "ZfsArchive Destructor Called"); ZfsEntryHeaderMap::iterator it = _entryHeaders.begin(); - for ( ; it != _entryHeaders.end(); ++it) { + for (; it != _entryHeaders.end(); ++it) { delete it->_value; } } @@ -138,7 +137,7 @@ Common::SeekableReadStream *ZfsArchive::createReadStreamForMember(const Common:: zfsArchive.seek(entryHeader->offset); // This *HAS* to be malloc (not new[]) because MemoryReadStream uses free() to free the memory - byte* buffer = (byte *)malloc(entryHeader->size); + byte *buffer = (byte *)malloc(entryHeader->size); zfsArchive.read(buffer, entryHeader->size); // Decrypt the data in place if (_header.xorKey != 0) @@ -153,5 +152,3 @@ void ZfsArchive::unXor(byte *buffer, uint32 length, const byte *xorKey) const { } } // End of namespace ZVision - - diff --git a/engines/zvision/archives/zfs_archive.h b/engines/zvision/utility/zfs_archive.h index 3509cfee26..571591a6d1 100644 --- a/engines/zvision/archives/zfs_archive.h +++ b/engines/zvision/utility/zfs_archive.h @@ -27,7 +27,6 @@ #include "common/hashmap.h" #include "common/hash-str.h" - namespace Common { class String; } @@ -53,7 +52,7 @@ struct ZfsEntryHeader { uint32 unknown; }; -typedef Common::HashMap<Common::String, ZfsEntryHeader*, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> ZfsEntryHeaderMap; +typedef Common::HashMap<Common::String, ZfsEntryHeader *, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> ZfsEntryHeaderMap; class ZfsArchive : public Common::Archive { public: diff --git a/engines/zvision/video/video.cpp b/engines/zvision/video/video.cpp index d1fff30408..36b5f9b921 100644 --- a/engines/zvision/video/video.cpp +++ b/engines/zvision/video/video.cpp @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -21,107 +21,43 @@ */ #include "common/scummsys.h" - -#include "zvision/zvision.h" - -#include "zvision/utility/clock.h" -#include "zvision/graphics/render_manager.h" - #include "common/system.h" - #include "video/video_decoder.h" - #include "engines/util.h" - #include "graphics/surface.h" +#include "zvision/zvision.h" +#include "zvision/utility/clock.h" +#include "zvision/graphics/render_manager.h" +#include "zvision/graphics/subtitles.h" namespace ZVision { -// Taken/modified from SCI -void scaleBuffer(const byte *src, byte *dst, uint32 srcWidth, uint32 srcHeight, byte bytesPerPixel, uint scaleAmount) { - assert(bytesPerPixel == 1 || bytesPerPixel == 2); - - const uint32 newWidth = srcWidth * scaleAmount; - const uint32 pitch = newWidth * bytesPerPixel; - const byte *srcPtr = src; - - if (bytesPerPixel == 1) { - for (uint32 y = 0; y < srcHeight; ++y) { - for (uint32 x = 0; x < srcWidth; ++x) { - const byte color = *srcPtr++; - - for (uint i = 0; i < scaleAmount; ++i) { - dst[i] = color; - dst[pitch + i] = color; - } - dst += scaleAmount; - } - dst += pitch; - } - } else if (bytesPerPixel == 2) { - for (uint32 y = 0; y < srcHeight; ++y) { - for (uint32 x = 0; x < srcWidth; ++x) { - const byte color = *srcPtr++; - const byte color2 = *srcPtr++; - - for (uint i = 0; i < scaleAmount; ++i) { - uint index = i *2; - - dst[index] = color; - dst[index + 1] = color2; - dst[pitch + index] = color; - dst[pitch + index + 1] = color2; - } - dst += 2 * scaleAmount; - } - dst += pitch; - } - } -} - -void ZVision::playVideo(Video::VideoDecoder &videoDecoder, const Common::Rect &destRect, bool skippable) { - byte bytesPerPixel = videoDecoder.getPixelFormat().bytesPerPixel; - - uint16 origWidth = videoDecoder.getWidth(); - uint16 origHeight = videoDecoder.getHeight(); - - uint scale = 1; +void ZVision::playVideo(Video::VideoDecoder &vid, const Common::Rect &destRect, bool skippable, Subtitle *sub) { + Common::Rect dst = destRect; // If destRect is empty, no specific scaling was requested. However, we may choose to do scaling anyway - if (destRect.isEmpty()) { - // Most videos are very small. Therefore we do a simple 2x scale - if (origWidth * 2 <= 640 && origHeight * 2 <= 480) { - scale = 2; - } - } else { - // Assume bilinear scaling. AKA calculate the scale from just the width. - // Also assume that the scaling is in integral intervals. AKA no 1.5x scaling - // TODO: Test ^these^ assumptions - scale = destRect.width() / origWidth; - - // TODO: Test if we need to support downscale. - } - - uint16 pitch = origWidth * bytesPerPixel; + if (dst.isEmpty()) + dst = Common::Rect(vid.getWidth(), vid.getHeight()); - uint16 finalWidth = origWidth * scale; - uint16 finalHeight = origHeight * scale; + Graphics::Surface *scaled = NULL; - byte *scaledVideoFrameBuffer = 0; - if (scale != 1) { - scaledVideoFrameBuffer = new byte[finalWidth * finalHeight * bytesPerPixel]; + if (vid.getWidth() != dst.width() || vid.getHeight() != dst.height()) { + scaled = new Graphics::Surface; + scaled->create(dst.width(), dst.height(), vid.getPixelFormat()); } - uint16 x = ((WINDOW_WIDTH - finalWidth) / 2) + destRect.left; - uint16 y = ((WINDOW_HEIGHT - finalHeight) / 2) + destRect.top; + uint16 x = _workingWindow.left + dst.left; + uint16 y = _workingWindow.top + dst.top; + uint16 finalWidth = dst.width() < _workingWindow.width() ? dst.width() : _workingWindow.width(); + uint16 finalHeight = dst.height() < _workingWindow.height() ? dst.height() : _workingWindow.height(); _clock.stop(); - videoDecoder.start(); + vid.start(); // Only continue while the video is still playing - while (!shouldQuit() && !videoDecoder.endOfVideo() && videoDecoder.isPlaying()) { + while (!shouldQuit() && !vid.endOfVideo() && vid.isPlaying()) { // Check for engine quit and video stop key presses - while (!videoDecoder.endOfVideo() && videoDecoder.isPlaying() && _eventMan->pollEvent(_event)) { + while (_eventMan->pollEvent(_event)) { switch (_event.type) { case Common::EVENT_KEYDOWN: switch (_event.kbd.keycode) { @@ -131,7 +67,7 @@ void ZVision::playVideo(Video::VideoDecoder &videoDecoder, const Common::Rect &d break; case Common::KEYCODE_SPACE: if (skippable) { - videoDecoder.stop(); + vid.stop(); } break; default: @@ -142,29 +78,32 @@ void ZVision::playVideo(Video::VideoDecoder &videoDecoder, const Common::Rect &d } } - if (videoDecoder.needsUpdate()) { - const Graphics::Surface *frame = videoDecoder.decodeNextFrame(); + if (vid.needsUpdate()) { + const Graphics::Surface *frame = vid.decodeNextFrame(); + if (sub) + sub->process(vid.getCurFrame()); if (frame) { - if (scale != 1) { - scaleBuffer((const byte *)frame->getPixels(), scaledVideoFrameBuffer, origWidth, origHeight, bytesPerPixel, scale); - _system->copyRectToScreen(scaledVideoFrameBuffer, pitch * 2, x, y, finalWidth, finalHeight); - } else { - _system->copyRectToScreen((const byte *)frame->getPixels(), pitch, x, y, finalWidth, finalHeight); + if (scaled) { + _renderManager->scaleBuffer(frame->getPixels(), scaled->getPixels(), frame->w, frame->h, frame->format.bytesPerPixel, scaled->w, scaled->h); + frame = scaled; } + _system->copyRectToScreen((const byte *)frame->getPixels(), frame->pitch, x, y, finalWidth, finalHeight); + _renderManager->processSubs(0); } } // Always update the screen so the mouse continues to render _system->updateScreen(); - _system->delayMillis(videoDecoder.getTimeToNextFrame()); + _system->delayMillis(vid.getTimeToNextFrame() / 2); } _clock.start(); - if (scale != 1) { - delete[] scaledVideoFrameBuffer; + if (scaled) { + scaled->free(); + delete scaled; } } diff --git a/engines/zvision/video/zork_avi_decoder.cpp b/engines/zvision/video/zork_avi_decoder.cpp index f22a4203ab..67fab0a114 100644 --- a/engines/zvision/video/zork_avi_decoder.cpp +++ b/engines/zvision/video/zork_avi_decoder.cpp @@ -29,7 +29,7 @@ #include "common/stream.h" #include "audio/audiostream.h" - +#include "audio/decoders/raw.h" namespace ZVision { @@ -42,11 +42,19 @@ void ZorkAVIDecoder::ZorkAVIAudioTrack::queueSound(Common::SeekableReadStream *s if (_audStream) { if (_wvInfo.tag == kWaveFormatZorkPCM) { assert(_wvInfo.size == 8); - _audStream->queueAudioStream(makeRawZorkStream(stream, _wvInfo.samplesPerSec, _audStream->isStereo(), DisposeAfterUse::YES), DisposeAfterUse::YES); + RawChunkStream::RawChunk chunk = decoder->readNextChunk(stream); + delete stream; + + if (chunk.data) + _audStream->queueBuffer((byte *)chunk.data, chunk.size, DisposeAfterUse::YES, Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN | Audio::FLAG_STEREO); + } else { + AVIAudioTrack::queueSound(stream); } - } else { - delete stream; } } +void ZorkAVIDecoder::ZorkAVIAudioTrack::resetStream() { + decoder->init(); +} + } // End of namespace ZVision diff --git a/engines/zvision/video/zork_avi_decoder.h b/engines/zvision/video/zork_avi_decoder.h index c47f007f9b..89c0d1e4b9 100644 --- a/engines/zvision/video/zork_avi_decoder.h +++ b/engines/zvision/video/zork_avi_decoder.h @@ -8,41 +8,53 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * */ #ifndef ZORK_AVI_DECODER_H #define ZORK_AVI_DECODER_H #include "video/avi_decoder.h" - +#include "zvision/sound/zork_raw.h" namespace ZVision { class ZorkAVIDecoder : public Video::AVIDecoder { public: ZorkAVIDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType) : - Video::AVIDecoder(soundType) {} + Video::AVIDecoder(soundType) {} - virtual ~ZorkAVIDecoder() {} + virtual ~ZorkAVIDecoder() {} private: class ZorkAVIAudioTrack : public Video::AVIDecoder::AVIAudioTrack { public: ZorkAVIAudioTrack(const AVIStreamHeader &streamHeader, const PCMWaveFormat &waveFormat, Audio::Mixer::SoundType soundType) : - Video::AVIDecoder::AVIAudioTrack(streamHeader, waveFormat, soundType) {} - virtual ~ZorkAVIAudioTrack() {} + Video::AVIDecoder::AVIAudioTrack(streamHeader, waveFormat, soundType), + decoder(NULL) { + if (_audStream) { + decoder = new RawChunkStream(_audStream->isStereo()); + } + } + virtual ~ZorkAVIAudioTrack() { + if (decoder) + delete decoder; + } void queueSound(Common::SeekableReadStream *stream); + void resetStream(); + private: + RawChunkStream *decoder; }; Video::AVIDecoder::AVIAudioTrack *createAudioTrack(Video::AVIDecoder::AVIStreamHeader sHeader, Video::AVIDecoder::PCMWaveFormat wvInfo); @@ -50,7 +62,7 @@ private: private: // Audio Codecs enum { - kWaveFormatZorkPCM = 17 // special Zork PCM audio format (clashes with MS IMA ADPCM) + kWaveFormatZorkPCM = 17 // special Zork PCM audio format (clashes with MS IMA ADPCM) }; }; diff --git a/engines/zvision/zvision.cpp b/engines/zvision/zvision.cpp index b464f6ee81..af9d26a350 100644 --- a/engines/zvision/zvision.cpp +++ b/engines/zvision/zvision.cpp @@ -8,12 +8,12 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -23,17 +23,22 @@ #include "common/scummsys.h" #include "zvision/zvision.h" - #include "zvision/core/console.h" #include "zvision/scripting/script_manager.h" #include "zvision/graphics/render_manager.h" #include "zvision/cursors/cursor_manager.h" #include "zvision/core/save_manager.h" -#include "zvision/strings/string_manager.h" -#include "zvision/archives/zfs_archive.h" +#include "zvision/text/string_manager.h" #include "zvision/detection.h" +#include "zvision/core/menu.h" +#include "zvision/core/search_manager.h" +#include "zvision/text/text.h" +#include "zvision/graphics/truetype_font.h" +#include "zvision/core/midi.h" +#include "zvision/utility/zfs_archive.h" #include "common/config-manager.h" +#include "common/str.h" #include "common/debug.h" #include "common/debug-channels.h" #include "common/textconsole.h" @@ -45,24 +50,57 @@ #include "audio/mixer.h" - namespace ZVision { +#define ZVISION_SETTINGS_KEYS_COUNT 17 + +struct zvisionIniSettings { + const char *name; + int16 slot; + int16 deflt; +} settingsKeys[ZVISION_SETTINGS_KEYS_COUNT] = { + {"ZVision_KeyboardTurnSpeed", StateKey_KbdRotateSpeed, 5}, + {"ZVision_PanaRotateSpeed", StateKey_RotateSpeed, 540}, + {"ZVision_QSoundEnabled", StateKey_Qsound, 1}, + {"ZVision_VenusEnabled", StateKey_VenusEnable, 1}, + {"ZVision_HighQuality", StateKey_HighQuality, 1}, + {"ZVision_Platform", StateKey_Platform, 0}, + {"ZVision_InstallLevel", StateKey_InstallLevel, 0}, + {"ZVision_CountryCode", StateKey_CountryCode, 0}, + {"ZVision_CPU", StateKey_CPU, 1}, + {"ZVision_MovieCursor", StateKey_MovieCursor, 1}, + {"ZVision_NoAnimWhileTurning", StateKey_NoTurnAnim, 0}, + {"ZVision_Win958", StateKey_WIN958, 0}, + {"ZVision_ShowErrorDialogs", StateKey_ShowErrorDlg, 0}, + {"ZVision_ShowSubtitles", StateKey_Subtitles, 1}, + {"ZVision_DebugCheats", StateKey_DebugCheats, 0}, + {"ZVision_JapaneseFonts", StateKey_JapanFonts, 0}, + {"ZVision_Brightness", StateKey_Brightness, 0} +}; + ZVision::ZVision(OSystem *syst, const ZVisionGameDescription *gameDesc) - : Engine(syst), - _gameDescription(gameDesc), - _workingWindow(gameDesc->gameId == GID_NEMESIS ? Common::Rect((WINDOW_WIDTH - ZNEM_WORKING_WINDOW_WIDTH) / 2, (WINDOW_HEIGHT - ZNEM_WORKING_WINDOW_HEIGHT) / 2, ((WINDOW_WIDTH - ZNEM_WORKING_WINDOW_WIDTH) / 2) + ZNEM_WORKING_WINDOW_WIDTH, ((WINDOW_HEIGHT - ZNEM_WORKING_WINDOW_HEIGHT) / 2) + ZNEM_WORKING_WINDOW_HEIGHT) : - Common::Rect((WINDOW_WIDTH - ZGI_WORKING_WINDOW_WIDTH) / 2, (WINDOW_HEIGHT - ZGI_WORKING_WINDOW_HEIGHT) / 2, ((WINDOW_WIDTH - ZGI_WORKING_WINDOW_WIDTH) / 2) + ZGI_WORKING_WINDOW_WIDTH, ((WINDOW_HEIGHT - ZGI_WORKING_WINDOW_HEIGHT) / 2) + ZGI_WORKING_WINDOW_HEIGHT)), - _pixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0), /*RGB 565*/ - _desiredFrameTime(33), /* ~30 fps */ - _clock(_system), - _scriptManager(nullptr), - _renderManager(nullptr), - _saveManager(nullptr), - _stringManager(nullptr), - _cursorManager(nullptr) { + : Engine(syst), + _gameDescription(gameDesc), + _workingWindow_ZGI((WINDOW_WIDTH - WORKING_WINDOW_WIDTH) / 2, (WINDOW_HEIGHT - WORKING_WINDOW_HEIGHT) / 2, ((WINDOW_WIDTH - WORKING_WINDOW_WIDTH) / 2) + WORKING_WINDOW_WIDTH, ((WINDOW_HEIGHT - WORKING_WINDOW_HEIGHT) / 2) + WORKING_WINDOW_HEIGHT), + _workingWindow_ZNM((WINDOW_WIDTH - ZNM_WORKING_WINDOW_WIDTH) / 2, (WINDOW_HEIGHT - ZNM_WORKING_WINDOW_HEIGHT) / 2, ((WINDOW_WIDTH - ZNM_WORKING_WINDOW_WIDTH) / 2) + ZNM_WORKING_WINDOW_WIDTH, ((WINDOW_HEIGHT - ZNM_WORKING_WINDOW_HEIGHT) / 2) + ZNM_WORKING_WINDOW_HEIGHT), + _workingWindow(gameDesc->gameId == GID_NEMESIS ? _workingWindow_ZNM : _workingWindow_ZGI), + _pixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0), /*RGB 565*/ + _desiredFrameTime(33), /* ~30 fps */ + _clock(_system), + _scriptManager(nullptr), + _renderManager(nullptr), + _saveManager(nullptr), + _stringManager(nullptr), + _cursorManager(nullptr), + _midiManager(nullptr), + _audioId(0), + _rendDelay(2), + _kbdVelocity(0), + _mouseVelocity(0) { debug(1, "ZVision::ZVision"); + + memset(_cheatBuff, 0, sizeof(_cheatBuff)); } ZVision::~ZVision() { @@ -76,39 +114,60 @@ ZVision::~ZVision() { delete _renderManager; delete _scriptManager; delete _rnd; + delete _midiManager; // Remove all of our debug levels DebugMan.clearAllDebugChannels(); } +void ZVision::registerDefaultSettings() { + for (int i = 0; i < ZVISION_SETTINGS_KEYS_COUNT; i++) + ConfMan.registerDefault(settingsKeys[i].name, settingsKeys[i].deflt); + ConfMan.registerDefault("doublefps", false); +} + +void ZVision::loadSettings() { + for (int i = 0; i < ZVISION_SETTINGS_KEYS_COUNT; i++) + _scriptManager->setStateValue(settingsKeys[i].slot, ConfMan.getInt(settingsKeys[i].name)); + + if (getGameId() == GID_NEMESIS) + _scriptManager->setStateValue(StateKey_ExecScopeStyle, 1); + else + _scriptManager->setStateValue(StateKey_ExecScopeStyle, 0); +} + +void ZVision::saveSettings() { + for (int i = 0; i < ZVISION_SETTINGS_KEYS_COUNT; i++) + ConfMan.setInt(settingsKeys[i].name, _scriptManager->getStateValue(settingsKeys[i].slot)); + ConfMan.flushToDisk(); +} + void ZVision::initialize() { const Common::FSNode gameDataDir(ConfMan.get("path")); - // TODO: There are 10 file clashes when we flatten the directories. - // From a quick look, the files are exactly the same, so it shouldn't matter. - // But I'm noting it here just in-case it does become a problem. - SearchMan.addSubDirectoryMatching(gameDataDir, "data1", 0, 4, true); - SearchMan.addSubDirectoryMatching(gameDataDir, "data2", 0, 4, true); - SearchMan.addSubDirectoryMatching(gameDataDir, "data3", 0, 4, true); - SearchMan.addSubDirectoryMatching(gameDataDir, "zassets1", 0, 2, true); - SearchMan.addSubDirectoryMatching(gameDataDir, "zassets2", 0, 2, true); - SearchMan.addSubDirectoryMatching(gameDataDir, "znemmx", 0, 1, true); - SearchMan.addSubDirectoryMatching(gameDataDir, "zgi", 0, 4, true); - SearchMan.addSubDirectoryMatching(gameDataDir, "fonts", 0, 1, true); - - // Find zfs archive files - Common::ArchiveMemberList list; - SearchMan.listMatchingMembers(list, "*.zfs"); - - // Register the file entries within the zfs archives with the SearchMan - for (Common::ArchiveMemberList::iterator iter = list.begin(); iter != list.end(); ++iter) { - Common::String name = (*iter)->getName(); - Common::SeekableReadStream *stream = (*iter)->createReadStream(); - ZfsArchive *archive = new ZfsArchive(name, stream); - - delete stream; - - SearchMan.add(name, archive); - } + + _searchManager = new SearchManager(ConfMan.get("path"), 6); + + _searchManager->addDir("FONTS"); + _searchManager->addDir("addon"); + + if (_gameDescription->gameId == GID_GRANDINQUISITOR) { + _searchManager->loadZix("INQUIS.ZIX"); + _searchManager->addPatch("C000H01Q.RAW", "C000H01Q.SRC"); + _searchManager->addPatch("CM00H01Q.RAW", "CM00H01Q.SRC"); + _searchManager->addPatch("DM00H01Q.RAW", "DM00H01Q.SRC"); + _searchManager->addPatch("E000H01Q.RAW", "E000H01Q.SRC"); + _searchManager->addPatch("EM00H50Q.RAW", "EM00H50Q.SRC"); + _searchManager->addPatch("GJNPH65P.RAW", "GJNPH65P.SRC"); + _searchManager->addPatch("GJNPH72P.RAW", "GJNPH72P.SRC"); + _searchManager->addPatch("H000H01Q.RAW", "H000H01Q.SRC"); + _searchManager->addPatch("M000H01Q.RAW", "M000H01Q.SRC"); + _searchManager->addPatch("P000H01Q.RAW", "P000H01Q.SRC"); + _searchManager->addPatch("Q000H01Q.RAW", "Q000H01Q.SRC"); + _searchManager->addPatch("SW00H01Q.RAW", "SW00H01Q.SRC"); + _searchManager->addPatch("T000H01Q.RAW", "T000H01Q.SRC"); + _searchManager->addPatch("U000H01Q.RAW", "U000H01Q.SRC"); + } else if (_gameDescription->gameId == GID_NEMESIS) + _searchManager->loadZix("NEMESIS.ZIX"); initGraphics(WINDOW_WIDTH, WINDOW_HEIGHT, true, &_pixelFormat); @@ -117,18 +176,30 @@ void ZVision::initialize() { // Create managers _scriptManager = new ScriptManager(this); - _renderManager = new RenderManager(_system, WINDOW_WIDTH, WINDOW_HEIGHT, _workingWindow, _pixelFormat); + _renderManager = new RenderManager(this, WINDOW_WIDTH, WINDOW_HEIGHT, _workingWindow, _pixelFormat); _saveManager = new SaveManager(this); _stringManager = new StringManager(this); _cursorManager = new CursorManager(this, &_pixelFormat); + _textRenderer = new TextRenderer(this); + _midiManager = new MidiManager(); + + if (_gameDescription->gameId == GID_GRANDINQUISITOR) + _menu = new MenuZGI(this); + else + _menu = new MenuNemesis(this); // Initialize the managers _cursorManager->initialize(); _scriptManager->initialize(); _stringManager->initialize(_gameDescription->gameId); + registerDefaultSettings(); + + loadSettings(); + // Create debugger console. It requires GFX to be initialized _console = new Console(this); + _halveDelay = ConfMan.getBool("doublefps"); } Common::Error ZVision::run() { @@ -140,29 +211,111 @@ Common::Error ZVision::run() { uint32 currentTime = _clock.getLastMeasuredTime(); uint32 deltaTime = _clock.getDeltaTime(); + _cursorManager->setItemID(_scriptManager->getStateValue(StateKey_InventoryItem)); + processEvents(); + updateRotation(); // Call _renderManager->update() first so the background renders // before anything that puzzles/controls will render - _renderManager->update(deltaTime); _scriptManager->update(deltaTime); + _menu->process(deltaTime); // Render the backBuffer to the screen + _renderManager->prepareBkg(); + _renderManager->renderMenuToScreen(); + _renderManager->processSubs(deltaTime); _renderManager->renderBackbufferToScreen(); // Update the screen - _system->updateScreen(); + if (_rendDelay <= 0) + _system->updateScreen(); + else + _rendDelay--; // Calculate the frame delay based off a desired frame time int delay = _desiredFrameTime - int32(_system->getMillis() - currentTime); // Ensure non-negative delay = delay < 0 ? 0 : delay; + if (_halveDelay) + delay >>= 1; _system->delayMillis(delay); } return Common::kNoError; } +bool ZVision::askQuestion(const Common::String &str) { + uint16 msgid = _renderManager->createSubArea(); + _renderManager->updateSubArea(msgid, str); + _renderManager->processSubs(0); + _renderManager->renderBackbufferToScreen(); + _clock.stop(); + + int result = 0; + + while (result == 0) { + Common::Event evnt; + while (_eventMan->pollEvent(evnt)) { + if (evnt.type == Common::EVENT_KEYDOWN) { + switch (evnt.kbd.keycode) { + case Common::KEYCODE_y: + result = 2; + break; + case Common::KEYCODE_n: + result = 1; + break; + default: + break; + } + } + } + _system->updateScreen(); + if (_halveDelay) + _system->delayMillis(33); + else + _system->delayMillis(66); + } + _renderManager->deleteSubArea(msgid); + _clock.start(); + return result == 2; +} + +void ZVision::delayedMessage(const Common::String &str, uint16 milsecs) { + uint16 msgid = _renderManager->createSubArea(); + _renderManager->updateSubArea(msgid, str); + _renderManager->processSubs(0); + _renderManager->renderBackbufferToScreen(); + _clock.stop(); + + uint32 stopTime = _system->getMillis() + milsecs; + while (_system->getMillis() < stopTime) { + Common::Event evnt; + while (_eventMan->pollEvent(evnt)) { + if (evnt.type == Common::EVENT_KEYDOWN && + (evnt.kbd.keycode == Common::KEYCODE_SPACE || + evnt.kbd.keycode == Common::KEYCODE_RETURN || + evnt.kbd.keycode == Common::KEYCODE_ESCAPE)) + break; + } + _system->updateScreen(); + if (_halveDelay) + _system->delayMillis(33); + else + _system->delayMillis(66); + } + _renderManager->deleteSubArea(msgid); + _clock.start(); +} + +void ZVision::timedMessage(const Common::String &str, uint16 milsecs) { + uint16 msgid = _renderManager->createSubArea(); + _renderManager->updateSubArea(msgid, str); + _renderManager->processSubs(0); + _renderManager->renderBackbufferToScreen(); + _renderManager->deleteSubArea(msgid, milsecs); +} + void ZVision::pauseEngineIntern(bool pause) { _mixer->pauseAll(pause); @@ -181,4 +334,196 @@ Common::String ZVision::generateAutoSaveFileName() { return Common::String::format("%s.auto", _targetName.c_str()); } +void ZVision::setRenderDelay(uint delay) { + _rendDelay = delay; +} + +bool ZVision::canRender() { + return _rendDelay <= 0; +} + +void ZVision::updateRotation() { + int16 _velocity = _mouseVelocity + _kbdVelocity; + + if (_halveDelay) + _velocity /= 2; + + if (_velocity) { + RenderTable::RenderState renderState = _renderManager->getRenderTable()->getRenderState(); + if (renderState == RenderTable::PANORAMA) { + int16 startPosition = _scriptManager->getStateValue(StateKey_ViewPos); + + int16 newPosition = startPosition + (_renderManager->getRenderTable()->getPanoramaReverse() ? -_velocity : _velocity); + + int16 zeroPoint = _renderManager->getRenderTable()->getPanoramaZeroPoint(); + if (startPosition >= zeroPoint && newPosition < zeroPoint) + _scriptManager->setStateValue(StateKey_Rounds, _scriptManager->getStateValue(StateKey_Rounds) - 1); + if (startPosition <= zeroPoint && newPosition > zeroPoint) + _scriptManager->setStateValue(StateKey_Rounds, _scriptManager->getStateValue(StateKey_Rounds) + 1); + + int16 screenWidth = _renderManager->getBkgSize().x; + if (screenWidth) + newPosition %= screenWidth; + + if (newPosition < 0) + newPosition += screenWidth; + + _renderManager->setBackgroundPosition(newPosition); + } else if (renderState == RenderTable::TILT) { + int16 startPosition = _scriptManager->getStateValue(StateKey_ViewPos); + + int16 newPosition = startPosition + _velocity; + + int16 screenHeight = _renderManager->getBkgSize().y; + int16 tiltGap = _renderManager->getRenderTable()->getTiltGap(); + + if (newPosition >= (screenHeight - tiltGap)) + newPosition = screenHeight - tiltGap; + if (newPosition <= tiltGap) + newPosition = tiltGap; + + _renderManager->setBackgroundPosition(newPosition); + } + } +} + +void ZVision::checkBorders() { + RenderTable::RenderState renderState = _renderManager->getRenderTable()->getRenderState(); + if (renderState == RenderTable::PANORAMA) { + int16 startPosition = _scriptManager->getStateValue(StateKey_ViewPos); + + int16 newPosition = startPosition; + + int16 screenWidth = _renderManager->getBkgSize().x; + + if (screenWidth) + newPosition %= screenWidth; + + if (newPosition < 0) + newPosition += screenWidth; + + if (startPosition != newPosition) + _renderManager->setBackgroundPosition(newPosition); + } else if (renderState == RenderTable::TILT) { + int16 startPosition = _scriptManager->getStateValue(StateKey_ViewPos); + + int16 newPosition = startPosition; + + int16 screenHeight = _renderManager->getBkgSize().y; + int16 tiltGap = _renderManager->getRenderTable()->getTiltGap(); + + if (newPosition >= (screenHeight - tiltGap)) + newPosition = screenHeight - tiltGap; + if (newPosition <= tiltGap) + newPosition = tiltGap; + + if (startPosition != newPosition) + _renderManager->setBackgroundPosition(newPosition); + } +} + +void ZVision::rotateTo(int16 _toPos, int16 _time) { + if (_renderManager->getRenderTable()->getRenderState() != RenderTable::PANORAMA) + return; + + if (_time == 0) + _time = 1; + + int32 maxX = _renderManager->getBkgSize().x; + int32 curX = _renderManager->getCurrentBackgroundOffset(); + int32 dx = 0; + + if (curX == _toPos) + return; + + if (curX > _toPos) { + if (curX - _toPos > maxX / 2) + dx = (_toPos + (maxX - curX)) / _time; + else + dx = -(curX - _toPos) / _time; + } else { + if (_toPos - curX > maxX / 2) + dx = -((maxX - _toPos) + curX) / _time; + else + dx = (_toPos - curX) / _time; + } + + _clock.stop(); + + for (int16 i = 0; i <= _time; i++) { + if (i == _time) + curX = _toPos; + else + curX += dx; + + if (curX < 0) + curX = maxX - curX; + else if (curX >= maxX) + curX %= maxX; + + _renderManager->setBackgroundPosition(curX); + + _renderManager->prepareBkg(); + _renderManager->renderBackbufferToScreen(); + + _system->updateScreen(); + + _system->delayMillis(500 / _time); + } + + _clock.start(); +} + +void ZVision::menuBarEnable(uint16 menus) { + if (_menu) + _menu->setEnable(menus); +} + +uint16 ZVision::getMenuBarEnable() { + if (_menu) + return _menu->getEnable(); + return 0; +} + +bool ZVision::ifQuit() { + if (askQuestion(_stringManager->getTextLine(StringManager::ZVISION_STR_EXITPROMT))) { + quitGame(); + return true; + } + return false; +} + +void ZVision::pushKeyToCheatBuf(uint8 key) { + for (int i = 0; i < KEYBUF_SIZE - 1; i++) + _cheatBuff[i] = _cheatBuff[i + 1]; + + _cheatBuff[KEYBUF_SIZE - 1] = key; +} + +bool ZVision::checkCode(const char *code) { + int codeLen = strlen(code); + + if (codeLen > KEYBUF_SIZE) + return false; + + for (int i = 0; i < codeLen; i++) + if (code[i] != _cheatBuff[KEYBUF_SIZE - codeLen + i] && code[i] != '?') + return false; + + return true; +} + +uint8 ZVision::getBufferedKey(uint8 pos) { + if (pos >= KEYBUF_SIZE) + return 0; + else + return _cheatBuff[KEYBUF_SIZE - pos - 1]; +} + +void ZVision::showDebugMsg(const Common::String &msg, int16 delay) { + uint16 msgid = _renderManager->createSubArea(); + _renderManager->updateSubArea(msgid, msg); + _renderManager->deleteSubArea(msgid, delay); +} + } // End of namespace ZVision diff --git a/engines/zvision/zvision.h b/engines/zvision/zvision.h index 0b5a86f370..ca6c8e10e4 100644 --- a/engines/zvision/zvision.h +++ b/engines/zvision/zvision.h @@ -8,24 +8,25 @@ * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. - * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + * */ #ifndef ZVISION_ZVISION_H #define ZVISION_ZVISION_H -#include "zvision/core/console.h" #include "zvision/detection.h" #include "zvision/utility/clock.h" +#include "zvision/core/search_manager.h" #include "common/random.h" #include "common/events.h" @@ -36,7 +37,6 @@ #include "gui/debugger.h" - namespace Video { class VideoDecoder; } @@ -44,12 +44,17 @@ class VideoDecoder; namespace ZVision { struct ZVisionGameDescription; +class Console; class ScriptManager; class RenderManager; class CursorManager; class StringManager; class SaveManager; class RlfAnimation; +class MenuHandler; +class TextRenderer; +class Subtitle; +class MidiManager; class ZVision : public Engine { public: @@ -62,7 +67,7 @@ public: * are given in this coordinate space. Also, all images are clipped to the * edges of this Rectangle */ - const Common::Rect _workingWindow; + const Common::Rect &_workingWindow; const Graphics::PixelFormat _pixelFormat; private: @@ -71,15 +76,17 @@ private: WINDOW_HEIGHT = 480, //Zork nemesis working window sizes - ZNEM_WORKING_WINDOW_WIDTH = 512, - ZNEM_WORKING_WINDOW_HEIGHT = 320, + ZNM_WORKING_WINDOW_WIDTH = 512, + ZNM_WORKING_WINDOW_HEIGHT = 320, //ZGI(and default) working window sizes - ZGI_WORKING_WINDOW_WIDTH = 640, - ZGI_WORKING_WINDOW_HEIGHT = 344, + WORKING_WINDOW_WIDTH = 640, + WORKING_WINDOW_HEIGHT = 344, ROTATION_SCREEN_EDGE_OFFSET = 60, - MAX_ROTATION_SPEED = 400 // Pixels per second + MAX_ROTATION_SPEED = 400, // Pixels per second + + KEYBUF_SIZE = 20 }; Console *_console; @@ -96,27 +103,67 @@ private: CursorManager *_cursorManager; SaveManager *_saveManager; StringManager *_stringManager; + MenuHandler *_menu; + SearchManager *_searchManager; + TextRenderer *_textRenderer; + MidiManager *_midiManager; // Clock Clock _clock; + // Audio ID + int _audioId; + // To prevent allocation every time we process events Common::Event _event; + const Common::Rect _workingWindow_ZGI; + const Common::Rect _workingWindow_ZNM; + + int _rendDelay; + int16 _mouseVelocity; + int16 _kbdVelocity; + bool _halveDelay; + + uint8 _cheatBuff[KEYBUF_SIZE]; public: uint32 getFeatures() const; Common::Language getLanguage() const; Common::Error run(); void pauseEngineIntern(bool pause); - ScriptManager *getScriptManager() const { return _scriptManager; } - RenderManager *getRenderManager() const { return _renderManager; } - CursorManager *getCursorManager() const { return _cursorManager; } - SaveManager *getSaveManager() const { return _saveManager; } - StringManager *getStringManager() const { return _stringManager; } - Common::RandomSource *getRandomSource() const { return _rnd; } - ZVisionGameId getGameId() const { return _gameDescription->gameId; } - GUI::Debugger *getDebugger() { return _console; } + ScriptManager *getScriptManager() const { + return _scriptManager; + } + RenderManager *getRenderManager() const { + return _renderManager; + } + CursorManager *getCursorManager() const { + return _cursorManager; + } + SaveManager *getSaveManager() const { + return _saveManager; + } + StringManager *getStringManager() const { + return _stringManager; + } + SearchManager *getSearchManager() const { + return _searchManager; + } + TextRenderer *getTextRenderer() const { + return _textRenderer; + } + MidiManager *getMidiManager() const { + return _midiManager; + } + Common::RandomSource *getRandomSource() const { + return _rnd; + } + ZVisionGameId getGameId() const { + return _gameDescription->gameId; + } + + uint8 getZvisionKey(Common::KeyCode scummKeyCode); /** * Play a video until it is finished. This is a blocking call. It will call @@ -127,11 +174,30 @@ public: * @param destRect Where to put the video. (In working window coords) * @param skippable If true, the video can be skipped at any time using [Spacebar] */ - void playVideo(Video::VideoDecoder &videoDecoder, const Common::Rect &destRect = Common::Rect(0, 0, 0, 0), bool skippable = true); + void playVideo(Video::VideoDecoder &videoDecoder, const Common::Rect &destRect = Common::Rect(0, 0, 0, 0), bool skippable = true, Subtitle *sub = NULL); + + void rotateTo(int16 to, int16 time); Common::String generateSaveFileName(uint slot); Common::String generateAutoSaveFileName(); + bool askQuestion(const Common::String &str); + void delayedMessage(const Common::String &str, uint16 milsecs); + void timedMessage(const Common::String &str, uint16 milsecs); + + void setRenderDelay(uint); + bool canRender(); + + void loadSettings(); + void saveSettings(); + + void menuBarEnable(uint16 menus); + uint16 getMenuBarEnable(); + + bool ifQuit(); + + void checkBorders(); + void showDebugMsg(const Common::String &msg, int16 delay = 3000); private: void initialize(); void initFonts(); @@ -141,9 +207,16 @@ private: /** Called every frame from ZVision::run() to process any events from EventMan */ void processEvents(); - void onMouseDown(const Common::Point &pos); - void onMouseUp(const Common::Point &pos); void onMouseMove(const Common::Point &pos); + void updateRotation(); + + void registerDefaultSettings(); + void shortKeys(Common::Event); + + void cheatCodes(uint8 key); + void pushKeyToCheatBuf(uint8 key); + bool checkCode(const char *code); + uint8 getBufferedKey(uint8 pos); }; } // End of namespace ZVision diff --git a/gui/EventRecorder.cpp b/gui/EventRecorder.cpp index ab284aaa6e..d0371f5e78 100644 --- a/gui/EventRecorder.cpp +++ b/gui/EventRecorder.cpp @@ -49,7 +49,6 @@ namespace GUI { const int kMaxRecordsNames = 0x64; const int kDefaultScreenshotPeriod = 60000; -const int kDefaultBPP = 2; uint32 readTime(Common::ReadStream *inFile) { uint32 d = inFile->readByte(); diff --git a/gui/browser_osx.mm b/gui/browser_osx.mm index 0e80410032..18cbd134f3 100644 --- a/gui/browser_osx.mm +++ b/gui/browser_osx.mm @@ -154,7 +154,11 @@ int BrowserDialog::runModal() { [showHiddenFilesButton setAction:@selector(showHiddenFiles:)]; } +#if MAC_OS_X_VERSION_MAX_ALLOWED <= 1090 if ([panel runModal] == NSOKButton) { +#else + if ([panel runModal] == NSModalResponseOK) { +#endif NSURL *url = [panel URL]; if ([url isFileURL]) { const char *filename = [[url path] UTF8String]; diff --git a/gui/credits.h b/gui/credits.h index d908a730b7..5b33797a63 100644 --- a/gui/credits.h +++ b/gui/credits.h @@ -851,7 +851,7 @@ static const char *credits[] = { "C0""", "C0""Neil Dodwell and David Dew from Creative Reality for providing the source of Dreamweb and for their tremendous support.", "C0""", -"C0""Janusz Wisniewski and Miroslaw Liminowicz from Laboratorium Komputerowe Avalon for providing full source code for Soltys and letting us redistribute the game.", +"C0""Janusz Wisniewski and Miroslaw Liminowicz from Laboratorium Komputerowe Avalon for providing full source code for Soltys and Sfinx and letting us redistribute the games.", "C0""", "C0""Jan Nedoma for providing the sources to the Wintermute-engine, and for his support while porting the engine to ScummVM.", "C0""", diff --git a/gui/debugger.cpp b/gui/debugger.cpp index dcdc18d7b9..216bd626fe 100644 --- a/gui/debugger.cpp +++ b/gui/debugger.cpp @@ -27,6 +27,13 @@ #include "common/debug-channels.h" #include "common/system.h" +#ifndef DISABLE_MD5 +#include "common/md5.h" +#include "common/archive.h" +#include "common/macresman.h" +#include "common/stream.h" +#endif + #include "engines/engine.h" #include "gui/debugger.h" @@ -61,6 +68,10 @@ Debugger::Debugger() { registerCmd("help", WRAP_METHOD(Debugger, cmdHelp)); registerCmd("openlog", WRAP_METHOD(Debugger, cmdOpenLog)); +#ifndef DISABLE_MD5 + registerCmd("md5", WRAP_METHOD(Debugger, cmdMd5)); + registerCmd("md5mac", WRAP_METHOD(Debugger, cmdMd5Mac)); +#endif registerCmd("debuglevel", WRAP_METHOD(Debugger, cmdDebugLevel)); registerCmd("debugflag_list", WRAP_METHOD(Debugger, cmdDebugFlagsList)); @@ -502,6 +513,76 @@ bool Debugger::cmdOpenLog(int argc, const char **argv) { return true; } +#ifndef DISABLE_MD5 +struct ArchiveMemberLess { + bool operator()(const Common::ArchiveMemberPtr &x, const Common::ArchiveMemberPtr &y) const { + return (*x).getDisplayName().compareToIgnoreCase((*y).getDisplayName()) < 0; + } +}; + +bool Debugger::cmdMd5(int argc, const char **argv) { + if (argc < 2) { + debugPrintf("md5 <filename | pattern>\n"); + } else { + // Assume that spaces are part of a single filename. + Common::String filename = argv[1]; + for (int i = 2; i < argc; i++) { + filename = filename + " " + argv[i]; + } + Common::ArchiveMemberList list; + SearchMan.listMatchingMembers(list, filename); + if (list.empty()) { + debugPrintf("File '%s' not found\n", filename.c_str()); + } else { + sort(list.begin(), list.end(), ArchiveMemberLess()); + for (Common::ArchiveMemberList::iterator iter = list.begin(); iter != list.end(); ++iter) { + Common::ReadStream *stream = (*iter)->createReadStream(); + Common::String md5 = Common::computeStreamMD5AsString(*stream, 0); + debugPrintf("%s %s\n", md5.c_str(), (*iter)->getDisplayName().c_str()); + delete stream; + } + } + } + return true; +} + +bool Debugger::cmdMd5Mac(int argc, const char **argv) { + if (argc < 2) { + debugPrintf("md5mac <base filename>\n"); + } else { + // Assume that spaces are part of a single filename. + Common::String filename = argv[1]; + for (int i = 2; i < argc; i++) { + filename = filename + " " + argv[i]; + } + Common::MacResManager macResMan; + // FIXME: There currently isn't any way to tell the Mac resource + // manager to open a specific file. Instead, it takes a "base name" + // and constructs a file name out of that. While usually a desirable + // thing, it's not ideal here. + if (!macResMan.open(filename)) { + debugPrintf("Resource file '%s' not found\n", filename.c_str()); + } else { + if (!macResMan.hasResFork() && !macResMan.hasDataFork()) { + debugPrintf("'%s' has neither data not resource fork\n", macResMan.getBaseFileName().c_str()); + } else { + // The resource fork is probably the most relevant one. + if (macResMan.hasResFork()) { + Common::String md5 = macResMan.computeResForkMD5AsString(0); + debugPrintf("%s %s (resource)\n", md5.c_str(), macResMan.getBaseFileName().c_str()); + } + if (macResMan.hasDataFork()) { + Common::ReadStream *stream = macResMan.getDataFork(); + Common::String md5 = Common::computeStreamMD5AsString(*stream, 0); + debugPrintf("%s %s (data)\n", md5.c_str(), macResMan.getBaseFileName().c_str()); + } + } + macResMan.close(); + } + } + return true; +} +#endif bool Debugger::cmdDebugLevel(int argc, const char **argv) { if (argc == 1) { // print level diff --git a/gui/debugger.h b/gui/debugger.h index 175eb33960..ef6f900974 100644 --- a/gui/debugger.h +++ b/gui/debugger.h @@ -213,6 +213,10 @@ protected: bool cmdExit(int argc, const char **argv); bool cmdHelp(int argc, const char **argv); bool cmdOpenLog(int argc, const char **argv); +#ifndef DISABLE_MD5 + bool cmdMd5(int argc, const char **argv); + bool cmdMd5Mac(int argc, const char **argv); +#endif bool cmdDebugLevel(int argc, const char **argv); bool cmdDebugFlagsList(int argc, const char **argv); bool cmdDebugFlagEnable(int argc, const char **argv); diff --git a/gui/themes/translations.dat b/gui/themes/translations.dat Binary files differindex abd745bb2b..bfa33d4feb 100644 --- a/gui/themes/translations.dat +++ b/gui/themes/translations.dat diff --git a/po/nl_NL.po b/po/nl_NL.po index 43ac274ac5..3a9e6d8172 100644 --- a/po/nl_NL.po +++ b/po/nl_NL.po @@ -1,21 +1,21 @@ # LANGUAGE translation for ScummVM. # Copyright (C) YEAR ScummVM Team # This file is distributed under the same license as the ScummVM package. -# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# FIRST AUTHOR scummvm@bencastricum.nl, 2014. # msgid "" msgstr "" "Project-Id-Version: ScummVM 1.8.0git\n" "Report-Msgid-Bugs-To: scummvm-devel@lists.sf.net\n" -"POT-Creation-Date: 2014-10-04 00:58+0100\n" -"PO-Revision-Date: 2014-09-03 07:42+0100\n" +"POT-Creation-Date: 2014-11-25 20:41+0100\n" +"PO-Revision-Date: 2014-11-25 20:46+0100\n" "Last-Translator: Ben Castricum <scummvm@bencastricum.nl>\n" "Language-Team: Ben Castricum <scummvm@bencastricum.nl>\n" "Language: Nederlands\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=iso-8859-1\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.5.3\n" +"X-Generator: Poedit 1.6.10\n" "X-Poedit-SourceCharset: iso-8859-1\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -34,11 +34,11 @@ msgstr "Beschikbare engines:" #: gui/browser.cpp:68 msgid "Show hidden files" -msgstr "Verborgen bestanden weergeven" +msgstr "Toon verborgen bestanden" #: gui/browser.cpp:68 msgid "Show files marked with the hidden attribute" -msgstr "Toon de bestanden die met het verborgen kenmerk hebben." +msgstr "Toon bestanden die het verborgen kenmerk hebben." #: gui/browser.cpp:72 msgid "Go up" @@ -108,7 +108,7 @@ msgstr "Koppel" #: backends/platform/wii/options.cpp:47 #: backends/platform/wince/CELauncherDialog.cpp:54 #: engines/agos/animation.cpp:558 engines/drascula/saveload.cpp:49 -#: engines/groovie/script.cpp:399 engines/parallaction/saveload.cpp:274 +#: engines/groovie/script.cpp:408 engines/parallaction/saveload.cpp:274 #: engines/scumm/dialogs.cpp:193 engines/scumm/scumm.cpp:1825 #: engines/scumm/players/player_v3m.cpp:130 #: engines/scumm/players/player_v5m.cpp:108 engines/sky/compact.cpp:131 @@ -214,7 +214,7 @@ msgstr "Engine" #: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090 msgid "Graphics" -msgstr "Grafisch" +msgstr "Beeld" #: gui/launcher.cpp:245 gui/options.cpp:1073 gui/options.cpp:1090 msgid "GFX" @@ -231,7 +231,7 @@ msgstr "Negeer algemene grafische instellingen" #: gui/launcher.cpp:257 gui/options.cpp:1096 msgid "Audio" -msgstr "Audio" +msgstr "Geluid" #: gui/launcher.cpp:260 msgid "Override global audio settings" @@ -319,7 +319,7 @@ msgstr "Extra Pad:" #: gui/launcher.cpp:339 gui/options.cpp:1134 msgid "Save Path:" -msgstr "Save Pad:" +msgstr "Bewaar Pad:" #: gui/launcher.cpp:339 gui/launcher.cpp:341 gui/launcher.cpp:342 #: gui/options.cpp:1134 gui/options.cpp:1136 gui/options.cpp:1137 @@ -329,7 +329,7 @@ msgstr "Bepaalt waar opgeslagen spellen worden bewaard." #: gui/launcher.cpp:341 gui/options.cpp:1136 msgctxt "lowres" msgid "Save Path:" -msgstr "Save Pad:" +msgstr "Bewaar Pad:" #: gui/launcher.cpp:360 gui/launcher.cpp:459 gui/launcher.cpp:517 #: gui/launcher.cpp:571 gui/options.cpp:1145 gui/options.cpp:1153 @@ -604,8 +604,7 @@ msgstr "Geen" #: gui/options.cpp:389 msgid "Failed to apply some of the graphic options changes:" -msgstr "" -"Het is niet gelukt om enkele veranderingen in grafische opties toe te passen:" +msgstr "Sommige grafische opties konden niet worden toegepast:" #: gui/options.cpp:401 msgid "the video mode could not be changed." @@ -781,7 +780,7 @@ msgstr "Geen Roland MT-32 muziek gebruiken" #: gui/options.cpp:927 msgid "Text and Speech:" -msgstr "Spraak en/of ondertitels:" +msgstr "Spraak en/of tekst:" #: gui/options.cpp:931 gui/options.cpp:941 msgid "Speech" @@ -789,7 +788,7 @@ msgstr "Spraak" #: gui/options.cpp:932 gui/options.cpp:942 msgid "Subtitles" -msgstr "Ondertitels" +msgstr "Tekst" #: gui/options.cpp:933 msgid "Both" @@ -797,7 +796,7 @@ msgstr "Beide" #: gui/options.cpp:935 msgid "Subtitle speed:" -msgstr "Snelheid ondertitels:" +msgstr "Snelheid tekst:" #: gui/options.cpp:937 msgctxt "lowres" @@ -819,7 +818,7 @@ msgstr "Beide" #: gui/options.cpp:943 msgid "Show subtitles and play speech" -msgstr "Toon ondertitels en speel spraak af" +msgstr "Toon tekst en speel spraak af" #: gui/options.cpp:945 msgctxt "lowres" @@ -1277,17 +1276,17 @@ msgstr "O~v~er" #: engines/dialogs.cpp:105 engines/dialogs.cpp:181 msgid "~R~eturn to Launcher" -msgstr "~T~erug naar het startmenu" +msgstr "Terug naar s~t~artmenu" #: engines/dialogs.cpp:107 engines/dialogs.cpp:183 msgctxt "lowres" msgid "~R~eturn to Launcher" -msgstr "~T~erug naar startmenu" +msgstr "S~t~artmenu" #: engines/dialogs.cpp:116 engines/agi/saveload.cpp:803 #: engines/cruise/menu.cpp:212 engines/drascula/saveload.cpp:336 #: engines/dreamweb/saveload.cpp:261 engines/neverhood/menumodule.cpp:873 -#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:758 +#: engines/pegasus/pegasus.cpp:377 engines/sci/engine/kfile.cpp:759 #: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 msgid "Save game:" msgstr "Spel opslaan:" @@ -1300,7 +1299,7 @@ msgstr "Spel opslaan:" #: engines/agi/saveload.cpp:803 engines/cruise/menu.cpp:212 #: engines/drascula/saveload.cpp:336 engines/dreamweb/saveload.cpp:261 #: engines/neverhood/menumodule.cpp:873 engines/pegasus/pegasus.cpp:377 -#: engines/sci/engine/kfile.cpp:758 engines/scumm/dialogs.cpp:188 +#: engines/sci/engine/kfile.cpp:759 engines/scumm/dialogs.cpp:188 #: engines/toltecs/menu.cpp:281 engines/tsage/scenes.cpp:598 msgid "Save" msgstr "Opslaan" @@ -1540,7 +1539,7 @@ msgstr "~I~ndy vecht besturing" #: backends/platform/ds/arm9/source/dsoptions.cpp:65 msgid "Show mouse cursor" -msgstr "Toon muis wijzer" +msgstr "Toon muiswijzer" #: backends/platform/ds/arm9/source/dsoptions.cpp:66 msgid "Snap to edges" @@ -1769,7 +1768,7 @@ msgstr "Video" #: backends/platform/wii/options.cpp:54 msgid "Current video mode:" -msgstr "Huidige video modus:" +msgstr "Huidige videomodus:" #: backends/platform/wii/options.cpp:56 msgid "Double-strike" @@ -2113,13 +2112,13 @@ msgstr "" #: engines/agi/saveload.cpp:816 engines/drascula/saveload.cpp:349 #: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886 -#: engines/sci/engine/kfile.cpp:857 engines/toltecs/menu.cpp:256 +#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256 msgid "Restore game:" msgstr "Laad opgeslagen spel:" #: engines/agi/saveload.cpp:816 engines/drascula/saveload.cpp:349 #: engines/dreamweb/saveload.cpp:169 engines/neverhood/menumodule.cpp:886 -#: engines/sci/engine/kfile.cpp:857 engines/toltecs/menu.cpp:256 +#: engines/sci/engine/kfile.cpp:858 engines/toltecs/menu.cpp:256 msgid "Restore" msgstr "Laad" @@ -2161,14 +2160,13 @@ msgstr "" msgid "Cutscene file '%s' not found!" msgstr "Cutscene bestand '%s' niet gevonden!" -#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:81 -#, fuzzy +#: engines/cge/detection.cpp:105 engines/cge2/detection.cpp:91 msgid "Color Blind Mode" -msgstr "Klik Modus" +msgstr "Kleurenblind Modus" -#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:82 +#: engines/cge/detection.cpp:106 engines/cge2/detection.cpp:92 msgid "Enable Color Blind Mode by default" -msgstr "" +msgstr "Schakel Kleurenblind modus standaard in" #: engines/drascula/saveload.cpp:47 msgid "" @@ -2218,17 +2216,17 @@ msgstr "Film snel afspelen" msgid "Play movies at an increased speed" msgstr "Speel films sneller af" -#: engines/groovie/script.cpp:399 +#: engines/groovie/script.cpp:408 msgid "Failed to save game" msgstr "Opslaan van spel mislukt." #: engines/hopkins/detection.cpp:76 engines/hopkins/detection.cpp:86 msgid "Gore Mode" -msgstr "" +msgstr "Gore Modus" #: engines/hopkins/detection.cpp:77 engines/hopkins/detection.cpp:87 msgid "Enable Gore Mode when available" -msgstr "" +msgstr "Gore modus inschakelen waar mogelijk" #. I18N: Studio audience adds an applause and cheering sounds whenever #. Malcolm makes a joke. @@ -2359,6 +2357,12 @@ msgid "" "Do you wish to use this save game file with ScummVM?\n" "\n" msgstr "" +"Het volgende originele opgeslagen spel was gevonden in uw spel pad:\n" +"\n" +"%s %s\n" +"\n" +"Wilt u dit opgeslagen spel gebruiken in ScummVM?\n" +"\n" #: engines/kyra/saveload_eob.cpp:590 #, c-format @@ -2366,6 +2370,8 @@ msgid "" "A save game file was found in the specified slot %d. Overwrite?\n" "\n" msgstr "" +"Er is al een opgeslagen spel in slot %d. Deze overschrijven?\n" +"\n" #: engines/kyra/saveload_eob.cpp:623 #, c-format @@ -2377,6 +2383,12 @@ msgid "" "'import_savefile'.\n" "\n" msgstr "" +"%d origneel opgeslagen spellen zijn succesvol geimporteerd in ScummVM.\n" +"Als u later handmatig origineel opgeslagen spellen wilt importeren dan zult " +"u de\n" +"ScummVM debug console moeten openen en het commando 'import_savefile' " +"gebruiken.\n" +"\n" #. I18N: Option for fast scene switching #: engines/mohawk/dialogs.cpp:92 engines/mohawk/dialogs.cpp:167 @@ -2433,7 +2445,7 @@ msgstr "" #: engines/parallaction/saveload.cpp:204 msgid "Loading game..." -msgstr "Laden spel..." +msgstr "Spel laden..." #: engines/parallaction/saveload.cpp:219 msgid "Saving game..." @@ -2510,12 +2522,12 @@ msgstr "Toon/Verberg Pauze-Menu" #: engines/queen/detection.cpp:56 msgid "Alternative intro" -msgstr "" +msgstr "Alternatieve intro" #: engines/queen/detection.cpp:57 -#, fuzzy msgid "Use an alternative game intro (CD version only)" -msgstr "Gebruik de floppy versie van de intro (alleen voor de CD versie)" +msgstr "" +"Gebruik een alternatieve versie van de intro (alleen voor de CD versie)" #: engines/sci/detection.cpp:374 msgid "EGA undithering" @@ -2598,12 +2610,12 @@ msgstr "Spel is gepauzeerd. Druk op de spatiebalk om verder te gaan." #. "Moechten Sie wirklich neu starten? (J/N)J" #. Will react to J as 'Yes' #: engines/scumm/dialogs.cpp:183 -msgid "Are you sure you want to restart? (Y/N)" +msgid "Are you sure you want to restart? (Y/N)Y" msgstr "Weet u zeker dat u opnieuw wilt beginnen? (J/N)J" #. I18N: you may specify 'Yes' symbol at the end of the line. See previous comment #: engines/scumm/dialogs.cpp:185 -msgid "Are you sure you want to quit? (Y/N)" +msgid "Are you sure you want to quit? (Y/N)Y" msgstr "Weet u zeker dat u wilt stoppen? (J/N)J" #: engines/scumm/dialogs.cpp:190 @@ -3224,12 +3236,16 @@ msgid "" "Could not find the 'Loom' Macintosh executable to read the\n" "instruments from. Music will be disabled." msgstr "" +"De 'Loom' Macintosh executable is niet gevonden om de instrumenten van te " +"laden. Muziek wordt uitgeschakeld." #: engines/scumm/players/player_v5m.cpp:107 msgid "" "Could not find the 'Monkey Island' Macintosh executable to read the\n" "instruments from. Music will be disabled." msgstr "" +"De 'Monkey Island' Macintosh executable is niet gevonden om de instrumenten " +"van te laden. Muziek wordt uitgeschakeld." #: engines/sky/compact.cpp:130 msgid "" @@ -3312,7 +3328,7 @@ msgstr "Houd de nieuwe" #: engines/sword1/logic.cpp:1633 msgid "This is the end of the Broken Sword 1 Demo" -msgstr "Dit is het einde van de Broken Sword 1 Demo" +msgstr "Dit is het einde van de Broken Sword 1 demo." #: engines/sword2/animation.cpp:425 msgid "" @@ -3346,8 +3362,8 @@ msgstr "" #: engines/wintermute/detection.cpp:58 msgid "Show FPS-counter" -msgstr "" +msgstr "Toon FPS-teller" #: engines/wintermute/detection.cpp:59 msgid "Show the current number of frames per second in the upper left corner" -msgstr "" +msgstr "Toon de huidige Frames Per Second teller in de linkerbovenhoek" |